From: <he...@us...> - 2005-05-17 20:08:47
|
Update of /cvsroot/gc-linux/linux/drivers/block/gcn-di In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10355 Modified Files: Makefile gcn-di.c Added Files: drive_all.S Removed Files: drive_20020402.asm Log Message: Added (untested) support for drive 06 and 08 too. --- NEW FILE: drive_all.S --- /* * DVD-R compatible "cactus" firmware extensions * Copyright (C) 2005 The GameCube Linux Team * Copyright (C) 2005 Albert Herranz * * Based on analysis of Cobra 1.0 drive code released by tmbinc on dextrose. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ /* * This code is compatible with binutils 2.15 limited mn10200 support. * */ .equ NMICR, 0xfc40 .equ UNICR, 0xfc44 .equ UNID, (1<<0) .equ ADB0, 0xfcd2 .equ ADB1, 0xfcd6 .equ ADBCTL, 0xfcda .equ ADB0CK, (1<<0) .equ ADB1CK, (1<<1) .equ ADB0ON, (1<<2) .equ ADB1ON, (1<<3) .equ irq_handler_vector, 0x804c /* 04, 06, 08 */ .equ irq_depth, 0x805b /* 04, 06, 08 */ #if DRIVE_MODEL == 0x20020402 /* 04 */ .equ dicmdbuf0, 0x80b4 .equ entry_return_address, 0x08d47e .equ data1, 0x008000 .equ data1_size, 0x6e .equ data1_copy_from, 0x08ea2a .equ bss, 0x00806e .equ bss_size, 0x1b8 .equ cactus, 0x40ecf9 .equ bert, 0x8084 .equ ernie, 0x819c .section absolute .org 0x0808aa /* 04, 06, 08 */ initialize_drive: .org 0x082f27 /* 04, 08 */ memcpy: .org 0x082f49 /* 04, 08 */ memset: .equ adb1_break_address, 0x08a7db .org 0x08a88d adb1_fixup_exit: .equ adb0_break_address, 0x08ae28 .org 0x08ae33 adb0_fixup_exit: .equ disable_extensions_when_called_from, 0x0885c1 /* 04, 08 */ #elif DRIVE_MODEL == 0x20010608 /* 06 */ .equ dicmdbuf0, 0x80a8 .equ entry_return_address, 0x08d41e .equ data1, 0x008000 .equ data1_size, 0x6e .equ data1_copy_from, 0x08e9c8 .equ bss, 0x00806e .equ bss_size, 0x1ac .equ cactus, 0x40ed02 .equ bert, 0x8078 .equ ernie, 0x8190 .section absolute .org 0x0808aa /* 04, 06, 08 */ initialize_drive: .org 0x082f2e memcpy: .org 0x082f50 memset: .equ adb1_break_address, 0x08aaf0 .org 0x08aba2 adb1_fixup_exit: .equ adb0_break_address, 0x08b145 .org 0x08b150 adb0_fixup_exit: .equ disable_extensions_when_called_from, 0x0885b9 #elif DRIVE_MODEL == 0x20020823 /* 08 */ .equ dicmdbuf0, 0x80b0 .equ entry_return_address, 0x08d4d9 .equ data1, 0x008000 .equ data1_size, 0x6e .equ data1_copy_from, 0x08ea7c .equ bss, 0x00806e .equ bss_size, 0x1b6 .equ cactus, 0x40ecf5 .equ bert, 0x8080 .equ ernie, 0x8198 .section absolute .org 0x0808aa /* 04, 06, 08 */ initialize_drive: .org 0x082f27 /* 04, 08 */ memcpy: .org 0x082f49 /* 04, 08 */ memset: .equ adb1_break_address, 0x08a828 .org 0x08a8da adb1_fixup_exit: .equ adb0_break_address, 0x08ae75 .org 0x08ae80 adb0_fixup_exit: .equ disable_extensions_when_called_from, 0x0885c1 /* 04, 08 */ #else #error Sorry, unsupported drive. #endif .section .text .global _start .global _exit /* * Our entry point is a bit special. We start executing for the first time * from the interrupt handler. */ _start: _main: /* * We reinitialize the hardware here, just like the firmware does. */ jsr initialize_drive /* relocate initialized data */ mov data1, a0 mov data1_copy_from, d1 mov data1_size, d0 jsr memcpy /* zero out the bss */ mov bss, a0 sub d0, d0 mov bss_size, d0 jsr memset /* replace the current irq handler with ours */ mov our_irq_handler, a0 mov a0, (irq_handler_vector) /* setup our extending functions ... */ mov adb1_break_address, a0 mov a0, (ADB1) mov adb0_break_address, a0 mov a0, (ADB0) /* ... and enable them */ mov ADB1ON|ADB0ON, d0 movb d0, (ADBCTL) mov entry_return_address, a0 jmp (a0) our_irq_handler: /* check for Address Break 0 */ mov (ADBCTL), d0 and ADB0CK, d0 bne adb0_break_handler /* check for Address Break 1 */ mov (ADBCTL), d0 and ADB1CK, d0 bne adb1_break_handler /* tell the drive to please accept the disk */ mov cactus, a0 mov 2, d0 bset d0, (a0) /* this seems to avoid errors if the drive idles for too long */ mov (bert), d0 mov d0, (ernie) /* call the original handler */ mov (saved_irq_handler), a0 jsr (a0) rts /* * This is how the stacks look like when our interrupt handler is called. * * Our interrupt handler is in fact not the real interrupt handler, but * just a subroutine called by the real interrupt handler. * That's why we just RTS and not RTI from our interrupt handler. * * | | | | * 00| d0 0| <- old a3 | | * 02| 8| | | * 04| d1 6| | | * 06| 4| | | * 08| d2 2| | | * 0a| 0| | | * 0c| d3 8| | | * 0e| 6| | | * 10| a0 4| | | * 12| 2| | | * 14| a1 0| | | * 16| 8| | | * 18| a2 6| | | * 1a| 4| | | * 1c| MDR 2| | | * 1e| PSW | | | * 20| PC lo | | PC lo | <- a3 * 22| PC hi | | PC hi | * : : | old a3 | * | ... | | | * +--------+ +--------+ <- (0x8ea1c) for drive 04 * normal context stack interrupt context stack * */ adb0_break_handler: /* ack the interrupt */ movbu (ADBCTL), d0 and ~ADB0CK, d0 movb d0, (ADBCTL) movbu (UNICR), d0 and ~UNID, d0 movb d0, (UNICR) /* point to the previous stack pointer */ mov a3, a0 add 4, a0 /* * Special case. When entering interrupt context the first time, * the old stack is pushed in the interrupt stack before calling us. */ movbu (irq_depth), d0 cmp 1, d0 bne 1f mov (4, a3), a0 /* get the old stack pointer */ 1: /* overwrite the original return address (look at the stack layout) */ mov adb0_fixup, a1 mov a1, (0x20, a0) /* * We disable the extensions when an original disc is found. * * We do that by checking if we were called from a piece of * code reached only when original discs are inserted. Tricky. */ /* 0x20 + 0x10 + 0x04 = 0x34 */ mov (0x34, a0), a1 cmp disable_extensions_when_called_from, a1 bne 1f di_disable_extensions: mov disable_extensions, a1 mov 1, d0 movb d0, (a1) movbu (ADBCTL), d0 and ~ADB1ON, d0 movb d0, (ADBCTL) 1: rts adb0_fixup: /* disable interrupts */ and 0xf7ff, psw /* deal with the dvd seed */ mov (a0), d1 cmp 0x00f000, d1 bne 1f mov 0x00, d0 movbu (disable_extensions), d1 cmp 0, d1 bne 1f movb d0, (0x09, a0) 1: /* skip the extra field */ mov (a0), d1 cmp 0x06, d1 bne 1f mov (0x06, a0), d1 movbu (disable_extensions), d0 cmp 0, d0 bne 2f add 6, d1 2: mov d1, (0x06, a0) 1: jmp adb0_fixup_exit adb1_break_handler: /* ack the interrupt */ movbu (ADBCTL), d0 and ~ADB1CK, d0 movb d0, (ADBCTL) movbu (UNICR), d0 and ~UNID, d0 movb d0, (UNICR) /* point to the previous stack pointer */ mov a3, a0 add 4, a0 /* * Special case. When entering interrupt context the first time, * the old stack is pushed in the interrupt stack before calling us. */ movbu (irq_depth), d0 cmp 1, d0 bne 1f mov (4, a3), a0 /* get the old stack pointer */ 1: /* overwrite the original return address (look at the stack layout) */ mov adb1_fixup, a1 mov a1, (0x20, a0) rts adb1_fixup: /* no disk id */ sub d0, d0 jmp adb1_fixup_exit .align 2 saved_irq_handler: .long 0x00080A74 /* 04, 06, 08 */ disable_extensions: .byte 0x00 _exit: Index: Makefile =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/block/gcn-di/Makefile,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- Makefile 14 May 2005 21:40:12 -0000 1.1 +++ Makefile 17 May 2005 20:08:38 -0000 1.2 @@ -1,8 +1,10 @@ obj-$(CONFIG_GAMECUBE_DI) += gcn-di.o -$(obj)/gcn-di.o: $(obj)/drive_20020402.h +$(obj)/gcn-di.o: $(obj)/drive_20020402.h \ + $(obj)/drive_20010608.h \ + $(obj)/drive_20020823.h -#CONFIG_GAMECUBE_DI_BUILD_FIRMWARE=y +CONFIG_GAMECUBE_DI_BUILD_FIRMWARE=y ifeq ($(CONFIG_GAMECUBE_DI_BUILD_FIRMWARE),y) @@ -12,17 +14,29 @@ quiet_cmd_build_difw = BLD FW $@ cmd_build_difw = \ - $(ASMN102) -o $(obj)/$(<F).o $<; \ + $(CPP) -DDRIVE_MODEL=$(DRIVE_MODEL) $< > $(obj)/$(@F).s; \ + $(ASMN102) -o $(obj)/$(@F).o $(obj)/$(@F).s; \ $(LDMN102) --section-start absolute=0 -Ttext=0x40d000 \ - -o $(obj)/$(<F).elf -e 0x40d000 $(obj)/$(<F).o; \ - $(OCMN102) -I elf32-mn10200 -O binary $(obj)/$(<F).elf \ - $(obj)/$(<F).bin; \ - (echo "static "; cat $(obj)/$(<F).bin | scripts/bin2c "$(subst .asm,,$(<F))_firmware") > $@; \ - rm -f $(obj)/$(<F).o $(obj)/$(<F).elf $(obj)/$(<F).bin + -o $(obj)/$(@F).elf -e 0x40d000 $(obj)/$(@F).o; \ + $(OCMN102) -I elf32-mn10200 -O binary $(obj)/$(@F).elf \ + $(obj)/$(@F).bin; \ + (echo "static "; cat $(obj)/$(@F).bin | scripts/bin2c "$(subst .h,,$(@F))_firmware") > $@; \ + rm -f $(obj)/$(@F).o $(obj)/$(@F).elf $(obj)/$(@F).bin $(obj)/$(@F).s targets += drive_20020402.h -$(obj)/drive_20020402.h: $(src)/drive_20020402.asm FORCE +$(obj)/drive_20020402.h: DRIVE_MODEL := 0x20020402 +$(obj)/drive_20020402.h: $(src)/drive_all.S FORCE + $(call if_changed,build_difw) + +targets += drive_20010608.h +$(obj)/drive_20010608.h: DRIVE_MODEL := 0x20010608 +$(obj)/drive_20010608.h: $(src)/drive_all.S FORCE + $(call if_changed,build_difw) + +targets += drive_20020823.h +$(obj)/drive_20020823.h: DRIVE_MODEL := 0x20020823 +$(obj)/drive_20020823.h: $(src)/drive_all.S FORCE $(call if_changed,build_difw) endif Index: gcn-di.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/block/gcn-di/gcn-di.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- gcn-di.c 14 May 2005 21:40:12 -0000 1.1 +++ gcn-di.c 17 May 2005 20:08:38 -0000 1.2 @@ -249,13 +249,29 @@ * Drive 06 (XXX) firmware extensions. */ -/* XXX TODO */ +#include "drive_20010608.h" + +static struct di_drive_code drive_20010608[] = { + [0] = { + .address = DI_DRIVE_CODE_BASE, + .len = sizeof(drive_20010608_firmware), + .code = (u8 *)drive_20010608_firmware, + }, +}; /* - * Drive 08 (XXX) firmware extensions. + * Drive 08 (20020823) firmware extensions. */ -/* XXX TODO */ +#include "drive_20020823.h" + +static struct di_drive_code drive_20020823[] = { + [0] = { + .address = DI_DRIVE_CODE_BASE, + .len = sizeof(drive_20020823_firmware), + .code = (u8 *)drive_20020823_firmware, + }, +}; /* @@ -879,6 +895,18 @@ di_patch(ddev, &generic_drive_code_trigger, 1); ddev->flags |= DI_INTEROPERABLE; break; + case 0x20010608: + di_patch(ddev, drive_20010608, + ARRAY_SIZE(drive_20010608)); + di_patch(ddev, &generic_drive_code_trigger, 1); + ddev->flags |= DI_INTEROPERABLE; + break; + case 0x20020823: + di_patch(ddev, drive_20020823, + ARRAY_SIZE(drive_20020823)); + di_patch(ddev, &generic_drive_code_trigger, 1); + ddev->flags |= DI_INTEROPERABLE; + break; default: di_printk(KERN_ERR, "sorry, drive %x is not yet" " supported\n", --- drive_20020402.asm DELETED --- |