From: <he...@us...> - 2005-05-14 21:40:21
|
Update of /cvsroot/gc-linux/linux/drivers/block/gcn-di In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15497/drivers/block/gcn-di Added Files: Makefile drive_20020402.asm drive_20020402.h gcn-di.c Log Message: Added an alternate DVD driver. This driver allows using DVD-R media like in a normal DVD drive. Currently, only drive 04 (20020402) is supported. Support for drive 06 and 08 should be easily added. By default, the driver will reject original media. --- NEW FILE: Makefile --- obj-$(CONFIG_GAMECUBE_DI) += gcn-di.o $(obj)/gcn-di.o: $(obj)/drive_20020402.h #CONFIG_GAMECUBE_DI_BUILD_FIRMWARE=y ifeq ($(CONFIG_GAMECUBE_DI_BUILD_FIRMWARE),y) ASMN102 = mn10200-linux-as LDMN102 = mn10200-linux-ld OCMN102 = mn10200-linux-objcopy quiet_cmd_build_difw = BLD FW $@ cmd_build_difw = \ $(ASMN102) -o $(obj)/$(<F).o $<; \ $(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 targets += drive_20020402.h $(obj)/drive_20020402.h: $(src)/drive_20020402.asm FORCE $(call if_changed,build_difw) endif --- NEW FILE: drive_20020402.asm --- /* * drive 04 (20020402) 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 irq_handler_vector, 0x804c .equ irq_depth, 0x805b .equ dicmdbuf0, 0x80b4 .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) /* we jump here on return from our entry point */ .equ entry_return_address, 0x08d47e .equ data1, 0x08ea2a .equ data1_size, 0x10 .equ data2, 0x08ea3a .equ data2_size, 0x5e .equ bss_size, 0x1b8 .equ cactus, 0x40ecf9 .section absolute .org 0x0808aa initialize_drive: .org 0x082f27 memcpy: .org 0x082f49 memset: .equ adb1_break_address, 0x08a7db .org 0x08a88d adb1_fixup_exit: .equ disable_extensions_when_called_from, 0x0885c1 .equ adb0_break_address, 0x08ae28 .org 0x08ae33 adb0_fixup_exit: .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 0x8000, a0 mov data1, d1 mov data1_size, d0 jsr memcpy mov 0x8010, a0 mov data2, d1 mov data2_size, d0 jsr memcpy /* zero out the bss */ mov 0x806e, 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) /* not sure about this ... */ mov (0x8084), d0 mov d0, (0x819c) /* 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 * 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 disable_extensions: .byte 0x00 _exit: --- NEW FILE: drive_20020402.h --- static const char drive_20020402_firmware[] = "\xf4\xe1\xa5\x38\xc7\xdc\x00\x80\xf4\x71\x2a\xea\x08\x80\x10\xf4" "\xe1\x13\x5f\xc7\xdc\x10\x80\xf4\x71\x3a\xea\x08\x80\x5e\xf4\xe1" "\x04\x5f\xc7\xdc\x6e\x80\xa0\xf8\xb8\x01\xf4\xe1\x1a\x5f\xc7\xf4" "\x74\x56\xd0\x40\xf7\x20\x4c\x80\xf4\x74\xdb\xa7\x08\xf7\x20\xd6" "\xfc\xf4\x74\x28\xae\x08\xf7\x20\xd2\xfc\x80\x0c\xc4\xda\xfc\xf4" "\x74\x7e\xd4\x08\xf0\x00\xc8\xda\xfc\xf5\x00\x01\xe9\x22\xc8\xda" "\xfc\xf5\x00\x02\xe8\x03\xfc\x8e\x00\xf4\x74\xf9\xec\x40\x80\x02" "\xf0\x20\xc8\x84\x80\xc0\x9c\x81\xf4\xd0\x28\xd1\x40\xf0\x01\xfe" "\xcc\xda\xfc\xf7\x00\xfe\xff\xc4\xda\xfc\xcc\x44\xfc\xf7\x00\xfe" "\xff\xc4\x44\xfc\xf2\x7c\xd0\x04\xcc\x5b\x80\xd8\x01\xe9\x02\x7c" "\x04\xf4\x75\xc4\xd0\x40\x51\x20\x71\x34\xf4\x7d\xc1\x85\x08\xe9" "\x12\xf4\x75\x2c\xd1\x40\x80\x01\x14\xcc\xda\xfc\xf7\x00\xf7\xff" "\xc4\xda\xfc\xfe\xf7\x10\xff\xf7\x21\xf4\x79\x00\xf0\x00\xe9\x0e" "\x80\x00\xf4\xc9\x2c\xd1\x40\xd9\x00\xe9\x03\xf5\x10\x09\x21\xd9" "\x06\xe9\x0f\x61\x06\xf4\xc8\x2c\xd1\x40\xd8\x00\xe9\x02\xd5\x06" "\x41\x06\xf4\xe0\x3c\xdd\xc7\xcc\xda\xfc\xf7\x00\xfd\xff\xc4\xda" "\xfc\xcc\x44\xfc\xf7\x00\xfe\xff\xc4\x44\xfc\xf2\x7c\xd0\x04\xcc" "\x5b\x80\xd8\x01\xe9\x02\x7c\x04\xf4\x75\x20\xd1\x40\x51\x20\xfe" "\xa0\xf4\xe0\x67\xd7\xc7\x00\x00\x74\x0a\x08\x00\x00\x00\x00\x00" "" ; const int drive_20020402_firmware_size = 304; --- NEW FILE: gcn-di.c --- /* * drivers/block/gcn-di/gcn-di.c * * Nintendo GameCube DVD Interface driver * Copyright (C) 2005 The GameCube Linux Team * Copyright (C) 2005 Albert Herranz * * Portions based on previous work by Scream|CT. * * 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. * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> [...1526 lines suppressed...] return retval; } /* * Module de-initialization routine. */ static void __exit di_exit_module(void) { platform_device_unregister(&di_device.pdev); driver_unregister(&di_driver); } module_init(di_init_module); module_exit(di_exit_module); MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("GPL"); |