diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Wed Feb 2 22:58:21 2000 +++ new/linux/CREDITS Wed Feb 2 23:00:00 2000 @@ -301,6 +301,13 @@ E: knan@mo.himolde.no D: Misc kernel hacks +N: Andreas E. Bombe +E: andreas.bombe@munich.netsurf.de +W: http://home.pages.de/~andreas.bombe/ +P: 1024/04880A44 72E5 7031 4414 2EB6 F6B4 4CBD 1181 7032 0488 0A44 +D: IEEE 1394 subsystem rewrite and maintainer +D: Texas Instruments PCILynx IEEE 1394 driver + N: Zoltán Böszörményi E: zboszor@mail.externet.hu D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support @@ -468,6 +475,13 @@ S: NN1 3QT S: United Kingdom +N: Uwe Dannowski +E: Uwe.Dannowski@ira.uka.de +W: http://i30www.ira.uka.de/~dannowsk/ +D: FORE PCA-200E driver +S: University of Karlsruhe +S: Germany + N: Ray Dassen E: jdassen@wi.LeidenUniv.nl W: http://www.wi.leidenuniv.nl/~jdassen/ @@ -1327,6 +1341,14 @@ S: North Little Rock, Arkansas 72115 S: USA +N: Stephan Linz +E: linz@mazet.de +E: Stephan.Linz@gmx.de +W: http://www.crosswinds.net/~tuxer +D: PCILynx patch to work with 1394a PHY and without local RAM +S: (ask for current address) +S: Germany + N: Christophe Lizzi E: lizzi@cnam.fr W: http://cedric.cnam.fr/personne/lizzi @@ -1538,13 +1560,14 @@ S: Netherlands N: David S. Miller -E: davem@dm.cobaltmicro.com +E: davem@redhat.com D: Sparc and blue box hacker D: Vger Linux mailing list co-maintainer D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) -S: 331 Santa Rosa Drive -S: Los Gatos, California 95032 +S: 750 N. Shoreline Blvd. +S: Apt. #111 +S: Mountain View, California 94043 S: USA N: Rick Miller @@ -1732,6 +1755,13 @@ S: Tula 300000 S: Russia +N: Gordon Peters +E: GordPeters@smarttech.com +D: Isochronous receive for IEEE 1394 driver (OHCI module). +D: Bugfixes for the aforementioned. +S: Calgary, Alberta +S: Canada + N: Johnnie Peters E: jpeters@phx.mcd.mot.com D: Motorola PowerPC changes for PReP @@ -1766,6 +1796,12 @@ S: 13349 Berlin S: Germany +N: Emanuel Pirker +E: epirker@edu.uni-klu.ac.at +D: AIC5800 IEEE 1394, RAW I/O on 1394 +D: Starter of Linux1394 effort +S: ask per mail for current address + N: Ken Pizzini E: ken@halcyon.com D: CDROM driver "sonycd535" (Sony CDU-535/531) @@ -1885,6 +1921,13 @@ S: 21 Rue Carnot S: 95170 Deuil La Barre S: France + +N: Sebastien Rougeaux +E: Sebastien.Rougeaux@syseng.anu.edu.au +D: IEEE 1394 OHCI module +S: Research School of Information Science and Engineering +S: The Australian National University, ACT 0200 +S: Australia N: Alessandro Rubini E: rubini@ipvvis.unipv.it diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Wed Feb 2 22:58:21 2000 +++ new/linux/Documentation/Configure.help Wed Feb 2 23:00:00 2000 @@ -7626,14 +7626,16 @@ Linux Token Ring Project site for the latest information at http://www.linuxtr.net -Generic TMS380 Token Ring ISA/PCI adapter support +Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support CONFIG_TMS380TR This driver provides generic support for token ring adapters based on the Texas Instruments TMS380 series chipsets. This includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591), - Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and Intel - TokenExpress 4/16 and PRO ISA adapters. + Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several + Madge adapters. If selected, you will be asked to select + which cards to support below. If you're using modules, each + class of card will be supported by a seperate module. If you have such an adapter and would like to use it, say Y or M and read the Token-Ring mini-HOWTO, available from @@ -7642,9 +7644,28 @@ Also read the file linux/Documentation/networking/tms380tr.txt or check http://www.auk.cx/tms380tr/ +Generic TMS380 PCI support +CONFIG_TMSPCI + This tms380 module supports generic TMS380-based PCI cards. + + These cards are known to work: + - Compaq 4/16 TR PCI + - SysKonnect TR4/16 PCI (SK-4590/SK-4591) + - Thomas-Conrad TC4048 PCI 4/16 + - 3Com Token Link Velocity + +Madge Smart 16/4 PCI Mk2 support +CONFIG_ABYSS + This tms380 module supports the Madge Smart 16/4 PCI Mk2 cards (51-02). + +Madge Smart 16/4 Ringode MicroChannel +CONFIG_MADGEMC + This tms380 module supports the Madge Smart 16/4 MC16 and MC32 + MicroChannel adapters + SMC ISA TokenRing adapter support CONFIG_SMCTR - This is support for the ISA SMC Token Ring cards, specifically + This is support for the ISA and MCA SMC Token Ring cards, specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A (8115T/A) adapters. If you have such an adapter and would like to use it, say Y or M and @@ -8050,6 +8071,25 @@ The module will be called usb-uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +UHCI (intel PIIX4, VIA, ...) alternate (JE) support? +CONFIG_USB_UHCI_ALT + This is an alternate driver for UHCI support. It has been commonly + been referred to as the "JE driver". + + The Universal Host Controller Interface is a standard by Intel for + accessing the USB hardware in the PC (which is also called the USB + host controller). If your USB host controller conforms to this + standard, say Y. All recent boards with Intel PCI chipsets (like + intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard. + Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo + Pro II or Apollo Pro 133). + If unsure, say Y. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called uhci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support? CONFIG_USB_OHCI The Open Host Controller Interface is a standard by @@ -8857,6 +8897,30 @@ If you are not a part of a fairly large, distributed network, you probably do not need an automounter, and can say N here. + If you want to use the newer version of autofs with more features, + say N here and select automounter v4. + +Kernel automounter v4 support +CONFIG_AUTOFS4_FS + The automounter is a tool to automatically mount remote filesystems + on demand. This implementation is partially kernel-based to reduce + overhead in the already-mounted case; this is unlike the BSD + automounter (amd), which is a pure user space daemon. + + To use the automounter you need the user-space tools from + ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4 ; you also + want to answer Y to "NFS filesystem support", below. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called autofs4.o. You will need to add "alias autofs autofs4" to + your modules configuration file. + + If you are not a part of a fairly large, distributed network or don't + have a laptop which needs to dynamically reconfigure to the local + network, you probably do not need an automounter, and can say N here. + EFS filesystem support (read only) (EXPERIMENTAL) CONFIG_EFS_FS EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk @@ -10987,20 +11051,6 @@ You can say M here to compile this driver as a module; the module is called sb.o. -Generic OPL2/OPL3 FM synthesizer support -CONFIG_SOUND_ADLIB - Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering Y is usually a safe and recommended choice, however some - cards may have software (TSR) FM emulation. Enabling FM support with - these cards may cause trouble (I don't currently know of any such - cards, however). - - Please read the file Documentation/sound/OPL3 if your card has an - OPL3 chip. - - If unsure, say Y. - - #Loopback MIDI device support #CONFIG_SOUND_VMIDI ### @@ -11276,8 +11326,16 @@ FM synthesizer (YM3812/OPL-3) support CONFIG_SOUND_YM3812 - Answer Y here, unless you know you will not need the option. + Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). + Answering Y is usually a safe and recommended choice, however some + cards may have software (TSR) FM emulation. Enabling FM support with + these cards may cause trouble (I don't currently know of any such + cards, however). + Please read the file Documentation/sound/OPL3 if your card has an + OPL3 chip. + If unsure, say Y. + Sun Audio support CONFIG_SUN_AUDIO This is support for the sound cards on Sun workstations. The code @@ -11445,6 +11503,20 @@ differs slightly from OSS/Free, so PLEASE READ Documentation/sound/sonicvibes. +Trident 4DWave DX/NX or SiS 7018 PCI Audio Core +CONFIG_SOUND_TRIDENT + Say Y or M if you have a PCI sound card utilizing the Trident + 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 + built-in. The SiS 7018 PCI Audio Core is embedded in SiS960 + Super South Bridge and SiS540/630 Single Chipset. + + Use lspci -n to find out if your sound card or chipset uses + Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands + for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. + + This driver differs slightly from OSS/Free, so PLEASE READ the + comments at of driver/sound/trident.c + Rockwell WaveArtist CONFIG_SOUND_WAVEARTIST Say Y here to include support for the Rockwell WaveArtist sound @@ -13313,8 +13385,7 @@ and makes it possible to use all existing applications that understands TTY's with an infrared link. Thus you should be able to use application like PPP, minicom and others. Enabling this option - will create two modules called ircomm and ircomm_tty. For more - information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/ + will create two modules called ircomm and ircomm-tty. IrTTY IrDA Device Driver CONFIG_IRTTY_SIR @@ -13364,11 +13435,10 @@ NSC PC87108 IrDA Device Driver CONFIG_NSC_FIR - Say Y here if you want to build support for the NSC PC87108 IrDA - chipset. If you want to compile it as a module, say M here and - read Documentation/modules.txt. This drivers currently only supports - the ACTiSYS IR2000B ISA card and supports SIR, MIR and FIR (4Mbps) - speeds. + Say Y here if you want to build support for the NSC PC87108 and + PC87338 IrDA chipsets. If you want to compile it as a module, say M + here and read Documentation/modules.txt. This driver supports SIR, + MIR and FIR (4Mbps) speeds. Toshiba Type-O IR Port Device Driver CONFIG_TOSHIBA_FIR @@ -13384,7 +13454,7 @@ and read Documentation/modules.txt. The ESI dongle attaches to the normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for ESI dongles you will have to - insert "irattach -d esi" in the /etc/irda/drivers script. + start irattach like this: "irattach -d esi". ACTiSYS IR-220L and IR220L+ dongle CONFIG_ACTISYS_DONGLE @@ -13393,8 +13463,8 @@ say M here and read Documentation/modules.txt. The ACTiSYS dongles attaches to the normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for ACTiSYS - dongles you will have to insert "irattach -d actisys" or - "irattach -d actisys_plus" in the/etc/irda/drivers script. + dongles you will have to start irattach like this: + "irattach -d actisys" or "irattach -d actisys+". Tekram IrMate 210B dongle CONFIG_TEKRAM_DONGLE @@ -13403,7 +13473,7 @@ and read Documentation/modules.txt. The Tekram dongle attaches to the normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for Tekram dongles you will have - to insert "irattach -d tekram" in the /etc/irda/drivers script. + to start irattach like this: "irattach -d tekram". Greenwich GIrBIL dongle CONFIG_GIRBIL_DONGLE @@ -13421,17 +13491,7 @@ Documentation/modules.txt. The Parallax dongle attaches to the normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for Parallax dongles you will have to - insert "irattach -d litelink" in the /etc/irda/drivers script. - -Adaptec Airport 1000 and 2000 dongle -CONFIG_AIRPORT_DONGLE - Say Y here if you want to build support for the Adaptec Airport 1000 - and 2000 dongles. If you want to compile it as a module, say M here - and read Documentation/modules.txt. The module will be called - airport.o. The Airport dongle attaches to the normal 9-pin serial - port connector, and can currently only be used by IrTTY. To activate - support for Airport dongles you will have to insert "irattach -d - airport" in the /etc/irda/drivers script. + start irattach like this "irattach -d litelink". VME (Motorola and BVM) support CONFIG_VME @@ -13549,6 +13609,7 @@ The kHTTPd is experimental. Be careful when using it on a production machine. Also note that kHTTPd doesn't support virtual servers yet. +# I2C support CONFIG_I2C I2C (pronounce: I-square-C) is a slow bus protocol developed by @@ -13601,7 +13662,6 @@ files, usually found in the /dev directory on your system. They make it possible to have user-space programs use the I2C bus. -# # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, # Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Wed Jan 26 21:24:41 2000 +++ new/linux/MAINTAINERS Mon Jan 31 19:13:03 2000 @@ -456,6 +456,41 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +IEEE 1394 SUBSYSTEM +P: Andreas Bombe +M: andreas.bombe@munich.netsurf.de +L: linux1394-devel@eclipt.uni-klu.ac.at +W: http://eclipt.uni-klu.ac.at/ieee1394 +S: Maintained + +IEEE 1394 AIC5800 DRIVER +P: Emanuel Pirker +M: epirker@edu.uni-klu.ac.at +L: linux1394-devel@eclipt.uni-klu.ac.at +W: http://eclipt.uni-klu.ac.at/ieee1394 +S: Maintained + +IEEE 1394 OHCI DRIVER +P: Sebastien Rougeaux +M: sebastien.rougeaux@anu.edu.au +L: linux1394-devel@eclipt.uni-klu.ac.at +W: http://eclipt.uni-klu.ac.at/ieee1394 +S: Maintained + +IEEE 1394 PCILYNX DRIVER +P: Andreas Bombe +M: andreas.bombe@munich.netsurf.de +L: linux1394-devel@eclipt.uni-klu.ac.at +W: http://eclipt.uni-klu.ac.at/ieee1394 +S: Maintained + +IEEE 1394 RAW I/O DRIVER +P: Andreas Bombe +M: andreas.bombe@munich.netsurf.de +L: linux1394-devel@eclipt.uni-klu.ac.at +W: http://eclipt.uni-klu.ac.at/ieee1394 +S: Maintained + INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT P: Ingo Molnar M: mingo@redhat.com @@ -935,6 +970,12 @@ L: linux-net@vger.rutgers.edu L: linux-tr@linuxtr.net S: Maintained + +TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE +P: Ollie Lho +M: ollie@sis.com.tw +L: linux-kernel@vger.rutgers.edu +S: Supported TMS380 TOKEN-RING NETWORK DRIVER P: Adam Fritzler diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Wed Jan 26 22:16:04 2000 +++ new/linux/Makefile Sat Jan 29 00:11:36 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 41 +SUBLEVEL = 42 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -ur --new-file old/linux/arch/alpha/lib/csum_ipv6_magic.S new/linux/arch/alpha/lib/csum_ipv6_magic.S --- old/linux/arch/alpha/lib/csum_ipv6_magic.S Mon Jan 12 23:49:36 1998 +++ new/linux/arch/alpha/lib/csum_ipv6_magic.S Tue Feb 1 08:41:13 2000 @@ -4,7 +4,7 @@ * * unsigned short csum_ipv6_magic(struct in6_addr *saddr, * struct in6_addr *daddr, - * __u16 len, + * __u32 len, * unsigned short proto, * unsigned int csum); */ @@ -18,54 +18,74 @@ ldq $0,0($16) # e0 : load src & dst addr words zapnot $20,15,$20 # .. e1 : zero extend incoming csum - extwh $18,7,$4 # e0 : byte swap len & proto while we wait + extqh $18,7,$4 # e0 : byte swap len & proto while we wait ldq $1,8($16) # .. e1 : - extbl $18,1,$18 # e0 : + + extbl $18,1,$5 # e0 : ldq $2,0($17) # .. e1 : - extwh $19,7,$5 # e0 : + extbl $18,2,$6 # e0 : ldq $3,8($17) # .. e1 : - extbl $19,1,$19 # e0 : - or $18,$4,$18 # .. e1 : - addq $20,$0,$20 # e0 : begin summing the words - or $19,$5,$19 # .. e1 : - sll $18,48,$18 # e0 : + + extbl $18,3,$18 # e0 : + sra $4,32,$4 # e0 : + sll $5,16,$5 # e0 : + addq $20,$0,$20 # .. e1 : begin summing the words + + sll $6,8,$6 # e0 : cmpult $20,$0,$0 # .. e1 : + extwh $19,7,$7 # e0 : + or $4,$18,$18 # .. e1 : + + extbl $19,1,$19 # e0 : + or $5,$6,$5 # .. e1 : + or $18,$5,$18 # e0 : len complete + or $19,$7,$19 # .. e1 : + sll $19,48,$19 # e0 : addq $20,$1,$20 # .. e1 : - sra $18,32,$18 # e0 : len complete - cmpult $20,$1,$1 # .. e1 : sra $19,32,$19 # e0 : proto complete + cmpult $20,$1,$1 # .. e1 : + + nop # e0 : addq $20,$2,$20 # .. e1 : cmpult $20,$2,$2 # e0 : addq $20,$3,$20 # .. e1 : + cmpult $20,$3,$3 # e0 : addq $20,$18,$20 # .. e1 : cmpult $20,$18,$18 # e0 : addq $20,$19,$20 # .. e1 : + cmpult $20,$19,$19 # e0 : addq $0,$1,$0 # .. e1 : merge the carries back into the csum addq $2,$3,$2 # e0 : addq $18,$19,$18 # .. e1 : + addq $0,$2,$0 # e0 : addq $20,$18,$20 # .. e1 : addq $0,$20,$0 # e0 : unop # : + extwl $0,2,$2 # e0 : begin folding the 64-bit value zapnot $0,3,$3 # .. e1 : extwl $0,4,$1 # e0 : addq $2,$3,$3 # .. e1 : + extwl $0,6,$0 # e0 : addq $3,$1,$3 # .. e1 : addq $0,$3,$0 # e0 : unop # : + extwl $0,2,$1 # e0 : fold 18-bit value zapnot $0,3,$0 # .. e1 : addq $0,$1,$0 # e0 : unop # : + extwl $0,2,$1 # e0 : fold 17-bit value zapnot $0,3,$0 # .. e1 : addq $0,$1,$0 # e0 : not $0,$0 # e1 : and compliment. + zapnot $0,3,$0 # e0 : ret # .. e1 : diff -ur --new-file old/linux/arch/i386/config.in new/linux/arch/i386/config.in --- old/linux/arch/i386/config.in Tue Jan 25 23:13:46 2000 +++ new/linux/arch/i386/config.in Sat Jan 29 04:36:22 2000 @@ -22,7 +22,7 @@ 586/K5/5x86/6x86 CONFIG_M586 \ Pentium/TSC CONFIG_M586TSC \ PPro/6x86MX CONFIG_M686 \ - K6/II/II CONFIG_MK6 \ + K6/II/III CONFIG_MK6 \ Athlon CONFIG_MK7" PPro # # Define implied options from the CPU selection here diff -ur --new-file old/linux/arch/i386/kernel/smpboot.c new/linux/arch/i386/kernel/smpboot.c --- old/linux/arch/i386/kernel/smpboot.c Thu Jan 20 18:51:42 2000 +++ new/linux/arch/i386/kernel/smpboot.c Tue Feb 1 01:33:22 2000 @@ -710,7 +710,8 @@ static void smp_tune_scheduling (void) { - unsigned long cachesize; + unsigned long cachesize; /* kB */ + unsigned long bandwidth = 350; /* MB/s */ /* * Rough estimation for SMP scheduling, this is the number of * cycles it takes for a fully memory-limited process to flush @@ -731,10 +732,12 @@ return; } else { cachesize = boot_cpu_data.x86_cache_size; - if (cachesize == -1) - cachesize = 8; /* Pentiums */ + if (cachesize == -1) { + cachesize = 16; /* Pentiums, 2x8kB cache */ + bandwidth = 100; + } - cacheflush_time = cpu_hz/1024*cachesize/5000; + cacheflush_time = (cpu_hz>>20) * (cachesize<<10) / bandwidth; } printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", diff -ur --new-file old/linux/arch/m68k/amiga/amiints.c new/linux/arch/m68k/amiga/amiints.c --- old/linux/arch/m68k/amiga/amiints.c Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/amiga/amiints.c Mon Jan 31 19:32:53 2000 @@ -364,7 +364,7 @@ intena = ami_intena_vals[irq]; custom.intreq = intena; - /* serve first fast handlers - there can only be one of these */ + /* serve fast handler if present - there can only be one of these */ node = ami_irq_list[irq]; /* @@ -392,7 +392,11 @@ */ custom.intena = intena; save_flags(flags); +#if 0 /* def CPU_M68060_ONLY */ sti(); +#else + restore_flags((flags & ~0x0700) | (fp->sr & 0x0700)); +#endif slow_nodes = node; for (;;) { diff -ur --new-file old/linux/arch/m68k/atari/debug.c new/linux/arch/m68k/atari/debug.c --- old/linux/arch/m68k/atari/debug.c Thu Aug 26 21:42:31 1999 +++ new/linux/arch/m68k/atari/debug.c Mon Jan 31 19:32:53 2000 @@ -311,10 +311,6 @@ void __init atari_debug_init(void) { -#ifdef CONFIG_KGDB - /* the m68k_debug_device is used by the GDB stub, do nothing here */ - return; -#endif if (!strcmp( m68k_debug_device, "ser" )) { /* defaults to ser2 for a Falcon and ser1 otherwise */ strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); diff -ur --new-file old/linux/arch/m68k/bvme6000/config.c new/linux/arch/m68k/bvme6000/config.c --- old/linux/arch/m68k/bvme6000/config.c Wed Jan 26 21:44:20 2000 +++ new/linux/arch/m68k/bvme6000/config.c Mon Jan 31 19:32:53 2000 @@ -132,6 +132,7 @@ bvme6000_set_vectors(); #endif + mach_max_dma_address = 0xffffffff; mach_sched_init = bvme6000_sched_init; mach_keyb_init = bvme6000_keyb_init; mach_kbdrate = bvme6000_kbdrate; diff -ur --new-file old/linux/arch/m68k/kernel/signal.c new/linux/arch/m68k/kernel/signal.c --- old/linux/arch/m68k/kernel/signal.c Wed Jan 26 21:44:20 2000 +++ new/linux/arch/m68k/kernel/signal.c Mon Jan 31 19:32:53 2000 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1048,6 +1049,7 @@ info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; + info.si_uid16 = high2lowuid(current->p_pptr->uid); } /* If the (new) signal is now blocked, requeue it. */ diff -ur --new-file old/linux/arch/m68k/kernel/traps.c new/linux/arch/m68k/kernel/traps.c --- old/linux/arch/m68k/kernel/traps.c Wed Jan 26 21:44:20 2000 +++ new/linux/arch/m68k/kernel/traps.c Mon Jan 31 19:32:53 2000 @@ -37,9 +37,6 @@ #include #include #include -#ifdef CONFIG_KGDB -#include -#endif /* assembler routines */ asmlinkage void system_call(void); @@ -766,11 +763,6 @@ static void dump_stack(struct frame *fp) { -#ifdef CONFIG_KGDB - /* This will never return to here, if kgdb has been initialized. And if - * it returns from there, then to where the error happened... */ - enter_kgdb( &fp->ptregs ); -#else unsigned long *stack, *endstack, addr, module_start, module_end; extern char _start, _etext; int i; @@ -868,15 +860,10 @@ for (i = 0; i < 10; i++) printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); printk ("\n"); -#endif } void bad_super_trap (struct frame *fp) { -#ifdef CONFIG_KGDB - /* Save the register dump if we'll enter kgdb anyways */ - if (!kgdb_initialized) { -#endif console_verbose(); if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) printk ("*** %s *** FORMAT=%X\n", @@ -906,9 +893,6 @@ fp->ptregs.pc); } printk ("Current process id is %d\n", current->pid); -#ifdef CONFIG_KGDB - } -#endif die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); } @@ -1037,10 +1021,6 @@ if (!(fp->sr & PS_S)) return; -#ifdef CONFIG_KGDB - /* Save the register dump if we'll enter kgdb anyways */ - if (!kgdb_initialized) { -#endif console_verbose(); printk("%s: %08x\n",str,nr); printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", @@ -1052,9 +1032,6 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, PAGE_SIZE+(unsigned long)current); -#ifdef CONFIG_KGDB - } -#endif dump_stack((struct frame *)fp); do_exit(SIGSEGV); } diff -ur --new-file old/linux/arch/m68k/mac/debug.c new/linux/arch/m68k/mac/debug.c --- old/linux/arch/m68k/mac/debug.c Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/mac/debug.c Mon Jan 31 19:32:53 2000 @@ -397,10 +397,6 @@ void __init mac_debug_init(void) { -#ifdef CONFIG_KGDB - /* the m68k_debug_device is used by the GDB stub, do nothing here */ - return; -#endif #ifdef DEBUG_SERIAL if ( !strcmp( m68k_debug_device, "ser" ) || !strcmp( m68k_debug_device, "ser1" )) { diff -ur --new-file old/linux/arch/m68k/mvme147/config.c new/linux/arch/m68k/mvme147/config.c --- old/linux/arch/m68k/mvme147/config.c Wed Jan 26 21:44:21 2000 +++ new/linux/arch/m68k/mvme147/config.c Mon Jan 31 19:32:53 2000 @@ -101,6 +101,7 @@ void __init config_mvme147(void) { + mach_max_dma_address = 0x01000000; mach_sched_init = mvme147_sched_init; mach_keyb_init = mvme147_keyb_init; mach_kbdrate = mvme147_kbdrate; diff -ur --new-file old/linux/arch/m68k/mvme16x/config.c new/linux/arch/m68k/mvme16x/config.c --- old/linux/arch/m68k/mvme16x/config.c Fri Jan 28 17:04:58 2000 +++ new/linux/arch/m68k/mvme16x/config.c Mon Jan 31 19:32:53 2000 @@ -145,6 +145,7 @@ p_bdid p = &mvme_bdid; char id[40]; + mach_max_dma_address = 0xffffffff; mach_sched_init = mvme16x_sched_init; mach_keyb_init = mvme16x_keyb_init; mach_kbdrate = mvme16x_kbdrate; diff -ur --new-file old/linux/arch/sparc/Makefile new/linux/arch/sparc/Makefile --- old/linux/arch/sparc/Makefile Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/Makefile Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.44 1999/08/19 06:22:20 jj Exp $ +# $Id: Makefile,v 1.45 2000/01/29 01:08:48 anton Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -43,14 +43,6 @@ LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a - -ifdef CONFIG_AP1000 -SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp -CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \ - $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) -DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a -CFLAGS := $(CFLAGS) -D__MPP__=1 -endif # This one has to come last SUBDIRS += arch/sparc/boot diff -ur --new-file old/linux/arch/sparc/ap1000/Makefile new/linux/arch/sparc/ap1000/Makefile --- old/linux/arch/sparc/ap1000/Makefile Mon Dec 20 23:43:40 1999 +++ new/linux/arch/sparc/ap1000/Makefile Thu Jan 1 01:00:00 1970 @@ -1,20 +0,0 @@ -# Makefile for the AP1000 files in the Linux kernel -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# - -.S.s: - $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o - -all: ap1000lib.o - -O_TARGET := ap1000lib.o -O_OBJS := bnet.o timer.o util.o dma.o kgdb.o irq.o \ - msc.o hw.o tnet.o sync.o mpp.o \ - apmmu.o aplib.o approm.o - -include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/sparc/ap1000/apinline.h new/linux/arch/sparc/ap1000/apinline.h --- old/linux/arch/sparc/ap1000/apinline.h Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/apinline.h Thu Jan 1 01:00:00 1970 @@ -1,86 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* inline utilities to support the AP1000 code */ - -#if 0 -/* MMU bypass access */ - -static inline unsigned long phys_9_in(unsigned long paddr) -{ - unsigned long word; - - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (word) : - "r" (paddr), "i" (0x29) : - "memory"); - return word; -} - -static inline void phys_9_out(unsigned long paddr, unsigned long word) -{ - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (word), "r" (paddr), "i" (0x29) : - "memory"); -} - -static inline unsigned long phys_b_in(unsigned long paddr) -{ - unsigned long word; - - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (word) : - "r" (paddr), "i" (0x2b) : - "memory"); - return word; -} - -static inline void phys_b_out(unsigned long paddr, unsigned long word) -{ - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (word), "r" (paddr), "i" (0x2b) : - "memory"); -} - -static inline unsigned long phys_c_in(unsigned long paddr) -{ - unsigned long word; - - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (word) : - "r" (paddr), "i" (0x2b) : - "memory"); - return word; -} - -static inline void phys_c_out(unsigned long paddr, unsigned long word) -{ - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (word), "r" (paddr), "i" (0x2b) : - "memory"); -} - -#undef BIF_IN -#undef BIF_OUT -#undef DMA_IN -#undef DMA_OUT -#undef MSC_IN -#undef MSC_OUT -#undef MC_IN -#undef MC_OUT - -#define BIF_IN(reg) phys_9_in(reg) -#define BIF_OUT(reg,v) phys_9_out(reg,v) -#define DMA_IN(reg) phys_9_in(reg) -#define DMA_OUT(reg,v) phys_9_out(reg,v) -#define MC_IN(reg) phys_b_in((reg) - MC_BASE0) -#define MC_OUT(reg,v) phys_b_out((reg) - MC_BASE0,v) -#define MSC_IN(reg) phys_c_in((reg) - MSC_BASE0) -#define MSC_OUT(reg,v) phys_c_out((reg) - MSC_BASE0,v) -#endif - - diff -ur --new-file old/linux/arch/sparc/ap1000/aplib.c new/linux/arch/sparc/ap1000/aplib.c --- old/linux/arch/sparc/ap1000/aplib.c Tue Jul 6 05:35:17 1999 +++ new/linux/arch/sparc/ap1000/aplib.c Thu Jan 1 01:00:00 1970 @@ -1,496 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ - -/* kernel based aplib. - - This was initially implemented in user space, but we eventually - relented when we discovered some really nasty MSC hardware bugs and - decided to disallow access to the device registers by users. Pity :-( - - Andrew Tridgell, November 1996 -*/ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - #include -#include -#include -#include - - -extern int *tnet_rel_cid_table; -extern unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy; - - -/* this is used to stop the task hogging the MSC while paging in data */ -static inline void page_in(char *addr,long size) -{ - unsigned sum = 0; - while (size > 0) { - sum += *(volatile char *)addr; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } -} - - -/* this sets up the aplib structures using info passed in from user space - it should only be called once, and should be the first aplib call - it should be followed by APLIB_SYNC - */ -static inline int aplib_init(struct aplib_init *init) -{ - struct aplib_struct *aplib; - int error,i; - int old_uid; - - error = verify_area(VERIFY_READ,init,sizeof(*init)); - if (error) return error; - error = verify_area(VERIFY_READ,init->phys_cells, - sizeof(int)*init->numcells); - if (error) return error; - error = verify_area(VERIFY_WRITE, - init->ringbuffer, - init->ringbuf_size * sizeof(int)); - if (error) return error; - error = verify_area(VERIFY_WRITE, - (char *)APLIB_PAGE_BASE, - APLIB_PAGE_LEN); - if (error) return error; - - if (!MPP_IS_PAR_TASK(current->taskid)) - return -EINVAL; - - if (current->aplib) - return -EINVAL; - - aplib = current->aplib = (struct aplib_struct *)APLIB_PAGE_BASE; - - /* lock the aplib structure in memory */ - old_uid = current->euid; - current->euid = 0; - memset(aplib,0,APLIB_PAGE_LEN); - error = sys_mlock(aplib,APLIB_PAGE_LEN); - current->euid = old_uid; - if (error) { - printk("mlock1 failed\n"); - return error; - } - - /* lock the ringbuffer in memory */ - old_uid = current->euid; - current->euid = 0; - memset(init->ringbuffer,0,init->ringbuf_size*4); - error = sys_mlock(init->ringbuffer,init->ringbuf_size*4); - current->euid = old_uid; - if (error) { - printk("mlock2 failed\n"); - return error; - } - - aplib->ringbuf = init->ringbuffer; - aplib->ringbuf_size = init->ringbuf_size; - aplib->numcells = init->numcells; - aplib->cid = init->cid; - aplib->tid = current->taskid; - aplib->numcells_x = init->numcells_x; - aplib->numcells_y = init->numcells_y; - aplib->cidx = init->cid % init->numcells_x; - aplib->cidy = init->cid / init->numcells_x; - - aplib->physical_cid = (unsigned *)(aplib+1); - aplib->rel_cid = aplib->physical_cid + init->numcells; - - if ((char *)(aplib->rel_cid + init->numcells) > - (char *)(APLIB_PAGE_BASE + APLIB_PAGE_LEN)) { - return -ENOMEM; - } - - memcpy(aplib->physical_cid,init->phys_cells, - sizeof(int)*init->numcells); - - /* initialise the relative cid table */ - for (i=0;inumcells;i++) - aplib->rel_cid[i] = - tnet_rel_cid_table[aplib->physical_cid[i]]; - - return 0; -} - - -/* n == which sync line (ignored) - returns logical or of the stat values across the cells (1 bit resolution) - - This has to be done very carefully as the tasks can startup on the cells - in any order, so we don't know which tasks have started up when this - is called -*/ -static inline int aplib_sync(int n,int stat) -{ - struct aplib_struct *aplib = current->aplib; - static int sync_flags[MPP_NUM_TASKS]; - int i,err; - int tsk = current->taskid; - - stat &= 1; - - if (aplib->numcells < 2) - return stat; - - tsk -= MPP_TASK_BASE; - - if (aplib->cid == 0) { - if ((err=wait_on_int(&sync_flags[tsk], - aplib->numcells-1,5))) - return err; - sync_flags[tsk] = 0; - if (aplib->numcells == _ncel) { - ap_bput(0,0,0,(u_long)&sync_flags[tsk],0); - } else { - for (i=1;inumcells;i++) - ap_put(aplib->physical_cid[i], - 0,0,0,(u_long)&sync_flags[tsk],0); - } - } else { - ap_put(aplib->physical_cid[0], - 0,0,0,(u_long)&sync_flags[tsk],0); - if ((err=wait_on_int(&sync_flags[tsk],1,5))) - return err; - sync_flags[tsk] = 0; - } - - /* I haven't written the xy_ calls yet ... */ - /* aplib_xy_ior(stat,&stat); */ - - return stat; -} - - - -static inline void _putget(unsigned q, - unsigned rcell, - unsigned *src_addr, - unsigned size,unsigned *dest_addr, - unsigned *dest_flag,unsigned *src_flag) -{ - unsigned flags; - volatile unsigned *entry = (volatile unsigned *)q; - - save_flags(flags); cli(); - - *entry = rcell; - *entry = size; - *entry = (unsigned)dest_addr; - *entry = 0; - *entry = (unsigned)dest_flag; - *entry = (unsigned)src_flag; - *entry = (unsigned)src_addr; - *entry = 0; - - restore_flags(flags); -} - - -/* a basic put() operation. Note the avoidance of odd word boundaries - and transfers sizes beyond what the hardware can deal with */ -static inline int aplib_put(struct aplib_putget *put) -{ - int error; - struct aplib_struct *aplib = current->aplib; - - error = verify_area(VERIFY_WRITE,put,sizeof(*put)); - if (error) return error; - - if (put->cid >= aplib->numcells) - return -EINVAL; - - do { - int n; - - if (put->size && (((unsigned)put->src_addr) & 4)) { - n = 1; - } else if (put->size > MAX_PUT_SIZE) { - n = MAX_PUT_SIZE; - } else { - n = put->size; - } - - put->size -= n; - - page_in((char *)put->src_addr,n<<2); - - _putget(MSC_PUT_QUEUE, - aplib->rel_cid[put->cid], - put->src_addr, - n, - put->dest_addr, - put->size?0:put->dest_flag, - put->size?0:put->src_flag); - - put->dest_addr += n; - put->src_addr += n; - } while (put->size); - - if (put->ack) { - aplib->ack_request++; - _putget(MSC_GET_QUEUE, - aplib->rel_cid[put->cid], - 0, 0, 0, - &aplib->ack_flag, 0); - } - - return 0; -} - - -/* a basic get() operation */ -static inline int aplib_get(struct aplib_putget *get) -{ - struct aplib_struct *aplib = current->aplib; - int error = verify_area(VERIFY_WRITE,get,sizeof(*get)); - if (error) return error; - - if (get->cid >= aplib->numcells) - return -EINVAL; - - do { - int n; - - if (get->size && (((unsigned)get->src_addr) & 4)) { - n = 1; - } else if (get->size > MAX_PUT_SIZE) { - n = MAX_PUT_SIZE; - } else { - n = get->size; - } - - get->size -= n; - - page_in((char *)get->dest_addr,n<<2); - - _putget(MSC_GET_QUEUE, - aplib->rel_cid[get->cid], - get->src_addr, - n, - get->dest_addr, - get->size?0:get->dest_flag, - get->size?0:get->src_flag); - - get->dest_addr += n; - get->src_addr += n; - } while (get->size); - - return 0; -} - - -/* we have received a protocol message - now do the get - This function is called from interrupt level with interrupts - disabled - - note that send->size is now in words -*/ -void aplib_bigrecv(unsigned *msgp) -{ - struct aplib_struct *aplib; - struct aplib_send *send = (struct aplib_send *)(msgp+2); - unsigned tid = (msgp[1]&0x3FF); - unsigned cid = (msgp[0]>>22)&0x1FF; - unsigned octx, ctx; - struct task_struct *tsk; - unsigned room; - - tsk = task[tid]; - if (!tsk || !tsk->aplib) - return; - - octx = apmmu_get_context(); - ctx = MPP_TASK_TO_CTX(tid); - if (octx != ctx) - apmmu_set_context(ctx); - aplib = tsk->aplib; - - if (aplib->write_pointer < aplib->read_pointer) - room = aplib->read_pointer - (aplib->write_pointer+1); - else - room = aplib->ringbuf_size - - ((aplib->write_pointer+1)-aplib->read_pointer); - - if (room < (send->size+2)) { - send_sig(SIGLOST,tsk,1); - goto finished; - } - - aplib->ringbuf[aplib->write_pointer++] = send->info1; - aplib->ringbuf[aplib->write_pointer++] = send->info2; - - /* now finally do the get() */ - _putget(MSC_GET_QUEUE, - aplib->rel_cid[cid], - send->src_addr, - send->size, - &aplib->ringbuf[aplib->write_pointer], - &aplib->rbuf_flag2, - send->flag_addr); - - aplib->write_pointer += send->size; - if (aplib->write_pointer >= aplib->ringbuf_size) - aplib->write_pointer -= aplib->ringbuf_size; - -finished: - if (octx != ctx) - apmmu_set_context(octx); -} - - -/* note the 8 byte alignment fix for the MSC bug */ -static inline int aplib_send(struct aplib_send *send) -{ - struct aplib_struct *aplib = current->aplib; - int wordSize; - int byteAlign, byteFix; - u_long src; - u_long info1, info2; - volatile unsigned *q = (volatile unsigned *)MSC_SEND_QUEUE_S; - extern long system_recv_flag; - int error; - unsigned flags, rcell; - unsigned flag_ptr; - - error = verify_area(VERIFY_WRITE,send,sizeof(*send)); - if (error) return error; - - if (send->cid >= aplib->numcells) - return -EINVAL; - - if (send->tag == RBUF_SYSTEM || send->tag == RBUF_BIGSEND) - return -EINVAL; - - error = verify_area(VERIFY_READ,(char *)send->src_addr,send->size); - if (error) return error; - - page_in((char *)send->src_addr,send->size); - - rcell = aplib->rel_cid[send->cid]; - - byteAlign = send->src_addr & 0x3; - byteFix = send->size & 0x3; - - wordSize = (send->size + byteAlign + 3) >> 2; - - src = send->src_addr & ~3; - - /* this handles the MSC alignment bug */ - if (wordSize > 1 && - (src & 4)) { - info1 |= 0x80000000; - src -= 4; - wordSize++; - } - - info1 = (aplib->cid<<22) | (byteFix<<20) | wordSize; - info2 = (send->tag<<28) | (byteAlign<<26) | - (send->type<<10) | aplib->tid; - flag_ptr = (unsigned)&send->flag; - - if (send->size > SMALL_SEND_THRESHOLD) { - send->info1 = info1; - send->info2 = info2; - send->size = wordSize; - send->src_addr = src; - send->flag_addr = (unsigned)&send->flag; - flag_ptr = 0; - - wordSize = sizeof(*send)>>2; - src = (unsigned)send; - - info1 = (aplib->cid<<22) | wordSize; - info2 = (RBUF_BIGSEND<<28) | aplib->tid; - } - - save_flags(flags); cli(); - - *q = rcell; - *q = wordSize; - *q = (u_long)&system_recv_flag; - *q = flag_ptr; - *q = (u_long)src; - *q = 0; - *q = info1; - *q = info2; - - restore_flags(flags); - - return 0; -} - - -static inline int aplib_probe(void) -{ - tnet_check_completion(); - return 0; -} - -static inline int aplib_poll(unsigned counter) -{ - struct aplib_struct *aplib = current->aplib; - - while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) { - tnet_check_completion(); - if (current->need_resched) - break; - if (signal_pending(current)) break; - } - return 0; -} - -int sys_aplib(unsigned call,int a1,int a2,int a3,int a4) -{ - - if (!current->aplib && call != APLIB_INIT) - return -EINVAL; - - switch (call) { - case APLIB_INIT: - return aplib_init((struct aplib_init *)a1); - - case APLIB_SYNC: - return aplib_sync(a1,a2); - - case APLIB_PUT: - return aplib_put((struct aplib_putget *)a1); - - case APLIB_GET: - return aplib_get((struct aplib_putget *)a1); - - case APLIB_SEND: - return aplib_send((struct aplib_send *)a1); - - case APLIB_PROBE: - return aplib_probe(); - - case APLIB_POLL: - return aplib_poll((unsigned)a1); - } - - return -EINVAL; -} - - diff -ur --new-file old/linux/arch/sparc/ap1000/apmmu.c new/linux/arch/sparc/ap1000/apmmu.c --- old/linux/arch/sparc/ap1000/apmmu.c Thu Jan 13 21:03:00 2000 +++ new/linux/arch/sparc/ap1000/apmmu.c Thu Jan 1 01:00:00 1970 @@ -1,1144 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * apmmu.c: mmu routines for the AP1000 - * - * based on srmmu.c - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -extern void mc_tlb_flush_all(void); - -static void poke_viking(void); -static void viking_flush_tlb_page_for_cbit)(unsigned long page); - -static struct apmmu_stats { - int invall; - int invpg; - int invrnge; - int invmm; -} module_stats; - -static char *apmmu_name; - -static ctxd_t *apmmu_ctx_table_phys; -static ctxd_t *apmmu_context_table; - -static unsigned long ap_mem_size; -static unsigned long mempool; - - -static inline unsigned long apmmu_v2p(unsigned long vaddr) -{ - if (KERNBASE <= vaddr && - (KERNBASE + ap_mem_size > vaddr)) { - return (vaddr - KERNBASE); - } - return 0xffffffffUL; -} - -static inline unsigned long apmmu_p2v(unsigned long paddr) -{ - if (ap_mem_size > paddr) - return (paddr + KERNBASE); - return 0xffffffffUL; -} - -/* In general all page table modifications should use the V8 atomic - * swap instruction. This insures the mmu and the cpu are in sync - * with respect to ref/mod bits in the page tables. - */ -static inline unsigned long apmmu_swap(unsigned long *addr, unsigned long value) -{ - /* the AP1000 has its memory on bus 8, not 0 like suns do */ - if ((value&0xF0000000) == 0) - value |= MEM_BUS_SPACE<<28; - __asm__ __volatile__("swap [%2], %0\n\t" : - "=&r" (value) : - "0" (value), "r" (addr)); - return value; -} - -/* Functions really use this, not apmmu_swap directly. */ -#define apmmu_set_entry(ptr, newentry) \ - apmmu_swap((unsigned long *) (ptr), (newentry)) - - -/* The very generic APMMU page table operations. */ -static unsigned int apmmu_pmd_align(unsigned int addr) { return APMMU_PMD_ALIGN(addr); } -static unsigned int apmmu_pgdir_align(unsigned int addr) { return APMMU_PGDIR_ALIGN(addr); } - -static inline int apmmu_device_memory(unsigned long x) -{ - return ((x & 0xF0000000) != 0); -} - -static unsigned long apmmu_pgd_page(pgd_t pgd) -{ return apmmu_device_memory(pgd_val(pgd))?~0:apmmu_p2v((pgd_val(pgd) & APMMU_PTD_PMASK) << 4); } - -static unsigned long apmmu_pmd_page(pmd_t pmd) -{ return apmmu_device_memory(pmd_val(pmd))?~0:apmmu_p2v((pmd_val(pmd) & APMMU_PTD_PMASK) << 4); } - -static unsigned long apmmu_pte_page(pte_t pte) -{ return apmmu_device_memory(pte_val(pte))?~0:apmmu_p2v((pte_val(pte) & APMMU_PTE_PMASK) << 4); } - -static int apmmu_pte_none(pte_t pte) -{ return !(pte_val(pte) & 0xFFFFFFF); } - -static int apmmu_pte_present(pte_t pte) -{ return ((pte_val(pte) & APMMU_ET_MASK) == APMMU_ET_PTE); } - -static void apmmu_pte_clear(pte_t *ptep) { set_pte(ptep, __pte(0)); } - -static int apmmu_pmd_none(pmd_t pmd) -{ return !(pmd_val(pmd) & 0xFFFFFFF); } - -static int apmmu_pmd_bad(pmd_t pmd) -{ return (pmd_val(pmd) & APMMU_ET_MASK) != APMMU_ET_PTD; } - -static int apmmu_pmd_present(pmd_t pmd) -{ return ((pmd_val(pmd) & APMMU_ET_MASK) == APMMU_ET_PTD); } - -static void apmmu_pmd_clear(pmd_t *pmdp) { set_pte((pte_t *)pmdp, __pte(0)); } - -static int apmmu_pgd_none(pgd_t pgd) -{ return !(pgd_val(pgd) & 0xFFFFFFF); } - -static int apmmu_pgd_bad(pgd_t pgd) -{ return (pgd_val(pgd) & APMMU_ET_MASK) != APMMU_ET_PTD; } - -static int apmmu_pgd_present(pgd_t pgd) -{ return ((pgd_val(pgd) & APMMU_ET_MASK) == APMMU_ET_PTD); } - -static void apmmu_pgd_clear(pgd_t * pgdp) { set_pte((pte_t *)pgdp, __pte(0)); } - -static pte_t apmmu_pte_mkwrite(pte_t pte) { return __pte(pte_val(pte) | APMMU_WRITE);} -static pte_t apmmu_pte_mkdirty(pte_t pte) { return __pte(pte_val(pte) | APMMU_DIRTY);} -static pte_t apmmu_pte_mkyoung(pte_t pte) { return __pte(pte_val(pte) | APMMU_REF);} - -/* - * Conversion functions: convert a page and protection to a page entry, - * and a page entry and page directory to the page they refer to. - */ -static pte_t apmmu_mk_pte(unsigned long page, pgprot_t pgprot) -{ return __pte(((apmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); } - -static pte_t apmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot) -{ return __pte(((page) >> 4) | pgprot_val(pgprot)); } - -static pte_t apmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) -{ - return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); -} - -static void apmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ - set_pte((pte_t *)ctxp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pgdp) >> 4))); -} - -static void apmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - set_pte((pte_t *)pgdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pmdp) >> 4))); -} - -static void apmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - set_pte((pte_t *)pmdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) ptep) >> 4))); -} - -static pte_t apmmu_pte_modify(pte_t pte, pgprot_t newprot) -{ - return __pte((pte_val(pte) & APMMU_CHG_MASK) | pgprot_val(newprot)); -} - -/* to find an entry in a top-level page table... */ -static pgd_t *apmmu_pgd_offset(struct mm_struct * mm, unsigned long address) -{ - return mm->pgd + ((address >> APMMU_PGDIR_SHIFT) & (APMMU_PTRS_PER_PGD - 1)); -} - -/* Find an entry in the second-level page table.. */ -static pmd_t *apmmu_pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) apmmu_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1)); -} - -/* Find an entry in the third-level page table.. */ -static pte_t *apmmu_pte_offset(pmd_t * dir, unsigned long address) -{ - return (pte_t *) apmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1)); -} - -/* This must update the context table entry for this process. */ -static void apmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) -{ - if(tsk->mm->context != NO_CONTEXT) { - flush_cache_mm(current->mm); - apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(current->mm); - } -} - - -/* Accessing the MMU control register. */ -static inline unsigned int apmmu_get_mmureg(void) -{ - unsigned int retval; - __asm__ __volatile__("lda [%%g0] %1, %0\n\t" : - "=r" (retval) : - "i" (ASI_M_MMUREGS)); - return retval; -} - -static inline void apmmu_set_mmureg(unsigned long regval) -{ - __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : : - "r" (regval), "i" (ASI_M_MMUREGS) : "memory"); - -} - -static inline void apmmu_set_ctable_ptr(unsigned long paddr) -{ - paddr = ((paddr >> 4) & APMMU_CTX_PMASK); - paddr |= (MEM_BUS_SPACE<<28); - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (paddr), "r" (APMMU_CTXTBL_PTR), - "i" (ASI_M_MMUREGS) : - "memory"); -} - -static inline void apmmu_flush_whole_tlb(void) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : - "r" (0x400), /* Flush entire TLB!! */ - "i" (ASI_M_FLUSH_PROBE) : "memory"); - -} - -/* These flush types are not available on all chips... */ -static inline void apmmu_flush_tlb_ctx(void) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : - "r" (0x300), /* Flush TLB ctx.. */ - "i" (ASI_M_FLUSH_PROBE) : "memory"); - -} - -static inline void apmmu_flush_tlb_region(unsigned long addr) -{ - addr &= APMMU_PGDIR_MASK; - __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : - "r" (addr | 0x200), /* Flush TLB region.. */ - "i" (ASI_M_FLUSH_PROBE) : "memory"); - -} - - -static inline void apmmu_flush_tlb_segment(unsigned long addr) -{ - addr &= APMMU_PMD_MASK; - __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : - "r" (addr | 0x100), /* Flush TLB segment.. */ - "i" (ASI_M_FLUSH_PROBE) : "memory"); - -} - -static inline void apmmu_flush_tlb_page(unsigned long page) -{ - page &= PAGE_MASK; - __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : - "r" (page), /* Flush TLB page.. */ - "i" (ASI_M_FLUSH_PROBE) : "memory"); - -} - -static inline unsigned long apmmu_hwprobe(unsigned long vaddr) -{ - unsigned long retval; - - vaddr &= PAGE_MASK; - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (retval) : - "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); - - return retval; -} - -static inline void apmmu_uncache_page(unsigned long addr) -{ - pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr); - pmd_t *pmdp; - pte_t *ptep; - - if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { - ptep = (pte_t *) pgdp; - } else { - pmdp = apmmu_pmd_offset(pgdp, addr); - if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { - ptep = (pte_t *) pmdp; - } else { - ptep = apmmu_pte_offset(pmdp, addr); - } - } - - set_pte(ptep, __pte((pte_val(*ptep) & ~APMMU_CACHE))); - viking_flush_tlb_page_for_cbit(addr); -} - -static inline void apmmu_recache_page(unsigned long addr) -{ - pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr); - pmd_t *pmdp; - pte_t *ptep; - - if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { - ptep = (pte_t *) pgdp; - } else { - pmdp = apmmu_pmd_offset(pgdp, addr); - if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { - ptep = (pte_t *) pmdp; - } else { - ptep = apmmu_pte_offset(pmdp, addr); - } - } - set_pte(ptep, __pte((pte_val(*ptep) | APMMU_CACHE))); - viking_flush_tlb_page_for_cbit(addr); -} - -static inline unsigned long apmmu_getpage(void) -{ - unsigned long page = get_free_page(GFP_KERNEL); - - return page; -} - -static inline void apmmu_putpage(unsigned long page) -{ - free_page(page); -} - -/* The easy versions. */ -#define NEW_PGD() (pgd_t *) apmmu_getpage() -#define NEW_PMD() (pmd_t *) apmmu_getpage() -#define NEW_PTE() (pte_t *) apmmu_getpage() -#define FREE_PGD(chunk) apmmu_putpage((unsigned long)(chunk)) -#define FREE_PMD(chunk) apmmu_putpage((unsigned long)(chunk)) -#define FREE_PTE(chunk) apmmu_putpage((unsigned long)(chunk)) - -static pte_t *apmmu_get_pte_fast(void) -{ - return (pte_t *)0; -} - -static pmd_t *apmmu_get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -static pgd_t *apmmu_get_pgd_fast(void) -{ - return (pgd_t *)0; -} - -static void apmmu_free_pte_slow(pte_t *pte) -{ -/* TBD */ -} - -static void apmmu_free_pmd_slow(pmd_t *pmd) -{ -/* TBD */ -} - -static void apmmu_free_pgd_slow(pgd_t *pgd) -{ -/* TBD */ -} - - -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. - */ -static void apmmu_pte_free_kernel(pte_t *pte) -{ - FREE_PTE(pte); -} - -static pte_t *apmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1); - if(apmmu_pmd_none(*pmd)) { - pte_t *page = NEW_PTE(); - if(apmmu_pmd_none(*pmd)) { - if(page) { - apmmu_pmd_set(pmd, page); - return page + address; - } - apmmu_pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - FREE_PTE(page); - } - if(apmmu_pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - apmmu_pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - return (pte_t *) apmmu_pmd_page(*pmd) + address; -} - -static void apmmu_pmd_free_kernel(pmd_t *pmd) -{ - FREE_PMD(pmd); -} - -static pmd_t *apmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) -{ - address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1); - if(apmmu_pgd_none(*pgd)) { - pmd_t *page; - page = NEW_PMD(); - if(apmmu_pgd_none(*pgd)) { - if(page) { - pgd_set(pgd, page); - return page + address; - } - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); - return NULL; - } - FREE_PMD(page); - } - if(apmmu_pgd_bad(*pgd)) { - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + address; -} - -static void apmmu_pte_free(pte_t *pte) -{ - FREE_PTE(pte); -} - -static pte_t *apmmu_pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1); - if(apmmu_pmd_none(*pmd)) { - pte_t *page = NEW_PTE(); - if(apmmu_pmd_none(*pmd)) { - if(page) { - apmmu_pmd_set(pmd, page); - return page + address; - } - apmmu_pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - FREE_PTE(page); - } - if(apmmu_pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - apmmu_pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - return ((pte_t *) apmmu_pmd_page(*pmd)) + address; -} - -/* Real three-level page tables on APMMU. */ -static void apmmu_pmd_free(pmd_t * pmd) -{ - FREE_PMD(pmd); -} - -static pmd_t *apmmu_pmd_alloc(pgd_t * pgd, unsigned long address) -{ - address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1); - if(apmmu_pgd_none(*pgd)) { - pmd_t *page = NEW_PMD(); - if(apmmu_pgd_none(*pgd)) { - if(page) { - pgd_set(pgd, page); - return page + address; - } - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); - return NULL; - } - FREE_PMD(page); - } - if(apmmu_pgd_bad(*pgd)) { - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); - return NULL; - } - return (pmd_t *) apmmu_pgd_page(*pgd) + address; -} - -static void apmmu_pgd_free(pgd_t *pgd) -{ - FREE_PGD(pgd); -} - -static pgd_t *apmmu_pgd_alloc(void) -{ - return NEW_PGD(); -} - -static void apmmu_pgd_flush(pgd_t *pgdp) -{ -} - -static void apmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval) -{ - apmmu_set_entry(ptep, pte_val(pteval)); -} - -static void apmmu_quick_kernel_fault(unsigned long address) -{ - printk("Kernel faults at addr=0x%08lx\n", address); - printk("PTE=%08lx\n", apmmu_hwprobe((address & PAGE_MASK))); - die_if_kernel("APMMU bolixed...", current->thread.kregs); -} - -static inline void alloc_context(struct task_struct *tsk) -{ - struct mm_struct *mm = tsk->mm; - struct ctx_list *ctxp; - - if (tsk->taskid >= MPP_TASK_BASE) { - mm->context = MPP_CONTEXT_BASE + (tsk->taskid - MPP_TASK_BASE); - return; - } - - ctxp = ctx_free.next; - if(ctxp != &ctx_free) { - remove_from_ctx_list(ctxp); - add_to_used_ctxlist(ctxp); - mm->context = ctxp->ctx_number; - ctxp->ctx_mm = mm; - return; - } - ctxp = ctx_used.next; - if(ctxp->ctx_mm == current->mm) - ctxp = ctxp->next; - if(ctxp == &ctx_used) - panic("out of mmu contexts"); - flush_cache_mm(ctxp->ctx_mm); - flush_tlb_mm(ctxp->ctx_mm); - remove_from_ctx_list(ctxp); - add_to_used_ctxlist(ctxp); - ctxp->ctx_mm->context = NO_CONTEXT; - ctxp->ctx_mm = mm; - mm->context = ctxp->ctx_number; -} - -static inline void free_context(int context) -{ - struct ctx_list *ctx_old; - - if (context >= MPP_CONTEXT_BASE) - return; /* nothing to do! */ - - ctx_old = ctx_list_pool + context; - remove_from_ctx_list(ctx_old); - add_to_free_ctxlist(ctx_old); -} - - -static void apmmu_switch_to_context(struct task_struct *tsk) -{ - if(tsk->mm->context == NO_CONTEXT) { - alloc_context(tsk); - flush_cache_mm(current->mm); - apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd); - flush_tlb_mm(current->mm); - } - apmmu_set_context(tsk->mm->context); -} - -static char *apmmu_lockarea(char *vaddr, unsigned long len) -{ - return vaddr; -} - -static void apmmu_unlockarea(char *vaddr, unsigned long len) -{ -} - -struct task_struct *apmmu_alloc_task_struct(void) -{ - return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL); -} - -static void apmmu_free_task_struct(struct task_struct *tsk) -{ - kfree(tsk); -} - -static void apmmu_null_func(void) -{ -} - -static inline void mc_tlb_flush_all(void) -{ - unsigned long long *tlb4k; - int i; - - tlb4k = (unsigned long long *)MC_MMU_TLB4K; - for (i = MC_MMU_TLB4K_SIZE/4; i > 0; --i) { - tlb4k[0] = 0; - tlb4k[1] = 0; - tlb4k[2] = 0; - tlb4k[3] = 0; - tlb4k += 4; - } -} - -static inline void mc_tlb_flush_page(unsigned vaddr,int ctx) -{ - if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) { - *(((unsigned long long *)MC_MMU_TLB4K) + ((vaddr>>12)&0xFF)) = 0; - } -} - -static inline void mc_tlb_flush_ctx(int ctx) -{ - unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K; - if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) { - int i; - for (i=0; i> 5) & 0xFFF) == ctx) tlb4k[i] = 0; - } -} - -static inline void mc_tlb_flush_region(unsigned start,int ctx) -{ - mc_tlb_flush_ctx(ctx); -} - -static inline void mc_tlb_flush_segment(unsigned start,int ctx) -{ - mc_tlb_flush_ctx(ctx); -} - -static void viking_flush_tlb_all(void) -{ - module_stats.invall++; - flush_user_windows(); - apmmu_flush_whole_tlb(); - mc_tlb_flush_all(); -} - -static void viking_flush_tlb_mm(struct mm_struct *mm) -{ - int octx; - - module_stats.invmm++; - - if(mm->context != NO_CONTEXT) { - flush_user_windows(); - octx = apmmu_get_context(); - if (octx != mm->context) - apmmu_set_context(mm->context); - apmmu_flush_tlb_ctx(); - mc_tlb_flush_ctx(mm->context); - if (octx != mm->context) - apmmu_set_context(octx); - } -} - -static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) -{ - int octx; - - module_stats.invrnge++; - - if(mm->context != NO_CONTEXT) { - flush_user_windows(); - octx = apmmu_get_context(); - if (octx != mm->context) - apmmu_set_context(mm->context); - if((end - start) < APMMU_PMD_SIZE) { - start &= PAGE_MASK; - while(start < end) { - apmmu_flush_tlb_page(start); - mc_tlb_flush_page(start,mm->context); - start += PAGE_SIZE; - } - } else if((end - start) < APMMU_PGDIR_SIZE) { - start &= APMMU_PMD_MASK; - while(start < end) { - apmmu_flush_tlb_segment(start); - mc_tlb_flush_segment(start,mm->context); - start += APMMU_PMD_SIZE; - } - } else { - start &= APMMU_PGDIR_MASK; - while(start < end) { - apmmu_flush_tlb_region(start); - mc_tlb_flush_region(start,mm->context); - start += APMMU_PGDIR_SIZE; - } - } - if (octx != mm->context) - apmmu_set_context(octx); - } -} - -static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - int octx; - struct mm_struct *mm = vma->vm_mm; - - module_stats.invpg++; - if(mm->context != NO_CONTEXT) { - flush_user_windows(); - octx = apmmu_get_context(); - if (octx != mm->context) - apmmu_set_context(mm->context); - apmmu_flush_tlb_page(page); - mc_tlb_flush_page(page,mm->context); - if (octx != mm->context) - apmmu_set_context(octx); - } -} - -static void viking_flush_tlb_page_for_cbit(unsigned long page) -{ - apmmu_flush_tlb_page(page); - mc_tlb_flush_page(page,apmmu_get_context()); -} - -/* Some dirty hacks to abstract away the painful boot up init. */ -static inline unsigned long apmmu_early_paddr(unsigned long vaddr) -{ - return (vaddr - KERNBASE); -} - -static inline void apmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp) -{ - set_pte((pte_t *)pgdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) pmdp) >> 4)))); -} - -static inline void apmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep) -{ - set_pte((pte_t *)pmdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) ptep) >> 4)))); -} - -static inline unsigned long apmmu_early_pgd_page(pgd_t pgd) -{ - return ((pgd_val(pgd) & APMMU_PTD_PMASK) << 4) + KERNBASE; -} - -static inline unsigned long apmmu_early_pmd_page(pmd_t pmd) -{ - return ((pmd_val(pmd) & APMMU_PTD_PMASK) << 4) + KERNBASE; -} - -static inline pmd_t *apmmu_early_pmd_offset(pgd_t *dir, unsigned long address) -{ - return (pmd_t *) apmmu_early_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1)); -} - -static inline pte_t *apmmu_early_pte_offset(pmd_t *dir, unsigned long address) -{ - return (pte_t *) apmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1)); -} - -static inline void __init apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end) -{ - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - while(start < end) { - pgdp = apmmu_pgd_offset(&init_mm, start); - if(apmmu_pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); - apmmu_early_pgd_set(pgdp, pmdp); - } - pmdp = apmmu_early_pmd_offset(pgdp, start); - if(apmmu_pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE); - apmmu_early_pmd_set(pmdp, ptep); - } - start = (start + APMMU_PMD_SIZE) & APMMU_PMD_MASK; - } -} - - -static void __init make_page(unsigned virt_page, unsigned phys_page, unsigned prot) -{ - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - unsigned start = virt_page<<12; - - pgdp = apmmu_pgd_offset(&init_mm, start); - if(apmmu_pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); - apmmu_early_pgd_set(pgdp, pmdp); - } - pmdp = apmmu_early_pmd_offset(pgdp, start); - if(apmmu_pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE); - apmmu_early_pmd_set(pmdp, ptep); - } - ptep = apmmu_early_pte_offset(pmdp, start); - *ptep = __pte((phys_page<<8) | prot); -} - - -static void __init make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot) -{ - pgd_t *pgdp; - unsigned start = virt_page<<12; - - pgdp = apmmu_pgd_offset(&init_mm, start); - *pgdp = __pgd((phys_page<<8) | prot); -} - - -static void __init ap_setup_mappings(void) -{ - unsigned Srwe = APMMU_PRIV | APMMU_VALID; - unsigned SrweUr = 0x14 | APMMU_VALID; /* weird! */ - - /* LBus */ - make_large_page(0xfb000,0x9fb000,Srwe); - make_large_page(0xff000,0x9ff000,SrweUr); - make_large_page(0xfc000,0x911000,Srwe); - - /* MC Register */ - make_page(0xfa000,0xb00000,SrweUr); - make_page(0xfa001,0xb00001,Srwe); - make_page(0xfa002,0xb00002,Srwe); - make_page(0xfa003,0xb00003,Srwe); - make_page(0xfa004,0xb00004,Srwe); - make_page(0xfa005,0xb00005,Srwe); - make_page(0xfa006,0xb00006,Srwe); - make_page(0xfa007,0xb00007,Srwe); - - /* MSC+ Register */ - make_page(0xfa008,0xc00000,SrweUr); - make_page(0xfa009,0xc00001,Srwe); - make_page(0xfa00a,0xc00002,Srwe); - make_page(0xfa00b,0xc00003,Srwe); - make_page(0xfa00c,0xc00004,Srwe); - make_page(0xfa00d,0xc00005,Srwe); /* RBMPR 0 */ - make_page(0xfa00e,0xc00006,Srwe); /* RBMPR 1 */ - make_page(0xfa00f,0xc00007,Srwe); /* RBMPR 2 */ - - /* user queues */ - make_page(MSC_PUT_QUEUE>>PAGE_SHIFT, 0xa00000,Srwe); - make_page(MSC_GET_QUEUE>>PAGE_SHIFT, 0xa00001,Srwe); - make_page(MSC_SEND_QUEUE>>PAGE_SHIFT, 0xa00040,Srwe); - make_page(MSC_XY_QUEUE>>PAGE_SHIFT, 0xa00640,Srwe); - make_page(MSC_X_QUEUE>>PAGE_SHIFT, 0xa00240,Srwe); - make_page(MSC_Y_QUEUE>>PAGE_SHIFT, 0xa00440,Srwe); - make_page(MSC_XYG_QUEUE>>PAGE_SHIFT, 0xa00600,Srwe); - make_page(MSC_XG_QUEUE>>PAGE_SHIFT, 0xa00200,Srwe); - make_page(MSC_YG_QUEUE>>PAGE_SHIFT, 0xa00400,Srwe); - make_page(MSC_CSI_QUEUE>>PAGE_SHIFT, 0xa02004,Srwe); - make_page(MSC_FOP_QUEUE>>PAGE_SHIFT, 0xa02005,Srwe); - - /* system queues */ - make_page(MSC_PUT_QUEUE_S>>PAGE_SHIFT, 0xa02000,Srwe); /* system put */ - make_page(MSC_CPUT_QUEUE_S>>PAGE_SHIFT, 0xa02020,Srwe); /* system creg put */ - make_page(MSC_GET_QUEUE_S>>PAGE_SHIFT, 0xa02001,Srwe); /* system get */ - make_page(MSC_CGET_QUEUE_S>>PAGE_SHIFT, 0xa02021,Srwe); /* system creg get */ - make_page(MSC_SEND_QUEUE_S>>PAGE_SHIFT, 0xa02040,Srwe); /* system send */ - make_page(MSC_BSEND_QUEUE_S>>PAGE_SHIFT,0xa02640,Srwe); /* system send broad */ - make_page(MSC_XYG_QUEUE_S>>PAGE_SHIFT, 0xa02600,Srwe); /* system put broad */ - make_page(MSC_CXYG_QUEUE_S>>PAGE_SHIFT, 0xa02620,Srwe); /* system put broad */ - - /* Direct queue access entries for refilling the MSC send queue */ - make_page(MSC_SYSTEM_DIRECT>>PAGE_SHIFT, 0xa08000,Srwe); - make_page(MSC_USER_DIRECT>>PAGE_SHIFT, 0xa08001,Srwe); - make_page(MSC_REMOTE_DIRECT>>PAGE_SHIFT, 0xa08002,Srwe); - make_page(MSC_REPLY_DIRECT>>PAGE_SHIFT, 0xa08003,Srwe); - make_page(MSC_REMREPLY_DIRECT>>PAGE_SHIFT, 0xa08004,Srwe); - - /* As above with end-bit set */ - make_page(MSC_SYSTEM_DIRECT_END>>PAGE_SHIFT, 0xa0c000,Srwe); - make_page(MSC_USER_DIRECT_END>>PAGE_SHIFT, 0xa0c001,Srwe); - make_page(MSC_REMOTE_DIRECT_END>>PAGE_SHIFT, 0xa0c002,Srwe); - make_page(MSC_REPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c003,Srwe); - make_page(MSC_REMREPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c004,Srwe); -} - -static void __init map_kernel(void) -{ - int phys; - - /* the AP+ only ever has one bank of memory starting at address 0 */ - ap_mem_size = sp_banks[0].num_bytes; - for (phys=0; phys < sp_banks[0].num_bytes; phys += APMMU_PGDIR_SIZE) - make_large_page((KERNBASE+phys)>>12, - (phys>>12), - APMMU_CACHE|APMMU_PRIV|APMMU_VALID); - init_mm.mmap->vm_start = PAGE_OFFSET; -} - -extern unsigned long free_area_init(unsigned long, unsigned long); -extern unsigned long sparc_context_init(unsigned long, int); - -extern int physmem_mapped_contig; -extern int linux_num_cpus; - -unsigned long __init apmmu_paging_init(unsigned long start_mem, unsigned long end_mem) -{ - int i; - - physmem_mapped_contig = 1; /* for init.c:taint_real_pages() */ - - num_contexts = AP_NUM_CONTEXTS; - mempool = PAGE_ALIGN(start_mem); - memset(swapper_pg_dir, 0, PAGE_SIZE); - - apmmu_allocate_ptable_skeleton(KERNBASE, end_mem); - mempool = PAGE_ALIGN(mempool); - map_kernel(); - ap_setup_mappings(); - - /* the MSC wants this aligned on a 16k boundary */ - apmmu_context_table = - sparc_init_alloc(&mempool, - num_contexts*sizeof(ctxd_t)<0x4000? - 0x4000: - num_contexts*sizeof(ctxd_t)); - apmmu_ctx_table_phys = (ctxd_t *) apmmu_v2p((unsigned long) apmmu_context_table); - for(i = 0; i < num_contexts; i++) - apmmu_ctxd_set(&apmmu_context_table[i], swapper_pg_dir); - - start_mem = PAGE_ALIGN(mempool); - - flush_cache_all(); - apmmu_set_ctable_ptr((unsigned long) apmmu_ctx_table_phys); - flush_tlb_all(); - poke_viking(); - - /* on the AP we don't put the top few contexts into the free - context list as these are reserved for parallel tasks */ - start_mem = sparc_context_init(start_mem, MPP_CONTEXT_BASE); - start_mem = free_area_init(start_mem, end_mem); - - return PAGE_ALIGN(start_mem); -} - -static int apmmu_mmu_info(char *buf) -{ - return sprintf(buf, - "MMU type\t: %s\n" - "invall\t\t: %d\n" - "invmm\t\t: %d\n" - "invrnge\t\t: %d\n" - "invpg\t\t: %d\n" - "contexts\t: %d\n" - , apmmu_name, - module_stats.invall, - module_stats.invmm, - module_stats.invrnge, - module_stats.invpg, - num_contexts - ); -} - -static void apmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) -{ -} - -static void __init poke_viking(void) -{ - unsigned long mreg = apmmu_get_mmureg(); - - mreg |= VIKING_SPENABLE; - mreg |= (VIKING_ICENABLE | VIKING_DCENABLE); - mreg &= ~VIKING_ACENABLE; - mreg &= ~VIKING_SBENABLE; - mreg |= VIKING_TCENABLE; - apmmu_set_mmureg(mreg); -} - -static void __init init_viking(void) -{ - apmmu_name = "TI Viking/AP1000"; - - BTFIXUPSET_CALL(flush_cache_all, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_mm, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_page, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_range, apmmu_null_func, BTFIXUPCALL_NOP); - - BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(flush_page_to_ram, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_sig_insns, apmmu_null_func, BTFIXUPCALL_NOP); -} - - -extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, - tsetup_mmu_patchme, rtrap_mmu_patchme; - -extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk, - tsetup_srmmu_stackchk, srmmu_rett_stackchk; - -extern unsigned long srmmu_fault; - -#define PATCH_BRANCH(insn, dest) do { \ - iaddr = &(insn); \ - daddr = &(dest); \ - *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ - } while(0); - -static void __init patch_window_trap_handlers(void) -{ - unsigned long *iaddr, *daddr; - - PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk); - PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk); - PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk); - PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk); - PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault); - PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault); - PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault); -} - -/* Load up routines and constants for apmmu */ -void __init ld_mmu_apmmu(void) -{ - /* First the constants */ - BTFIXUPSET_SIMM13(pmd_shift, APMMU_PMD_SHIFT); - BTFIXUPSET_SETHI(pmd_size, APMMU_PMD_SIZE); - BTFIXUPSET_SETHI(pmd_mask, APMMU_PMD_MASK); - BTFIXUPSET_SIMM13(pgdir_shift, APMMU_PGDIR_SHIFT); - BTFIXUPSET_SETHI(pgdir_size, APMMU_PGDIR_SIZE); - BTFIXUPSET_SETHI(pgdir_mask, APMMU_PGDIR_MASK); - - BTFIXUPSET_SIMM13(ptrs_per_pte, APMMU_PTRS_PER_PTE); - BTFIXUPSET_SIMM13(ptrs_per_pmd, APMMU_PTRS_PER_PMD); - BTFIXUPSET_SIMM13(ptrs_per_pgd, APMMU_PTRS_PER_PGD); - - BTFIXUPSET_INT(page_none, pgprot_val(APMMU_PAGE_NONE)); - BTFIXUPSET_INT(page_shared, pgprot_val(APMMU_PAGE_SHARED)); - BTFIXUPSET_INT(page_copy, pgprot_val(APMMU_PAGE_COPY)); - BTFIXUPSET_INT(page_readonly, pgprot_val(APMMU_PAGE_RDONLY)); - BTFIXUPSET_INT(page_kernel, pgprot_val(APMMU_PAGE_KERNEL)); - pg_iobits = APMMU_VALID | APMMU_WRITE | APMMU_REF; - - /* Functions */ - BTFIXUPSET_CALL(get_pte_fast, apmmu_get_pte_fast, BTFIXUPCALL_RETINT(0)); - BTFIXUPSET_CALL(get_pmd_fast, apmmu_get_pmd_fast, BTFIXUPCALL_RETINT(0)); - BTFIXUPSET_CALL(get_pgd_fast, apmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0)); - BTFIXUPSET_CALL(free_pte_slow, apmmu_free_pte_slow, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(free_pmd_slow, apmmu_free_pmd_slow, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(free_pgd_slow, apmmu_free_pgd_slow, BTFIXUPCALL_NOP); - - BTFIXUPSET_CALL(set_pte, apmmu_set_pte_cacheable, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_to_context, apmmu_switch_to_context, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(pte_page, apmmu_pte_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_page, apmmu_pmd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_page, apmmu_pgd_page, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, apmmu_update_rootmmu_dir, BTFIXUPCALL_NORM); - - BTFIXUPSET_SETHI(none_mask, 0xF0000000); - - BTFIXUPSET_CALL(pte_present, apmmu_pte_present, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_clear, apmmu_pte_clear, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(pmd_bad, apmmu_pmd_bad, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_present, apmmu_pmd_present, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_clear, apmmu_pmd_clear, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(pgd_none, apmmu_pgd_none, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_bad, apmmu_pgd_bad, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_present, apmmu_pgd_present, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_clear, apmmu_pgd_clear, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(mk_pte, apmmu_mk_pte, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte_phys, apmmu_mk_pte_phys, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte_io, apmmu_mk_pte_io, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_set, apmmu_pgd_set, BTFIXUPCALL_NORM); - - BTFIXUPSET_INT(pte_modify_mask, APMMU_CHG_MASK); - BTFIXUPSET_CALL(pgd_offset, apmmu_pgd_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_offset, apmmu_pmd_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_offset, apmmu_pte_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_free_kernel, apmmu_pte_free_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free_kernel, apmmu_pmd_free_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_alloc_kernel, apmmu_pte_alloc_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_alloc_kernel, apmmu_pmd_alloc_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_free, apmmu_pte_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_alloc, apmmu_pte_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free, apmmu_pmd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_alloc, apmmu_pmd_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_free, apmmu_pgd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_alloc, apmmu_pgd_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_flush, apmmu_pgd_flush, BTFIXUPCALL_NORM); - - BTFIXUPSET_HALF(pte_writei, APMMU_WRITE); - BTFIXUPSET_HALF(pte_dirtyi, APMMU_DIRTY); - BTFIXUPSET_HALF(pte_youngi, APMMU_REF); - BTFIXUPSET_HALF(pte_wrprotecti, APMMU_WRITE); - BTFIXUPSET_HALF(pte_mkcleani, APMMU_DIRTY); - BTFIXUPSET_HALF(pte_mkoldi, APMMU_REF); - BTFIXUPSET_CALL(pte_mkwrite, apmmu_pte_mkwrite, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_mkdirty, apmmu_pte_mkdirty, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_mkyoung, apmmu_pte_mkyoung, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(update_mmu_cache, apmmu_update_mmu_cache, BTFIXUPCALL_NOP); - - BTFIXUPSET_CALL(mmu_lockarea, apmmu_lockarea, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_unlockarea, apmmu_unlockarea, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(mmu_get_scsi_one, apmmu_null_func, BTFIXUPCALL_RETO0); - BTFIXUPSET_CALL(mmu_get_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(mmu_release_scsi_one, apmmu_null_func, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(mmu_release_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP); - - BTFIXUPSET_CALL(mmu_info, apmmu_mmu_info, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_v2p, apmmu_v2p, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_p2v, apmmu_p2v, BTFIXUPCALL_NORM); - - /* Task struct and kernel stack allocating/freeing. */ - BTFIXUPSET_CALL(alloc_task_struct, apmmu_alloc_task_struct, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(free_task_struct, apmmu_free_task_struct, BTFIXUPCALL_NORM); - - BTFIXUPSET_CALL(quick_kernel_fault, apmmu_quick_kernel_fault, BTFIXUPCALL_NORM); - - init_viking(); - patch_window_trap_handlers(); -} diff -ur --new-file old/linux/arch/sparc/ap1000/approm.c new/linux/arch/sparc/ap1000/approm.c --- old/linux/arch/sparc/ap1000/approm.c Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/approm.c Thu Jan 1 01:00:00 1970 @@ -1,148 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * fake a really simple Sun prom for the AP+ - * - */ - -#include -#include -#include -#include -#include -#include - -static struct linux_romvec ap_romvec; -static struct idprom ap_idprom; - -struct property { - char *name; - char *value; - int length; -}; - -struct node { - int level; - struct property *properties; -}; - -struct property null_properties = { NULL, NULL, -1 }; - -struct property root_properties[] = { - {"device_type", "cpu", 4}, - {"idprom", (char *)&ap_idprom, sizeof(ap_idprom)}, - {"banner-name", "Fujitsu AP1000+", 16}, - {NULL, NULL, -1} -}; - -struct node nodes[] = { - { 0, &null_properties }, - { 0, root_properties }, - { -1,&null_properties } -}; - - -static int no_nextnode(int node) -{ - if (nodes[node].level == nodes[node+1].level) - return node+1; - return -1; -} - -static int no_child(int node) -{ - if (nodes[node].level == nodes[node+1].level-1) - return node+1; - return -1; -} - -static struct property *find_property(int node,char *name) -{ - struct property *prop = &nodes[node].properties[0]; - while (prop && prop->name) { - if (strcmp(prop->name,name) == 0) return prop; - prop++; - } - return NULL; -} - -static int no_proplen(int node,char *name) -{ - struct property *prop = find_property(node,name); - if (prop) return prop->length; - return -1; -} - -static int no_getprop(int node,char *name,char *value) -{ - struct property *prop = find_property(node,name); - if (prop) { - memcpy(value,prop->value,prop->length); - return 1; - } - return -1; -} - -static int no_setprop(int node,char *name,char *value,int len) -{ - return -1; -} - -static char *no_nextprop(int node,char *name) -{ - struct property *prop = find_property(node,name); - if (prop) return prop[1].name; - return NULL; -} - - -static struct linux_nodeops ap_nodeops = { - no_nextnode, - no_child, - no_proplen, - no_getprop, - no_setprop, - no_nextprop -}; - - - -static unsigned char calc_idprom_cksum(struct idprom *idprom) -{ - unsigned char cksum, i, *ptr = (unsigned char *)idprom; - - for (i = cksum = 0; i <= 0x0E; i++) - cksum ^= *ptr++; - - return cksum; -} - -static int synch_hook; - - -struct linux_romvec *ap_prom_init(void) -{ - memset(&ap_romvec,0,sizeof(ap_romvec)); - - ap_romvec.pv_romvers = 42; - ap_romvec.pv_nodeops = &ap_nodeops; - ap_romvec.pv_reboot = ap_reboot; - ap_romvec.pv_synchook = &synch_hook; - - ap_idprom.id_format = 1; - ap_idprom.id_sernum = mpp_cid(); - ap_idprom.id_machtype = SM_SUN4M_OBP; - ap_idprom.id_cksum = calc_idprom_cksum(&ap_idprom); - - return &ap_romvec; -} - - - - - diff -ur --new-file old/linux/arch/sparc/ap1000/bnet.c new/linux/arch/sparc/ap1000/bnet.c --- old/linux/arch/sparc/ap1000/bnet.c Sat Feb 21 03:28:22 1998 +++ new/linux/arch/sparc/ap1000/bnet.c Thu Jan 1 01:00:00 1970 @@ -1,1205 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* routines to control the AP1000 bif interface. This is the interface - used to talk to the front end processor */ - -#include -#include -#include -#include -#include -#include -#include - -#define NET_DEBUG 0 - -#define DUMMY_MSG_LEN 100 -#define DUMMY_MSG_WAIT 30 - -#define MAX_CELLS 128 - -#define HAVE_BIF() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG) -#define BIF_BUSY() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BB) - -#define SNET_ARBITRATION 0 -#define TOKEN_ARBITRATION 1 - -#define DEBUG(x) - -#if TOKEN_ARBITRATION -static int have_token = 0; -#endif - -extern struct cap_init cap_init; - -static int interrupt_driven = 0; -static int use_dma = 0; -struct pt_regs *bif_pt_regs = NULL; -enum dma_state {DMA_IDLE,DMA_INCOMING,DMA_OUTGOING}; -static enum dma_state dma_state = DMA_IDLE; - -static int net_started = 0; -static int waiting_for_bif = 0; -static int queue_length = 0; - -static int drop_ip_packets = 0; - -#define DMA_THRESHOLD 64 - -static struct cap_request bread_req; - -int tnet_ip_enabled = 1; - -#define BIF_DATA_WAITING() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) - -#define ROUND4(x) (((x) + 3) & -4) - -static void bif_intr_receive(struct cap_request *req1); - - -/* read some data from the bif */ -void read_bif(char *buf,int size) -{ - unsigned *ibuf = (unsigned *)buf; - unsigned avail; - - DEBUG(("|read_bif %d\n",size)); - - if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); - - size = (size+3) >> 2; - - while (size > 4) { - while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_RB_SHIFT) & 7)) - ; - if (avail & 4) { - ibuf[0] = BIF_IN(BIF_DATA); - ibuf[1] = BIF_IN(BIF_DATA); - ibuf[2] = BIF_IN(BIF_DATA); - ibuf[3] = BIF_IN(BIF_DATA); - size -= 4; ibuf += 4; - continue; - } - - if (avail & 2) { - ibuf[0] = BIF_IN(BIF_DATA); - ibuf[1] = BIF_IN(BIF_DATA); - size -= 2; ibuf += 2; - continue; - } - *ibuf++ = BIF_IN(BIF_DATA); - size--; - } - - while (size--) { - while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)) ; - *ibuf++ = BIF_IN(BIF_DATA); - } - - DEBUG(("|read bif done\n")); -} - -/* throw out some data from the bif. This is usually called when we - don't have the resources to handle it immediately */ -void bif_toss(int size) -{ - unsigned flags; - save_flags(flags); cli(); - - DEBUG(("|bif toss %d\n",size)); - - while (size>0) { - while (!BIF_DATA_WAITING()); - BIF_IN(BIF_DATA); - size -= 4; - } - - DEBUG(("|bif toss done\n")); - - restore_flags(flags); -} - - -static void bif_reset_interrupts(void) -{ - BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_GET_SH); - BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_HEADER_SH); -} - -static void bif_mask_interrupts(void) -{ - BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_GET_SH); - BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_HEADER_SH); -} - -static void attn_enable(void) -{ - BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_ATTN_SH); -} - -static void attn_mask(void) -{ - BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_ATTN_SH); -} - - -void ap_bif_status(void) -{ - static int bif_sdcsr; - static int bif_intr; - static int bif_mhocr; - static int bif_x0sk; - static int bif_xsk; - static int bif_xsz; - static int bif_y0sk; - static int bif_ysk; - static int bif_ysz; - static int bif_cx0sk; - static int bif_cxsk; - static int bif_cxsz; - static int bif_cy0sk; - static int bif_cysk; - static int bif_cysz; - static int bif_ttl; - static int bif_cttl; - static int bif_header; - - bif_sdcsr = BIF_IN(BIF_SDCSR); - bif_intr = BIF_IN(BIF_INTR); - bif_mhocr = BIF_IN(BIF_MHOCR); - - bif_x0sk = BIF_IN(BIF_X0SK); - bif_xsk = BIF_IN(BIF_XSK); - bif_xsz = BIF_IN(BIF_XSZ); - bif_y0sk = BIF_IN(BIF_Y0SK); - bif_ysk = BIF_IN(BIF_YSK); - bif_ysz = BIF_IN(BIF_YSZ); - - bif_cx0sk = BIF_IN(BIF_CX0SK); - bif_cxsk = BIF_IN(BIF_CXSK); - bif_cxsz = BIF_IN(BIF_CXSZ); - bif_cy0sk = BIF_IN(BIF_CY0SK); - bif_cysk = BIF_IN(BIF_CYSK); - bif_cysz = BIF_IN(BIF_CYSZ); - - bif_ttl = BIF_IN(BIF_TTL); - bif_cttl = BIF_IN(BIF_CTTL); - bif_header = BIF_IN(BIF_HEADER); - - printk("|\t***** BIF REG. *****\n"); - printk("|\tBIF_SDCSR = %08x ", bif_sdcsr); - if(bif_sdcsr & BIF_SDCSR_CN) printk("|"); - if(bif_sdcsr & BIF_SDCSR_FN) printk("|"); - if(bif_sdcsr & BIF_SDCSR_DE) printk("|"); - if(bif_sdcsr & BIF_SDCSR_DR) printk("|"); - if(bif_sdcsr & BIF_SDCSR_BB) printk("|"); - if(bif_sdcsr & BIF_SDCSR_BR) printk("|"); - if(bif_sdcsr & BIF_SDCSR_BG) printk("|"); - if(bif_sdcsr & BIF_SDCSR_ER) printk("|"); - if(bif_sdcsr & BIF_SDCSR_PE) printk("|"); - printk("|\n"); - printk("|\tBIF_INTR = %08x\n", bif_intr); - printk("|\tBIF_MHOCR = %08x\n", bif_mhocr); - - printk("|\tBIF_X0SK = %08x\n", bif_x0sk); - printk("|\tBIF_XSK = %08x\n", bif_xsk); - printk("|\tBIF_XSZ = %08x\n", bif_xsz); - printk("|\tBIF_Y0SK = %08x\n", bif_y0sk); - printk("|\tBIF_YSK = %08x\n", bif_ysk); - printk("|\tBIF_YSZ = %08x\n", bif_ysz); - printk("|\tBIF_CX0SK = %08x\n", bif_cx0sk); - printk("|\tBIF_CXSK = %08x\n", bif_cxsk); - printk("|\tBIF_CXSZ = %08x\n", bif_cxsz); - printk("|\tBIF_CY0SK = %08x\n", bif_cy0sk); - printk("|\tBIF_CYSK = %08x\n", bif_cysk); - printk("|\tBIF_CYSZ = %08x\n", bif_cysz); - - printk("|\tBIF_TTL = %08x\n", bif_ttl); - printk("|\tBIF_CTTL = %08x\n", bif_cttl); - printk("|\tBIF_HEADER = %08x\n", bif_header); -} - - -void bif_led_status(void) -{ -#if 1 - static int i = 0; - unsigned char res = 0; - - switch (i) { - case 0: - case 2: - res = 0xff; - break; - case 1: - case 3: - res = 0; - break; - default: - res = 0xFF & (BIF_IN(BIF_SDCSR) >> (((i-4)/4)*8)); - } - i = (i+1) % 20; - - ap_led(res); -#endif -} - -static void get_bif(void) -{ - if (HAVE_BIF()) - return; - - drop_ip_packets = 1; - - DEBUG(("|get_bif started\n")); - - if (dma_state != DMA_IDLE) - ap_dma_wait(DMA_CH2); - -#if SNET_ARBITRATION - /* wait till the host doesn't want the BIF anymore, tossing - any data that arrives */ - while (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) - if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) - bif_intr_receive(NULL); - waiting_for_bif = 0; -#endif - -#if TOKEN_ARBITRATION - BIF_OUT(FSTT_CLR,HOST_STATUS_BIT); -#endif - - /* request the BIF */ - BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); - - /* loop waiting for us to get the BIF, tossing any data */ - while (!HAVE_BIF()) - if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) - bif_intr_receive(NULL); - - bif_reset_interrupts(); - if (!interrupt_driven) - bif_mask_interrupts(); - - drop_ip_packets = 0; - -#if TOKEN_ARBITRATION - BIF_OUT(FSTT_SET,HOST_STATUS_BIT); -#endif - - DEBUG(("|get_bif done\n")); -} - - -/* write a message to the front end over the Bnet. This can be in - multiple parts, as long as the first part sets "start" and the last - part sets "end". The bus will be grabbed while this is going on - */ -static void write_bif(char *buf,int size,int start,int end) -{ - unsigned *ibuf; - unsigned avail; - - DEBUG(("|write_bif %d %d %d\n",size,start,end)); - - if (start) { - /* a dma op may be in progress */ - if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); - } - - size = (size+3) >> 2; - ibuf = (unsigned *)buf; - if (end) size--; - - while (size > 4) { - while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_TB_SHIFT) & 7)) - ; - if (avail & 4) { - BIF_OUT(BIF_DATA,ibuf[0]); - BIF_OUT(BIF_DATA,ibuf[1]); - BIF_OUT(BIF_DATA,ibuf[2]); - BIF_OUT(BIF_DATA,ibuf[3]); - size -= 4; ibuf += 4; - continue; - } - - if (avail & 2) { - BIF_OUT(BIF_DATA,ibuf[0]); - BIF_OUT(BIF_DATA,ibuf[1]); - size -= 2; ibuf += 2; - continue; - } - BIF_OUT(BIF_DATA,ibuf[0]); - ibuf++; size--; - } - - while (size--) { - while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ; - BIF_OUT(BIF_DATA,ibuf[0]); - ibuf++; - } - - if (end) { - while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ; - BIF_OUT(BIF_EDATA,*ibuf); - } - - DEBUG(("|write bif done\n")); -} - -#if TOKEN_ARBITRATION -static void forward_token(void) -{ - struct cap_request req; - req.cid = mpp_cid(); - req.type = REQ_BIF_TOKEN; - req.size = sizeof(req); - if (req.cid == cap_init.numcells - 1) - req.header = MAKE_HEADER(HOST_CID); - else - req.header = MAKE_HEADER(req.cid + 1); - - write_bif((char *)&req,sizeof(req),1,1); - have_token = 0; -} -#endif - -static void release_bif(void) -{ - static int dummy[DUMMY_MSG_LEN]; - - waiting_for_bif = 0; - -#if SNET_ARBITRATION - /* mask the attention interrupt */ - attn_mask(); -#endif - - /* maybe we don't have it?? */ - if (!HAVE_BIF()) - return; - - DEBUG(("|release bif started\n")); - - if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); - -#if TOKEN_ARBITRATION - if (have_token) - forward_token(); -#endif - -#if 1 - /* send a dummy message to ensure FIFO flushing - (suggestion from woods to overcome bif release - hardware bug) */ - dummy[0] = 0xEEEE4000; - write_bif((char *)dummy,DUMMY_MSG_LEN,1,1); -#endif - /* wait till the send FIFO is completely empty */ - while (!((BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB) == BIF_SDCSR_TB)) ; - - /* wait another few us */ - udelay(DUMMY_MSG_WAIT); - - /* send release-data */ - BIF_OUT(BIF_DATA,BIF_HEADER_RS); - - /* wait until we don't have the bus */ - while (HAVE_BIF()) ; - - DEBUG(("|release bif done\n")); -} - - -/* wait for a particular request type - throwing away anything else! */ -void ap_wait_request(struct cap_request *req,int type) -{ - drop_ip_packets = 1; - do { - while (!BIF_DATA_WAITING()) - if (HAVE_BIF()) release_bif(); - read_bif((char *)req,sizeof(*req)); - if (req->type != type) { - bif_intr_receive(req); - } - } while (req->type != type); - drop_ip_packets = 0; -} - - -void write_bif_polled(char *buf1,int len1,char *buf2,int len2) -{ - unsigned flags; - save_flags(flags); cli(); - - get_bif(); - write_bif(buf1,len1,1,(buf2&&len2)?0:1); - if (buf2 && len2) - write_bif(buf2,len2,0,1); - release_bif(); - restore_flags(flags); -} - -static void want_bif(void) -{ - unsigned flags; - - save_flags(flags); cli(); - - /* maybe we've already got it */ - if (HAVE_BIF()) { - waiting_for_bif = 0; - restore_flags(flags); - return; - } - -#if SNET_ARBITRATION - if (interrupt_driven) - attn_enable(); - - /* check if the host wants it */ - if (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) { - /* the host wants it - don't get it yet */ - waiting_for_bif = 1; - } else { - /* the host doesn't want it - just set bus request */ - waiting_for_bif = 0; - BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); - while (!HAVE_BIF() && !BIF_BUSY()) ; - DEBUG(("|set bif request\n")); - } - restore_flags(flags); - return; -#endif - -#if TOKEN_ARBITRATION - if (net_started && !have_token) { - BIF_OUT(FSTT_CLR,HOST_STATUS_BIT); - restore_flags(flags); - return; - } - BIF_OUT(FSTT_SET,HOST_STATUS_BIT); -#endif - - BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); - restore_flags(flags); -} - -#define BIF_NOCOPY (1<<0) - -/* a queue of requests that need to be sent over the bif. Needs to be -modified sometime to allow the direct queueing of skb's */ -struct bif_queue { - volatile struct bif_queue *next; - struct cap_request req; - char *data; - int data_size; - int flags; -}; - -static volatile struct bif_queue *bif_queue_top = NULL; -static volatile struct bif_queue *bif_queue_end = NULL; - -static struct sk_buff *skb_out = NULL; -static struct sk_buff *skb_in = NULL; -static char *bif_dma_data = NULL; -static int bif_dma_out_size = 0; - - -/* send waiting elements. Called mainly when we get a bif "bus get" - interrupt to say we now have the bus */ -static void bif_intr_runqueue(void) -{ - unsigned flags; - - /* if I don't have the bus then return */ - if (!HAVE_BIF()) - return; - - if (dma_state != DMA_IDLE) return; - - save_flags(flags); cli(); - - while (bif_queue_top) { - volatile struct bif_queue *q = bif_queue_top; - bif_queue_top = q->next; - - /* printk("|queue run (length=%d)\n",queue_length); */ - queue_length--; - - if (!q->data) { - /* use programmed IO for small requests */ - write_bif((char *)&q->req,sizeof(q->req),1,1); - kfree_s((char *)q,sizeof(*q)); - continue; - } - - if (q->flags & BIF_NOCOPY) { - write_bif((char *)&q->req,sizeof(q->req),1,0); - } - - if (use_dma && q->data_size > DMA_THRESHOLD) { - dma_state = DMA_OUTGOING; - if (q->req.type == REQ_IP) { - skb_out = (struct sk_buff *)q->data; - ap_dma_go(DMA_CH2,(unsigned)skb_out->data, - q->data_size,DMA_DCMD_TD_MD); - } else { - if (!(q->flags & BIF_NOCOPY)) { - bif_dma_data = q->data; - bif_dma_out_size = q->data_size; - } - ap_dma_go(DMA_CH2,(unsigned)q->data, - q->data_size,DMA_DCMD_TD_MD); - } - kfree_s((char *)q,sizeof(*q)); - restore_flags(flags); - return; /* wait for DMA to complete */ - } - - if (q->req.type == REQ_IP) { - struct sk_buff *skb = (struct sk_buff *)q->data; - write_bif(skb->data,q->data_size,1,1); - dev_kfree_skb(skb); - } else { - write_bif(q->data,q->data_size,1,1); - if (!(q->flags & BIF_NOCOPY)) - kfree_s(q->data,q->data_size); - } - kfree_s((char *)q,sizeof(*q)); - } - - /* I don't want the bus now */ - release_bif(); - restore_flags(flags); -} - - -static void queue_attach(struct bif_queue *q) -{ - unsigned flags; - save_flags(flags); cli(); - - /* attach it to the end of the queue */ - if (!bif_queue_top) { - bif_queue_top = q; - } else { - bif_queue_end->next = q; - } - bif_queue_end = q; - - queue_length++; - - /* printk("|queue add (length=%d)\n",queue_length); */ - - /* tell the bus we want access */ - want_bif(); - - restore_flags(flags); -} - - -/* queue an element for sending over the bif. */ -int bif_queue(struct cap_request *req,char *buf,int bufsize) -{ - struct bif_queue *q; - - if (req->header == 0) - req->header = MAKE_HEADER(HOST_CID); - - /* if we aren't running interrupt driven then just send it - immediately */ - if (!interrupt_driven) { - write_bif_polled((char *)req,sizeof(*req),buf,bufsize); - return(0); - } - - /* allocate a queue element */ - q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); - if (!q) { - /* yikes! */ - return(-ENOMEM); - } - - q->flags = 0; - q->data = NULL; - q->data_size = 0; - - if (buf && bufsize>0) { - q->data_size = bufsize+sizeof(*req); - q->data = (char *)kmalloc(q->data_size,GFP_ATOMIC); - if (!q->data) { - kfree_s(q,sizeof(*q)); - return(-ENOMEM); - } - } - - q->req = *req; - if (buf&&bufsize) { - memcpy(q->data,(char *)req,sizeof(*req)); - memcpy(q->data+sizeof(*req),buf,bufsize); - } - q->next = NULL; - - queue_attach(q); - - return(0); -} - - -/* queue an element for sending over the bif. */ -int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize) -{ - struct bif_queue *q; - - if (req->header == 0) - req->header = MAKE_HEADER(HOST_CID); - - /* allocate a queue element */ - q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); - if (!q) { - return(-ENOMEM); - } - - q->data = buf; - q->data_size = bufsize; - q->flags = BIF_NOCOPY; - q->req = *req; - q->next = NULL; - - queue_attach(q); - - return(0); -} - - -/* put an IP packet into the bif queue */ -int bif_send_ip(int cid, struct sk_buff *skb) -{ - struct cap_request *req = (struct cap_request *)skb->data; - struct bif_queue *q; - u_long destip; - - destip = *(u_long *)(skb->data+sizeof(*req)+16); - - if (cid != -1) { - req->header = MAKE_HEADER(cid); - } else if (destip == (cap_init.baseIP | ~cap_init.netmask)) { - req->header = BIF_HEADER_IN | BIF_HEADER_BR; - } else { - req->header = MAKE_HEADER(HOST_CID); - } - - /* allocate a queue element */ - q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); - if (!q) { - /* yikes! */ - dev_kfree_skb(skb); - return(-ENOMEM); - } - - req->size = ROUND4(skb->len); - req->cid = mpp_cid(); - req->type = REQ_IP; - - q->data = (char *)skb; - q->data_size = req->size; - q->next = NULL; - q->req = *req; - q->flags = 0; - - queue_attach(q); - - return(0); -} - - -/* send an OPENNET request to tell the front end to open the apnet - network interface */ -void start_apnet(void) -{ - struct cap_request req; - req.cid = mpp_cid(); - req.type = REQ_OPENNET; - req.size = sizeof(req); - req.header = MAKE_HEADER(HOST_CID); - - bif_queue(&req,NULL,0); - printk("sent start_apnet request\n"); -} - -/* we have received an IP packet - pass it to the bif network - interface code */ -static void reply_ip(struct cap_request *req) -{ - if (drop_ip_packets || - !(skb_in = dev_alloc_skb(req->size - sizeof(*req)))) { - bif_toss(req->size - sizeof(*req)); - return; - } - - if (use_dma && req->size > DMA_THRESHOLD) { - dma_state = DMA_INCOMING; - ap_dma_go(DMA_CH2, - (unsigned)skb_put(skb_in,req->size - sizeof(*req)), - req->size - sizeof(*req),DMA_DCMD_TD_DM); - } else { - read_bif(skb_put(skb_in,req->size - sizeof(*req)), - req->size - sizeof(*req)); - bif_rx(skb_in); - skb_in = NULL; - } -} - - -/* we have received a bread block - DMA it in */ -static void reply_bread(struct cap_request *req) -{ - extern char *ap_buffer(struct cap_request *creq); - char *buffer; - - buffer = ap_buffer(req); - bread_req = *req; - - if (use_dma) { - dma_state = DMA_INCOMING; - ap_dma_go(DMA_CH2, - (unsigned)buffer,req->size - sizeof(*req), - DMA_DCMD_TD_DM); - } else { - read_bif(buffer,req->size - sizeof(*req)); - ap_complete(&bread_req); - bread_req.type = -1; - } -} - - -static struct debug_key { - struct debug_key *next; - char key; - void (*fn)(void); - char *description; -} *debug_keys = NULL; - - -void show_debug_keys(void) -{ - struct debug_key *r; - for (r=debug_keys;r;r=r->next) - printk("%c: %s\n",r->key,r->description); -} - - -void bif_add_debug_key(char key,void (*fn)(void),char *description) -{ - struct debug_key *r,*r2; - r = (struct debug_key *)kmalloc(sizeof(*r),GFP_ATOMIC); - if (r) { - r->next = NULL; - r->key = key; - r->fn = fn; - r->description = description; - if (!debug_keys) { - debug_keys = r; - } else { - for (r2=debug_keys; - r2->next && r2->key != key;r2=r2->next) ; - - if (r2->key == key) { - r2->fn = fn; - r2->description = description; - kfree_s(r,sizeof(*r)); - } else { - r2->next = r; - } - } - } -} - -/* these are very useful for debugging ! */ -static void reply_putchar(struct cap_request *req) -{ - struct debug_key *r; - - char c = req->data[0]; - - ap_set_user(req->data[1]); - - for (r=debug_keys;r;r=r->next) - if (r->key == c) { - r->fn(); - break; - } - if (!r) - printk("cell %d got character %d [%c]\n",mpp_cid(),(int)c,c); - - ap_set_user(-1); -} - - -/* send a signal to a task by name or pid */ -static void reply_kill(struct cap_request *req) -{ - int sig = req->data[0]; - struct task_struct *p; - int len; - char name[32]; - - len = req->size - sizeof(*req); - if (len == 0) { - int pid = req->data[1]; - p = find_task_by_pid(pid); - - if(p) - send_sig(sig, p, 1); - else - printk("cell %d: no task with pid %d\n",mpp_cid(),pid); - return; - } - - if (len > sizeof(name)-1) { - bif_toss(len); - return; - } - - read_bif(name,len); - name[len] = 0; - - read_lock(&tasklist_lock); - for_each_task(p) - if (strcmp(name,p->comm) == 0) - send_sig(sig,p,1); - read_unlock(&tasklist_lock); -} - - -static struct req_list { - struct req_list *next; - int type; - void (*fn)(struct cap_request *); -} *reg_req_list = NULL; - - -void bif_register_request(int type,void (*fn)(struct cap_request *)) -{ - struct req_list *r,*r2; - r = (struct req_list *)kmalloc(sizeof(*r),GFP_ATOMIC); - if (r) { - r->next = NULL; - r->type = type; - r->fn = fn; - if (!reg_req_list) { - reg_req_list = r; - } else { - for (r2=reg_req_list; - r2->next && r2->type != type;r2=r2->next) ; - - if (r2->type == type) { - r2->fn = fn; - kfree_s(r,sizeof(*r)); - } else { - r2->next = r; - } - } - } -} - - - -/* a request has come in on the bif - process it */ -static void bif_intr_receive(struct cap_request *req1) -{ - struct req_list *r; - extern void ap_open_reply(struct cap_request *creq); - struct cap_request req; - - if (req1) { - req = *req1; - } else { - /* read the main cap request header */ - read_bif((char *)&req,sizeof(req)); - } - - /* service it */ - switch (req.type) - { - case REQ_PUTCHAR: - reply_putchar(&req); - break; - case REQ_KILL: - reply_kill(&req); - break; - case REQ_BREAK: - breakpoint(); - break; - case REQ_IP: - reply_ip(&req); - break; -#if TOKEN_ARBITRATION - case REQ_BIF_TOKEN: - have_token = 1; - want_bif(); - break; -#endif - case REQ_OPENNET: - net_started = 1; - break; - case REQ_BREAD: - reply_bread(&req); - break; - case REQ_BOPEN: - ap_open_reply(&req); - break; - case REQ_BWRITE: - ap_complete(&req); - break; - case REQ_SCHEDULE: - mpp_schedule(&req); - break; - - default: - for (r=reg_req_list;r;r=r->next) - if (r->type == req.type) { - r->fn(&req); - return; - } - printk("Unknown request %d\n",req.type); - break; - } -} - - -static void bif_dma_complete(void) -{ - extern int bif_rx(struct sk_buff *skb); - enum dma_state old_state = dma_state; - unsigned a; - - a = DMA_IN(DMA2_DMST); - - if (a & DMA_DMST_AC) return; - - DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ< -#include -#include -#include -#include -#include - -#define DMA_MAX_TRANS_SIZE2 (0xfffffc) - -int ap_dma_wait(int ch) -{ - int i = 0; - while (DMA_IN(ch+DMA_DMST) & DMA_DMST_AC) i++; - return i; -} - -/* send some data out a dma channel */ -int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd) -{ - int rest; - - p = mmu_v2p(p); - - cmd |= DMA_DCMD_ST | DMA_DCMD_TYP_AUTO; - -#if 0 - if (ap_dma_wait(ch)) { - printk("WARNING: dma started when not complete\n"); - } - - if (cmd == DMA_DCMD_TD_MD && !(BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)) { - ap_led(0xAA); - printk("attempt to dma without holding the bus\n"); - return -1; - } -#endif - - /* reset the dma system */ - DMA_OUT(ch + DMA_DMST,DMA_DMST_RST); - - if (size <= DMA_MAX_TRANS_SIZE) { - DMA_OUT(ch + DMA_MADDR,(unsigned long)p); - DMA_OUT(ch + DMA_HSKIP,1); - DMA_OUT(ch + DMA_VSKIP,1); - DMA_OUT(ch + DMA_DCMD,cmd | B2W(size)); - return 0; - } - - if (size <= DMA_MAX_TRANS_SIZE2) { - if(size & 0x3) size += 4; - rest = (size & (DMA_TRANS_BLOCK_SIZE - 1)) >> 2; - if (rest) { - DMA_OUT(ch + DMA_HDRP,(unsigned)p); - p += rest << 2; - } - DMA_OUT(ch + DMA_MADDR,(unsigned)p); - DMA_OUT(ch + DMA_HSKIP,size >> (2 + 6)); - DMA_OUT(ch + DMA_VSKIP,1); - DMA_OUT(ch + DMA_DCMD,cmd | (rest << 16) | 64); - return 0; - } - - printk("AP1000 DMA operation too big (%d bytes) - aborting\n",size); - return(-1); -} - diff -ur --new-file old/linux/arch/sparc/ap1000/hw.c new/linux/arch/sparc/ap1000/hw.c --- old/linux/arch/sparc/ap1000/hw.c Wed May 14 07:41:03 1997 +++ new/linux/arch/sparc/ap1000/hw.c Thu Jan 1 01:00:00 1970 @@ -1,200 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Initialize the AP1000 hardware: BIF, MSC+, MC+, etc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define APLOG 0 - -/* these make using CellOS code easier */ -int cap_nopt0; -int cap_cid0; -int cap_ncel0; - -unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy; - -/* yuck - needed for sun4c! */ -static unsigned char dummy; -unsigned char *auxio_register = &dummy; - - -extern struct cap_init cap_init; - -static void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - ap_panic("** unexpected interrupt %d **\n",irq); -} - -static void ap_other_irqs(void) -{ - request_irq(3, unexpected_irq, SA_INTERRUPT, "unused", 0); - request_irq(5, unexpected_irq, SA_INTERRUPT, "unused", 0); - request_irq(12, unexpected_irq, SA_INTERRUPT, "unused", 0); - request_irq(15, unexpected_irq, SA_INTERRUPT, "unused", 0); -} - -int ap_memory_size(void) -{ - if ((MSC_IN(MSC_SIMMCHK) & MSC_SIMMCHK_MASK) == 0) { - return 16*1024*1024; - } - return 64*1024*1024; -} - -static void show_registers(void) -{ - extern struct pt_regs *bif_pt_regs; - if (bif_pt_regs) - show_regs(bif_pt_regs); - else - printk("unable to show registers\n"); -} - - -static void check_alive(void) -{ - printk("Cell %d is alive\n",mpp_cid()); -} - - - -static void show_task(struct task_struct *t) -{ - printk("cell=%3d uid=%5d pid=%5d utime=%3d stime=%3d etime=%3d name=%s\n", - mpp_cid(), - t->uid, - (int)t->pid, - (int)t->utime, - (int)t->stime, - (jiffies - (int)t->start_time) / 100, - t->comm); -} - -static void show_ptasks(void) -{ - extern struct task_struct *task[]; - struct task_struct *p; - int i; - int count=0; - - read_lock(&tasklist_lock); - for_each_task(p) { - struct task_struct **tp = p->tarray_ptr; - - if(tp >= &task[MPP_TASK_BASE]) { - show_task(p); - count++; - } - } - read_unlock(&tasklist_lock); - - if (count == 0) - printk("no parallel tasks on cell %d\n",mpp_cid()); -} - -static void show_utasks(void) -{ - extern struct task_struct *task[]; - struct task_struct *p; - int i; - int count=0; - - read_lock(&tasklist_lock); - for_each_task(p) { - if(p->uid > 1) { - show_task(task[i]); - count++; - } - } - read_unlock(&tasklist_lock); - - if (count == 0) - printk("no user tasks on cell %d\n",mpp_cid()); -} - - -static void show_otasks(void) -{ - extern struct task_struct *task[]; - struct task_struct *p; - int i; - int count=0; - extern int ap_current_uid; - - read_lock(&tasklist_lock); - for_each_task(p) { - if(p->uid == ap_current_uid) { - show_task(task[i]); - count++; - } - } - read_unlock(&tasklist_lock); - - if (count == 0) - printk("no tasks on cell %d\n",mpp_cid()); -} - - -void do_panic(void) -{ - int *x = 0; - *x = 1; /* uggh */ -} - - -void mpp_hw_init(void) -{ - extern void show_state(void); - extern void breakpoint(void); - extern void ctrl_alt_del(void); - extern void mac_print_state(void); - extern void show_debug_keys(void); - - bif_add_debug_key('c',check_alive,"check if a cell is alive"); - bif_add_debug_key('k',show_debug_keys,"show the kernel debug keys"); - bif_add_debug_key('p',show_registers,"show register info"); - bif_add_debug_key('p',show_registers,"show register info"); - bif_add_debug_key('m',show_mem,"detailed memory stats"); - bif_add_debug_key('s',show_state,"detailed process stats"); - bif_add_debug_key('D',ap_start_debugger,"launch the kernel debugger"); - bif_add_debug_key('i',breakpoint,"send a breakpoint"); - bif_add_debug_key('r',ctrl_alt_del,"run shutdown (doesn't work)"); - bif_add_debug_key('P',show_ptasks,"show running parallel tasks"); - bif_add_debug_key('U',show_utasks,"show all user tasks"); - bif_add_debug_key('O',show_otasks,"show own user tasks"); - bif_add_debug_key('^',do_panic,"panic :-)"); - - - cap_cid0 = BIF_IN(BIF_CIDR1); - cap_ncel0 = cap_init.numcells; - - _cid = cap_cid0; - _ncel = cap_ncel0; - _ncelx = _ncel<8?_ncel:8; - _ncely = ((_ncel-1) / _ncelx) + 1; - _cidx = _cid % _ncelx; - _cidy = _cid / _ncelx; - - ap_bif_init(); - ap_msc_init(); - ap_tnet_init(); - ap_profile_init(); - ap_other_irqs(); - ap_ringbuf_init(); -#if APLOG - ap_log(NULL,-1); -#endif -} diff -ur --new-file old/linux/arch/sparc/ap1000/irq.c new/linux/arch/sparc/ap1000/irq.c --- old/linux/arch/sparc/ap1000/irq.c Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/irq.c Thu Jan 1 01:00:00 1970 @@ -1,64 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void ap_clear_clock_irq(void); -extern void ap_init_timers(void); - -static void ap_enable_irq(unsigned int irq_nr) -{ - /* printk("ENABLE IRQ %d IGNORED\n",irq_nr); */ -} - -static void ap_disable_irq(unsigned int irq_nr) -{ - printk("DISABLE IRQ %d IGNORED\n",irq_nr); -} - -static void ap_clear_profile_irq(void) -{ - MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); -} - -static void ap_load_profile_irq(unsigned limit) -{ - MC_OUT(MC_ITIMER0,limit); -} - -void ap_init_IRQ(void) -{ - enable_irq = ap_enable_irq; - disable_irq = ap_disable_irq; - clear_clock_irq = ap_clear_clock_irq; - clear_profile_irq = ap_clear_profile_irq; - load_profile_irq = ap_load_profile_irq; - init_timers = ap_init_timers; - - sti(); /* the sun4m code does this, so we do too */ -} diff -ur --new-file old/linux/arch/sparc/ap1000/kgdb.c new/linux/arch/sparc/ap1000/kgdb.c --- old/linux/arch/sparc/ap1000/kgdb.c Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/kgdb.c Thu Jan 1 01:00:00 1970 @@ -1,78 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* routines to support remote kgdb to Linux/AP+ cells */ - -#include -#include -#include -#include -#include - -static char out_buf[0x100]; -static int out_buf_pos = 0; - -static char in_buf[0x100]; -static int in_buf_pos = 0; -static int in_buf_count = 0; - -static int hash_pos = -1; - -void ap_dbg_flush(void) -{ - struct cap_request req; - - if (out_buf_pos == 0) return; - - req.cid = mpp_cid(); - req.type = REQ_PUTDEBUGSTRING; - req.size = sizeof(req) + out_buf_pos; - req.header = MAKE_HEADER(HOST_CID); - - write_bif_polled((char *)&req,sizeof(req),(char *)out_buf,out_buf_pos); - - out_buf_pos = 0; - hash_pos = -1; -} - -/* called by the gdb stuff */ -void putDebugChar(char c) -{ - if (c == '#') hash_pos = out_buf_pos; - - out_buf[out_buf_pos++] = c; - if (out_buf_pos == sizeof(out_buf)) { - ap_dbg_flush(); - } -} - -/* used by gdb to get input */ -char getDebugChar(void) -{ - unsigned flags; - struct cap_request req; - - ap_dbg_flush(); - - if (in_buf_count == 0) { - req.cid = mpp_cid(); - req.type = REQ_GETDEBUGCHAR; - req.size = sizeof(req); - req.header = MAKE_HEADER(HOST_CID); - - save_flags(flags); cli(); - write_bif_polled((char *)&req,sizeof(req),NULL,0); - ap_wait_request(&req,REQ_GETDEBUGCHAR); - read_bif(in_buf,req.size - sizeof(req)); - in_buf_pos = 0; - in_buf_count = req.size - sizeof(req); - restore_flags(flags); - } - - in_buf_count--; - return(in_buf[in_buf_pos++]); -} diff -ur --new-file old/linux/arch/sparc/ap1000/mpp.c new/linux/arch/sparc/ap1000/mpp.c --- old/linux/arch/sparc/ap1000/mpp.c Wed Aug 5 01:03:34 1998 +++ new/linux/arch/sparc/ap1000/mpp.c Thu Jan 1 01:00:00 1970 @@ -1,83 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * simple mpp functions for the AP+ - */ - -#include -#include -#include -#include -#include -#include - -extern int cap_cid0; -extern int cap_ncel0; -extern struct cap_init cap_init; - -static volatile int mpp_current_task = 0; -static int gang_factor = DEF_GANG_FACTOR; -static int last_task = 0; - - -void mpp_schedule(struct cap_request *req) -{ - mpp_current_task = req->data[0]; - current->need_resched = 1; - mark_bh(TQUEUE_BH); -} - - -void mpp_notify_schedule(struct task_struct *tsk) -{ - last_task = tsk->taskid; - - msc_switch_check(tsk); - - if (gang_factor == 0) return; - - if (cap_cid0 == cap_init.bootcid && - mpp_current_task != tsk->taskid) { - struct cap_request req; - - mpp_current_task = tsk->taskid; - - req.cid = mpp_cid(); - req.type = REQ_SCHEDULE; - req.size = sizeof(req); - req.header = MAKE_HEADER(-1); - req.data[0] = mpp_current_task; - - bif_queue(&req,NULL,0); - } -} - - -int mpp_weight(struct task_struct *tsk) -{ - extern int block_parallel_tasks; - - if (!MPP_IS_PAR_TASK(tsk->taskid)) return 0; - - if (block_parallel_tasks) return -1000; - - /* XXX task[] fixme */ - if (last_task && last_task != tsk->taskid && task[last_task] && - !msc_switch_ok()) return -1000; - - if (cap_cid0 != cap_init.bootcid && - tsk->taskid != mpp_current_task) { - return -gang_factor; - } - return 0; -} - -void mpp_set_gang_factor(int factor) -{ - gang_factor = factor; -} diff -ur --new-file old/linux/arch/sparc/ap1000/msc.c new/linux/arch/sparc/ap1000/msc.c --- old/linux/arch/sparc/ap1000/msc.c Wed Sep 1 23:12:09 1999 +++ new/linux/arch/sparc/ap1000/msc.c Thu Jan 1 01:00:00 1970 @@ -1,1262 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Routines to control the AP1000+ Message Controller (MSC+) - * and Memory Controller (MC+). - * - */ -#define _APLIB_ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs); -static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs); -static void msc_set_ringbuf(int context); -static void msc_update_read_ptr(int context,int overflow); -static void fail_write(int context,int intr,unsigned vaddr); -static void fail_read(int context,int intr,unsigned vaddr); -static void msc_switch_from_check(struct task_struct *tsk); -static void msc_status(void); - -#define DEBUG 0 - -/* - * This describes how the 5 queues for outgoing requests - * are mapped into the 256 words of send queue RAM in the MSC+. - */ -#define NSENDQUEUES 5 - -static struct send_queues { - int base; /* must be a multiple of size */ - int size; /* must be 32 or 64 */ -} send_queues[NSENDQUEUES] = { - {0, 64}, /* System put/send requests */ - {192, 32}, /* Remote read/write requests */ - {64, 64}, /* User put/send requests */ - {224, 32}, /* Remote read replies */ - {128, 64}, /* Get replies */ -}; - -#define NR_RBUFS MSC_NR_RBUFS - -static struct { - unsigned rbmbwp; - unsigned rbmmode; - unsigned rbmrp; -} ringbufs[MSC_NR_RBUFS] = { - {MSC_RBMBWP0, MSC_RBMMODE0, MSC_RBMRP0}, - {MSC_RBMBWP1, MSC_RBMMODE1, MSC_RBMRP1}, - {MSC_RBMBWP2, MSC_RBMMODE2, MSC_RBMRP2}, -}; - -#define CTX_MASK 0xfff -#define NULL_CONTEXT CTX_MASK - -#define QOF_ORDER 3 /* 32kB queue overflow buffer */ -#define QOF_SIZE ((1<> 19, MSC_QBMP_BP) \ - + MKFIELD((qof) >> 3, MSC_QBMP_WP) \ - + MKFIELD(((qof) + (size) - 1) >> 13, MSC_QBMP_LIM)) - -#define QBM_UPDATE_WP(wp) \ - MSC_OUT(MSC_QBMPTR, INSFIELD(MSC_IN(MSC_QBMPTR), (unsigned)(wp) >> 3, \ - MSC_QBMP_WP)) - -/* Send queue overflow buffer structure */ -struct qof_elt { - unsigned info; - unsigned data; -}; - -/* Fields in qof_elt.info */ -#define QOF_QUEUE_SH 24 /* queue bits start at bit 24 */ -#define QOF_QUEUE_M 0x1f /* 5 bits wide */ -#define QOF_ENDBIT 1 /* end bit in bit 0 */ - -static struct qof_elt *qof_base=NULL; /* start of overflow buffer */ -static unsigned long qof_phys; /* physical start adrs of overflow buffer */ -static struct qof_elt *qof_rp; /* read pointer for refills */ -static struct qof_elt *qof_new; /* first element we haven't yet looked at */ -static int qof_present[NSENDQUEUES];/* # elts for each q in [qof_rp,qof_new) */ - -/* this is used to flag when the msc is blocked, so we can't send - messages on it without the possability of deadlock */ -int msc_blocked = 0; -int block_parallel_tasks = 0; - -static int qbm_full_counter = 0; - -#define INTR_LIMIT 10000 -static int intr_counter = 0; -static unsigned intr_mask; - -#define DUMMY_RINGBUF_ORDER 5 -#define DUMMY_RINGBUF_SIZE ((1<>5)-1; -unsigned dummy_read_ptr = (DUMMY_RINGBUF_SIZE>>5)-1; - -#define SQ_NEW_MODE(mode) do { \ - MSC_OUT(MSC_SQCTRL, ((MSC_IN(MSC_SQCTRL) & ~MSC_SQC_RMODE) \ - | MSC_SQC_RMODE_ ## mode)); \ - while ((MSC_IN(MSC_SQCTRL) & MSC_SQC_MODE) != MSC_SQC_MODE_ ## mode) \ - /* hang */ ; \ -} while (0) - -/* Repack the queue overflow buffer if >= this many already-used entries */ -#define REPACK_THRESH 64 - - -static void refill_sq(void); -static void repack_qof(void); -static void shuffle_qof(void); -static void async_callback(int, unsigned long, int, int); - - -static void mask_all_interrupts(void) -{ - /* disable all MSC+ interrupts */ - MSC_OUT(MSC_INTR, - (AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH) | - (AP_SET_INTR_MASK << MSC_INTR_SQFILL_SH) | - (AP_SET_INTR_MASK << MSC_INTR_RBMISS_SH) | - (AP_SET_INTR_MASK << MSC_INTR_RBFULL_SH) | - (AP_SET_INTR_MASK << MSC_INTR_RMASF_SH) | - (AP_SET_INTR_MASK << MSC_INTR_RMASE_SH) | - (AP_SET_INTR_MASK << MSC_INTR_SMASF_SH) | - (AP_SET_INTR_MASK << MSC_INTR_SMASE_SH)); -} - -static inline int valid_task(struct task_struct *tsk) -{ - return(tsk && - !((tsk)->flags & PF_EXITING) && - tsk->mm && - tsk->mm->context != NO_CONTEXT); -} - -static inline unsigned long apmmu_get_raw_ctable_ptr(void) -{ - unsigned int retval; - - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (retval) : - "r" (APMMU_CTXTBL_PTR), - "i" (ASI_M_MMUREGS)); - return (retval); -} - -static void mc_tlb_map(unsigned phys_page,unsigned vpage,int context) -{ - unsigned long long *tlb4k; - unsigned long long new_entry; - unsigned long *new_entryp = (unsigned long *)&new_entry; - tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF); - new_entryp[0] = (phys_page&~7) >> 3; - new_entryp[1] = ((phys_page & 7) << 29) | (((vpage>>8)&0xFFF) << 17) | - (context << 5) | 0x13; - tlb4k[0] = new_entry; -#if DEBUG - printk("mc_tlb_map(%x,%x,%x) %x %x at %x\n", - phys_page,vpage,context,new_entryp[0],new_entryp[1],tlb4k); -#endif -} - -static void mc_tlb_unmap(unsigned vpage) -{ - unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K; - tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF); - tlb4k[0] = 0; -} - -void mc_tlb_init(void) -{ - unsigned long long *tlb256k, *tlb4k; - int i; - - tlb4k = (unsigned long long *)MC_MMU_TLB4K; - for (i = MC_MMU_TLB4K_SIZE; i > 0; --i) - *tlb4k++ = 0; - tlb256k = (unsigned long long *)MC_MMU_TLB256K; - for (i = MC_MMU_TLB256K_SIZE; i > 0; --i) - *tlb256k++ = 0; -} - -void ap_msc_init(void) -{ - int i, flags, res; - unsigned int qp; - - bif_add_debug_key('M',msc_status,"MSC+ status"); - -#if DEBUG - printk("MSC+ version %x\n", MSC_IN(MSC_VERSION)); - printk("MC+ version %x\n", MC_IN(MC_VERSION)); -#endif - - mc_tlb_init(); - - /* Set the MC's copy of the context table pointer */ - MC_OUT(MC_CTP, apmmu_get_raw_ctable_ptr()); - - /* Initialize the send queue pointers */ - qp = MSC_SQPTR0; - for (i = 0; i < 5; ++i) { - MSC_OUT(qp, ((send_queues[i].size == 64? MSC_SQP_MODE: 0) - + ((send_queues[i].base >> 5) << MSC_SQP_BP_SH))); - qp += (MSC_SQPTR1 - MSC_SQPTR0); - } - - /* Initialize the send queue RAM */ - for (i = 0; i < 256; ++i) - MSC_OUT(MSC_SQRAM + i * 8, -1); - - if (!qof_base) { - qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER); - for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i) - set_bit(PG_reserved, &mem_map[i].flags); - } - - qof_phys = mmu_v2p((unsigned long) qof_base); - MSC_OUT(MSC_QBMPTR, MAKE_QBMPTR((unsigned long)qof_base, QOF_SIZE)); - qof_rp = qof_base; - qof_new = qof_base; - for (i = 0; i < NSENDQUEUES; ++i) - qof_present[i] = 0; - - SQ_NEW_MODE(NORMAL); /* Set the send queue to normal mode */ - - /* Register interrupt handler for MSC+ */ - save_flags(flags); cli(); - res = request_irq(APMSC_IRQ, msc_interrupt_11, SA_INTERRUPT, - "apmsc", NULL); - if (res != 0) - printk("couldn't register MSC interrupt 11: error=%d\n", res); - res = request_irq(APMAS_IRQ, msc_interrupt_9, SA_INTERRUPT, - "apmas", NULL); - if (res != 0) - printk("couldn't register MSC interrupt 9: error=%d\n", res); - restore_flags(flags); - - MSC_OUT(MSC_MASCTRL, 0); - - /* Enable all MSC+ interrupts (for now) */ - MSC_OUT(MSC_INTR, - (AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_SQFILL_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_RBMISS_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_RBFULL_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_RMASE_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH) | - (AP_CLR_INTR_MASK << MSC_INTR_SMASE_SH)); - - /* setup invalid contexts */ - for (i=0; i= QOF_GREEN_NELT) { -#if DEBUG - printk("send queue overflow buffer overflow\n"); -#endif - MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH); - intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH); - current->need_resched = 1; - block_parallel_tasks = 1; - mark_bh(TQUEUE_BH); - } - ntot = qof_new - qof_rp; /* total # words of qof buf used */ - if (ntot - nvalid >= REPACK_THRESH || ntot >= QOF_GREEN_NELT - || (ntot > nvalid && nvalid >= QOF_GREEN_NELT - REPACK_THRESH)) { - repack_qof(); - if (qof_new - qof_rp != nvalid) { - printk("MSC: qof_present wrong\n"); - } - } else if (nvalid > 0) { - shuffle_qof(); - } - /* N.B. if nvalid == 0, msc_refill_sq has already reset the QBM's WP */ - SQ_NEW_MODE(NORMAL); - - /* dismiss the interrupt */ - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_QBMFUL_SH); -} - - -static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned intr; - unsigned long flags; - - save_flags(flags); cli(); - - if (intr_counter++ == INTR_LIMIT) { - mask_all_interrupts(); - printk("too many MSC interrupts\n"); - restore_flags(flags); - return; - } - - intr = MSC_IN(MSC_INTR); - -#if DEBUG - printk("CID(%d) msc_interrupt_11: intr = %x\n", mpp_cid(), intr); -#endif - - if (intr & (AP_INTR_REQ << MSC_INTR_RBMISS_SH)) { - int context; - context = MSC_IN(MSC_RMASREG) >> 20; - - msc_set_ringbuf(context); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBMISS_SH); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_RBFULL_SH)) { - int context = MSC_IN(MSC_RMASREG) >> 20; - msc_update_read_ptr(context,1); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBFULL_SH); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_SQFILL_SH)) { - qbmfill_interrupt(); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_QBMFUL_SH)) { - qbmful_interrupt(); - } - - restore_flags(flags); -} - - -void msc_timer(void) -{ - /* unmask all the interrupts that are supposed to be unmasked */ - intr_counter = 0; -} - -/* assumes NSENDQUEUES == 5 */ -static int log2tbl[32] = { - -1, 0, 1, -1, 2, -1, -1, -1, - 3, -1, -1, -1, -1, -1, -1, -1, - 4, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static unsigned long direct_queues[NSENDQUEUES][2] = { - { MSC_SYSTEM_DIRECT, MSC_SYSTEM_DIRECT_END }, - { MSC_REMOTE_DIRECT, MSC_REMOTE_DIRECT_END }, - { MSC_USER_DIRECT, MSC_USER_DIRECT_END }, - { MSC_REMREPLY_DIRECT, MSC_REMREPLY_DIRECT_END }, - { MSC_REPLY_DIRECT, MSC_REPLY_DIRECT_END } -}; - -/* - * Copy entries from the queue overflow buffer back to the send queue. - * This must be called with the send queue controller in THRU mode. - */ -static void refill_sq(void) -{ - int notfull, use_old; - int q, kept_some; - int sqp, sqc; - struct qof_elt *rp, *qof_wp; - int freew[NSENDQUEUES]; /* # free words in each queue */ - - /* give parallel tasks another chance */ - block_parallel_tasks = 0; - - /* get the qbm's write pointer */ - qof_wp = qof_base + (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) - & ((QOF_SIZE - 1) >> 3)); -#if 0 - printk("refill_sq: rp=%p new=%p wp=%p pres=[", - qof_rp, qof_new, qof_wp); - for (q = 0; q < NSENDQUEUES; ++q) - printk("%d ", qof_present[q]); - printk("]\n"); -#endif - - /* work out which send queues and aren't full */ - notfull = 0; - use_old = 0; - for (q = 0; q < NSENDQUEUES; ++q) { - sqp = MSC_IN(MSC_SQPTR0 + q * 8); - freew[q] = (EXTFIELD(sqp, MSC_SQP_RP) - EXTFIELD(sqp, MSC_SQP_WP) - 1) - & ((sqp & MSC_SQP_MODE)? 0x3f: 0x1f); - if (freew[q] > 0) - notfull |= 1 << (q + QOF_QUEUE_SH); - use_old += (freew[q] < qof_present[q])? freew[q]: qof_present[q]; - } - - /* - * If there are useful entries in the old part of the overflow - * queue, process them. - */ - kept_some = 0; - for (rp = qof_rp; rp < qof_new && use_old > 0; ++rp) { - if (rp->info & notfull) { - /* Here's one we can stuff back into the send queue */ - q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)]; - if (q < 0) { - printk("bad queue bits in qof info (%x) at %p\n", - rp->info, rp); - /* XXX just ignore this entry - should never happen */ - rp->info = 0; - continue; - } - MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data); - if (--freew[q] == 0) - notfull &= ~(1 << (q + QOF_QUEUE_SH)); - --qof_present[q]; - --use_old; - rp->info = 0; - } else if (!kept_some && rp->info != 0) { - qof_rp = rp; - kept_some = 1; - } - } - - /* Trim off any further already-used items. */ - if (!kept_some) { - for (; rp < qof_new; ++rp) { - if (rp->info) { - qof_rp = rp; - kept_some = 1; - break; - } - } - } - - /* - * Now process everything that's arrived since we last updated qof_new. - */ - for (rp = qof_new; rp < qof_wp; ++rp) { - if (rp->info == 0) - continue; - q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)]; - if (q < 0) { - printk("bad queue bits in qof info (%x) at %p\n", rp->info, rp); - /* XXX just ignore this entry - should never happen */ - rp->info = 0; - continue; - } - if (rp->info & notfull) { - /* Another one to stuff back into the send queue. */ - MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data); - if (--freew[q] == 0) - notfull &= ~(1 << (q + QOF_QUEUE_SH)); - rp->info = 0; - } else { - ++qof_present[q]; - if (!kept_some) { - qof_rp = rp; - kept_some = 1; - } - } - } - - /* Update state and the MSC queue-spill flags. */ - if (!kept_some) { - /* queue is empty; avoid unnecessary overflow interrupt later */ - qof_rp = qof_new = qof_base; - QBM_UPDATE_WP(mmu_v2p((unsigned long)qof_base)); - } else { - qof_new = qof_wp; - } - - sqc = MSC_IN(MSC_SQCTRL); - for (q = 0; q < NSENDQUEUES; ++q) - if (qof_present[q] == 0 && freew[q] > 0) - sqc &= ~(1 << (q + MSC_SQC_SPLF_SH)); - MSC_OUT(MSC_SQCTRL, sqc); -} - -/* - * Copy the valid entries from their current position - * in the queue overflow buffer to the beginning. - * This must be called with the send queue controller in THRU or BLOCKING mode. - */ -static void repack_qof(void) -{ - struct qof_elt *rp, *wp; - - wp = qof_base; - for (rp = qof_rp; rp < qof_new; ++rp) { - if (rp->info) { - if (rp > wp) - *wp = *rp; - ++wp; - } - } - qof_rp = qof_base; - qof_new = wp; - QBM_UPDATE_WP(wp); -} - -/* - * Copy all entries from their current position - * in the queue overflow buffer to the beginning. - * This must be called with the send queue controller in THRU or BLOCKING mode. - */ -static void shuffle_qof(void) -{ - int n; - - n = qof_new - qof_rp; - memmove(qof_base, qof_rp, n * sizeof(struct qof_elt)); - qof_rp = qof_base; - qof_new = qof_base + n; - QBM_UPDATE_WP(qof_new); -} - -static inline void handle_signal(int context,unsigned vaddr) -{ - int signum = (vaddr - MSC_REM_SIGNAL) >> PAGE_SHIFT; - int taskid = MPP_CTX_TO_TASK(context); - if (MPP_IS_PAR_TASK(taskid) && valid_task(task[taskid])) { - send_sig(signum,task[taskid],1); -#if DEBUG - printk("CID(%d) sent signal %d to task %d\n",mpp_cid(),signum,taskid); -#endif - } -} - - -/* - * fail a msc write operation. We use Pauls dirty tlb trick to avoide - * the msc hardware bugs - */ -static void fail_write(int context,int intr,unsigned vaddr) -{ - int tsk = MPP_CTX_TO_TASK(context); - int vpage = vaddr >> 12; -#if DEBUG - printk("fail write tsk=%d intr=%x vaddr=%x RMASREG=%x errproc=%x\n", - tsk,intr,vaddr,MSC_IN(MSC_RMASREG),MSC_IN(MSC_RHDERRPROC)); -#endif - - mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12), - vpage,context); - MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr); - - mc_tlb_unmap(vpage); - - if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) { - if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { - handle_signal(context,vaddr); - } else { - task[tsk]->thread.sig_address = vaddr; - task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING; - send_sig(SIGSEGV, task[tsk], 1); - } - } -} - -/* - * fail a msc read operation using the tlb trick */ -static void fail_read(int context,int intr,unsigned vaddr) -{ - int tsk = MPP_CTX_TO_TASK(context); -#if DEBUG - printk("fail read tsk=%d intr=%x\n",tsk,intr); -#endif - - mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12), - vaddr>>12,context); - MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr); - - mc_tlb_unmap(vaddr>>12); - - if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) { - if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { - handle_signal(context,vaddr); - } else { - task[tsk]->thread.sig_address = vaddr; - task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING; - send_sig(SIGSEGV, task[tsk], 1); - } - } -} - -static void async_callback(int tsk,unsigned long vaddr,int write,int ret) -{ - unsigned flags; - save_flags(flags); cli(); - - msc_blocked--; - if (write) { - intr_mask &= ~(AP_INTR_REQ << MSC_INTR_RMASF_SH); - if (ret) { - fail_write(MPP_TASK_TO_CTX(tsk),MSC_INTR_RMASF_SH,vaddr); - MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH); - restore_flags(flags); - return; - } - MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASF_SH); - MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH); - } else { - intr_mask &= ~(AP_INTR_REQ << MSC_INTR_SMASF_SH); - if (ret) { - fail_read(MPP_TASK_TO_CTX(tsk),MSC_INTR_SMASF_SH,vaddr); - MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH); - restore_flags(flags); - return; - } - MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT); - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH); - MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH); - } - restore_flags(flags); -} - - - -static inline void msc_write_fault(void) -{ - unsigned context = MSC_IN(MSC_RMASREG) >> 20; - unsigned vaddr = MSC_IN(MSC_RMASTWP)<<12; - - if (context == SYSTEM_CONTEXT) { - fail_write(context,MSC_INTR_RMASF_SH,vaddr); - show_mapping_ctx(0,context,vaddr); - printk("ERROR: system write fault at %x\n",vaddr); - return; - } - - if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { - fail_write(context,MSC_INTR_RMASF_SH,vaddr); - return; - } - - if (MPP_IS_PAR_CTX(context)) { - int tsk = MPP_CTX_TO_TASK(context); - if (valid_task(task[tsk]) && task[tsk]->ringbuf) { - MSC_OUT(MSC_INTR, - AP_SET_INTR_MASK << MSC_INTR_RMASF_SH); - intr_mask |= (AP_INTR_REQ << MSC_INTR_RMASF_SH); -#if DEBUG - show_mapping_ctx(0,context,vaddr); -#endif - msc_blocked++; - async_fault(vaddr,1,tsk,async_callback); - return; - } - } - -#if DEBUG - printk("CID(%d) mas write fault context=%x vaddr=%x\n", - mpp_cid(),context,vaddr); -#endif - - fail_write(context,MSC_INTR_RMASF_SH,vaddr); -} - - -static inline void msc_read_fault(void) -{ - unsigned context = MSC_IN(MSC_SMASREG) >> 20; - unsigned vaddr = MSC_IN(MSC_SMASTWP)<<12; - - if (context == SYSTEM_CONTEXT) { - fail_read(context,MSC_INTR_SMASF_SH,vaddr); - show_mapping_ctx(0,context,vaddr); - printk("ERROR: system read fault at %x\n",vaddr); - return; - } - - if (MPP_IS_PAR_CTX(context)) { - int tsk = MPP_CTX_TO_TASK(context); - - if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { - fail_read(context,MSC_INTR_SMASF_SH,vaddr); - return; - } - - if (valid_task(task[tsk]) && task[tsk]->ringbuf) { - MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_SMASF_SH); - intr_mask |= (AP_INTR_REQ << MSC_INTR_SMASF_SH); - msc_blocked++; - async_fault(vaddr,0,tsk,async_callback); - return; - } - } - -#if DEBUG - printk("CID(%d) mas read fault context=%x vaddr=%x\n", - mpp_cid(),context,vaddr); -#endif - - fail_read(context,MSC_INTR_SMASF_SH,vaddr); -} - - - -static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - unsigned intr, cnt, r; - - save_flags(flags); cli(); - - if (intr_counter++ == INTR_LIMIT) { - mask_all_interrupts(); - printk("too many MSC interrupts\n"); - restore_flags(flags); - return; - } - - intr = MSC_IN(MSC_INTR) & ~intr_mask; - -#if DEBUG - printk("CID(%d) msc_interrupt_9: intr = %x\n", mpp_cid(), intr); -#endif - - if (intr & (AP_INTR_REQ << MSC_INTR_RMASF_SH)) { - msc_write_fault(); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_SMASF_SH)) { - msc_read_fault(); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_RMASE_SH)) { - printk("recv mas error interrupt (write)\n"); - printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL)); - printk("rmasadr = %x %x\n", MSC_IN(MSC_RMASADR), - MSC_IN(MSC_RMASADR + 4)); - printk("rmastwp = %x\n", MSC_IN(MSC_RMASTWP)); - printk("rmasreg = %x\n", MSC_IN(MSC_RMASREG)); - r = MSC_IN(MSC_RMASREG); - if ((r & MSC_MASR_AVIO) || (r & MSC_MASR_CMD) != MSC_MASR_CMD_XFER) - /* throw away the rest of the incoming data */ - MSC_OUT(MSC_RHDERRPROC, 0); - /* clear the interrupt */ - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASE_SH); - } - - if (intr & (AP_INTR_REQ << MSC_INTR_SMASE_SH)) { - printk("send mas error interrupt (read)\n"); - printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL)); - printk("smasadr = %x %x\n", MSC_IN(MSC_SMASADR), - MSC_IN(MSC_SMASADR + 4)); - printk("smascnt = %x\n", MSC_IN(MSC_SMASCNT)); - printk("smastwp = %x\n", MSC_IN(MSC_SMASTWP)); - printk("smasreg = %x\n", MSC_IN(MSC_SMASREG)); - /* supply dummy data */ - cnt = MSC_IN(MSC_SMASCNT); - switch (MSC_IN(MSC_SMASREG) & MSC_MASR_CMD) { - case MSC_MASR_CMD_XFER: - MSC_OUT(MSC_HDGERRPROC, (EXTFIELD(cnt, MSC_SMCT_MCNT) - + EXTFIELD(cnt, MSC_SMCT_ICNT))); - break; - /* case remote read: */ - case MSC_MASR_CMD_FOP: - case MSC_MASR_CMD_CSI: - MSC_OUT(MSC_HDGERRPROC, 1); - break; - } - /* clear interrupt */ - MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH); - } - - restore_flags(flags); -} - -/* - * remove access to a tasks ring buffer - */ -void msc_unset_ringbuf(int i) -{ - int ctx = MSC_IN(ringbufs[i].rbmmode) & CTX_MASK; - int tsk = MPP_CTX_TO_TASK(ctx); - struct ringbuf_struct *rbuf; - -#if DEBUG - printk("msc_unset_ringbuf(%d) %x\n",i,ctx); -#endif - - MSC_OUT(ringbufs[i].rbmmode,NULL_CONTEXT); - if (ctx == SYSTEM_CONTEXT) { - rbuf = &system_ringbuf; - } else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && - valid_task(task[tsk]) && task[tsk]->ringbuf) { - rbuf = task[tsk]->ringbuf; - } else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && - valid_task(task[tsk]) && task[tsk]->aplib) { - rbuf = &system_ringbuf; - } else { - rbuf = &dummy_ringbuf; - } - - rbuf->write_ptr = MSC_IN(ringbufs[i].rbmbwp); -} - -static void msc_update_read_ptr(int context,int overflow) -{ - int i; - unsigned new_read_ptr; - - for (i=0;iringbuf) { - struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)]; - struct _kernel_cap_shared *_kernel; - unsigned soft_read_ptr; - unsigned octx; - - octx = apmmu_get_context(); - if (octx != context) - apmmu_set_context(context); - _kernel = (struct _kernel_cap_shared *)(RBUF_VBASE + RBUF_SHARED_PAGE_OFF); - soft_read_ptr = _kernel->rbuf_read_ptr; - if (octx != context) - apmmu_set_context(octx); - - if (overflow && MSC_IN(ringbufs[i].rbmrp) == soft_read_ptr) { - /* send them a SIGLOST and wipe their ring buffer */ - printk("ring buffer overflow for %s ctx=%x\n", - tsk->comm,context); - send_sig(SIGLOST,tsk,1); - soft_read_ptr--; - } - new_read_ptr = soft_read_ptr; - } else if (MPP_IS_PAR_CTX(context) && - valid_task(task[MPP_CTX_TO_TASK(context)]) && - task[MPP_CTX_TO_TASK(context)]->aplib) { - tnet_check_completion(); - if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr) - printk("system ringbuffer overflow\n"); - new_read_ptr = system_read_ptr; - } else { - dummy_read_ptr = MSC_IN(ringbufs[i].rbmrp) - 1; - new_read_ptr = dummy_read_ptr - 1; -#if DEBUG - if (overflow) - printk("reset dummy ring buffer for context %x\n", - context); -#endif - } - - - MSC_OUT(ringbufs[i].rbmrp,new_read_ptr); -} - -/* - * give a task one of the system ring buffers - * this is called on a context miss interrupt, so we can assume that - * the tasks context is not currently set in one of the ringbufs - */ -static void msc_set_ringbuf(int context) -{ - int i; - int ctx; - int mode; - unsigned write_ptr; - static unsigned next_ctx = 0; - struct ringbuf_struct *rbuf; - - if (context == SYSTEM_CONTEXT) { - rbuf = &system_ringbuf; - } else if (MPP_IS_PAR_CTX(context) && - valid_task(task[MPP_CTX_TO_TASK(context)]) && - task[MPP_CTX_TO_TASK(context)]->ringbuf) { - struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)]; - rbuf = tsk->ringbuf; - } else if (MPP_IS_PAR_CTX(context) && - valid_task(task[MPP_CTX_TO_TASK(context)]) && - task[MPP_CTX_TO_TASK(context)]->aplib) { - rbuf = &system_ringbuf; - } else { - /* use the dummy ring buffer */ - rbuf = &dummy_ringbuf; - } - - for (i=0;iwrite_ptr; - mode = (rbuf->order - 5) >> 1; - - MSC_OUT(ringbufs[i].rbmmode,context | (mode << 12)); - MSC_OUT(ringbufs[i].rbmbwp,write_ptr); - - if (rbuf == &system_ringbuf) { - MSC_OUT(ringbufs[i].rbmrp,system_read_ptr); - } else { - msc_update_read_ptr(context,0); - } - -#if DEBUG - printk("CID(%d) mapped ringbuf for context %d in slot %d\n", - mpp_cid(),context,i); -#endif -} - - -/* - * this is called when a task exits -*/ -void exit_msc(struct task_struct *tsk) -{ - int i; - - if (!MPP_IS_PAR_TASK(tsk->taskid)) - return; - -#if DEBUG - printk("exit_msc(%d) ctx=%d\n",tsk->taskid,tsk->mm->context); -#endif - - for (i=0;itaskid)) - msc_unset_ringbuf(i); - } - msc_switch_from_check(tsk); - - /* stop it receiving new-style messages */ - tsk->aplib = NULL; - - exit_ringbuf(tsk); -} - - -static void msc_sq_pause(void) -{ - MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) | MSC_SQC_PAUSE); - while (!(MSC_IN(MSC_SQCTRL) & MSC_SQC_STABLE)) /* wait for stable bit */ ; -} - -static void msc_sq_resume(void) -{ - MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) & ~MSC_SQC_PAUSE); -} - -static void msc_switch_from_check(struct task_struct *tsk) -{ - int user_count; - unsigned flags; - struct ringbuf_struct *rbuf = NULL; - int octx, ctx; - - if (valid_task(tsk) && tsk->ringbuf) - rbuf = tsk->ringbuf; - - /* it doesn't seem obvious why this field should contain count+1, - but it does */ - user_count = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1; - - /* check if the user queue count is != 0 */ - if (user_count == 0) return; - - if (!rbuf) - printk("switching from dead task\n"); - -#if 1 - printk("saving %d words MSC_QWORDCNT=%x\n", - user_count,MSC_IN(MSC_QWORDCNT)); -#endif - - /* bugger - we have to do some messy work */ - save_flags(flags); cli(); - - ctx = MPP_TASK_TO_CTX(tsk->taskid); - octx = apmmu_get_context(); - if (octx != ctx) - apmmu_set_context(ctx); - - msc_sq_pause(); - - /* remember the expected length of the command - usually (always?) 8 */ - if (rbuf) - rbuf->frag_len = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRLEN); - - /* pull words from the overflow first */ - if (MSC_IN(MSC_SQCTRL) & MSC_SQC_USERF) { - /* we have overflowed */ - struct qof_elt *qof_wp = qof_base + - (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) & ((QOF_SIZE - 1) >> 3)); - while (qof_wp != qof_rp && user_count) { - qof_wp--; - /* only grab elements in the user queue */ - if (qof_wp->info && log2tbl[EXTFIELD(qof_wp->info, QOF_QUEUE)] == 2) { - if (qof_wp->info & 1) { - printk("MSC: end bit set - yikes!\n"); - } - qof_wp->info = 0; - if (rbuf) { - rbuf->sq_fragment[--user_count] = qof_wp->data; - rbuf->frag_count++; - } - if (qof_wp < qof_new) - qof_present[2]--; - } - } -#if DEBUG - if (rbuf) - printk("pulled %d elements from overflow (%d left)\n", - rbuf->frag_count,user_count); -#endif - } - - /* then pull words direct from the msc ram */ - if (user_count) { - int wp = EXTFIELD(MSC_IN(MSC_SQPTR2),MSC_SQP_WP); - int i; - wp -= user_count; - if (wp < 0) wp += send_queues[2].size; - - for (i=0;isq_fragment[i + rbuf->frag_count] = - MSC_IN(MSC_SQRAM + (send_queues[2].base + wp2)*8); - } - - if (rbuf) - rbuf->frag_count += user_count; - - MSC_OUT(MSC_SQPTR2,INSFIELD(MSC_IN(MSC_SQPTR2),wp,MSC_SQP_WP)); -#if DEBUG - printk("saved %d words from msc ram\n",rbuf->frag_count); -#endif - } - - /* reset the user count to 1 */ - MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),1,MSC_QWDC_USRCNT)); - - msc_sq_resume(); - - if (octx != ctx) - apmmu_set_context(octx); - - restore_flags(flags); -} - -static void msc_switch_to_check(struct task_struct *tsk) -{ - int i; - unsigned flags; - int octx, ctx; - - if (!valid_task(tsk) || !tsk->ringbuf) - return; - - save_flags(flags); cli(); - - - ctx = MPP_TASK_TO_CTX(tsk->taskid); - octx = apmmu_get_context(); - if (octx != ctx) - apmmu_set_context(ctx); - - /* if the task we are switching to has no saved words then - we're finished */ - if (tsk->ringbuf->frag_count == 0) { - if (octx != ctx) - apmmu_set_context(octx); - restore_flags(flags); - return; - } - - -#if 1 - printk("frag fill MSC_QWORDCNT=%x frag_count=%d\n", - MSC_IN(MSC_QWORDCNT),tsk->ringbuf->frag_count); -#endif - - /* reset the user length */ - MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT), - tsk->ringbuf->frag_len, - MSC_QWDC_USRLEN)); - - /* push the words into the direct queue */ - for (i=0;iringbuf->frag_count;i++) - MSC_OUT(MSC_USER_DIRECT,tsk->ringbuf->sq_fragment[i]); - - /* reset the user count */ - MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT), - 1+tsk->ringbuf->frag_count, - MSC_QWDC_USRCNT)); - -#if DEBUG - printk("frag fill done MSC_QWORDCNT=%x\n", - MSC_IN(MSC_QWORDCNT)); -#endif - - tsk->ringbuf->frag_count = 0; - tsk->ringbuf->frag_len = 0; - if (octx != ctx) - apmmu_set_context(octx); - restore_flags(flags); -} - - - -void msc_switch_check(struct task_struct *tsk) -{ - static int last_task = 0; - - if (last_task == tsk->taskid) return; - - if (MPP_IS_PAR_TASK(last_task)) - msc_switch_from_check(task[last_task]); - - msc_switch_to_check(tsk); - - last_task = tsk->taskid; -} - -/* we want to try to avoid task switching while there are partial commands - in the send queues */ -int msc_switch_ok(void) -{ - if ((EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1)) - return 0; - - return 1; -} - -/* - * print out the state of the msc -*/ -static void msc_status(void) -{ - int i; - - printk("MSC_SQCTRL=%x\n",MSC_IN(MSC_SQCTRL)); - - for (i=0;i<5;i++) - printk("MSC_SQPTR%d=%x\n",i,MSC_IN(MSC_SQPTR0 + 8*i)); - printk("MSC_OPTADR=%x\n",MSC_IN(MSC_OPTADR)); - printk("MSC_MASCTRL=%x\n", MSC_IN(MSC_MASCTRL)); - printk("MSC_SMASADR=%x_%x\n", MSC_IN(MSC_SMASADR),MSC_IN(MSC_SMASADR + 4)); - printk("MSC_RMASADR=%x_%x\n", MSC_IN(MSC_RMASADR),MSC_IN(MSC_RMASADR + 4)); - printk("MSC_PID=%x\n",MSC_IN(MSC_PID)); - - printk("MSC_QWORDCNT=%x\n",MSC_IN(MSC_QWORDCNT)); - - printk("MSC_INTR=%x\n",MSC_IN(MSC_INTR)); - printk("MSC_CIDRANGE=%x\n",MSC_IN(MSC_CIDRANGE)); - printk("MSC_QBMPTR=%x\n",MSC_IN(MSC_QBMPTR)); - printk("MSC_SMASTWP=%x\n", MSC_IN(MSC_SMASTWP)); - printk("MSC_RMASTWP=%x\n", MSC_IN(MSC_RMASTWP)); - printk("MSC_SMASREG=%x\n", MSC_IN(MSC_SMASREG)); - printk("MSC_RMASREG=%x\n", MSC_IN(MSC_RMASREG)); - printk("MSC_SMASCNT=%x\n", MSC_IN(MSC_SMASCNT)); - printk("MSC_IRL=%x\n", MSC_IN(MSC_IRL)); - printk("MSC_SIMMCHK=%x\n", MSC_IN(MSC_SIMMCHK)); - - for (i=0;i<3;i++) { - printk("RBMBWP%d=%x\n",i,MSC_IN(ringbufs[i].rbmbwp)); - printk("RBMMODE%d=%x\n",i,MSC_IN(ringbufs[i].rbmmode)); - printk("RBMRP%d=%x\n",i,MSC_IN(ringbufs[i].rbmrp)); - } - - printk("DMA_GEN=%x\n",MSC_IN(DMA_GEN)); - - printk("qbm_full_counter=%d\n",qbm_full_counter); -} diff -ur --new-file old/linux/arch/sparc/ap1000/sync.c new/linux/arch/sparc/ap1000/sync.c --- old/linux/arch/sparc/ap1000/sync.c Wed Sep 1 23:12:09 1999 +++ new/linux/arch/sparc/ap1000/sync.c Thu Jan 1 01:00:00 1970 @@ -1,55 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* sync functions using the Tnet */ - -#include -#include -#include -#include - -extern int cap_cid0; -extern unsigned _ncel, _ncelx, _ncely, _cid; - -static volatile int sync_flags[MPP_NUM_TASKS]; - - -int ap_sync(int numcells, int *phys_map) -{ - int basecell; - int i,err; - int tsk = current->taskid; - - if (numcells < 2) return 0; - - if (!MPP_IS_PAR_TASK(tsk)) { - printk("nonparallel task %d called ap_sync\n",tsk); - return 0; - } - tsk -= MPP_TASK_BASE; - - basecell = phys_map[0]; - if (cap_cid0 == basecell) { - if ((err=wait_on_int(&sync_flags[tsk],numcells-1,5))) - return err; - sync_flags[tsk] = 0; - if (numcells == _ncel) { - ap_bput(0,0,0,&sync_flags[tsk],0); - } else { - for (i=1;i -#include -#include -#include -#include -#include -#include -#include - -#define INIT_TIM1 (781250/HZ) -#define INIT_TIM0 (781250/(10*HZ)) - -static unsigned long last_freerun; - -unsigned ap_freerun(void) -{ - return *((volatile unsigned long *)(MC_FREERUN + 4)); -} - -void ap_clear_clock_irq(void) -{ - MC_OUT(MC_INTR, AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH); - last_freerun = *((unsigned long *)(MC_FREERUN + 4)); - tnet_check_completion(); -#if 1 - if ((((unsigned)jiffies) % (HZ/4)) == 0) { - msc_timer(); - ap_xor_led(1); - bif_timer(); - ap_dbg_flush(); -#if 0 - bif_led_status(); -#endif - } -#endif -} - - -void ap_gettimeofday(struct timeval *xt) -{ - unsigned long d; - unsigned v; - unsigned long new_freerun; - - /* this is in 80ns units - we only use the low 32 bits - as 5mins is plenty for this stuff */ - d = new_freerun = *((unsigned long *)(MC_FREERUN + 4)); - - if (d < last_freerun) { - /* wraparound */ - d += ((~0) - last_freerun); - } else { - d -= last_freerun; - } - - /* convert to microseconds */ - v = ((d&0xffffff)*10)/125; - - /* only want microseconds/HZ */ - v = v%(1000000/HZ); - - xt->tv_usec += v; - - last_freerun = new_freerun; -} - -static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long ip = instruction_pointer(regs); - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - if (ip < prof_len) - prof_buffer[ip]++; - } - MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); -} - -void ap_profile_init(void) -{ - if (prof_shift) { - printk("Initialising profiling with prof_shift=%d\n",(int)prof_shift); - MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); - MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM0_SH); - } -} - -void ap_init_timers(void) -{ - extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs); - unsigned flags; - - printk("Initialising ap1000 timer\n"); - - save_flags(flags); cli(); - - request_irq(APTIM1_IRQ, - timer_interrupt, - (SA_INTERRUPT | SA_STATIC_ALLOC), - "timer", NULL); - - request_irq(APTIM0_IRQ, - profile_interrupt, - (SA_INTERRUPT | SA_STATIC_ALLOC), - "profile", NULL); - - ap_clear_clock_irq(); - - MC_OUT(MC_ITIMER0,INIT_TIM0); - MC_OUT(MC_ITIMER1,INIT_TIM1); - MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH); - MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM1_SH); - MC_OUT(MC_INTR,AP_SET_INTR_MASK << MC_INTR_ITIM0_SH); - restore_flags(flags); -} diff -ur --new-file old/linux/arch/sparc/ap1000/tnet.c new/linux/arch/sparc/ap1000/tnet.c --- old/linux/arch/sparc/ap1000/tnet.c Wed Aug 5 01:03:34 1998 +++ new/linux/arch/sparc/ap1000/tnet.c Thu Jan 1 01:00:00 1970 @@ -1,708 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* routines to control the AP1000 Tnet interface */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* message types for system messages */ -#define TNET_IP 0 -#define TNET_IP_SMALL 1 -#define TNET_RPC 2 - -static struct { - int errors; - int alloc_errors; - int bytes_received; - int bytes_sent; - int packets_received; - int packets_sent; - int small_packets_received; - int small_packets_sent; -} tnet_stats; - -extern int cap_cid0; -extern int cap_ncel0; -static u_long xy_global_head; - -extern unsigned _ncel, _ncelx, _ncely, _cid, _cidx, _cidy; - -extern struct ringbuf_struct system_ringbuf; -extern u_long system_read_ptr; - -u_long system_recv_flag = 0; -static u_long system_recv_count = 0; - -int *tnet_rel_cid_table; - -static int dummy=1; - -#define TNET_IP_THRESHOLD 100 - -void tnet_check_completion(void); -static void reschedule(void); -static u_long tnet_add_completion(void (*fn)(int a1,...), - int a1,int a2); -static void tnet_info(void); - -static struct { - int shift; - void (*fn)(void); -} iports[4] = { - {MC_INTP_0_SH,tnet_check_completion}, - {MC_INTP_1_SH,reschedule}, - {MC_INTP_2_SH,NULL}, - {MC_INTP_3_SH,NULL}}; - -static inline int rel_cid(unsigned dst) -{ - unsigned dstx, dsty; - unsigned dx,dy; - - if (dst == _cid) return 0; - - dstx = dst % _ncelx; - dsty = dst / _ncelx; - if (dstx >= _cidx) - dx = dstx - _cidx; - else - dx = (_ncelx - _cidx) + dstx; - - if (dsty >= _cidy) - dy = dsty - _cidy; - else - dy = (_ncely - _cidy) + dsty; - - return (dx<<8) | dy; -} - -#define SAVE_PID() \ - unsigned long flags; \ - int saved_pid; \ - save_flags(flags); cli(); \ - saved_pid = MSC_IN(MSC_PID); \ - MSC_OUT(MSC_PID,SYSTEM_CONTEXT); - -#define RESTORE_PID() \ - MSC_OUT(MSC_PID,saved_pid); \ - restore_flags(flags); - - -void ap_put(int dest_cell,u_long local_addr,int size, - u_long remote_addr,u_long dest_flag,u_long local_flag) -{ - volatile u_long *entry; - SAVE_PID(); - - entry = (volatile u_long *)MSC_PUT_QUEUE_S; - - *entry = tnet_rel_cid_table[dest_cell]; - *entry = ((size+3) >> 2); - *entry = (u_long)remote_addr; - *entry = 0; - *entry = (u_long)dest_flag; - *entry = (u_long)local_flag; - *entry = (u_long)local_addr; - *entry = 0; - RESTORE_PID(); -} - -/* remote_addr is physical - local address is virtual - both flags are virtual */ -void ap_phys_put(int dest_cell,u_long local_addr,int size, - u_long remote_addr,u_long dest_flag,u_long local_flag) -{ - volatile u_long *entry; - SAVE_PID(); - - entry = (volatile u_long *)MSC_CPUT_QUEUE_S; - - *entry = tnet_rel_cid_table[dest_cell]; - *entry = ((size+3) >> 2); - *entry = (u_long)remote_addr; - *entry = 0; - *entry = (u_long)dest_flag; - *entry = (u_long)local_flag; - *entry = (u_long)local_addr; - *entry = 0; - RESTORE_PID(); -} - - -/* broadcast put - yeah! */ -void ap_bput(u_long local_addr,int size, - u_long remote_addr,u_long dest_flag,u_long local_flag) -{ - volatile u_long *entry = (volatile u_long *)MSC_XYG_QUEUE_S; - SAVE_PID(); - - *entry = xy_global_head; - *entry = ((size+3) >> 2); - *entry = (u_long)remote_addr; - *entry = 0; - *entry = (u_long)dest_flag; - *entry = (u_long)local_flag; - *entry = (u_long)local_addr; - *entry = 0; - RESTORE_PID(); -} - - -/* remote_addr is physical */ -void ap_phys_bput(u_long local_addr,int size, - u_long remote_addr,u_long dest_flag,u_long local_flag) -{ - volatile u_long *entry = (volatile u_long *)MSC_CXYG_QUEUE_S; - SAVE_PID(); - - *entry = xy_global_head; - *entry = ((size+3) >> 2); - *entry = (u_long)remote_addr; - *entry = 0; - *entry = (u_long)dest_flag; - *entry = (u_long)local_flag; - *entry = (u_long)local_addr; - *entry = 0; - RESTORE_PID(); -} - - - -void ap_get(int dest_cell,u_long local_addr,int size, - u_long remote_addr,u_long local_flag,u_long dest_flag) -{ - volatile u_long *entry; - SAVE_PID(); - - entry = (u_long *)MSC_GET_QUEUE_S; - - *entry = tnet_rel_cid_table[dest_cell]; - *entry = (size+3) >> 2; /* byte --> word */ - *entry = (u_long)local_addr; - *entry = 0; - *entry = (u_long)local_flag; - *entry = (u_long)dest_flag; - *entry = (u_long)remote_addr; - *entry = 0; - RESTORE_PID(); -} - - -/* local_addr is physical - remote_addr is virtual - both flags are virtual -*/ -void ap_phys_get(int dest_cell,u_long local_addr,int size, - u_long remote_addr,u_long local_flag,u_long dest_flag) -{ - volatile u_long *entry; - SAVE_PID(); - - entry = (u_long *)MSC_CGET_QUEUE_S; - - *entry = tnet_rel_cid_table[dest_cell]; - *entry = (size+3) >> 2; /* byte --> word */ - *entry = (u_long)local_addr; - *entry = 0; - *entry = (u_long)local_flag; - *entry = (u_long)dest_flag; - *entry = (u_long)remote_addr; - *entry = 0; - RESTORE_PID(); -} - - -/* - * copy a message from the ringbuffer - being careful of wraparound -*/ -static inline void tnet_copyin(unsigned *dest,unsigned *src,int size) -{ - unsigned *limit = (unsigned *)system_ringbuf.ringbuf + - (SYSTEM_RINGBUF_SIZE>>2); - int size1 = limit - src; - - if (size < size1) - size1 = size; - - size -= size1; - while (size1--) { - *dest++ = *src++; - } - src = system_ringbuf.ringbuf; - while (size--) { - *dest++ = *src++; - } -} - - -/* - put some data into a tasks ringbuffer. size is in words. - */ -static inline void memcpy_to_rbuf(unsigned tid,unsigned *msgp,unsigned size) -{ - struct aplib_struct *aplib; - unsigned octx, ctx; - struct task_struct *tsk; - unsigned room; - - tsk = task[tid]; - if (!tsk || !tsk->aplib) - return; - - octx = srmmu_get_context(); - ctx = MPP_TASK_TO_CTX(tid); - if (octx != ctx) - srmmu_set_context(ctx); - aplib = tsk->aplib; - - if (aplib->write_pointer < aplib->read_pointer) - room = aplib->read_pointer - (aplib->write_pointer+1); - else - room = aplib->ringbuf_size - - ((aplib->write_pointer+1)-aplib->read_pointer); - - if (room < size) { - send_sig(SIGLOST,tsk,1); - goto finished; - } - - tnet_copyin(&aplib->ringbuf[aplib->write_pointer], msgp, size); - - aplib->write_pointer += size; - if (aplib->write_pointer >= aplib->ringbuf_size) - aplib->write_pointer -= aplib->ringbuf_size; - - aplib->rbuf_flag1++; - -finished: - if (octx != ctx) - srmmu_set_context(octx); -} - - - -/* a aplib message has arrived on the system message queue - process - it immediately and return the number of bytes taken by the message in - the system ringbuffer - - Note that this function may be called from interrupt level - */ -static inline void aplib_system_recv(unsigned *msgp) -{ - unsigned tag = msgp[1]>>28; - unsigned size, tid; - - if (tag == RBUF_BIGSEND) { - aplib_bigrecv(msgp); - return; - } - - size = (msgp[0]&0xFFFFF); - tid = (msgp[1]&0x3FF); - - memcpy_to_rbuf(tid,msgp,size+2); -} - - -void tnet_ip_complete(struct sk_buff *skb,int from) -{ -#if IP_DEBUG - char *data = skb->data; - int i; - printk("CID(%d) tnet ip complete from %d\n",_cid,from); - - for (i=0;ilen;i+=4) - printk("(%08x)%c",*(int *)(data+i),i==32?'\n':' '); - printk("\n"); -#endif - /* ap_phys_put(from,(u_long)&dummy,4,MC_INTP_0,0,0); */ - bif_rx(skb); - tnet_stats.bytes_received += skb->len; - tnet_stats.packets_received++; -} - - -static void tnet_ip_recv(int cid,u_long *info) -{ - u_long flag; - u_long ipsize = info[1]; - u_long remote_addr = info[0]; - u_long remote_flag = info[2]; - struct sk_buff *skb = dev_alloc_skb(ipsize+8); - char *p; - - if (!skb) { - ap_put(cid,0,0,0,remote_flag,0); - ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0); - tnet_stats.alloc_errors++; - return; - } - - skb_reserve(skb,8); /* align on 16 byte boundary */ - - flag = tnet_add_completion(tnet_ip_complete,(int)skb,(int)cid); - - p = (char *)skb_put(skb,ipsize); -#if 0 -{ - static unsigned count=0; - if (count%500 == 0) - printk("CID(%d) fetching %d bytes from %x to %x\n", - _cid,ipsize,remote_addr,p); - count++; -} -#endif - ap_get(cid,p,ipsize,remote_addr,flag,remote_flag); - ap_phys_get(cid,MC_INTP_0,4,(u_long)&dummy,0,0); -#if IP_DEBUG - printk("CID(%d) ip packet of length %ld from %ld\n",_cid,ipsize,cid); -#endif -} - - -static void tnet_ip_recv_small(u_long *data,int size) -{ - struct sk_buff *skb = dev_alloc_skb(size+8); - if (skb) { - skb_reserve(skb,8); - tnet_copyin((unsigned *)skb_put(skb,size),(unsigned *)data,(size+3)>>2); - bif_rx(skb); - tnet_stats.bytes_received += size; - tnet_stats.packets_received++; - tnet_stats.small_packets_received++; - } else { - tnet_stats.alloc_errors++; - } -} - - -/* we've got an RPC from a remote cell */ -static void tnet_rpc_recv(u_long *data,int size) -{ - struct fnp { - void (*fn)(); - } fnp; - fnp = *(struct fnp *)data; - fnp.fn(data,size); -} - -/* - * receive messages from the system ringbuffer. We don't bother with - * all the niceities that are done in user space, we just always - * process the messages in order - */ -static inline void tnet_recv(void) -{ - unsigned flags; - u_long from,*data,fix,align,size1,size,type; - - if (system_recv_flag == system_recv_count) - return; - - save_flags(flags); cli(); - while (system_recv_flag != system_recv_count) { - u_long read_ptr = - (system_read_ptr + 1) % (SYSTEM_RINGBUF_SIZE>>5); - u_long *msgp = - ((u_long *)system_ringbuf.ringbuf) + (read_ptr<<3); - u_long tag = (msgp[1]>>28) & 0xF; - size1 = (msgp[0]&0xFFFFF)<<2; - - /* move our read pointer past this message */ - system_read_ptr = (system_read_ptr + - ((size1+8+31)>>5))%(SYSTEM_RINGBUF_SIZE>>5); - system_recv_count++; - - - if (tag != RBUF_SYSTEM) { - aplib_system_recv(msgp); - continue; - } - - from = msgp[0] >> 22; - data = msgp+2; - fix = (msgp[0]>>20)&3; - align = (msgp[1]>>26)&3; - size = ((size1 - align) & ~3) | fix; - type = (msgp[1]&0xFF); - - switch (type) { - case TNET_IP: - tnet_ip_recv(from,data); - break; - - case TNET_IP_SMALL: - tnet_ip_recv_small(data,size); - break; - - case TNET_RPC: - tnet_rpc_recv(data,size); - break; - - default: - tnet_stats.errors++; - printk("unknown Tnet type %ld\n",type); - } - -#if DEBUG - printk("CID(%d) recvd %d bytes of type %d read_ptr=%x\n", - _cid,size,type,system_read_ptr); -#endif - } - restore_flags(flags); -} - - -#define COMPLETION_LIST_LENGTH 256 - -static unsigned completion_list_rp = 0; -static unsigned completion_list_wp = 0; - -static volatile struct completion_struct { - u_long flag; - void (*fn)(int a1,...); - u_long args[2]; -} completion_list[COMPLETION_LIST_LENGTH]; - - -void tnet_check_completion(void) -{ - struct completion_struct *cs; - unsigned flags; - - tnet_recv(); - - if (completion_list[completion_list_rp].flag != 2) - return; - - save_flags(flags); cli(); - - while (completion_list[completion_list_rp].flag == 2) { - cs = &completion_list[completion_list_rp]; - cs->flag = 0; - if (++completion_list_rp == COMPLETION_LIST_LENGTH) - completion_list_rp = 0; - - restore_flags(flags); - - cs->fn(cs->args[0],cs->args[1]); - - if (completion_list[completion_list_rp].flag != 2) - return; - - save_flags(flags); cli(); - } - - restore_flags(flags); -} - - -static u_long tnet_add_completion(void (*fn)(int a1,...),int a1,int a2) -{ - unsigned flags; - struct completion_struct *cs; - - save_flags(flags); cli(); - - while (completion_list[completion_list_wp].flag != 0) - tnet_check_completion(); - - cs = &completion_list[completion_list_wp]; - - if (++completion_list_wp == COMPLETION_LIST_LENGTH) - completion_list_wp = 0; - - restore_flags(flags); - - cs->flag = 1; - cs->fn = fn; - cs->args[0] = a1; - cs->args[1] = a2; - - return (u_long)&cs->flag; -} - - -/* - * send a message to the tnet ringuffer on another cell. When the send has - * completed call fn with the args supplied - */ -static void tnet_send(long cid,long type,char *src_addr,long byteSize, - int immediate,u_long flag) -{ - int wordSize; - int byteAlign, byteFix; - u_long src; - u_long info1, info2; - volatile u_long *entry = (volatile u_long *)MSC_SEND_QUEUE_S; - SAVE_PID(); - - byteAlign = ((u_long)src_addr) & 0x3; - byteFix = byteSize & 0x3; - - src = (u_long)src_addr & ~3; - - wordSize = (byteSize + byteAlign + 3) >> 2; - - info1 = (_cid << 22) | (byteFix << 20) | wordSize; - info2 = (RBUF_SYSTEM<<28) | (byteAlign << 26) | type; - - *entry = tnet_rel_cid_table[cid]; - *entry = wordSize; - *entry = (u_long)&system_recv_flag; - *entry = flag; - *entry = (u_long)src; - *entry = 0; - *entry = info1; - *entry = info2; - RESTORE_PID(); - - ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0); - if (immediate && flag) - ap_phys_put(_cid,(u_long)&dummy,4,MC_INTP_0,0,0); -} - - -static void free_skb(struct sk_buff *skb, int op) -{ - dev_kfree_skb(skb); -} - -void tnet_send_ip(int cid,struct sk_buff *skb) -{ - char *data = skb->data + sizeof(struct cap_request); - int size = skb->len - sizeof(struct cap_request); - u_long flag; -#if IP_DEBUG - int i; - for (i=0;i TNET_IP_THRESHOLD) { - int *info = (int *)skb->data; /* re-use the header */ - info[0] = (int)data; - info[1] = size; - info[2] = tnet_add_completion(free_skb, (int)skb, 0); - tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0); - } else { - flag = tnet_add_completion(free_skb, (int)skb, 0); - tnet_send(cid,TNET_IP_SMALL,data,size,0,flag); - tnet_stats.small_packets_sent++; - } - tnet_stats.packets_sent++; - tnet_stats.bytes_sent += size; -#if IP_DEBUG - printk("CID(%d) sent IP of size %d to %d\n",_cid,size,cid); -#endif -} - -static void reschedule(void) -{ - current->need_resched = 1; - mark_bh(TQUEUE_BH); -} - - -/* make a remote procedure call - If free is set then free the data after sending it - The first element of data is presumed to be a function pointer -*/ -int tnet_rpc(int cell,char *data,int size,int free) -{ - unsigned flag=0; - - if (free) { - flag = tnet_add_completion(kfree,data,0); - } - - tnet_send(cell,TNET_RPC,data,size,0,flag); - return 0; -} - - -static void iport_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int i; - u_long intr = MC_IN(MC_INTR_PORT); - - for (i=0;i<4;i++) { - if (intr & (AP_INTR_REQ << iports[i].shift)) { - MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift); - if (iports[i].fn) iports[i].fn(); - } - } -} - - -void ap_tnet_init(void) -{ - int i; - - bif_add_debug_key('T',tnet_info,"Tnet status"); - - memset(completion_list,0,sizeof(completion_list)); - - request_irq(APIPORT_IRQ, iport_irq, SA_INTERRUPT, "iport", 0); - - for (i=0;i<4;i++) { - MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift); - MC_OUT(MC_INTR_PORT,AP_CLR_INTR_MASK << iports[i].shift); - } - - - tnet_rel_cid_table = (int *)kmalloc(sizeof(int)*_ncel,GFP_ATOMIC); - for (i=0;i<_ncel;i++) - tnet_rel_cid_table[i] = rel_cid(i); - - if(_cid == 0) { - xy_global_head = (((_ncelx -1) << 8) & 0xff00) | - ((_ncely - 1) & 0xff); - } - else { - for(i = 1; i < _ncel; i *= 2){ - if(i & _cid) { - int rcidx = (_cid-i)%_ncelx - _cid%_ncelx; - int rcidy = (_cid-i)/_ncelx - _cid/_ncelx; - xy_global_head = ((rcidx << 8) & 0xff00) | - (rcidy & 0xff); - break; - } - } - } -} - -static void tnet_info(void) -{ - struct completion_struct *cs; - - printk( - "errors=%d alloc_errors=%d -bytes_received=%d bytes_sent=%d -packets_received=%d packets_sent=%d -small_received=%d small_sent=%d -", - tnet_stats.errors, tnet_stats.alloc_errors, - tnet_stats.bytes_received, - tnet_stats.bytes_sent, tnet_stats.packets_received, - tnet_stats.packets_sent, tnet_stats.small_packets_received, - tnet_stats.small_packets_sent); - - printk("recv_flag=%d recv_count=%d read_ptr=%d\n", - system_recv_flag,system_recv_count,system_read_ptr); - printk("completion_list_rp=%d completion_list_wp=%d\n", - completion_list_rp,completion_list_wp); -} diff -ur --new-file old/linux/arch/sparc/ap1000/util.c new/linux/arch/sparc/ap1000/util.c --- old/linux/arch/sparc/ap1000/util.c Wed May 12 17:41:12 1999 +++ new/linux/arch/sparc/ap1000/util.c Thu Jan 1 01:00:00 1970 @@ -1,436 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* general utility functions for the AP1000 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APLOG 0 - -struct cap_init cap_init; - -/* find what cell id we are running on */ -int mpp_cid(void) -{ - return(BIF_IN(BIF_CIDR1)); -} - -/* find how many cells there are */ -int mpp_num_cells(void) -{ - return(cap_init.numcells); -} - -/* this can be used to ensure some data is readable before DMAing - it. */ -int ap_verify_data(char *d,int len) -{ - int res = 0; - while (len--) res += *d++; - return res; -} - -/* How many BogoMIPS in the entire machine -Don't worry about float because when it gets this big, it's irrelevant */ -int mpp_agg_bogomips(void) -{ - return mpp_num_cells()*loops_per_sec/500000; /* cheat in working it out */ -} - -/* Puts multiprocessor configuration info into a buffer */ -int get_mppinfo(char *buffer) -{ - return sprintf(buffer, - "Machine Type:\t\t: %s\nNumber of Cells\t\t: %d\nAggregate BogoMIPS\t: %d\n", - "Fujitsu AP1000+", - mpp_num_cells(), - mpp_agg_bogomips()); -} - -#if APLOG -static int do_logging = 0; - - -void ap_log(char *buf,int len) -{ -#define LOG_MAGIC 0x8736526 - static char *logbase; - static char *logptr; - static int logsize = 1024; - int l,i; - - if (buf == NULL && len == -1) { - logbase = kmalloc(logsize + 8,GFP_ATOMIC); - - if (!logbase) { - printk("log init failed\n"); - return; - } - for (i=0;i len) l = len; - memcpy(logptr,buf,l); - len -= l; - logptr += l; - if (logptr == logbase + logsize) - logptr = logbase; - } - *(int *)(logbase - 4) = (logptr - logbase); -} -#endif - -int ap_current_uid = -1; - -/* set output only to a particular uid */ -void ap_set_user(int uid) -{ - ap_current_uid = uid; -} - -/* write some data to a filedescriptor on the front end */ -int ap_write(int fd,char *buf,int nbytes) -{ - struct cap_request req; - - if (nbytes == 0) return 0; - -#if APLOG - ap_log(buf,nbytes); - - if (buf[0] == '|') return nbytes; -#endif - - req.cid = mpp_cid(); - req.type = REQ_WRITE; - req.size = nbytes + sizeof(req); - req.data[0] = fd; - if (ap_current_uid == -1 && current && current->pid) { - req.data[1] = current->uid; - } else { - req.data[1] = ap_current_uid; - } - req.header = MAKE_HEADER(HOST_CID); - - bif_queue(&req,buf,nbytes); - - return(nbytes); -} - -/* write one character to stdout on the front end */ -int ap_putchar(char c) -{ - struct cap_request req; - -#if APLOG - ap_log(&c,1); -#endif - - req.cid = mpp_cid(); - req.type = REQ_PUTCHAR; - req.size = sizeof(req); - req.data[0] = c; - req.header = MAKE_HEADER(HOST_CID); - - bif_queue(&req,0,0); - - return(0); -} - -/* start the debugger (kgdb) on this cell */ -void ap_start_debugger(void) -{ - static int done = 0; - extern void set_debug_traps(void); - extern void breakpoint(void); - if (!done) - set_debug_traps(); - done = 1; - breakpoint(); -} - -void ap_panic(char *msg,int a1,int a2,int a3,int a4,int a5) -{ - ap_led(0xAA); - printk(msg,a1,a2,a3,a4,a5); - ap_start_debugger(); -} - -void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5) -{ - printk(msg,a1,a2,a3,a4,a5); - /* bif_queue_flush(); */ -} - -/* get the command line arguments from the front end */ -void ap_getbootargs(char *buf) -{ - struct cap_request req; - int size; - - req.cid = mpp_cid(); - req.type = REQ_GETBOOTARGS; - req.size = sizeof(req); - req.header = MAKE_HEADER(HOST_CID); - - write_bif_polled((char *)&req,sizeof(req),NULL,0); - - ap_wait_request(&req,REQ_GETBOOTARGS); - - size = req.size - sizeof(req); - if (size == 0) - buf[0] = '\0'; - else { - read_bif(buf, size); - } - - req.cid = mpp_cid(); - req.type = REQ_INIT; - req.size = sizeof(req); - req.header = MAKE_HEADER(HOST_CID); - - write_bif_polled((char *)&req,sizeof(req),NULL,0); - - ap_wait_request(&req,REQ_INIT); - - if (req.size != sizeof(req)) - read_bif((char *)&cap_init,req.size - sizeof(req)); - if ((req.size - sizeof(req)) != sizeof(cap_init)) - printk("WARNING: Init structure is wrong size, recompile util.c\n"); - - if (cap_init.gdbcell == mpp_cid()) - ap_start_debugger(); - - printk("Got command line arguments from server\n"); -} - -/* a useful utility for debugging pagetable setups */ -void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm) -{ - unsigned *pgtable; - int entry[3]; - int level = 0; - - if (!ctp) ctp = (unsigned *)mmu_p2v(srmmu_get_ctable_ptr()); - - printk("ctp=0x%x ",(int)ctp); - - pgtable = ctp + context; - - /* get the virtual page */ - Vm = Vm>>12; - - printk("Vm page 0x%x is ",Vm); - - entry[0] = Vm>>12; - entry[1] = (Vm>>6) & 0x3f; - entry[2] = Vm & 0x3f; - - while (1) { - -#if 1 - printk("(%08x) ",pgtable[0]); -#endif - - if ((pgtable[0] & 3) == 2) { - printk("mapped at level %d to 0x%x\n",level,pgtable[0]>>8); - return; - } - - if ((pgtable[0] & 3) == 0) { - printk("unmapped at level %d\n",level); - return; - } - - if ((pgtable[0] & 3) == 3) { - printk("invalid at level %d\n",level); - return; - } - - if ((pgtable[0] & 3) == 1) { - pgtable = (unsigned *)(((pgtable[0]>>2)<<6)|0xf0000000); - pgtable += entry[level]; - level++; - } - } -} - - - -static unsigned char current_led = 0; - -void ap_led(unsigned char d) -{ - unsigned paddr = 0x1000; - unsigned word = 0xff & ~d; - current_led = d; - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (word), "r" (paddr), "i" (0x2c) : - "memory"); -} - -void ap_xor_led(unsigned char d) -{ - ap_led(current_led ^ d); -} - -void ap_set_led(unsigned char d) -{ - ap_led(current_led | d); -} - -void ap_unset_led(unsigned char d) -{ - ap_led(current_led & ~d); -} - - -void kbd_put_char(char c) -{ - ap_putchar(c); -} - - -void ap_enter_irq(int irq) -{ - unsigned char v = current_led; - switch (irq) { - case 2: v |= (1<<1); break; - case 4: v |= (1<<2); break; - case 8: v |= (1<<3); break; - case 9: v |= (1<<4); break; - case 10: v |= (1<<5); break; - case 11: v |= (1<<6); break; - default: v |= (1<<7); break; - } - ap_led(v); -} - -void ap_exit_irq(int irq) -{ - unsigned char v = current_led; - switch (irq) { - case 2: v &= ~(1<<1); break; - case 4: v &= ~(1<<2); break; - case 8: v &= ~(1<<3); break; - case 9: v &= ~(1<<4); break; - case 10: v &= ~(1<<5); break; - case 11: v &= ~(1<<6); break; - default: v &= ~(1<<7); break; - } - ap_led(v); -} - - -static DECLARE_WAIT_QUEUE_HEAD(timer_wait); - -static void wait_callback(unsigned long _ignored) -{ - wake_up(&timer_wait); -} - -/* wait till x == *p */ -int wait_on_int(volatile int *p,int x,int interval) -{ - struct timer_list *timer = kmalloc(sizeof(*timer),GFP_KERNEL); - if (!timer) panic("out of memory in wait_on_int()\n"); - timer->next = NULL; - timer->prev = NULL; - timer->data = 0; - timer->function = wait_callback; - while (*p != x) { - timer->expires = jiffies + interval; - add_timer(timer); - interruptible_sleep_on(&timer_wait); - del_timer(timer); - if (signal_pending(current)) - return -EINTR; - } - kfree_s(timer,sizeof(*timer)); - return 0; -} - - -/* an ugly hack to get nfs booting from a central cell to work */ -void ap_nfs_hook(unsigned long server) -{ - unsigned cid = server - cap_init.baseIP; - if (cid < cap_init.bootcid + cap_init.numcells && - cid != mpp_cid()) { - unsigned end = jiffies + 20*HZ; - /* we are booting from another cell */ - printk("waiting for the master cell\n"); - while (time_before(jiffies, end)) ; - printk("continuing\n"); - } -} - -/* convert a IP address to a cell id */ -int ap_ip_to_cid(u_long ip) -{ - unsigned cid; - - if ((ip & cap_init.netmask) != (cap_init.baseIP & cap_init.netmask)) - return -1; - - if ((ip & ~cap_init.netmask) == AP_ALIAS_IP) - cid = cap_init.bootcid; - else - cid = ip - cap_init.baseIP; - if (cid >= cap_init.bootcid + cap_init.numcells) - return -1; - return cid; -} - - -void ap_reboot(char *bootstr) -{ - printk("cell(%d) - don't know how to reboot\n",mpp_cid()); - sti(); - while (1) ; -} - - -void dumb_memset(char *buf,char val,int len) -{ - while (len--) *buf++ = val; -} - -void ap_init_time(struct timeval *xtime) -{ - xtime->tv_sec = cap_init.init_time; - xtime->tv_usec = 0; -} diff -ur --new-file old/linux/arch/sparc/config.in new/linux/arch/sparc/config.in --- old/linux/arch/sparc/config.in Mon Jan 24 04:48:47 2000 +++ new/linux/arch/sparc/config.in Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.81 2000/01/22 05:14:44 zaitcev Exp $ +# $Id: config.in,v 1.84 2000/01/31 21:10:04 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -19,43 +19,33 @@ bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP -bool 'Support for AP1000 multicomputer' CONFIG_AP1000 -if [ "$CONFIG_AP1000" = "y" ]; then - define_bool CONFIG_NO_KEYBOARD y - define_bool CONFIG_FDDI y - define_bool CONFIG_APFDDI y - define_bool CONFIG_APBLOCK y - define_bool CONFIG_APBIF y - tristate ' OPIU DDV Driver' CONFIG_DDV -else - bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 - if [ "$CONFIG_SUN4" != "y" ]; then - bool ' Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI - source drivers/pci/Config.in - fi - - mainmenu_option next_comment - comment 'Console drivers' - bool 'PROM console' CONFIG_PROM_CONSOLE - source drivers/video/Config.in - endmenu +bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 +if [ "$CONFIG_SUN4" != "y" ]; then + bool ' Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + source drivers/pci/Config.in +fi - # Global things across all Sun machines. - define_bool CONFIG_SBUS y - define_bool CONFIG_SBUSCHAR y - define_bool CONFIG_BUSMOUSE y - define_bool CONFIG_SUN_MOUSE y - define_bool CONFIG_SERIAL y - define_bool CONFIG_SUN_SERIAL y - define_bool CONFIG_SERIAL_CONSOLE y - define_bool CONFIG_SUN_KEYBOARD y - define_bool CONFIG_SUN_CONSOLE y - define_bool CONFIG_SUN_AUXIO y - define_bool CONFIG_SUN_IO y - if [ "$CONFIG_SUN4" != "y" ]; then - source drivers/sbus/char/Config.in - source drivers/sbus/audio/Config.in - fi +mainmenu_option next_comment +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +source drivers/video/Config.in +endmenu + +# Global things across all Sun machines. +define_bool CONFIG_SBUS y +define_bool CONFIG_SBUSCHAR y +define_bool CONFIG_BUSMOUSE y +define_bool CONFIG_SUN_MOUSE y +define_bool CONFIG_SERIAL y +define_bool CONFIG_SUN_SERIAL y +define_bool CONFIG_SERIAL_CONSOLE y +define_bool CONFIG_SUN_KEYBOARD y +define_bool CONFIG_SUN_CONSOLE y +define_bool CONFIG_SUN_AUXIO y +define_bool CONFIG_SUN_IO y +if [ "$CONFIG_SUN4" != "y" ]; then + source drivers/sbus/char/Config.in + source drivers/sbus/audio/Config.in fi tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS @@ -161,7 +151,10 @@ tristate ' Dummy net driver support' CONFIG_DUMMY tristate ' PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' + dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP + dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP + dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP + dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m fi tristate ' SLIP (serial line) support' CONFIG_SLIP if [ "$CONFIG_SLIP" != "n" ]; then diff -ur --new-file old/linux/arch/sparc/defconfig new/linux/arch/sparc/defconfig --- old/linux/arch/sparc/defconfig Sun Jan 16 07:08:28 2000 +++ new/linux/arch/sparc/defconfig Tue Feb 1 08:37:19 2000 @@ -14,7 +14,6 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set -# CONFIG_AP1000 is not set # CONFIG_SUN4 is not set # CONFIG_PCI is not set @@ -22,7 +21,6 @@ # Console drivers # CONFIG_PROM_CONSOLE=y -CONFIG_FB=y # # Frame-buffer support @@ -217,10 +215,10 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y @@ -242,10 +240,12 @@ # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m # CONFIG_ADFS_FS is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_BFS_FS_WRITE is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set @@ -256,23 +256,27 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m # CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m -CONFIG_UFS_FS_WRITE=y +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set CONFIG_NFSD=m # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y @@ -295,7 +299,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set CONFIG_SUN_PARTITION=y CONFIG_NLS=y diff -ur --new-file old/linux/arch/sparc/kernel/head.S new/linux/arch/sparc/kernel/head.S --- old/linux/arch/sparc/kernel/head.S Tue Dec 21 07:05:52 1999 +++ new/linux/arch/sparc/kernel/head.S Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.101 1999/12/02 08:34:56 jj Exp $ +/* $Id: head.S,v 1.102 2000/01/29 01:08:54 anton Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -483,10 +483,8 @@ 1: mov %o7, %g3 -#ifndef CONFIG_AP1000 tst %o0 be no_sun4u_here -#endif mov %g4, %o7 /* Previous %o7. */ mov %o0, %l0 ! stash away romvec @@ -762,11 +760,6 @@ * I figure out and store nwindows and nwindowsm1 later on. */ execute_in_high_mem: -#if CONFIG_AP1000 - /* we don't have a prom :-( */ - b sun4m_init - nop -#endif mov %l0, %o0 ! put back romvec mov %l1, %o1 ! and debug_vec diff -ur --new-file old/linux/arch/sparc/kernel/ioport.c new/linux/arch/sparc/kernel/ioport.c --- old/linux/arch/sparc/kernel/ioport.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc/kernel/ioport.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.29 2000/01/22 07:35:25 zaitcev Exp $ +/* $Id: ioport.c,v 1.30 2000/01/28 13:41:55 jj Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -ur --new-file old/linux/arch/sparc/kernel/irq.c new/linux/arch/sparc/kernel/irq.c --- old/linux/arch/sparc/kernel/irq.c Mon Jan 3 21:01:31 2000 +++ new/linux/arch/sparc/kernel/irq.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $ +/* $Id: irq.c,v 1.100 2000/01/29 01:38:04 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -738,12 +738,6 @@ case sun4d: sun4d_init_IRQ(); break; - - case ap1000: -#if CONFIG_AP1000 - ap_init_IRQ();; - break; -#endif default: prom_printf("Cannot initialize IRQ's on this Sun machine..."); diff -ur --new-file old/linux/arch/sparc/kernel/process.c new/linux/arch/sparc/kernel/process.c --- old/linux/arch/sparc/kernel/process.c Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc/kernel/process.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.144 2000/01/21 11:38:39 jj Exp $ +/* $Id: process.c,v 1.145 2000/01/29 01:08:56 anton Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -266,9 +266,6 @@ void show_regs(struct pt_regs * regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr, regs->pc, regs->npc, regs->y); printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ", diff -ur --new-file old/linux/arch/sparc/kernel/setup.c new/linux/arch/sparc/kernel/setup.c --- old/linux/arch/sparc/kernel/setup.c Tue Dec 21 07:05:52 1999 +++ new/linux/arch/sparc/kernel/setup.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.113 1999/12/16 14:37:35 anton Exp $ +/* $Id: setup.c,v 1.114 2000/01/29 01:08:57 anton Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -201,11 +201,6 @@ prom_printf("KGDB: Using serial line /dev/ttyb.\n"); break; #endif -#ifdef CONFIG_AP1000 - case 'c': - printk("KGDB: AP1000+ debugging\n"); - break; -#endif default: printk("KGDB: Unknown tty line.\n"); break; @@ -326,10 +321,6 @@ prom_halt(); } #endif -#if CONFIG_AP1000 - sparc_cpu_model=ap1000; - strcpy(&cputypval, "ap+"); -#endif printk("ARCH: "); switch(sparc_cpu_model) { case sun4: @@ -349,10 +340,6 @@ break; case sun4u: printk("SUN4U\n"); - break; - case ap1000: - register_console(&prom_console); - printk("AP1000\n"); break; default: printk("UNKNOWN!\n"); diff -ur --new-file old/linux/arch/sparc/kernel/sparc_ksyms.c new/linux/arch/sparc/kernel/sparc_ksyms.c --- old/linux/arch/sparc/kernel/sparc_ksyms.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc/kernel/sparc_ksyms.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.87 2000/01/21 17:41:14 anton Exp $ +/* $Id: sparc_ksyms.c,v 1.88 2000/01/28 13:41:55 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff -ur --new-file old/linux/arch/sparc/kernel/sys_sparc.c new/linux/arch/sparc/kernel/sys_sparc.c --- old/linux/arch/sparc/kernel/sys_sparc.c Thu Jan 27 15:32:14 2000 +++ new/linux/arch/sparc/kernel/sys_sparc.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.57 2000/01/21 11:38:42 jj Exp $ +/* $Id: sys_sparc.c,v 1.59 2000/01/29 07:40:10 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -383,12 +383,3 @@ up_read(&uts_sem); return err; } - - -#ifndef CONFIG_AP1000 -/* only AP+ systems have sys_aplib */ -asmlinkage int sys_aplib(void) -{ - return -ENOSYS; -} -#endif diff -ur --new-file old/linux/arch/sparc/kernel/sys_sunos.c new/linux/arch/sparc/kernel/sys_sunos.c --- old/linux/arch/sparc/kernel/sys_sunos.c Thu Jan 27 15:32:14 2000 +++ new/linux/arch/sparc/kernel/sys_sunos.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.111 2000/01/22 05:17:55 anton Exp $ +/* $Id: sys_sunos.c,v 1.112 2000/01/29 07:40:11 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -ur --new-file old/linux/arch/sparc/kernel/systbls.S new/linux/arch/sparc/kernel/systbls.S --- old/linux/arch/sparc/kernel/systbls.S Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc/kernel/systbls.S Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.91 2000/01/16 06:20:44 davem Exp $ +/* $Id: systbls.S,v 1.93 2000/01/29 16:41:18 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -47,7 +47,7 @@ /*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall /*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64 /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit -/*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write +/*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall /*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall @@ -70,7 +70,7 @@ /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -/*255*/ .long sys_aplib, sys_nis_syscall +/*255*/ .long sys_nis_syscall, sys_nis_syscall #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ @@ -164,6 +164,6 @@ .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_nosys, sunos_nosys /*250*/ .long sunos_nosys, sunos_nosys, sunos_nosys - .long sunos_nosys, sunos_nosys, sys_aplib + .long sunos_nosys, sunos_nosys, sunos_nosys #endif diff -ur --new-file old/linux/arch/sparc/kernel/time.c new/linux/arch/sparc/kernel/time.c --- old/linux/arch/sparc/kernel/time.c Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc/kernel/time.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.50 2000/01/21 04:35:53 anton Exp $ +/* $Id: time.c,v 1.51 2000/01/29 01:08:59 anton Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -353,12 +353,6 @@ BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); btfixup(); -#if CONFIG_AP1000 - init_timers(timer_interrupt); - ap_init_time(&xtime); - return; -#endif - if (ARCH_SUN4) sun4_clock_probe(); else @@ -451,14 +445,6 @@ */ void do_gettimeofday(struct timeval *tv) { -#if CONFIG_AP1000 - unsigned long flags; - - save_and_cli(flags); - ap_gettimeofday(&xtime); - *tv = xtime; - restore_flags(flags); -#else /* !(CONFIG_AP1000) */ /* Load doubles must be used on xtime so that what we get * is guarenteed to be atomic, this is why we can run this * with interrupts on full blast. Don't touch this... -DaveM @@ -493,7 +479,6 @@ sub %o5, %o2, %o5 st %o4, [%o0 + 0x0] 1: st %o5, [%o0 + 0x4]"); -#endif } void do_settimeofday(struct timeval *tv) @@ -505,13 +490,11 @@ static void sbus_do_settimeofday(struct timeval *tv) { -#if !CONFIG_AP1000 tv->tv_usec -= do_gettimeoffset(); if(tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } -#endif xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; diff -ur --new-file old/linux/arch/sparc/mm/Makefile new/linux/arch/sparc/mm/Makefile --- old/linux/arch/sparc/mm/Makefile Tue Dec 21 07:05:52 1999 +++ new/linux/arch/sparc/mm/Makefile Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.35 1999/10/09 05:32:01 zaitcev Exp $ +# $Id: Makefile,v 1.36 2000/01/29 01:09:05 anton Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -9,9 +9,6 @@ O_TARGET := mm.o O_OBJS := fault.o init.o loadmmu.o generic.o extable.o btfixup.o -ifeq ($(CONFIG_AP1000),y) -O_OBJS += asyncd.o -endif ifeq ($(CONFIG_SUN4),y) O_OBJS += nosrmmu.o else diff -ur --new-file old/linux/arch/sparc/mm/asyncd.c new/linux/arch/sparc/mm/asyncd.c --- old/linux/arch/sparc/mm/asyncd.c Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc/mm/asyncd.c Thu Jan 1 01:00:00 1970 @@ -1,290 +0,0 @@ -/* $Id: asyncd.c,v 1.20 2000/01/21 11:38:47 jj Exp $ - * The asyncd kernel daemon. This handles paging on behalf of - * processes that receive page faults due to remote (async) memory - * accesses. - * - * Idea and skeleton code courtesy of David Miller (bless his cotton socks) - * - * Implemented by tridge - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include /* for cli()/sti() */ -#include /* for memcpy_to/fromfs */ -#include -#include -#include - -#define DEBUG 0 - -#define WRITE_LIMIT 100 -#define LOOP_LIMIT 200 - -static struct { - int faults, read, write, success, failure, errors; -} stats; - -/* - * The wait queue for waking up the async daemon: - */ -static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait); - -struct async_job { - volatile struct async_job *next; - int taskid; - struct mm_struct *mm; - unsigned long address; - int write; - void (*callback)(int,unsigned long,int,int); -}; - -static volatile struct async_job *async_queue = NULL; -static volatile struct async_job *async_queue_end = NULL; - -static void add_to_async_queue(int taskid, - struct mm_struct *mm, - unsigned long address, - int write, - void (*callback)(int,unsigned long,int,int)) -{ - struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC); - - if (!a) { - printk("ERROR: out of memory in asyncd\n"); - a->callback(taskid,address,write,1); - return; - } - - if (write) - stats.write++; - else - stats.read++; - - a->next = NULL; - a->taskid = taskid; - a->mm = mm; - a->address = address; - a->write = write; - a->callback = callback; - - if (!async_queue) { - async_queue = a; - } else { - async_queue_end->next = a; - } - async_queue_end = a; -} - - -void async_fault(unsigned long address, int write, int taskid, - void (*callback)(int,unsigned long,int,int)) -{ - struct task_struct *tsk = task[taskid]; - struct mm_struct *mm = tsk->mm; - - stats.faults++; - -#if 0 - printk("paging in %x for task=%d\n",address,taskid); -#endif - - add_to_async_queue(taskid, mm, address, write, callback); - wake_up(&asyncd_wait); - mark_bh(TQUEUE_BH); -} - -static int fault_in_page(int taskid, - struct vm_area_struct *vma, - unsigned address,int write) -{ - static unsigned last_address; - static int last_task, loop_counter; - struct task_struct *tsk = task[taskid]; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - siginfo_t info; - - if (!tsk || !tsk->mm) - return 1; - - if (!vma || (write && !(vma->vm_flags & VM_WRITE))) - goto bad_area; - if (vma->vm_start > address) - goto bad_area; - - if (address == last_address && taskid == last_task) { - loop_counter++; - } else { - loop_counter = 0; - last_address = address; - last_task = taskid; - } - - if (loop_counter == WRITE_LIMIT && !write) { - printk("MSC bug? setting write request\n"); - stats.errors++; - write = 1; - } - - if (loop_counter == LOOP_LIMIT) { - printk("MSC bug? failing request\n"); - stats.errors++; - return 1; - } - - pgd = pgd_offset(vma->vm_mm, address); - pmd = pmd_alloc(pgd,address); - if(!pmd) - goto no_memory; - pte = pte_alloc(pmd, address); - if(!pte) - goto no_memory; - if(!pte_present(*pte)) { - handle_mm_fault(tsk, vma, address, write); - goto finish_up; - } - set_pte(pte, pte_mkyoung(*pte)); - flush_tlb_page(vma, address); - if(!write) - goto finish_up; - if(pte_write(*pte)) { - set_pte(pte, pte_mkdirty(*pte)); - flush_tlb_page(vma, address); - goto finish_up; - } - handle_mm_fault(tsk, vma, address, write); - - /* Fall through for do_wp_page */ -finish_up: - stats.success++; - return 0; - -no_memory: - stats.failure++; - oom(tsk); - return 1; - -bad_area: - stats.failure++; - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void *)address; - info.si_trapno = 0; - send_sig_info(SIGSEGV, &info, tsk); - return 1; -} - - -/* Note the semaphore operations must be done here, and _not_ - * in async_fault(). - */ -static void run_async_queue(void) -{ - int ret; - unsigned flags; - - while (async_queue) { - volatile struct async_job *a; - struct mm_struct *mm; - struct vm_area_struct *vma; - - save_flags(flags); cli(); - a = async_queue; - async_queue = async_queue->next; - restore_flags(flags); - - mm = a->mm; - - down(&mm->mmap_sem); - vma = find_vma(mm, a->address); - ret = fault_in_page(a->taskid,vma,a->address,a->write); -#if DEBUG - printk("fault_in_page(task=%d addr=%x write=%d) = %d\n", - a->taskid,a->address,a->write,ret); -#endif - a->callback(a->taskid,a->address,a->write,ret); - up(&mm->mmap_sem); - kfree_s((void *)a,sizeof(*a)); - } -} - - -#if CONFIG_AP1000 -static void asyncd_info(void) -{ - printk("CID(%d) faults: total=%d read=%d write=%d success=%d fail=%d err=%d\n", - mpp_cid(),stats.faults, stats.read, stats.write, stats.success, - stats.failure, stats.errors); -} -#endif - - -/* - * The background async daemon. - * Started as a kernel thread from the init process. - */ -int asyncd(void *unused) -{ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "asyncd"); - sigfillset(¤t->blocked); /* block all signals */ - recalc_sigpending(current); - - /* Give asyncd a realtime priority. */ - current->policy = SCHED_FIFO; - current->priority = 32; /* Fixme --- we need to standardise our - namings for POSIX.4 realtime scheduling - priorities. */ - - printk("Started asyncd\n"); - -#if CONFIG_AP1000 - bif_add_debug_key('a',asyncd_info,"stats on asyncd"); -#endif - - while (1) { - unsigned flags; - - save_flags(flags); cli(); - - while (!async_queue) { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&asyncd_wait); - __sti(); cli(); - } - - restore_flags(flags); - - run_async_queue(); - } -} - -#if CONFIG_AP1000 - -static int __init init_ap1000(void) -{ - kernel_thread(asyncd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - return 0; -} - -module_init(init_ap1000) - -#endif diff -ur --new-file old/linux/arch/sparc/mm/init.c new/linux/arch/sparc/mm/init.c --- old/linux/arch/sparc/mm/init.c Tue Jan 25 19:26:04 2000 +++ new/linux/arch/sparc/mm/init.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.78 2000/01/24 03:22:38 anton Exp $ +/* $Id: init.c,v 1.79 2000/01/29 01:09:06 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -238,15 +238,6 @@ sparc_unmapped_base = 0x50000000; BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000); break; - - case ap1000: -#if CONFIG_AP1000 - apmmu_paging_init(); - sparc_unmapped_base = 0x50000000; - BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000); - break; -#endif - default: prom_printf("paging_init: Cannot init paging on this Sparc\n"); prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model); diff -ur --new-file old/linux/arch/sparc/mm/loadmmu.c new/linux/arch/sparc/mm/loadmmu.c --- old/linux/arch/sparc/mm/loadmmu.c Thu Jan 13 21:03:00 2000 +++ new/linux/arch/sparc/mm/loadmmu.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.53 2000/01/09 10:46:50 anton Exp $ +/* $Id: loadmmu.c,v 1.54 2000/01/29 01:09:07 anton Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -39,11 +39,6 @@ case sun4d: ld_mmu_srmmu(); break; - case ap1000: -#if CONFIG_AP1000 - ld_mmu_apmmu(); - break; -#endif default: prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model); prom_halt(); diff -ur --new-file old/linux/arch/sparc/prom/bootstr.c new/linux/arch/sparc/prom/bootstr.c --- old/linux/arch/sparc/prom/bootstr.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/prom/bootstr.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: bootstr.c,v 1.18 1999/08/31 06:54:45 davem Exp $ +/* $Id: bootstr.c,v 1.19 2000/01/29 01:09:11 anton Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -55,11 +55,6 @@ */ strncpy(barg_buf, *romvec->pv_v2bootargs.bootargs, BARG_LEN-1); break; - case PROM_AP1000: -#if CONFIG_AP1000 - ap_getbootargs(barg_buf, BARG_LEN); - break; -#endif default: break; } diff -ur --new-file old/linux/arch/sparc/prom/console.c new/linux/arch/sparc/prom/console.c --- old/linux/arch/sparc/prom/console.c Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc/prom/console.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.20 1998/09/21 05:05:50 jj Exp $ +/* $Id: console.c,v 1.21 2000/01/29 01:09:12 anton Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -45,7 +45,6 @@ i = -1; } break; - case PROM_AP1000: default: i = -1; break; @@ -79,15 +78,6 @@ else i = -1; break; - case PROM_AP1000: -#if CONFIG_AP1000 - { - extern void ap_putchar(char ); - ap_putchar(c); - i = 0; - } -#endif - break; default: i = -1; break; @@ -160,8 +150,6 @@ return PROMDEV_ITTYB; } return PROMDEV_I_UNK; - case PROM_AP1000: - return PROMDEV_I_UNK; } } @@ -219,7 +207,6 @@ }; } break; - case PROM_AP1000: default: } return PROMDEV_O_UNK; diff -ur --new-file old/linux/arch/sparc/prom/devops.c new/linux/arch/sparc/prom/devops.c --- old/linux/arch/sparc/prom/devops.c Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc/prom/devops.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: devops.c,v 1.11 1998/03/09 14:04:24 jj Exp $ +/* $Id: devops.c,v 1.12 2000/01/29 01:09:12 anton Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -31,7 +31,6 @@ case PROM_V3: handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr); break; - case PROM_AP1000: default: handle = -1; break; @@ -56,7 +55,6 @@ case PROM_V3: (*(romvec->pv_v2devops.v2_dev_close))(dhandle); break; - case PROM_AP1000: default: break; }; @@ -81,7 +79,6 @@ case PROM_V3: (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo); break; - case PROM_AP1000: default: break; }; diff -ur --new-file old/linux/arch/sparc/prom/init.c new/linux/arch/sparc/prom/init.c --- old/linux/arch/sparc/prom/init.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/prom/init.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.13 1999/08/31 06:54:45 davem Exp $ +/* $Id: init.c,v 1.14 2000/01/29 01:09:12 anton Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -41,10 +41,6 @@ extern struct linux_romvec *sun4_prom_init(void); rp = sun4_prom_init(); #endif -#if CONFIG_AP1000 - extern struct linux_romvec *ap_prom_init(void); - rp = ap_prom_init(); -#endif romvec = rp; switch(romvec->pv_romvers) { @@ -60,10 +56,6 @@ case 40: prom_vers = PROM_SUN4; break; - case 42: /* why not :-) */ - prom_vers = PROM_AP1000; - break; - default: prom_printf("PROMLIB: Bad PROM version %d\n", romvec->pv_romvers); diff -ur --new-file old/linux/arch/sparc/prom/memory.c new/linux/arch/sparc/prom/memory.c --- old/linux/arch/sparc/prom/memory.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/prom/memory.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.14 1999/08/31 06:54:46 davem Exp $ +/* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -194,19 +194,6 @@ #endif break; - case PROM_AP1000: -#if CONFIG_AP1000 - /* really simple memory map */ - prom_phys_total[0].start_adr = 0x00000000; - prom_phys_total[0].num_bytes = ap_memory_size(); - prom_phys_total[0].theres_more = 0x0; - prom_prom_taken[0].start_adr = 0x00000000; - prom_prom_taken[0].num_bytes = 0x00000000; - prom_prom_taken[0].theres_more = 0x0; - prom_phys_avail[0].start_adr = 0x00000000; - prom_phys_avail[0].num_bytes = prom_phys_total[0].num_bytes; - prom_phys_avail[0].theres_more = 0x0; -#endif default: break; }; diff -ur --new-file old/linux/arch/sparc/prom/mp.c new/linux/arch/sparc/prom/mp.c --- old/linux/arch/sparc/prom/mp.c Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc/prom/mp.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.10 1998/03/09 14:04:26 jj Exp $ +/* $Id: mp.c,v 1.11 2000/01/29 01:09:12 anton Exp $ * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * @@ -29,7 +29,6 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: - case PROM_AP1000: default: ret = -1; break; @@ -56,7 +55,6 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: - case PROM_AP1000: default: ret = -1; break; @@ -83,7 +81,6 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: - case PROM_AP1000: default: ret = -1; break; @@ -110,7 +107,6 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: - case PROM_AP1000: default: ret = -1; break; diff -ur --new-file old/linux/arch/sparc/prom/printf.c new/linux/arch/sparc/prom/printf.c --- old/linux/arch/sparc/prom/printf.c Sat Nov 9 09:12:28 1996 +++ new/linux/arch/sparc/prom/printf.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $ +/* $Id: printf.c,v 1.6 2000/01/29 01:09:12 anton Exp $ * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -28,16 +28,12 @@ bptr = ppbuf; -#if CONFIG_AP1000 - ap_write(1,bptr,strlen(bptr)); -#else while((ch = *(bptr++)) != 0) { if(ch == '\n') prom_putchar('\r'); prom_putchar(ch); } -#endif va_end(args); return; } diff -ur --new-file old/linux/arch/sparc64/config.in new/linux/arch/sparc64/config.in --- old/linux/arch/sparc64/config.in Wed Feb 2 22:58:21 2000 +++ new/linux/arch/sparc64/config.in Wed Feb 2 23:00:01 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.87 2000/01/16 06:18:53 davem Exp $ +# $Id: config.in,v 1.89 2000/01/31 21:10:10 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # diff -ur --new-file old/linux/arch/sparc64/defconfig new/linux/arch/sparc64/defconfig --- old/linux/arch/sparc64/defconfig Fri Jan 14 09:50:53 2000 +++ new/linux/arch/sparc64/defconfig Tue Feb 1 08:37:19 2000 @@ -292,6 +292,7 @@ # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m # CONFIG_ADFS_FS is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set @@ -307,10 +308,12 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m @@ -318,15 +321,16 @@ CONFIG_UDF_FS=m # CONFIG_UDF_RW is not set CONFIG_UFS_FS=m -CONFIG_UFS_FS_WRITE=y +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set CONFIG_NFSD=m -CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m @@ -347,7 +351,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set CONFIG_SUN_PARTITION=y CONFIG_NLS=y diff -ur --new-file old/linux/arch/sparc64/kernel/binfmt_elf32.c new/linux/arch/sparc64/kernel/binfmt_elf32.c --- old/linux/arch/sparc64/kernel/binfmt_elf32.c Sun Jan 16 07:08:28 2000 +++ new/linux/arch/sparc64/kernel/binfmt_elf32.c Tue Feb 1 08:37:19 2000 @@ -1,7 +1,7 @@ /* * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. * - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) */ diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_backend.S new/linux/arch/sparc64/kernel/dtlb_backend.S --- old/linux/arch/sparc64/kernel/dtlb_backend.S Tue Dec 21 07:05:52 1999 +++ new/linux/arch/sparc64/kernel/dtlb_backend.S Tue Feb 1 08:37:19 2000 @@ -1,8 +1,8 @@ -/* $Id: dtlb_backend.S,v 1.8 1999/12/05 10:41:35 davem Exp $ +/* $Id: dtlb_backend.S,v 1.9 2000/01/31 04:59:12 davem Exp $ * dtlb_backend.S: Back end to DTLB miss replacement strategy. * This is included directly into the trap table. * - * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_base.S new/linux/arch/sparc64/kernel/dtlb_base.S --- old/linux/arch/sparc64/kernel/dtlb_base.S Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/kernel/dtlb_base.S Tue Feb 1 08:37:19 2000 @@ -1,8 +1,8 @@ -/* $Id: dtlb_base.S,v 1.4 1998/06/15 16:59:30 jj Exp $ +/* $Id: dtlb_base.S,v 1.5 2000/01/31 04:59:12 davem Exp $ * dtlb_base.S: Front end to DTLB miss replacement strategy. * This is included directly into the trap table. * - * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_prot.S new/linux/arch/sparc64/kernel/dtlb_prot.S --- old/linux/arch/sparc64/kernel/dtlb_prot.S Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/kernel/dtlb_prot.S Tue Feb 1 08:37:19 2000 @@ -1,8 +1,8 @@ -/* $Id: dtlb_prot.S,v 1.18 1999/03/02 15:42:14 jj Exp $ +/* $Id: dtlb_prot.S,v 1.19 2000/01/31 04:59:12 davem Exp $ * dtlb_prot.S: DTLB protection trap strategy. * This is included directly into the trap table. * - * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ diff -ur --new-file old/linux/arch/sparc64/kernel/ioctl32.c new/linux/arch/sparc64/kernel/ioctl32.c --- old/linux/arch/sparc64/kernel/ioctl32.c Wed Feb 2 22:58:21 2000 +++ new/linux/arch/sparc64/kernel/ioctl32.c Wed Feb 2 23:00:01 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.74 2000/01/15 04:47:48 davem Exp $ +/* $Id: ioctl32.c,v 1.76 2000/01/31 21:10:15 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -ur --new-file old/linux/arch/sparc64/kernel/iommu_common.c new/linux/arch/sparc64/kernel/iommu_common.c --- old/linux/arch/sparc64/kernel/iommu_common.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/iommu_common.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: iommu_common.c,v 1.2 1999/12/19 09:17:53 davem Exp $ +/* $Id: iommu_common.c,v 1.3 2000/01/28 13:41:59 jj Exp $ * iommu_common.c: UltraSparc SBUS/PCI common iommu code. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) diff -ur --new-file old/linux/arch/sparc64/kernel/itlb_base.S new/linux/arch/sparc64/kernel/itlb_base.S --- old/linux/arch/sparc64/kernel/itlb_base.S Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/kernel/itlb_base.S Tue Feb 1 08:37:19 2000 @@ -1,8 +1,8 @@ -/* $Id: itlb_base.S,v 1.7 1999/03/02 15:42:12 jj Exp $ +/* $Id: itlb_base.S,v 1.8 2000/01/31 04:59:12 davem Exp $ * itlb_base.S: Front end to ITLB miss replacement strategy. * This is included directly into the trap table. * - * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com) * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ diff -ur --new-file old/linux/arch/sparc64/kernel/pci_iommu.c new/linux/arch/sparc64/kernel/pci_iommu.c --- old/linux/arch/sparc64/kernel/pci_iommu.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/pci_iommu.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_iommu.c,v 1.7 1999/12/20 14:08:15 jj Exp $ +/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) diff -ur --new-file old/linux/arch/sparc64/kernel/pci_psycho.c new/linux/arch/sparc64/kernel/pci_psycho.c --- old/linux/arch/sparc64/kernel/pci_psycho.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/pci_psycho.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.9 2000/01/11 23:38:32 davem Exp $ +/* $Id: pci_psycho.c,v 1.10 2000/01/28 13:42:00 jj Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) diff -ur --new-file old/linux/arch/sparc64/kernel/pci_sabre.c new/linux/arch/sparc64/kernel/pci_sabre.c --- old/linux/arch/sparc64/kernel/pci_sabre.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/pci_sabre.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.10 2000/01/11 23:38:35 davem Exp $ +/* $Id: pci_sabre.c,v 1.11 2000/01/28 13:42:01 jj Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) diff -ur --new-file old/linux/arch/sparc64/kernel/sbus.c new/linux/arch/sparc64/kernel/sbus.c --- old/linux/arch/sparc64/kernel/sbus.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/sbus.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.6 1999/12/20 14:08:17 jj Exp $ +/* $Id: sbus.c,v 1.7 2000/01/28 13:41:58 jj Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) diff -ur --new-file old/linux/arch/sparc64/kernel/sparc64_ksyms.c new/linux/arch/sparc64/kernel/sparc64_ksyms.c --- old/linux/arch/sparc64/kernel/sparc64_ksyms.c Thu Jan 27 17:58:15 2000 +++ new/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.70 2000/01/07 18:15:18 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.72 2000/01/28 13:41:59 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -124,11 +124,6 @@ EXPORT_SYMBOL_PRIVATE(write_unlock); #endif -/* rw semaphores */ -EXPORT_SYMBOL_NOVERS(__down_read_failed); -EXPORT_SYMBOL_NOVERS(__down_write_failed); -EXPORT_SYMBOL_NOVERS(__rwsem_wake); - /* Kernel wide locking */ EXPORT_SYMBOL(kernel_flag); @@ -168,6 +163,11 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); #endif + +/* rw semaphores */ +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Atomic counter implementation. */ EXPORT_SYMBOL_PRIVATE(atomic_add); diff -ur --new-file old/linux/arch/sparc64/kernel/starfire.c new/linux/arch/sparc64/kernel/starfire.c --- old/linux/arch/sparc64/kernel/starfire.c Tue Dec 21 07:05:52 1999 +++ new/linux/arch/sparc64/kernel/starfire.c Tue Feb 1 08:37:19 2000 @@ -1,7 +1,7 @@ -/* $Id: starfire.c,v 1.4 1999/09/21 14:35:25 davem Exp $ +/* $Id: starfire.c,v 1.5 2000/01/31 04:59:12 davem Exp $ * starfire.c: Starfire/E10000 support. * - * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) */ #include diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc.c new/linux/arch/sparc64/kernel/sys_sparc.c --- old/linux/arch/sparc64/kernel/sys_sparc.c Thu Jan 27 15:32:14 2000 +++ new/linux/arch/sparc64/kernel/sys_sparc.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.34 2000/01/21 11:39:06 jj Exp $ +/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sunos32.c new/linux/arch/sparc64/kernel/sys_sunos32.c --- old/linux/arch/sparc64/kernel/sys_sunos32.c Thu Jan 27 15:32:14 2000 +++ new/linux/arch/sparc64/kernel/sys_sunos32.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.37 2000/01/21 11:39:03 jj Exp $ +/* $Id: sys_sunos32.c,v 1.38 2000/01/29 07:40:13 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -ur --new-file old/linux/arch/sparc64/kernel/systbls.S new/linux/arch/sparc64/kernel/systbls.S --- old/linux/arch/sparc64/kernel/systbls.S Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc64/kernel/systbls.S Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.66 2000/01/16 06:20:48 davem Exp $ +/* $Id: systbls.S,v 1.67 2000/01/29 16:41:21 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -48,7 +48,7 @@ /*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64 /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit - .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write + .word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall @@ -107,7 +107,7 @@ /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit - .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write + .word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install diff -ur --new-file old/linux/arch/sparc64/lib/debuglocks.c new/linux/arch/sparc64/lib/debuglocks.c --- old/linux/arch/sparc64/lib/debuglocks.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc64/lib/debuglocks.c Tue Feb 1 08:37:19 2000 @@ -1,7 +1,7 @@ -/* $Id: debuglocks.c,v 1.3 1999/09/10 10:40:50 davem Exp $ +/* $Id: debuglocks.c,v 1.4 2000/01/31 04:59:10 davem Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * - * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) */ #include diff -ur --new-file old/linux/arch/sparc64/lib/memscan.S new/linux/arch/sparc64/lib/memscan.S --- old/linux/arch/sparc64/lib/memscan.S Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/lib/memscan.S Tue Feb 1 08:37:19 2000 @@ -1,8 +1,8 @@ -/* $Id: memscan.S,v 1.2 1998/05/21 14:42:22 jj Exp $ +/* $Id: memscan.S,v 1.3 2000/01/31 04:59:10 davem Exp $ * memscan.S: Optimized memscan for Sparc64. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) */ #define HI_MAGIC 0x8080808080808080 diff -ur --new-file old/linux/arch/sparc64/mm/Makefile new/linux/arch/sparc64/mm/Makefile --- old/linux/arch/sparc64/mm/Makefile Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/mm/Makefile Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 1998/07/26 03:02:54 davem Exp $ +# $Id: Makefile,v 1.6 2000/01/31 01:30:49 davem Exp $ # Makefile for the linux Sparc64-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -14,6 +14,6 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o O_TARGET := mm.o -O_OBJS := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o +O_OBJS := ultra.o fault.o init.o generic.o extable.o modutil.o include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/sparc64/mm/asyncd.c new/linux/arch/sparc64/mm/asyncd.c --- old/linux/arch/sparc64/mm/asyncd.c Sat Jan 22 03:22:54 2000 +++ new/linux/arch/sparc64/mm/asyncd.c Thu Jan 1 01:00:00 1970 @@ -1,283 +0,0 @@ -/* $Id: asyncd.c,v 1.12 2000/01/21 11:39:13 jj Exp $ - * The asyncd kernel daemon. This handles paging on behalf of - * processes that receive page faults due to remote (async) memory - * accesses. - * - * Idea and skeleton code courtesy of David Miller (bless his cotton socks) - * - * Implemented by tridge - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include /* for cli()/sti() */ -#include /* for memcpy_to/fromfs */ -#include -#include -#include - -#define DEBUG 0 - -#define WRITE_LIMIT 100 -#define LOOP_LIMIT 200 - -static struct { - int faults, read, write, success, failure, errors; -} stats; - -/* - * The wait queue for waking up the async daemon: - */ -static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait); - -struct async_job { - volatile struct async_job *next; - int taskid; - struct mm_struct *mm; - unsigned long address; - int write; - void (*callback)(int,unsigned long,int,int); -}; - -static volatile struct async_job *async_queue = NULL; -static volatile struct async_job *async_queue_end = NULL; - -static void add_to_async_queue(int taskid, - struct mm_struct *mm, - unsigned long address, - int write, - void (*callback)(int,unsigned long,int,int)) -{ - struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC); - - if (!a) { - printk("ERROR: out of memory in asyncd\n"); - a->callback(taskid,address,write,1); - return; - } - - if (write) - stats.write++; - else - stats.read++; - - a->next = NULL; - a->taskid = taskid; - a->mm = mm; - a->address = address; - a->write = write; - a->callback = callback; - - if (!async_queue) { - async_queue = a; - } else { - async_queue_end->next = a; - } - async_queue_end = a; -} - - -void async_fault(unsigned long address, int write, int taskid, - void (*callback)(int,unsigned long,int,int)) -{ -#warning Need some fixing here... -DaveM - struct task_struct *tsk = current /* XXX task[taskid] */; - struct mm_struct *mm = tsk->mm; - - stats.faults++; - -#if 0 - printk("paging in %x for task=%d\n",address,taskid); -#endif - - add_to_async_queue(taskid, mm, address, write, callback); - wake_up(&asyncd_wait); - mark_bh(TQUEUE_BH); -} - -static int fault_in_page(int taskid, - struct vm_area_struct *vma, - unsigned long address, int write) -{ - static unsigned last_address; - static int last_task, loop_counter; - siginfo_t info; -#warning Need some fixing here... -DaveM - struct task_struct *tsk = current /* XXX task[taskid] */; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - if (!tsk || !tsk->mm) - return 1; - - if (!vma || (write && !(vma->vm_flags & VM_WRITE))) - goto bad_area; - if (vma->vm_start > address) - goto bad_area; - - if (address == last_address && taskid == last_task) { - loop_counter++; - } else { - loop_counter = 0; - last_address = address; - last_task = taskid; - } - - if (loop_counter == WRITE_LIMIT && !write) { - printk("MSC bug? setting write request\n"); - stats.errors++; - write = 1; - } - - if (loop_counter == LOOP_LIMIT) { - printk("MSC bug? failing request\n"); - stats.errors++; - return 1; - } - - pgd = pgd_offset(vma->vm_mm, address); - pmd = pmd_alloc(pgd,address); - if(!pmd) - goto no_memory; - pte = pte_alloc(pmd, address); - if(!pte) - goto no_memory; - if(!pte_present(*pte)) { - handle_mm_fault(tsk, vma, address, write); - goto finish_up; - } - set_pte(pte, pte_mkyoung(*pte)); - flush_tlb_page(vma, address); - if(!write) - goto finish_up; - if(pte_write(*pte)) { - set_pte(pte, pte_mkdirty(*pte)); - flush_tlb_page(vma, address); - goto finish_up; - } - handle_mm_fault(tsk, vma, address, write); - - /* Fall through for do_wp_page */ -finish_up: - stats.success++; - return 0; - -no_memory: - stats.failure++; - oom(tsk); - return 1; - -bad_area: - stats.failure++; - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void *)address; - info.si_trapno = 0; - send_sig_info(SIGSEGV, &info, tsk); - return 1; -} - - -/* Note the semaphore operations must be done here, and _not_ - * in async_fault(). - */ -static void run_async_queue(void) -{ - int ret; - unsigned flags; - - while (async_queue) { - volatile struct async_job *a; - struct mm_struct *mm; - struct vm_area_struct *vma; - - save_flags(flags); cli(); - a = async_queue; - async_queue = async_queue->next; - restore_flags(flags); - - mm = a->mm; - - down(&mm->mmap_sem); - vma = find_vma(mm, a->address); - ret = fault_in_page(a->taskid,vma,a->address,a->write); -#if DEBUG - printk("fault_in_page(task=%d addr=%x write=%d) = %d\n", - a->taskid,a->address,a->write,ret); -#endif - a->callback(a->taskid,a->address,a->write,ret); - up(&mm->mmap_sem); - kfree_s((void *)a,sizeof(*a)); - } -} - - -#if CONFIG_AP1000 -static void asyncd_info(void) -{ - printk("CID(%d) faults: total=%d read=%d write=%d success=%d fail=%d err=%d\n", - mpp_cid(),stats.faults, stats.read, stats.write, stats.success, - stats.failure, stats.errors); -} -#endif - - -/* - * The background async daemon. - * Started as a kernel thread from the init process. - */ -int asyncd(void *unused) -{ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "asyncd"); - - sigfillset(¤t->blocked); /* block all signals */ - recalc_sigpending(current); - - /* Give asyncd a realtime priority. */ - current->policy = SCHED_FIFO; - current->priority = 32; /* Fixme --- we need to standardise our - namings for POSIX.4 realtime scheduling - priorities. */ - - printk("Started asyncd\n"); - -#if CONFIG_AP1000 - bif_add_debug_key('a',asyncd_info,"stats on asyncd"); -#endif - - while (1) { - unsigned flags; - - save_flags(flags); cli(); - - while (!async_queue) { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&asyncd_wait); - __sti(); cli(); /* acquire gloabl_irq_lock */ - } - - restore_flags(flags); - - run_async_queue(); - } -} - diff -ur --new-file old/linux/arch/sparc64/solaris/misc.c new/linux/arch/sparc64/solaris/misc.c --- old/linux/arch/sparc64/solaris/misc.c Thu Jan 27 15:32:14 2000 +++ new/linux/arch/sparc64/solaris/misc.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.20 2000/01/12 02:59:26 davem Exp $ +/* $Id: misc.c,v 1.21 2000/01/29 07:40:15 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -ur --new-file old/linux/drivers/Makefile new/linux/drivers/Makefile --- old/linux/drivers/Makefile Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/Makefile Tue Feb 1 08:37:19 2000 @@ -11,7 +11,7 @@ MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o ieee1394 \ macintosh video dio zorro fc4 usb \ - nubus tc ap1000 atm pcmcia i2c telephony + nubus tc atm pcmcia i2c telephony ifdef CONFIG_DIO SUB_DIRS += dio @@ -135,10 +135,6 @@ ifdef CONFIG_ATM SUB_DIRS += atm MOD_SUB_DIRS += atm -endif - -ifeq ($(CONFIG_AP1000),y) -SUB_DIRS += ap1000 endif ifeq ($(CONFIG_FC4),y) diff -ur --new-file old/linux/drivers/ap1000/Makefile new/linux/drivers/ap1000/Makefile --- old/linux/drivers/ap1000/Makefile Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/Makefile Thu Jan 1 01:00:00 1970 @@ -1,29 +0,0 @@ -# File: drivers/ap1000/Makefile -# -# Makefile for the AP1000 drivers -# - -L_TARGET := ap1000.a -L_OBJS := bif.o apfddi.o mac.o plc.o ringbuf.o - -ifeq ($(CONFIG_APBLOCK),y) -L_OBJS += ap.o -else - ifeq ($(CONFIG_APBLOCK),m) - M_OBJS += ap.o - endif -endif - -ifeq ($(CONFIG_DDV),y) -L_OBJS += ddv.o ddv_util.o -else - ifeq ($(CONFIG_DDV),m) - M_OBJS += ddv.o ddv_util.o - endif -endif - -include $(TOPDIR)/Rules.make - -clean: - rm -f core *.o *.a *.s - diff -ur --new-file old/linux/drivers/ap1000/am79c830.h new/linux/drivers/ap1000/am79c830.h --- old/linux/drivers/ap1000/am79c830.h Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/am79c830.h Thu Jan 1 01:00:00 1970 @@ -1,276 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Definitions for the AM79C830 FORMAC (Fiber Optic Ring MAC) chip. - */ - -typedef int formac_reg; - -struct formac { - formac_reg cmdreg1; /* command register 1 */ - formac_reg cmdreg2; /* command register 2 */ -#define st1u cmdreg1 /* status reg 1, upper */ -#define st1l cmdreg2 /* status reg 1, lower */ - formac_reg st2u; /* status reg 2, upper */ - formac_reg st2l; /* status reg 2, lower */ - formac_reg imsk1u; /* interrupt mask 1, upper */ - formac_reg imsk1l; /* interrupt mask 1, lower */ - formac_reg imsk2u; /* interrupt mask 2, upper */ - formac_reg imsk2l; /* interrupt mask 2, lower */ - formac_reg said; /* short address, individual */ - formac_reg laim; /* long adrs, indiv, MS word */ - formac_reg laic; /* long adrs, indiv, middle word */ - formac_reg lail; /* long adrs, indiv, LS word */ - formac_reg sagp; /* short address, group */ - formac_reg lagm; /* short adrs, group, MS word */ - formac_reg lagc; /* short adrs, group, middle word */ - formac_reg lagl; /* short adrs, group, LS word */ - formac_reg mdreg1; /* mode reg 1 */ - formac_reg stmchn; /* state machine reg */ - formac_reg mir1; /* MAC information reg, upper */ - formac_reg mir0; /* MAC information reg, lower */ - formac_reg tmax; /* TMax value (2's-comp) */ - formac_reg tvx; /* TVX value (2's-comp) */ - formac_reg trt; /* TRT timer value */ - formac_reg tht; /* THT timer value */ - formac_reg tneg; /* current TNeg (2's-comp) */ - formac_reg tmrs; /* extra bits of tneg, trt, tht; late count */ - formac_reg treq0; /* our TReq (2's-comp), lower */ - formac_reg treq1; /* our TReq (2's-comp), upper */ - formac_reg pri0; /* priority reg for async queue 0 */ - formac_reg pri1; /* priority reg for async queue 1 */ - formac_reg pri2; /* priority reg for async queue 2 */ - formac_reg tsync; /* TSync value (2's-comp) */ - formac_reg mdreg2; /* mode reg 2 */ - formac_reg frmthr; /* frame threshold reg */ - formac_reg eacb; /* end address of claim/beacon area */ - formac_reg earv; /* end address of receive area */ - formac_reg eas; /* end address of sync queue */ - formac_reg eaa0; /* end address of async queue 0 */ - formac_reg eaa1; /* end address of async queue 1 */ - formac_reg eaa2; /* end address of async queue 2 */ - formac_reg sacl; /* start address of claim frame */ - formac_reg sabc; /* start address of beacon frame */ - formac_reg wpxsf; /* write pointer, special frames */ - formac_reg rpxsf; /* read pointer, special frames */ - formac_reg dummy1; /* not used */ - formac_reg rpr; /* read pointer, receive */ - formac_reg wpr; /* write pointer, receive */ - formac_reg swpr; /* shadow write pointer, receive */ - formac_reg wpxs; /* write pointer, sync queue */ - formac_reg wpxa0; /* write pointer, async queue 0 */ - formac_reg wpxa1; /* write pointer, async queue 1 */ - formac_reg wpxa2; /* write pointer, async queue 2 */ - formac_reg swpxs; /* shadow write pointer, sync queue */ - formac_reg swpxa0; /* shadow write pointer, async queue 0 */ - formac_reg swpxa1; /* shadow write pointer, async queue 1 */ - formac_reg swpxa2; /* shadow write pointer, async queue 2 */ - formac_reg rpxs; /* read pointer, sync queue */ - formac_reg rpxa0; /* read pointer, async queue 0 */ - formac_reg rpxa1; /* read pointer, async queue 1 */ - formac_reg rpxa2; /* read pointer, async queue 2 */ - formac_reg marr; /* memory address for random reads */ - formac_reg marw; /* memory address for random writes */ - formac_reg mdru; /* memory data register, upper */ - formac_reg mdrl; /* memory data register, lower */ - formac_reg tmsync; /* TSync timer value */ - formac_reg fcntr; /* frame counter */ - formac_reg lcntr; /* lost counter */ - formac_reg ecntr; /* error counter */ -}; - -/* Values for cmdreg1 */ -#define C1_SOFTWARE_RESET 1 -#define C1_IRMEMWI 2 -#define C1_IRMEMWO 3 -#define C1_IDLE_LISTEN 4 -#define C1_CLAIM_LISTEN 5 -#define C1_BEACON_LISTEN 6 -#define C1_LOAD_TVX 7 -#define C1_SEND_NR_TOKEN 0x0c -#define C1_SEND_R_TOKEN 0x0d -#define C1_ENTER_SI_MODE 0x0e -#define C1_EXIT_SI_MODE 0x0f -#define C1_CLR_SYNCQ_LOCK 0x11 -#define C1_CLR_ASYNCQ0_LOCK 0x12 -#define C1_CLR_ASYNCQ1_LOCK 0x14 -#define C1_CLR_ASYNCQ2_LOCK 0x18 -#define C1_CLR_RECVQ_LOCK 0x20 -#define C1_CLR_ALL_LOCKS 0x3f - -/* Values for cmdreg2 */ -#define C2_XMIT_SYNCQ 1 -#define C2_XMIT_ASYNCQ0 2 -#define C2_XMIT_ASYNCQ1 4 -#define C2_XMIT_ASYNCQ2 8 -#define C2_ABORT_XMIT 0x10 -#define C2_RESET_XMITQS 0x20 -#define C2_SET_TAG 0x30 -#define C2_EN_RECV_FRAME 0x40 - -/* Bits in (st1u << 16) + st1l (and (imsk1u << 16) + imsk1l) */ -#define S1_XMIT_ABORT 0x80000000 -#define S1_XABORT_ASYNC2 0x40000000 -#define S1_XABORT_ASYNC1 0x20000000 -#define S1_XABORT_ASYNC0 0x10000000 -#define S1_XABORT_SYNC 0x08000000 -#define S1_XBUF_FULL_SYNC 0x04000000 -#define S1_XBUF_FULL_ASYNC 0x02000000 -#define S1_XDONE_SYNC 0x01000000 -#define S1_END_CHAIN_ASYNC2 0x00800000 -#define S1_END_CHAIN_ASYNC1 0x00400000 -#define S1_END_CHAIN_ASYNC0 0x00200000 -#define S1_END_CHAIN_SYNC 0x00100000 -#define S1_END_FRAME_ASYNC2 0x00080000 -#define S1_END_FRAME_ASYNC1 0x00040000 -#define S1_END_FRAME_ASYNC0 0x00020000 -#define S1_END_FRAME_SYNC 0x00010000 -#define S1_BUF_UNDERRUN_ASYNC2 0x00008000 -#define S1_BUF_UNDERRUN_ASYNC1 0x00004000 -#define S1_BUF_UNDERRUN_ASYNC0 0x00002000 -#define S1_BUF_UNDERRUN_SYNC 0x00001000 -#define S1_PAR_ERROR_ASYNC2 0x00000800 -#define S1_PAR_ERROR_ASYNC1 0x00000400 -#define S1_PAR_ERROR_ASYNC0 0x00000200 -#define S1_PAR_ERROR_SYNC 0x00000100 -#define S1_XINSTR_FULL_ASYNC2 0x00000080 -#define S1_XINSTR_FULL_ASYNC1 0x00000040 -#define S1_XINSTR_FULL_ASYNC0 0x00000020 -#define S1_XINSTR_FULL_SYNC 0x00000010 -#define S1_QUEUE_LOCK_ASYNC2 0x00000008 -#define S1_QUEUE_LOCK_ASYNC1 0x00000004 -#define S1_QUEUE_LOCK_ASYNC0 0x00000002 -#define S1_QUEUE_LOCK_SYNC 0x00000001 - -/* Bits in (st2u << 16) + st2l (and (imsk2u << 16) + imsk2l) */ -#define S2_RECV_COMPLETE 0x80000000 -#define S2_RECV_BUF_EMPTY 0x40000000 -#define S2_RECV_ABORT 0x20000000 -#define S2_RECV_BUF_FULL 0x10000000 -#define S2_RECV_FIFO_OVF 0x08000000 -#define S2_RECV_FRAME 0x04000000 -#define S2_RECV_FRCT_OVF 0x02000000 -#define S2_NP_SIMULT_LOAD 0x01000000 -#define S2_ERR_SPECIAL_FR 0x00800000 -#define S2_CLAIM_STATE 0x00400000 -#define S2_MY_CLAIM 0x00200000 -#define S2_HIGHER_CLAIM 0x00100000 -#define S2_LOWER_CLAIM 0x00080000 -#define S2_BEACON_STATE 0x00040000 -#define S2_MY_BEACON 0x00020000 -#define S2_OTHER_BEACON 0x00010000 -#define S2_RING_OP 0x00008000 -#define S2_MULTIPLE_DA 0x00004000 -#define S2_TOKEN_ERR 0x00002000 -#define S2_TOKEN_ISSUED 0x00001000 -#define S2_TVX_EXP 0x00000800 -#define S2_TRT_EXP 0x00000400 -#define S2_MISSED_FRAME 0x00000200 -#define S2_ADDRESS_DET 0x00000100 -#define S2_PHY_INVALID 0x00000080 -#define S2_LOST_CTR_OVF 0x00000040 -#define S2_ERR_CTR_OVF 0x00000020 -#define S2_FRAME_CTR_OVF 0x00000010 -#define S2_SHORT_IFG 0x00000008 -#define S2_DUPL_CLAIM 0x00000004 -#define S2_TRT_EXP_RECOV 0x00000002 - -/* Bits in mdreg1 */ -#define M1_SINGLE_FRAME 0x8000 -#define M1_MODE 0x7000 -#define M1_MODE_INITIALIZE 0x0000 -#define M1_MODE_MEMORY 0x1000 -#define M1_MODE_ONLINE_SP 0x2000 -#define M1_MODE_ONLINE 0x3000 -#define M1_MODE_INT_LOOP 0x4000 -#define M1_MODE_EXT_LOOP 0x7000 -#define M1_SHORT_ADRS 0x0800 -#define M1_ADDET 0x0700 -#define M1_ADDET_NORM 0x0000 -#define M1_ADDET_METOO 0x0100 -#define M1_ADDET_NSA_NOTME 0x0200 -#define M1_ADDET_NSA 0x0300 -#define M1_ADDET_DISABLE_RECV 0x0400 -#define M1_ADDET_LIM_PROMISC 0x0600 -#define M1_ADDET_PROMISC 0x0700 -#define M1_SELECT_RA 0x0080 -#define M1_DISABLE_CARRY 0x0040 -#define M1_EXT_GRP 0x0030 -#define M1_EXT_GRP_MYGRP 0x0000 -#define M1_EXT_GRP_SOFT 0x0010 -#define M1_EXT_GRP_UPPER24 0x0020 -#define M1_EXT_GRP_UPPER16 0x0030 -#define M1_LOCK_XMIT_QS 0x0008 -#define M1_FULL_DUPLEX 0x0004 -#define M1_XMTINH_PIN 0x0002 - -/* Bits in mdreg2 */ -#define M2_TAGMODE 0x8000 -#define M2_STRIP_FCS 0x4000 -#define M2_CHECK_PARITY 0x2000 -#define M2_EVEN_PARITY 0x1000 -#define M2_LSB_FIRST 0x0800 -#define M2_RCV_BYTE_BDRY_MASK 0x0600 -#define M2_RCV_BYTE_BDRY 0x0200 -#define M2_ENABLE_HSREQ 0x0100 -#define M2_ENABLE_NPDMA 0x0080 -#define M2_SYNC_NPDMA 0x0040 -#define M2_SYMBOL_CTRL 0x0020 -#define M2_RECV_BAD_FRAMES 0x0010 -#define M2_AFULL_MASK 0x000f -#define M2_AFULL 0x0001 - -/* Bits in stmchn */ -#define SM_REV_MASK 0xe000 -#define SM_REV 0x2000 -#define SM_SEND_IMM_MODE 0x1000 -#define SM_TOKEN_MODE 0x0c00 -#define SM_TOKEN_MODE_NR 0x0000 -#define SM_TOKEN_MODE_ENTER_R 0x0400 -#define SM_TOKEN_MODE_ENTER_NR 0x0800 -#define SM_TOKEN_MODE_R 0x0c00 -#define SM_RCV_STATE 0x0380 -#define SM_XMIT_STATE 0x0070 -#define SM_MDR_PENDING 0x0008 -#define SM_MDR_TAG 0x0004 - -/* Bits in transmit descriptor */ -#define TD_MORE 0x80000000 -#define TD_MAGIC 0x40000000 -#define TD_BYTE_BDRY_MASK 0x18000000 -#define TD_BYTE_BDRY_1 0x08000000 -#define TD_XMIT_DONE 0x04000000 -#define TD_NO_FCS 0x02000000 -#define TD_XMIT_ABORT 0x01000000 -#define TD_BYTE_BDRY_LG 27 - -/* Bits in pointer in buffer memory (nontag mode) */ -#define PT_MAGIC 0xa0000000 - -/* Bits in receive status word */ -#define RS_VALID 0x80000000 -#define RS_ABORTED 0x40000000 -#define RS_SRC_ROUTE 0x10000000 -#define RS_E_INDIC 0x08000000 -#define RS_A_INDIC 0x04000000 -#define RS_C_INDIC 0x02000000 -#define RS_ERROR 0x01000000 -#define RS_ADDR_MATCH 0x00800000 -#define RS_FRAME_TYPE 0x00700000 -#define RS_FT_SMT 0x00000000 -#define RS_FT_LLC 0x00100000 -#define RS_FT_IMPL 0x00200000 -#define RS_FT_MAC 0x00400000 -#define RS_FT_LLC_SYNC 0x00500000 -#define RS_FT_IMPL_SYNC 0x00600000 -#define RS_BYTE_BDRY_MASK 0x00030000 -#define RS_BYTE_BDRY 0x00010000 -#define RS_BYTE_BDRY_LG 16 - -#define RS_LENGTH 0x0000ffff - diff -ur --new-file old/linux/drivers/ap1000/am79c864.h new/linux/drivers/ap1000/am79c864.h --- old/linux/drivers/ap1000/am79c864.h Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/am79c864.h Thu Jan 1 01:00:00 1970 @@ -1,162 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Definitions for Am79c864 PLC (Physical Layer Controller) - */ - -typedef int plc_reg; - -struct plc { - plc_reg ctrl_a; - plc_reg ctrl_b; - plc_reg intr_mask; - plc_reg xmit_vector; - plc_reg vec_length; - plc_reg le_threshold; - plc_reg c_min; - plc_reg tl_min; - plc_reg tb_min; - plc_reg t_out; - plc_reg dummy1; - plc_reg lc_length; - plc_reg t_scrub; - plc_reg ns_max; - plc_reg tpc_load; - plc_reg tne_load; - plc_reg status_a; - plc_reg status_b; - plc_reg tpc; - plc_reg tne; - plc_reg clk_div; - plc_reg bist_sig; - plc_reg rcv_vector; - plc_reg intr_event; - plc_reg viol_sym_ct; - plc_reg min_idle_ct; - plc_reg link_err_ct; -}; - -/* Bits in ctrl_a */ -#define CA_NOISE_TIMER 0x4000 -#define CA_TNE_16BIT 0x2000 -#define CA_TPC_16BIT 0x1000 -#define CA_REQ_SCRUB 0x0800 -#define CA_VSYM_INTR_MODE 0x0200 -#define CA_MINI_INTR_MODE 0x0100 -#define CA_LOOPBACK 0x0080 -#define CA_FOT_OFF 0x0040 -#define CA_EB_LOOP 0x0020 -#define CA_LM_LOOP 0x0010 -#define CA_BYPASS 0x0008 -#define CA_REM_LOOP 0x0004 -#define CA_RF_DISABLE 0x0002 -#define CA_RUN_BIST 0x0001 - -/* Bits in ctrl_b */ -#define CB_CONFIG_CTRL 0x8000 -#define CB_MATCH_LS 0x7800 -#define CB_MATCH_LS_ANY 0x0000 -#define CB_MATCH_LS_QLS 0x4000 -#define CB_MATCH_LS_MLS 0x2000 -#define CB_MATCH_LS_HLS 0x1000 -#define CB_MATCH_LS_ILS 0x0800 -#define CB_MAINT_LS 0x0700 -#define CB_MAINT_LS_QLS 0x0000 -#define CB_MAINT_LS_ILS 0x0100 -#define CB_MAINT_LS_HLS 0x0200 -#define CB_MAINT_LS_MLS 0x0300 -#define CB_MAINT_LS_PDR 0x0600 -#define CB_CLASS_S 0x0080 -#define CB_PC_LCT 0x0060 -#define CB_PC_LCT_NONE 0x0000 -#define CB_PC_LCT_PDR 0x0020 -#define CB_PC_LCT_IDLE 0x0040 -#define CB_PC_LCT_LOOP 0x0060 -#define CB_PC_JOIN 0x0010 -#define CB_LONG_LCT 0x0008 -#define CB_PC_MAINT 0x0004 -#define CB_PCM_CTRL 0x0003 -#define CB_PC_START 0x0001 -#define CB_PC_TRACE 0x0002 -#define CB_PC_STOP 0x0003 - -/* Bits in status_a */ -#define SA_SIG_DETECT 0x0400 -#define SA_PREV_LS 0x0300 -#define SA_PREV_LS_QLS 0x0000 -#define SA_PREV_LS_MLS 0x0100 -#define SA_PREV_LS_HLS 0x0200 -#define SA_PREV_LS_ILS 0x0300 -#define SA_LINE_ST 0x00e0 -#define SA_LINE_ST_NLS 0x0000 -#define SA_LINE_ST_ALS 0x0020 -#define SA_LINE_ST_ILS4 0x0060 -#define SA_LINE_ST_QLS 0x0080 -#define SA_LINE_ST_MLS 0x00a0 -#define SA_LINE_ST_HLS 0x00c0 -#define SA_LINE_ST_ILS 0x00e0 -#define SA_LSM_STATE 0x0010 -#define SA_UNKN_LINE_ST 0x0008 -#define SA_SYM_PAIR_CTR 0x0007 - -/* Bits in status_b */ -#define SB_RF_STATE 0xc000 -#define SB_RF_STATE_REPEAT 0x0000 -#define SB_RF_STATE_IDLE 0x4000 -#define SB_RF_STATE_HALT1 0x8000 -#define SB_RF_STATE_HALT2 0xc000 -#define SB_PCI_STATE 0x3000 -#define SB_PCI_STATE_REMOVED 0x0000 -#define SB_PCI_STATE_INS_SCR 0x1000 -#define SB_PCI_STATE_REM_SCR 0x2000 -#define SB_PCI_STATE_INSERTED 0x3000 -#define SB_PCI_SCRUB 0x0800 -#define SB_PCM_STATE 0x0780 -#define SB_PCM_STATE_OFF 0x0000 -#define SB_PCM_STATE_BREAK 0x0080 -#define SB_PCM_STATE_TRACE 0x0100 -#define SB_PCM_STATE_CONNECT 0x0180 -#define SB_PCM_STATE_NEXT 0x0200 -#define SB_PCM_STATE_SIGNAL 0x0280 -#define SB_PCM_STATE_JOIN 0x0300 -#define SB_PCM_STATE_VERIFY 0x0380 -#define SB_PCM_STATE_ACTIVE 0x0400 -#define SB_PCM_STATE_MAIN 0x0480 -#define SB_PCM_SIGNALING 0x0040 -#define SB_LSF 0x0020 -#define SB_RCF 0x0010 -#define SB_TCF 0x0008 -#define SB_BREAK_REASON 0x0007 -#define SB_BREAK_REASON_NONE 0x0000 -#define SB_BREAK_REASON_START 0x0001 -#define SB_BREAK_REASON_T_OUT 0x0002 -#define SB_BREAK_REASON_NS_MAX 0x0003 -#define SB_BREAK_REASON_QLS 0x0004 -#define SB_BREAK_REASON_ILS 0x0005 -#define SB_BREAK_REASON_HLS 0x0006 - -/* Bits in intr_event and intr_mask */ -#define IE_NP_ERROR 0x8000 -#define IE_SIGNAL_OFF 0x4000 -#define IE_LE_CTR 0x2000 -#define IE_MINI_CTR 0x1000 -#define IE_VSYM_CTR 0x0800 -#define IE_PHY_INVALID 0x0400 -#define IE_EBUF_ERR 0x0200 -#define IE_TNE_EXP 0x0100 -#define IE_TPC_EXP 0x0080 -#define IE_PCM_ENABLED 0x0040 -#define IE_PCM_BREAK 0x0020 -#define IE_SELF_TEST 0x0010 -#define IE_TRACE_PROP 0x0008 -#define IE_PCM_CODE 0x0004 -#define IE_LS_MATCH 0x0002 -#define IE_PARITY_ERR 0x0001 - -/* Correct value for BIST signature */ -#define BIST_CORRECT 0x6ecd diff -ur --new-file old/linux/drivers/ap1000/ap.c new/linux/drivers/ap1000/ap.c --- old/linux/drivers/ap1000/ap.c Wed Jan 19 03:54:20 2000 +++ new/linux/drivers/ap1000/ap.c Thu Jan 1 01:00:00 1970 @@ -1,307 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * ap.c - Single AP1000 block driver. - * - * (C) dwalsh, Pious project, DCS, ANU 1996 - * - * This block driver is designed to simply to perform - * io operations to the hosts file system. - * - * Heavily modified by tridge - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AP_DEBUG 0 - -#define MAJOR_NR APBLOCK_MAJOR -#define AP_DRIVER 1 -#include - -#define NUM_APDEVS 8 -#define MAX_REQUESTS 1 - -static DECLARE_WAIT_QUEUE_HEAD(busy_wait); - -static int ap_blocksizes[NUM_APDEVS]; -static int ap_length[NUM_APDEVS]; -static int ap_fds[NUM_APDEVS]; - -#define SECTOR_BLOCK_SHIFT 9 -#define AP_BLOCK_SHIFT 12 /* 4k blocks */ -#define AP_BLOCK_SIZE (1<= MAX_REQUESTS) return; - -repeat: - - if (!CURRENT) { - return; - } - - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) { - panic(DEVICE_NAME ": request list destroyed"); - } - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) { - panic(DEVICE_NAME ": block not locked"); - } - } - - req = CURRENT; - - minor = MINOR(req->rq_dev); - - if (minor >= NUM_APDEVS) { - printk("apblock: request for invalid minor %d\n",minor); - end_request(0); - goto repeat; - } - - offset = req->sector; - len = req->current_nr_sectors; - - if ((offset + len) > ap_length[minor]) { - printk("apblock: request for invalid sectors %d -> %d\n", - offset,offset+len); - end_request(0); - goto repeat; - } - - if (ap_fds[minor] == -1) { - printk("apblock: minor %d not open\n",minor); - end_request(0); - goto repeat; - } - - /* convert to our units */ - offset <<= SECTOR_BLOCK_SHIFT; - len <<= SECTOR_BLOCK_SHIFT; - - /* setup a request for the host */ - creq.cid = mpp_cid(); - creq.size = sizeof(creq); - creq.header = 0; - creq.data[0] = (int)(req); - creq.data[1] = ap_fds[minor]; - creq.data[2] = offset; - creq.data[3] = len; - - switch (req->cmd) { - case READ: -#if AP_DEBUG - printk("apblock: read req=0x%x len=%d offset=%d\n", - req,len,offset); -#endif - creq.type = REQ_BREAD; - if (bif_queue(&creq,0,0)) { - return; - } - break; - - case WRITE: -#if AP_DEBUG - printk("apblock: write req=0x%x len=%d offset=%d\n", - req,len,offset); -#endif - creq.type = REQ_BWRITE; - creq.size += len; - if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) { - return; - } - break; - - default: - printk("apblock: unknown ap op %d\n",req->cmd); - end_request(0); - return; - } - - if (++request_count < MAX_REQUESTS) - goto repeat; -} - -/* this is called by ap1000/bif.c when a read/write has completed */ -void ap_complete(struct cap_request *creq) -{ -#if AP_DEBUG - struct request *req = (struct request *)(creq->data[0]); - - printk("request 0x%x complete\n",req); -#endif - end_request(1); - request_count--; - ap_request(NULL); -} - - -/* this is called by ap1000/bif.c to find a buffer to put a BREAD into - using DMA */ -char *ap_buffer(struct cap_request *creq) -{ - struct request *req = (struct request *)(creq->data[0]); - - return(req->buffer); -} - - -static int ap_open(struct inode * inode, struct file * filp) -{ - struct cap_request creq; - int minor; - minor = DEVICE_NR(inode->i_rdev); - -#if AP_DEBUG - printk("ap_open: minor=%x\n", minor); -#endif - - if (minor >= NUM_APDEVS) - return -ENODEV; - - /* if its already open then don't do anything */ - if (ap_fds[minor] != -1) - return 0; - - /* send the open request to the front end */ - creq.cid = mpp_cid(); - creq.type = REQ_BOPEN; - creq.header = 0; - creq.size = sizeof(creq); - creq.data[0] = minor; - - bif_queue(&creq,0,0); - - /* wait for the reply */ - while (ap_fds[minor] == -1) - sleep_on(&busy_wait); - - return 0; -} - - -static int ap_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (!inode || !inode->i_rdev) - return -EINVAL; - - switch (cmd) { - case BLKGETSIZE: /* Return device size */ - if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg)) - return -EFAULT; - return 0; - - default: - break; - }; - - return 0; -} - - -/* this is called by ap1000/bif.c when a open reply comes in */ -void ap_open_reply(struct cap_request *creq) -{ - int minor = creq->data[0]; - - ap_fds[minor] = creq->data[1]; - ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT; - -#if AP_DEBUG - printk("ap opened minor %d length=%d fd=%d\n", - minor,ap_length[minor],ap_fds[minor]); -#endif - - wake_up(&busy_wait); -} - -static struct block_device_operations ap_fops = { - open: ap_open, - release: ap_release, - ioctl: ap_ioctl, -}; - - -int ap_init(void) -{ - int i; - static int done = 0; - - if (done) return(1); - - if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) { - printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR); - return -1; - } - printk("ap_init: register dev %d\n", MAJOR_NR); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &ap_request); - - for (i=0;i -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "apfddi.h" -#include "smt-types.h" -#include "mac.h" -#include "plc.h" -#include "am79c830.h" -#include "apfddi-reg.h" - -volatile struct formac *mac; -volatile struct plc *plc; -volatile int *csr0; -volatile int *csr1; -volatile int *buffer_mem; -volatile int *fifo; - -#define APFDDI_DEBUG 0 - -#define APFDDI_IRQ 7 - -#define T(x) (-SECS_TO_FDDI_TIME(x)) - -struct plc_info plc_info = { - pt_s, /* port_type */ - T(1.6e-3), /* c_min */ - T(50e-6), /* tl_min */ - T(5e-3), /* tb_min */ - T(100e-3), /* t_out */ - T(50e-3), /* lc_short */ - T(500e-3), /* lc_medium */ - T(5.0), /* lc_long */ - T(50.0), /* lc_extended */ - T(3.5e-3), /* t_scrub */ - T(1.3e-3), /* ns_max */ -}; - -struct mac_info mac_info = { - T(165e-3), /* tmax */ - T(3.5e-3), /* tvx */ - T(20e-3), /* treq */ - { 0x42, 0x59 }, /* s_address */ - { 0x42, 0x59, 0x10, 0x76, 0x88, 0x82 }, /* l_address */ - { 0 }, /* s_group_adrs */ - { 0 }, /* l_group_adrs */ - 0, /* rcv_own_frames */ - 1, /* only_good_frames */ -}; - -u_char fddi_bitrev[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, -}; - -/* XXX our hardware address, canonical bit order */ -static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 }; - -struct net_device *apfddi_device = NULL; -struct net_device_stats *apfddi_stats = NULL; - -volatile struct apfddi_queue *apfddi_queue_top = NULL; - -void map_regs(void) -{ - unsigned long reg_base_addr = 0xfbf00000; - - mac = (volatile struct formac *) (reg_base_addr + FORMAC); - plc = (volatile struct plc *) (reg_base_addr + PLC); - csr0 = (volatile int *) (reg_base_addr + CSR0); - csr1 = (volatile int *) (reg_base_addr + CSR1); - buffer_mem = (volatile int *) (reg_base_addr + BUFFER_MEM); - fifo = (volatile int *) (reg_base_addr + FIFO); -} - -int ring_op; - -void apfddi_startup(void) -{ - int reason; - -#if APFDDI_DEBUG - printk("In apfddi_startup\n"); -#endif - - *csr0 = CS0_LED0; - ring_op = 0; - if (*csr1 & 0xf078) { - *csr1 = CS1_RESET_MAC | CS1_RESET_FIFO; - *csr1 = 0; - reason = 1; - printk("resetting after power-on\n"); - } else { - *csr1 = CS1_RESET_FIFO; - *csr1 = 0; - reason = plc_inited(&plc_info); - if (reason) - printk("resetting: plc reason %d\n", reason); - } - if (reason) { -#if APFDDI_DEBUG - printk("Calling plc_init\n"); -#endif - plc_init(&plc_info); -#if APFDDI_DEBUG - printk("Calling mac_init\n"); -#endif - mac_init(&mac_info); - *csr0 |= CS0_LED1; - pc_start(loop_none); - - } else { - *csr0 |= CS0_LED2 | CS0_LED1; - reason = mac_inited(&mac_info); - if (reason) { - printk("resetting mac: reason %d\n", reason); - mac_init(&mac_info); - mac_reset(loop_none); - mac_claim(); - } else { - ring_op = 1; - *csr0 &= ~(CS0_LED0 | CS0_LED1 | CS0_LED2); - } - } -} - -void apfddi_off(void) -{ - *csr0 &= ~CS0_LED1; - pc_stop(); -} - -void apfddi_sleep(void) -{ - mac_sleep(); - plc_sleep(); -} - -void apfddi_poll(void) -{ - if (*csr0 & CS0_PHY_IRQ) - plc_poll(); - if (*csr0 & CS0_MAC_IRQ) - mac_poll(); -} - -void set_cf_join(int on) -{ - if (on) { -#if APFDDI_DEBUG - printk("apfddi: joined the ring!\n"); -#endif - mac_reset(loop_none); - *csr0 |= CS0_LED2; - mac_claim(); - } else { - mac_disable(); - ring_op = 0; - *csr0 = (*csr0 & ~CS0_LED2) | CS0_LED1 | CS0_LED0; - } -} - -void set_ring_op(int up) -{ - ring_op = up; - if (up) { -#if APFDDI_DEBUG - printk("apfddi: ring operational!\n"); -#endif - *csr0 &= ~(CS0_LED2 | CS0_LED1 | CS0_LED0); - } else - *csr0 |= CS0_LED2 | CS0_LED1 | CS0_LED0; -} - -void rmt_event(int st) -{ - if (st & (S2_BEACON_STATE|S2_MULTIPLE_DA|S2_TOKEN_ERR - |S2_DUPL_CLAIM|S2_TRT_EXP_RECOV)) { - printk("st2 = %x\n", st); - } -} - - -int apfddi_init(struct net_device *dev); -static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev); -int apfddi_rx(struct mac_buf *mbuf); -static struct net_device_stats *apfddi_get_stats(struct net_device *dev); -#if APFDDI_DEBUG -void dump_packet(char *action, char *buf, int len, int seq); -#endif - -/* - * Create FDDI header for an arbitrary protocol layer - * - * saddr=NULL means use device source address (always will anyway) - * daddr=NULL means leave destination address (eg unresolved arp) - */ -static int apfddi_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len) -{ - struct fddi_header *fh; - struct llc_header *lh; - u_char *base_header; - u_char *fd_daddr = (u_char *)daddr; - int i; - -#if APFDDI_DEBUG - printk("In apfddi_hard_header\n"); -#endif - - if (skb == NULL) { - printk("Null skb in apfddi_hard_header... returning...\n"); - return 0; - } - - switch(type) { - case ETH_P_IP: -#if APFDDI_DEBUG - printk("apfddi_hard_header: Processing IP packet\n"); -#endif - break; - case ETH_P_ARP: -#if APFDDI_DEBUG - printk("apfddi_hard_header: Processing ARP packet\n"); -#endif - break; - case ETH_P_RARP: -#if APFDDI_DEBUG - printk("apfddi_hard_header: Processing RARP packet\n"); -#endif - break; - default: - printk("apfddi_hard_header: I don't understand protocol %d (0x%x)\n", - type, type); - apfddi_stats->tx_errors++; - return 0; - } - - base_header = (u_char *)skb_push(skb, FDDI_HARDHDR_LEN-4); - if (base_header == NULL) { - printk("apfddi_hard_header: Memory squeeze, dropping packet.\n"); - apfddi_stats->tx_dropped++; - return 0; - } - fh = (struct fddi_header *)(base_header + 3); - lh = (struct llc_header *)((char *)fh + FDDI_HDRLEN); - - lh->llc_dsap = lh->llc_ssap = LLC_SNAP_LSAP; - lh->snap_control = LLC_UI; - lh->snap_org_code[0] = 0; - lh->snap_org_code[1] = 0; - lh->snap_org_code[2] = 0; - lh->snap_ether_type = htons(type); - -#if APFDDI_DEBUG - printk("snap_ether_type is %d (0x%x)\n", lh->snap_ether_type, - lh->snap_ether_type); -#endif - - fh->fddi_fc = FDDI_FC_LLC; - - /* - * Fill in the source address. - */ - for (i = 0; i < 6; i++) - fh->fddi_shost[i] = fddi_bitrev[apfddi_saddr[i]]; - - /* - * Fill in the destination address. - */ - if (daddr) { -#if APFDDI_DEBUG - printk("daddr is: "); -#endif - for (i = 0; i < 6; i++) { - fh->fddi_dhost[i] = fddi_bitrev[fd_daddr[i]]; -#if APFDDI_DEBUG - printk("%x(%x):",fh->fddi_dhost[i], fd_daddr[i]); -#endif - } -#if APFDDI_DEBUG - printk("\n"); -#endif - return(FDDI_HARDHDR_LEN-4); - } - else { -#if APFDDI_DEBUG - printk("apfddi_hard_header, daddr was NULL\n"); -#endif - return -(FDDI_HARDHDR_LEN-4); - } -} - -/* - * Rebuild the FDDI header. This is called after an ARP (or in future - * other address resolution) has completed on this sk_buff. We now let - * ARP fill in the other fields. - */ -static int apfddi_rebuild_header(void *buff, struct net_device *dev, - unsigned long raddr, struct sk_buff *skb) -{ - int i, status; - struct fddi_header *fh = (struct fddi_header *)(buff+3); - -#if APFDDI_DEBUG - printk("In apfddi_rebuild_header, dev is %x apfddi_device is %x\n", dev, - apfddi_device); - printk("rebuild header for fc 0x%x\n", fh->fddi_fc); - printk("dest address is:\n"); - for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]); -#endif - status = arp_find(raddr, skb) ? 1 : 0; - - if (!status) { -#if APFDDI_DEBUG - printk("dest address is now:\n"); - for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]); - printk("status is %d\n", status); -#endif - /* - * Bit reverse the dest_address. - */ - for (i = 0; i < 6; i++) - fh->fddi_dhost[i] = fddi_bitrev[fh->fddi_dhost[i]]; - } -#if APFDDI_DEBUG - printk("\n"); -#endif - return(status); -} - -static int apfddi_set_mac_address(struct net_device *dev, void *addr) -{ -#if APFDDI_DEBUG - printk("In apfddi_set_mac_address\n"); -#endif - return (0); -} - -static void apfddi_set_multicast_list(struct net_device *dev) -{ -#if APFDDI_DEBUG - printk("In apfddi_set_multicast_list\n"); -#endif -} - -static int apfddi_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ -#if APFDDI_DEBUG - printk("In apfddi_do_ioctl\n"); -#endif - return (0); -} - -static int apfddi_set_config(struct net_device *dev, struct ifmap *map) -{ -#if APFDDI_DEBUG - printk("In apfddi_set_config\n"); -#endif - return (0); -} - -/* - * Opening the fddi device through ifconfig. - */ -int apfddi_open(struct net_device *dev) -{ - static int already_run = 0; - unsigned flags; - int res; - - if (already_run) { - apfddi_startup(); - *csr0 |= CS0_INT_ENABLE; - return 0; - } - already_run = 1; - - map_regs(); - apfddi_startup(); - - save_flags(flags); cli(); - if ((res = request_irq(APFDDI_IRQ, apfddi_interrupt, SA_INTERRUPT, - "apfddi", dev))) { - printk("Failed to install apfddi handler error=%d\n", res); - restore_flags(flags); - return(0); - } - enable_irq(APFDDI_IRQ); - restore_flags(flags); - -#if APFDDI_DEBUG - printk("Installed apfddi interrupt handler\n"); -#endif - *csr0 |= CS0_INT_ENABLE; -#if APFDDI_DEBUG - printk("Enabled fddi interrupts\n"); -#endif - - return 0; -} - -/* - * Stop the fddi device through ifconfig. - */ -int apfddi_stop(struct net_device *dev) -{ - *csr0 &= ~CS0_INT_ENABLE; - apfddi_sleep(); - return 0; -} - - -/* - * Initialise fddi network interface. - */ -int apfddi_init(struct net_device *dev) -{ - int i; - - /* - * Check if this thing has already been initialised. - */ - if (apfddi_device != NULL) - return -ENODEV; - - printk("apfddi_init(): Initialising fddi interface\n"); - - apfddi_device = dev; - - dev->open = apfddi_open; - dev->stop = apfddi_stop; - dev->hard_start_xmit = apfddi_xmit; - dev->get_stats = apfddi_get_stats; - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_ATOMIC); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_device_stats)); - apfddi_stats = (struct net_device_stats *)apfddi_device->priv; - - /* Initialise the fddi device structure */ - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&dev->buffs[i]); - - dev->hard_header = apfddi_hard_header; - dev->rebuild_header = apfddi_rebuild_header; - dev->set_mac_address = apfddi_set_mac_address; - dev->header_cache_update = NULL; - dev->do_ioctl = apfddi_do_ioctl; - dev->set_config = apfddi_set_config; - dev->set_multicast_list = apfddi_set_multicast_list; - dev->type = ARPHRD_ETHER; - dev->hard_header_len = FDDI_HARDHDR_LEN; - dev->mtu = FDDIMTU; - dev->addr_len = 6; - memcpy(dev->dev_addr, apfddi_saddr, sizeof(apfddi_saddr)); - dev->tx_queue_len = 100; /* XXX What should this be? */ - dev->irq = APFDDI_IRQ; - - memset(dev->broadcast, 0xFF, ETH_ALEN); - - return(0); -} - -static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#if APFDDI_DEBUG - static int times = 0; -#endif - unsigned flags; - save_flags(flags); cli(); - -#if APFDDI_DEBUG - printk("In apfddi_interrupt irq %d dev_id %p times %d\n", - irq, dev_id, ++times); -#endif - - apfddi_poll(); - restore_flags(flags); -} - -#if APFDDI_DEBUG -static char *flagbits[8] = { - "fin", "syn", "rst", "push", "ack", "urg", "6", "7" -}; - -void dump_packet(action, buf, len, seq) - char *action, *buf; - int len, seq; -{ - int i, flags; - char *sep; - - printk("%s packet %d of %d bytes at %d:\n", action, seq, - len, jiffies); - printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n", - *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4), - *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2)); - if( buf[9] == 6 || buf[9] == 17 ){ - /* TCP or UDP */ - printk(" sport=%d dport=%d", - *(u_short *)(buf+20), *(u_short *)(buf+22)); - if( buf[9] == 6 ){ - printk(" seq=%d ack=%d win=%d flags=<", - *(long *)(buf+24), *(long *)(buf+28), - *(unsigned short *)(buf+34)); - flags = buf[33]; - sep = ""; - for (i = 7; i >= 0; --i) { - if (flags & (1 << i)) { - printk("%s%s", sep, flagbits[i]); - sep = "+"; - } - } - printk(">"); - } - printk("\n"); - } -} -#endif - -#if APFDDI_DEBUG -static void apfddi_print_frame(struct sk_buff *skb) -{ - int i; - struct llc_header *lh; - static int seq = 0; - -#if 0 - printk("skb->len is %d\n", skb->len); - printk("fc is 0x%x\n", *(u_char *)(skb->data+3)); - printk("dest address is:\n"); - for (i = 0; i < 6; i++) { - printk("%x:", fddi_bitrev[*(u_char *)(skb->data+4+i)]); - } - printk("\n"); - printk("source address is:\n"); - for (i = 0; i < 6; i++) { - printk("%x:", fddi_bitrev[*(u_char *)(skb->data+10+i)]); - } - printk("\n"); -#endif - lh = (struct llc_header *)(skb->data+16); -#if 0 - printk("llc_dsp %d llc_ssap %d snap_control %d org_code [0]=%d [1]=%d [2]=%d ether_type=%d\n", - lh->llc_dsap, lh->llc_ssap, lh->snap_control, - lh->snap_org_code[0], lh->snap_org_code[1], lh->snap_org_code[2], - lh->snap_ether_type); -#endif - if (lh->snap_ether_type == ETH_P_IP) - dump_packet("apfddi_xmit:", skb->data+24, skb->len-24, seq++); -} -#endif - -/* - * Transmitting packet over FDDI. - */ -static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned long flags; - -#if APFDDI_DEBUG - printk("In apfddi_xmit\n"); -#endif - - /* - * Check there is some work to do. - */ - if (skb == NULL || dev == NULL) - return(0); - -#if APFDDI_DEBUG - printk("skb address is for apfddi 0x%x\n", skb); -#endif - - /* - * Check lock variable. - */ - save_flags(flags); cli(); - if (dev->tbusy != 0) { - restore_flags(flags); - printk("apfddi_xmit: device busy\n"); - apfddi_stats->tx_errors++; - return 1; - } - restore_flags(flags); - dev->tbusy = 1; - - dev->trans_start = jiffies; - - skb->mac.raw = skb->data; - - /* - * Append packet onto send queue. - */ - if (mac_queue_append(skb)) { - /* - * No memory. - */ - return 1; - } - - /* - * Process packet queue. - */ - mac_process(); - - apfddi_stats->tx_packets++; - dev->tbusy = 0; - return 0; -} - -#if APFDDI_DEBUG -void print_mbuf(struct mac_buf *mbuf) -{ - printk("mac %p length=%d ptr=%p wraplen=%d wrapptr=%x fr_start=%d fr_end=%d\n", - mbuf, mbuf->length, mbuf->ptr, mbuf->wraplen, mbuf->wrapptr, - mbuf->fr_start, mbuf->fr_end); -} -#endif - -/* - * Return statistics of fddi driver. - */ -static struct net_device_stats *apfddi_get_stats(struct net_device *dev) -{ - return((struct net_device_stats *)dev->priv); -} - - - - diff -ur --new-file old/linux/drivers/ap1000/apfddi.h new/linux/drivers/ap1000/apfddi.h --- old/linux/drivers/ap1000/apfddi.h Wed Aug 18 20:38:58 1999 +++ new/linux/drivers/ap1000/apfddi.h Thu Jan 1 01:00:00 1970 @@ -1,142 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -#define BUFFER_MEM 0x40000 -#define CSR0 0x60000 -#define CSR1 0x60004 -#define PLC 0x60080 -#define FORMAC 0x60200 -#define FIFO 0x68000 - -/* Size of buffer memory */ -#define BUFFER_SIZE 32768 /* words; 128kB */ - -/* Bits in CSR0 */ -#define CS0_INT_REQ 0x8000 /* board interrupt request asserted */ -#define CS0_MAC_IRQ 0x4000 /* FORMAC is requesting interrupt */ -#define CS0_PHY_IRQ 0x2000 /* PLC is requesting interrupt */ -#define CS0_LED2 0x1000 /* turn on led 2 */ -#define CS0_DO_IRQ 0x0200 /* request interrupt */ -#define CS0_INT_ENABLE 0x0100 /* enable interrupt requests */ -#define CS0_DMA_ENABLE 0x0080 /* enable DMA requests */ -#define CS0_DMA_RECV 0x0040 /* DMA requests are in receive dirn. */ -#define CS0_LED1 0x0010 /* turn on led 1 */ -#define CS0_LED0 0x0008 /* turn on led 0 (red) */ -#define CS0_HREQ 0x0007 /* host request to FORMAC */ -#define CS0_HREQ_WSPEC 0x0002 /* write special frames */ -#define CS0_HREQ_RECV 0x0003 /* read receive queue */ -#define CS0_HREQ_WS 0x0004 /* write synchronous queue */ -#define CS0_HREQ_WA0 0x0005 /* write async queue 0 */ -#define CS0_HREQ_WA1 0x0006 /* write async queue 1 */ -#define CS0_HREQ_WA2 0x0007 /* write async queue 2 */ - -/* Bits in CSR1 */ -#define CS1_THIS_QAF 0x0800 /* this queue almost full */ -#define CS1_FIFO_TAG 0x0400 /* tag of word at head of fifo */ -#define CS1_BUF_RD_TAG 0x0200 /* tag of last word read from buffer */ -#define CS1_BUF_WR_TAG 0x0100 /* tag to write to buffer */ -#define CS1_TAGMODE 0x0080 /* enable tag mode */ -#define CS1_RESET_MAC 0x0040 /* reset FORMAC and PLC */ -#define CS1_RESET_FIFO 0x0020 /* reset FIFO */ -#define CS1_CLEAR_QAF 0x0010 /* clear queue-almost-full bits */ -#define CS1_FIFO_LEVEL 0x0007 /* # words in FIFO (0 - 4) */ - -/* - * FDDI Frame Control values. - */ -#define FDDI_SMT 0x41 -#define FDDI_SMT_NSA 0x4f -#define FDDI_FC_LLC 0x50 -#define FDDI_FC_LLC_MASK 0xf0 - -/* - * Unnumbered LLC format commands - */ -#define LLC_UI 0x3 -#define LLC_UI_P 0x13 -#define LLC_DISC 0x43 -#define LLC_DISC_P 0x53 -#define LLC_UA 0x63 -#define LLC_UA_P 0x73 -#define LLC_TEST 0xe3 -#define LLC_TEST_P 0xf3 -#define LLC_FRMR 0x87 -#define LLC_FRMR_P 0x97 -#define LLC_DM 0x0f -#define LLC_DM_P 0x1f -#define LLC_XID 0xaf -#define LLC_XID_P 0xbf -#define LLC_SABME 0x6f -#define LLC_SABME_P 0x7f - -/* - * Supervisory LLC commands - */ -#define LLC_RR 0x01 -#define LLC_RNR 0x05 -#define LLC_REJ 0x09 - -/* - * Info format - dummy only - */ -#define LLC_INFO 0x00 - -/* - * ISO PDTR 10178 contains among others - */ -#define LLC_X25_LSAP 0x7e -#define LLC_SNAP_LSAP 0xaa -#define LLC_ISO_LSAP 0xfe - -/* - * Structure of the FDDI MAC header. - */ -struct fddi_header { - u_char fddi_fc; /* frame control field */ - u_char fddi_dhost[6]; /* destination address */ - u_char fddi_shost[6]; /* source address */ -}; - -/* - * Structure of LLC/SNAP header. - */ -struct llc_header { - u_char llc_dsap; - u_char llc_ssap; - u_char snap_control; - u_char snap_org_code[3]; - u_short snap_ether_type; -}; - -#define FDDI_HDRLEN 13 /* sizeof(struct fddi_header) */ -#define LLC_SNAPLEN 8 /* bytes for LLC/SNAP header */ -#define FDDI_HARDHDR_LEN 28 /* Hard header size */ - -#define FDDIMTU 4352 - - -/* Types of loopback we can do. */ -typedef enum { - loop_none, - loop_formac, - loop_plc_lm, - loop_plc_eb, - loop_pdx -} LoopbackType; - -/* Offset from fifo for writing word with tag. */ -#define FIFO_TAG 0x80 - -#define MAX_FRAME_LEN 4500 - -void set_ring_op(int up); -void rmt_event(int st); -void set_cf_join(int on); - -extern struct net_device *apfddi_device; -extern struct net_device_stats *apfddi_stats; - diff -ur --new-file old/linux/drivers/ap1000/bif.c new/linux/drivers/ap1000/bif.c --- old/linux/drivers/ap1000/bif.c Wed Aug 18 20:38:58 1999 +++ new/linux/drivers/ap1000/bif.c Thu Jan 1 01:00:00 1970 @@ -1,280 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * $Id: bif.c,v 1.13 1996/12/18 01:45:52 tridge Exp $ - * - * Network interface definitions for bif device. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include -#include /* For ARPHRD_BIF */ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#define BIF_DEBUG 0 -#if BIF_DEBUG -static int seq = 0; -#endif - -#define BIF_MTU 10240 - -static struct net_device *bif_device = 0; -static struct net_device_stats *bif_stats = 0; - -int bif_init(struct net_device *dev); -int bif_open(struct net_device *dev); -static int bif_xmit(struct sk_buff *skb, struct net_device *dev); -int bif_rx(struct sk_buff *skb); -int bif_stop(struct net_device *dev); -static struct net_device_stats *bif_get_stats(struct net_device *dev); - -static int bif_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len) -{ -#if BIF_DEBUG - printk("bif_hard_header()\n"); -#endif - - skb_push(skb,dev->hard_header_len); - - if (daddr) skb->arp = 1; - - /* tell IP how much space we took */ - return (dev->hard_header_len); -} - -static int bif_rebuild_header(void *buff, struct net_device *dev, - unsigned long raddr, struct sk_buff *skb) -{ - /* this would normally be used to fill in hardware addresses after - an ARP */ -#if BIF_DEBUG - printk("bif_rebuild_header()\n"); -#endif - if (skb) skb->arp = 1; - return(0); -} - -static int bif_set_mac_address(struct net_device *dev, void *addr) -{ - printk("BIF: set_mac_address called\n"); - return (0); -} - -static void bif_set_multicast_list(struct net_device *dev) -{ - return; -} - -static int bif_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - printk("BIF: Called do_ioctl\n"); - return (0); -} - -static int bif_set_config(struct net_device *dev, struct ifmap *map) -{ - printk("BIF: Called bif_set_config\n"); - return (0); -} - -/* - * Initialise bif network interface. - */ -int bif_init(struct net_device *dev) -{ - int i; - - printk("bif_init(): Initialising bif interface\n"); - bif_device = dev; - - dev->mtu = BIF_MTU; - dev->tbusy = 0; - dev->hard_start_xmit = bif_xmit; - dev->hard_header = bif_hard_header; - dev->hard_header_len = sizeof(struct cap_request); - dev->addr_len = 0; - dev->tx_queue_len = 50000; /* no limit (almost!) */ - dev->type = ARPHRD_BIF; - dev->rebuild_header = bif_rebuild_header; - dev->open = bif_open; - dev->flags = IFF_NOARP; /* Don't use ARP on this device */ - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_device_stats)); - bif_stats = (struct net_device_stats *)bif_device->priv; - - - dev->stop = bif_stop; - dev->get_stats = bif_get_stats; - - dev->set_mac_address = bif_set_mac_address; - dev->header_cache_update = NULL; - dev->do_ioctl = bif_do_ioctl; - dev->set_config = bif_set_config; - dev->set_multicast_list = bif_set_multicast_list; - - memset(dev->broadcast, 0xFF, ETH_ALEN); - - dev_init_buffers(dev); - - return(0); -} - -int bif_open(struct net_device *dev) -{ - printk("In bif_open\n"); - dev->tbusy = 0; - dev->start = 1; - return 0; -} - -#if BIF_DEBUG -static void dump_packet(char *action, char *buf, int len, int seq) -{ - int flags; - char *sep; - - printk("%s packet %d of %d bytes at %d:\n", action, seq, - len, (int)jiffies); - printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n", - *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4), - *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2)); - if( buf[9] == 6 || buf[9] == 17 ){ - /* TCP or UDP */ - printk(" sport=%d dport=%d", - *(u_short *)(buf+20), *(u_short *)(buf+22)); - if( buf[9] == 6 ){ - printk(" seq=%d ack=%d win=%d flags=<", - *(long *)(buf+24), *(long *)(buf+28), - *(unsigned short *)(buf+34)); - flags = buf[33]; - sep = ""; - printk(">"); - } - printk("\n"); - } - else { - printk(" protocol = %d\n", buf[9]); - } -} -#endif - - -static int bif_xmit(struct sk_buff *skb, struct net_device *dev) -{ - extern int bif_send_ip(int cid,struct sk_buff *skb); - extern int tnet_send_ip(int cid,struct sk_buff *skb); - extern int msc_blocked, tnet_ip_enabled; - u_long destip; - int cid; - - if (skb == NULL || dev == NULL) - return(0); - - destip = *(u_long *)(skb->data+sizeof(struct cap_request)+16); - cid = ap_ip_to_cid(destip); - - skb->dev = dev; - skb->mac.raw = skb->data; - - if (cid != -1 && tnet_ip_enabled && !msc_blocked) { - tnet_send_ip(cid,skb); - } else { - bif_send_ip(cid, skb); - } - - dev->tbusy = 0; - - bif_stats->tx_packets++; - - mark_bh(NET_BH); - - return 0; -} - - -/* - * Receive a packet from the BIF - called from interrupt handler. - */ -int bif_rx(struct sk_buff *skb) -{ -#if BIF_DEBUG - dump_packet("bif_rx:", skb->data, skb->len, seq++); -#endif - - if (bif_device == NULL) { - printk("bif: bif_device is NULL in bif_rx\n"); - dev_kfree_skb(skb); - return 0; - } - skb->dev = bif_device; - skb->protocol = ETH_P_IP; - -#if 1 - /* try disabling checksums on receive */ - if (ap_ip_to_cid(*(u_long *)(((char *)skb->data)+12)) != -1) - skb->ip_summed = CHECKSUM_UNNECESSARY; -#endif - - /* - * Inform the network layer of the new packet. - */ - skb->mac.raw = skb->data; - netif_rx(skb); - - if (bif_stats == NULL) { - printk("bif: bif_stats is NULL is bif_rx\n"); - return 0; - } - bif_stats->rx_packets++; - - return 0; -} - -int bif_stop(struct net_device *dev) -{ - printk("in bif_close\n"); - - dev->tbusy = 1; - dev->start = 0; - - return 0; -} - -/* - * Return statistics of bif driver. - */ -static struct net_device_stats *bif_get_stats(struct net_device *dev) -{ - return((struct net_device_stats *)dev->priv); -} - diff -ur --new-file old/linux/drivers/ap1000/ddv.c new/linux/drivers/ap1000/ddv.c --- old/linux/drivers/ap1000/ddv.c Wed Jan 19 03:54:20 2000 +++ new/linux/drivers/ap1000/ddv.c Thu Jan 1 01:00:00 1970 @@ -1,1008 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * ddv.c - Single AP1000 block driver. - * - * This block driver performs io operations to the ddv option - * board. (Hopefully:) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#define __KERNEL_SYSCALLS__ -#include -#include -#include -#include -#include -#include -#include - -#define MAJOR_NR DDV_MAJOR - -#include -#include -#include - -#define DDV_DEBUG 0 -#define AIR_DISK 1 - -#define SECTOR_SIZE 512 - -/* we can have lots of partitions */ -#define PARTN_BITS 6 -#define NUM_DDVDEVS (1<> 9) - 1) - -/* try to read ahead a bit */ -#define DDV_READ_AHEAD 64 - -static int have_ddv_board = 1; -static unsigned num_options = 0; -static unsigned this_option = 0; - -extern int ddv_get_mlist(unsigned mptr[],int bnum); -extern int ddv_set_request(struct request *req, - int request_type,int bnum,int mlist,int len,int offset); -extern void ddv_load_kernel(char *opcodep); -extern int ddv_restart_cpu(void); -extern int ddv_mlist_available(void); -static int ddv_revalidate(kdev_t dev, struct gendisk *gdev); -static void ddv_geninit(void); -static void ddv_release(struct inode * inode, struct file * filp); -static void ddv_request1(void); - - -static char *ddv_opcodep = NULL; -static struct request *next_request = NULL; - -static DECLARE_WAIT_QUEUE_HEAD(busy_wait); - -static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */ -int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */ -int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */ - -/* these are used by the ddv_daemon, which services remote disk requests */ -static struct remote_request *rem_queue = NULL; -static struct remote_request *rem_queue_end; -static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait); - -static int opiu_kernel_loaded = 0; - -static struct { - unsigned reads, writes, blocks, rq_started, rq_finished, errors; - unsigned sectors_read, sectors_written; -} ddv_stats; - -static struct hd_struct partition_tables[NUM_DDVDEVS]; - -static struct gendisk ddv_gendisk = { - MAJOR_NR, /* Major number */ - DEVICE_NAME, /* Major name */ - PARTN_BITS, /* Bits to shift to get real from partition */ - 1 << PARTN_BITS, /* Number of partitions per real */ - partition_tables,/* hd struct */ - ddv_blk_length, /* block sizes */ - 1, /* number */ - (void *) NULL, /* internal */ - NULL /* next */ -}; - -struct ddv_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; - -static struct ddv_geometry ddv_geometry; - - -struct remote_request { - union { - struct remote_request *next; - void (*fn)(void); - } u; - unsigned bnum; /* how many blocks does this contain */ - struct request *reqp; /* pointer to the request on the original cell */ - unsigned cell; /* what cell is the request from */ - struct request req; /* details of the request */ -}; - - -static void ddv_set_optadr(void) -{ - unsigned addr = 0x11000000; - OPT_IO(OBASE) = addr; - MSC_IO(MSC_OPTADR) = - ((addr & 0xff000000)>>16) | - ((OPTION_BASE & 0xf0000000)>>24) | - ((OPTION_BASE + 0x10000000)>>28); - OPT_IO(PRST) = 0; -} - -extern struct RequestTable *RTable; -extern struct OPrintBufArray *PrintBufs; -extern struct OAlignBufArray *AlignBufs; -extern struct DiskInfo *DiskInfo; - -static void ddv_release(struct inode * inode, struct file * filp) -{ -#if DEBUG - printk("ddv_release started\n"); -#endif -#if DEBUG - printk("ddv_release done\n"); -#endif -} - - -static unsigned in_request = 0; -static unsigned req_queued = 0; - -static void ddv_end_request(int uptodate,struct request *req) -{ - struct buffer_head * bh; - - ddv_stats.rq_finished++; - -/* printk("ddv_end_request(%d,%p)\n",uptodate,req); */ - - req->errors = 0; - if (!uptodate) { - printk("end_request: I/O error, dev %s, sector %lu\n", - kdevname(req->rq_dev), req->sector); - req->nr_sectors--; - req->nr_sectors &= ~SECTOR_MASK; - req->sector += (BLOCK_SIZE / SECTOR_SIZE); - req->sector &= ~SECTOR_MASK; - ddv_stats.errors++; - } - - if ((bh = req->bh) != NULL) { - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); - if ((bh = req->bh) != NULL) { - req->current_nr_sectors = bh->b_size >> 9; - if (req->nr_sectors < req->current_nr_sectors) { - req->nr_sectors = req->current_nr_sectors; - printk("end_request: buffer-list destroyed\n"); - } - req->buffer = bh->b_data; - printk("WARNING: ddv: more sectors!\n"); - ddv_stats.errors++; - return; - } - } - if (req->sem != NULL) - up(req->sem); - req->rq_status = RQ_INACTIVE; - wake_up(&wait_for_request); -} - - -/* check that a request is all OK to process */ -static int request_ok(struct request *req) -{ - int minor; - if (!req) return 0; - - if (MAJOR(req->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": bad major number\n"); - if (!buffer_locked(req->bh)) - panic(DEVICE_NAME ": block not locked"); - - minor = MINOR(req->rq_dev); - if (minor >= NUM_DDVDEVS) { - printk("ddv_request: Invalid minor (%d)\n", minor); - return 0; - } - - if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) { - printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n", - minor,(int)req->sector,(int)req->current_nr_sectors, - ddv_sect_length[minor]); - return 0; - } - - if (req->cmd != READ && req->cmd != WRITE) { - printk("unknown request type %d\n",req->cmd); - return 0; - } - - /* it seems to be OK */ - return 1; -} - - -static void complete_request(struct request *req,int bnum) -{ - while (bnum--) { - ddv_end_request(1,req); - req = req->next; - } -} - - -static int completion_pointer = 0; - -static void check_completion(void) -{ - int i,bnum; - struct request *req; - - if (!RTable) return; - - for (; - (i=completion_pointer) != RTable->ddv_pointer && - RTable->async_info[i].status == DDV_REQ_FREE; - completion_pointer = INC_T(completion_pointer)) - { - req = (struct request *)RTable->async_info[i].argv[7]; - bnum = RTable->async_info[i].bnum; - if (!req || !bnum) { - printk("%s(%d)\n",__FILE__,__LINE__); - ddv_stats.errors++; - continue; - } - - RTable->async_info[i].status = 0; - RTable->async_info[i].argv[7] = 0; - - complete_request(req,bnum); - in_request--; - } -} - - -static struct request *get_request_queue(struct request *oldq) -{ - struct request *req,*req2; - - /* skip any non-active or bad requests */ - skip1: - if (!(req = CURRENT)) - return oldq; - - if (req->rq_status != RQ_ACTIVE) { - CURRENT = req->next; - goto skip1; - } - - if (!request_ok(req)) { - ddv_end_request(0,req); - CURRENT = req->next; - goto skip1; - } - - /* now grab as many as we can */ - req_queued++; - - for (req2 = req; - req2->next && - req2->next->rq_status == RQ_ACTIVE && - request_ok(req2->next); - req2 = req2->next) - req_queued++; - - /* leave CURRENT pointing at the bad ones */ - CURRENT = req2->next; - - /* chop our list at that point */ - req2->next = NULL; - - if (!oldq) - return req; - - for (req2=oldq;req2->next;req2=req2->next) ; - - req2->next = req; - - return oldq; -} - - -static void ddv_rem_complete(struct remote_request *rem) -{ - unsigned flags; - int bnum = rem->bnum; - struct request *req = rem->reqp; - - complete_request(req,bnum); - in_request--; - - save_flags(flags); cli(); - ddv_request1(); - restore_flags(flags); -} - - -/* - * The background ddv daemon. This receives remote disk requests - * and processes them via the normal block operations - */ -static int ddv_daemon(void *unused) -{ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "ddv_daemon"); - spin_lock_irq(¤t->sigmask_lock); - sigfillset(¤t->blocked); /* block all signals */ - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - /* Give it a realtime priority. */ - current->policy = SCHED_FIFO; - current->priority = 32; /* Fixme --- we need to standardise our - namings for POSIX.4 realtime scheduling - priorities. */ - - printk("Started ddv_daemon\n"); - - while (1) { - struct remote_request *rem; - unsigned flags; - struct buffer_head *bhlist[MAX_BNUM*4]; - int i,j,minor,len,shift,offset; - - save_flags(flags); cli(); - - while (!rem_queue) { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&ddv_daemon_wait); - __sti(); cli(); - } - - rem = rem_queue; - rem_queue = rem->u.next; - restore_flags(flags); - - - minor = MINOR(rem->req.rq_dev); - len = rem->req.current_nr_sectors; - offset = rem->req.sector; - - /* work out the conversion to the local block size from - sectors */ - for (shift=0; - (SECTOR_SIZE<req.rq_dev, - offset >> shift, - ddv_blocksizes[minor]); - if (!buffer_uptodate(bhlist[i])) - ll_rw_block(READ,1,&bhlist[i]); - offset += 1<u.fn = ddv_rem_complete; - tnet_rpc(rem->cell,rem,sizeof(int)*3,1); - } -} - - -/* receive a remote disk request */ -static void ddv_rem_queue(char *data,unsigned size) -{ - unsigned flags; - struct remote_request *rem = (struct remote_request *) - kmalloc(size,GFP_ATOMIC); - - if (!rem) { - /* oh bugger! */ - ddv_stats.errors++; - return; - } - - memcpy(rem,data,size); - rem->u.next = NULL; - - save_flags(flags); cli(); - - /* add it to our remote request queue */ - if (!rem_queue) - rem_queue = rem; - else - rem_queue_end->u.next = rem; - rem_queue_end = rem; - - restore_flags(flags); - - wake_up(&ddv_daemon_wait); -} - - -/* which disk should this request go to */ -static inline unsigned pardisk_num(struct request *req) -{ - int minor = MINOR(req->rq_dev); - unsigned stripe; - unsigned cell; - - if (minor < PARDISK_BASE) - return this_option; - - stripe = req->sector >> STRIPE_SHIFT; - cell = stripe % num_options; - - return cell; -} - - -/* check if a 2nd request can be tacked onto the first */ -static inline int contiguous(struct request *req1,struct request *req2) -{ - if (req2->cmd != req1->cmd || - req2->rq_dev != req1->rq_dev || - req2->sector != req1->sector + req1->current_nr_sectors || - req2->current_nr_sectors != req1->current_nr_sectors) - return 0; - if (pardisk_num(req1) != pardisk_num(req2)) - return 0; - return 1; -} - -static void ddv_request1(void) -{ - struct request *req,*req1,*req2; - unsigned offset,len,req_num,mlist,bnum,available=0; - static unsigned mptrs[MAX_BNUM]; - unsigned cell; - - if (in_request > REQUEST_HIGH) - return; - - next_request = get_request_queue(next_request); - - while ((req = next_request)) { - int minor; - - if (in_request >= MAX_REQUEST) - return; - - if (in_request>1 && req_queued MAX_BNUM) - available = MAX_BNUM; - - offset = req->sector; - len = req->current_nr_sectors; - minor = MINOR(req->rq_dev); - - mptrs[0] = (int)req->buffer; - - for (bnum=1,req1=req,req2=req->next; - req2 && bnumnext) { - mptrs[bnum++] = (int)req2->buffer; - } - - next_request = req2; - - - req_queued -= bnum; - ddv_stats.blocks += bnum; - ddv_stats.rq_started += bnum; - - if (req->cmd == READ) { - ddv_stats.reads++; - ddv_stats.sectors_read += len*bnum; - } else { - ddv_stats.writes++; - ddv_stats.sectors_written += len*bnum; - } - - if (minor >= PARDISK_BASE) { - /* translate the request to the normal partition */ - unsigned stripe; - minor -= PARDISK_BASE; - - stripe = offset >> STRIPE_SHIFT; - stripe /= num_options; - offset = (stripe << STRIPE_SHIFT) + - (offset & ((1<u.fn = ddv_rem_queue; - rem->cell = this_option; - rem->bnum = bnum; - rem->req = *req; - rem->reqp = req; - rem->req.rq_dev = MKDEV(MAJOR_NR,minor); - rem->req.sector = offset; - memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum); - - if (tnet_rpc(cell,rem,size,1) != 0) { - kfree_s(rem,size); - return; - } - } else { - /* its a local request */ - if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) { - ddv_stats.errors++; - panic("ddv: mlist corrupted"); - } - - req_num = RTable->cell_pointer; - RTable->async_info[req_num].status = - req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ; - RTable->async_info[req_num].bnum = bnum; - RTable->async_info[req_num].argv[0] = mlist; - RTable->async_info[req_num].argv[1] = len; - RTable->async_info[req_num].argv[2] = offset + - partition_tables[minor].start_sect; - RTable->async_info[req_num].argv[3] = bnum; - RTable->async_info[req_num].argv[7] = (unsigned)req; - RTable->cell_pointer = INC_T(RTable->cell_pointer); - - } - - in_request++; - } -} - - -static void ddv_request(request_queue_t * q) -{ - cli(); - ddv_request1(); - sti(); -} - - -static void check_printbufs(void) -{ - int i; - - if (!PrintBufs) return; - - while (PrintBufs->option_counter != PrintBufs->cell_counter) { - i = PrintBufs->cell_counter; - printk("opiu (%d): ",i); - if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000) - printk("Error: bad format in printk at %p\n", - PrintBufs->bufs[i].fmt); - else - printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE, - PrintBufs->bufs[i].args[0], - PrintBufs->bufs[i].args[1], - PrintBufs->bufs[i].args[2], - PrintBufs->bufs[i].args[3], - PrintBufs->bufs[i].args[4], - PrintBufs->bufs[i].args[5]); - if (++PrintBufs->cell_counter == PRINT_BUFS) - PrintBufs->cell_counter = 0; - } -} - -static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - save_flags(flags); cli(); - OPT_IO(IRC1) = 0x80000000; - - check_printbufs(); - check_completion(); - - ddv_request1(); - restore_flags(flags); -} - -static int ddv_open(struct inode * inode, struct file * filp) -{ - int minor = MINOR(inode->i_rdev); - - if (!have_ddv_board || minor >= NUM_DDVDEVS) - return -ENODEV; - - if (minor >= PARDISK_BASE) { - ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE]; - ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE]; - } - - return 0; -} - - -static void ddv_open_reply(struct cap_request *creq) -{ - int size = creq->size - sizeof(*creq); - ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC); - read_bif(ddv_opcodep, size); -#if DEBUG - printk("received opiu kernel of size %d\n",size); -#endif - if (size == 0) - have_ddv_board = 0; - wake_up(&busy_wait); -} - -extern struct block_device_operations ddv_fops; - -static void ddv_load_opiu(void) -{ - int i; - struct cap_request creq; - - /* if the opiu kernel is already loaded then we don't do anything */ - if (!have_ddv_board || opiu_kernel_loaded) - return; - - bif_register_request(REQ_DDVOPEN,ddv_open_reply); - - /* send the open request to the front end */ - creq.cid = mpp_cid(); - creq.type = REQ_DDVOPEN; - creq.header = 0; - creq.size = sizeof(creq); - - bif_queue(&creq,0,0); - - ddv_set_optadr(); - - while (!ddv_opcodep) - sleep_on(&busy_wait); - - if (!have_ddv_board) - return; - - ddv_load_kernel(ddv_opcodep); - - kfree(ddv_opcodep); - ddv_opcodep = NULL; - - if (ddv_restart_cpu()) - return; - - ddv_sect_length[0] = DiskInfo->blocks; - ddv_blk_length[0] = DiskInfo->blocks >> 1; - ddv_blocksizes[0] = BLOCK_SIZE; - - ddv_geometry.cylinders = ddv_sect_length[0] / - (ddv_geometry.heads*ddv_geometry.sectors); - - register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<> 1; - } - - /* setup the parallel partitions by multiplying the normal - partition by the number of options */ - for (;imax_p; - start = target << gdev->minor_shift; - - printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n", - dev,target,max_p,start); - - for (i=max_p - 1; i >=0 ; i--) { - int minor = start + i; - kdev_t devi = MKDEV(gdev->major, minor); - sync_dev(devi); - invalidate_inodes(devi); - invalidate_buffers(devi); - gdev->part[minor].start_sect = 0; - gdev->part[minor].nr_sects = 0; - }; - - ddv_sect_length[start] = DiskInfo->blocks; - ddv_blk_length[start] = DiskInfo->blocks >> 1; - - grok_partitions(gdev, target, 1<part[start+i].nr_sects; - ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1; - if (gdev->part[start+i].nr_sects) - printk("partition[%d] start=%d length=%d\n",i, - (int)gdev->part[start+i].start_sect, - (int)gdev->part[start+i].nr_sects); - } - - return 0; -} - - - - -static int ddv_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err; - struct ddv_geometry *loc = (struct ddv_geometry *) arg; - int dev; - int minor = MINOR(inode->i_rdev); - - if ((!inode) || !(inode->i_rdev)) - return -EINVAL; - dev = DEVICE_NR(inode->i_rdev); -#if DEBUG - printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor); -#endif - switch (cmd) { - case HDIO_GETGEO: - printk("\tHDIO_GETGEO\n"); - if (!loc) return -EINVAL; - if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT; - if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT; - if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT; - if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT; - return 0; - - case HDIO_GET_MULTCOUNT : - printk("\tHDIO_GET_MULTCOUNT\n"); - return -EINVAL; - - case HDIO_GET_IDENTITY : - printk("\tHDIO_GET_IDENTITY\n"); - return -EINVAL; - - case HDIO_GET_NOWERR : - printk("\tHDIO_GET_NOWERR\n"); - return -EINVAL; - - case HDIO_SET_NOWERR : - printk("\tHDIO_SET_NOWERR\n"); - return -EINVAL; - - case BLKRRPART: - printk("\tBLKRRPART\n"); - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return ddv_revalidate(inode->i_rdev,&ddv_gendisk); - - case BLKGETSIZE: /* Return device size */ - if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT; -#if DEBUG - printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]); -#endif - return 0; - - default: - printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd); - return -EINVAL; - }; -} - -static struct block_device_operations ddv_fops = { - open: ddv_open, - release: ddv_release, - ioctl: ddv_ioctl, -}; - - -static void ddv_status(void) -{ - if (!have_ddv_board) { - printk("no ddv board\n"); - return; - } - - printk(" -in_request %u req_queued %u -MTable: start=%u end=%u -Requests: started=%u finished=%u -Requests: completion_pointer=%u ddv_pointer=%u cell_pointer=%u -PrintBufs: option_counter=%u cell_counter=%u -ddv_stats: reads=%u writes=%u blocks=%u -ddv_stats: sectors_read=%u sectors_written=%u -CURRENT=%p next_request=%p errors=%u -", - in_request,req_queued, - RTable->start_mtable,RTable->end_mtable, - ddv_stats.rq_started,ddv_stats.rq_finished, - completion_pointer,RTable->ddv_pointer,RTable->cell_pointer, - PrintBufs->option_counter,PrintBufs->cell_counter, - ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks, - ddv_stats.sectors_read,ddv_stats.sectors_written, - CURRENT,next_request, - ddv_stats.errors); -} - - -int ddv_init(void) -{ - int cid; - - cid = mpp_cid(); - - if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) { - printk("ap: unable to get major %d for ap block dev\n", - MAJOR_NR); - return -1; - } - - printk("ddv_init: register dev %d\n", MAJOR_NR); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); - read_ahead[MAJOR_NR] = DDV_READ_AHEAD; - - bif_add_debug_key('d',ddv_status,"DDV status"); - ddv_gendisk.next = gendisk_head; - gendisk_head = &ddv_gendisk; - - num_options = mpp_num_cells(); - this_option = mpp_cid(); - - kernel_thread(ddv_daemon, NULL, 0); - - ddv_geninit(); - - return(0); -} - - -static void ddv_geninit(void) -{ - int i; - static int done = 0; - - if (done) - printk("ddv_geninit already done!\n"); - - done = 1; - - printk("ddv_geninit\n"); - - /* request interrupt line 2 */ - if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) { - printk("Failed to install ddv interrupt handler\n"); - } - - for (i=0;inext)) - if (*gdp == &ddv_gendisk) - break; - if (*gdp) - *gdp = (*gdp)->next; - free_irq(APOPT0_IRQ, NULL); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); -} - -#endif /* MODULE */ - - diff -ur --new-file old/linux/drivers/ap1000/ddv_util.c new/linux/drivers/ap1000/ddv_util.c --- old/linux/drivers/ap1000/ddv_util.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/ap1000/ddv_util.c Thu Jan 1 01:00:00 1970 @@ -1,116 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -#define __NO_VERSION__ -#include -#include -#include -#include -#include -#include - - -#define GENDISK_STRUCT ddv_gendisk - -struct RequestTable *RTable=NULL; -struct OPrintBufArray *PrintBufs=NULL; -struct OAlignBufArray *AlignBufs=NULL; -struct DiskInfo *DiskInfo=NULL; - -extern int ddv_length[]; - -int ddv_mlist_available(void) -{ - int start = RTable->start_mtable; - int end = RTable->end_mtable; - - if (start >= end) - return (MTABLE_SIZE - start); - return (end+1) - start; -} - - -int ddv_get_mlist(unsigned mptr[],int bnum) -{ - int available = ddv_mlist_available(); - int i; - int start = RTable->start_mtable; - - if (available < bnum) { - return -1; - } - - for (i = 0; i < bnum; i++) { - unsigned phys = (unsigned)mmu_v2p((unsigned)mptr[i]); - if (phys == -1) - panic("bad address %x in ddv_get_mlist\n",mptr[i]); - RTable->mtable[RTable->start_mtable] = phys; - RTable->start_mtable = INC_ML(RTable->start_mtable); - } - - return start; -} - - - -void ddv_load_kernel(char *opcodep) -{ - int tsize; - char *p; - struct exec *mhead; - - mhead = (struct exec *)opcodep; - p = opcodep + sizeof(*mhead); - - tsize = (mhead->a_text + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); - memcpy((char *)OPIBUS_BASE+mhead->a_entry,p,mhead->a_text); - memcpy((char *)OPIBUS_BASE+mhead->a_entry+tsize, - p+mhead->a_text,mhead->a_data); - memset((char *)OPIBUS_BASE+mhead->a_entry+tsize+mhead->a_data,0, - mhead->a_bss+PAGE_SIZE); - -#ifdef DDV_DEBUG - printk("CELL(%d) loaded opiu kernel of size %ld %ld %ld (%ld)\n", - ap_getcid(), - mhead->a_text,mhead->a_data,mhead->a_bss,mhead->a_entry); -#endif -} - - -int ddv_restart_cpu(void) -{ - unsigned long timeout; - - OPT_IO(OPIU_OP) = OPIU_RESET; - OPT_IO(PRST) = PRST_IRST; - if (OPT_IO(PRST) != PRST_IRST) { - printk("_iu_load reset release error.\n"); - return(-1); - } - for (timeout=jiffies + 10; - time_before(jiffies, timeout) || (OPT_IO(PBUF0) == 0); - ) /* wait */ ; - if (OPT_IO(PBUF0) == 0) { - printk("WARNING: option kernel didn't startup\n"); - return(-1); - } else { - printk("option kernel IU running\n"); - DiskInfo = (struct DiskInfo *)(OPT_IO(PBUF0) + OPIBUS_BASE); - RTable = (struct RequestTable *)(DiskInfo->ptrs[0]+OPIBUS_BASE); - PrintBufs = (struct OPrintBufArray *)(DiskInfo->ptrs[1]+OPIBUS_BASE); - AlignBufs = (struct OAlignBufArray *)(DiskInfo->ptrs[2]+OPIBUS_BASE); - - printk("Disk capacity: %d blocks of size %d\n", - (int)DiskInfo->blocks,(int)DiskInfo->blk_size); - - OPT_IO(PBUF0) = 0; - } - return(0); -} - - - diff -ur --new-file old/linux/drivers/ap1000/mac.c new/linux/drivers/ap1000/mac.c --- old/linux/drivers/ap1000/mac.c Tue Feb 10 22:07:50 1998 +++ new/linux/drivers/ap1000/mac.c Thu Jan 1 01:00:00 1970 @@ -1,1177 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Routines for controlling the FORMAC+ - */ -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include -#include -#include -#include - -#include -#include -#include - -#include "apfddi.h" -#include "smt-types.h" -#include "am79c830.h" -#include "mac.h" -#include "plc.h" -#include "apfddi-reg.h" - -#define MAC_DEBUG 0 - -/* Values for dma_state */ -#define IDLE 0 -#define XMITTING 1 -#define RECVING 2 - -/* - * Messages greater than this value are transferred to the FDDI send buffer - * using DMA. - */ -#define DMA_XMIT_THRESHOLD 64 -#define DMA_RECV_THRESHOLD 64 - -/* - * If the FDDI receive buffer is occupied by less than this value, then - * sending has priority. - */ -#define RECV_THRESHOLD (20*1024) - -#define DMA_RESET_MASKS ((AP_CLR_INTR_MASK<cmdreg1 = C1_SOFTWARE_RESET; - mac->said = (mip->s_address[0] << 8) + mip->s_address[1]; - mac->laim = (mip->l_address[0] << 8) + mip->l_address[1]; - mac->laic = (mip->l_address[2] << 8) + mip->l_address[3]; - mac->lail = (mip->l_address[4] << 8) + mip->l_address[5]; - mac->sagp = (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1]; - mac->lagm = (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1]; - mac->lagc = (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3]; - mac->lagl = (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5]; - mac->tmax = mip->tmax >> 5; - mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */ - mac->treq0 = mip->treq; - mac->treq1 = mip->treq >> 16; - mac->pri0 = ~0; - mac->pri1 = ~0; - mac->pri2 = ~0; - mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY - + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ - + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES; - mac->eacb = RECV_BUF_START - 1; - mac->earv = XMIT_BUF_START - 1; - mac->eas = mac->earv; - mac->eaa0 = BUFFER_SIZE - 1; - mac->eaa1 = mac->eaa0; - mac->eaa2 = mac->eaa1; - mac->wpxsf = 0; - mac->rpr = RECV_BUF_START; - mac->wpr = RECV_BUF_START + 1; - mac->swpr = RECV_BUF_START; - mac->wpxs = mac->eas; - mac->swpxs = mac->eas; - mac->rpxs = mac->eas; - mac->wpxa0 = XMIT_BUF_START; - mac->rpxa0 = XMIT_BUF_START; - - memset(msp, 0, sizeof(*msp)); - msp->recv_ptr = RECV_BUF_START; - msp->recv_empty = 1; - msp->xmit_ptr = XMIT_BUF_START; - msp->xmit_free = XMIT_BUF_START + 1; - msp->xmit_start = XMIT_BUF_START; - msp->xmit_chains = 0; - msp->frames_xmitted = 0; - msp->frames_recvd = 0; - msp->recv_aborted = 0; - - mac->mdreg1 = M1_MODE_MEMORY; - - mac_make_spframes(); - - return 0; -} - -int -mac_inited(struct mac_info *mip) -{ - struct formac_state *msp = &this_mac_state; - mac_status_t st1, st2; - - if (mac->said != (mip->s_address[0] << 8) + mip->s_address[1] - || mac->laim != (mip->l_address[0] << 8) + mip->l_address[1] - || mac->laic != (mip->l_address[2] << 8) + mip->l_address[3] - || mac->lail != (mip->l_address[4] << 8) + mip->l_address[5] - || mac->sagp != (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1] - || mac->lagm != (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1] - || mac->lagc != (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3] - || mac->lagl != (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5]) - return 1; - if ((mac->mdreg1 & ~M1_ADDET) != (M1_MODE_ONLINE | M1_SELECT_RA - | M1_FULL_DUPLEX)) - return 3; - if (mac->treq0 != (mip->treq & 0xffff) - || mac->treq1 != ((unsigned)mip->treq >> 16)) - return 4; - - st1 = (mac->st1u << 16) + mac->st1l; - st2 = (mac->st2u << 16) + mac->st2l; - if ((st2 & S2_RING_OP) == 0) - return 5; - - /* It's probably OK, reset some things to be safe. */ - this_mac_info = mip; - *csr0 &= ~CS0_HREQ; - mac->tmax = mip->tmax >> 5; - mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */ - mac->pri0 = ~0; - mac->pri1 = ~0; - mac->pri2 = ~0; - mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY - + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ - + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES; - - /* clear out the receive queue */ - mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV; - mac->rpr = RECV_BUF_START; - mac->wpr = RECV_BUF_START + 1; - mac->swpr = RECV_BUF_START; - - memset(msp, 0, sizeof(*msp)); - msp->recv_ptr = RECV_BUF_START; - msp->recv_empty = 1; - - /* XXX reset transmit pointers */ - mac->cmdreg2 = C2_ABORT_XMIT; - mac->cmdreg2 = C2_RESET_XMITQS; - mac->wpxa0 = XMIT_BUF_START; - mac->rpxa0 = XMIT_BUF_START; - msp->xmit_ptr = XMIT_BUF_START; - msp->xmit_free = XMIT_BUF_START + 1; - msp->xmit_start = XMIT_BUF_START; - msp->xmit_chains = 0; - - mac_make_spframes(); - mac->cmdreg1 = C1_CLR_ALL_LOCKS; - - msp->frames_xmitted = 0; - msp->frames_recvd = 0; - msp->recv_aborted = 0; - msp->ring_op = 1; - - mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_NSA; - mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16; - mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0); - mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF - | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS - | S2_NP_SIMULT_LOAD) >> 16; - mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME); - - return 0; -} - -void mac_make_spframes(void) -{ - volatile int *bp; - struct mac_info *mip = this_mac_info; - int sa; - struct formac_state *msp = &this_mac_state; - - /* initialize memory to avoid parity errors */ - *csr0 &= ~CS0_HREQ; - *csr1 &= ~CS1_BUF_WR_TAG; - for (bp = &buffer_mem[BUFFER_SIZE]; bp > &buffer_mem[XMIT_BUF_START];) - *--bp = 0xdeadbeef; - for (; bp > buffer_mem;) - *--bp = 0xfeedf00d; - buffer_mem[msp->recv_ptr] = 0; - - bp = buffer_mem; - *bp++ = 0; /* auto-void frame pointer (not used) */ - - /* make claim frame */ - sa = bp - buffer_mem; - *bp++ = 0xd8000011; /* claim frame descr. + length */ - *bp++ = 0xc3; /* FC value for claim frame, long addr */ - *bp++ = (mip->l_address[0] << 24) + (mip->l_address[1] << 16) - + (mip->l_address[2] << 8) + mip->l_address[3]; - *bp++ = (mip->l_address[4] << 24) + (mip->l_address[5] << 16) - + (mip->l_address[0] << 8) + mip->l_address[1]; - *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16) - + (mip->l_address[4] << 8) + mip->l_address[5]; - *bp++ = mip->treq; - mac->sacl = bp - buffer_mem; /* points to pointer to claim frame */ - *bp++ = 0xa0000000 + sa; /* pointer to start of claim frame */ - - /* make beacon frame */ - sa = bp - buffer_mem; - *bp++ = 0xd8000011; /* beacon frame descr. + length */ - *bp++ = 0xc2; /* FC value for beacon frame, long addr */ - *bp++ = 0; /* DA = 0 */ - *bp++ = (mip->l_address[0] << 8) + mip->l_address[1]; - *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16) - + (mip->l_address[4] << 8) + mip->l_address[5]; - *bp++ = 0; /* beacon reason = failed claim */ - mac->sabc = bp - buffer_mem; - *bp++ = 0xa0000000 + sa; /* pointer to start of beacon frame */ -} - -void mac_reset(LoopbackType loopback) -{ - int mode; - struct formac_state *msp = &this_mac_state; - - msp->loopback = loopback; - switch (loopback) { - case loop_none: - mode = M1_MODE_ONLINE; - break; - case loop_formac: - mode = M1_MODE_INT_LOOP; - break; - default: - mode = M1_MODE_EXT_LOOP; - break; - } - mac->mdreg1 = mode | M1_ADDET_NSA | M1_SELECT_RA | M1_FULL_DUPLEX; - mac->cmdreg1 = C1_IDLE_LISTEN; - mac->cmdreg1 = C1_CLR_ALL_LOCKS; - mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16; - mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0); - mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF - | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS - | S2_NP_SIMULT_LOAD) >> 16; - mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME); -} - -void mac_claim(void) -{ - mac->cmdreg1 = C1_CLAIM_LISTEN; -} - -void mac_disable(void) -{ - mac->mdreg1 = M1_MODE_MEMORY; - mac->imsk1u = ~0; - mac->imsk1l = ~0; - mac->imsk2u = ~0; - mac->imsk2l = ~0; - mac->wpr = mac->swpr + 1; - if (mac->wpr > mac->earv) - mac->wpr = mac->eacb + 1; - buffer_mem[mac->swpr] = 0; -} - -void mac_stats(void) -{ - struct formac_state *msp = &this_mac_state; - - if (msp->recv_ovf) - printk("%d receive buffer overflows\n", msp->recv_ovf); - if (msp->wrong_bb) - printk("%d frames on wrong byte bdry\n", msp->wrong_bb); - printk("%d frames transmitted, %d aborted\n", msp->frames_xmitted, - msp->xmit_aborted); - printk("%d frames received, %d aborted\n", msp->frames_recvd, - msp->recv_aborted); - printk("%d frames received with errors\n", msp->recv_error); -} - -void mac_sleep(void) -{ - /* disable the receiver */ - mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV; -} - -void mac_poll(void) -{ - mac_status_t st1, st2; - struct formac_state *msp = &this_mac_state; - int up, f, d, l, r, e, i; - - st1 = (mac->st1u << 16) + mac->st1l; - st2 = (mac->st2u << 16) + mac->st2l; - - if (st2 & S2_NP_SIMULT_LOAD) - panic("NP/formac simultaneous load!!!"); - - up = (st2 & S2_RING_OP) != 0; - if (up != msp->ring_op) { - /* ring has come up or down */ - msp->ring_op = up; - printk("mac: ring %s\n", up? "up": "down"); - set_ring_op(up); - } - - if (up) { - if (st1 & S1_XMIT_ABORT) { - ++msp->xmit_aborted; - if (st1 & S1_QUEUE_LOCK_ASYNC0) { - printk("mac: xmit queue locked, resetting xmit buffer\n"); - mac->cmdreg2 = C2_RESET_XMITQS; /* XXX bit gross */ - mac->rpxa0 = XMIT_BUF_START; - buffer_mem[XMIT_BUF_START] = 0; - msp->xmit_ptr = XMIT_BUF_START; - msp->xmit_start = XMIT_BUF_START; - msp->xmit_chains = 0; - mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK; - st1 &= ~(S1_END_CHAIN_ASYNC0 | S1_END_FRAME_ASYNC0 - | S1_XINSTR_FULL_ASYNC0); - } else - st1 |= S1_END_FRAME_ASYNC0; - } else if (st1 & S1_QUEUE_LOCK_ASYNC0) { - printk("mac: xmit queue locked, why?\n"); - mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK; - } - - if (st1 & S1_END_FRAME_ASYNC0) { - /* advance xmit_start */ - e = msp->xmit_start; - while (e != msp->xmit_ptr) { - /* find the end of the current frame */ - f = buffer_mem[e]; /* read pointer */ - if (f == 0) - break; /* huh?? */ - f &= 0xffff; - d = buffer_mem[f]; /* read descriptor */ - l = ((d & 0xffff) + ((d >> TD_BYTE_BDRY_LG) & 3) + 3) >> 2; - e = f + 1 + l; /* index of ptr at end of frame */ - r = mac->rpxa0; - if ((r <= msp->xmit_ptr && r < e && e <= msp->xmit_ptr) - || (r > msp->xmit_ptr && (r < e || e <= msp->xmit_ptr))) - break; /* up to current frame */ - /* printk("frame @ %x done\n", msp->xmit_start); */ - msp->xmit_start = e; - if ((st1 & S1_XMIT_ABORT) == 0) - ++msp->frames_xmitted; - if ((msp->xmit_chains == 1 && e == msp->xmit_ptr) || - (msp->xmit_chains > 1 && e == msp->xmit_chain_start[1])) { - /* we've finished chain 0 */ - --msp->xmit_chains; - for (i = 0; i < msp->xmit_chains; ++i) - msp->xmit_chain_start[i] = msp->xmit_chain_start[i+1]; - if (msp->xmit_chains >= 2) { - mac->cmdreg2 = C2_XMIT_ASYNCQ0; - /* printk("mac_poll: xmit chain\n"); */ - } - if (msp->xmit_chains == 0) - *csr0 &= ~CS0_LED1; - } - } - /* - * Now that we have a bit more space in the transmit buffer, - * see if we want to put another frame in. - */ -#if MAC_DEBUG - printk("Removed space in transmit buffer.\n"); -#endif - mac_process(); - } - } - - if (st2 & S2_RMT_EVENTS) { - rmt_event(st2); - } - - if (st2 & S2_RECV_COMPLETE) { - /* - * A frame has just finished arriving in the receive buffer. - */ - *csr0 |= CS0_LED2; - msp->recv_empty = 0; -#if MAC_DEBUG - printk("Frame has just trickled in...\n"); -#endif - mac_process(); - } - - if (st2 & S2_RECV_BUF_FULL) { - /* - * receive buffer overflow: reset and unlock the receive buffer. - */ -/* printk("mac: receive buffer full\n"); */ - mac->rpr = RECV_BUF_START; - mac->wpr = RECV_BUF_START + 1; - mac->swpr = RECV_BUF_START; - msp->recv_ptr = RECV_BUF_START; - msp->recv_empty = 1; - buffer_mem[RECV_BUF_START] = 0; - mac->cmdreg1 = C1_CLR_RECVQ_LOCK; - ++msp->recv_ovf; - -#if 0 - } else if (st2 & S2_RECV_FIFO_OVF) { - printk("mac: receive FIFO overflow\n"); - /* any further action required here? */ - - } else if (st2 & S2_MISSED_FRAME) { - printk("mac: missed frame\n"); -#endif - } - - if (st2 & S2_ERR_SPECIAL_FR) { - printk("mac: bug: error in special frame\n"); - mac_disable(); - } -} - -void -mac_xmit_alloc(sp, bb) - struct mac_buf *sp; - int bb; -{ - int nwords; - - nwords = (sp->length + bb + 3) >> 2; - sp->fr_start = mac_xalloc(nwords + 2); - sp->fr_end = sp->fr_start + nwords + 1; - sp->ptr = (char *) &buffer_mem[sp->fr_start + 1] + bb; - buffer_mem[sp->fr_start] = TD_MAGIC + (bb << TD_BYTE_BDRY_LG) + sp->length; -} - -void -mac_queue_frame(sp) - struct mac_buf *sp; -{ - struct formac_state *msp = &this_mac_state; - - buffer_mem[sp->fr_end] = 0; /* null pointer at end of frame */ - buffer_mem[msp->xmit_ptr] = PT_MAGIC + sp->fr_start; - if (msp->xmit_chains <= 2) { - msp->xmit_chain_start[msp->xmit_chains] = msp->xmit_ptr; - if (msp->xmit_chains < 2) - mac->cmdreg2 = C2_XMIT_ASYNCQ0; - ++msp->xmit_chains; - } else { - buffer_mem[msp->xmit_more_ptr] |= TD_MORE; - } - msp->xmit_ptr = sp->fr_end; - msp->xmit_more_ptr = sp->fr_start; - *csr0 |= CS0_LED1; -} - -int -mac_xalloc(int nwords) -{ - int fr_start; - struct formac_state *msp = &this_mac_state; - - /* - * Find some room in the transmit buffer. - */ - fr_start = msp->xmit_free; - if (fr_start > msp->xmit_start) { - if (fr_start + nwords > XMIT_BUF_END) { - /* no space at end - see if we can start again from the front */ - fr_start = XMIT_BUF_START; - if (fr_start + nwords > msp->xmit_start) - panic("no space in xmit buffer (1)"); - } - } else { - if (fr_start + nwords > msp->xmit_start) - panic("no space in xmit buffer (2)"); - } - - msp->xmit_free = fr_start + nwords; - - return fr_start; -} - -int -mac_recv_frame(sp) - struct mac_buf *sp; -{ - struct formac_state *msp = &this_mac_state; - int status, bb, orig_recv_ptr; - - orig_recv_ptr = msp->recv_ptr; - for (;;) { - status = buffer_mem[msp->recv_ptr]; - if ((status & RS_VALID) == 0) { - if (status != 0) { - printk("recv buf out of sync: recv_ptr=%x status=%x\n", - msp->recv_ptr, status); - printk(" rpr=%x swpr=%x, buf[rpr]=%x\n", mac->rpr, mac->swpr, - buffer_mem[mac->rpr]); - msp->recv_ptr = mac->swpr; - } - *csr0 &= ~CS0_LED2; - msp->recv_empty = 1; - if (mac->rpr == orig_recv_ptr) - mac->rpr = msp->recv_ptr; - return 0; - } - if (status & RS_ABORTED) - ++msp->recv_aborted; - else { - bb = (status >> RS_BYTE_BDRY_LG) & 3; - if (bb != 3) { - ++msp->wrong_bb; - bb = 3; - } - if ((status & RS_ERROR) == 0) - break; - ++msp->recv_error; - msp->recv_ptr += NWORDS((status & RS_LENGTH) + bb); - } - if (++msp->recv_ptr >= RECV_BUF_END) - msp->recv_ptr -= RECV_BUF_SIZE; - } - ++msp->frames_recvd; - if (mac->rpr == orig_recv_ptr) - mac->rpr = msp->recv_ptr; - - sp->fr_start = msp->recv_ptr; - sp->length = (status & RS_LENGTH) + bb; /* + 4 (status) - 4 (FCS) */ - sp->ptr = (void *) &buffer_mem[sp->fr_start]; - if ((msp->recv_ptr += NWORDS(sp->length) + 1) >= RECV_BUF_END) - msp->recv_ptr -= RECV_BUF_SIZE; - sp->fr_end = msp->recv_ptr; - sp->wraplen = (RECV_BUF_END - sp->fr_start) * 4; - sp->wrapptr = (void *) &buffer_mem[RECV_BUF_START]; - - return 1; -} - -void -mac_discard_frame(sp) - struct mac_buf *sp; -{ - mac->rpr = sp->fr_end; -} - -/* - * Return the number of bytes free in the async 0 transmit queue. - */ -int -mac_xmit_space(void) -{ - struct formac_state *msp = &this_mac_state; - int nw; - - if (msp->xmit_free > msp->xmit_start) { - nw = XMIT_BUF_END - msp->xmit_free; - if (nw < msp->xmit_start - XMIT_BUF_START) - nw = msp->xmit_start - XMIT_BUF_START; - } else - nw = msp->xmit_start - msp->xmit_free; - return nw <= 2? 0: (nw - 2) << 2; -} - -/* - * Return the number of bytes of frames available in the receive queue. - */ -int -mac_recv_level(void) -{ - int nw; - - nw = mac->swpr - mac->rpr; - if (nw < 0) - nw += mac->earv - mac->eacb; - return nw << 2; -} - -/* - * Return 1 iff all transmission has been completed, 0 otherwise. - */ -int mac_xmit_done(void) -{ - struct formac_state *msp = &this_mac_state; - - return msp->xmit_chains == 0; -} - -/* - * Append skbuff packet to queue. - */ -int mac_queue_append (struct sk_buff *skb) -{ - struct mac_queue *el; - unsigned flags; - save_flags(flags); cli(); - -#if MAC_DEBUG - printk("Appending queue element skb 0x%x\n", skb); -#endif - - if ((el = (struct mac_queue *)kmalloc(sizeof(*el), GFP_ATOMIC)) == NULL) { - restore_flags(flags); - return 1; - } - el->next = NULL; - el->skb = skb; - - if (mac_queue_top == NULL) { - mac_queue_top = mac_queue_bottom = el; - } - else { - mac_queue_bottom->next = el; - mac_queue_bottom = el; - } - restore_flags(flags); - return 0; -} - -/* - * If the packet originated from the same FDDI subnet as we are on, - * there is no need to perform checksumming as FDDI will does this - * us. - */ -#define CHECK_IF_CHECKSUM_REQUIRED(skb) \ - if ((skb)->protocol == ETH_P_IP) { \ - extern struct cap_init cap_init; \ - int *from_ip = (int *)((skb)->data+12); \ - int *to_ip = (int *)((skb)->data+16); \ - if ((*from_ip & cap_init.netmask) == (*to_ip & cap_init.netmask)) \ - (skb)->ip_summed = CHECKSUM_UNNECESSARY; \ - } - -/* - * Try to send and/or recv frames. - */ -void mac_process(void) -{ - volatile struct dma_chan *dma = (volatile struct dma_chan *) DMA3; - struct formac_state *msp = &this_mac_state; - struct mac_queue *el; - int nw=0, mrl = 0, fstart, send_buffer_full = 0; - unsigned flags; - - save_flags(flags); cli(); - -#if MAC_DEBUG - printk("In mac_process()\n"); -#endif - - /* - * Check if the DMA is being used. - */ - if (msp->dma_state != IDLE) { - restore_flags(flags); - return; - } - - while (mac_queue_top != NULL || /* Something to transmit */ - (mrl = mac_recv_level()) > 0) { /* Frames in receive buffer */ - send_buffer_full = 0; -#if MAC_DEBUG - printk("mac_process(): something to do... mqt %x mrl is %d\n", - mac_queue_top, mrl); -#endif - if (mac_queue_top != NULL && mrl < RECV_THRESHOLD) { - el = (struct mac_queue *)mac_queue_top; - - /* - * Check there is enough space in the FDDI send buffer. - */ - if (mac_xmit_space() < el->skb->len) { -#if MAC_DEBUG - printk("process_queue(): FDDI send buffer is full\n"); -#endif - send_buffer_full = 1; - } - else { -#if MAC_DEBUG - printk("mac_process(): sending a frame\n"); -#endif - /* - * Update mac_queue_top. - */ - mac_queue_top = mac_queue_top->next; - - /* - * Allocate space in the FDDI send buffer. - */ - msp->cur_mbuf.length = el->skb->len-3; - mac_xmit_alloc((struct mac_buf *)&msp->cur_mbuf, 3); - - /* - * If message size is greater than DMA_XMIT_THRESHOLD, send - * using DMA, otherwise use memcpy(). - */ - if (el->skb->len > DMA_XMIT_THRESHOLD) { - /* - * Start the DMA. - */ -#if MAC_DEBUG - printk("mac_process(): Starting send DMA...\n"); -#endif - nw = msp->cur_mbuf.fr_end - msp->cur_mbuf.fr_start + 1; - mac->wpxa0 = msp->cur_mbuf.fr_start + 1; - - *csr0 |= CS0_HREQ_WA0; - - msp->cur_macq = el; - msp->dma_state = XMITTING; - dma->st = DMA_DMST_RST; - dma->st = DMA_RESET_MASKS; - dma->hskip = 1; /* skip = 0, count = 1 */ - dma->vskip = 1; /* skip = 0, count = 1 */ - dma->maddr = (u_char *) - mmu_v2p((unsigned long)el->skb->data); - dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + - DMA_DCMD_TD_MD + nw; - *csr0 &= ~CS0_DMA_RECV; - *csr0 |= CS0_DMA_ENABLE; - - /* - * Don't process any more packets since the DMA is - * being used. - */ - break; - } - else { /* el->skb->len <= DMA_XMIT_THRESHOLD */ - /* - * Copy the data directly into the FDDI buffer. - */ -#if MAC_DEBUG - printk("mac_proces(): Copying send data...\n"); -#endif - memcpy(msp->cur_mbuf.ptr - 3, el->skb->data, - ROUND4(el->skb->len)); - mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); - dev_kfree_skb(el->skb); - kfree_s(el, sizeof(*el)); - continue; - } - } - - /* - * We have reached here if there is not enough space in the - * send buffer. Try to receive some packets instead. - */ - } - - if (mac_recv_frame((struct mac_buf *)&msp->cur_mbuf)) { - volatile int fc, llc_header_word2; - int pkt_len = 0; - -#if MAC_DEBUG - printk("mac_process(): Receiving frames...\n"); -#endif - /* - * Get the fc, note only word accesses are allowed from the - * FDDI buffers. - */ - if (msp->cur_mbuf.wraplen > 4) { - fc = *(int *)(msp->cur_mbuf.ptr+4); - } - else { - /* - * fc_word must be at the start of the FDDI buffer. - */ -#if MAC_DEBUG - printk("Grabbed fc_word from wrapptr, wraplen %d\n", - msp->cur_mbuf.wraplen); -#endif - fc = *(int *)msp->cur_mbuf.wrapptr; - } - fc &= 0xff; - -#if MAC_DEBUG - printk("fc is 0x%x\n", fc); -#endif - if (fc < 0x50 || fc > 0x57) { - mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); - continue; - } - - /* - * Determine the size of the packet data and allocate a socket - * buffer. - */ - pkt_len = msp->cur_mbuf.length - FDDI_HARDHDR_LEN; -#if MAC_DEBUG - printk("Packet of length %d\n", pkt_len); -#endif - msp->cur_skb = dev_alloc_skb(ROUND4(pkt_len)); - - if (msp->cur_skb == NULL) { - printk("mac_process(): Memory squeeze, dropping packet.\n"); - apfddi_stats->rx_dropped++; - restore_flags(flags); - return; - } - msp->cur_skb->dev = apfddi_device; - - /* - * Hardware header isn't copied to skbuff. - */ - msp->cur_skb->mac.raw = msp->cur_skb->data; - apfddi_stats->rx_packets++; - - /* - * Determine protocol from llc header. - */ - if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) { - llc_header_word2 = *(int *)(msp->cur_mbuf.wrapptr + - (FDDI_HARDHDR_LEN - - msp->cur_mbuf.wraplen - 4)); - } - else { - llc_header_word2 = *(int *)(msp->cur_mbuf.ptr + - FDDI_HARDHDR_LEN - 4); - } - msp->cur_skb->protocol = llc_header_word2 & 0xFFFF; -#if MAC_DEBUG - printk("Got protocol 0x%x\n", msp->cur_skb->protocol); -#endif - - /* - * Copy data into socket buffer, which may be wrapped around the - * FDDI buffer. Use memcpy if the size of the data is less - * than DMA_RECV_THRESHOLD. Note if DMA is used, then wrap- - * arounds are handled automatically. - */ - if (pkt_len < DMA_RECV_THRESHOLD) { - if (msp->cur_mbuf.length < msp->cur_mbuf.wraplen) { - memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), - msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, - ROUND4(pkt_len)); - } - else if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) { -#if MAC_DEBUG - printk("Wrap case 2\n"); -#endif - memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), - msp->cur_mbuf.wrapptr + - (FDDI_HARDHDR_LEN - msp->cur_mbuf.wraplen), - ROUND4(pkt_len)); - } - else { -#if MAC_DEBUG - printk("wrap case 3\n"); -#endif - memcpy(skb_put(msp->cur_skb, - ROUND4(msp->cur_mbuf.wraplen- - FDDI_HARDHDR_LEN)), - msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, - ROUND4(msp->cur_mbuf.wraplen - FDDI_HARDHDR_LEN)); - memcpy(skb_put(msp->cur_skb, - ROUND4(msp->cur_mbuf.length - - msp->cur_mbuf.wraplen)), - msp->cur_mbuf.wrapptr, - ROUND4(msp->cur_mbuf.length - - msp->cur_mbuf.wraplen)); - } - -#if MAC_DEBUG - if (msp->cur_skb->protocol == ETH_P_IP) { - dump_packet("apfddi_rx:", msp->cur_skb->data, pkt_len, 0); - } - else if (msp->cur_skb->protocol == ETH_P_ARP) { - struct arphdr *arp = (struct arphdr *)msp->cur_skb->data; - printk("arp->ar_op is 0x%x ar_hrd %d ar_pro 0x%x ar_hln %d ar_ln %d\n", - arp->ar_op, arp->ar_hrd, arp->ar_pro, arp->ar_hln, - arp->ar_pln); - printk("sender hardware address: %x:%x:%x:%x:%x:%x\n", - *((u_char *)msp->cur_skb->data+8), - *((u_char *)msp->cur_skb->data+9), - *((u_char *)msp->cur_skb->data+10), - *((u_char *)msp->cur_skb->data+11), - *((u_char *)msp->cur_skb->data+12), - *((u_char *)msp->cur_skb->data+13)); - printk("sender IP number %d.%d.%d.%d\n", - *((u_char *)msp->cur_skb->data+14), - *((u_char *)msp->cur_skb->data+15), - *((u_char *)msp->cur_skb->data+16), - *((u_char *)msp->cur_skb->data+17)); - printk("receiver hardware address: %x:%x:%x:%x:%x:%x\n", - *((u_char *)msp->cur_skb->data+18), - *((u_char *)msp->cur_skb->data+19), - *((u_char *)msp->cur_skb->data+20), - *((u_char *)msp->cur_skb->data+21), - *((u_char *)msp->cur_skb->data+22), - *((u_char *)msp->cur_skb->data+23)); - printk("receiver IP number %d.%d.%d.%d\n", - *((u_char *)msp->cur_skb->data+24), - *((u_char *)msp->cur_skb->data+25), - *((u_char *)msp->cur_skb->data+26), - *((u_char *)msp->cur_skb->data+27)); - } -#endif - CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb); - - /* - * Inform the network layer of the new packet. - */ -#if MAC_DEBUG - printk("Calling netif_rx()\n"); -#endif - netif_rx(msp->cur_skb); - - /* - * Remove frame from FDDI buffer. - */ - mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); - continue; - } - else { - /* - * Set up dma and break. - */ -#if MAC_DEBUG - printk("mac_process(): Starting receive DMA...\n"); -#endif - nw = NWORDS(pkt_len); - msp->dma_state = RECVING; - *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE); -/* *csr1 |= CS1_RESET_FIFO; - *csr1 &= ~CS1_RESET_FIFO; */ - if ((*csr1 & CS1_FIFO_LEVEL) != 0) { - int x; - printk("fifo not empty! (csr1 = 0x%x) emptying...", *csr1); - do { - x = *fifo; - } while ((*csr1 & CS1_FIFO_LEVEL) != 0); - printk("done\n"); - } - fstart = msp->cur_mbuf.fr_start + NWORDS(FDDI_HARDHDR_LEN); - if (fstart >= RECV_BUF_END) - fstart -= RECV_BUF_SIZE; - mac->rpr = fstart; -#if MAC_DEBUG - printk("rpr=0x%x, nw=0x%x, stat=0x%x\n", - mac->rpr, nw, buffer_mem[msp->cur_mbuf.fr_start]); -#endif - dma->st = DMA_DMST_RST; - dma->st = DMA_RESET_MASKS; - dma->hskip = 1; /* skip = 0, count = 1 */ - dma->vskip = 1; /* skip = 0, count = 1 */ - dma->maddr = (u_char *) - mmu_v2p((unsigned long) - skb_put(msp->cur_skb, ROUND4(pkt_len))); - dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + DMA_DCMD_TD_DM - + nw - 4; - *csr0 |= CS0_HREQ_RECV | CS0_DMA_RECV; - *csr0 |= CS0_DMA_ENABLE; -#if MAC_DEBUG - printk("mac_process(): DMA is away!\n"); -#endif - break; - } - } - else { -#if MAC_DEBUG - printk("mac_recv_frame failed\n"); -#endif - if (msp->recv_empty && send_buffer_full) - break; - } - } - /* - * Update mac_queue_bottom. - */ - if (mac_queue_top == NULL) - mac_queue_bottom = NULL; - -#if MAC_DEBUG - printk("End of mac_process()\n"); -#endif - restore_flags(flags); -} - - -#define DMA_IN(reg) (*(volatile unsigned *)(reg)) -#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) - -/* - * DMA completion handler. - */ -void mac_dma_complete(void) -{ - volatile struct dma_chan *dma; - struct formac_state *msp = &this_mac_state; - unsigned a; - - a = DMA_IN(DMA3_DMST); - if (!(a & DMA_INTR_REQS)) { - if (msp->dma_state != IDLE && (a & DMA_DMST_AC) == 0) { - printk("dma completed but no interrupt!\n"); - msp->dma_state = IDLE; - } - return; - } - - DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<dma_state == XMITTING && ((dma->st & DMA_DMST_AC) == 0)) { - /* - * Transmit DMA finished. - */ - int i = 20; -#if MAC_DEBUG - printk("In mac_dma_complete for transmit complete\n"); -#endif - while (*csr1 & CS1_FIFO_LEVEL) { - if (--i <= 0) { - printk("csr0=0x%x csr1=0x%x: fifo not emptying\n", *csr0, - *csr1); - return; - } - } - *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE); - msp->dma_state = IDLE; -#if MAC_DEBUG - printk("mac_dma_complete(): Calling mac_queue_frame\n"); -#endif - mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); - dev_kfree_skb(msp->cur_macq->skb); - kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq))); - msp->cur_macq = NULL; -#if MAC_DEBUG - printk("mac_dma_complete(): Calling mac_process()\n"); -#endif - mac_process(); -#if MAC_DEBUG - printk("End of mac_dma_complete transmitting\n"); -#endif - } - else if (msp->dma_state == RECVING && ((dma->st & DMA_DMST_AC) == 0)) { - /* - * Receive DMA finished. Copy the last four words from the - * fifo into the buffer, after turning off the host requests. - * We do this to avoid reading past the end of frame. - */ - int *ip, i; - -#if MAC_DEBUG - printk("In mac_dma_complete for receive complete\n"); -#endif - msp->dma_state = IDLE; - ip = (int *)mmu_p2v((unsigned long)dma->cmaddr); - -#if MAC_DEBUG - printk("ip is 0x%x, skb->data is 0x%x\n", ip, msp->cur_skb->data); -#endif - - *csr0 &= ~(CS0_DMA_ENABLE | CS0_HREQ); - - for (i = 0; (*csr1 & CS1_FIFO_LEVEL); ++i) - ip[i] = *fifo; - if (i != 4) - printk("mac_dma_complete(): not four words remaining in fifo?\n"); -#if MAC_DEBUG - printk("Copied last four words out of fifo\n"); -#endif - - /* - * Remove the frame from the FDDI receive buffer. - */ - mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); - - CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb); - - /* - * Now inject the packet into the network system. - */ - netif_rx(msp->cur_skb); - -#if MAC_DEBUG - dump_packet("mac_dma_complete:", msp->cur_skb->data, 0, 0); -#endif - - /* - * Check if any more frames can be processed. - */ - mac_process(); - -#if MAC_DEBUG - printk("End of mac_dma_complete receiving\n"); -#endif - } -#if MAC_DEBUG - printk("End of mac_dma_complete()\n"); -#endif -} - -static void mac_print_state(void) -{ - struct formac_state *msp = &this_mac_state; - - printk("DMA3_DMST is 0x%x dma_state is %d\n", DMA_IN(DMA3_DMST), - msp->dma_state); - printk("csr0 = 0x%x, csr1 = 0x%x\n", *csr0, *csr1); -} - - diff -ur --new-file old/linux/drivers/ap1000/mac.h new/linux/drivers/ap1000/mac.h --- old/linux/drivers/ap1000/mac.h Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/mac.h Thu Jan 1 01:00:00 1970 @@ -1,82 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Definitions of MAC state structures etc. - */ - -struct mac_info { - TimerTwosComplement tmax; - TimerTwosComplement tvx; - TimerTwosComplement treq; - ShortAddressType s_address; - LongAddressType l_address; - ShortAddressType s_group_adrs; - LongAddressType l_group_adrs; - int rcv_own_frames; - int only_good_frames; -}; - - -struct mac_buf { - struct mac_buf *next; - int ack; - int length; - void *ptr; - int wraplen; - void *wrapptr; - int fr_start; - int fr_end; -}; - -int mac_xmit_space(void); -void mac_xmit_alloc(struct mac_buf *, int); -void mac_queue_frame(struct mac_buf *); -int mac_recv_frame(struct mac_buf *); -void mac_discard_frame(struct mac_buf *); -int mac_init(struct mac_info *mip); -int mac_inited(struct mac_info *mip); -void mac_reset(LoopbackType loopback); -void mac_claim(void); -void mac_sleep(void); -void mac_poll(void); -void mac_disable(void); -void mac_make_spframes(void); -int mac_xalloc(int nwords); -int mac_xmit_dma(struct sk_buff *skb); -void mac_dma_complete(void); -void mac_process(void); -int mac_queue_append(struct sk_buff *skb); - -struct dma_chan { - int cmd; /* cmd << 16 + size */ - int st; /* status << 16 + current size */ - int hskip; /* hskip << 16 + hcnt */ - int vskip; /* vskip << 16 + vcnt */ - unsigned char *maddr; /* memory address */ - unsigned char *cmaddr; /* current memory address */ - int ccount; /* h_count << 16 + v_count */ - int *tblp; /* table pointer */ - int *ctblp; /* current table pointer */ - unsigned char *hdptr; /* header pointer */ -}; - -#define ROUND4(x) (((x) + 3) & -4) -#define ROUND8(x) (((x) + 7) & -8) -#define ROUND16(x) (((x) + 15) & -16) -#define ROUNDLINE(x) ROUND16(x) - -#define NWORDS(x) (((x) + 3) >> 2) -#define NLINES(x) (((x) + 15) >> 4) - -/* - * Queue element used to queue transmit requests on the FDDI. - */ -struct mac_queue { - volatile struct mac_queue *next; - struct sk_buff *skb; -}; diff -ur --new-file old/linux/drivers/ap1000/plc.c new/linux/drivers/ap1000/plc.c --- old/linux/drivers/ap1000/plc.c Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/plc.c Thu Jan 1 01:00:00 1970 @@ -1,393 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Routines for controlling the Am79c864 physical layer controller. - * - * This chip implements some parts of the FDDI SMT standard - * (PCM: physical connection management, LEM: link error monitor, etc.) - * as well as the FDDI PHY standard. - */ -#include -#include -#include -#include "apfddi.h" -#include "smt-types.h" -#include "am79c864.h" -#include "plc.h" -#include "apfddi-reg.h" - -typedef enum { - off, - signalling, - doing_lct, - joining, - active -} PlcPhase; - -struct plc_state { - LoopbackType loopback; - char t_val[16]; - char r_val[16]; - int n; - PortType peer_type; - PlcPhase phase; -}; - -struct plc_info *this_plc_info; -struct plc_state this_plc_state; - -void plc_init(struct plc_info *pip) -{ - int class, x; - struct plc_state *psp = &this_plc_state; - - this_plc_info = pip; - - /* first turn it off, clear registers */ - class = pip->port_type == pt_s? CB_CLASS_S: 0; - plc->ctrl_b = CB_PC_STOP + class; - plc->intr_mask = IE_NP_ERROR; - x = plc->intr_event; /* these register clear when read */ - x = plc->viol_sym_ct; - x = plc->min_idle_ct; - x = plc->link_err_ct; - - /* initialize registers */ - plc->ctrl_a = 0; - plc->ctrl_b = class; - plc->c_min = pip->c_min >> 8; - plc->tl_min = pip->tl_min >> 8; - plc->tb_min = pip->tb_min >> 8; - plc->t_out = pip->t_out >> 8; - plc->t_scrub = pip->t_scrub >> 8; - plc->ns_max = pip->ns_max >> 2; - - psp->phase = off; -} - -int -plc_inited(struct plc_info *pip) -{ - int class, x; - struct plc_state *psp = &this_plc_state; - - class = pip->port_type == pt_s? CB_CLASS_S: 0; - if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0) - return 1; - if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class) - return 2; - if (plc->status_a & SA_SIG_DETECT) - return 3; - if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE)) - != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE)) - return 4; - - /* all seems OK, reset the timers and counters just to be sure */ - plc->intr_mask = IE_NP_ERROR; - x = plc->intr_event; /* these register clear when read */ - x = plc->viol_sym_ct; - x = plc->min_idle_ct; - x = plc->link_err_ct; - - plc->c_min = pip->c_min >> 8; - plc->tl_min = pip->tl_min >> 8; - plc->tb_min = pip->tb_min >> 8; - plc->t_out = pip->t_out >> 8; - plc->t_scrub = pip->t_scrub >> 8; - plc->ns_max = pip->ns_max >> 2; - - psp->phase = active; - /* XXX should initialize other fields of this_plc_state */ - - return 0; -} - -void plc_sleep(void) -{ -} - -void pc_start(LoopbackType loopback) -{ - int x; - struct plc_info *pip = this_plc_info; - struct plc_state *psp = &this_plc_state; - - /* make sure it's off */ - plc->ctrl_b &= ~CB_PCM_CTRL; - plc->ctrl_b |= CB_PC_STOP; - - /* set up loopback required */ - psp->loopback = loopback; - x = 0; - switch (loopback) { - case loop_plc_lm: - x = CA_LM_LOOP; - break; - case loop_plc_eb: - x = CA_EB_LOOP; - break; - case loop_pdx: - x = CA_LOOPBACK; - break; - default: - x = 0; - } - plc->ctrl_a = x; - - /* set up bits to be exchanged */ - psp->t_val[0] = 0; - psp->t_val[1] = ((int) pip->port_type >> 1) & 1; - psp->t_val[2] = (int) pip->port_type & 1; - psp->t_val[4] = 0; /* XXX assume we want short LCT */ - psp->t_val[5] = 0; - psp->t_val[6] = 0; /* XXX too lazy to fire up my MAC for LCT */ - psp->t_val[8] = 0; /* XXX don't wanna local loop */ - psp->t_val[9] = 1; /* gotta MAC on port output */ - - pc_restart(); -} - -void pc_restart(void) -{ - struct plc_state *psp = &this_plc_state; - - if (psp->phase != off) - printk("restarting pcm\n"); - if (psp->phase == active) - set_cf_join(0); /* we're down :-( */ - - psp->n = 0; - plc->vec_length = 3 - 1; - plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1) - + (psp->t_val[2] << 2); - - plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE; - plc->ctrl_b &= ~CB_PCM_CTRL; - plc->ctrl_b |= CB_PC_START; /* light blue paper and stand clear */ - - psp->phase = signalling; -} - -void pc_stop(void) -{ - struct plc_state *psp = &this_plc_state; - - if (psp->phase == active) - set_cf_join(0); - plc->ctrl_b &= ~CB_PCM_CTRL; - plc->ctrl_b |= CB_PC_STOP; - plc->intr_mask = IE_NP_ERROR; - psp->phase = off; -} - -void plc_poll(void) -{ - struct plc_state *psp = &this_plc_state; - int events, i; - - if ((*csr0 & CS0_PHY_IRQ) == 0) - return; - events = plc->intr_event & plc->intr_mask; - if (events & IE_NP_ERROR) { - printk("plc: NP error!\n"); - } - if (events & IE_PCM_BREAK) { - i = plc->status_b & SB_BREAK_REASON; - if (i > SB_BREAK_REASON_START) { - if (psp->phase == signalling || psp->phase == doing_lct) - pcm_dump_rtcodes(); - printk("pcm: break reason %d\n", i); - if (psp->phase != off) - pc_restart(); - /* XXX need to check for trace? */ - } - } - if (events & IE_PCM_CODE) { - if (psp->phase == signalling) - pcm_pseudo_code(); - else if (psp->phase == doing_lct) - pcm_lct_done(); - else - printk("XXX pcm_code interrupt in phase %d?\n", psp->phase); - } - if (events & IE_PCM_ENABLED) { - if (psp->phase == joining) - pcm_enabled(); - else - printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase); - } - if (events & IE_TRACE_PROP) { - if (psp->phase == active) - pcm_trace_prop(); - else - printk("XXX trace_prop interrupt in phase %d\n", psp->phase); - } -} - -void pcm_pseudo_code(void) -{ - struct plc_info *pip = this_plc_info; - struct plc_state *psp = &this_plc_state; - int i, nb, lct, hislct; - - /* unpack the bits from the peer */ - nb = plc->vec_length + 1; - i = plc->rcv_vector; - do { - psp->r_val[psp->n++] = i & 1; - i >>= 1; - } while (--nb > 0); - - /* send some more, do LCT, whatever */ - switch (psp->n) { - case 3: - /* - * Got escape flag, port type; send compatibility, - * LCT duration, MAC for LCT flag. - */ - if (psp->r_val[0]) { - /* help! what do I do now? */ - pcm_dump_rtcodes(); - pc_restart(); - break; - } - psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]); - /* XXX we're type S, we talk to anybody */ - psp->t_val[3] = 1; - - plc->vec_length = 4 - 1; - plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1) - + (psp->t_val[5] << 2) + (psp->t_val[6] << 3); - break; - - case 7: - /* - * Got compatibility, LCT duration, MAC for LCT flag; - * time to do the LCT. - */ - lct = (psp->t_val[4] << 1) + psp->t_val[5]; - hislct = (psp->r_val[4] << 1) + psp->r_val[5]; - if (hislct > lct) - lct = hislct; - - /* set LCT duration */ - switch (lct) { - case 0: - plc->lc_length = pip->lc_short >> 8; - plc->ctrl_b &= ~CB_LONG_LCT; - break; - case 1: - plc->lc_length = pip->lc_medium >> 8; - plc->ctrl_b &= ~CB_LONG_LCT; - break; - case 2: - plc->ctrl_b |= CB_LONG_LCT; - /* XXX set up a timeout for pip->lc_long */ - break; - case 3: - plc->ctrl_b |= CB_LONG_LCT; - /* XXX set up a timeout for pip->lc_extended */ - break; - } - - /* start the LCT */ - i = plc->link_err_ct; /* clear the register */ - plc->ctrl_b &= ~CB_PC_LCT; - /* XXX assume we're not using the MAC for LCT; - if he's got a MAC, loop his stuff back, otherwise send idle. */ - if (psp->r_val[6]) - plc->ctrl_b |= CB_PC_LCT_LOOP; - else - plc->ctrl_b |= CB_PC_LCT_IDLE; - psp->phase = doing_lct; - break; - - case 8: - /* - * Got LCT result, send MAC for local loop and MAC on port - * output flags. - */ - if (psp->t_val[7] || psp->r_val[7]) { - printk("LCT failed, restarting.\n"); - /* LCT failed - do at least a medium length test next time. */ - if (psp->t_val[4] == 0 && psp->t_val[5] == 0) - psp->t_val[5] = 1; - pcm_dump_rtcodes(); - pc_restart(); - break; - } - plc->vec_length = 2 - 1; - plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1); - break; - - case 10: - /* - * Got MAC for local loop and MAC on port output flags. - * Let's join. - */ - plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED; - plc->ctrl_b |= CB_PC_JOIN; - psp->phase = joining; - /* printk("pcm: joining\n"); */ - break; - - default: - printk("pcm_pseudo_code bug: n = %d\n", psp->n); - } -} - -void pcm_lct_done(void) -{ - struct plc_state *psp = &this_plc_state; - int i; - - i = plc->link_err_ct; - psp->t_val[7] = i > 0; - printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i); - plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT); - plc->vec_length = 1 - 1; - plc->xmit_vector = psp->t_val[7]; - psp->phase = signalling; -} - -void pcm_dump_rtcodes(void) -{ - struct plc_state *psp = &this_plc_state; - int i; - - if (psp->n > 0) { - printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n); - for (i = 0; i < psp->n; ++i) - printk(" %d", psp->t_val[i]); - printk("\nr_val:"); - for (i = 0; i < psp->n; ++i) - printk(" %d", psp->r_val[i]); - printk("\n"); - } -} - -void pcm_enabled(void) -{ - struct plc_state *psp = &this_plc_state; - int i; - - printk("pcm: enabled\n"); - psp->phase = active; - i = plc->link_err_ct; /* clear the register */ - /* XXX should set up LEM here */ - /* XXX do we want to count violation symbols, minimum idle gaps, - or elasticity buffer errors? */ - plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP; - set_cf_join(1); /* we're up :-) */ -} - -void pcm_trace_prop(void) -{ - /* XXX help! what do I do now? */ - pc_stop(); -} diff -ur --new-file old/linux/drivers/ap1000/plc.h new/linux/drivers/ap1000/plc.h --- old/linux/drivers/ap1000/plc.h Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/plc.h Thu Jan 1 01:00:00 1970 @@ -1,53 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Definitions for PLC state structures etc. - */ - -struct plc_info { - PortType port_type; - TimerTwosComplement c_min; - TimerTwosComplement tl_min; - TimerTwosComplement tb_min; - TimerTwosComplement t_out; - TimerTwosComplement lc_short; - TimerTwosComplement lc_medium; - TimerTwosComplement lc_long; - TimerTwosComplement lc_extended; - TimerTwosComplement t_scrub; - TimerTwosComplement ns_max; - Counter link_errors; - Counter viol_syms; - Counter mini_occur; - int min_idle_gap; - double link_error_rate; -}; - -void plc_init(struct plc_info *pip); -int plc_inited(struct plc_info *pip); -void pc_start(LoopbackType loopback); -void plc_sleep(void); -void plc_poll(void); -void pc_stop(void); -void pc_restart(void); -void pcm_dump_rtcodes(void); -void pcm_pseudo_code(void); -void pcm_lct_done(void); -void pcm_enabled(void); -void pcm_trace_prop(void); - - - - - - - - - - - diff -ur --new-file old/linux/drivers/ap1000/ringbuf.c new/linux/drivers/ap1000/ringbuf.c --- old/linux/drivers/ap1000/ringbuf.c Sun Dec 5 17:42:03 1999 +++ new/linux/drivers/ap1000/ringbuf.c Thu Jan 1 01:00:00 1970 @@ -1,311 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * linux/drivers/ap1000/ringbuf.c - * - * This provides the /proc/XX/ringbuf interface to the Tnet ring buffer - */ -#define _APLIB_ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* we have a small number of reserved ring buffers to ensure that at - least one parallel program can always run */ -#define RBUF_RESERVED 4 -#define RBUF_RESERVED_ORDER 5 -static struct { - char *rb_ptr; - char *shared_ptr; - int used; -} reserved_ringbuf[RBUF_RESERVED]; - - -void ap_ringbuf_init(void) -{ - int i,j; - char *rb_ptr, *shared_ptr; - int rb_size = PAGE_SIZE * (1<ringbuf) return; - - if (tsk->ringbuf->ringbuf) { - char *rb_ptr = tsk->ringbuf->ringbuf; - char *shared_ptr = tsk->ringbuf->shared; - int order = tsk->ringbuf->order; - int rb_size = PAGE_SIZE * (1<ringbuf,sizeof(*(tsk->ringbuf))); - tsk->ringbuf = NULL; -} - - -/* - * map the ring buffer into users memory - */ -static int cap_map(int rb_size) -{ - struct task_struct *tsk=current; - int i; - char *rb_ptr=NULL; - char *shared_ptr=NULL; - int order = 0; - int error,old_uid; - - error = verify_area(VERIFY_WRITE,(char *)RBUF_VBASE,rb_size); - if (error) return error; - - if (!MPP_IS_PAR_TASK(tsk->taskid)) { - printk("ringbuf_mmap called from non-parallel task\n"); - return -EINVAL; - } - - - if (tsk->ringbuf) return -EINVAL; - - rb_size -= RBUF_RING_BUFFER_OFFSET; - rb_size >>= 1; - - switch (rb_size/1024) { - case 128: - order = 5; - break; - case 512: - order = 7; - break; - case 2048: - order = 9; - break; - case 8192: - order = 11; - break; - default: - printk("ringbuf_mmap with invalid size %d\n",rb_size); - return -EINVAL; - } - - if (order == RBUF_RESERVED_ORDER) { - for (i=0;ieuid; - current->euid = 0; - error = sys_mlock(RBUF_VBASE,2*rb_size+RBUF_RING_BUFFER_OFFSET); - current->euid = old_uid; - if (error) { - printk("ringbuffer mlock failed\n"); - return error; - } -#endif - - /* the queue pages */ -#define MAP_QUEUE(offset,phys) \ - io_remap_page_range(RBUF_VBASE + offset, \ - phys<ringbuf) { - tsk->ringbuf = (void *)kmalloc(sizeof(*(tsk->ringbuf)),GFP_ATOMIC); - if (!tsk->ringbuf) - return -ENOMEM; - } - - memset(tsk->ringbuf,0,sizeof(*tsk->ringbuf)); - tsk->ringbuf->ringbuf = rb_ptr; - tsk->ringbuf->shared = shared_ptr; - tsk->ringbuf->order = order; - tsk->ringbuf->write_ptr = mmu_v2p((unsigned)rb_ptr)<<1; - tsk->ringbuf->vaddr = RBUF_VBASE; - - memset(tsk->ringbuf->vaddr+RBUF_SHARED_PAGE_OFF,0,PAGE_SIZE); - { - struct _kernel_cap_shared *_kernel = - (struct _kernel_cap_shared *)tsk->ringbuf->vaddr; - _kernel->rbuf_read_ptr = (rb_size>>5) - 1; - } - - return 0; -} - - -static int -ringbuf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - int numcells, *phys_cells; - extern struct cap_init cap_init; - - switch (cmd) { - case CAP_GETINIT: - if (copy_to_user((char *)arg,(char *)&cap_init,sizeof(cap_init))) - return -EFAULT; - break; - - case CAP_SYNC: - if (verify_area(VERIFY_READ, (void *) arg, sizeof(int)*2)) - return -EFAULT; - if (get_user(numcells,(int *)arg)) return -EFAULT; - if (get_user((unsigned)phys_cells, - ((int *)arg)+1)) return -EFAULT; - if (verify_area(VERIFY_READ,phys_cells,sizeof(int)*numcells)) - return -EFAULT; - return ap_sync(numcells,phys_cells); - break; - - case CAP_SETGANG: - { - int v; - if (get_user(v,(int *)arg)) return -EFAULT; - mpp_set_gang_factor(v); - break; - } - - case CAP_MAP: - return cap_map(arg); - - default: - printk("unknown ringbuf ioctl %d\n",cmd); - return -EINVAL; - } - return 0; -} - - -static struct file_operations proc_ringbuf_operations = { - NULL, - NULL, - NULL, - NULL, /* readdir */ - NULL, /* poll */ - ringbuf_ioctl, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ -}; - -struct inode_operations proc_ringbuf_inode_operations = { - &proc_ringbuf_operations, /* default base directory file-ops */ -}; diff -ur --new-file old/linux/drivers/ap1000/smt-types.h new/linux/drivers/ap1000/smt-types.h --- old/linux/drivers/ap1000/smt-types.h Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/smt-types.h Thu Jan 1 01:00:00 1970 @@ -1,167 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * Definitions for FDDI Station Management. - */ - -/* - * FDDI-COMMON types. - */ - -typedef unsigned int Counter; /* 32-bit event counter */ - -typedef enum { - cp_isolated, - cp_local, - cp_secondary, - cp_primary, - cp_concatenated, - cp_thru -} CurrentPath; - -typedef char Flag; - -typedef unsigned char LongAddressType[6]; - -typedef enum { - pt_a, - pt_b, - pt_s, - pt_m, - pt_none -} PortType; - -typedef unsigned short ResourceId; - -typedef int Time; /* time in 80ns units */ -#define FDDI_TIME_UNIT 80e-9 /* 80 nanoseconds */ -#define SECS_TO_FDDI_TIME(s) ((int)((s)/FDDI_TIME_UNIT+0.99)) - -typedef int TimerTwosComplement; - -/* - * FDDI-SMT types. - */ -typedef enum { - ec_Out, - ec_In, - ec_Trace, - ec_Leave, - ec_Path_Test, - ec_Insert, - ec_Check, - ec_Deinsert -} ECMState; - -/* - * FDDI-MAC types. - */ -typedef enum { - dat_none, - dat_pass, - dat_fail -} DupAddressTest; - -typedef unsigned short DupCondition; -#define DC_MYDUP 1 -#define DC_UNADUP 2 - -typedef unsigned short FS_Functions; -#define FSF_FS_REPEATING 1 -#define FSF_FS_SETTING 2 -#define FSF_FS_CLEARING 4 - -typedef unsigned char NACondition; -#define NAC_UNACHANGE 1 -#define NAC_DNACHANGE 2 - -typedef enum { - rmt_Isolated, - rmt_Non_Op, - rmt_Ring_Op, - rmt_Detect, - rmt_Non_Op_Dup, - rmt_Ring_Op_Dup, - rmt_Directed, - rmt_Trace -} RMTState; - -typedef unsigned char ShortAddressType[2]; - -/* - * FDDI-PATH types. - */ -typedef unsigned short TraceStatus; -#define TS_TRACEINITIATED 1 -#define TS_TRACEPROPAGATED 2 -#define TS_TRACETERMINATED 4 -#define TS_TRACETIMEOUT 8 - -/* - * FDDI-PORT types. - */ -typedef enum { - PC_Maint, - PC_Enable, - PC_Disable, - PC_Start, - PC_Stop -} ActionType; - -typedef unsigned char ConnectionPolicies; -#define PC_MAC_LCT 1 -#define PC_MAC_LOOP 2 - -typedef enum { - cs_disabled, - cs_connecting, - cs_standby, - cs_active -} ConnectState; - -typedef enum { - ls_qls, - ls_ils, - ls_mls, - ls_hls, - ls_pdr, - ls_lsu, - ls_nls -} LineState; - -typedef enum { - pc_Off, - pc_Break, - pc_Trace, - pc_Connect, - pc_Next, - pc_Signal, - pc_Join, - pc_Verify, - pc_Active, - pc_Maint -} PCMState; - -typedef enum { - pcw_none, - pcw_mm, - pcw_otherincompatible, - pcw_pathnotavailable -} PC_Withhold; - -typedef enum { - pmd_multimode, - pmd_single_mode1, - pmd_single_mode2, - pmd_sonet, - pmd_low_cost_fiber, - pmd_twisted_pair, - pmd_unknown, - pmd_unspecified -} PMDClass; - diff -ur --new-file old/linux/drivers/block/cmd64x.c new/linux/drivers/block/cmd64x.c --- old/linux/drivers/block/cmd64x.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/block/cmd64x.c Tue Feb 1 08:37:19 2000 @@ -7,7 +7,7 @@ * on the 646U2 and not on the 646U. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) * Copyright (C) 1999 Andre Hedrick (andre@suse.com) */ diff -ur --new-file old/linux/drivers/block/swim3.c new/linux/drivers/block/swim3.c --- old/linux/drivers/block/swim3.c Sun Jan 9 02:41:16 2000 +++ new/linux/drivers/block/swim3.c Sat Jan 29 09:17:38 2000 @@ -241,10 +241,6 @@ unsigned int cmd, unsigned long param); static int floppy_open(struct inode *inode, struct file *filp); static int floppy_release(struct inode *inode, struct file *filp); -static ssize_t floppy_read(struct file *filp, char *buf, - size_t count, loff_t *ppos); -static ssize_t floppy_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos); static int floppy_check_change(kdev_t dev); static int floppy_revalidate(kdev_t dev); static int swim3_add_device(struct device_node *swims); @@ -986,42 +982,6 @@ release_drive(fs); return ret; -} - -static ssize_t floppy_read(struct file *filp, char *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - struct floppy_state *fs; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - - fs = &floppy_states[devnum]; - if (fs->ejected) - return -ENXIO; - return block_read(filp, buf, count, ppos); -} - -static ssize_t floppy_write(struct file * filp, const char * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = filp->f_dentry->d_inode; - struct floppy_state *fs; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - check_disk_change(inode->i_rdev); - fs = &floppy_states[devnum]; - if (fs->ejected) - return -ENXIO; - if (fs->write_prot < 0) - fs->write_prot = swim3_readbit(fs, WRITE_PROT); - if (fs->write_prot) - return -EROFS; - return block_write(filp, buf, count, ppos); } static void floppy_off(unsigned int nr) diff -ur --new-file old/linux/drivers/block/swim_iop.c new/linux/drivers/block/swim_iop.c --- old/linux/drivers/block/swim_iop.c Sun Jan 9 02:41:16 2000 +++ new/linux/drivers/block/swim_iop.c Sat Jan 29 09:17:38 2000 @@ -102,10 +102,6 @@ static void swimiop_status_update(int, struct swim_drvstatus *); static int swimiop_eject(struct floppy_state *fs); -static ssize_t floppy_read(struct file *filp, char *buf, - size_t count, loff_t *ppos); -static ssize_t floppy_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos); static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); static int floppy_open(struct inode *inode, struct file *filp); @@ -336,40 +332,6 @@ } release_drive(fs); return cmd->error; -} - -static ssize_t floppy_read(struct file *filp, char *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - struct floppy_state *fs; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - - fs = &floppy_states[devnum]; - if (fs->ejected) - return -ENXIO; - return block_read(filp, buf, count, ppos); -} - -static ssize_t floppy_write(struct file * filp, const char * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = filp->f_dentry->d_inode; - struct floppy_state *fs; - int devnum = MINOR(inode->i_rdev); - - if (devnum >= floppy_count) - return -ENODEV; - check_disk_change(inode->i_rdev); - fs = &floppy_states[devnum]; - if (fs->ejected) - return -ENXIO; - if (fs->write_prot) - return -EROFS; - return block_write(filp, buf, count, ppos); } static struct floppy_struct floppy_type = diff -ur --new-file old/linux/drivers/char/agp/agpgart_be.c new/linux/drivers/char/agp/agpgart_be.c --- old/linux/drivers/char/agp/agpgart_be.c Tue Jan 4 18:41:45 2000 +++ new/linux/drivers/char/agp/agpgart_be.c Sun Jan 30 05:41:40 2000 @@ -232,7 +232,6 @@ } if (curr->type != 0) { agp_bridge.free_by_type(curr); - MOD_DEC_USE_COUNT; return; } if (curr->page_count != 0) { @@ -260,15 +259,23 @@ agp_bridge.max_memory_agp) { return NULL; } + if (type != 0) { new = agp_bridge.alloc_by_type(page_count, type); return new; } + /* We always increase the module count, since free auto-decrements + * it + */ + + MOD_INC_USE_COUNT; + scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; new = agp_create_memory(scratch_pages); if (new == NULL) { + MOD_DEC_USE_COUNT; return NULL; } for (i = 0; i < page_count; i++) { @@ -286,7 +293,6 @@ new->page_count++; } - MOD_INC_USE_COUNT; return new; } @@ -781,11 +787,13 @@ }; #define AGP_DCACHE_MEMORY 1 +#define AGP_PHYS_MEMORY 2 static gatt_mask intel_i810_masks[] = { {I810_PTE_VALID, 0}, - {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY} + {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}, + {I810_PTE_VALID, 0} }; static struct _intel_i810_private { @@ -896,7 +904,7 @@ if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { /* special insert */ - + CACHE_FLUSH(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { OUTREG32(intel_i810_private.registers, @@ -904,20 +912,24 @@ (i * 4096) | I810_PTE_LOCAL | I810_PTE_VALID); } - + CACHE_FLUSH(); agp_bridge.tlb_flush(mem); return 0; } + if((type == AGP_PHYS_MEMORY) && + (mem->type == AGP_PHYS_MEMORY)) { + goto insert; + } return -EINVAL; } - if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); - mem->is_flushed = TRUE; - } + +insert: + CACHE_FLUSH(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { OUTREG32(intel_i810_private.registers, I810_PTE_BASE + (j * 4), mem->memory[i]); } + CACHE_FLUSH(); agp_bridge.tlb_flush(mem); return 0; @@ -955,15 +967,55 @@ new->page_count = pg_count; new->num_scratch_pages = 0; vfree(new->memory); + MOD_INC_USE_COUNT; return new; } + if(type == AGP_PHYS_MEMORY) { + /* The I810 requires a physical address to program + * it's mouse pointer into hardware. However the + * Xserver still writes to it through the agp + * aperture + */ + if (pg_count != 1) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + MOD_INC_USE_COUNT; + new->memory[0] = agp_alloc_page(); + + if (new->memory[0] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[0] = + agp_bridge.mask_memory( + virt_to_phys((void *) new->memory[0]), + type); + new->page_count = 1; + new->num_scratch_pages = 1; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) new->memory[0]); + return new; + } + return NULL; } static void intel_i810_free_by_type(agp_memory * curr) { agp_free_key(curr->key); + if(curr->type == AGP_PHYS_MEMORY) { + agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[0])); + vfree(curr->memory); + } kfree(curr); + MOD_DEC_USE_COUNT; } static unsigned long intel_i810_mask_memory(unsigned long addr, int type) @@ -1916,7 +1968,7 @@ static int agp_find_max(void) { - long memory, t, index, result; + long memory, index, result; memory = virt_to_phys(high_memory) >> 20; index = 1; @@ -1926,16 +1978,15 @@ index++; } - t = (memory - maxes_table[index - 1].mem) / - (maxes_table[index].mem - maxes_table[index - 1].mem); - result = maxes_table[index - 1].agp + - (t * (maxes_table[index].agp - maxes_table[index - 1].agp)); + ( (memory - maxes_table[index - 1].mem) * + (maxes_table[index].agp - maxes_table[index - 1].agp)) / + (maxes_table[index].mem - maxes_table[index - 1].mem); printk(KERN_INFO "agpgart: Maximum main memory to use " "for agp memory: %ldM\n", result); result = result << (20 - PAGE_SHIFT); - return result; + return result; } #define AGPGART_VERSION_MAJOR 0 diff -ur --new-file old/linux/drivers/char/agp/agpgart_fe.c new/linux/drivers/char/agp/agpgart_fe.c --- old/linux/drivers/char/agp/agpgart_fe.c Thu Jan 6 19:23:46 2000 +++ new/linux/drivers/char/agp/agpgart_fe.c Sun Jan 30 05:41:40 2000 @@ -298,7 +298,7 @@ agp_memory *memory; memory = agp_allocate_memory(pg_count, type); - + printk("memory : %p\n", memory); if (memory == NULL) { return NULL; } @@ -911,6 +911,7 @@ return -ENOMEM; } alloc.key = memory->key; + alloc.physical = memory->physical; if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) { agp_free_memory_wrap(memory); diff -ur --new-file old/linux/drivers/char/generic_serial.c new/linux/drivers/char/generic_serial.c --- old/linux/drivers/char/generic_serial.c Tue Aug 31 20:30:48 1999 +++ new/linux/drivers/char/generic_serial.c Mon Jan 31 19:29:16 2000 @@ -103,10 +103,6 @@ #include "generic_serial.h" -#ifndef MODULE -extern void my_hd (unsigned char *ptr, int n); -#endif - static char * tmp_buf; static DECLARE_MUTEX(tmp_buf_sem); @@ -119,8 +115,8 @@ #define gs_dprintk(f, str...) /* nothing */ #endif -#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n") -#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n") +#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n") +#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n") @@ -856,7 +852,6 @@ if (gs_debug & GS_DEBUG_TERMIOS) { gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); - my_hd ((unsigned char *)tiosp, sizeof (struct termios)); } #if 0 diff -ur --new-file old/linux/drivers/char/generic_serial.h new/linux/drivers/char/generic_serial.h --- old/linux/drivers/char/generic_serial.h Thu Aug 5 23:47:44 1999 +++ new/linux/drivers/char/generic_serial.h Mon Jan 31 19:29:16 2000 @@ -12,6 +12,8 @@ #ifndef GENERIC_SERIAL_H #define GENERIC_SERIAL_H +#define RS_EVENT_WRITE_WAKEUP 0 + struct real_driver { void (*disable_tx_interrupts) (void *); void (*enable_tx_interrupts) (void *); @@ -75,6 +77,7 @@ #define GS_DEBUG_TERMIOS 0x00000004 #define GS_DEBUG_STUFF 0x00000008 #define GS_DEBUG_CLOSE 0x00000010 +#define GS_DEBUG_FLOW 0x00000020 void gs_put_char(struct tty_struct *tty, unsigned char ch); diff -ur --new-file old/linux/drivers/char/joystick/joy-creative.c new/linux/drivers/char/joystick/joy-creative.c --- old/linux/drivers/char/joystick/joy-creative.c Tue Dec 7 19:13:11 1999 +++ new/linux/drivers/char/joystick/joy-creative.c Tue Feb 1 01:30:19 2000 @@ -66,7 +66,7 @@ int r[2], t[2], p[2]; int i, j, ret; - for (i = 0; i < 2; i++); { + for (i = 0; i < 2; i++) { r[i] = buf[i] = 0; p[i] = t[i] = JS_CR_MAX_STROBE; p[i] += JS_CR_MAX_STROBE; diff -ur --new-file old/linux/drivers/char/scc.h new/linux/drivers/char/scc.h --- old/linux/drivers/char/scc.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/scc.h Tue Feb 1 08:43:51 2000 @@ -0,0 +1,613 @@ +/* + * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller + * + * Copyright 1994 Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + + +#ifndef _SCC_H +#define _SCC_H + +#include + +/* Special configuration ioctls for the Atari SCC5380 Serial + * Communications Controller + */ + +/* ioctl command codes */ + +#define TIOCGATSCC 0x54c0 /* get SCC configuration */ +#define TIOCSATSCC 0x54c1 /* set SCC configuration */ +#define TIOCDATSCC 0x54c2 /* reset configuration to defaults */ + +/* Clock sources */ + +#define CLK_RTxC 0 +#define CLK_TRxC 1 +#define CLK_PCLK 2 + +/* baud_bases for the common clocks in the Atari. These are the real + * frequencies divided by 16. + */ + +#define SCC_BAUD_BASE_TIMC 19200 /* 0.3072 MHz from TT-MFP, Timer C */ +#define SCC_BAUD_BASE_BCLK 153600 /* 2.4576 MHz */ +#define SCC_BAUD_BASE_PCLK4 229500 /* 3.6720 MHz */ +#define SCC_BAUD_BASE_PCLK 503374 /* 8.0539763 MHz */ +#define SCC_BAUD_BASE_NONE 0 /* for not connected or unused + * clock sources */ + +/* The SCC clock configuration structure */ + +struct scc_clock_config { + unsigned RTxC_base; /* base_baud of RTxC */ + unsigned TRxC_base; /* base_baud of TRxC */ + unsigned PCLK_base; /* base_baud of PCLK, both channels! */ + struct { + unsigned clksrc; /* CLK_RTxC, CLK_TRxC or CLK_PCLK */ + unsigned divisor; /* divisor for base baud, valid values: + * see below */ + } baud_table[17]; /* For 50, 75, 110, 135, 150, 200, 300, + * 600, 1200, 1800, 2400, 4800, 9600, + * 19200, 38400, 57600 and 115200 bps. + * The last two could be replaced by + * other rates > 38400 if they're not + * possible. + */ +}; + +/* The following divisors are valid: + * + * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use + * the BRG) + * + * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible) + * + * - CLK_PCLK: >= 4 and even (no direct modes, only BRG) + * + */ + +struct scc_port { + struct gs_port gs; + volatile unsigned char *ctrlp; + volatile unsigned char *datap; + int x_char; /* xon/xoff character */ + int c_dcd; + int channel; + struct scc_port *port_a; /* Reference to port A and B */ + struct scc_port *port_b; /* structs for reg access */ +}; + +#define SCC_MAGIC 0x52696368 + +/***********************************************************************/ +/* */ +/* Register Names */ +/* */ +/***********************************************************************/ + +/* The SCC documentation gives no explicit names to the registers, + * they're just called WR0..15 and RR0..15. To make the source code + * better readable and make the transparent write reg read access (see + * below) possible, I christen them here with self-invented names. + * Note that (real) read registers are assigned numbers 16..31. WR7' + * has number 33. + */ + +#define COMMAND_REG 0 /* wo */ +#define INT_AND_DMA_REG 1 /* wo */ +#define INT_VECTOR_REG 2 /* rw, common to both channels */ +#define RX_CTRL_REG 3 /* rw */ +#define AUX1_CTRL_REG 4 /* rw */ +#define TX_CTRL_REG 5 /* rw */ +#define SYNC_ADR_REG 6 /* wo */ +#define SYNC_CHAR_REG 7 /* wo */ +#define SDLC_OPTION_REG 33 /* wo */ +#define TX_DATA_REG 8 /* wo */ +#define MASTER_INT_CTRL 9 /* wo, common to both channels */ +#define AUX2_CTRL_REG 10 /* rw */ +#define CLK_CTRL_REG 11 /* wo */ +#define TIMER_LOW_REG 12 /* rw */ +#define TIMER_HIGH_REG 13 /* rw */ +#define DPLL_CTRL_REG 14 /* wo */ +#define INT_CTRL_REG 15 /* rw */ + +#define STATUS_REG 16 /* ro */ +#define SPCOND_STATUS_REG 17 /* wo */ +/* RR2 is WR2 for Channel A, Channel B gives vector + current status: */ +#define CURR_VECTOR_REG 18 /* Ch. B only, Ch. A for rw */ +#define INT_PENDING_REG 19 /* Channel A only! */ +/* RR4 is WR4, if b6(MR7') == 1 */ +/* RR5 is WR5, if b6(MR7') == 1 */ +#define FS_FIFO_LOW_REG 22 /* ro */ +#define FS_FIFO_HIGH_REG 23 /* ro */ +#define RX_DATA_REG 24 /* ro */ +/* RR9 is WR3, if b6(MR7') == 1 */ +#define DPLL_STATUS_REG 26 /* ro */ +/* RR11 is WR10, if b6(MR7') == 1 */ +/* RR12 is WR12 */ +/* RR13 is WR13 */ +/* RR14 not present */ +/* RR15 is WR15 */ + + +/***********************************************************************/ +/* */ +/* Register Values */ +/* */ +/***********************************************************************/ + + +/* WR0: COMMAND_REG "CR" */ + +#define CR_RX_CRC_RESET 0x40 +#define CR_TX_CRC_RESET 0x80 +#define CR_TX_UNDERRUN_RESET 0xc0 + +#define CR_EXTSTAT_RESET 0x10 +#define CR_SEND_ABORT 0x18 +#define CR_ENAB_INT_NEXT_RX 0x20 +#define CR_TX_PENDING_RESET 0x28 +#define CR_ERROR_RESET 0x30 +#define CR_HIGHEST_IUS_RESET 0x38 + + +/* WR1: INT_AND_DMA_REG "IDR" */ + +#define IDR_EXTSTAT_INT_ENAB 0x01 +#define IDR_TX_INT_ENAB 0x02 +#define IDR_PARERR_AS_SPCOND 0x04 + +#define IDR_RX_INT_DISAB 0x00 +#define IDR_RX_INT_FIRST 0x08 +#define IDR_RX_INT_ALL 0x10 +#define IDR_RX_INT_SPCOND 0x18 +#define IDR_RX_INT_MASK 0x18 + +#define IDR_WAITREQ_RX 0x20 +#define IDR_WAITREQ_IS_REQ 0x40 +#define IDR_WAITREQ_ENAB 0x80 + + +/* WR3: RX_CTRL_REG "RCR" */ + +#define RCR_RX_ENAB 0x01 +#define RCR_DISCARD_SYNC_CHARS 0x02 +#define RCR_ADDR_SEARCH 0x04 +#define RCR_CRC_ENAB 0x08 +#define RCR_SEARCH_MODE 0x10 +#define RCR_AUTO_ENAB_MODE 0x20 + +#define RCR_CHSIZE_MASK 0xc0 +#define RCR_CHSIZE_5 0x00 +#define RCR_CHSIZE_6 0x40 +#define RCR_CHSIZE_7 0x80 +#define RCR_CHSIZE_8 0xc0 + + +/* WR4: AUX1_CTRL_REG "A1CR" */ + +#define A1CR_PARITY_MASK 0x03 +#define A1CR_PARITY_NONE 0x00 +#define A1CR_PARITY_ODD 0x01 +#define A1CR_PARITY_EVEN 0x03 + +#define A1CR_MODE_MASK 0x0c +#define A1CR_MODE_SYNCR 0x00 +#define A1CR_MODE_ASYNC_1 0x04 +#define A1CR_MODE_ASYNC_15 0x08 +#define A1CR_MODE_ASYNC_2 0x0c + +#define A1CR_SYNCR_MODE_MASK 0x30 +#define A1CR_SYNCR_MONOSYNC 0x00 +#define A1CR_SYNCR_BISYNC 0x10 +#define A1CR_SYNCR_SDLC 0x20 +#define A1CR_SYNCR_EXTCSYNC 0x30 + +#define A1CR_CLKMODE_MASK 0xc0 +#define A1CR_CLKMODE_x1 0x00 +#define A1CR_CLKMODE_x16 0x40 +#define A1CR_CLKMODE_x32 0x80 +#define A1CR_CLKMODE_x64 0xc0 + + +/* WR5: TX_CTRL_REG "TCR" */ + +#define TCR_TX_CRC_ENAB 0x01 +#define TCR_RTS 0x02 +#define TCR_USE_CRC_CCITT 0x00 +#define TCR_USE_CRC_16 0x04 +#define TCR_TX_ENAB 0x08 +#define TCR_SEND_BREAK 0x10 + +#define TCR_CHSIZE_MASK 0x60 +#define TCR_CHSIZE_5 0x00 +#define TCR_CHSIZE_6 0x20 +#define TCR_CHSIZE_7 0x40 +#define TCR_CHSIZE_8 0x60 + +#define TCR_DTR 0x80 + + +/* WR7': SLDC_OPTION_REG "SOR" */ + +#define SOR_AUTO_TX_ENAB 0x01 +#define SOR_AUTO_EOM_RESET 0x02 +#define SOR_AUTO_RTS_MODE 0x04 +#define SOR_NRZI_DISAB_HIGH 0x08 +#define SOR_ALT_DTRREQ_TIMING 0x10 +#define SOR_READ_CRC_CHARS 0x20 +#define SOR_EXTENDED_REG_ACCESS 0x40 + + +/* WR9: MASTER_INT_CTRL "MIC" */ + +#define MIC_VEC_INCL_STAT 0x01 +#define MIC_NO_VECTOR 0x02 +#define MIC_DISAB_LOWER_CHAIN 0x04 +#define MIC_MASTER_INT_ENAB 0x08 +#define MIC_STATUS_HIGH 0x10 +#define MIC_IGN_INTACK 0x20 + +#define MIC_NO_RESET 0x00 +#define MIC_CH_A_RESET 0x40 +#define MIC_CH_B_RESET 0x80 +#define MIC_HARD_RESET 0xc0 + + +/* WR10: AUX2_CTRL_REG "A2CR" */ + +#define A2CR_SYNC_6 0x01 +#define A2CR_LOOP_MODE 0x02 +#define A2CR_ABORT_ON_UNDERRUN 0x04 +#define A2CR_MARK_IDLE 0x08 +#define A2CR_GO_ACTIVE_ON_POLL 0x10 + +#define A2CR_CODING_MASK 0x60 +#define A2CR_CODING_NRZ 0x00 +#define A2CR_CODING_NRZI 0x20 +#define A2CR_CODING_FM1 0x40 +#define A2CR_CODING_FM0 0x60 + +#define A2CR_PRESET_CRC_1 0x80 + + +/* WR11: CLK_CTRL_REG "CCR" */ + +#define CCR_TRxCOUT_MASK 0x03 +#define CCR_TRxCOUT_XTAL 0x00 +#define CCR_TRxCOUT_TXCLK 0x01 +#define CCR_TRxCOUT_BRG 0x02 +#define CCR_TRxCOUT_DPLL 0x03 + +#define CCR_TRxC_OUTPUT 0x04 + +#define CCR_TXCLK_MASK 0x18 +#define CCR_TXCLK_RTxC 0x00 +#define CCR_TXCLK_TRxC 0x08 +#define CCR_TXCLK_BRG 0x10 +#define CCR_TXCLK_DPLL 0x18 + +#define CCR_RXCLK_MASK 0x60 +#define CCR_RXCLK_RTxC 0x00 +#define CCR_RXCLK_TRxC 0x20 +#define CCR_RXCLK_BRG 0x40 +#define CCR_RXCLK_DPLL 0x60 + +#define CCR_RTxC_XTAL 0x80 + + +/* WR14: DPLL_CTRL_REG "DCR" */ + +#define DCR_BRG_ENAB 0x01 +#define DCR_BRG_USE_PCLK 0x02 +#define DCR_DTRREQ_IS_REQ 0x04 +#define DCR_AUTO_ECHO 0x08 +#define DCR_LOCAL_LOOPBACK 0x10 + +#define DCR_DPLL_EDGE_SEARCH 0x20 +#define DCR_DPLL_ERR_RESET 0x40 +#define DCR_DPLL_DISAB 0x60 +#define DCR_DPLL_CLK_BRG 0x80 +#define DCR_DPLL_CLK_RTxC 0xa0 +#define DCR_DPLL_FM 0xc0 +#define DCR_DPLL_NRZI 0xe0 + + +/* WR15: INT_CTRL_REG "ICR" */ + +#define ICR_OPTIONREG_SELECT 0x01 +#define ICR_ENAB_BRG_ZERO_INT 0x02 +#define ICR_USE_FS_FIFO 0x04 +#define ICR_ENAB_DCD_INT 0x08 +#define ICR_ENAB_SYNC_INT 0x10 +#define ICR_ENAB_CTS_INT 0x20 +#define ICR_ENAB_UNDERRUN_INT 0x40 +#define ICR_ENAB_BREAK_INT 0x80 + + +/* RR0: STATUS_REG "SR" */ + +#define SR_CHAR_AVAIL 0x01 +#define SR_BRG_ZERO 0x02 +#define SR_TX_BUF_EMPTY 0x04 +#define SR_DCD 0x08 +#define SR_SYNC_ABORT 0x10 +#define SR_CTS 0x20 +#define SR_TX_UNDERRUN 0x40 +#define SR_BREAK 0x80 + + +/* RR1: SPCOND_STATUS_REG "SCSR" */ + +#define SCSR_ALL_SENT 0x01 +#define SCSR_RESIDUAL_MASK 0x0e +#define SCSR_PARITY_ERR 0x10 +#define SCSR_RX_OVERRUN 0x20 +#define SCSR_CRC_FRAME_ERR 0x40 +#define SCSR_END_OF_FRAME 0x80 + + +/* RR3: INT_PENDING_REG "IPR" */ + +#define IPR_B_EXTSTAT 0x01 +#define IPR_B_TX 0x02 +#define IPR_B_RX 0x04 +#define IPR_A_EXTSTAT 0x08 +#define IPR_A_TX 0x10 +#define IPR_A_RX 0x20 + + +/* RR7: FS_FIFO_HIGH_REG "FFHR" */ + +#define FFHR_CNT_MASK 0x3f +#define FFHR_IS_FROM_FIFO 0x40 +#define FFHR_FIFO_OVERRUN 0x80 + + +/* RR10: DPLL_STATUS_REG "DSR" */ + +#define DSR_ON_LOOP 0x02 +#define DSR_ON_LOOP_SENDING 0x10 +#define DSR_TWO_CLK_MISSING 0x40 +#define DSR_ONE_CLK_MISSING 0x80 + +/***********************************************************************/ +/* */ +/* Register Access */ +/* */ +/***********************************************************************/ + + +/* The SCC needs 3.5 PCLK cycles recovery time between to register + * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 * + * 125 ns = 437.5 ns. This is too short for udelay(). + * 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be + * quite right + */ + +#define scc_reg_delay() \ + do { \ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) \ + __asm__ __volatile__ ( " nop; nop"); \ + else if (MACH_IS_ATARI) \ + __asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" );\ + } while (0) + +extern unsigned char scc_shadow[2][16]; + +/* The following functions should relax the somehow complicated + * register access of the SCC. _SCCwrite() stores all written values + * (except for WR0 and WR8) in shadow registers for later recall. This + * removes the burden of remembering written values as needed. The + * extra work of storing the value doesn't count, since a delay is + * needed after a SCC access anyway. Additionally, _SCCwrite() manages + * writes to WR0 and WR8 differently, because these can be accessed + * directly with less overhead. Another special case are WR7 and WR7'. + * _SCCwrite automatically checks what of this registers is selected + * and changes b0 of WR15 if needed. + * + * _SCCread() for standard read registers is straightforward, except + * for RR2 (split into two "virtual" registers: one for the value + * written to WR2 (from the shadow) and one for the vector including + * status from RR2, Ch. B) and RR3. The latter must be read from + * Channel A, because it reads as all zeros on Ch. B. RR0 and RR8 can + * be accessed directly as before. + * + * The two inline function contain complicated switch statements. But + * I rely on regno and final_delay being constants, so gcc can reduce + * the whole stuff to just some assembler statements. + * + * _SCCwrite and _SCCread aren't intended to be used directly under + * normal circumstances. The macros SCCread[_ND] and SCCwrite[_ND] are + * for that purpose. They assume that a local variable 'port' is + * declared and pointing to the port's scc_struct entry. The + * variants with "_NB" appended should be used if no other SCC + * accesses follow immediatly (within 0.5 usecs). They just skip the + * final delay nops. + * + * Please note that accesses to SCC registers should only take place + * when interrupts are turned off (at least if SCC interrupts are + * enabled). Otherwise, an interrupt could interfere with the + * two-stage accessing process. + * + */ + + +static __inline__ void _SCCwrite( + struct scc_port *port, + unsigned char *shadow, + volatile unsigned char *_scc_del, + int regno, + unsigned char val, int final_delay ) +{ + switch( regno ) { + + case COMMAND_REG: + /* WR0 can be written directly without pointing */ + *port->ctrlp = val; + break; + + case SYNC_CHAR_REG: + /* For WR7, first set b0 of WR15 to 0, if needed */ + if (shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT) { + *port->ctrlp = 15; + shadow[INT_CTRL_REG] &= ~ICR_OPTIONREG_SELECT; + scc_reg_delay(); + *port->ctrlp = shadow[INT_CTRL_REG]; + scc_reg_delay(); + } + goto normal_case; + + case SDLC_OPTION_REG: + /* For WR7', first set b0 of WR15 to 1, if needed */ + if (!(shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT)) { + *port->ctrlp = 15; + shadow[INT_CTRL_REG] |= ICR_OPTIONREG_SELECT; + scc_reg_delay(); + *port->ctrlp = shadow[INT_CTRL_REG]; + scc_reg_delay(); + } + *port->ctrlp = 7; + shadow[8] = val; /* WR7' shadowed at WR8 */ + scc_reg_delay(); + *port->ctrlp = val; + break; + + case TX_DATA_REG: /* WR8 */ + /* TX_DATA_REG can be accessed directly on some h/w */ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) + { + *port->ctrlp = regno; + scc_reg_delay(); + *port->ctrlp = val; + } + else + *port->datap = val; + break; + + case MASTER_INT_CTRL: + *port->ctrlp = regno; + val &= 0x3f; /* bits 6..7 are the reset commands */ + scc_shadow[0][regno] = val; + scc_reg_delay(); + *port->ctrlp = val; + break; + + case DPLL_CTRL_REG: + *port->ctrlp = regno; + val &= 0x1f; /* bits 5..7 are the DPLL commands */ + shadow[regno] = val; + scc_reg_delay(); + *port->ctrlp = val; + break; + + case 1 ... 6: + case 10 ... 13: + case 15: + normal_case: + *port->ctrlp = regno; + shadow[regno] = val; + scc_reg_delay(); + *port->ctrlp = val; + break; + + default: + printk( "Bad SCC write access to WR%d\n", regno ); + break; + + } + + if (final_delay) + scc_reg_delay(); +} + + +static __inline__ unsigned char _SCCread( + struct scc_port *port, + unsigned char *shadow, + volatile unsigned char *_scc_del, + int regno, int final_delay ) +{ + unsigned char rv; + + switch( regno ) { + + /* --- real read registers --- */ + case STATUS_REG: + rv = *port->ctrlp; + break; + + case INT_PENDING_REG: + /* RR3: read only from Channel A! */ + port = port->port_a; + goto normal_case; + + case RX_DATA_REG: + /* RR8 can be accessed directly on some h/w */ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) + { + *port->ctrlp = 8; + scc_reg_delay(); + rv = *port->ctrlp; + } + else + rv = *port->datap; + break; + + case CURR_VECTOR_REG: + /* RR2 (vector including status) from Ch. B */ + port = port->port_b; + goto normal_case; + + /* --- reading write registers: access the shadow --- */ + case 1 ... 7: + case 10 ... 15: + return shadow[regno]; /* no final delay! */ + + /* WR7' is special, because it is shadowed at the place of WR8 */ + case SDLC_OPTION_REG: + return shadow[8]; /* no final delay! */ + + /* WR9 is special too, because it is common for both channels */ + case MASTER_INT_CTRL: + return scc_shadow[0][9]; /* no final delay! */ + + default: + printk( "Bad SCC read access to %cR%d\n", (regno & 16) ? 'R' : 'W', + regno & ~16 ); + break; + + case SPCOND_STATUS_REG: + case FS_FIFO_LOW_REG: + case FS_FIFO_HIGH_REG: + case DPLL_STATUS_REG: + normal_case: + *port->ctrlp = regno & 0x0f; + scc_reg_delay(); + rv = *port->ctrlp; + break; + + } + + if (final_delay) + scc_reg_delay(); + return rv; +} + +#define SCC_ACCESS_INIT(port) \ + unsigned char *_scc_shadow = &scc_shadow[port->channel][0] + +#define SCCwrite(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),1) +#define SCCwrite_NB(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),0) +#define SCCread(reg) _SCCread(port,_scc_shadow,scc_del,(reg),1) +#define SCCread_NB(reg) _SCCread(port,_scc_shadow,scc_del,(reg),0) + +#define SCCmod(reg,and,or) SCCwrite((reg),(SCCread(reg)&(and))|(or)) + +#endif /* _SCC_H */ diff -ur --new-file old/linux/drivers/char/serial167.c new/linux/drivers/char/serial167.c --- old/linux/drivers/char/serial167.c Tue Aug 31 20:30:48 1999 +++ new/linux/drivers/char/serial167.c Mon Jan 31 19:32:04 2000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,8 @@ #include #include #include +#include +#include #include #include @@ -144,7 +147,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf = 0; -static struct semaphore tmp_buf_sem = MUTEX; +DECLARE_MUTEX(tmp_buf_sem); /* * This is used to look up the divisor speeds and the timeouts @@ -2501,8 +2504,8 @@ info->tqueue.data = info; info->callout_termios =cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); /* info->session */ /* info->pgrp */ /*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/ @@ -2728,7 +2731,7 @@ * that serial167_init() doesn't leave the chip non-functional. */ -void serial167_write(struct console *co, const char *str, unsigned count) +void serial167_console_write(struct console *co, const char *str, unsigned count) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; @@ -2786,6 +2789,95 @@ base_addr[CyIER] = ier; restore_flags(flags); +} + +/* This is a hack; if there are multiple chars waiting in the chip we + * discard all but the last one, and return that. The cd2401 is not really + * designed to be driven in polled mode. + */ + +int serial167_console_wait_key(struct console *co) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + volatile u_char sink; + u_char ier; + int port; + int keypress = 0; + + save_flags(flags); cli(); + + /* Ensure receiver is enabled! */ + + port = 0; + base_addr[CyCAR] = (u_char)port; + while (base_addr[CyCCR]) + ; + base_addr[CyCCR] = CyENB_RCVR; + ier = base_addr[CyIER]; + base_addr[CyIER] = CyRxData; + + while (!keypress) { + if (pcc2chip[PccSCCRICR] & 0x20) + { + /* We have an Rx int. Acknowledge it */ + sink = pcc2chip[PccRPIACKR]; + if ((base_addr[CyLICR] >> 2) == port) { + int cnt = base_addr[CyRFOC]; + while (cnt-- > 0) + { + keypress = base_addr[CyRDR]; + } + base_addr[CyREOIR] = 0; + } + else + base_addr[CyREOIR] = CyNOTRANS; + } + } + + base_addr[CyIER] = ier; + + restore_flags(flags); + + return keypress; +} + + +static kdev_t serial167_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + + +static int __init serial167_console_setup(struct console *co, char *options) +{ + return 0; +} + + +static struct console sercons = { + "ttyS", + serial167_console_write, + NULL, + serial167_console_device, + serial167_console_wait_key, + NULL, + serial167_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +void __init serial167_console_init(void) +{ + if (vme_brdtype == VME_TYPE_MVME166 || + vme_brdtype == VME_TYPE_MVME167 || + vme_brdtype == VME_TYPE_MVME177) { + mvme167_serial_console_setup(0); + register_console(&sercons); + } } #ifdef CONFIG_REMOTE_DEBUG diff -ur --new-file old/linux/drivers/char/tty_io.c new/linux/drivers/char/tty_io.c --- old/linux/drivers/char/tty_io.c Thu Jan 20 19:44:46 2000 +++ new/linux/drivers/char/tty_io.c Mon Jan 31 19:32:53 2000 @@ -128,6 +128,14 @@ #ifdef CONFIG_SX extern int sx_init (void); #endif +#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) +extern int vme_scc_init (void); +extern long vme_scc_console_init(void); +#endif +#ifdef CONFIG_SERIAL167 +extern int serial167_init(void); +extern long serial167_console_init(void); +#endif #ifdef CONFIG_8xx extern console_8xx_init(void); extern int rs_8xx_init(void); @@ -2090,9 +2098,15 @@ #ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_8xx console_8xx_init(); -#else +#elif defined(CONFIG_SERIAL) serial_console_init(); #endif /* CONFIG_8xx */ +#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) + vme_scc_console_init(); +#endif +#if defined(CONFIG_SERIAL167) + serial167_console_init(); +#endif #endif } @@ -2176,6 +2190,9 @@ #ifdef CONFIG_SERIAL rs_init(); #endif +#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) + vme_scc_init(); +#endif #ifdef CONFIG_COMPUTONE ip2_init(); #endif @@ -2185,7 +2202,7 @@ #ifdef CONFIG_ROCKETPORT rp_init(); #endif -#ifdef CONFIG_MVME16x +#ifdef CONFIG_SERIAL167 serial167_init(); #endif #ifdef CONFIG_CYCLADES diff -ur --new-file old/linux/drivers/char/vme_scc.c new/linux/drivers/char/vme_scc.c --- old/linux/drivers/char/vme_scc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/vme_scc.c Mon Jan 31 19:32:04 2000 @@ -0,0 +1,1136 @@ +/* + * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports + * implementation. + * Copyright 1999 Richard Hirst + * + * Based on atari_SCC.c which was + * Copyright 1994-95 Roman Hodek + * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MVME147_SCC +#include +#endif +#ifdef CONFIG_MVME162_SCC +#include +#endif +#ifdef CONFIG_BVME6000_SCC +#include +#endif + +#include "generic_serial.h" +#include "scc.h" + + +#define CHANNEL_A 0 +#define CHANNEL_B 1 + +#define SCC_MINOR_BASE 64 + +/* Shadows for all SCC write registers */ +static unsigned char scc_shadow[2][16]; + +/* Location to access for SCC register access delay */ +static volatile unsigned char *scc_del = NULL; + +/* To keep track of STATUS_REG state for detection of Ext/Status int source */ +static unsigned char scc_last_status_reg[2]; + +/***************************** Prototypes *****************************/ + +/* Function prototypes */ +static void scc_disable_tx_interrupts(void * ptr); +static void scc_enable_tx_interrupts(void * ptr); +static void scc_disable_rx_interrupts(void * ptr); +static void scc_enable_rx_interrupts(void * ptr); +static int scc_get_CD(void * ptr); +static void scc_shutdown_port(void * ptr); +static void scc_set_real_termios(void *ptr); +static void scc_hungup(void *ptr); +static void scc_close(void *ptr); +static int scc_chars_in_buffer(void * ptr); +static int scc_open(struct tty_struct * tty, struct file * filp); +static int scc_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg); +static void scc_throttle(struct tty_struct *tty); +static void scc_unthrottle(struct tty_struct *tty); +static void scc_tx_int(int irq, void *data, struct pt_regs *fp); +static void scc_rx_int(int irq, void *data, struct pt_regs *fp); +static void scc_stat_int(int irq, void *data, struct pt_regs *fp); +static void scc_spcond_int(int irq, void *data, struct pt_regs *fp); +static void scc_setsignals(struct scc_port *port, int dtr, int rts); +static void scc_break_ctl(struct tty_struct *tty, int break_state); + +static struct tty_driver scc_driver, scc_callout_driver; + +static struct tty_struct *scc_table[2] = { NULL, }; +static struct termios * scc_termios[2]; +static struct termios * scc_termios_locked[2]; +struct scc_port scc_ports[2]; + +int scc_refcount; +int scc_initialized = 0; + +/*--------------------------------------------------------------------------- + * Interface from generic_serial.c back here + *--------------------------------------------------------------------------*/ + +static struct real_driver scc_real_driver = { + scc_disable_tx_interrupts, + scc_enable_tx_interrupts, + scc_disable_rx_interrupts, + scc_enable_rx_interrupts, + scc_get_CD, + scc_shutdown_port, + scc_set_real_termios, + scc_chars_in_buffer, + scc_close, + scc_hungup, + NULL +}; + + +/*---------------------------------------------------------------------------- + * vme_scc_init() and support functions + *---------------------------------------------------------------------------*/ + +static int scc_init_drivers(void) +{ + int error; + + memset(&scc_driver, 0, sizeof(scc_driver)); + scc_driver.magic = TTY_DRIVER_MAGIC; + scc_driver.driver_name = "scc"; + scc_driver.name = "ttyS"; + scc_driver.major = TTY_MAJOR; + scc_driver.minor_start = SCC_MINOR_BASE; + scc_driver.num = 2; + scc_driver.type = TTY_DRIVER_TYPE_SERIAL; + scc_driver.subtype = SERIAL_TYPE_NORMAL; + scc_driver.init_termios = tty_std_termios; + scc_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + scc_driver.flags = TTY_DRIVER_REAL_RAW; + scc_driver.refcount = &scc_refcount; + scc_driver.table = scc_table; + scc_driver.termios = scc_termios; + scc_driver.termios_locked = scc_termios_locked; + + scc_driver.open = scc_open; + scc_driver.close = gs_close; + scc_driver.write = gs_write; + scc_driver.put_char = gs_put_char; + scc_driver.flush_chars = gs_flush_chars; + scc_driver.write_room = gs_write_room; + scc_driver.chars_in_buffer = gs_chars_in_buffer; + scc_driver.flush_buffer = gs_flush_buffer; + scc_driver.ioctl = scc_ioctl; + scc_driver.throttle = scc_throttle; + scc_driver.unthrottle = scc_unthrottle; + scc_driver.set_termios = gs_set_termios; + scc_driver.stop = gs_stop; + scc_driver.start = gs_start; + scc_driver.hangup = gs_hangup; + scc_driver.break_ctl = scc_break_ctl; + + scc_callout_driver = scc_driver; + scc_callout_driver.name = "cua"; + scc_callout_driver.major = TTYAUX_MAJOR; + scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if ((error = tty_register_driver(&scc_driver))) { + printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&scc_callout_driver))) { + tty_unregister_driver(&scc_driver); + printk(KERN_ERR "scc: Couldn't register scc callout driver, error = %d\n", + error); + return 1; + } + + return 0; +} + + +/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1). + */ + +static void scc_init_portstructs(void) +{ + struct scc_port *port; + int i; + + for (i = 0; i < 2; i++) { + port = scc_ports + i; + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SCC_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &scc_real_driver; +#ifdef NEW_WRITE_LOCKING + port->gs.port_write_sem = MUTEX; +#endif + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + } +} + + +#ifdef CONFIG_MVME147_SCC +static int mvme147_scc_init(void) +{ + struct scc_port *port; + + printk("SCC: MVME147 Serial Driver\n"); + /* Init channel A */ + port = &scc_ports[0]; + port->channel = CHANNEL_A; + port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR; + port->datap = port->ctrlp + 1; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT, + "SCC-A TX", port); + request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-A status", port); + request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT, + "SCC-A RX", port); + request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-A special cond", port); + { + SCC_ACCESS_INIT(port); + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + /* Set the interrupt vector */ + SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE); + /* Interrupt parameters: vector includes status, status low */ + SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); + SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); + } + + /* Init channel B */ + port = &scc_ports[1]; + port->channel = CHANNEL_B; + port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR; + port->datap = port->ctrlp + 1; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT, + "SCC-B TX", port); + request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-B status", port); + request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT, + "SCC-B RX", port); + request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-B special cond", port); + { + SCC_ACCESS_INIT(port); + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + } + + /* Ensure interrupts are enabled in the PCC chip */ + m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB; + + /* Initialise the tty driver structures and register */ + scc_init_portstructs(); + scc_init_drivers(); + + return 0; +} +#endif + + +#ifdef CONFIG_MVME162_SCC +static int mvme162_scc_init(void) +{ + struct scc_port *port; + + if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) + return (-ENODEV); + + printk("SCC: MVME162 Serial Driver\n"); + /* Init channel A */ + port = &scc_ports[0]; + port->channel = CHANNEL_A; + port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR; + port->datap = port->ctrlp + 2; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT, + "SCC-A TX", port); + request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-A status", port); + request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT, + "SCC-A RX", port); + request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-A special cond", port); + { + SCC_ACCESS_INIT(port); + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + /* Set the interrupt vector */ + SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE); + /* Interrupt parameters: vector includes status, status low */ + SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); + SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); + } + + /* Init channel B */ + port = &scc_ports[1]; + port->channel = CHANNEL_B; + port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR; + port->datap = port->ctrlp + 2; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT, + "SCC-B TX", port); + request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-B status", port); + request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT, + "SCC-B RX", port); + request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-B special cond", port); + + { + SCC_ACCESS_INIT(port); /* Either channel will do */ + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + } + + /* Ensure interrupts are enabled in the MC2 chip */ + *(volatile char *)0xfff4201d = 0x14; + + /* Initialise the tty driver structures and register */ + scc_init_portstructs(); + scc_init_drivers(); + + return 0; +} +#endif + + +#ifdef CONFIG_BVME6000_SCC +static int bvme6000_scc_init(void) +{ + struct scc_port *port; + + printk("SCC: BVME6000 Serial Driver\n"); + /* Init channel A */ + port = &scc_ports[0]; + port->channel = CHANNEL_A; + port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR; + port->datap = port->ctrlp + 4; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT, + "SCC-A TX", port); + request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-A status", port); + request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT, + "SCC-A RX", port); + request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-A special cond", port); + { + SCC_ACCESS_INIT(port); + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + /* Set the interrupt vector */ + SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE); + /* Interrupt parameters: vector includes status, status low */ + SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); + SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); + } + + /* Init channel B */ + port = &scc_ports[1]; + port->channel = CHANNEL_B; + port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR; + port->datap = port->ctrlp + 4; + port->port_a = &scc_ports[0]; + port->port_b = &scc_ports[1]; + request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT, + "SCC-B TX", port); + request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT, + "SCC-B status", port); + request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT, + "SCC-B RX", port); + request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT, + "SCC-B special cond", port); + + { + SCC_ACCESS_INIT(port); /* Either channel will do */ + + /* disable interrupts for this channel */ + SCCwrite(INT_AND_DMA_REG, 0); + } + + /* Initialise the tty driver structures and register */ + scc_init_portstructs(); + scc_init_drivers(); + + return 0; +} +#endif + + +int vme_scc_init(void) +{ + int res = -ENODEV; + static int called = 0; + + if (called) + return res; + called = 1; +#ifdef CONFIG_MVME147_SCC + if (MACH_IS_MVME147) + res = mvme147_scc_init(); +#endif +#ifdef CONFIG_MVME162_SCC + if (MACH_IS_MVME16x) + res = mvme162_scc_init(); +#endif +#ifdef CONFIG_BVME6000_SCC + if (MACH_IS_BVME6000) + res = bvme6000_scc_init(); +#endif + return res; +} + + +/*--------------------------------------------------------------------------- + * Interrupt handlers + *--------------------------------------------------------------------------*/ + +static void scc_rx_int(int irq, void *data, struct pt_regs *fp) +{ + unsigned char ch; + struct scc_port *port = data; + struct tty_struct *tty = port->gs.tty; + SCC_ACCESS_INIT(port); + + ch = SCCread_NB(RX_DATA_REG); + if (!tty) { + printk ("scc_rx_int with NULL tty!\n"); + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + return; + } + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + + /* Check if another character is already ready; in that case, the + * spcond_int() function must be used, because this character may have an + * error condition that isn't signalled by the interrupt vector used! + */ + if (SCCread(INT_PENDING_REG) & + (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { + scc_spcond_int (irq, data, fp); + return; + } + + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + + tty_flip_buffer_push(tty); +} + + +static void scc_spcond_int(int irq, void *data, struct pt_regs *fp) +{ + struct scc_port *port = data; + struct tty_struct *tty = port->gs.tty; + unsigned char stat, ch, err; + int int_pending_mask = port->channel == CHANNEL_A ? + IPR_A_RX : IPR_B_RX; + SCC_ACCESS_INIT(port); + + if (!tty) { + printk ("scc_spcond_int with NULL tty!\n"); + SCCwrite(COMMAND_REG, CR_ERROR_RESET); + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + return; + } + do { + stat = SCCread(SPCOND_STATUS_REG); + ch = SCCread_NB(RX_DATA_REG); + + if (stat & SCSR_RX_OVERRUN) + err = TTY_OVERRUN; + else if (stat & SCSR_PARITY_ERR) + err = TTY_PARITY; + else if (stat & SCSR_CRC_FRAME_ERR) + err = TTY_FRAME; + else + err = 0; + + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = err; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + + /* ++TeSche: *All* errors have to be cleared manually, + * else the condition persists for the next chars + */ + if (err) + SCCwrite(COMMAND_REG, CR_ERROR_RESET); + + } while(SCCread(INT_PENDING_REG) & int_pending_mask); + + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + + tty_flip_buffer_push(tty); +} + + +static void scc_tx_int(int irq, void *data, struct pt_regs *fp) +{ + struct scc_port *port = data; + SCC_ACCESS_INIT(port); + + if (!port->gs.tty) { + printk ("scc_tx_int with NULL tty!\n"); + SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); + SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + return; + } + while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { + if (port->x_char) { + SCCwrite(TX_DATA_REG, port->x_char); + port->x_char = 0; + } + else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || + port->gs.tty->hw_stopped) + break; + else { + SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); + port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); + if (--port->gs.xmit_cnt <= 0) + break; + } + } + if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || + port->gs.tty->hw_stopped) { + /* disable tx interrupts */ + SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); + SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ + port->gs.flags &= ~GS_TX_INTEN; + } + if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); +} + + +static void scc_stat_int(int irq, void *data, struct pt_regs *fp) +{ + struct scc_port *port = data; + unsigned channel = port->channel; + unsigned char last_sr, sr, changed; + SCC_ACCESS_INIT(port); + + last_sr = scc_last_status_reg[channel]; + sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); + changed = last_sr ^ sr; + + if (changed & SR_DCD) { + port->c_dcd = !!(sr & SR_DCD); + if (!(port->gs.flags & ASYNC_CHECK_CD)) + ; /* Don't report DCD changes */ + else if (port->c_dcd) { + if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || + ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { + /* Are we blocking in open?*/ + wake_up_interruptible(&port->gs.open_wait); + } + } + else { + if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && + (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + if (port->gs.tty) + tty_hangup (port->gs.tty); + } + } + } + SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); +} + + +/*--------------------------------------------------------------------------- + * generic_serial.c callback funtions + *--------------------------------------------------------------------------*/ + +static void scc_disable_tx_interrupts(void *ptr) +{ + struct scc_port *port = ptr; + unsigned long flags; + SCC_ACCESS_INIT(port); + + save_flags(flags); + cli(); + SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); + port->gs.flags &= ~GS_TX_INTEN; + restore_flags(flags); +} + + +static void scc_enable_tx_interrupts(void *ptr) +{ + struct scc_port *port = ptr; + unsigned long flags; + SCC_ACCESS_INIT(port); + + save_flags(flags); + cli(); + SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); + /* restart the transmitter */ + scc_tx_int (0, port, 0); + restore_flags(flags); +} + + +static void scc_disable_rx_interrupts(void *ptr) +{ + struct scc_port *port = ptr; + unsigned long flags; + SCC_ACCESS_INIT(port); + + save_flags(flags); + cli(); + SCCmod(INT_AND_DMA_REG, + ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); + restore_flags(flags); +} + + +static void scc_enable_rx_interrupts(void *ptr) +{ + struct scc_port *port = ptr; + unsigned long flags; + SCC_ACCESS_INIT(port); + + save_flags(flags); + cli(); + SCCmod(INT_AND_DMA_REG, 0xff, + IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); + restore_flags(flags); +} + + +static int scc_get_CD(void *ptr) +{ + struct scc_port *port = ptr; + unsigned channel = port->channel; + + return !!(scc_last_status_reg[channel] & SR_DCD); +} + + +static void scc_shutdown_port(void *ptr) +{ + struct scc_port *port = ptr; + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + scc_setsignals (port, 0, 0); + } +} + + +static void scc_set_real_termios (void *ptr) +{ + /* the SCC has char sizes 5,7,6,8 in that order! */ + static int chsize_map[4] = { 0, 2, 1, 3 }; + unsigned cflag, baud, chsize, channel, brgval = 0; + unsigned long flags; + struct scc_port *port = ptr; + SCC_ACCESS_INIT(port); + + if (!port->gs.tty || !port->gs.tty->termios) return; + + channel = port->channel; + + if (channel == CHANNEL_A) + return; /* Settings controlled by boot PROM */ + + cflag = port->gs.tty->termios->c_cflag; + baud = port->gs.baud; + chsize = (cflag & CSIZE) >> 4; + + if (baud == 0) { + /* speed == 0 -> drop DTR */ + save_flags(flags); + cli(); + SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); + restore_flags(flags); + return; + } + else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || + (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) || + (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) { + printk("SCC: Bad speed requested, %d\n", baud); + return; + } + + if (cflag & CLOCAL) + port->gs.flags &= ~ASYNC_CHECK_CD; + else + port->gs.flags |= ASYNC_CHECK_CD; + +#ifdef CONFIG_MVME147_SCC + if (MACH_IS_MVME147) + brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; + else +#endif +#ifdef CONFIG_MVME162_SCC + if (MACH_IS_MVME16x) + brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; + else +#endif +#ifdef CONFIG_BVME6000_SCC + if (MACH_IS_BVME6000) + brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2; +#endif + /* Now we have all parameters and can go to set them: */ + save_flags(flags); + cli(); + + /* receiver's character size and auto-enables */ + SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), + (chsize_map[chsize] << 6) | + ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0)); + /* parity and stop bits (both, Tx and Rx), clock mode never changes */ + SCCmod (AUX1_CTRL_REG, + ~(A1CR_PARITY_MASK | A1CR_MODE_MASK), + ((cflag & PARENB + ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) + : A1CR_PARITY_NONE) + | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1))); + /* sender's character size, set DTR for valid baud rate */ + SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR); + /* clock sources never change */ + /* disable BRG before changing the value */ + SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0); + /* BRG value */ + SCCwrite(TIMER_LOW_REG, brgval & 0xff); + SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff); + /* BRG enable, and clock source never changes */ + SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); + + restore_flags(flags); +} + + +static int scc_chars_in_buffer (void *ptr) +{ + struct scc_port *port = ptr; + SCC_ACCESS_INIT(port); + + return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1; +} + + +static void scc_hungup(void *ptr) +{ + scc_disable_tx_interrupts(ptr); + scc_disable_rx_interrupts(ptr); + MOD_DEC_USE_COUNT; +} + + +static void scc_close(void *ptr) +{ + scc_disable_tx_interrupts(ptr); + scc_disable_rx_interrupts(ptr); +} + + +/*--------------------------------------------------------------------------- + * Internal support functions + *--------------------------------------------------------------------------*/ + +static void scc_setsignals(struct scc_port *port, int dtr, int rts) +{ + unsigned long flags; + unsigned char t; + SCC_ACCESS_INIT(port); + + save_flags(flags); + t = SCCread(TX_CTRL_REG); + if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); + if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); + SCCwrite(TX_CTRL_REG, t); + restore_flags(flags); +} + + +static void scc_send_xchar(struct tty_struct *tty, char ch) +{ + struct scc_port *port = (struct scc_port *)tty->driver_data; + + port->x_char = ch; + if (ch) + scc_enable_tx_interrupts(port); +} + + +/*--------------------------------------------------------------------------- + * Driver entrypoints referenced from above + *--------------------------------------------------------------------------*/ + +static int scc_open (struct tty_struct * tty, struct file * filp) +{ + int line = MINOR(tty->device) - SCC_MINOR_BASE; + int retval; + struct scc_port *port = &scc_ports[line]; + int i, channel = port->channel; + unsigned long flags; + SCC_ACCESS_INIT(port); +#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC) + static const struct { + unsigned reg, val; + } mvme_init_tab[] = { + /* Values for MVME162 and MVME147 */ + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, + { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: DCD only */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + }; +#endif +#if defined(CONFIG_BVME6000_SCC) + static const struct { + unsigned reg, val; + } bvme_init_tab[] = { + /* Values for BVME6000 */ + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG }, + { DPLL_CTRL_REG, DCR_BRG_ENAB }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: DCD only */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + }; +#endif + if (!(port->gs.flags & ASYNC_INITIALIZED)) { + save_flags(flags); + cli(); +#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) + if (MACH_IS_MVME147 || MACH_IS_MVME16x) { + for (i=0; ic_dcd = 0; /* Prevent initial 1->0 interrupt */ + scc_setsignals (port, 1,1); + restore_flags(flags); + } + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + retval = gs_init_port(&port->gs); + if (retval) { + port->gs.count--; + return retval; + } + port->gs.flags |= GS_ACTIVE; + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + retval = block_til_ready(port, filp); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + scc_set_real_termios (port); + } + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + port->c_dcd = scc_get_CD (port); + + scc_enable_rx_interrupts(port); + + return 0; +} + + +static void scc_throttle (struct tty_struct * tty) +{ + struct scc_port *port = (struct scc_port *)tty->driver_data; + unsigned long flags; + SCC_ACCESS_INIT(port); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); + cli(); + SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); + restore_flags(flags); + } + if (I_IXOFF(tty)) + scc_send_xchar(tty, STOP_CHAR(tty)); +} + + +static void scc_unthrottle (struct tty_struct * tty) +{ + struct scc_port *port = (struct scc_port *)tty->driver_data; + unsigned long flags; + SCC_ACCESS_INIT(port); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); + cli(); + SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); + restore_flags(flags); + } + if (I_IXOFF(tty)) + scc_send_xchar(tty, START_CHAR(tty)); +} + + +static int scc_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + + +static void scc_break_ctl(struct tty_struct *tty, int break_state) +{ + struct scc_port *port = (struct scc_port *)tty->driver_data; + unsigned long flags; + SCC_ACCESS_INIT(port); + + save_flags(flags); + cli(); + SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, + break_state ? TCR_SEND_BREAK : 0); + restore_flags(flags); +} + + +/*--------------------------------------------------------------------------- + * Serial console stuff... + *--------------------------------------------------------------------------*/ + +#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0) + +static void scc_ch_write (char ch) +{ + volatile char *p = NULL; + +#ifdef CONFIG_MVME147_SCC + if (MACH_IS_MVME147) + p = (volatile char *)M147_SCC_A_ADDR; +#endif +#ifdef CONFIG_MVME162_SCC + if (MACH_IS_MVME16x) + p = (volatile char *)MVME_SCC_A_ADDR; +#endif +#ifdef CONFIG_BVME6000_SCC + if (MACH_IS_BVME6000) + p = (volatile char *)BVME_SCC_A_ADDR; +#endif + + do { + scc_delay(); + } + while (!(*p & 4)); + scc_delay(); + *p = 8; + scc_delay(); + *p = ch; +} + + +static void scc_console_write (struct console *co, const char *str, unsigned count) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + while (count--) + { + if (*str == '\n') + scc_ch_write ('\r'); + scc_ch_write (*str++); + } + restore_flags(flags); +} + + +static int scc_console_wait_key(struct console *co) +{ + unsigned long flags; + volatile char *p = NULL; + int c; + +#ifdef CONFIG_MVME147_SCC + if (MACH_IS_MVME147) + p = (volatile char *)M147_SCC_A_ADDR; +#endif +#ifdef CONFIG_MVME162_SCC + if (MACH_IS_MVME16x) + p = (volatile char *)MVME_SCC_A_ADDR; +#endif +#ifdef CONFIG_BVME6000_SCC + if (MACH_IS_BVME6000) + p = (volatile char *)BVME_SCC_A_ADDR; +#endif + + save_flags(flags); + cli(); + + /* wait for rx buf filled */ + while ((*p & 0x01) == 0) + ; + + *p = 8; + scc_delay(); + c = *p; + restore_flags(flags); + return c; +} + + +static kdev_t scc_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index); +} + + +static int __init scc_console_setup(struct console *co, char *options) +{ + return 0; +} + + +static struct console sercons = { + "ttyS", + scc_console_write, + NULL, + scc_console_device, + scc_console_wait_key, + NULL, + scc_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +void __init vme_scc_console_init(void) +{ + if (vme_brdtype == VME_TYPE_MVME147 || + vme_brdtype == VME_TYPE_MVME162 || + vme_brdtype == VME_TYPE_MVME172 || + vme_brdtype == VME_TYPE_BVME4000 || + vme_brdtype == VME_TYPE_BVME6000) + register_console(&sercons); +} + diff -ur --new-file old/linux/drivers/i2c/Config.in new/linux/drivers/i2c/Config.in --- old/linux/drivers/i2c/Config.in Thu Dec 16 22:59:38 1999 +++ new/linux/drivers/i2c/Config.in Sat Jan 29 04:36:23 2000 @@ -8,22 +8,22 @@ if [ "$CONFIG_I2C" != "n" ]; then - dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C - if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then - dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT - dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT - dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT - fi + dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C + if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then + dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT + dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT + dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT + fi - dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C - if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then - dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF - fi + dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C + if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then + dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF + fi # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here - dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C + dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C fi endmenu diff -ur --new-file old/linux/drivers/i2c/i2c-core.c new/linux/drivers/i2c/i2c-core.c --- old/linux/drivers/i2c/i2c-core.c Thu Dec 30 02:29:43 1999 +++ new/linux/drivers/i2c/i2c-core.c Sat Jan 29 04:36:23 2000 @@ -20,7 +20,7 @@ /* With some changes from Kyösti Mälkki . All SMBus-related things are written by Frodo Looijaard */ -/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-core.c,v 1.48 2000/01/24 21:41:19 frodo Exp $ */ #include #include @@ -33,37 +33,14 @@ /* ----- compatibility stuff ----------------------------------------------- */ -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - #include -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53) #include -#else -#define __init -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) #define init_MUTEX(s) do { *(s) = MUTEX; } while(0) #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4)) -#define copy_from_user memcpy_fromfs -#define copy_to_user memcpy_tofs -#else #include -#endif /* ----- global defines ---------------------------------------------------- */ @@ -83,8 +60,8 @@ /* ----- global variables -------------------------------------------------- */ /**** lock for writing to global variables: the adapter & driver list */ -struct semaphore adap_lock; -struct semaphore driver_lock; +struct semaphore adap_lock; +struct semaphore driver_lock; /**** adapter list */ static struct i2c_adapter *adapters[I2C_ADAP_MAX]; @@ -104,73 +81,29 @@ *---------------------------------------------------- */ -/* Note that quite some things changed within the 2.1 kernel series. - Some things below are somewhat difficult to read because of this. */ - #ifdef CONFIG_PROC_FS static int i2cproc_init(void); static int i2cproc_cleanup(void); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \ - (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) static void monitor_bus_i2c(struct inode *inode, int fill); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos); static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof , void *private); -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - -static int i2cproc_bus_read(struct inode * inode, struct file * file, - char * buf, int count); -static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int unused); - -static struct proc_dir_entry proc_bus_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, - /* name */ "bus", - /* mode */ S_IRUGO | S_IXUGO | S_IFDIR, - /* nlink */ 2, /* Corrected by proc_register[_dynamic] */ - /* uid */ 0, - /* gid */ 0, - /* size */ 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) - /* ops */ &proc_dir_inode_operations, -#endif - }; - -static struct proc_dir_entry proc_bus_i2c_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, - /* name */ "i2c", - /* mode */ S_IRUGO | S_IFREG, - /* nlink */ 1, - /* uid */ 0, - /* gid */ 0, - /* size */ 0, - /* ops */ NULL, - /* get_info */ &read_bus_i2c - }; - -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - /* To implement the dynamic /proc/bus/i2c-? files, we need our own implementation of the read hook */ static struct file_operations i2cproc_operations = { - NULL, - i2cproc_bus_read, + NULL, + i2cproc_bus_read, }; static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations + &i2cproc_operations }; static int i2cproc_initialized = 0; @@ -183,7 +116,7 @@ #endif /* CONFIG_PROC_FS */ -/* --------------------------------------------------- +/* --------------------------------------------------- * registering functions * --------------------------------------------------- */ @@ -222,55 +155,21 @@ if (i2cproc_initialized) { char name[8]; struct proc_dir_entry *proc_entry; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) - int res; -#endif sprintf(name,"i2c-%d", i); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) proc_entry = create_proc_entry(name,0,proc_bus); if (! proc_entry) { printk("i2c-core.o: Could not create /proc/bus/%s\n", - name); + name); return -ENOENT; - } + } proc_entry->ops = &i2cproc_inode_operations; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_entry->owner = THIS_MODULE; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) +#else proc_entry->fill_inode = &monitor_bus_i2c; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - adap->proc_entry = NULL; - if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+ - strlen(name)+1, GFP_KERNEL))) { - printk("i2c-core.o: Out of memory!\n"); - return -ENOMEM; - } - memset(proc_entry,0,sizeof(struct proc_dir_entry)); - proc_entry->namelen = strlen(name); - proc_entry->name = (char *) (proc_entry + 1); - proc_entry->mode = S_IRUGO | S_IFREG; - proc_entry->nlink = 1; - proc_entry->ops = &i2cproc_inode_operations; - - /* Nasty stuff to keep GCC satisfied */ - { - char *procname; - (const char *) procname = proc_entry->name; - strcpy (procname,name); - } - - if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) { - printk("i2c-core.o: Could not create %s.\n",name); - kfree(proc_entry); - return res; - } - - adap->proc_entry = proc_entry; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - adap->inode = proc_entry->low_ino; } @@ -283,7 +182,8 @@ drivers[j]->attach_adapter(adap); DRV_UNLOCK(); - DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i)); + DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n", + adap->name,i)); return 0; } @@ -306,23 +206,9 @@ i2c_dummy_adapter(adap); /* actually i2c_dummy->del_adapter */ #ifdef CONFIG_PROC_FS if (i2cproc_initialized) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) char name[8]; sprintf(name,"i2c-%d", i); remove_proc_entry(name,proc_bus); -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - int res; - if (adapters[i]->proc_entry) { - if ((res = proc_unregister(&proc_bus_dir, - adapters[i]->proc_entry->low_ino))) { - printk("i2c-core.o: Deregistration of /proc " - "entry failed\n"); - ADAP_UNLOCK(); - return res; - } - kfree(adapters[i]->proc_entry); - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ } #endif /* def CONFIG_PROC_FS */ @@ -344,7 +230,7 @@ ADAP_UNLOCK(); DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name)); - return 0; + return 0; } @@ -384,7 +270,8 @@ driver->attach_adapter(adapters[i]); for (j=0; jclients[j]) - driver->detach_client(adapters[i]->clients[j]); + driver->detach_client( + adapters[i]->clients[j]); } } ADAP_UNLOCK(); @@ -418,7 +305,7 @@ } /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver - * afterwards. + * afterwards. */ DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n")); /* removing clients does not depend on the notify flag, else @@ -453,11 +340,11 @@ int i2c_check_addr (struct i2c_adapter *adapter, int addr) { - int i; - for (i = 0; i < I2C_CLIENT_MAX ; i++) - if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) - return -EBUSY; - return 0; + int i; + for (i = 0; i < I2C_CLIENT_MAX ; i++) + if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) + return -EBUSY; + return 0; } int i2c_attach_client(struct i2c_client *client) @@ -465,8 +352,8 @@ struct i2c_adapter *adapter = client->adapter; int i; - if (i2c_check_addr(client->adapter,client->addr)) - return -EBUSY; + if (i2c_check_addr(client->adapter,client->addr)) + return -EBUSY; for (i = 0; i < I2C_CLIENT_MAX; i++) if (NULL == adapter->clients[i]) @@ -513,7 +400,7 @@ i2c_dummy_client(client); DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name)); - return 0; + return 0; } void i2c_inc_use_client(struct i2c_client *client) @@ -543,26 +430,21 @@ #ifdef CONFIG_PROC_FS -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \ - (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) /* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible if some process still uses it or some file in it */ void monitor_bus_i2c(struct inode *inode, int fill) { - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,37)) */ /* This function generates the output for /proc/bus/i2c */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, void *private) -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ -int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused) -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ { int i; int nr = 0; @@ -571,7 +453,7 @@ if (adapters[i]) { nr += sprintf(buf+nr, "i2c-%d\t", i); if (adapters[i]->algo->smbus_xfer) { - if (adapters[i]->algo->master_xfer) + if (adapters[i]->algo->master_xfer) nr += sprintf(buf+nr,"smbus/i2c"); else nr += sprintf(buf+nr,"smbus "); @@ -587,62 +469,55 @@ } /* This function generates the output for /proc/bus/i2c-? */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos) { - struct inode * inode = file->f_dentry->d_inode; -#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) -int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf, - int count) -{ -#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - char *kbuf; - struct i2c_client *client; - int i,j,len=0; - - if (count < 0) - return -EINVAL; - if (count > 4000) - count = 4000; - for (i = 0; i < I2C_ADAP_MAX; i++) - if (adapters[i]->inode == inode->i_ino) { - /* We need a bit of slack in the kernel buffer; this makes the - sprintf safe. */ - if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) - return -ENOMEM; - for (j = 0; j < I2C_CLIENT_MAX; j++) - if ((client = adapters[i]->clients[j])) - /* Filter out dummy clients */ - if (client->driver->id != I2C_DRIVERID_I2CDEV) - len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", - client->addr, - client->name,client->driver->name); - if (file->f_pos+len > count) - len = count - file->f_pos; - len = len - file->f_pos; - if (len < 0) - len = 0; - copy_to_user (buf,kbuf+file->f_pos,len); - file->f_pos += len; - kfree(kbuf); - return len; - } - return -ENOENT; + struct inode * inode = file->f_dentry->d_inode; + char *kbuf; + struct i2c_client *client; + int i,j,len=0; + + if (count < 0) + return -EINVAL; + if (count > 4000) + count = 4000; + for (i = 0; i < I2C_ADAP_MAX; i++) + if (adapters[i]->inode == inode->i_ino) { + /* We need a bit of slack in the kernel buffer; this makes the + sprintf safe. */ + if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) + return -ENOMEM; + for (j = 0; j < I2C_CLIENT_MAX; j++) + if ((client = adapters[i]->clients[j])) + /* Filter out dummy clients */ + if (client->driver->id != I2C_DRIVERID_I2CDEV) + len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", + client->addr, + client->name,client->driver->name); + if (file->f_pos+len > count) + len = count - file->f_pos; + len = len - file->f_pos; + if (len < 0) + len = 0; + if (copy_to_user (buf,kbuf+file->f_pos, + len)) { + kfree(kbuf); + return -EFAULT; + } + file->f_pos += len; + kfree(kbuf); + return len; + } + return -ENOENT; } int i2cproc_init(void) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) struct proc_dir_entry *proc_bus_i2c; -#else - int res; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ i2cproc_initialized = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) if (! proc_bus) { printk("i2c-core.o: /proc/bus/ does not exist"); i2cproc_cleanup(); @@ -657,29 +532,10 @@ proc_bus_i2c->read_proc = &read_bus_i2c; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_bus_i2c->owner = THIS_MODULE; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) +#else proc_bus_i2c->fill_inode = &monitor_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */ i2cproc_initialized += 2; -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module - introduced it, or we are fucked. And 2.0.35 and earlier does not - export proc_dir_inode_operations, so we grab it from proc_net, - which also uses it. Not nice. */ - proc_bus_dir.ops = proc_net.ops; - if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) { - printk("i2c-core.o: Could not create /proc/bus/"); - i2cproc_cleanup(); - return res; - } - i2cproc_initialized ++; - if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) { - printk("i2c-core.o: Could not create /proc/bus/i2c\n"); - i2cproc_cleanup(); - return res; - } - i2cproc_initialized ++; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ return 0; } @@ -687,27 +543,8 @@ { if (i2cproc_initialized >= 1) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) remove_proc_entry("i2c",proc_bus); i2cproc_initialized -= 2; -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - int res; - if (i2cproc_initialized >= 2) { - if ((res = proc_unregister(&proc_bus_dir, - proc_bus_i2c_dir.low_ino))) { - printk("i2c-core.o: could not delete " - "/proc/bus/i2c, module not removed."); - return res; - } - i2cproc_initialized --; - } - if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) { - printk("i2c-core.o: could not delete /proc/bus/, " - "module not removed."); - return res; - } - i2cproc_initialized --; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ } return 0; } @@ -715,7 +552,7 @@ #endif /* def CONFIG_PROC_FS */ -/* --------------------------------------------------- +/* --------------------------------------------------- * dummy driver notification * --------------------------------------------------- */ @@ -724,16 +561,16 @@ { int i; for (i=0; iflags & I2C_DF_DUMMY)) - drivers[i]->attach_adapter(adap); + if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY)) + drivers[i]->attach_adapter(adap); } static void i2c_dummy_client(struct i2c_client *client) { int i; for (i=0; iflags & I2C_DF_DUMMY)) - drivers[i]->detach_client(client); + if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY)) + drivers[i]->detach_client(client); } @@ -747,7 +584,8 @@ int ret; if (adap->algo->master_xfer) { - DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",adap->name,num)); + DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n", + adap->name,num)); I2C_LOCK(adap); ret = adap->algo->master_xfer(adap,msgs,num); @@ -756,7 +594,7 @@ return ret; } else { printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", - adap->id); + adap->id); return -ENOSYS; } } @@ -786,7 +624,7 @@ return (ret == 1 )? count : ret; } else { printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", - client->adapter->id); + client->adapter->id); return -ENOSYS; } } @@ -819,7 +657,7 @@ return (ret == 1 )? count : ret; } else { printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", - client->adapter->id); + client->adapter->id); return -ENOSYS; } } @@ -855,128 +693,124 @@ struct i2c_client_address_data *address_data, i2c_client_found_addr_proc *found_proc) { - int addr,i,found,err; - int adap_id = i2c_adapter_id(adapter); + int addr,i,found,err; + int adap_id = i2c_adapter_id(adapter); + + /* Forget it if we can't probe using SMBUS_QUICK */ + if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) + return -1; + + for (addr = 0x00; addr <= 0x7f; addr++) { + + /* Skip if already in use */ + if (i2c_check_addr(adapter,addr)) + continue; + + /* If it is in one of the force entries, we don't do any detection + at all */ + found = 0; + + for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) { + if (((adap_id == address_data->force[i]) || + (address_data->force[i] == ANY_I2C_BUS)) && + (addr == address_data->force[i+1])) { + DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n", + adap_id,addr)); + if ((err = found_proc(adapter,addr,0,0))) + return err; + found = 1; + } + } + if (found) + continue; + + /* If this address is in one of the ignores, we can forget about + it right now */ + for (i = 0; + !found && (address_data->ignore[i] != I2C_CLIENT_END); + i += 2) { + if (((adap_id == address_data->ignore[i]) || + ((address_data->ignore[i] == ANY_I2C_BUS))) && + (addr == address_data->ignore[i+1])) { + DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, " + "addr %04x\n", adap_id ,addr)); + found = 1; + } + } + for (i = 0; + !found && (address_data->ignore_range[i] != I2C_CLIENT_END); + i += 3) { + if (((adap_id == address_data->ignore_range[i]) || + ((address_data->ignore_range[i]==ANY_I2C_BUS))) && + (addr >= address_data->ignore_range[i+1]) && + (addr <= address_data->ignore_range[i+2])) { + DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + found = 1; + } + } + if (found) + continue; + + /* Now, we will do a detection, but only if it is in the normal or + probe entries */ + for (i = 0; + !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); + i += 1) { + if (addr == address_data->normal_i2c[i]) { + found = 1; + DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, " + "addr %02x", adap_id,addr)); + } + } + + for (i = 0; + !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); + i += 2) { + if ((addr >= address_data->normal_i2c_range[i]) && + (addr <= address_data->normal_i2c_range[i+1])) { + found = 1; + DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + + for (i = 0; + !found && (address_data->probe[i] != I2C_CLIENT_END); + i += 2) { + if (((adap_id == address_data->probe[i]) || + ((address_data->probe[i] == ANY_I2C_BUS))) && + (addr == address_data->probe[i+1])) { + found = 1; + DEB2(printk("i2c-core.o: found probe parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + for (i = 0; + !found && (address_data->probe_range[i] != I2C_CLIENT_END); + i += 3) { + if (((adap_id == address_data->probe_range[i]) || + (address_data->probe_range[i] == ANY_I2C_BUS)) && + (addr >= address_data->probe_range[i+1]) && + (addr <= address_data->probe_range[i+2])) { + found = 1; + DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + if (!found) + continue; - /* Forget it if we can't probe using SMBUS_QUICK */ - if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) - return -1; - - for (addr = 0x00; - addr <= 0x7f; - addr++) { - - /* Skip if already in use */ - if (i2c_check_addr(adapter,addr)) - continue; - - /* If it is in one of the force entries, we don't do any detection - at all */ - found = 0; - - for (i = 0; - !found && (address_data->force[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->force[i]) || - (address_data->force[i] == ANY_I2C_BUS)) && - (addr == address_data->force[i+1])) { - DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n", - adap_id,addr)); - if ((err = found_proc(adapter,addr,0,0))) - return err; - found = 1; - } - } - if (found) - continue; - - /* If this address is in one of the ignores, we can forget about it - right now */ - for (i = 0; - !found && (address_data->ignore[i] != I2C_CLIENT_END); - i += 2) { - if (((adap_id == address_data->ignore[i]) || - ((address_data->ignore[i] == ANY_I2C_BUS))) && - (addr == address_data->ignore[i+1])) { - DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, " - "addr %04x\n", adap_id ,addr)); - found = 1; - } - } - for (i = 0; - !found && (address_data->ignore_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->ignore_range[i]) || - ((address_data->ignore_range[i]==ANY_I2C_BUS))) && - (addr >= address_data->ignore_range[i+1]) && - (addr <= address_data->ignore_range[i+2])) { - DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr)); - found = 1; - } - } - if (found) - continue; - - /* Now, we will do a detection, but only if it is in the normal or - probe entries */ - for (i = 0; - !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); - i += 1) { - if (addr == address_data->normal_i2c[i]) { - found = 1; - DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, " - "addr %02x", adap_id,addr)); - } - } - - for (i = 0; - !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); - i += 2) { - if ((addr >= address_data->normal_i2c_range[i]) && - (addr <= address_data->normal_i2c_range[i+1])) { - found = 1; - DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, " - "addr %04x\n", adap_id,addr)); - } - } - - for (i = 0; - !found && (address_data->probe[i] != I2C_CLIENT_END); - i += 2) { - if (((adap_id == address_data->probe[i]) || - ((address_data->probe[i] == ANY_I2C_BUS))) && - (addr == address_data->probe[i+1])) { - found = 1; - DEB2(printk("i2c-core.o: found probe parameter for adapter %d, " - "addr %04x\n", adap_id,addr)); - } - } - for (i = 0; - !found && (address_data->probe_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->probe_range[i]) || - (address_data->probe_range[i] == ANY_I2C_BUS)) && - (addr >= address_data->probe_range[i+1]) && - (addr <= address_data->probe_range[i+2])) { - found = 1; - DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr)); - } - } - if (!found) - continue; - - /* OK, so we really should examine this address. First check - whether there is some client here at all! */ - if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) - if ((err = found_proc(adapter,addr,0,-1))) - return err; - } - return 0; + /* OK, so we really should examine this address. First check + whether there is some client here at all! */ + if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + if ((err = found_proc(adapter,addr,0,-1))) + return err; + } + return 0; } -/* +++ frodo +/* * return id number for a specific adapter */ int i2c_adapter_id(struct i2c_adapter *adap) @@ -993,14 +827,14 @@ extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - value,0,I2C_SMBUS_QUICK,NULL); + value,0,I2C_SMBUS_QUICK,NULL); } extern s32 i2c_smbus_read_byte(struct i2c_client * client) { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) + I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) return -1; else return 0x0FF & data.byte; @@ -1009,26 +843,26 @@ extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); + I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); } extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) + I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) return -1; else return 0x0FF & data.byte; } -extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, - u8 command, u8 value) +extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command, + u8 value) { union i2c_smbus_data data; data.byte = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, + I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data); } @@ -1036,7 +870,7 @@ { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) + I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) return -1; else return 0x0FFFF & data.word; @@ -1048,8 +882,8 @@ union i2c_smbus_data data; data.word = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, - I2C_SMBUS_WORD_DATA,&data); + I2C_SMBUS_WRITE,command, + I2C_SMBUS_WORD_DATA,&data); } extern s32 i2c_smbus_process_call(struct i2c_client * client, @@ -1058,8 +892,8 @@ union i2c_smbus_data data; data.word = value; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, - I2C_SMBUS_PROC_CALL, &data)) + I2C_SMBUS_WRITE,command, + I2C_SMBUS_PROC_CALL, &data)) return -1; else return 0x0FFFF & data.word; @@ -1072,7 +906,7 @@ union i2c_smbus_data data; int i; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, + I2C_SMBUS_READ,command, I2C_SMBUS_BLOCK_DATA,&data)) return -1; else { @@ -1093,7 +927,7 @@ data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, + I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data); } @@ -1177,7 +1011,7 @@ size); return -1; } - + if (i2c_transfer(adapter, msg, num) < 0) return -1; @@ -1193,8 +1027,8 @@ case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; - } - return 0; + } + return 0; } @@ -1203,7 +1037,7 @@ union i2c_smbus_data * data) { s32 res; - flags = flags & I2C_M_TEN; + flags = flags & I2C_M_TEN; if (adapter->algo->smbus_xfer) { I2C_LOCK(adapter); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, @@ -1211,7 +1045,7 @@ I2C_UNLOCK(adapter); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, - command,size,data); + command,size,data); return res; } @@ -1220,22 +1054,22 @@ backward compatibility. */ u32 i2c_get_functionality (struct i2c_adapter *adap) { - if (adap->algo->functionality) - return adap->algo->functionality(adap); - else - return 0xffffffff; + if (adap->algo->functionality) + return adap->algo->functionality(adap); + else + return 0xffffffff; } int i2c_check_functionality (struct i2c_adapter *adap, u32 func) { - u32 adap_func = i2c_get_functionality (adap); - return (func & adap_func) == func; + u32 adap_func = i2c_get_functionality (adap); + return (func & adap_func) == func; } static int __init i2c_init(void) { - printk("i2c-core.o: i2c core module\n"); + printk("i2c-core.o: i2c core module\n"); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers)); adap_count=0; diff -ur --new-file old/linux/drivers/i2c/i2c-dev.c new/linux/drivers/i2c/i2c-dev.c --- old/linux/drivers/i2c/i2c-dev.c Thu Dec 30 02:29:43 1999 +++ new/linux/drivers/i2c/i2c-dev.c Sat Jan 29 04:36:23 2000 @@ -23,7 +23,7 @@ But I have used so much of his original code and ideas that it seems only fair to recognize him as co-author -- Frodo */ -/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-dev.c,v 1.25 2000/01/26 14:14:20 frodo Exp $ */ #include #include @@ -34,34 +34,8 @@ /* If you want debugging uncomment: */ /* #define DEBUG */ -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,51) #include -#else -#define __init -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4)) -#define copy_from_user memcpy_fromfs -#define copy_to_user memcpy_tofs -#define get_user_data(to,from) ((to) = get_user(from),0) -#else #include -#define get_user_data(to,from) get_user(to,from) -#endif - -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif #include #include @@ -73,45 +47,18 @@ /* struct file_operations changed too often in the 2.1 series for nice code */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) -static long long i2cdev_lseek (struct file *file, long long offset, int origin); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long long i2cdev_llseek (struct inode *inode, struct file *file, - long long offset, int origin); -#else -static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, - int origin); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, loff_t *offset); static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, loff_t *offset); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_read (struct inode *inode, struct file *file, char *buf, - unsigned long count); -static long i2cdev_write (struct inode *inode, struct file *file, - const char *buf, unsigned long offset); -#else -static int i2cdev_read(struct inode *inode, struct file *file, char *buf, - int count); -static int i2cdev_write(struct inode *inode, struct file *file, - const char *buf, int count); -#endif static int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int i2cdev_open (struct inode *inode, struct file *file); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) static int i2cdev_release (struct inode *inode, struct file *file); -#else -static void i2cdev_release (struct inode *inode, struct file *file); -#endif - static int i2cdev_attach_adapter(struct i2c_adapter *adap); static int i2cdev_detach_client(struct i2c_client *client); @@ -127,413 +74,349 @@ static int i2cdev_cleanup(void); static struct file_operations i2cdev_fops = { - i2cdev_lseek, - i2cdev_read, - i2cdev_write, - NULL, /* i2cdev_readdir */ - NULL, /* i2cdev_select */ - i2cdev_ioctl, - NULL, /* i2cdev_mmap */ - i2cdev_open, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) - NULL, /* i2cdev_flush */ -#endif - i2cdev_release, + i2cdev_lseek, + i2cdev_read, + i2cdev_write, + NULL, /* i2cdev_readdir */ + NULL, /* i2cdev_select */ + i2cdev_ioctl, + NULL, /* i2cdev_mmap */ + i2cdev_open, + NULL, /* i2cdev_flush */ + i2cdev_release, }; #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX]; static struct i2c_driver i2cdev_driver = { - /* name */ "i2c-dev dummy driver", - /* id */ I2C_DRIVERID_I2CDEV, - /* flags */ I2C_DF_DUMMY, - /* attach_adapter */ i2cdev_attach_adapter, - /* detach_client */ i2cdev_detach_client, - /* command */ i2cdev_command, - /* inc_use */ NULL, - /* dec_use */ NULL, + /* name */ "i2c-dev dummy driver", + /* id */ I2C_DRIVERID_I2CDEV, + /* flags */ I2C_DF_DUMMY, + /* attach_adapter */ i2cdev_attach_adapter, + /* detach_client */ i2cdev_detach_client, + /* command */ i2cdev_command, + /* inc_use */ NULL, + /* dec_use */ NULL, }; static struct i2c_client i2cdev_client_template = { - /* name */ "I2C /dev entry", - /* id */ 1, - /* flags */ 0, - /* addr */ -1, - /* adapter */ NULL, - /* driver */ &i2cdev_driver, - /* data */ NULL + /* name */ "I2C /dev entry", + /* id */ 1, + /* flags */ 0, + /* addr */ -1, + /* adapter */ NULL, + /* driver */ &i2cdev_driver, + /* data */ NULL }; static int i2cdev_initialized; /* Note that the lseek function is called llseek in 2.1 kernels. But things are complicated enough as is. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) -long long i2cdev_lseek (struct file *file, long long offset, int origin) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -long long i2cdev_llseek (struct inode *inode, struct file *file, - long long offset, int origin) -#else -int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, - int origin) -#endif { #ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ - printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n", - MINOR(inode->i_rdev),(long) offset,origin); + struct inode *inode = file->f_dentry->d_inode; + printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n", + MINOR(inode->i_rdev),(long) offset,origin); #endif /* DEBUG */ - return -ESPIPE; + return -ESPIPE; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, loff_t *offset) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_read (struct inode *inode, struct file *file, char *buf, - unsigned long count) -#else -static int i2cdev_read(struct inode *inode, struct file *file, char *buf, - int count) -#endif { - char *tmp; - int ret; + char *tmp; + int ret; #ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ + struct inode *inode = file->f_dentry->d_inode; #endif /* DEBUG */ - struct i2c_client *client = (struct i2c_client *)file->private_data; + struct i2c_client *client = (struct i2c_client *)file->private_data; - /* copy user space data to kernel space. */ - tmp = kmalloc(count,GFP_KERNEL); - if (tmp==NULL) - return -ENOMEM; + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; #ifdef DEBUG - printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count); + printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), + count); #endif - ret = i2c_master_recv(client,tmp,count); - copy_to_user(buf,tmp,count); - kfree(tmp); - return ret; + ret = i2c_master_recv(client,tmp,count); + if (! ret) + ret = copy_to_user(buf,tmp,count)?-EFAULT:0; + kfree(tmp); + return ret; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, loff_t *offset) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_write (struct inode *inode, struct file *file, - const char *buf, unsigned long offset) -#else -static int i2cdev_write(struct inode *inode, struct file *file, - const char *buf, int count) -#endif { - int ret; - char *tmp; - struct i2c_client *client = (struct i2c_client *)file->private_data; + int ret; + char *tmp; + struct i2c_client *client = (struct i2c_client *)file->private_data; #ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ + struct inode *inode = file->f_dentry->d_inode; #endif /* DEBUG */ - /* copy user space data to kernel space. */ - tmp = kmalloc(count,GFP_KERNEL); - if (tmp==NULL) - return -ENOMEM; - copy_from_user(tmp,buf,count); - -#ifdef DEBUG - printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count); -#endif - ret = i2c_master_send(client,tmp,count); - kfree(tmp); - return ret; + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + if (copy_from_user(tmp,buf,count)) { + kfree(tmp); + return -EFAULT; + } + +#ifdef DEBUG + printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), + count); +#endif + ret = i2c_master_send(client,tmp,count); + kfree(tmp); + return ret; } int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = (struct i2c_client *)file->private_data; - struct i2c_smbus_ioctl_data data_arg; - union i2c_smbus_data temp; - int ver,datasize,res; - unsigned long funcs; + struct i2c_client *client = (struct i2c_client *)file->private_data; + struct i2c_smbus_ioctl_data data_arg; + union i2c_smbus_data temp; + int datasize,res; + unsigned long funcs; #ifdef DEBUG - printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); + printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", + MINOR(inode->i_rdev),cmd, arg); #endif /* DEBUG */ - switch ( cmd ) { - case I2C_SLAVE: - case I2C_SLAVE_FORCE: - if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) - return -EINVAL; - if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg)) - return -EBUSY; - client->addr = arg; - return 0; - case I2C_TENBIT: - if (arg) - client->flags |= I2C_M_TEN; - else - client->flags &= ~I2C_M_TEN; - return 0; - case I2C_FUNCS: - if (! arg) { -#ifdef DEBUG - printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n"); -#endif - return -EINVAL; - } - if (verify_area(VERIFY_WRITE,(unsigned long *) arg, - sizeof(unsigned long))) { -#ifdef DEBUG - printk("i2c-dev.o: invalid argument pointer (%ld) " - "in IOCTL I2C_SMBUS.\n", arg); -#endif - return -EINVAL; - } - - funcs = i2c_get_functionality(client->adapter); - copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long)); - return 0; - case I2C_SMBUS: - if (! arg) { -#ifdef DEBUG - printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n"); -#endif - return -EINVAL; - } - if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg, - sizeof(struct i2c_smbus_ioctl_data))) { -#ifdef DEBUG - printk("i2c-dev.o: invalid argument pointer (%ld) " - "in IOCTL I2C_SMBUS.\n", arg); -#endif - return -EINVAL; - } - copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg, - sizeof(struct i2c_smbus_ioctl_data)); - if ((data_arg.size != I2C_SMBUS_BYTE) && - (data_arg.size != I2C_SMBUS_QUICK) && - (data_arg.size != I2C_SMBUS_BYTE_DATA) && - (data_arg.size != I2C_SMBUS_WORD_DATA) && - (data_arg.size != I2C_SMBUS_PROC_CALL) && - (data_arg.size != I2C_SMBUS_BLOCK_DATA)) { -#ifdef DEBUG - printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.size); -#endif - return -EINVAL; - } - /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, - so the check is valid if size==I2C_SMBUS_QUICK too. */ - if ((data_arg.read_write != I2C_SMBUS_READ) && - (data_arg.read_write != I2C_SMBUS_WRITE)) { -#ifdef DEBUG - printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.read_write); -#endif - return -EINVAL; - } - - /* Note that command values are always valid! */ - - if ((data_arg.size == I2C_SMBUS_QUICK) || - ((data_arg.size == I2C_SMBUS_BYTE) && - (data_arg.read_write == I2C_SMBUS_WRITE))) - /* These are special: we do not use data */ - return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - data_arg.read_write, data_arg.command, - data_arg.size, NULL); - - if (data_arg.data == NULL) { -#ifdef DEBUG - printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); -#endif - return -EINVAL; - } - - /* This seems unlogical but it is not: if the user wants to read a - value, we must write that value to user memory! */ - ver = ((data_arg.read_write == I2C_SMBUS_WRITE) && - (data_arg.size != I2C_SMBUS_PROC_CALL))?VERIFY_READ:VERIFY_WRITE; - - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || - (data_arg.size == I2C_SMBUS_PROC_CALL)) - datasize = sizeof(data_arg.data->word); - else /* size == I2C_SMBUS_BLOCK_DATA */ - datasize = sizeof(data_arg.data->block); - - if (verify_area(ver,data_arg.data,datasize)) { -#ifdef DEBUG - printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n", - data_arg.data); -#endif - return -EINVAL; - } - - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_WRITE)) - copy_from_user(&temp,data_arg.data,datasize); - res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, - data_arg.read_write, - data_arg.command,data_arg.size,&temp); - if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) - copy_to_user(data_arg.data,&temp,datasize); - return res; - - default: - return i2c_control(client,cmd,arg); - } - return 0; + switch ( cmd ) { + case I2C_SLAVE: + case I2C_SLAVE_FORCE: + if ((arg > 0x3ff) || + (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) + return -EINVAL; + if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg)) + return -EBUSY; + client->addr = arg; + return 0; + case I2C_TENBIT: + if (arg) + client->flags |= I2C_M_TEN; + else + client->flags &= ~I2C_M_TEN; + return 0; + case I2C_FUNCS: + funcs = i2c_get_functionality(client->adapter); + return (copy_to_user((unsigned long *)arg,&funcs, + sizeof(unsigned long)))?-EFAULT:0; + case I2C_SMBUS: + copy_from_user_ret(&data_arg, + (struct i2c_smbus_ioctl_data *) arg, + sizeof(struct i2c_smbus_ioctl_data), + -EFAULT); + if ((data_arg.size != I2C_SMBUS_BYTE) && + (data_arg.size != I2C_SMBUS_QUICK) && + (data_arg.size != I2C_SMBUS_BYTE_DATA) && + (data_arg.size != I2C_SMBUS_WORD_DATA) && + (data_arg.size != I2C_SMBUS_PROC_CALL) && + (data_arg.size != I2C_SMBUS_BLOCK_DATA)) { +#ifdef DEBUG + printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", + data_arg.size); +#endif + return -EINVAL; + } + /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, + so the check is valid if size==I2C_SMBUS_QUICK too. */ + if ((data_arg.read_write != I2C_SMBUS_READ) && + (data_arg.read_write != I2C_SMBUS_WRITE)) { +#ifdef DEBUG + printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", + data_arg.read_write); +#endif + return -EINVAL; + } + + /* Note that command values are always valid! */ + + if ((data_arg.size == I2C_SMBUS_QUICK) || + ((data_arg.size == I2C_SMBUS_BYTE) && + (data_arg.read_write == I2C_SMBUS_WRITE))) + /* These are special: we do not use data */ + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags, + data_arg.read_write, + data_arg.command, + data_arg.size, NULL); + + if (data_arg.data == NULL) { +#ifdef DEBUG + printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); +#endif + return -EINVAL; + } + + if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || + (data_arg.size == I2C_SMBUS_BYTE)) + datasize = sizeof(data_arg.data->byte); + else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || + (data_arg.size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data_arg.data->word); + else /* size == I2C_SMBUS_BLOCK_DATA */ + datasize = sizeof(data_arg.data->block); + + if ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_WRITE)) + copy_from_user_ret(&temp,data_arg.data,datasize, + -EFAULT); + res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, + data_arg.read_write, + data_arg.command,data_arg.size,&temp); + if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_READ))) + copy_to_user_ret(data_arg.data,&temp,datasize,-EFAULT); + return res; + + default: + return i2c_control(client,cmd,arg); + } + return 0; } int i2cdev_open (struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - struct i2c_client *client; + unsigned int minor = MINOR(inode->i_rdev); + struct i2c_client *client; - if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { + if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { #ifdef DEBUG - printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor); + printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n", + minor); #endif - return -ENODEV; - } + return -ENODEV; + } - /* Note that we here allocate a client for later use, but we will *not* - register this client! Yes, this is safe. No, it is not very clean. */ - if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); - client->adapter = i2cdev_adaps[minor]; - file->private_data = client; + /* Note that we here allocate a client for later use, but we will *not* + register this client! Yes, this is safe. No, it is not very clean. */ + if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); + client->adapter = i2cdev_adaps[minor]; + file->private_data = client; - i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); - MOD_INC_USE_COUNT; + if (i2cdev_adaps[minor]->inc_use) + i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); + MOD_INC_USE_COUNT; #ifdef DEBUG - printk("i2c-dev.o: opened i2c-%d\n",minor); + printk("i2c-dev.o: opened i2c-%d\n",minor); #endif - return 0; + return 0; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) static int i2cdev_release (struct inode *inode, struct file *file) -#else -static void i2cdev_release (struct inode *inode, struct file *file) -#endif { - unsigned int minor = MINOR(inode->i_rdev); - kfree(file->private_data); - file->private_data=NULL; -#ifdef DEBUG - printk("i2c-dev.o: Closed: i2c-%d\n", minor); -#endif - MOD_DEC_USE_COUNT; - i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) - return 0; -#endif + unsigned int minor = MINOR(inode->i_rdev); + kfree(file->private_data); + file->private_data=NULL; +#ifdef DEBUG + printk("i2c-dev.o: Closed: i2c-%d\n", minor); +#endif + MOD_DEC_USE_COUNT; + if (i2cdev_adaps[minor]->dec_use) + i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); + return 0; } int i2cdev_attach_adapter(struct i2c_adapter *adap) { - int i; + int i; - if ((i = i2c_adapter_id(adap)) < 0) { - printk("i2c-dev.o: Unknown adapter ?!?\n"); - return -ENODEV; - } - if (i >= I2CDEV_ADAPS_MAX) { - printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i); - return -ENODEV; - } - - if (! i2cdev_adaps[i]) { - i2cdev_adaps[i] = adap; - printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); - } else { - i2cdev_adaps[i] = NULL; + if ((i = i2c_adapter_id(adap)) < 0) { + printk("i2c-dev.o: Unknown adapter ?!?\n"); + return -ENODEV; + } + if (i >= I2CDEV_ADAPS_MAX) { + printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i); + return -ENODEV; + } + + if (! i2cdev_adaps[i]) { + i2cdev_adaps[i] = adap; + printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + } else { + i2cdev_adaps[i] = NULL; #ifdef DEBUG - printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); + printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); #endif - } + } - return 0; + return 0; } int i2cdev_detach_client(struct i2c_client *client) { - return 0; + return 0; } static int i2cdev_command(struct i2c_client *client, unsigned int cmd, void *arg) { - return -1; + return -1; } int __init i2c_dev_init(void) { - int res; + int res; - printk("i2c-dev.o: i2c /dev entries driver module\n"); + printk("i2c-dev.o: i2c /dev entries driver module\n"); - i2cdev_initialized = 0; - if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { - printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR); - return -EIO; - } - i2cdev_initialized ++; - - if ((res = i2c_add_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); - i2cdev_cleanup(); - return res; - } - i2cdev_initialized ++; - return 0; + i2cdev_initialized = 0; + if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { + printk("i2c-dev.o: unable to get major %d for i2c bus\n", + I2C_MAJOR); + return -EIO; + } + i2cdev_initialized ++; + + if ((res = i2c_add_driver(&i2cdev_driver))) { + printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); + i2cdev_cleanup(); + return res; + } + i2cdev_initialized ++; + return 0; } int i2cdev_cleanup(void) { - int res; + int res; - if (i2cdev_initialized >= 2) { - if ((res = i2c_del_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver deregistration failed, " - "module not removed.\n"); - return res; - } - i2cdev_initialized ++; - } - - if (i2cdev_initialized >= 1) { - if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { - printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR); - return res; - } - i2cdev_initialized --; - } - return 0; + if (i2cdev_initialized >= 2) { + if ((res = i2c_del_driver(&i2cdev_driver))) { + printk("i2c-dev.o: Driver deregistration failed, " + "module not removed.\n"); + return res; + } + i2cdev_initialized ++; + } + + if (i2cdev_initialized >= 1) { + if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { + printk("i2c-dev.o: unable to release major %d for i2c bus\n", + I2C_MAJOR); + return res; + } + i2cdev_initialized --; + } + return 0; } EXPORT_NO_SYMBOLS; @@ -545,12 +428,12 @@ int init_module(void) { - return i2c_dev_init(); + return i2c_dev_init(); } int cleanup_module(void) { - return i2cdev_cleanup(); + return i2cdev_cleanup(); } #endif /* def MODULE */ diff -ur --new-file old/linux/drivers/i2c/i2c-elektor.c new/linux/drivers/i2c/i2c-elektor.c --- old/linux/drivers/i2c/i2c-elektor.c Thu Dec 30 02:29:43 1999 +++ new/linux/drivers/i2c/i2c-elektor.c Sat Jan 29 04:36:23 2000 @@ -22,7 +22,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-elektor.c,v 1.16 2000/01/24 02:06:33 mds Exp $ */ #include #include @@ -30,24 +30,10 @@ #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif #include #include -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - #include #include #include @@ -87,56 +73,48 @@ static void pcf_isa_setbyte(void *data, int ctl, int val) { - if (ctl) { - if (gpi.pi_irq > 0) { - DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val|I2C_PCF_ENI)); - outb(val | I2C_PCF_ENI, CTRL); - } else { - DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val)); - outb(val, CTRL); - } - } else { - DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val)); - outb(val, DATA); - } + if (ctl) { + if (gpi.pi_irq > 0) { + DEB3(printk("i2c-elektor.o: Write control 0x%x\n", + val|I2C_PCF_ENI)); + outb(val | I2C_PCF_ENI, CTRL); + } else { + DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val)); + outb(val, CTRL); + } + } else { + DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val)); + outb(val, DATA); + } } static int pcf_isa_getbyte(void *data, int ctl) { - int val; + int val; - if (ctl) { - val = inb(CTRL); - DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val)); - } else { - val = inb(DATA); - DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val)); - } - return (val); + if (ctl) { + val = inb(CTRL); + DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val)); + } else { + val = inb(DATA); + DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val)); + } + return (val); } static int pcf_isa_getown(void *data) { - return (gpi.pi_own); + return (gpi.pi_own); } static int pcf_isa_getclock(void *data) { - return (gpi.pi_clock); + return (gpi.pi_clock); } -#if LINUX_VERSION_CODE < 0x02017f -static void schedule_timeout(int j) -{ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + j; - schedule(); -} -#endif - #if 0 static void pcf_isa_sleep(unsigned long timeout) { @@ -147,64 +125,53 @@ static void pcf_isa_waitforpin(void) { - int timeout = 2; + int timeout = 2; - if (gpi.pi_irq > 0) { - cli(); - if (pcf_pending == 0) { -#if LINUX_VERSION_CODE < 0x02017f - current->timeout = jiffies + timeout * HZ; - interruptible_sleep_on(&pcf_wait); -#else - interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ ); -#endif - } - else - pcf_pending = 0; - sti(); -#if LINUX_VERSION_CODE < 0x02017f - current->timeout = 0; -#endif - } - else { - udelay(100); - } + if (gpi.pi_irq > 0) { + cli(); + if (pcf_pending == 0) { + interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ ); + } else + pcf_pending = 0; + sti(); + } else { + udelay(100); + } } static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) { - - pcf_pending = 1; - wake_up_interruptible(&pcf_wait); + pcf_pending = 1; + wake_up_interruptible(&pcf_wait); } static int pcf_isa_init(void) { - if (check_region(gpi.pi_base, 2) < 0 ) { - return -ENODEV; - } else { - request_region(gpi.pi_base, 2, "i2c (isa bus adapter)"); - } - if (gpi.pi_irq > 0) { - if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) { - printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq); - gpi.pi_irq = 0; - } - else - enable_irq(gpi.pi_irq); - } - return 0; + if (check_region(gpi.pi_base, 2) < 0 ) { + return -ENODEV; + } else { + request_region(gpi.pi_base, 2, "i2c (isa bus adapter)"); + } + if (gpi.pi_irq > 0) { + if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) + < 0) { + printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq); + gpi.pi_irq = 0; + } else + enable_irq(gpi.pi_irq); + } + return 0; } static void pcf_isa_exit(void) { - if (gpi.pi_irq > 0) { - disable_irq(gpi.pi_irq); - free_irq(gpi.pi_irq, 0); - } - release_region(gpi.pi_base , 2); + if (gpi.pi_irq > 0) { + disable_irq(gpi.pi_irq); + free_irq(gpi.pi_irq, 0); + } + release_region(gpi.pi_base , 2); } @@ -222,14 +189,14 @@ static void pcf_isa_inc_use(struct i2c_adapter *adap) { #ifdef MODULE - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; #endif } static void pcf_isa_dec_use(struct i2c_adapter *adap) { #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif } @@ -262,41 +229,41 @@ int __init i2c_pcfisa_init(void) { - struct i2c_pcf_isa *pisa = &gpi; + struct i2c_pcf_isa *pisa = &gpi; - printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n"); - if (base == 0) - pisa->pi_base = DEFAULT_BASE; - else - pisa->pi_base = base; - - if (irq == 0) - pisa->pi_irq = DEFAULT_IRQ; - else - pisa->pi_irq = irq; - - if (clock == 0) - pisa->pi_clock = DEFAULT_CLOCK; - else - pisa->pi_clock = clock; - - if (own == 0) - pisa->pi_own = DEFAULT_OWN; - else - pisa->pi_own = own; + printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n"); + if (base == 0) + pisa->pi_base = DEFAULT_BASE; + else + pisa->pi_base = base; + + if (irq == 0) + pisa->pi_irq = DEFAULT_IRQ; + else + pisa->pi_irq = irq; + + if (clock == 0) + pisa->pi_clock = DEFAULT_CLOCK; + else + pisa->pi_clock = clock; + + if (own == 0) + pisa->pi_own = DEFAULT_OWN; + else + pisa->pi_own = own; - pcf_isa_data.data = (void *)pisa; + pcf_isa_data.data = (void *)pisa; #if (LINUX_VERSION_CODE >= 0x020301) - init_waitqueue_head(&pcf_wait); + init_waitqueue_head(&pcf_wait); #endif - if (pcf_isa_init() == 0) { - if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) - return -ENODEV; - } else { - return -ENODEV; - } - printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base); - return 0; + if (pcf_isa_init() == 0) { + if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base); + return 0; } @@ -313,7 +280,7 @@ int init_module(void) { - return i2c_pcfisa_init(); + return i2c_pcfisa_init(); } void cleanup_module(void) diff -ur --new-file old/linux/drivers/i2c/i2c-pcf8584.h new/linux/drivers/i2c/i2c-pcf8584.h --- old/linux/drivers/i2c/i2c-pcf8584.h Thu Dec 30 02:29:43 1999 +++ new/linux/drivers/i2c/i2c-pcf8584.h Sat Jan 29 04:36:23 2000 @@ -21,20 +21,20 @@ /* With some changes from Frodo Looijaard */ -/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-pcf8584.h,v 1.3 2000/01/18 23:54:07 frodo Exp $ */ #ifndef I2C_PCF8584_H #define I2C_PCF8584_H 1 /* ----- Control register bits ---------------------------------------- */ -#define I2C_PCF_PIN 0x80 -#define I2C_PCF_ESO 0x40 -#define I2C_PCF_ES1 0x20 -#define I2C_PCF_ES2 0x10 -#define I2C_PCF_ENI 0x08 -#define I2C_PCF_STA 0x04 -#define I2C_PCF_STO 0x02 -#define I2C_PCF_ACK 0x01 +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 #define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) #define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) @@ -45,7 +45,7 @@ /*#define I2C_PCF_PIN 0x80 as above*/ #define I2C_PCF_INI 0x40 /* 1 if not initialized */ -#define I2C_PCF_STS 0x20 +#define I2C_PCF_STS 0x20 #define I2C_PCF_BER 0x10 #define I2C_PCF_AD0 0x08 #define I2C_PCF_LRB 0x08 @@ -54,17 +54,17 @@ #define I2C_PCF_BB 0x01 /* ----- Chip clock frequencies --------------------------------------- */ -#define I2C_PCF_CLK3 0x00 -#define I2C_PCF_CLK443 0x10 -#define I2C_PCF_CLK6 0x14 -#define I2C_PCF_CLK8 0x18 -#define I2C_PCF_CLK12 0x1c +#define I2C_PCF_CLK3 0x00 +#define I2C_PCF_CLK443 0x10 +#define I2C_PCF_CLK6 0x14 +#define I2C_PCF_CLK 0x18 +#define I2C_PCF_CLK12 0x1c /* ----- transmission frequencies ------------------------------------- */ -#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ -#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ -#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ -#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ +#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ +#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ +#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ +#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ /* ----- Access to internal registers according to ES1,ES2 ------------ */ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_syms.c new/linux/drivers/ieee1394/ieee1394_syms.c --- old/linux/drivers/ieee1394/ieee1394_syms.c Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/ieee1394/ieee1394_syms.c Mon Jan 31 19:13:03 2000 @@ -39,6 +39,7 @@ EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); EXPORT_SYMBOL(hpsb_make_writebpacket); +EXPORT_SYMBOL(hpsb_make_lockpacket); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_transactions.c new/linux/drivers/ieee1394/ieee1394_transactions.c --- old/linux/drivers/ieee1394/ieee1394_transactions.c Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/ieee1394/ieee1394_transactions.c Mon Jan 31 19:13:03 2000 @@ -329,6 +329,30 @@ return p; } +struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(8); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + fill_async_lock(p, addr, extcode, 4); + break; + default: + fill_async_lock(p, addr, extcode, 8); + break; + } + + return p; +} /* * FIXME - these functions should probably read from / write to user space to diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_transactions.h new/linux/drivers/ieee1394/ieee1394_transactions.h --- old/linux/drivers/ieee1394/ieee1394_transactions.h Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/ieee1394/ieee1394_transactions.h Mon Jan 31 19:13:03 2000 @@ -39,6 +39,9 @@ struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host, nodeid_t node, u64 addr, size_t length); +struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode); + /* * hpsb_packet_success - Make sense of the ack and reply codes and diff -ur --new-file old/linux/drivers/ieee1394/ohci1394.c new/linux/drivers/ieee1394/ohci1394.c --- old/linux/drivers/ieee1394/ohci1394.c Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/ieee1394/ohci1394.c Tue Feb 1 08:43:51 2000 @@ -1,5 +1,5 @@ /* - * ti_ohci1394.c - Texas Instruments Ohci1394 driver + * ohci1394.c - driver for OHCI 1394 boards * Copyright (C)1999,2000 Sebastien Rougeaux * Gord Peters * @@ -18,6 +18,7 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include #include @@ -40,8 +41,6 @@ #include "ieee1394_core.h" #include "ohci1394.h" -#undef CONFIG_PROC_FS - /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) \ printk(level "ohci1394: " fmt "\n" , ## args) @@ -68,7 +67,6 @@ * IEEE-1394 functionality section * ***********************************/ - #if 0 /* not needed at this time */ static int get_phy_reg(struct ti_ohci *ohci, int addr) { @@ -324,31 +322,53 @@ } /* Initialize AR dma */ - ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE; - ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf); - ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE; - PRINT(KERN_INFO, ohci->id, "AR control: %x", - ohci->AR_resp_prg->control); - PRINT(KERN_INFO, ohci->id, "AR status: %x %d", - ohci->AR_resp_prg->status & 0xffff, - ohci->AR_resp_prg->status & 0xffff); - - /* Tell the controller where the AR program is */ - reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, - virt_to_bus(ohci->AR_resp_prg)|0x00000001); + /* make sure the context isn't running, dead, or active */ + if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) { -#if 1 - /* Accept phy packets into AR request context */ - reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); -#endif + /* initialize AR program */ + for (i= 0; i < AR_RESP_NUM_DESC; i++) { + + /* end of descriptor list? */ + if ((i + 1) < AR_RESP_NUM_DESC) { + ohci->AR_resp_prg[i]->control= + (0x283C << 16) | AR_RESP_BUF_SIZE; + ohci->AR_resp_prg[i]->branchAddress= + (virt_to_bus(ohci->AR_resp_prg[i + 1]) + & 0xfffffff0) | 0x1; + } else { + ohci->AR_resp_prg[i]->control= + (0x283C << 16) | AR_RESP_BUF_SIZE; + ohci->AR_resp_prg[i]->branchAddress= + (virt_to_bus(ohci->AR_resp_prg[0]) + & 0xfffffff0) | 0x1; + } + + ohci->AR_resp_prg[i]->address= + virt_to_bus(ohci->AR_resp_buf[i]); + ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE; + } + + /* Tell the controller where the first AR program is */ + reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, + virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 ); + + /* Accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); + + /* Run AR context */ + reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000); + } - /* Run AR context */ - reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000); + /* Specify AT retries */ + reg_write(ohci, OHCI1394_ATRetries, + OHCI1394_MAX_AT_REQ_RETRIES | + (OHCI1394_MAX_AT_RESP_RETRIES<<4) | + (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); #ifndef __BIG_ENDIAN - reg_write(ohci, OHCI1394_HCControlSet, 0x40000000); -#else reg_write(ohci, OHCI1394_HCControlClear, 0x40000000); +#else + reg_write(ohci, OHCI1394_HCControlSet, 0x40000000); #endif /* Enable interrupts */ @@ -386,8 +406,9 @@ int i=0; struct hpsb_packet *packet = ohci->async_queue; struct dma_cmd prg; +#if 0 quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg; - +#endif //HPSB_TRACE(); /* stop the channel program if it's still running */ @@ -435,14 +456,14 @@ prg.status = 0; memcpy(ohci->AT_req_prg, &prg, 16); memcpy(ohci->AT_req_prg + 1, packet->header, 16); - +#if 0 PRINT(KERN_INFO, ohci->id, "dma_cmd: %08x %08x %08x %08x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); PRINT(KERN_INFO, ohci->id, "header: %08x %08x %08x %08x", *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); - +#endif reg_write(ohci, OHCI1394_AsReqTrCommandPtr, virt_to_bus(ohci->AT_req_prg)|0x2); } @@ -455,11 +476,11 @@ prg.branchAddress = 0; prg.status = 0; memcpy(ohci->AT_req_prg, &prg, 16); - +#if 0 PRINT(KERN_INFO, ohci->id, "dma_cmd: %08x %08x %08x %08x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); - +#endif reg_write(ohci, OHCI1394_AsReqTrCommandPtr, virt_to_bus(ohci->AT_req_prg)|0x2); } @@ -638,6 +659,26 @@ * Global stuff (interrupt handler, init/shutdown code) * ********************************************************/ +static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg) +{ + int i=0; + + /* stop the channel program if it's still running */ + reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000); + + /* Wait until it effectively stops */ + while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) + & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, ohci->id, + "runaway loop in Dma Ar Resp. bailing out..."); + break; + } + } + PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg); +} + static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) { @@ -656,15 +697,14 @@ event,reg_read(ohci, OHCI1394_IntMaskSet)); */ if (event & OHCI1394_busReset) { +#if 0 PRINT(KERN_INFO, ohci->id, "bus reset interrupt"); +#endif if (!host->in_bus_reset) { hpsb_bus_reset(host); } ohci->NumBusResets++; } - if (event & OHCI1394_reqTxComplete) { - PRINT(KERN_INFO, ohci->id, "reqTxComplete int received"); - } if (event & OHCI1394_RQPkt) { PRINT(KERN_INFO, ohci->id, "RQPkt int received"); } @@ -673,58 +713,55 @@ reg_read(ohci, OHCI1394_AsReqRcvContextControlSet)); } if (event & OHCI1394_RSPkt) { - int rcv_bytes; - int i=0; + unsigned int idx,offset,rescount; - /* we calculate the number of received bytes from the - residual count field */ - rcv_bytes = AR_RESP_BUF_SIZE - - (ohci->AR_resp_prg->status & 0xFFFF); - - PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read", - ohci->AR_resp_prg->status, - ohci->AR_resp_prg->status & 0xffff, - rcv_bytes); - - ohci->AR_resp_active = 0; - - if ((ohci->AR_resp_prg->status & 0x84000000) - && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) { - hpsb_packet_received(host, ohci->AR_resp_buf, - rcv_bytes); - } else { - //HPSB_TRACE(); - PRINT(KERN_ERR, ohci->id, - "AR resp DMA program status value 0x%x is incorrect!", - ohci->AR_resp_prg->status); - } + spin_lock(&ohci->AR_resp_lock); + idx = ohci->AR_resp_buf_th_ind; + offset = ohci->AR_resp_buf_th_offset; - /* --------------- FIXME --------------------------------- - this is a complete hack... we stop the dma prg - and start it again so as to reset the dma buffer address - Very slow, very bad design... to change ASAP */ - - /* stop the channel program if it's still running */ - reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000); - - /* Wait until it effectively stops */ - while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) - & 0x400) { - i++; - if (i>5000) { - PRINT(KERN_ERR, ohci->id, - "runaway loop in DmaAT. bailing out..."); - break; + rescount = ohci->AR_resp_prg[idx]->status&0xffff; + ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE - rescount - offset; + offset = AR_RESP_BUF_SIZE - rescount; + + if (!rescount) { /* We cross a buffer boundary */ + idx = (idx+1) % AR_RESP_NUM_DESC; + +#if 0 + /* This bit of code does not work */ + /* Let's see how many bytes were written in the async response + receive buf since last interrupt. This is done by finding + the next active context (See OHCI Spec p91) */ + while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) { + if (ohci->AR_resp_prg[idx]->status&0x04000000) break; + idx = (idx+1) % AR_RESP_NUM_DESC; + PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!"); + ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE; } +#endif + /* ASSUMPTION: only one buffer boundary is crossed */ + rescount = ohci->AR_resp_prg[idx]->status&0xffff; + offset = AR_RESP_BUF_SIZE - rescount; + ohci->AR_resp_bytes_left += offset; + } + if (offset==AR_RESP_BUF_SIZE) { + offset=0; + idx = (idx+1) % AR_RESP_NUM_DESC; } + ohci->AR_resp_buf_th_ind = idx; + ohci->AR_resp_buf_th_offset = offset; - reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, - virt_to_bus(ohci->AR_resp_prg)|0x00000001); - ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE; - reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000); + /* is buffer processing too slow? (all buffers used) */ + if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) { + stop_ar_resp_context(ohci,"async response receive processing too slow"); + spin_unlock(&ohci->AR_resp_lock); + return; + } + spin_unlock(&ohci->AR_resp_lock); - /* ---------------- end of FIXME --------------------------*/ + /* queue bottom half in immediate queue */ + queue_task(&ohci->AR_resp_pdl_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; @@ -826,8 +863,10 @@ send_next_async(ohci); } spin_unlock(&ohci->async_queue_lock); +#if 0 PRINT(KERN_INFO,ohci->id, "packet sent with ack code %d",ack); +#endif hpsb_packet_sent(host, packet, ack); } else PRINT(KERN_INFO,ohci->id, @@ -839,6 +878,129 @@ ohci->NumInterrupts++; } + +/* This is the bottom half that processes async response receive descriptor buffers. */ +static void ohci_ar_resp_proc_desc(void *data) +{ + quadlet_t *buf_ptr; + char *split_ptr; + unsigned int split_left; + struct ti_ohci *ohci= (struct ti_ohci*)data; + unsigned int packet_length; + unsigned int idx,offset,tcode; + unsigned long flags; + char msg[256]; + + spin_lock_irqsave(&ohci->AR_resp_lock, flags); + + idx = ohci->AR_resp_buf_bh_ind; + offset = ohci->AR_resp_buf_bh_offset; + + buf_ptr = ohci->AR_resp_buf[idx]; + buf_ptr += offset/4; + + while(ohci->AR_resp_bytes_left > 0) { + + /* check to see if a fatal error occurred */ + if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) { + sprintf(msg,"fatal async response receive error -- status is %d", + ohci->AR_resp_prg[idx]->status & 0x1F); + stop_ar_resp_context(ohci, msg); + spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); + return; + } + + spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); + + /* Let's see what kind of packet is in there */ + tcode = (buf_ptr[0]>>4)&0xf; + if (tcode==2) /* no-data receive */ + packet_length=16; + else if (tcode==6) /* quadlet receive */ + packet_length=20; + else if (tcode==7) { /* block receive */ + /* Where is the data length ? */ + if (offset+12>=AR_RESP_BUF_SIZE) + packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC] + [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20; + else + packet_length=(buf_ptr[3]>>16)+20; + if (packet_length % 4) + packet_length += 4 - (packet_length % 4); + } + else /* something is wrong */ { + sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode); + stop_ar_resp_context(ohci,msg); + return; + } + if ((offset+packet_length)>AR_RESP_BUF_SIZE) { + /* we have a split packet */ + if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) { + sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes", + packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE); + stop_ar_resp_context(ohci, msg); + return; + } + split_left = packet_length; + split_ptr = (char *)ohci->AR_resp_spb; + while (split_left>0) { + memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset); + split_left -= AR_RESP_BUF_SIZE-offset; + split_ptr += AR_RESP_BUF_SIZE-offset; + ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; + idx = (idx+1) % AR_RESP_NUM_DESC; + buf_ptr = ohci->AR_resp_buf[idx]; + offset=0; + while (split_left >= AR_RESP_BUF_SIZE) { + memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE); + split_ptr += AR_RESP_BUF_SIZE; + split_left -= AR_RESP_BUF_SIZE; + ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; + idx = (idx+1) % AR_RESP_NUM_DESC; + buf_ptr = ohci->AR_resp_buf[idx]; + } + if (split_left>0) { + memcpy(split_ptr,buf_ptr,split_left); + offset = split_left; + split_left=0; + buf_ptr += split_left/4; + } + } +#if 0 + PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d", + tcode,packet_length); +#endif + hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length); + ohci->AR_resp_bytes_left -= packet_length; + } + else { +#if 0 + PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d", + tcode,packet_length); +#endif + hpsb_packet_received(ohci->host, buf_ptr, packet_length); + offset += packet_length; + buf_ptr += packet_length/4; + ohci->AR_resp_bytes_left -= packet_length; + if (offset==AR_RESP_BUF_SIZE) { + ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; + idx = (idx+1) % AR_RESP_NUM_DESC; + buf_ptr = ohci->AR_resp_buf[idx]; + offset=0; + } + } + + } + + if (ohci->AR_resp_bytes_left<0) + stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer"); + + ohci->AR_resp_buf_bh_ind = idx; + ohci->AR_resp_buf_bh_offset = offset; + + spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); +} + /* This is the bottom half that processes iso receive descriptor buffers. */ static void ohci_ir_proc_desc(void *data) { @@ -1023,23 +1185,61 @@ FAIL("failed to allocate DMA buffer for self-id packets"); } - /* AR dma buffer allocation */ - ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL); - if (ohci->AR_resp_buf != NULL) { - memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE); - } else { - FAIL("failed to allocate AR response DMA buffer"); + /* AR dma buffer and program allocation */ + ohci->AR_resp_buf= + kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*), + GFP_KERNEL); + + if (ohci->AR_resp_buf == NULL) { + FAIL("failed to allocate AR response receive DMA buffer"); } - /* AR dma program allocation */ - ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE, - GFP_KERNEL); - if (ohci->AR_resp_prg != NULL) { - memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE); - } else { - FAIL("failed to allocate AR response DMA program"); + ohci->AR_resp_prg= + kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*), + GFP_KERNEL); + + if (ohci->AR_resp_prg == NULL) { + FAIL("failed to allocate AR response receive DMA program"); } + ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL); + + if (ohci->AR_resp_spb == NULL) { + FAIL("failed to allocate AR response split packet buffer"); + } + + for (i= 0; i < AR_RESP_NUM_DESC; i++) { + ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL); + + if (ohci->AR_resp_buf[i] != NULL) { + memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE); + } else { + FAIL("failed to allocate AR response DMA buffer"); + } + + ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd), + GFP_KERNEL); + + if (ohci->AR_resp_prg[i] != NULL) { + memset(ohci->AR_resp_prg[i], 0, + sizeof(struct dma_cmd)); + } else { + FAIL("failed to allocate AR response DMA buffer"); + } + + } + + ohci->AR_resp_buf_th_ind = 0; + ohci->AR_resp_buf_th_offset = 0; + ohci->AR_resp_buf_bh_ind = 0; + ohci->AR_resp_buf_bh_offset = 0; + ohci->AR_resp_bytes_left = 0; + spin_lock_init(&ohci->AR_resp_lock); + + /* initialize AR response receive task */ + ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc; + ohci->AR_resp_pdl_task.data= (void*)ohci; + /* AT dma program allocation */ ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, GFP_KERNEL); @@ -1129,8 +1329,12 @@ p += sprintf(p,fmt,reg_read(ohci, reg0),\ reg_read(ohci, reg1),reg_read(ohci, reg2)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +static int ohci_get_status(char *buf) +#else int ohci_get_info(char *buf, char **start, off_t fpos, int length, int dummy) +#endif { struct ti_ohci *ohci=&cards[0]; struct hpsb_host *host=ohci->host; @@ -1165,15 +1369,23 @@ host->is_irm ? "iso_res_mgr" : "", host->is_busmgr ? "bus_mgr" : ""); - p += sprintf(p,"\n### ohci data ###\n"); - p += sprintf(p,"AR_resp_buf : %p AR_resp_prg: %p\n", - ohci->AR_resp_buf, ohci->AR_resp_prg); - + p += sprintf(p,"\n---Iso Receive DMA---\n"); for (i= 0; i < IR_NUM_DESC; i++) { p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n", i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]); } + + p += sprintf(p,"\n---Async Reponse Receive DMA---\n"); + for (i= 0; i < AR_RESP_NUM_DESC; i++) { + p += sprintf(p, "AR_resp_buf[%d] : %p AR_resp_prg[%d]: %p\n", + i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]); + } + p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n", + ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset); + p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n", + ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset); + /* ----- Register Dump ----- */ p += sprintf(p,"\n### HC Register dump ###\n"); SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n", @@ -1242,12 +1454,27 @@ phyreg&0x3f); #endif +#if 0 p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control); p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status); +#endif return p - buf; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +static int ohci1394_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = ohci_get_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#else struct proc_dir_entry ohci_proc_entry = { 0, /* Inode number - dynamic */ @@ -1261,18 +1488,36 @@ ohci_get_info, /* The read function for this file */ NULL }; -#endif +#endif /* LINUX_VERSION_CODE */ +#endif /* CONFIG_PROC_FS */ static void remove_card(struct ti_ohci *ohci) { if (ohci->registers) iounmap(ohci->registers); - if (ohci->AR_resp_buf) - kfree(ohci->AR_resp_buf); - if (ohci->AR_resp_prg) - kfree(ohci->AR_resp_prg); + + /* Free AR response buffers and programs */ + if (ohci->AR_resp_buf) { + int i; + for (i= 0; i < AR_RESP_NUM_DESC; i++) { + kfree(ohci->AR_resp_buf[i]); + } + kfree(ohci->AR_resp_buf); + } + if (ohci->AR_resp_prg) { + int i; + for (i= 0; i < AR_RESP_NUM_DESC; i++) { + kfree(ohci->AR_resp_prg[i]); + } + kfree(ohci->AR_resp_prg); + } + kfree(ohci->AR_resp_spb); + + /* Free AT request buffer and program */ if (ohci->AT_req_prg) kfree(ohci->AT_req_prg); + + /* Free Iso receive buffers and programs */ if (ohci->IR_recv_buf) { int i; for (i= 0; i < IR_NUM_DESC; i++) { @@ -1288,11 +1533,16 @@ kfree(ohci->IR_recv_prg); } kfree(ohci->IR_spb); + + /* Free self-id buffer */ if (ohci->self_id_buffer) kfree(ohci->self_id_buffer); + + /* Free config rom */ if (ohci->csr_config_rom) kfree(ohci->csr_config_rom); + /* Free the IRQ */ free_irq(ohci->dev->irq, ohci); ohci->state = 0; @@ -1327,11 +1577,15 @@ } #ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL); +#else if (proc_register(&proc_root, &ohci_proc_entry)) { PRINT_G(KERN_ERR, "unable to register proc file\n"); return -EIO; } #endif +#endif return 0; } @@ -1384,7 +1638,11 @@ { hpsb_unregister_lowlevel(get_ohci_template()); #ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + remove_proc_entry ("ohci1394", NULL); +#else proc_unregister(&proc_root, ohci_proc_entry.low_ino); +#endif #endif PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n"); } diff -ur --new-file old/linux/drivers/ieee1394/ohci1394.h new/linux/drivers/ieee1394/ohci1394.h --- old/linux/drivers/ieee1394/ohci1394.h Fri Jan 14 01:49:22 2000 +++ new/linux/drivers/ieee1394/ohci1394.h Mon Jan 31 19:13:03 2000 @@ -20,9 +20,15 @@ #define MAX_OHCI1394_CARDS 4 -#define AR_RESP_BUF_SIZE 4096 -#define AR_RESP_PRG_SIZE 256 -#define AT_REQ_PRG_SIZE 256 +#define OHCI1394_MAX_AT_REQ_RETRIES 1 +#define OHCI1394_MAX_AT_RESP_RETRIES 1 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 4 + +#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ +#define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */ +#define AR_RESP_SPLIT_PACKET_BUF_SIZE 256 /* split packet buffer */ +#define AR_RESP_TOTAL_BUF_SIZE (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC) +#define AT_REQ_PRG_SIZE 256 #define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */ #define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */ @@ -49,8 +55,18 @@ quadlet_t *csr_config_rom; /* buffer for csr config rom */ /* asynchronous receive */ - struct dma_cmd *AR_resp_prg; - quadlet_t *AR_resp_buf; + struct dma_cmd **AR_resp_prg; + quadlet_t **AR_resp_buf; + unsigned int AR_resp_buf_bh_ind; + unsigned int AR_resp_buf_bh_offset; + unsigned int AR_resp_buf_th_ind; + unsigned int AR_resp_buf_th_offset; + int AR_resp_bytes_left; + quadlet_t *AR_resp_spb; + spinlock_t AR_resp_lock; + + /* async receive task */ + struct tq_struct AR_resp_pdl_task; /* asynchronous transmit */ struct dma_cmd *AT_req_prg; diff -ur --new-file old/linux/drivers/ieee1394/raw1394.c new/linux/drivers/ieee1394/raw1394.c --- old/linux/drivers/ieee1394/raw1394.c Sat Jan 15 04:18:53 2000 +++ new/linux/drivers/ieee1394/raw1394.c Mon Jan 31 19:13:03 2000 @@ -495,8 +495,8 @@ if (req->req.length == 8) { req->req.error = highlevel_lock(fi->host, req->data, - addr, req->data[0], - req->data[1], + addr, req->data[1], + req->data[0], req->req.misc); req->req.length = 4; } else { @@ -567,6 +567,32 @@ break; case RAW1394_REQ_LOCK: + if ((req->req.misc != EXTCODE_FETCH_ADD) + && (req->req.misc != EXTCODE_LITTLE_ADD)) { + if (req->req.length != 4) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } else { + if (req->req.length != 8) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } + + packet = hpsb_make_lockpacket(fi->host, node, addr, + req->req.misc); + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->data, req->req.sendb, + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + break; + } + + req->req.length = 4; + break; + case RAW1394_REQ_LOCK64: default: req->req.error = RAW1394_ERROR_STATE_ORDER; diff -ur --new-file old/linux/drivers/net/Makefile new/linux/drivers/net/Makefile --- old/linux/drivers/net/Makefile Fri Jan 14 03:03:58 2000 +++ new/linux/drivers/net/Makefile Mon Jan 31 19:34:12 2000 @@ -115,7 +115,7 @@ obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_DAYNAPORT) += daynaport.o 8390.o +obj-$(CONFIG_MAC8390) += daynaport.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_SHAPER) += shaper.o @@ -247,6 +247,8 @@ obj-$(CONFIG_RCPCI) += rcpci.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_MACSONIC) += macsonic.o +obj-$(CONFIG_MACMACE) += macmace.o +obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_BMAC) += bmac.o obj-$(CONFIG_NCR885E) += ncr885e.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o diff -ur --new-file old/linux/drivers/net/Space.c new/linux/drivers/net/Space.c --- old/linux/drivers/net/Space.c Wed Jan 26 22:16:05 2000 +++ new/linux/drivers/net/Space.c Mon Jan 31 19:34:12 2000 @@ -105,7 +105,13 @@ extern int mvme147lance_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); -extern int mac_onboard_sonic_probe(struct net_device *dev); +extern int mace68k_probe(struct net_device *dev); +extern int macsonic_probe(struct net_device *dev); +extern int mac8390_probe(struct net_device *dev); +extern int mac89x0_probe(struct net_device *dev); + + /* Gigabit Ethernet adapters */ + extern int yellowfin_probe(struct net_device *dev); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct net_device *); @@ -355,8 +361,17 @@ #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ {mvme147lance_probe, 0}, #endif -#ifdef CONFIG_MACSONIC /* Mac 68k Quadra builtin Ethernet */ - {mac_onboard_sonic_probe, 0}, +#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ + {mace68k_probe, 0}, +#endif +#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */ + {macsonic_probe, 0}, +#endif +#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ + {mac8390_probe, 0}, +#endif +#ifdef CONFIG_MAC89x0 + {mac89x0_probe, 0}, #endif {NULL, 0}, }; diff -ur --new-file old/linux/drivers/net/cs89x0.h new/linux/drivers/net/cs89x0.h --- old/linux/drivers/net/cs89x0.h Mon Aug 23 19:12:37 1999 +++ new/linux/drivers/net/cs89x0.h Tue Feb 1 08:43:51 2000 @@ -14,6 +14,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -76,6 +78,12 @@ #define LAST_IO 0x037C /* Last I/O port to check (+10h) */ #define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ #define ADD_SIG 0x3000 /* Expected ID signature */ + +/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */ +#ifdef CONFIG_MAC +#define LCSLOTBASE 0xfee00000 +#define MMIOBASE 0x40000 +#endif #define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ diff -ur --new-file old/linux/drivers/net/daynaport.c new/linux/drivers/net/daynaport.c --- old/linux/drivers/net/daynaport.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/daynaport.c Mon Jan 31 19:34:12 2000 @@ -1,4 +1,4 @@ -/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */ +/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */ /* Derived from code: @@ -15,14 +15,20 @@ The block output routines may be wrong for non Dayna cards - Reading MAC addresses -*/ + Fix this driver so that it will attempt to use the info + (i.e. iobase, iosize) given to it by the new and improved + NuBus code. + + Despite its misleading filename, this driver is not Dayna-specific + anymore. */ +/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */ static const char *version = - "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n"; + "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n"; +static int version_printed = 0; #include - +#include #include #include #include @@ -31,20 +37,26 @@ #include #include #include +#include #include #include #include #include "8390.h" -int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom); +extern int console_loglevel; + +int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, + int prom, struct nubus_dev *ndev); static int ns8390_open(struct net_device *dev); static void ns8390_no_reset(struct net_device *dev); static int ns8390_close_card(struct net_device *dev); +/* Interlan */ static void interlan_reset(struct net_device *dev); +/* Dayna */ static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void dayna_block_input(struct net_device *dev, int count, @@ -52,6 +64,7 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page); +/* Sane (32-bit chunk memory read/write) */ static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct net_device *dev, int count, @@ -59,6 +72,7 @@ static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page); +/* Slow Sane (16-bit chunk memory read/write) */ static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void slow_sane_block_input(struct net_device *dev, int count, @@ -71,6 +85,10 @@ #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ +#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ +#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ + #define DAYNA_MAC_BASE 0xf0007 #define DAYNA_8390_BASE 0x80000 /* 3 */ @@ -81,9 +99,14 @@ #define APPLE_8390_MEM 0xD0000 #define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */ -#define KINETICS_8390_BASE 0x80003 -#define KINETICS_8390_MEM 0x00000 +#define KINETICS_MAC_BASE 0xf0004 /* first byte of each long */ +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 /* first word of each long */ #define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */ +/*#define KINETICS_MEMSIZE (0x10000/2) * CSA: on the board I have, at least */ + +#define CABLETRON_8390_BASE 0x90000 +#define CABLETRON_8390_MEM 0x00000 static int test_8390(volatile char *ptr, int scale) { @@ -113,34 +136,59 @@ * Identify the species of NS8390 card/driver we need */ -#define NS8390_DAYNA 1 -#define NS8390_INTERLAN 2 -#define NS8390_KINETICS 3 -#define NS8390_APPLE 4 -#define NS8390_FARALLON 5 -#define NS8390_ASANTE 6 - -int ns8390_ident(struct nubus_type *nb) -{ - /* It appears anything with a software type of 0 is an apple - compatible - even if the hardware matches others */ - - if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100) - return NS8390_APPLE; - +enum mac8390_type { + NS8390_DAYNA, + NS8390_INTERLAN, + NS8390_KINETICS, + NS8390_APPLE, + NS8390_FARALLON, + NS8390_ASANTE, + NS8390_CABLETRON +}; + +int __init ns8390_ident(struct nubus_dev* ndev) +{ + /* This really needs to be tested and tested hard. */ + + /* Summary of what we know so far -- + * SW: 0x0104 -- asante, 16 bit, back4_offsets + * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets + * SW: 0x010c -- farallon, 16 bit, back4_offsets, no long word access + * SW: 0x011a -- focus, [no details yet] + * SW: ?????? -- interlan, 16 bit, back4_offsets, funny reset + * SW: ?????? -- kinetics, 8 bit, back4_offsets + * -- so i've this hypothesis going that says DrSW&1 says whether the + * map is forward or backwards -- and maybe DrSW&256 says what the + * register spacing is -- for all cards that report a DrSW in some + * range. + * This would allow the "apple compatible" driver to drive many + * seemingly different types of cards. More DrSW info is needed + * to investigate this properly. [CSA, 21-May-1999] + */ /* Dayna ex Kinetics board */ - if(nb->DrHW==0x0103) + if(ndev->dr_sw == NUBUS_DRSW_DAYNA) return NS8390_DAYNA; - - /* Asante board */ - if(nb->DrHW==0x0104) + if(ndev->dr_sw == NUBUS_DRSW_ASANTE) return NS8390_ASANTE; - if(nb->DrHW==0x0100) - return NS8390_INTERLAN; - if(nb->DrHW==0x0106) - return NS8390_KINETICS; - if(nb->DrSW==0x010C) + if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */ return NS8390_FARALLON; + if(ndev->dr_sw == NUBUS_DRSW_KINETICS) + return NS8390_KINETICS; + /* My ATI Engineering card with this combination crashes the */ + /* driver trying to xmit packets. Best not touch it for now. */ + /* - 1999-05-20 (funaho@jurai.org) */ + if(ndev->dr_sw == NUBUS_DRSW_FOCUS) + return -1; + + /* Check the HW on this one, because it shares the same DrSW as + the on-board SONIC chips */ + if(ndev->dr_hw == NUBUS_DRHW_CABLETRON) + return NS8390_CABLETRON; + /* does anyone have one of these? */ + if(ndev->dr_hw == NUBUS_DRHW_INTERLAN) + return NS8390_INTERLAN; + + /* FIXME: what do genuine Apple boards look like? */ return -1; } @@ -148,7 +196,7 @@ * Memory probe for 8390 cards */ -int apple_8390_mem_probe(volatile unsigned short *p) +int __init apple_8390_mem_probe(volatile unsigned short *p) { int i, j; /* @@ -192,61 +240,79 @@ /* * Probe for 8390 cards. * The ns8390_probe1() routine initializes the card and fills the - * station address field. On entry base_addr is set, irq is set - * (These come from the nubus probe code). dev->mem_start points + * station address field. + * + * The NuBus interface has changed! We now scan for these somewhat + * like how the PCI and Zorro drivers do. It's not clear whether + * this is actually better, but it makes things more consistent. + * + * dev->mem_start points * at the memory ring, dev->mem_end gives the end of it. */ -int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match) +int __init mac8390_probe(struct net_device *dev) { - struct net_device *dev; + static int slots = 0; volatile unsigned short *i; volatile unsigned char *p; int plen; int id; + static struct nubus_dev* ndev = NULL; - if(match->category!=NUBUS_CAT_NETWORK || match->type!=1) - return -ENODEV; - /* Ok so it is an ethernet network device */ - if((id=ns8390_ident(match))==-1) - { - printk("Ethernet but type unknown %d\n",match->DrHW); + /* Find the first card that hasn't already been seen */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) { + /* Have we seen it already? */ + if (slots & (1<board->slot)) + continue; + slots |= 1<board->slot; + + /* Is it one of ours? */ + if ((id = ns8390_ident(ndev)) != -1) + break; + } + + /* Hm. No more cards, then */ + if (ndev == NULL) return -ENODEV; + + dev = init_etherdev(dev, 0); + + if (!version_printed) { + printk(KERN_INFO "%s", version); + version_printed = 1; } - dev = init_etherdev(0, 0); - if(dev==NULL) - return -ENOMEM; /* * Dayna specific init */ if(id==NS8390_DAYNA) { - dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM); - dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ + dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM); + dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ - printk("daynaport: testing board: "); - + printk(KERN_INFO "%s: daynaport. testing board: ", dev->name); + printk("memory - "); - - i=(void *)dev->mem_start; + + i = (void *)dev->mem_start; memset((void *)i,0xAA, DAYNA_MEMSIZE); while(i<(volatile unsigned short *)dev->mem_end) { if(*i!=0xAAAA) goto membad; - *i=0x5555; - if(*i!=0x5555) + *i=0x5678; /* make sure we catch byte smearing */ + if(*i!=0x5678) goto membad; i+=2; /* Skip a word */ } - + printk("controller - "); - + p=(void *)dev->base_addr; plen=0; - + while(plen<0x3FF00) { if(test_8390(p,0)==0) @@ -263,26 +329,71 @@ if(plen==0x3FF00) goto membad; printk("OK\n"); - dev->irq=slot; - if(ns8390_probe1(dev, 0, "dayna", id, -1)==0) - return 0; + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0) + return 0; + } + /* Cabletron */ + if (id==NS8390_CABLETRON) { + int memsize = 16<<10; /* fix this */ + + dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM); + dev->mem_end=dev->mem_start+memsize; + dev->irq = SLOT2IRQ(ndev->board->slot); + + /* The base address is unreadable if 0x00 has been written to the command register */ + /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */ + i = (void *)dev->base_addr; + *i = 0x21; + + printk(KERN_INFO "%s: cabletron: testing board: ", dev->name); + printk("%dK memory - ", memsize>>10); + i=(void *)dev->mem_start; + while(i<(volatile unsigned short *)(dev->mem_start+memsize)) + { + *i=0xAAAA; + if(*i!=0xAAAA) + goto membad; + *i=0x5555; + if(*i!=0x5555) + goto membad; + i+=2; /* Skip a word */ + } + printk("OK\n"); + + if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0) + return 0; } /* Apple, Farallon, Asante */ - if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE) + if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE) { int memsize; - - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); - + + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); + memsize = apple_8390_mem_probe((void *)dev->mem_start); - + dev->mem_end=dev->mem_start+memsize; - dev->irq=slot; - printk("apple/clone: testing board: "); - + dev->irq = SLOT2IRQ(ndev->board->slot); + + switch(id) + { + case NS8390_FARALLON: + printk(KERN_INFO "%s: farallon: testing board: ", dev->name); + break; + case NS8390_ASANTE: + printk(KERN_INFO "%s: asante: testing board: ", dev->name); + break; + case NS8390_APPLE: + default: + printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name); + break; + } + printk("%dK memory - ", memsize>>10); - + i=(void *)dev->mem_start; memset((void *)i,0xAA, memsize); while(i<(volatile unsigned short *)dev->mem_end) @@ -295,51 +406,75 @@ i+=2; /* Skip a word */ } printk("OK\n"); - - if(id==NS8390_FARALLON) + + switch (id) { - if(ns8390_probe1(dev, 1, "farallon", id, -1)==0) + case NS8390_FARALLON: + if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0) return 0; - } - else - { - if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0) - return 0; + break; + case NS8390_ASANTE: + if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0) + return 0; + break; + case NS8390_APPLE: + default: + if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0) + return 0; + break; } } /* Interlan */ if(id==NS8390_INTERLAN) { /* As apple and asante */ - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 1, "interlan", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0) return 0; } - /* Kinetics */ + /* Kinetics (Shiva Etherport) */ if(id==NS8390_KINETICS) { - dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM); dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0) return 0; } - kfree(dev); + + /* We should hopefully not get here */ + printk(KERN_ERR "Probe unsucessful.\n"); return -ENODEV; -membad: - printk("failed.\n"); - kfree(dev); + + membad: + printk(KERN_ERR "failed at %p in %p - %p.\n", i, + (void *)dev->mem_start, (void *)dev->mem_end); return -ENODEV; } -int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type, int promoff) +int __init mac8390_ethernet_addr(struct nubus_dev* ndev, + unsigned char addr[6]) { - static unsigned version_printed = 0; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Get the functional resource for this device */ + if (nubus_get_func_dir(ndev, &dir) == -1) + return -1; + if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) + return -1; + + nubus_get_rsrc_mem(addr, &ent, 6); + return 0; +} +int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name, + int type, int promoff, struct nubus_dev *ndev) +{ static u32 fwrd4_offsets[16]={ 0, 4, 8, 12, 16, 20, 24, 28, @@ -352,25 +487,19 @@ 28, 24, 20, 16, 12, 8, 4, 0 }; + static u32 fwrd2_offsets[16]={ + 0, 2, 4, 6, + 8, 10, 12, 14, + 16, 18, 20, 22, + 24, 26, 28, 30 + }; - unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff; + unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff; - if (ei_debug && version_printed++ == 0) - printk(version); - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share a slot! and the board will usually be enabled. */ - if (nubus_request_irq(dev->irq, dev, ei_interrupt)) - { - printk (" unable to get nubus IRQ %d.\n", dev->irq); - return EAGAIN; - } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - nubus_free_irq(dev->irq); + printk ("%s: unable to get memory for dev->priv.\n", dev->name); return -ENOMEM; } @@ -378,16 +507,25 @@ ei_status.name = model_name; ei_status.word16 = word16; - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - dev->rmem_start = dev->mem_start + TX_PAGES*256; - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - dev->rmem_end = dev->mem_end; + if (type==NS8390_CABLETRON) { + /* Cabletron card puts the RX buffer before the TX buffer */ + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + dev->rmem_start = dev->mem_start; + dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + } else { + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_end = dev->mem_end; + } if(promoff==-1) /* Use nubus resources ? */ { - if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr)) + if(mac8390_ethernet_addr(ndev, dev->dev_addr)) { printk("mac_ns8390: MAC address not in resources!\n"); return -ENODEV; @@ -400,7 +538,7 @@ /* These should go in the end I hope */ if(type==NS8390_DAYNA) x=2; - if(type==NS8390_INTERLAN) + if(type==NS8390_INTERLAN || type==NS8390_KINETICS) x=4; while(i<6) { @@ -412,12 +550,24 @@ } } - printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", - model_name, dev->irq, dev->mem_start, dev->mem_end-1); + printk(KERN_INFO "%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, model_name); + printk(KERN_INFO "MAC "); + { + int i; + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + } + printk(" IRQ %d, shared memory at %#lx-%#lx.\n", + dev->irq, dev->mem_start, dev->mem_end-1); switch(type) { case NS8390_DAYNA: /* Dayna card */ + case NS8390_KINETICS: /* Kinetics -- 8 bit config, but 16 bit mem */ /* 16 bit, 4 word offsets */ ei_status.reset_8390 = &ns8390_no_reset; ei_status.block_input = &dayna_block_input; @@ -425,6 +575,15 @@ ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; break; + case NS8390_CABLETRON: /* Cabletron */ + /* 16 bit card, register map is short forward */ + ei_status.reset_8390 = &ns8390_no_reset; + /* Ctron card won't accept 32bit values read or written to it */ + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd2_offsets; + break; case NS8390_FARALLON: case NS8390_APPLE: /* Apple/Asante/Farallon */ /* 16 bit card, register map is reversed */ @@ -450,6 +609,8 @@ ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#if 0 /* i think this suffered code rot. my kinetics card has much + * different settings. -- CSA [22-May-1999] */ case NS8390_KINETICS: /* Kinetics */ /* 8bit card, map is forward */ ei_status.reset_8390 = &ns8390_no_reset; @@ -458,6 +619,7 @@ ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#endif default: panic("Detected a card I can't drive - whoops\n"); } @@ -472,6 +634,19 @@ static int ns8390_open(struct net_device *dev) { ei_open(dev); + + /* At least on my card (a Focus Enhancements PDS card) I start */ + /* getting interrupts right away, so the driver needs to be */ + /* completely initialized before enabling the interrupt. */ + /* - funaho@jurai.org (1999-05-17) */ + + /* Non-slow interrupt, works around issues with the SONIC driver */ + if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) + { + printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return EAGAIN; + } + MOD_INC_USE_COUNT; return 0; } @@ -489,24 +664,19 @@ { if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); + free_irq(dev->irq, dev); ei_close(dev); MOD_DEC_USE_COUNT; return 0; } -struct nubus_device_specifier nubus_8390={ - ns8390_probe, - NULL -}; - - /* * Interlan Specific Code Starts Here */ static void interlan_reset(struct net_device *dev) { - unsigned char *target=nubus_slot_addr(dev->irq); + unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); if (ei_debug > 1) printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; @@ -531,16 +701,23 @@ The only complications are that the ring buffer wraps. */ -static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int count) +static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) { volatile unsigned short *ptr; unsigned short *target=to; from<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+from); + /* + * Leading byte? + */ + if (from&2) { + *((char *)target)++ = *(((char *)ptr++)-1); + count--; + } while(count>=2) { *target++=*ptr++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -554,16 +731,24 @@ } } -static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, int count) +static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count) { volatile unsigned short *ptr; const unsigned short *src=from; to<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+to); + /* + * Leading byte? + */ + if (to&2) { /* avoid a byte write (stomps on other data) */ + ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; + ptr++; + count--; + } while(count>=2) { *ptr++=*src++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -573,14 +758,15 @@ { /* Big endian */ unsigned short v=*src; - *((char *)ptr)=v>>8; + /* card doesn't like byte writes */ + *ptr=(*ptr&0x00FF)|(v&0xFF00); } } static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4); + dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); /* Register endianism - fix here rather than 8390.c */ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); } @@ -599,14 +785,14 @@ { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); count -= semi_count; - dayna_cpu_memcpy(dev, skb->data + semi_count, + dayna_memcpy_fromcard(dev, skb->data + semi_count, dev->rmem_start - dev->mem_start, count); } else { - dayna_cpu_memcpy(dev, skb->data, xfer_base, count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); } } @@ -615,7 +801,7 @@ { long shmem = (start_page - WD_START_PG)<<8; - cpu_dayna_memcpy(dev, shmem, buf, count); + dayna_memcpy_tocard(dev, shmem, buf, count); } /* @@ -739,6 +925,7 @@ * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" * version-control: t + * c-basic-offset: 4 * tab-width: 4 * kept-new-versions: 5 * End: diff -ur --new-file old/linux/drivers/net/irda/Config.in new/linux/drivers/net/irda/Config.in --- old/linux/drivers/net/irda/Config.in Thu Jan 6 23:46:18 2000 +++ new/linux/drivers/net/irda/Config.in Sat Jan 29 04:36:22 2000 @@ -6,10 +6,12 @@ dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA comment 'FIR device drivers' -dep_tristate 'NSC PC87108/PC97338' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA -dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then +dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA +fi comment 'Dongle support' bool 'Serial dongle support' CONFIG_DONGLE @@ -19,9 +21,7 @@ dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA - dep_tristate ' Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA - dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA - + dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA fi endmenu diff -ur --new-file old/linux/drivers/net/irda/Makefile new/linux/drivers/net/irda/Makefile --- old/linux/drivers/net/irda/Makefile Thu Jan 6 23:46:18 2000 +++ new/linux/drivers/net/irda/Makefile Sat Jan 29 04:36:22 2000 @@ -29,10 +29,10 @@ endif ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc_fir.o +L_OBJS += nsc-ircc.o else ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc_fir.o + M_OBJS += nsc-ircc.o endif endif @@ -115,14 +115,6 @@ else ifeq ($(CONFIG_LITELINK_DONGLE),m) M_OBJS += litelink.o - endif -endif - -ifeq ($(CONFIG_AIRPORT_DONGLE),y) -L_OBJS += airport.o -else - ifeq ($(CONFIG_AIRPORT_DONGLE),m) - M_OBJS += airport.o endif endif diff -ur --new-file old/linux/drivers/net/irda/airport.c new/linux/drivers/net/irda/airport.c --- old/linux/drivers/net/irda/airport.c Tue Dec 21 19:17:31 1999 +++ new/linux/drivers/net/irda/airport.c Thu Jan 1 01:00:00 1970 @@ -1,358 +0,0 @@ -/********************************************************************* - * - * Filename: airport.c - * Version: 0.2 - * Description: Implementation for the Adaptec Airport 1000 and 2000 - * dongles - * Status: Experimental. - * Author: Fons Botman - * Created at: Wed May 19 23:14:34 CEST 1999 - * Based on: actisys.c by Dag Brattli - * - * Copyright (c) 1998-1999 Fons Botman, All Rights Reserved. - * - * 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. - * - * Neither Fons Botman nor anyone else admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include -#include - -static int airport_reset_wrapper(struct irda_task *task); -static void airport_open(dongle_t *self, struct qos_info *qos); -static void airport_close(dongle_t *self); -static int airport_change_speed_wrapper(struct irda_task *task); - -static struct dongle_reg dongle = { - Q_NULL, - IRDA_AIRPORT_DONGLE, - airport_open, - airport_close, - airport_reset_wrapper, - airport_change_speed_wrapper, -}; - -int __init airport_init(void) -{ - int ret; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - ret = irda_device_register_dongle(&dongle); - if (ret < 0) - return ret; - return 0; -} - -void airport_cleanup(void) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - irda_device_unregister_dongle(&dongle); -} - -static void airport_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= - IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - /* May need 1ms */ - qos->min_turn_time.bits = 0x07; - - MOD_INC_USE_COUNT; -} - -static void airport_close(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - - MOD_DEC_USE_COUNT; -} - -static void airport_set_command_mode(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - self->set_dtr_rts(self->dev, FALSE, TRUE); -} - -static void airport_set_normal_mode(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - self->set_dtr_rts(self->dev, TRUE, TRUE); -} - -void airport_write_char(dongle_t *self, unsigned char c) -{ - int actual; - IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c & 0xff); - actual = self->write(self->dev, &c, 1); - ASSERT(actual == 1, return;); -} - -#define JIFFIES_TO_MSECS(j) ((j)*1000/HZ) - -static int airport_waitfor_char(dongle_t *self, unsigned char c) -{ - __u8 buf[100]; - int i, found = FALSE; - int before; - int len; - - IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c); - - /* Sleep approx. 10 ms */ - before = jiffies; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - IRDA_DEBUG(4, __FUNCTION__ " waited %ldms\n", - JIFFIES_TO_MSECS(jiffies - before)); - - len = self->read(self->dev, buf, 100); - - for (i = 0; !found && i < len; i++ ) { - /* IRDA_DEBUG(6, __FUNCTION__ " 0x02x\n", idev->rx_buff.data[i]); */ - found = c == buf[i]; - } - - IRDA_DEBUG(2, __FUNCTION__ " returns %s\n", (found ? "true" : "false")); - return found; -} - -static int airport_check_command_mode(dongle_t *self) -{ - int i; - int found = FALSE; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - airport_set_command_mode(self); - - /* Loop until the time expires (200ms) or we get the magic char. */ - - for ( i = 0 ; i < 25 ; i++ ) { - airport_write_char(self, 0xff); - if (airport_waitfor_char(self, 0xc3)) { - found = TRUE; - break; - } - } - - if (found) { - IRDA_DEBUG(2, __FUNCTION__ " OK. (%d)\n", i); - } else { - IRDA_DEBUG(0, __FUNCTION__ " FAILED!\n"); - } - return found; -} - -static int airport_write_register(dongle_t *self, unsigned char reg) -{ - int ok = FALSE; - int i; - - IRDA_DEBUG(4, __FUNCTION__ "(,0x%x)\n", reg); - airport_check_command_mode(self); - - for ( i = 0 ; i < 6 ; i++ ) { - airport_write_char(self, reg); - if (!airport_waitfor_char(self, reg)) - continue; - - /* Now read it back */ - airport_write_char(self, (reg << 4) | 0x0f); - if (airport_waitfor_char(self, reg)) { - ok = TRUE; - break; - } - } - - airport_set_normal_mode(self); - if (ok) { - IRDA_DEBUG(4, __FUNCTION__ "(,0x%x) returns OK\n", reg); - } else { - IRDA_DEBUG(0, __FUNCTION__ "(,0x%x) returns False!\n", reg); - } - return ok; -} - - -/* - * Function airport_change_speed (self, speed) - * - * Change speed of the Airport type IrDA dongles. - */ -static void airport_change_speed(dongle_t *self, __u32 speed) -{ - __u32 current_baudrate; - int baudcode; - - IRDA_DEBUG(4, __FUNCTION__ "(,%d)\n", speed); - - ASSERT(self != NULL, return;); - - /* Find the correct baudrate code for the required baudrate */ - switch (speed) { - case 2400: baudcode = 0x10; break; - case 4800: baudcode = 0x20; break; - case 9600: baudcode = 0x30; break; - case 19200: baudcode = 0x40; break; - case 38400: baudcode = 0x50; break; - case 57600: baudcode = 0x60; break; - case 115200: baudcode = 0x70; break; - default: - IRDA_DEBUG(0, __FUNCTION__ " bad baud rate: %d\n", speed); - return; - } - - current_baudrate = self->speed; - IRDA_DEBUG(4, __FUNCTION__ " current baudrate: %d\n", current_baudrate); - - self->set_mode(self->dev, IRDA_RAW); - - /* Set the new speed in both registers */ - if (airport_write_register(self, baudcode)) { - if (airport_write_register(self, baudcode|0x01)) { - /* ok */ - } else { - IRDA_DEBUG(0, __FUNCTION__ - " Cannot set new speed in second register\n"); - } - } else { - IRDA_DEBUG(0, __FUNCTION__ - " Cannot set new speed in first register\n"); - } - - self->set_mode(self->dev, IRDA_IRLAP); - - /* How do I signal an error in these functions? */ - - IRDA_DEBUG(4, __FUNCTION__ " returning\n"); -} - -int airport_change_speed_wrapper(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - - irda_execute_as_process(self, (TODO_CALLBACK) airport_change_speed, - speed); - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -/* - * Function airport_reset (self) - * - * Reset the Airport type dongle. Warning, this function must only be - * called with a process context! - * - */ -static void airport_reset(dongle_t *self) -{ - int ok; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - ASSERT(self != NULL, return;); - - self->set_mode(self->dev, IRDA_RAW); - - airport_set_normal_mode(self); - - /* Sleep 2000 ms */ - IRDA_DEBUG(2, __FUNCTION__ " waiting for powerup\n"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(2000)); - IRDA_DEBUG(2, __FUNCTION__ " finished waiting for powerup\n"); - - /* set dongle speed to 9600 */ - ok = TRUE; - - if (ok) - ok = airport_write_register(self, 0x30); - if (!ok) - MESSAGE(__FUNCTION__ "() dongle not connected?\n"); - if (ok) - ok = airport_write_register(self, 0x31); - - if (ok) - ok = airport_write_register(self, 0x02); - if (ok) - ok = airport_write_register(self, 0x03); - - if (ok) { - ok = airport_check_command_mode(self); - - if (ok) { - airport_write_char(self, 0x04); - ok = airport_waitfor_char(self, 0x04); - } - airport_set_normal_mode(self); - } - - self->set_mode(self->dev, IRDA_IRLAP); - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - IRDA_DEBUG(4, __FUNCTION__ " waited 20ms\n"); - - self->speed = 9600; - if (!ok) - MESSAGE(__FUNCTION__ "() failed.\n"); - IRDA_DEBUG(2, __FUNCTION__ " returning.\n"); -} - -int airport_reset_wrapper(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - - irda_execute_as_process(self, (TODO_CALLBACK) airport_reset, 0); - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Fons Botman "); -MODULE_DESCRIPTION("Adaptec Airport 1000 and 2000 dongle driver"); - -/* - * Function init_module (void) - * - * Initialize Airport module - * - */ -int init_module(void) -{ - return airport_init(); -} - -/* - * Function cleanup_module (void) - * - * Cleanup Airport module - * - */ -void cleanup_module(void) -{ - airport_cleanup(); -} - -#endif diff -ur --new-file old/linux/drivers/net/irda/irport.c new/linux/drivers/net/irda/irport.c --- old/linux/drivers/net/irda/irport.c Thu Jan 6 23:46:18 2000 +++ new/linux/drivers/net/irda/irport.c Sat Jan 29 04:36:22 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Wed Jan 5 13:59:38 2000 + * Modified at: Fri Jan 28 20:22:38 2000 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds * @@ -161,20 +161,19 @@ self->index = i; /* Initialize IO */ - self->io.iobase = iobase; + self->io.sir_base = iobase; + self->io.sir_ext = IO_EXTENT; self->io.irq = irq; - self->io.io_ext = IO_EXTENT; self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.sir_base, self->io.sir_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); - /* irport_cleanup(self->self); */ + self->io.sir_base); return NULL; } - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.sir_base, self->io.sir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -218,7 +217,6 @@ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return NULL; } - self->netdev = dev; /* May be overridden by piggyback drivers */ @@ -268,19 +266,19 @@ /* Release the IO-port that this driver is using */ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); + self->io.sir_base); + release_region(self->io.sir_base, self->io.sir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); if (self->rx_buff.head) kfree(self->rx_buff.head); - + /* Remove ourselves */ dev_self[self->index] = NULL; kfree(self); - + return 0; } @@ -289,7 +287,7 @@ unsigned long flags; int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; spin_lock_irqsave(&self->lock, flags); @@ -310,7 +308,7 @@ unsigned long flags; int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; spin_lock_irqsave(&self->lock, flags); @@ -355,7 +353,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Update accounting for new speed */ self->io.speed = speed; @@ -431,7 +429,7 @@ break; case IRDA_TASK_CHILD_INIT: /* Go to default speed */ - irport_change_speed(self, 9600); + self->change_speed(self->priv, 9600); /* Change speed of dongle */ if (irda_task_execute(self->dongle, @@ -454,7 +452,7 @@ break; case IRDA_TASK_CHILD_DONE: /* Finally we are ready to change the speed */ - irport_change_speed(self, speed); + self->change_speed(self->priv, speed); irda_task_next_state(task, IRDA_TASK_DONE); break; @@ -484,7 +482,7 @@ IRDA_DEBUG(4, __FUNCTION__ "()\n"); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Finished with frame? */ if (self->tx_buff.len > 0) { @@ -598,7 +596,6 @@ { struct irport_cb *self; unsigned long flags; - int actual = 0; int iobase; __u32 speed; @@ -607,7 +604,7 @@ self = (struct irport_cb *) dev->priv; ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) { @@ -617,7 +614,7 @@ WARNING("%s: transmit timed out\n", dev->name); irport_start(self); - irport_change_speed(self, self->io.speed ); + self->change_speed(self->priv, self->io.speed); dev->trans_start = jiffies; } @@ -635,8 +632,7 @@ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; + self->stats.tx_bytes += self->tx_buff.len; /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); @@ -661,7 +657,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* * Receive all characters in Rx FIFO, unwrap and unstuff them. @@ -702,15 +698,16 @@ dev->interrupt = 1; - iobase = self->io.iobase; + iobase = self->io.sir_base; iir = inb(iobase+UART_IIR) & UART_IIR_ID; while (iir) { /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", - iir, lsr, iobase); + IRDA_DEBUG(4, __FUNCTION__ + "(), iir=%02x, lsr=%02x, iobase=%#x\n", + iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: @@ -765,7 +762,7 @@ ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; - iobase = self->io.iobase; + iobase = self->io.sir_base; if (request_irq(self->io.irq, self->interrupt, 0, dev->name, (void *) dev)) @@ -809,7 +806,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Stop device */ dev->tbusy = 1; @@ -840,7 +837,7 @@ { int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Wait until Tx FIFO is empty */ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { @@ -875,7 +872,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; if (dtr) dtr = UART_MCR_DTR; @@ -895,7 +892,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { diff -ur --new-file old/linux/drivers/net/irda/irtty.c new/linux/drivers/net/irda/irtty.c --- old/linux/drivers/net/irda/irtty.c Thu Jan 6 23:46:18 2000 +++ new/linux/drivers/net/irda/irtty.c Sat Jan 29 04:36:22 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Wed Jan 5 14:00:13 2000 + * Modified at: Fri Jan 14 21:02:27 2000 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -233,6 +233,8 @@ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } + /* dev_alloc doesn't clear the struct */ + memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); dev->priv = (void *) self; self->netdev = dev; @@ -654,6 +656,7 @@ self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); dev->trans_start = jiffies; + self->stats.tx_bytes += self->tx_buff.len; if (self->tty->driver.write) actual = self->tty->driver.write(self->tty, 0, @@ -663,9 +666,6 @@ self->tx_buff.data += actual; self->tx_buff.len -= actual; - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; - dev_kfree_skb(skb); return 0; @@ -709,6 +709,8 @@ self->tx_buff.data += actual; self->tx_buff.len -= actual; + + self->stats.tx_packets++; } else { /* * Now serial buffer is almost free & we can start diff -ur --new-file old/linux/drivers/net/irda/nsc-ircc.c new/linux/drivers/net/irda/nsc-ircc.c --- old/linux/drivers/net/irda/nsc-ircc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/irda/nsc-ircc.c Tue Feb 1 08:43:51 2000 @@ -0,0 +1,2073 @@ +/********************************************************************* + * + * Filename: nsc-ircc.c + * Version: 1.0 + * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets + * Status: Stable. + * Author: Dag Brattli + * Created at: Sat Nov 7 21:43:15 1998 + * Modified at: Fri Jan 28 12:10:10 2000 + * Modified by: Dag Brattli + * + * Copyright (c) 1998-2000 Dag Brattli + * Copyright (c) 1998 Lichen Wang, + * Copyright (c) 1998 Actisys Corp., www.actisys.com + * All Rights Reserved + * + * 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. + * + * Neither Dag Brattli nor University of Tromsř admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Notice that all functions that needs to access the chip in _any_ + * way, must save BSR register on entry, and restore it on exit. + * It is _very_ important to follow this policy! + * + * __u8 bank; + * + * bank = inb(iobase+BSR); + * + * do_your_stuff_here(); + * + * outb(bank, iobase+BSR); + * + * If you find bugs in this file, its very likely that the same bug + * will also be in w83977af_ir.c since the implementations are quite + * similar. + * + ********************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_APM +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#define CHIP_IO_EXTENT 8 +#define BROKEN_DONGLE_ID + +static char *driver_name = "nsc-ircc"; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static int dongle_id = 0; + +/* Use BIOS settions by default, but user may supply module parameters */ +static unsigned int io[] = { ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0, 0 }; + +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); + +/* These are the known NSC chips */ +static nsc_chip_t chips[] = { + { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, + nsc_ircc_probe_108, nsc_ircc_init_108 }, + { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, + nsc_ircc_probe_338, nsc_ircc_init_338 }, + { NULL } +}; + +/* Max 4 instances for now */ +static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; + +static char *dongle_types[] = { + "Differential serial interface", + "Differential serial interface", + "Reserved", + "Reserved", + "Sharp RY5HD01", + "Reserved", + "Single-ended serial interface", + "Consumer-IR only", + "HP HSDL-2300, HP HSDL-3600/HSDL-3610", + "IBM31T1100 or Temic TFDS6000/TFDS6500", + "Reserved", + "Reserved", + "HP HSDL-1100/HSDL-2100", + "HP HSDL-1100/HSDL-2100" + "Supports SIR Mode only", + "No dongle connected", +}; + +/* Some prototypes */ +static int nsc_ircc_open(int i, chipio_t *info); +#ifdef MODULE +static int nsc_ircc_close(struct nsc_ircc_cb *self); +#endif /* MODULE */ +static int nsc_ircc_setup(chipio_t *info); +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); +static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); +static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); +static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); +static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self); +static int nsc_ircc_read_dongle_id (int iobase); +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); + +static int nsc_ircc_net_init(struct net_device *dev); +static int nsc_ircc_net_open(struct net_device *dev); +static int nsc_ircc_net_close(struct net_device *dev); +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); +#ifdef CONFIG_APM +static int nsc_ircc_apmproc(apm_event_t event); +#endif /* CONFIG_APM */ + +/* + * Function nsc_ircc_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +int __init nsc_ircc_init(void) +{ + chipio_t info; + nsc_chip_t *chip; + int ret = -ENODEV; + int cfg_base; + int cfg, id; + int reg; + int i = 0; + + /* Probe for all the NSC chipsets we know about */ + for (chip=chips; chip->name ; chip++,i++) { + IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", + chip->name); + + /* Try all config registers for this chip */ + for (cfg=0; cfg<3; cfg++) { + cfg_base = chip->cfg[cfg]; + if (!cfg_base) + continue; + + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + /* Read index register */ + reg = inb(cfg_base); + if (reg == 0xff) { + IRDA_DEBUG(2, __FUNCTION__ + "() no chip at 0x%03x\n", cfg_base); + continue; + } + + /* Read chip identification register */ + outb(chip->cid_index, cfg_base); + id = inb(cfg_base+1); + if ((id & chip->cid_mask) == chip->cid_value) { + IRDA_DEBUG(2, __FUNCTION__ + "() Found %s chip, revision=%d\n", + chip->name, id & ~chip->cid_mask); + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 2000) { + chip->init(chip, &info); + } else + chip->probe(chip, &info); + + if (nsc_ircc_open(i, &info) == 0) + ret = 0; + i++; + } else { + IRDA_DEBUG(2, __FUNCTION__ + "(), Wrong chip id=0x%02x\n", id); + } + } + + } +#ifdef CONFIG_APM + /* Make sure at least one chip was found before enabling APM */ + if (ret == 0) + apm_register_callback(nsc_ircc_apmproc); +#endif /* CONFIG_APM */ + + return ret; +} + +/* + * Function nsc_ircc_cleanup () + * + * Close all configured chips + * + */ +#ifdef MODULE +static void nsc_ircc_cleanup(void) +{ + int i; + +#ifdef CONFIG_APM + apm_unregister_callback(nsc_ircc_apmproc); +#endif /* CONFIG_APM */ + + for (i=0; i < 4; i++) { + if (dev_self[i]) + nsc_ircc_close(dev_self[i]); + } +} +#endif /* MODULE */ + +/* + * Function nsc_ircc_open (iobase, irq) + * + * Open driver instance + * + */ +static int nsc_ircc_open(int i, chipio_t *info) +{ + struct net_device *dev; + struct nsc_ircc_cb *self; + int ret; + int err; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + if ((nsc_ircc_setup(info)) == -1) + return -1; + + /* Allocate new instance of the driver */ + self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); + if (self == NULL) { + ERROR(__FUNCTION__ "(), can't allocate memory for " + "control block!\n"); + return -ENOMEM; + } + memset(self, 0, sizeof(struct nsc_ircc_cb)); + spin_lock_init(&self->lock); + + /* Need to store self somewhere */ + dev_self[i] = self; + self->index = i; + + /* Initialize IO */ + self->io.cfg_base = info->cfg_base; + self->io.fir_base = info->fir_base; + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; + self->io.fifo_size = 32; + + /* Reserve the ioports that we need */ + ret = check_region(self->io.fir_base, self->io.fir_ext); + if (ret < 0) { + WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", + self->io.fir_base); + dev_self[i] = NULL; + kfree(self); + return -ENODEV; + } + request_region(self->io.fir_base, self->io.fir_ext, driver_name); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); + + self->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&self->qos); + + self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 14384; + + /* Allocate memory if needed */ + self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->rx_buff.head == NULL) { + kfree(self); + return -ENOMEM; + } + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + + self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + kfree(self); + kfree(self->rx_buff.head); + return -ENOMEM; + } + memset(self->tx_buff.head, 0, self->tx_buff.truesize); + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + if (!(dev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -ENOMEM; + } + + dev->priv = (void *) self; + self->netdev = dev; + + /* Override the network functions we need to use */ + dev->init = nsc_ircc_net_init; + dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; + dev->open = nsc_ircc_net_open; + dev->stop = nsc_ircc_net_close; + dev->do_ioctl = nsc_ircc_net_ioctl; + dev->get_stats = nsc_ircc_net_get_stats; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + MESSAGE("IrDA: Registered device %s\n", dev->name); + + /* Check if user has supplied the dongle id or not */ + if (!dongle_id) { + dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); + + MESSAGE("%s, Found dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } else { + MESSAGE("%s, Using dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } + + self->io.dongle_id = dongle_id; + nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); + + return 0; +} + +#ifdef MODULE +/* + * Function nsc_ircc_close (self) + * + * Close driver instance + * + */ +static int nsc_ircc_close(struct nsc_ircc_cb *self) +{ + int iobase; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return -1;); + + iobase = self->io.fir_base; + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + rtnl_unlock(); + } + + /* Release the PORT that this driver is using */ + IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", + self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + + if (self->tx_buff.head) + kfree(self->tx_buff.head); + + if (self->rx_buff.head) + kfree(self->rx_buff.head); + + dev_self[self->index] = NULL; + kfree(self); + + return 0; +} +#endif /* MODULE */ + +/* + * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma) + * + * Initialize the NSC '108 chip + * + */ +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + __u8 temp=0; + + outb(2, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x00, cfg_base+1); /* Disable device */ + + /* Base Address and Interrupt Control Register (BAIC) */ + outb(0, cfg_base); + switch (info->fir_base) { + case 0x3e8: outb(0x14, cfg_base+1); break; + case 0x2e8: outb(0x15, cfg_base+1); break; + case 0x3f8: outb(0x16, cfg_base+1); break; + case 0x2f8: outb(0x17, cfg_base+1); break; + default: ERROR(__FUNCTION__ "(), invalid base_address"); + } + + /* Control Signal Routing Register (CSRT) */ + switch (info->irq) { + case 3: temp = 0x01; break; + case 4: temp = 0x02; break; + case 5: temp = 0x03; break; + case 7: temp = 0x04; break; + case 9: temp = 0x05; break; + case 11: temp = 0x06; break; + case 15: temp = 0x07; break; + default: ERROR(__FUNCTION__ "(), invalid irq"); + } + outb(1, cfg_base); + + switch (info->dma) { + case 0: outb(0x08+temp, cfg_base+1); break; + case 1: outb(0x10+temp, cfg_base+1); break; + case 3: outb(0x18+temp, cfg_base+1); break; + default: ERROR(__FUNCTION__ "(), invalid dma"); + } + + outb(2, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x03, cfg_base+1); /* Enable device */ + + return 0; +} + +/* + * Function nsc_ircc_probe_108 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg; + + /* Read address and interrupt control register (BAIC) */ + outb(CFG_BAIC, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x03) { + case 0: + info->fir_base = 0x3e8; + break; + case 1: + info->fir_base = 0x2e8; + break; + case 2: + info->fir_base = 0x3f8; + break; + case 3: + info->fir_base = 0x2f8; + break; + } + info->sir_base = info->fir_base; + IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", + info->fir_base); + + /* Read control signals routing register (CSRT) */ + outb(CFG_CSRT, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x07) { + case 0: + info->irq = -1; + break; + case 1: + info->irq = 3; + break; + case 2: + info->irq = 4; + break; + case 3: + info->irq = 5; + break; + case 4: + info->irq = 7; + break; + case 5: + info->irq = 9; + break; + case 6: + info->irq = 11; + break; + case 7: + info->irq = 15; + break; + } + IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + + /* Currently we only read Rx DMA but it will also be used for Tx */ + switch ((reg >> 3) & 0x03) { + case 0: + info->dma = -1; + break; + case 1: + info->dma = 0; + break; + case 2: + info->dma = 1; + break; + case 3: + info->dma = 3; + break; + } + IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + + /* Read mode control register (MCTL) */ + outb(CFG_MCTL, cfg_base); + reg = inb(cfg_base+1); + + info->enabled = reg & 0x01; + info->suspended = !((reg >> 1) & 0x01); + + return 0; +} + +/* + * Function nsc_ircc_init_338 (chip, info) + * + * Initialize the NSC '338 chip. Remember that the 87338 needs two + * consecutive writes to the data registers while CPU interrupts are + * disabled. The 97338 does not require this, but shouldn't be any + * harm if we do it anyway. + */ +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) +{ + /* No init yet */ + + return 0; +} + +/* + * Function nsc_ircc_probe_338 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg, com = 0; + int pnp; + + /* Read funtion enable register (FER) */ + outb(CFG_FER, cfg_base); + reg = inb(cfg_base+1); + + info->enabled = (reg >> 2) & 0x01; + + /* Check if we are in Legacy or PnP mode */ + outb(CFG_PNP0, cfg_base); + reg = inb(cfg_base+1); + + pnp = (reg >> 4) & 0x01; + if (pnp) { + IRDA_DEBUG(2, "(), Chip is in PnP mode\n"); + outb(0x46, cfg_base); + reg = (inb(cfg_base+1) & 0xfe) << 2; + + outb(0x47, cfg_base); + reg |= ((inb(cfg_base+1) & 0xfc) << 8); + + info->fir_base = reg; + } else { + /* Read function address register (FAR) */ + outb(CFG_FAR, cfg_base); + reg = inb(cfg_base+1); + + switch ((reg >> 4) & 0x03) { + case 0: + info->fir_base = 0x3f8; + break; + case 1: + info->fir_base = 0x2f8; + break; + case 2: + com = 3; + break; + case 3: + com = 4; + break; + } + + if (com) { + switch ((reg >> 6) & 0x03) { + case 0: + if (com == 3) + info->fir_base = 0x3e8; + else + info->fir_base = 0x2e8; + break; + case 1: + if (com == 3) + info->fir_base = 0x338; + else + info->fir_base = 0x238; + break; + case 2: + if (com == 3) + info->fir_base = 0x2e8; + else + info->fir_base = 0x2e0; + break; + case 3: + if (com == 3) + info->fir_base = 0x220; + else + info->fir_base = 0x228; + break; + } + } + } + info->sir_base = info->fir_base; + + /* Read PnP register 1 (PNP1) */ + outb(CFG_PNP1, cfg_base); + reg = inb(cfg_base+1); + + info->irq = reg >> 4; + + /* Read PnP register 3 (PNP3) */ + outb(CFG_PNP3, cfg_base); + reg = inb(cfg_base+1); + + info->dma = (reg & 0x07) - 1; + + /* Read power and test register (PTR) */ + outb(CFG_PTR, cfg_base); + reg = inb(cfg_base+1); + + info->suspended = reg & 0x01; + + return 0; +} + +/* + * Function nsc_ircc_setup (info) + * + * Returns non-negative on success. + * + */ +static int nsc_ircc_setup(chipio_t *info) +{ + int version; + int iobase = info->fir_base; + + /* Read the Module ID */ + switch_bank(iobase, BANK3); + version = inb(iobase+MID); + + /* Should be 0x2? */ + if (0x20 != (version & 0xf0)) { + ERROR("%s, Wrong chip version %02x\n", driver_name, version); + return -1; + } + MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, + info->cfg_base); + + /* Switch to advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); + + /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ + switch_bank(iobase, BANK0); + outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + /* IRCR2: FEND_MD is set */ + switch_bank(iobase, BANK5); + outb(0x2a, iobase+4); + + /* Make sure that some defaults are OK */ + switch_bank(iobase, BANK6); + outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ + outb(0x0a, iobase+1); /* Set MIR pulse width */ + outb(0x0d, iobase+2); /* Set SIR pulse width */ + outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ + + MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); + + /* Enable receive interrupts */ + switch_bank(iobase, BANK0); + outb(IER_RXHDL_IE, iobase+IER); + + return 0; +} + +/* + * Function nsc_ircc_read_dongle_id (void) + * + * Try to read dongle indentification. This procedure needs to be executed + * once after power-on/reset. It also needs to be used whenever you suspect + * that the user may have plugged/unplugged the IrDA Dongle. + */ +static int nsc_ircc_read_dongle_id (int iobase) +{ + int dongle_id; + __u8 bank; + + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ + outb(0x00, iobase+7); + + /* ID0, 1, and 2 are pulled up/down very slowly */ + udelay(50); + + /* IRCFG1: read the ID bits */ + dongle_id = inb(iobase+4) & 0x0f; + +#ifdef BROKEN_DONGLE_ID + if (dongle_id == 0x0a) + dongle_id = 0x09; +#endif + /* Go back to bank 0 before returning */ + switch_bank(iobase, BANK0); + + outb(bank, iobase+BSR); + + return dongle_id; +} + +/* + * Function nsc_ircc_init_dongle_interface (iobase, dongle_id) + * + * This function initializes the dongle for the transceiver that is + * used. This procedure needs to be executed once after + * power-on/reset. It also needs to be used whenever you suspect that + * the dongle is changed. + */ +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) +{ + int bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + break; + case 0x05: /* Reserved, but this is what the Thinkpad reports */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", + dongle_types[dongle_id]); + break; + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + /* + * Set irsl0 as input, irsl[1-2] as output, and separate + * inputs are used for SIR and MIR/FIR + */ + outb(0x48, iobase+7); + break; + case 0x0E: /* Supports SIR Mode only */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0F: /* No dongle connected */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", + dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", + dongle_id); + } + + /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ + outb(0x00, iobase+4); + + /* Restore bank register */ + outb(bank, iobase+BSR); + +} /* set_up_dongle_interface */ + +/* + * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id) + * + * Change speed of the attach dongle + * + */ +static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) +{ + unsigned long flags; + __u8 bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG1: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + case 0x05: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", + dongle_types[dongle_id]); + outb(0x00, iobase+4); + if (speed > 115200) + outb(0x01, iobase+4); + break; + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + outb(0x01, iobase+4); + + if (speed == 4000000) { + save_flags(flags); + cli(); + outb(0x81, iobase+4); + outb(0x80, iobase+4); + restore_flags(flags); + } else + outb(0x00, iobase+4); + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + break; + case 0x0E: /* Supports SIR Mode only */ + break; + case 0x0F: /* No dongle connected */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n"); + } + /* Restore bank register */ + outb(bank, iobase+BSR); +} + +/* + * Function nsc_ircc_change_speed (self, baud) + * + * Change the speed of the device + * + */ +static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) +{ + struct net_device *dev = self->netdev; + __u8 mcr = MCR_SIR; + int iobase; + __u8 bank; + + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed); + + ASSERT(self != NULL, return;); + + iobase = self->io.fir_base; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + /* Select Bank 2 */ + switch_bank(iobase, BANK2); + + outb(0x00, iobase+BGDH); + switch (speed) { + case 9600: outb(0x0c, iobase+BGDL); break; + case 19200: outb(0x06, iobase+BGDL); break; + case 38400: outb(0x03, iobase+BGDL); break; + case 57600: outb(0x02, iobase+BGDL); break; + case 115200: outb(0x01, iobase+BGDL); break; + case 576000: + switch_bank(iobase, BANK5); + + /* IRCR2: MDRS is set */ + outb(inb(iobase+4) | 0x04, iobase+4); + + mcr = MCR_MIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); + break; + case 1152000: + mcr = MCR_MIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); + break; + case 4000000: + mcr = MCR_FIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); + break; + default: + mcr = MCR_FIR; + IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", + speed); + break; + } + + /* Set appropriate speed mode */ + switch_bank(iobase, BANK0); + outb(mcr | MCR_TX_DFR, iobase+MCR); + + /* Give some hits to the transceiver */ + nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); + + /* Set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, BANK0); + outb(0x00, iobase+FCR); + outb(FCR_FIFO_EN, iobase+FCR); + outb(FCR_RXTH| /* Set Rx FIFO threshold */ + FCR_TXTH| /* Set Tx FIFO threshold */ + FCR_TXSR| /* Reset Tx FIFO */ + FCR_RXSR| /* Reset Rx FIFO */ + FCR_FIFO_EN, /* Enable FIFOs */ + iobase+FCR); + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + self->netdev->tbusy = 0; + + /* Enable some interrupts so we can receive frames */ + switch_bank(iobase, BANK0); + if (speed > 115200) { + /* Install FIR xmit handler */ + dev->hard_start_xmit = nsc_ircc_hard_xmit_fir; + outb(IER_SFIF_IE, iobase+IER); + nsc_ircc_dma_receive(self); + } else { + /* Install SIR xmit handler */ + dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; + outb(IER_RXHDL_IE, iobase+IER); + } + + /* Restore BSR */ + outb(bank, iobase+BSR); +} + +/* + * Function nsc_ircc_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +{ + struct nsc_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + __u8 bank; + + self = (struct nsc_ircc_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + /* Lock transmit buffer */ + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + /* Check if we need to change the speed */ + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + + spin_lock_irqsave(&self->lock, flags); + + /* Save current bank */ + bank = inb(iobase+BSR); + + self->tx_buff.data = self->tx_buff.head; + + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + self->stats.tx_bytes += self->tx_buff.len; + + /* Add interrupt on tx low level (will fire immediately) */ + switch_bank(iobase, BANK0); + outb(IER_TXLDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +{ + struct nsc_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + __u8 bank; + int mtt, diff; + + self = (struct nsc_ircc_cb *) dev->priv; + iobase = self->io.fir_base; + + /* Lock transmit buffer */ + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + /* Check if we need to change the speed */ + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + + spin_lock_irqsave(&self->lock, flags); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Register and copy this frame to DMA memory */ + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + self->tx_fifo.tail += skb->len; + + self->stats.tx_bytes += skb->len; + + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); + + self->tx_fifo.len++; + self->tx_fifo.free++; + + /* Start transmit only if there is currently no transmit going on */ + if (self->tx_fifo.len == 1) { + /* Check if we must wait the min turn time or not */ + mtt = irda_get_mtt(skb); + if (mtt) { + /* Check how much time we have used already */ + get_fast_time(&self->now); + diff = self->now.tv_usec - self->stamp.tv_usec; + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + + /* + * Use timer if delay larger than 125 us, and + * use udelay for smaller values which should + * be acceptable + */ + if (mtt > 125) { + /* Adjust for timer resolution */ + mtt = mtt / 125; + + /* Setup timer */ + switch_bank(iobase, BANK4); + outb(mtt & 0xff, iobase+TMRL); + outb((mtt >> 8) & 0x0f, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + self->io.direction = IO_XMIT; + + /* Enable timer interrupt */ + switch_bank(iobase, BANK0); + outb(IER_TMR_IE, iobase+IER); + + /* Timer will take care of the rest */ + goto out; + } else + udelay(mtt); + } + } + /* Enable DMA interrupt */ + switch_bank(iobase, BANK0); + outb(IER_DMA_IE, iobase+IER); + + /* Transmit frame */ + nsc_ircc_dma_xmit(self, iobase); + } + out: + /* Not busy transmitting anymore if window is not full */ + if (self->tx_fifo.free < MAX_TX_WINDOW) + dev->tbusy = 0; + + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function nsc_ircc_dma_xmit (self, iobase) + * + * Transmit data using DMA + * + */ +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase) +{ + int bsr; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + self->io.direction = IO_XMIT; + + /* Choose transmit DMA channel */ + switch_bank(iobase, BANK2); + outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + setup_dma(self->io.dma, + self->tx_fifo.queue[self->tx_fifo.ptr].start, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + DMA_TX_MODE); + + /* Enable DMA and SIR interaction pulse */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); +} + +/* + * Function nsc_ircc_pio_xmit (self, iobase) + * + * Transmit data using PIO. Returns the number of bytes that actually + * got transfered + * + */ +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) +{ + int actual = 0; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Save current bank */ + bank = inb(iobase+BSR); + + switch_bank(iobase, BANK0); + if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { + IRDA_DEBUG(4, __FUNCTION__ + "(), warning, FIFO not empty yet!\n"); + + /* FIFO may still be filled to the Tx interrupt threshold */ + fifo_size -= 17; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual++], iobase+TXD); + } + + IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", + fifo_size, actual, len); + + /* Restore bank */ + outb(bank, iobase+BSR); + + return actual; +} + +/* + * Function nsc_ircc_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) +{ + int iobase; + __u8 bank; + int ret = TRUE; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + iobase = self->io.fir_base; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Check for underrrun! */ + if (inb(iobase+ASCR) & ASCR_TXUR) { + self->stats.tx_errors++; + self->stats.tx_fifo_errors++; + + /* Clear bit, by writing 1 into it */ + outb(ASCR_TXUR, iobase+ASCR); + } else { + self->stats.tx_packets++; + } + + /* Check if we need to change the speed */ + if (self->new_speed) { + nsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Finished with this frame, so prepare for next */ + self->tx_fifo.ptr++; + self->tx_fifo.len--; + + /* Any frames to be sent back-to-back? */ + if (self->tx_fifo.len) { + nsc_ircc_dma_xmit(self, iobase); + + /* Not finished yet! */ + ret = FALSE; + } else { + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + } + + /* Make sure we have room for more frames */ + if (self->tx_fifo.free < MAX_TX_WINDOW) { + /* Not busy transmitting anymore */ + self->netdev->tbusy = 0; + + /* Tell the network layer, that we can accept more frames */ + mark_bh(NET_BH); + } + + /* Restore bank */ + outb(bank, iobase+BSR); + + return ret; +} + +/* + * Function nsc_ircc_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) +{ + int iobase; + __u8 bsr; + + iobase = self->io.fir_base; + + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Choose DMA Rx, DMA Fairness, and Advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Rx FIFO. This will also flush the ST_FIFO */ + switch_bank(iobase, BANK0); + outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; + + setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Enable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); + + return 0; +} + +/* + * Function nsc_ircc_dma_receive_complete (self) + * + * Finished with receiving frames + * + * + */ +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + __u8 status; + __u8 bank; + int len; + + st_fifo = &self->st_fifo; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Read all entries in status FIFO */ + switch_bank(iobase, BANK5); + while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { + /* We must empty the status FIFO no matter what */ + len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); + + if (st_fifo->tail >= MAX_RX_WINDOW) + continue; + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; + st_fifo->tail++; + st_fifo->len++; + } + /* Try to process all entries in status FIFO */ + while (st_fifo->len > 0) { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->pending_bytes -= len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if (status & FRM_ST_ERR_MSK) { + if (status & FRM_ST_LOST_FR) { + /* Add number of lost frames to stats */ + self->stats.rx_errors += len; + } else { + /* Skip frame */ + self->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & FRM_ST_MAX_LEN) + self->stats.rx_length_errors++; + + if (status & FRM_ST_PHY_ERR) + self->stats.rx_frame_errors++; + + if (status & FRM_ST_BAD_CRC) + self->stats.rx_crc_errors++; + } + /* The errors below can be reported in both cases */ + if (status & FRM_ST_OVR1) + self->stats.rx_fifo_errors++; + + if (status & FRM_ST_OVR2) + self->stats.rx_fifo_errors++; + } else { + /* + * First we must make sure that the frame we + * want to deliver is all in main memory. If we + * cannot tell, then we check if the Rx FIFO is + * empty. If not then we will have to take a nap + * and try again later. + */ + if (st_fifo->pending_bytes < self->io.fifo_size) { + switch_bank(iobase, BANK0); + if (inb(iobase+LSR) & LSR_RXDA) { + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->pending_bytes += len; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; /* I'll be back! */ + } + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + get_fast_time(&self->stamp); + + skb = dev_alloc_skb(len+1); + if (skb == NULL) { + WARNING(__FUNCTION__ "(), memory squeeze, " + "dropping frame.\n"); + self->stats.rx_dropped++; + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + /* Copy frame without CRC */ + if (self->io.speed < 4000000) { + skb_put(skb, len-2); + memcpy(skb->data, self->rx_buff.data, len-2); + } else { + skb_put(skb, len-4); + memcpy(skb->data, self->rx_buff.data, len-4); + } + + /* Move to next frame */ + self->rx_buff.data += len; + self->stats.rx_bytes += len; + self->stats.rx_packets++; + + skb->dev = self->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + /* Restore bank register */ + outb(bank, iobase+BSR); + + return TRUE; +} + +/* + * Function nsc_ircc_pio_receive (self) + * + * Receive all data in receiver FIFO + * + */ +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) +{ + __u8 byte; + int iobase; + + iobase = self->io.fir_base; + + /* Receive all characters in Rx FIFO */ + do { + byte = inb(iobase+RXD); + async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + byte); + } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ +} + +/* + * Function nsc_ircc_sir_interrupt (self, eir) + * + * Handle SIR interrupt + * + */ +static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) +{ + int actual; + + /* Check if transmit FIFO is low on data */ + if (eir & EIR_TXLDL_EV) { + /* Write data left in transmit buffer */ + actual = nsc_ircc_pio_write(self->io.fir_base, + self->tx_buff.data, + self->tx_buff.len, + self->io.fifo_size); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + + self->io.direction = IO_XMIT; + + /* Check if finished */ + if (self->tx_buff.len > 0) + self->ier = IER_TXLDL_IE; + else { + self->netdev->tbusy = 0; /* Unlock */ + self->stats.tx_packets++; + + mark_bh(NET_BH); + + self->ier = IER_TXEMP_IE; + } + + } + /* Check if transmission has completed */ + if (eir & EIR_TXEMP_EV) { + /* Check if we need to change the speed? */ + if (self->new_speed) { + IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n"); + nsc_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + + /* Check if we are going to FIR */ + if (self->io.speed > 115200) { + /* Should wait for status FIFO interrupt */ + self->ier = IER_SFIF_IE; + + /* No need to do anymore SIR stuff */ + return; + } + } + /* Turn around and get ready to receive some data */ + self->io.direction = IO_RECV; + self->ier = IER_RXHDL_IE; + } + + /* Rx FIFO threshold or timeout */ + if (eir & EIR_RXHDL_EV) { + nsc_ircc_pio_receive(self); + + /* Keep receiving */ + self->ier = IER_RXHDL_IE; + } +} + +/* + * Function nsc_ircc_fir_interrupt (self, eir) + * + * Handle MIR/FIR interrupt + * + */ +static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, + int eir) +{ + __u8 bank; + + bank = inb(iobase+BSR); + + /* Status FIFO event*/ + if (eir & EIR_SFIF_EV) { + if (nsc_ircc_dma_receive_complete(self, iobase)) { + /* Wait for next status FIFO interrupt */ + self->ier = IER_SFIF_IE; + } else { + /* + * DMA not finished yet, so try again later, set + * timer value, resolution 125 us + */ + switch_bank(iobase, BANK4); + outb(0x02, iobase+TMRL); /* 2 * 125 us */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + self->ier = IER_TMR_IE | IER_SFIF_IE; + } + } else if (eir & EIR_TMR_EV) { /* Timer finished */ + /* Disable timer */ + switch_bank(iobase, BANK4); + outb(0, iobase+IRCR1); + + /* Clear timer event */ + switch_bank(iobase, BANK0); + outb(ASCR_CTE, iobase+ASCR); + + /* Check if this is a Tx timer interrupt */ + if (self->io.direction == IO_XMIT) { + nsc_ircc_dma_xmit(self, iobase); + + /* Interrupt on DMA */ + self->ier = IER_DMA_IE; + } else { + /* Check if DMA has now finished */ + nsc_ircc_dma_receive_complete(self, iobase); + + self->ier = IER_SFIF_IE; + } + } else if (eir & EIR_DMA_EV) { + /* Finished with all transmissions? */ + if (nsc_ircc_dma_xmit_complete(self)) { + /* Check if there are more frames to be transmitted */ + if (irda_device_txqueue_empty(self->netdev)) { + /* Prepare for receive */ + nsc_ircc_dma_receive(self); + + self->ier = IER_SFIF_IE; + } + } else { + /* Not finished yet, so interrupt on DMA again */ + self->ier = IER_DMA_IE; + } + } + outb(bank, iobase+BSR); +} + +/* + * Function nsc_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct nsc_ircc_cb *self; + __u8 bsr, eir; + int iobase; + + if (!dev) { + WARNING("%s: irq %d for unknown device.\n", driver_name, irq); + return; + } + self = (struct nsc_ircc_cb *) dev->priv; + + spin_lock(&self->lock); + dev->interrupt = 1; + + iobase = self->io.fir_base; + + bsr = inb(iobase+BSR); /* Save current bank */ + + switch_bank(iobase, BANK0); + self->ier = inb(iobase+IER); + eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ + + outb(0, iobase+IER); /* Disable interrupts */ + + if (eir) { + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > 115200) + nsc_ircc_fir_interrupt(self, iobase, eir); + else + nsc_ircc_sir_interrupt(self, eir); + } + + outb(self->ier, iobase+IER); /* Restore interrupts */ + outb(bsr, iobase+BSR); /* Restore bank register */ + + dev->interrupt = 0; + spin_unlock(&self->lock); +} + +/* + * Function nsc_ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self) +{ + unsigned long flags; + int status = FALSE; + int iobase; + __u8 bank; + + ASSERT(self != NULL, return FALSE;); + + spin_lock_irqsave(&self->lock, flags); + + if (self->io.speed > 115200) { + iobase = self->io.fir_base; + + /* Check if rx FIFO is not empty */ + bank = inb(iobase+BSR); + switch_bank(iobase, BANK2); + if ((inb(iobase+RXFLV) & 0x3f) != 0) { + /* We are receiving something */ + status = TRUE; + } + outb(bank, iobase+BSR); + } else + status = (self->rx_buff.state != OUTSIDE_FRAME); + + spin_unlock_irqrestore(&self->lock, flags); + + return status; +} + +/* + * Function nsc_ircc_net_init (dev) + * + * Initialize network device + * + */ +static int nsc_ircc_net_init(struct net_device *dev) +{ + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Setup to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function nsc_ircc_net_open (dev) + * + * Start the device + * + */ +static int nsc_ircc_net_open(struct net_device *dev) +{ + struct nsc_ircc_cb *self; + int iobase; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(dev != NULL, return -1;); + self = (struct nsc_ircc_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) { + WARNING("%s, unable to allocate irq=%d\n", driver_name, + self->io.irq); + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + WARNING("%s, unable to allocate dma=%d\n", driver_name, + self->io.dma); + free_irq(self->io.irq, self); + return -EAGAIN; + } + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* turn on interrupts */ + switch_bank(iobase, BANK0); + outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + /* Ready to play! */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * Function nsc_ircc_net_close (dev) + * + * Stop the device + * + */ +static int nsc_ircc_net_close(struct net_device *dev) +{ + struct nsc_ircc_cb *self; + int iobase; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(dev != NULL, return -1;); + + self = (struct nsc_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + iobase = self->io.fir_base; + + disable_dma(self->io.dma); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Function nsc_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct nsc_ircc_cb *self; + unsigned long flags; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + nsc_ircc_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = nsc_ircc_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + restore_flags(flags); + + return ret; +} + +static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) +{ + struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv; + + return &self->stats; +} + +#ifdef CONFIG_APM +static void nsc_ircc_suspend(struct nsc_ircc_cb *self) +{ + MESSAGE("%s, Suspending\n", driver_name); + + if (self->io.suspended) + return; + + nsc_ircc_net_close(self->netdev); + + self->io.suspended = 1; +} + +static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) +{ + struct net_device *dev = self->netdev; + int iobase; + + if (!self->io.suspended) + return; + + iobase = self->io.fir_base; + + /* Switch to advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); + + nsc_ircc_net_open(self->netdev); + + MESSAGE("%s, Waking up\n", driver_name); + + self->io.suspended = 0; +} + +static int nsc_ircc_apmproc(apm_event_t event) +{ + static int down = 0; /* Filter out double events */ + int i; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (!down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + nsc_ircc_suspend(dev_self[i]); + } + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + nsc_ircc_wakeup(dev_self[i]); + } + } + down = 0; + break; + } + return 0; +} +#endif /* CONFIG_APM */ + +#ifdef MODULE +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("NSC IrDA Device Driver"); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM(io, "1-4i"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM(dma, "1-4i"); +MODULE_PARM(dongle_id, "i"); + +int init_module(void) +{ + return nsc_ircc_init(); +} + +void cleanup_module(void) +{ + nsc_ircc_cleanup(); +} +#endif /* MODULE */ + diff -ur --new-file old/linux/drivers/net/irda/nsc_fir.c new/linux/drivers/net/irda/nsc_fir.c --- old/linux/drivers/net/irda/nsc_fir.c Fri Jan 7 20:51:56 2000 +++ new/linux/drivers/net/irda/nsc_fir.c Thu Jan 1 01:00:00 1970 @@ -1,1825 +0,0 @@ -/********************************************************************* - * - * Filename: nsc_fir.c - * Version: 1.0 - * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets - * Status: Stable. - * Author: Dag Brattli - * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Wed Jan 5 13:59:21 2000 - * Modified by: Dag Brattli - * - * Copyright (c) 1998-2000 Dag Brattli - * Copyright (c) 1998 Lichen Wang, - * Copyright (c) 1998 Actisys Corp., www.actisys.com - * All Rights Reserved - * - * 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. - * - * Neither Dag Brattli nor University of Tromsř admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * Notice that all functions that needs to access the chip in _any_ - * way, must save BSR register on entry, and restore it on exit. - * It is _very_ important to follow this policy! - * - * __u8 bank; - * - * bank = inb(iobase+BSR); - * - * do_your_stuff_here(); - * - * outb(bank, iobase+BSR); - * - * If you find bugs in this file, its very likely that the same bug - * will also be in w83977af_ir.c since the implementations are quite - * similar. - * - ********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_APM -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#define CHIP_IO_EXTENT 8 -#define BROKEN_DONGLE_ID - -/* - * Define if you have multiple NSC IrDA controllers in your machine. Not - * enabled by default since some single chips detects at multiple addresses - */ -#undef CONFIG_NSC_FIR_MULTIPLE - -static char *driver_name = "nsc_fir"; - -/* Module parameters */ -static int qos_mtt_bits = 0x07; /* 1 ms or more */ -static int dongle_id = 0; - -static unsigned int io[] = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 }; -static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e }; -static unsigned int irq[] = { 3, 3, 3, 3, 3 }; -static unsigned int dma[] = { 0, 0, 0, 0, 3 }; - -static struct nsc_fir_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; - -static char *dongle_types[] = { - "Differential serial interface", - "Differential serial interface", - "Reserved", - "Reserved", - "Sharp RY5HD01", - "Reserved", - "Single-ended serial interface", - "Consumer-IR only", - "HP HSDL-2300, HP HSDL-3600/HSDL-3610", - "IBM31T1100 or Temic TFDS6000/TFDS6500", - "Reserved", - "Reserved", - "HP HSDL-1100/HSDL-2100", - "HP HSDL-1100/HSDL-2100" - "Supports SIR Mode only", - "No dongle connected", -}; - -/* Some prototypes */ -static int nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma); -#ifdef MODULE -static int nsc_fir_close(struct nsc_fir_cb *self); -#endif /* MODULE */ -static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma); -static void nsc_fir_pio_receive(struct nsc_fir_cb *self); -static int nsc_fir_dma_receive(struct nsc_fir_cb *self); -static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase); -static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); -static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size); -static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase); -static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 baud); -static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int nsc_fir_is_receiving(struct nsc_fir_cb *self); -static int nsc_fir_read_dongle_id (int iobase); -static void nsc_fir_init_dongle_interface (int iobase, int dongle_id); - -static int nsc_fir_net_init(struct net_device *dev); -static int nsc_fir_net_open(struct net_device *dev); -static int nsc_fir_net_close(struct net_device *dev); -static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev); -#ifdef CONFIG_APM -static int nsc_fir_apmproc(apm_event_t event); -#endif /* CONFIG_APM */ -/* - * Function nsc_fir_init () - * - * Initialize chip. Just try to find out how many chips we are dealing with - * and where they are - */ -int __init nsc_fir_init(void) -{ - int ret = -ENODEV; - int ioaddr; - int i; - -#ifdef CONFIG_APM - apm_register_callback(nsc_fir_apmproc); -#endif /* CONFIG_APM */ - - for (i=0; (io[i] < 2000) && (i < 5); i++) { - ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) - continue; - if (nsc_fir_open(i, io[i], io2[i], irq[i], dma[i]) == 0) - { -#ifdef CONFIG_NSC_FIR_MULTIPLE - ret = 0; -#else - return 0; -#endif - } - } - - return ret; -} - -/* - * Function nsc_fir_cleanup () - * - * Close all configured chips - * - */ -#ifdef MODULE -static void nsc_fir_cleanup(void) -{ - int i; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - -#ifdef CONFIG_APM - apm_unregister_callback(nsc_fir_apmproc); -#endif /* CONFIG_APM */ - - - for (i=0; i < 5; i++) { - if (dev_self[i]) - nsc_fir_close(dev_self[i]); - } -} -#endif /* MODULE */ - -/* - * Function nsc_fir_open (iobase, irq) - * - * Open driver instance - * - */ -static int -nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma) -{ - struct net_device *dev; - struct nsc_fir_cb *self; - int dongle_id; - int ret; - int err; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - - if ((dongle_id = nsc_fir_probe(iobase, board_addr, irq, dma)) == -1) - return -1; - - /* - * Allocate new instance of the driver - */ - self = kmalloc(sizeof(struct nsc_fir_cb), GFP_KERNEL); - if (self == NULL) { - ERROR(__FUNCTION__ "(), can't allocate memory for " - "control block!\n"); - return -ENOMEM; - } - memset(self, 0, sizeof(struct nsc_fir_cb)); - spin_lock_init(&self->lock); - - /* Need to store self somewhere */ - dev_self[i] = self; - - /* Initialize IO */ - self->io.iobase = iobase; - self->io.irq = irq; - self->io.io_ext = CHIP_IO_EXTENT; - self->io.dma = dma; - self->io.fifo_size = 32; - - /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); - if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); - /* nsc_fir_cleanup(self->self); */ - return -ENODEV; - } - request_region(self->io.iobase, self->io.io_ext, driver_name); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); - - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384; - self->tx_buff.truesize = 14384; - - /* Allocate memory if needed */ - self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->rx_buff.head == NULL) - return -ENOMEM; - memset(self->rx_buff.head, 0, self->rx_buff.truesize); - - self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->tx_buff.head == NULL) { - kfree(self->rx_buff.head); - return -ENOMEM; - } - memset(self->tx_buff.head, 0, self->tx_buff.truesize); - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Tx queue info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); - return -ENOMEM; - } - - dev->priv = (void *) self; - self->netdev = dev; - - /* Override the network functions we need to use */ - dev->init = nsc_fir_net_init; - dev->hard_start_xmit = nsc_fir_hard_xmit_sir; - dev->open = nsc_fir_net_open; - dev->stop = nsc_fir_net_close; - dev->do_ioctl = nsc_fir_net_ioctl; - dev->get_stats = nsc_fir_net_get_stats; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); - return -1; - } - - MESSAGE("IrDA: Registered device %s\n", dev->name); - - self->io.dongle_id = dongle_id; - nsc_fir_init_dongle_interface(iobase, dongle_id); - - return 0; -} - -#ifdef MODULE -/* - * Function nsc_fir_close (self) - * - * Close driver instance - * - */ -static int nsc_fir_close(struct nsc_fir_cb *self) -{ - int iobase; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return -1;); - - iobase = self->io.iobase; - - /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } - - /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); - - if (self->tx_buff.head) - kfree(self->tx_buff.head); - - if (self->rx_buff.head) - kfree(self->rx_buff.head); - - kfree(self); - - return 0; -} -#endif /* MODULE */ - -/* - * Function nsc_fir_init_807 (iobase, board_addr, irq, dma) - * - * Initialize the NSC '108 chip - * - */ -static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma) -{ - __u8 temp=0; - - outb(2, board_addr); /* Mode Control Register (MCTL) */ - outb(0x00, board_addr+1); /* Disable device */ - - /* Base Address and Interrupt Control Register (BAIC) */ - outb(0, board_addr); - switch (iobase) { - case 0x3e8: outb(0x14, board_addr+1); break; - case 0x2e8: outb(0x15, board_addr+1); break; - case 0x3f8: outb(0x16, board_addr+1); break; - case 0x2f8: outb(0x17, board_addr+1); break; - default: ERROR(__FUNCTION__ "(), invalid base_address"); - } - - /* Control Signal Routing Register (CSRT) */ - switch (irq) { - case 3: temp = 0x01; break; - case 4: temp = 0x02; break; - case 5: temp = 0x03; break; - case 7: temp = 0x04; break; - case 9: temp = 0x05; break; - case 11: temp = 0x06; break; - case 15: temp = 0x07; break; - default: ERROR(__FUNCTION__ "(), invalid irq"); - } - outb(1, board_addr); - - switch (dma) { - case 0: outb(0x08+temp, board_addr+1); break; - case 1: outb(0x10+temp, board_addr+1); break; - case 3: outb(0x18+temp, board_addr+1); break; - default: ERROR(__FUNCTION__ "(), invalid dma"); - } - - outb(2, board_addr); /* Mode Control Register (MCTL) */ - outb(0x03, board_addr+1); /* Enable device */ -} - -/* - * Function nsc_fir_init_338 (iobase, board_addr, irq, dma) - * - * Initialize the NSC '338 chip. Remember that the 87338 needs two - * consecutive writes to the data registers while CPU interrupts are - * disabled. The 97338 does not require this, but shouldn't be any - * harm if we do it anyway. - */ -static void nsc_fir_init_338(int iobase, int board_addr, int irq, int dma) -{ - /* No init yet */ -} - -static int nsc_fir_find_chip(int board_addr) -{ - __u8 index, id; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Read index register */ - index = inb(board_addr); - if (index == 0xff) { - IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n", - board_addr); - return -1; - } - - /* Read chip identification register (SID) for the PC97338 */ - outb(8, board_addr); - id = inb(board_addr+1); - if ((id & 0xf0) == PC97338) { - MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n", - driver_name, id & 0x0f); - return PC97338; - } - - /* Read device identification (DID) for the PC87108 */ - outb(5, board_addr); - id = inb(board_addr+1); - if ((id & 0xf0) == PC87108) { - MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n", - driver_name, id & 0x0f); - return PC87108; - } - - return -1; -} - -/* - * Function nsc_fir_probe (iobase, board_addr, irq, dma) - * - * Returns non-negative on success. - * - */ -static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma) -{ - int version; - __u8 chip; - - chip = nsc_fir_find_chip(board_addr); - switch (chip) { - case PC87108: - nsc_fir_init_807(iobase, board_addr, irq, dma); - break; - case PC97338: - nsc_fir_init_338(iobase, board_addr, irq, dma); - break; - default: - /* Found no chip */ - return -1; - } - - /* Read the Module ID */ - switch_bank(iobase, BANK3); - version = inb(iobase+MID); - - /* Should be 0x2? */ - if (0x20 != (version & 0xf0)) { - ERROR("%s, Wrong chip version %02x\n", driver_name, version); - return -1; - } - MESSAGE("%s, Found chip at base=0x%04x\n", driver_name, board_addr); - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - - /* Check if user has supplied the dongle id or not */ - if (!dongle_id) { - dongle_id = nsc_fir_read_dongle_id(iobase); - - MESSAGE("%s, Found dongle: %s\n", driver_name, - dongle_types[dongle_id]); - } else { - MESSAGE("%s, Using dongle: %s\n", driver_name, - dongle_types[dongle_id]); - } - - /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ - switch_bank(iobase, BANK0); - outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - /* IRCR2: FEND_MD is set */ - switch_bank(iobase, BANK5); - outb(0x2a, iobase+4); - - /* Make sure that some defaults are OK */ - switch_bank(iobase, BANK6); - outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ - outb(0x0a, iobase+1); /* Set MIR pulse width */ - outb(0x0d, iobase+2); /* Set SIR pulse width */ - outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - - MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); - - /* Enable receive interrupts */ - switch_bank(iobase, BANK0); - outb(IER_RXHDL_IE, iobase+IER); - - return dongle_id; -} - -/* - * Function nsc_fir_read_dongle_id (void) - * - * Try to read dongle indentification. This procedure needs to be executed - * once after power-on/reset. It also needs to be used whenever you suspect - * that the user may have plugged/unplugged the IrDA Dongle. - * - */ -static int nsc_fir_read_dongle_id (int iobase) -{ - int dongle_id; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ - outb(0x00, iobase+7); - - /* ID0, 1, and 2 are pulled up/down very slowly */ - udelay(50); - - /* IRCFG1: read the ID bits */ - dongle_id = inb(iobase+4) & 0x0f; - -#ifdef BROKEN_DONGLE_ID - if (dongle_id == 0x0a) - dongle_id = 0x09; -#endif - - /* Go back to bank 0 before returning */ - switch_bank(iobase, BANK0); - - outb(bank, iobase+BSR); - - return dongle_id; -} - -/* - * Function nsc_fir_init_dongle_interface (iobase, dongle_id) - * - * This function initializes the dongle for the transceiver that is - * used. This procedure needs to be executed once after - * power-on/reset. It also needs to be used whenever you suspect that - * the dongle is changed. - */ -static void nsc_fir_init_dongle_interface (int iobase, int dongle_id) -{ - int bank; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - break; - case 0x05: /* Reserved, but this is what the Thinkpad reports */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - break; - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - /* - * Set irsl0 as input, irsl[1-2] as output, and separate - * inputs are used for SIR and MIR/FIR - */ - outb(0x48, iobase+7); - break; - case 0x0E: /* Supports SIR Mode only */ - outb(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", - dongle_id); - } - - /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ - outb(0x00, iobase+4); - - /* Restore bank register */ - outb(bank, iobase+BSR); - -} /* set_up_dongle_interface */ - -/* - * Function nsc_fir_change_dongle_speed (iobase, speed, dongle_id) - * - * Change speed of the attach dongle - * - */ -static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) -{ - unsigned long flags; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG1: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - case 0x05: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - switch_bank(iobase, BANK7); - outb_p(0x01, iobase+4); - - if (speed == 4000000) { - save_flags(flags); - cli(); - outb(0x81, iobase+4); - outb(0x80, iobase+4); - restore_flags(flags); - } else - outb_p(0x00, iobase+4); - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - break; - case 0x0E: /* Supports SIR Mode only */ - break; - case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n"); - } - /* Restore bank register */ - outb(bank, iobase+BSR); -} - -/* - * Function nsc_fir_change_speed (self, baud) - * - * Change the speed of the device - * - */ -static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) -{ - struct net_device *dev = self->netdev; - __u8 mcr = MCR_SIR; - int iobase; - __u8 bank; - - IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - /* Select Bank 2 */ - switch_bank(iobase, BANK2); - - outb(0x00, iobase+BGDH); - switch (speed) { - case 9600: outb(0x0c, iobase+BGDL); break; - case 19200: outb(0x06, iobase+BGDL); break; - case 38400: outb(0x03, iobase+BGDL); break; - case 57600: outb(0x02, iobase+BGDL); break; - case 115200: outb(0x01, iobase+BGDL); break; - case 576000: - switch_bank(iobase, BANK5); - - /* IRCR2: MDRS is set */ - outb(inb(iobase+4) | 0x04, iobase+4); - - mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); - break; - case 1152000: - mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); - break; - case 4000000: - mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); - break; - default: - mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", - speed); - break; - } - - /* Set appropriate speed mode */ - switch_bank(iobase, BANK0); - outb(mcr | MCR_TX_DFR, iobase+MCR); - - /* Give some hits to the transceiver */ - nsc_fir_change_dongle_speed(iobase, speed, self->io.dongle_id); - - /* Set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, BANK0); - outb(0x00, iobase+FCR); - outb(FCR_FIFO_EN, iobase+FCR); - outb(FCR_RXTH| /* Set Rx FIFO threshold */ - FCR_TXTH| /* Set Tx FIFO threshold */ - FCR_TXSR| /* Reset Tx FIFO */ - FCR_RXSR| /* Reset Rx FIFO */ - FCR_FIFO_EN, /* Enable FIFOs */ - iobase+FCR); - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - self->netdev->tbusy = 0; - - /* Enable some interrupts so we can receive frames */ - switch_bank(iobase, BANK0); - if (speed > 115200) { - /* Install FIR xmit handler */ - dev->hard_start_xmit = nsc_fir_hard_xmit_fir; - outb(IER_SFIF_IE, iobase+IER); - nsc_fir_dma_receive(self); - } else { - /* Install SIR xmit handler */ - dev->hard_start_xmit = nsc_fir_hard_xmit_sir; - outb(IER_RXHDL_IE, iobase+IER); - } - - /* Restore BSR */ - outb(bank, iobase+BSR); -} - -/* - * Function nsc_fir_hard_xmit (skb, dev) - * - * Transmit the frame! - * - */ -static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) -{ - struct nsc_fir_cb *self; - unsigned long flags; - int iobase; - __u32 speed; - __u8 bank; - - self = (struct nsc_fir_cb *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; - - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; - - /* Check if we need to change the speed */ - if ((speed = irda_get_speed(skb)) != self->io.speed) - self->new_speed = speed; - - spin_lock_irqsave(&self->lock, flags); - - /* Save current bank */ - bank = inb(iobase+BSR); - - self->tx_buff.data = self->tx_buff.head; - - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - /* Add interrupt on tx low level (will fire immediately) */ - switch_bank(iobase, BANK0); - outb(IER_TXLDL_IE, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - return 0; -} - -static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) -{ - struct nsc_fir_cb *self; - unsigned long flags; - int iobase; - __u32 speed; - __u8 bank; - int mtt, diff; - - self = (struct nsc_fir_cb *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; - - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; - - /* Check if we need to change the speed */ - if ((speed = irda_get_speed(skb)) != self->io.speed) - self->new_speed = speed; - - spin_lock_irqsave(&self->lock, flags); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Register and copy this frame to DMA memory */ - self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; - self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; - self->tx_fifo.tail += skb->len; - - memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, - skb->len); - - self->tx_fifo.len++; - self->tx_fifo.free++; - - /* Start transmit only if there is currently no transmit going on */ - if (self->tx_fifo.len == 1) { - mtt = irda_get_mtt(skb); - if (mtt) { - /* Check how much time we have used already */ - do_gettimeofday(&self->now); - diff = self->now.tv_usec - self->stamp.tv_usec; - if (diff < 0) - diff += 1000000; - - /* Check if the mtt is larger than the time we have - * already used by all the protocol processing - */ - if (mtt > diff) { - mtt -= diff; - if (mtt > 125) { - /* Adjust for timer resolution */ - mtt = mtt / 125 + 1; - - /* Setup timer */ - switch_bank(iobase, BANK4); - outb(mtt & 0xff, iobase+TMRL); - outb((mtt >> 8) & 0x0f, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->io.direction = IO_XMIT; - - /* Enable timer interrupt */ - switch_bank(iobase, BANK0); - outb(IER_TMR_IE, iobase+IER); - - /* Timer will take care of the rest */ - goto out; - } else - udelay(mtt); - } - } - - /* Enable DMA interrupt */ - switch_bank(iobase, BANK0); - outb(IER_DMA_IE, iobase+IER); - nsc_fir_dma_xmit(self, iobase); - } - /* Not busy transmitting anymore if window is not full */ - if (self->tx_fifo.len < MAX_WINDOW) - dev->tbusy = 0; - out: - /* Restore bank register */ - outb(bank, iobase+BSR); - - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function nsc_fir_dma_xmit (self, iobase) - * - * Transmit data using DMA - * - */ -static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase) -{ - int bsr; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - self->io.direction = IO_XMIT; - - /* Choose transmit DMA channel */ - switch_bank(iobase, BANK2); - outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); - - setup_dma(self->io.dma, - self->tx_fifo.queue[self->tx_fifo.ptr].start, - self->tx_fifo.queue[self->tx_fifo.ptr].len, - DMA_TX_MODE); - - /* Enable DMA and SIR interaction pulse */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); -} - -/* - * Function nsc_fir_pio_xmit (self, iobase) - * - * Transmit data using PIO. Returns the number of bytes that actually - * got transfered - * - */ -static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size) -{ - int actual = 0; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Save current bank */ - bank = inb(iobase+BSR); - - switch_bank(iobase, BANK0); - if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { - IRDA_DEBUG(4, __FUNCTION__ - "(), warning, FIFO not empty yet!\n"); - - fifo_size -= 17; - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual++], iobase+TXD); - } - - IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); - - /* Restore bank */ - outb(bank, iobase+BSR); - - return actual; -} - -/* - * Function nsc_fir_dma_xmit_complete (self) - * - * The transfer of a frame in finished. This function will only be called - * by the interrupt handler - * - */ -static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) -{ - int iobase; - __u8 bank; - int ret = TRUE; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - - iobase = self->io.iobase; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - /* Check for underrrun! */ - if (inb(iobase+ASCR) & ASCR_TXUR) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; - - /* Clear bit, by writing 1 into it */ - outb(ASCR_TXUR, iobase+ASCR); - } else { - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; - } - - if (self->new_speed) { - nsc_fir_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Finished with this frame, so prepare for next */ - self->tx_fifo.ptr++; - self->tx_fifo.len--; - - /* Any frames to be sent back-to-back? */ - if (self->tx_fifo.len) { - nsc_fir_dma_xmit(self, iobase); - - /* Not finished yet! */ - ret = FALSE; - } - - /* Not busy transmitting anymore */ - self->netdev->tbusy = 0; - - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); - - /* Restore bank */ - outb(bank, iobase+BSR); - - return ret; -} - -/* - * Function nsc_fir_dma_receive (self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int nsc_fir_dma_receive(struct nsc_fir_cb *self) -{ - int iobase; - __u8 bsr; - - ASSERT(self != NULL, return -1;); - - iobase = self->io.iobase; - - /* Reset Tx FIFO info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - /* Choose DMA Rx, DMA Fairness, and Advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); - - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Rx FIFO. This will also flush the ST_FIFO */ - switch_bank(iobase, BANK0); - outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; - - setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, - DMA_RX_MODE); - - /* Enable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); - - return 0; -} - -/* - * Function nsc_fir_dma_receive_complete (self) - * - * Finished with receiving frames - * - * - */ -static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) -{ - struct sk_buff *skb; - struct st_fifo *st_fifo; - __u8 bank; - __u8 status; - int len; - - st_fifo = &self->st_fifo; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Read status FIFO */ - switch_bank(iobase, BANK5); - while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { - st_fifo->entries[st_fifo->tail].status = status; - - st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); - st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; - - st_fifo->tail++; - st_fifo->len++; - } - /* Try to process all entries in status FIFO */ - while (st_fifo->len) { - /* Get first entry */ - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->head++; - st_fifo->len--; - - /* Check for errors */ - if (status & FRM_ST_ERR_MSK) { - if (status & FRM_ST_LOST_FR) { - /* Add number of lost frames to stats */ - self->stats.rx_errors += len; - } else { - /* Skip frame */ - self->stats.rx_errors++; - - self->rx_buff.data += len; - - if (status & FRM_ST_MAX_LEN) - self->stats.rx_length_errors++; - - if (status & FRM_ST_PHY_ERR) - self->stats.rx_frame_errors++; - - if (status & FRM_ST_BAD_CRC) - self->stats.rx_crc_errors++; - } - /* The errors below can be reported in both cases */ - if (status & FRM_ST_OVR1) - self->stats.rx_fifo_errors++; - - if (status & FRM_ST_OVR2) - self->stats.rx_fifo_errors++; - } else { - /* Check if we have transfered all data to memory */ - switch_bank(iobase, BANK0); - if (inb(iobase+LSR) & LSR_RXDA) { - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; /* I'll be back! */ - } - - /* - * Remember when we received this frame, so we can - * reduce the min turn time a bit since we will know - * how much time we have used for protocol processing - */ - do_gettimeofday(&self->stamp); - - skb = dev_alloc_skb(len+1); - if (skb == NULL) { - WARNING(__FUNCTION__ "(), memory squeeze, " - "dropping frame.\n"); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; - } - - /* Make sure IP header gets aligned */ - skb_reserve(skb, 1); - - /* Copy frame without CRC */ - if (self->io.speed < 4000000) { - skb_put(skb, len-2); - memcpy(skb->data, self->rx_buff.data, len-2); - } else { - skb_put(skb, len-4); - memcpy(skb->data, self->rx_buff.data, len-4); - } - - /* Move to next frame */ - self->rx_buff.data += len; - self->stats.rx_packets++; - - skb->dev = self->netdev; - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - } - /* Restore bank register */ - outb(bank, iobase+BSR); - - return TRUE; -} - -/* - * Function nsc_fir_pio_receive (self) - * - * Receive all data in receiver FIFO - * - */ -static void nsc_fir_pio_receive(struct nsc_fir_cb *self) -{ - __u8 byte = 0x00; - int iobase; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; - - /* Receive all characters in Rx FIFO */ - do { - byte = inb(iobase+RXD); - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, - byte); - } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ -} - -/* - * Function nsc_fir_sir_interrupt (self, eir) - * - * Handle SIR interrupt - * - */ -static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir) -{ - int actual; - __u8 new_ier = 0; - - /* Check if transmit FIFO is low on data */ - if (eir & EIR_TXLDL_EV) { - /* Write data left in transmit buffer */ - actual = nsc_fir_pio_write(self->io.iobase, - self->tx_buff.data, - self->tx_buff.len, - self->io.fifo_size); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - - self->io.direction = IO_XMIT; - - /* Check if finished */ - if (self->tx_buff.len > 0) - new_ier |= IER_TXLDL_IE; - else { - self->netdev->tbusy = 0; /* Unlock */ - self->stats.tx_packets++; - - mark_bh(NET_BH); - - new_ier |= IER_TXEMP_IE; - } - - } - /* Check if transmission has completed */ - if (eir & EIR_TXEMP_EV) { - /* Check if we need to change the speed? */ - if (self->new_speed) { - IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n"); - nsc_fir_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Turn around and get ready to receive some data */ - self->io.direction = IO_RECV; - new_ier |= IER_RXHDL_IE; - } - - /* Rx FIFO threshold or timeout */ - if (eir & EIR_RXHDL_EV) { - nsc_fir_pio_receive(self); - - /* Keep receiving */ - new_ier |= IER_RXHDL_IE; - } - return new_ier; -} - -/* - * Function nsc_fir_fir_interrupt (self, eir) - * - * Handle MIR/FIR interrupt - * - */ -static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir) -{ - __u8 new_ier = 0; - __u8 bank; - - bank = inb(iobase+BSR); - - /* Status event, or end of frame detected in FIFO */ - if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { - if (nsc_fir_dma_receive_complete(self, iobase)) { - - /* Wait for next status FIFO interrupt */ - new_ier |= IER_SFIF_IE; - } else { - /* DMA not finished yet */ - - /* Set timer value, resolution 125 us */ - switch_bank(iobase, BANK4); - outb(0x0f, iobase+TMRL); /* 125 us * 15 */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - - new_ier |= IER_TMR_IE; - } - } else if (eir & EIR_TMR_EV) { /* Timer finished */ - /* Disable timer */ - switch_bank(iobase, BANK4); - outb(0, iobase+IRCR1); - - /* Clear timer event */ - switch_bank(iobase, BANK0); - outb(ASCR_CTE, iobase+ASCR); - - /* Check if this is a TX timer interrupt */ - if (self->io.direction == IO_XMIT) { - nsc_fir_dma_xmit(self, iobase); - - /* Interrupt on DMA */ - new_ier |= IER_DMA_IE; - } else { - /* Check if DMA has now finished */ - nsc_fir_dma_receive_complete(self, iobase); - - new_ier |= IER_SFIF_IE; - } - } else if (eir & EIR_DMA_EV) { /* Finished with transmission */ - if (nsc_fir_dma_xmit_complete(self)) { - /* Check if there are more frames to be transmitted */ - if (irda_device_txqueue_empty(self->netdev)) { - /* Prepare for receive */ - nsc_fir_dma_receive(self); - - new_ier = IER_LS_IE|IER_SFIF_IE; - } - } else { - /* Not finished yet, so interrupt on DMA again */ - new_ier |= IER_DMA_IE; - } - } - outb(bank, iobase+BSR); - - return new_ier; -} - -/* - * Function nsc_fir_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct nsc_fir_cb *self; - __u8 bsr, eir, ier; - int iobase; - - if (!dev) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); - return; - } - self = (struct nsc_fir_cb *) dev->priv; - - spin_lock(&self->lock); - dev->interrupt = 1; - - iobase = self->io.iobase; - - bsr = inb(iobase+BSR); /* Save current bank */ - - switch_bank(iobase, BANK0); - ier = inb(iobase+IER); - eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ - - outb(0, iobase+IER); /* Disable interrupts */ - - if (eir) { - /* Dispatch interrupt handler for the current speed */ - if (self->io.speed > 115200) - ier = nsc_fir_fir_interrupt(self, iobase, eir); - else - ier = nsc_fir_sir_interrupt(self, eir); - } - - outb(ier, iobase+IER); /* Restore interrupts */ - outb(bsr, iobase+BSR); /* Restore bank register */ - - dev->interrupt = 0; - spin_unlock(&self->lock); -} - -/* - * Function nsc_fir_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int nsc_fir_is_receiving(struct nsc_fir_cb *self) -{ - int status = FALSE; - int iobase; - __u8 bank; - - ASSERT(self != NULL, return FALSE;); - - if (self->io.speed > 115200) { - iobase = self->io.iobase; - - /* Check if rx FIFO is not empty */ - bank = inb(iobase+BSR); - switch_bank(iobase, BANK2); - if ((inb(iobase+RXFLV) & 0x3f) != 0) { - /* We are receiving something */ - status = TRUE; - } - outb(bank, iobase+BSR); - } else - status = (self->rx_buff.state != OUTSIDE_FRAME); - - return status; -} - -/* - * Function nsc_fir_net_init (dev) - * - * Initialize network device - * - */ -static int nsc_fir_net_init(struct net_device *dev) -{ - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Setup to be a normal IrDA network device driver */ - irda_device_setup(dev); - - /* Insert overrides below this line! */ - - return 0; -} - -/* - * Function nsc_fir_net_open (dev) - * - * Start the device - * - */ -static int nsc_fir_net_open(struct net_device *dev) -{ - struct nsc_fir_cb *self; - int iobase; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return -1;); - self = (struct nsc_fir_cb *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; - - if (request_irq(self->io.irq, nsc_fir_interrupt, 0, dev->name, - (void *) dev)) - { - return -EAGAIN; - } - /* - * Always allocate the DMA channel after the IRQ, and clean up on - * failure. - */ - if (request_dma(self->io.dma, dev->name)) { - free_irq(self->io.irq, self); - return -EAGAIN; - } - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* turn on interrupts */ - switch_bank(iobase, BANK0); - outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos); - - MOD_INC_USE_COUNT; - - return 0; -} - -/* - * Function nsc_fir_net_close (dev) - * - * Stop the device - * - */ -static int nsc_fir_net_close(struct net_device *dev) -{ - struct nsc_fir_cb *self; - int iobase; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return -1;); - self = (struct nsc_fir_cb *) dev->priv; - - ASSERT(self != NULL, return 0;); - - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - iobase = self->io.iobase; - - disable_dma(self->io.dma); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - MOD_DEC_USE_COUNT; - - return 0; -} - -/* - * Function nsc_fir_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct nsc_fir_cb *self; - unsigned long flags; - int ret = 0; - - ASSERT(dev != NULL, return -1;); - - self = dev->priv; - - ASSERT(self != NULL, return -1;); - - IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); - - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - nsc_fir_change_speed(self, irq->ifr_baudrate); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = nsc_fir_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } - - restore_flags(flags); - - return ret; -} - -static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev) -{ - struct nsc_fir_cb *self = (struct nsc_fir_cb *) dev->priv; - - return &self->stats; -} - -#ifdef CONFIG_APM -static void nsc_fir_suspend(struct nsc_fir_cb *self) -{ - int i = 10; - - MESSAGE("%s, Suspending\n", driver_name); - - if (self->suspend) - return; - - self->suspend = 1; -} - - -static void nsc_fir_wakeup(struct nsc_fir_cb *self) -{ - struct net_device *dev = self->netdev; - unsigned long flags; - - if (!self->suspend) - return; - - save_flags(flags); - cli(); - - restore_flags(flags); - MESSAGE("%s, Waking up\n", driver_name); -} - -static int nsc_fir_apmproc(apm_event_t event) -{ - static int down = 0; /* Filter out double events */ - int i; - - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (!down) { - for (i = 0; i < 4; i++) { - if (dev_self[i]) - nsc_fir_suspend(dev_self[i]); - } - } - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (down) { - for (i = 0; i < 4; i++) { - if (dev_self[i]) - nsc_fir_wakeup(dev_self[i]); - } - } - down = 0; - break; - } - return 0; -} -#endif /* CONFIG_APM */ - -#ifdef MODULE -MODULE_AUTHOR("Dag Brattli "); -MODULE_DESCRIPTION("NSC FIR IrDA Device Driver"); - -MODULE_PARM(qos_mtt_bits, "i"); -MODULE_PARM(io, "1-4i"); -MODULE_PARM(io2, "1-4i"); -MODULE_PARM(irq, "1-4i"); -MODULE_PARM(dongle_id, "i"); - -int init_module(void) -{ - return nsc_fir_init(); -} - -void cleanup_module(void) -{ - nsc_fir_cleanup(); -} -#endif /* MODULE */ - diff -ur --new-file old/linux/drivers/net/irda/smc-ircc.c new/linux/drivers/net/irda/smc-ircc.c --- old/linux/drivers/net/irda/smc-ircc.c Thu Jan 6 23:46:18 2000 +++ new/linux/drivers/net/irda/smc-ircc.c Tue Feb 1 08:43:51 2000 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: smc-ircc.c - * Version: 0.3 + * Version: 0.4 * Description: Driver for the SMC Infrared Communications Controller * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Wed Jan 5 12:38:06 2000 + * Modified at: Fri Jan 21 09:41:08 2000 * Modified by: Dag Brattli * * Copyright (c) 1999-2000 Dag Brattli @@ -28,11 +28,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * SIO's: SMC FDC37N869, FDC37C669 + * SIO's: SMC FDC37N869, FDC37C669, FDC37N958 * Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX * ********************************************************************/ +#include #include #include @@ -44,11 +45,16 @@ #include #include #include +#include #include #include #include +#ifdef CONFIG_APM +#include +#endif + #include #include #include @@ -62,10 +68,10 @@ #define CHIP_IO_EXTENT 8 -static unsigned int io[] = { 0x2e8, 0x140, 0x118, 0x240 }; -static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0x3e8 }; +static unsigned int io[] = { ~0, ~0 }; +static unsigned int io2[] = { 0, 0 }; -static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL}; +static struct ircc_cb *dev_self[] = { NULL, NULL}; /* Some prototypes */ static int ircc_open(int i, unsigned int iobase, unsigned int board_addr); @@ -73,17 +79,30 @@ static int ircc_close(struct ircc_cb *self); #endif /* MODULE */ static int ircc_probe(int iobase, int board_addr); -static int ircc_probe_smc(int *ioaddr, int *ioaddr2); -static int ircc_dma_receive(struct ircc_cb *self); -static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase); +static int ircc_probe_58(smc_chip_t *chip, chipio_t *info); +static int ircc_probe_69(smc_chip_t *chip, chipio_t *info); +static int ircc_dma_receive(struct ircc_cb *self, int iobase); +static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase); static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev); -static void ircc_dma_xmit(struct ircc_cb *self, int iobase); +static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs); static void ircc_change_speed(void *priv, __u32 speed); static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int ircc_is_receiving(struct ircc_cb *self); static int ircc_net_open(struct net_device *dev); static int ircc_net_close(struct net_device *dev); +#ifdef CONFIG_APM +static int ircc_apmproc(apm_event_t event); +#endif /* CONFIG_APM */ + +/* These are the currently known SMC chipsets */ +static smc_chip_t chips[] = +{ + { "FDC37C669", 0x55, 0x55, 0x0d, 0x04, ircc_probe_69 }, + { "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 }, + { "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 }, + { NULL } +}; static int ircc_irq=255; static int ircc_dma=255; @@ -102,26 +121,38 @@ */ int __init ircc_init(void) { - int ioaddr, ioaddr2; + static int smcreg[] = { 0x3f0, 0x370 }; + smc_chip_t *chip; + chipio_t info; + int ret = -ENODEV; int i; IRDA_DEBUG(0, __FUNCTION__ "\n"); - for (i=0; (io[i] < 2000) && (i < 4); i++) { - int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT)) - continue; - if (ircc_open(i, io[i], io2[i]) == 0) - return 0; - } - - /* last chance saloon, see what the controller says */ - if (ircc_probe_smc(&ioaddr, &ioaddr2) == 0) { - if (check_region(ioaddr, CHIP_IO_EXTENT) == 0) - if (ircc_open(0, ioaddr, ioaddr2) == 0) - return 0; - } - return -ENODEV; + /* Probe for all the NSC chipsets we know about */ + for (chip=chips; chip->name ; chip++,i++) { + for (i=0; i<2; i++) { + info.cfg_base = smcreg[i]; + + /* + * First we check if the user has supplied any + * parameters which we should use instead of probed + * values + */ + if (io[i] < 2000) { + info.fir_base = io[i]; + info.sir_base = io2[i]; + } else if (chip->probe(chip, &info) < 0) + continue; + if (check_region(info.fir_base, CHIP_IO_EXTENT) < 0) + continue; + if (check_region(info.sir_base, CHIP_IO_EXTENT) < 0) + continue; + if (ircc_open(i, info.fir_base, info.sir_base) == 0) + ret = 0; + } + } + return ret; } /* @@ -137,7 +168,7 @@ IRDA_DEBUG(0, __FUNCTION__ "\n"); - for (i=0; i < 4; i++) { + for (i=0; i < 2; i++) { if (dev_self[i]) ircc_close(dev_self[i]); } @@ -150,7 +181,7 @@ * Open driver instance * */ -static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) +static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base) { struct ircc_cb *self; struct irport_cb *irport; @@ -159,9 +190,9 @@ IRDA_DEBUG(0, __FUNCTION__ "\n"); - if ((config = ircc_probe(iobase, iobase2)) == -1) { + if ((config = ircc_probe(fir_base, sir_base)) == -1) { IRDA_DEBUG(0, __FUNCTION__ - "(), addr 0x%04x - no device found!\n", iobase); + "(), addr 0x%04x - no device found!\n", fir_base); return -1; } @@ -180,7 +211,7 @@ /* Need to store self somewhere */ dev_self[i] = self; - irport = irport_open(0, iobase2, config >> 4 & 0x0f); + irport = irport_open(i, sir_base, config >> 4 & 0x0f); if (!irport) return -ENODEV; @@ -190,34 +221,32 @@ irport->priv = self; /* Initialize IO */ - self->io.iobase = iobase; - self->io.iobase2 = iobase2; /* Used by irport */ + self->io.fir_base = fir_base; + self->io.sir_base = sir_base; /* Used by irport */ self->io.irq = config >> 4 & 0x0f; if (ircc_irq < 255) { MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", driver_name, self->io.irq, ircc_irq); self->io.irq = ircc_irq; } - self->io.io_ext = CHIP_IO_EXTENT; - self->io.io_ext2 = 8; /* Used by irport */ + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.sir_ext = 8; /* Used by irport */ self->io.dma = config & 0x0f; if (ircc_dma < 255) { MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", driver_name, self->io.dma, ircc_dma); self->io.dma = ircc_dma; } - self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n", - self->io.iobase); - /* ircc_cleanup(self->self); */ + IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n", + self->io.fir_base); + kfree(self); return -ENODEV; } - - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&irport->qos); @@ -229,7 +258,7 @@ irport->qos.min_turn_time.bits = 0x07; irda_qos_bits_to_value(&irport->qos); - irport->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; + irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ self->rx_buff.truesize = 4000; @@ -256,6 +285,7 @@ /* Override the speed change function, since we must control it now */ irport->change_speed = &ircc_change_speed; + irport->interrupt = &ircc_interrupt; self->netdev->open = &ircc_net_open; self->netdev->stop = &ircc_net_close; @@ -279,23 +309,26 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_close(self->irport); + /* Stop interrupts */ register_bank(iobase, 0); outb(0, iobase+IRCC_IER); outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - + outb(0x00, iobase+IRCC_MASTER); +#if 0 + /* Reset to SIR mode */ register_bank(iobase, 1); - outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB); - +#endif /* Release the PORT that this driver is using */ - IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", self->io.iobase); + IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", + self->io.fir_base); - release_region(self->io.iobase, self->io.io_ext); + release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -310,58 +343,106 @@ #endif /* MODULE */ /* - * Function ircc_probe_smc (ioaddr, ioaddr2) + * Function ircc_probe_69 (chip, info) * - * Probe the SMC Chip for an IrDA port + * Probes for the SMC FDC37C669 and FDC37N869 * */ -static int ircc_probe_smc(int *ioaddr, int *ioaddr2) +static int ircc_probe_69(smc_chip_t *chip, chipio_t *info) { - static int smcreg[] = { 0x3f0, 0x370 }; + int cfg_base = info->cfg_base; __u8 devid, mode; - __u8 conf_reg; - int ret = -1; + int ret = -ENODEV; int fir_io; - int i; IRDA_DEBUG(0, __FUNCTION__ "()\n"); - for (i = 0; i < 2 && ret == -1; i++) { - conf_reg = smcreg[i]; - - /* Enter configuration */ - outb(0x55, conf_reg); - outb(0x55, conf_reg); - - outb(0x0d, conf_reg); - devid = inb(conf_reg+1); - IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + /* Enter configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + outb(chip->cid_index, cfg_base); + devid = inb(cfg_base+1); + IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + + /* Check for expected device ID; are there others? */ + if (devid == chip->cid_value) { + outb(0x0c, cfg_base); + mode = inb(cfg_base+1); + mode = (mode & 0x38) >> 3; - /* Check for expected device ID; are there others? */ - if (devid == 0x29) { - outb(0x0c, conf_reg); - mode = inb(conf_reg+1); - mode = (mode & 0x38) >> 3; - - /* Value for IR port */ - if (mode && mode < 4) { - /* SIR iobase */ - outb(0x25, conf_reg); - *ioaddr2 = inb(conf_reg+1) << 2; - - /* FIR iobase */ - outb(0x2b, conf_reg); - fir_io = inb(conf_reg+1) << 3; - if (fir_io) { - ret = 0; - *ioaddr = fir_io; - } + /* Value for IR port */ + if (mode && mode < 4) { + /* SIR iobase */ + outb(0x25, cfg_base); + info->sir_base = inb(cfg_base+1) << 2; + + /* FIR iobase */ + outb(0x2b, cfg_base); + fir_io = inb(cfg_base+1) << 3; + if (fir_io) { + ret = 0; + info->fir_base = fir_io; } } + } + + /* Exit configuration */ + outb(0xaa, cfg_base); + + return ret; +} + +/* + * Function ircc_probe_58 (chip, info) + * + * Probes for the SMC FDC37N958 + * + */ +static int ircc_probe_58(smc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + __u8 devid; + int ret = -ENODEV; + int fir_io; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Enter configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + outb(chip->cid_index, cfg_base); + devid = inb(cfg_base+1); + IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + + /* Check for expected device ID; are there others? */ + if (devid == chip->cid_value) { + /* Select logical device (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base + 1); + + /* SIR iobase */ + outb(0x60, cfg_base); + info->sir_base = inb(cfg_base + 1) << 8; + outb(0x61, cfg_base); + info->sir_base |= inb(cfg_base + 1); + + /* Read FIR base */ + outb(0x62, cfg_base); + fir_io = inb(cfg_base + 1) << 8; + outb(0x63, cfg_base); + fir_io |= inb(cfg_base + 1); + outb(0x2b, cfg_base); + if (fir_io) { + ret = 0; + info->fir_base = fir_io; + } + } + + /* Exit configuration */ + outb(0xaa, cfg_base); - /* Exit configuration */ - outb(0xaa, conf_reg); - } return ret; } @@ -371,34 +452,32 @@ * Returns non-negative on success. * */ -static int ircc_probe(int iobase, int iobase2) +static int ircc_probe(int fir_base, int sir_base) { - int version = 1; int low, high, chip, config, dma, irq; - - IRDA_DEBUG(0, __FUNCTION__ "\n"); + int iobase = fir_base; + int version = 1; - /* Power on device */ - outb(inb(iobase+IRCC_MASTER) & ~IRCC_MASTER_POWERDOWN, - iobase+IRCC_MASTER); + IRDA_DEBUG(0, __FUNCTION__ "\n"); register_bank(iobase, 3); - high = inb(iobase+IRCC_ID_HIGH); - low = inb(iobase+IRCC_ID_LOW); - chip = inb(iobase+IRCC_CHIP_ID); + high = inb(iobase+IRCC_ID_HIGH); + low = inb(iobase+IRCC_ID_LOW); + chip = inb(iobase+IRCC_CHIP_ID); version = inb(iobase+IRCC_VERSION); - config = inb(iobase+IRCC_INTERFACE); - irq = config >> 4 & 0x0f; - dma = config & 0x0f; + config = inb(iobase+IRCC_INTERFACE); + irq = config >> 4 & 0x0f; + dma = config & 0x0f; if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) { - IRDA_DEBUG(0, "SMC IrDA Controller found; IrCC version %d.%d, " - "port 0x%04x, dma %d, interrupt %d\n", - chip & 0x0f, version, iobase, dma, irq); + MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, " + "port 0x%03x, dma=%d, irq=%d\n", + chip & 0x0f, version, iobase, dma, irq); } else - return -1; + return -ENODEV; - outb(0, iobase+IRCC_MASTER); + /* Power on device */ + outb(0x00, iobase+IRCC_MASTER); return config; } @@ -411,7 +490,7 @@ */ static void ircc_change_speed(void *priv, __u32 speed) { - int iobase, ir_mode, select, fast; + int iobase, ir_mode, ctrl, fast; struct ircc_cb *self = (struct ircc_cb *) priv; struct net_device *dev; @@ -420,49 +499,39 @@ ASSERT(self != NULL, return;); dev = self->netdev; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); + switch (speed) { case 9600: case 19200: case 38400: case 57600: - case 115200: - IRDA_DEBUG(0, __FUNCTION__ - "(), using irport to change speed to %d\n", speed); - - register_bank(iobase, 0); - outb(0, iobase+IRCC_IER); - outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); - - dev->hard_start_xmit = &irport_hard_xmit; - - /* We must give the interrupt back to irport */ - self->irport->interrupt = irport_interrupt; - - irport_start(self->irport); - irport_change_speed(self->irport, speed); - return; + case 115200: + ir_mode = IRCC_CFGA_IRDA_SIR_A; + ctrl = 0; + fast = 0; break; case 576000: ir_mode = IRCC_CFGA_IRDA_HDLC; - select = 0; + ctrl = IRCC_CRC; fast = 0; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); break; case 1152000: ir_mode = IRCC_CFGA_IRDA_HDLC; - select = IRCC_1152; + ctrl = IRCC_1152 | IRCC_CRC; fast = 0; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); break; case 4000000: ir_mode = IRCC_CFGA_IRDA_4PPM; - select = 0; + ctrl = IRCC_CRC; fast = IRCC_LCR_A_FAST; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); break; @@ -471,39 +540,55 @@ speed); return; } - - outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - + register_bank(iobase, 0); outb(0, iobase+IRCC_IER); - - irport_stop(self->irport); - - /* Install FIR transmit handler */ - dev->hard_start_xmit = &ircc_hard_xmit; + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); - /* Need to steal the interrupt as well */ - self->irport->interrupt = &ircc_interrupt; + /* Make special FIR init if necessary */ + if (speed > 115200) { + irport_stop(self->irport); + + /* Install FIR transmit handler */ + dev->hard_start_xmit = &ircc_hard_xmit; + + /* + * Don't know why we have to do this, but FIR interrupts + * stops working if we remove it. + */ + /* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */ + /* Be ready for incomming frames */ + ircc_dma_receive(self, iobase); + } else { + /* Install SIR transmit handler */ + dev->hard_start_xmit = &irport_hard_xmit; + irport_start(self->irport); + + IRDA_DEBUG(0, __FUNCTION__ + "(), using irport to change speed to %d\n", speed); + irport_change_speed(self->irport, speed); + } dev->tbusy = 0; - + register_bank(iobase, 1); outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), iobase+IRCC_SCE_CFGA); - - outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_IR), - iobase+IRCC_SCE_CFGB); +#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + iobase+IRCC_SCE_CFGB); +#else + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + iobase+IRCC_SCE_CFGB); +#endif (void) inb(iobase+IRCC_FIFO_THRESHOLD); outb(64, iobase+IRCC_FIFO_THRESHOLD); - + register_bank(iobase, 4); - - outb((inb(iobase+IRCC_CONTROL) & 0x30) | select | IRCC_CRC, - iobase+IRCC_CONTROL); - + outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL); + register_bank(iobase, 0); - outb(fast, iobase+IRCC_LCR_A); } @@ -517,21 +602,20 @@ { struct irport_cb *irport; struct ircc_cb *self; + unsigned long flags; + __u32 speed; int iobase; int mtt; - __u32 speed; irport = (struct irport_cb *) dev->priv; self = (struct ircc_cb *) irport->priv; - ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, - (int) skb->len); + spin_lock_irqsave(&self->lock, flags); - /* Check if we need to change the speed */ + /* Check if we need to change the speed after this frame */ if ((speed = irda_get_speed(skb)) != self->io.speed) self->new_speed = speed; @@ -541,19 +625,28 @@ memcpy(self->tx_buff.head, skb->data, skb->len); - /* Make sure that the length is a multiple of 16 bits */ - if (skb->len & 0x01) - skb->len++; - self->tx_buff.len = skb->len; self->tx_buff.data = self->tx_buff.head; mtt = irda_get_mtt(skb); - if (mtt) - udelay(mtt); - - ircc_dma_xmit(self, iobase); + if (mtt) { + int bofs; + + /* + * Compute who many BOFS (STA or PA's) we need to waste the + * min turn time given the speed of the link. + */ + bofs = mtt * (self->io.speed / 1000) / 8000; + if (bofs > 4095) + bofs = 4095; + + ircc_dma_xmit(self, iobase, bofs); + } else { + /* Transmit frame */ + ircc_dma_xmit(self, iobase, 0); + } + spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -565,44 +658,49 @@ * Transmit data using DMA * */ -static void ircc_dma_xmit(struct ircc_cb *self, int iobase) +static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs) { - IRDA_DEBUG(2, __FUNCTION__ "\n"); - - ASSERT(self != NULL, return;); + __u8 ctrl; - iobase = self->io.iobase; + IRDA_DEBUG(2, __FUNCTION__ "\n"); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); - setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, - DMA_TX_MODE); - self->io.direction = IO_XMIT; - outb(0x08, self->io.iobase2+4); - + /* Set BOF additional count for generating the min turn time */ register_bank(iobase, 4); - outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL); - - outb(2, iobase+IRCC_BOF_COUNT_LO); - outb(0, iobase+IRCC_BRICKWALL_CNT_LO); -#if 1 - outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI); + outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO); + ctrl = inb(iobase+IRCC_CONTROL) & 0xf0; + outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI); + + /* Set max Tx frame size */ + outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI); outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO); -#else - outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); - outb(0, iobase+IRCC_TX_SIZE_LO); -#endif + /* Setup DMA controller (must be done after enabling chip DMA) */ + setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, + DMA_TX_MODE); + + outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); + /* Enable burst mode chip Tx DMA */ register_bank(iobase, 1); - outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE, - iobase+IRCC_SCE_CFGB); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); + /* Enable interrupt */ + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); register_bank(iobase, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); - outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + /* Enable transmit */ + outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); } /* @@ -612,39 +710,36 @@ * by the interrupt handler * */ -static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun) +static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase) { - int iobase, d; - IRDA_DEBUG(2, __FUNCTION__ "\n"); - - ASSERT(self != NULL, return;); - - register_bank(self->io.iobase, 1); - - outb(inb(self->io.iobase+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE, - self->io.iobase+IRCC_SCE_CFGB); - - d = get_dma_residue(self->io.dma); - - IRDA_DEBUG(0, __FUNCTION__ - ": dma residue = %d, len=%d, sent=%d\n", - d, self->tx_buff.len, self->tx_buff.len - d); - - iobase = self->io.iobase; +#if 0 + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(self->io.fir_base, 1); + outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + self->io.fir_base+IRCC_SCE_CFGB); /* Check for underrrun! */ - if (underrun) { + register_bank(iobase, 0); + if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) { self->irport->stats.tx_errors++; - self->irport->stats.tx_fifo_errors++; + self->irport->stats.tx_fifo_errors++; + + /* Reset error condition */ + register_bank(iobase, 0); + outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); } else { self->irport->stats.tx_packets++; self->irport->stats.tx_bytes += self->tx_buff.len; } + /* Check if it's time to change the speed */ if (self->new_speed) { - ircc_change_speed(self, self->new_speed); - + ircc_change_speed(self, self->new_speed); self->new_speed = 0; } @@ -662,39 +757,31 @@ * if it starts to receive a frame. * */ -static int ircc_dma_receive(struct ircc_cb *self) -{ - int iobase; - - IRDA_DEBUG(2, __FUNCTION__ "\n"); - - ASSERT(self != NULL, return -1;); - - iobase= self->io.iobase; +static int ircc_dma_receive(struct ircc_cb *self, int iobase) +{ + /* Turn off chip DMA */ + //register_bank(iobase, 1); + //outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + // iobase+IRCC_SCE_CFGB); setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, - DMA_RX_MODE); - - /* driver->media_busy = FALSE; */ + DMA_RX_MODE); + /* Set max Rx frame size */ + register_bank(iobase, 4); + outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI); + outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO); + self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head; -#if 0 - self->rx_buff.offset = 0; -#endif - - register_bank(iobase, 4); - outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL); - outb(2, iobase+IRCC_BOF_COUNT_LO); - outb(0, iobase+IRCC_BRICKWALL_CNT_LO); - outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); - outb(0, iobase+IRCC_TX_SIZE_LO); - outb(0, iobase+IRCC_RX_SIZE_HI); - outb(0, iobase+IRCC_RX_SIZE_LO); + /* Setup DMA controller */ + + /* Enable receiver */ register_bank(iobase, 0); outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); + /* Enable burst mode chip Rx DMA */ register_bank(iobase, 1); outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); @@ -709,45 +796,54 @@ * * */ -static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase) +static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase) { + unsigned long flags; struct sk_buff *skb; int len, msgcnt; IRDA_DEBUG(2, __FUNCTION__ "\n"); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 0); + msgcnt = inb(iobase+IRCC_LCR_B) & 0x08; - msgcnt = inb(self->io.iobase+IRCC_LCR_B) & 0x08; - - IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n", + IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n", get_dma_residue(self->io.dma)); - len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4; + len = self->rx_buff.truesize - get_dma_residue(self->io.dma); + + /* Remove CRC */ + if (self->io.speed < 4000000) + len -= 2; + else + len -= 4; - IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); + if ((len < 2) && (len > 2050)) { + WARNING(__FUNCTION__ "(), bogus len=%d\n", len); + return; + } + IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); skb = dev_alloc_skb(len+1); if (!skb) { WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n"); - return FALSE; - } - + return; + } /* Make sure IP header gets aligned */ skb_reserve(skb, 1); - skb_put(skb, len); - memcpy(skb->data, self->rx_buff.data, len); + memcpy(skb_put(skb, len), self->rx_buff.data, len); self->irport->stats.rx_packets++; + self->irport->stats.rx_bytes += len; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - - register_bank(self->io.iobase, 1); - outb(inb(self->io.iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - self->io.iobase+IRCC_SCE_CFGB); - - return TRUE; } /* @@ -758,58 +854,54 @@ */ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int iobase, iir; struct net_device *dev = (struct net_device *) dev_id; + struct irport_cb *irport; struct ircc_cb *self; + int iobase, iir; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); return; } - - self = (struct ircc_cb *) dev->priv; + irport = (struct irport_cb *) dev->priv; + ASSERT(irport != NULL, return;); + self = (struct ircc_cb *) irport->priv; + ASSERT(self != NULL, return;); - iobase = self->io.iobase; + /* Check if we should use the SIR interrupt handler */ + if (self->io.speed < 576000) { + irport_interrupt(irq, dev_id, regs); + return; + } + iobase = self->io.fir_base; + spin_lock(&self->lock); dev->interrupt = 1; - outb(0, iobase+IRCC_MASTER); - register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); /* Disable interrupts */ outb(0, iobase+IRCC_IER); - IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir); + IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir); if (iir & IRCC_IIR_EOM) { - IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n"); - if (self->io.direction == IO_RECV) ircc_dma_receive_complete(self, iobase); else ircc_dma_xmit_complete(self, iobase); - ircc_dma_receive(self); - } - if (iir & IRCC_IIR_ACTIVE_FRAME) { - IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n"); - self->rx_buff.state = INSIDE_FRAME; -#if 0 - ircc_dma_receive(self); -#endif - } - if (iir & IRCC_IIR_RAW_MODE) { - IRDA_DEBUG(0, __FUNCTION__ "(), IIR RAW mode interrupt.\n"); + ircc_dma_receive(self, iobase); } + /* Enable interrupts again */ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); dev->interrupt = 0; + spin_unlock(&self->lock); } /* @@ -855,7 +947,7 @@ ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_net_open(dev); /* irport allocates the irq */ @@ -894,7 +986,7 @@ ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_net_close(dev); @@ -906,6 +998,69 @@ return 0; } + +#ifdef CONFIG_APM +static void ircc_suspend(struct ircc_cb *self) +{ + int i = 10; + + MESSAGE("%s, Suspending\n", driver_name); + + if (self->io.suspended) + return; + + ircc_net_close(self->netdev); + + self->io.suspended = 1; +} + +static void ircc_wakeup(struct ircc_cb *self) +{ + struct net_device *dev = self->netdev; + unsigned long flags; + + if (!self->io.suspended) + return; + + save_flags(flags); + cli(); + + ircc_net_open(self->netdev); + + restore_flags(flags); + MESSAGE("%s, Waking up\n", driver_name); +} + +static int ircc_apmproc(apm_event_t event) +{ + static int down = 0; /* Filter out double events */ + int i; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (!down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + ircc_suspend(dev_self[i]); + } + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + ircc_wakeup(dev_self[i]); + } + } + down = 0; + break; + } + return 0; +} +#endif /* CONFIG_APM */ #ifdef MODULE MODULE_AUTHOR("Thomas Davis "); diff -ur --new-file old/linux/drivers/net/irda/toshoboe.c new/linux/drivers/net/irda/toshoboe.c --- old/linux/drivers/net/irda/toshoboe.c Fri Jan 7 20:51:56 2000 +++ new/linux/drivers/net/irda/toshoboe.c Sat Jan 29 04:36:22 2000 @@ -32,37 +32,6 @@ static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $"; -/* - * $Log: toshoboe.c,v $ - * Revision 1.9 1999/06/29 14:21:06 root - * *** empty log message *** - * - * Revision 1.8 1999/06/29 14:15:08 root - * *** empty log message *** - * - * Revision 1.7 1999/06/29 13:46:42 root - * *** empty log message *** - * - * Revision 1.6 1999/06/29 12:31:03 root - * *** empty log message *** - * - * Revision 1.5 1999/05/12 12:24:39 root - * *** empty log message *** - * - * Revision 1.4 1999/05/12 11:55:08 root - * *** empty log message *** - * - * Revision 1.3 1999/05/09 01:33:12 root - * *** empty log message *** - * - * Revision 1.2 1999/05/09 01:30:38 root - * *** empty log message *** - * - * Revision 1.1 1999/05/09 01:25:04 root - * Initial revision - * - */ - /* Define this to have only one frame in the XMIT or RECV queue */ /* Toshiba's drivers do this, but it disables back to back tansfers */ /* I think that the chip may have some problems certainly, I have */ @@ -682,7 +651,7 @@ toshoboe_disablebm (self); } - release_region (self->io.iobase, self->io.io_ext); + release_region (self->io.sir_base, self->io.sir_ext); for (i = 0; i < TX_SLOTS; ++i) @@ -754,17 +723,17 @@ self->pdev = pci_dev; self->base = pci_dev->resource[0].start; - self->io.iobase = self->base; + self->io.sir_base = self->base; self->io.irq = pci_dev->irq; - self->io.io_ext = CHIP_IO_EXTENT; + self->io.sir_ext = CHIP_IO_EXTENT; self->io.speed = 9600; /* Lock the port that we need */ - i = check_region (self->io.iobase, self->io.io_ext); + i = check_region (self->io.sir_base, self->io.sir_ext); if (i < 0) { IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); + self->io.sir_base); dev_self[i] = NULL; kfree (self); @@ -864,13 +833,12 @@ } - request_region (self->io.iobase, self->io.io_ext, driver_name); + request_region (self->io.sir_base, self->io.sir_ext, driver_name); if (!(dev = dev_alloc("irda%d", &err))) { ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - dev->priv = (void *) self; self->netdev = dev; @@ -1025,7 +993,7 @@ if (pci_dev) { printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", - pci_dev->resource[0].start, + pci_dev->resource[0].start, pci_dev->irq); if (!toshoboe_open (pci_dev)) diff -ur --new-file old/linux/drivers/net/irda/w83977af_ir.c new/linux/drivers/net/irda/w83977af_ir.c --- old/linux/drivers/net/irda/w83977af_ir.c Fri Jan 7 20:51:56 2000 +++ new/linux/drivers/net/irda/w83977af_ir.c Sat Jan 29 04:36:22 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Wed Jan 5 15:11:21 2000 + * Modified at: Fri Jan 28 12:10:59 2000 * Modified by: Dag Brattli * * Copyright (c) 1998-2000 Dag Brattli @@ -183,21 +183,21 @@ dev_self[i] = self; /* Initialize IO */ - self->io.iobase = iobase; + self->io.fir_base = iobase; self->io.irq = irq; - self->io.io_ext = CHIP_IO_EXTENT; + self->io.fir_ext = CHIP_IO_EXTENT; self->io.dma = dma; self->io.fifo_size = 32; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); + self->io.fir_base); /* w83977af_cleanup( self); */ return -ENODEV; } - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -243,9 +243,6 @@ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - /* dev_alloc doesn't clear the struct, so lets do a little hack */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); - dev->priv = (void *) self; self->netdev = dev; @@ -282,7 +279,7 @@ IRDA_DEBUG(0, __FUNCTION__ "()\n"); - iobase = self->io.iobase; + iobase = self->io.fir_base; #ifdef CONFIG_USE_W977_PNP /* enter PnP configuration mode */ @@ -301,14 +298,12 @@ rtnl_lock(); unregister_netdevice(self->netdev); rtnl_unlock(); - /* Must free the old-style 2.2.x device */ - kfree(self->netdev); } /* Release the PORT that this driver is using */ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); + self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -426,7 +421,7 @@ int iobase; __u8 set; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; @@ -510,7 +505,7 @@ self = (struct w83977af_ir *) dev->priv; - iobase = self->io.iobase; + iobase = self->io.fir_base; IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); @@ -692,7 +687,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); @@ -748,7 +743,7 @@ IRDA_DEBUG(4, __FUNCTION__ "\n"); - iobase= self->io.iobase; + iobase= self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); @@ -822,12 +817,12 @@ st_fifo = &self->st_fifo; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Read status FIFO */ switch_bank(iobase, SET5); @@ -948,7 +943,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Receive all characters in Rx FIFO */ do { @@ -973,11 +968,11 @@ IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Transmit FIFO low on data */ if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ - actual = w83977af_pio_write(self->io.iobase, + actual = w83977af_pio_write(self->io.fir_base, self->tx_buff.data, self->tx_buff.len, self->io.fifo_size); @@ -1042,7 +1037,7 @@ __u8 set; int iobase; - iobase = self->io.iobase; + iobase = self->io.fir_base; set = inb(iobase+SSR); /* End of frame detected in FIFO */ @@ -1131,7 +1126,7 @@ dev->interrupt = 1; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current bank */ set = inb(iobase+SSR); @@ -1171,7 +1166,7 @@ ASSERT(self != NULL, return FALSE;); if (self->io.speed > 115200) { - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Check if rx FIFO is not empty */ set = inb(iobase+SSR); @@ -1225,7 +1220,7 @@ ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, (void *) dev)) { @@ -1290,7 +1285,7 @@ ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Stop device */ dev->tbusy = 1; diff -ur --new-file old/linux/drivers/net/mac89x0.c new/linux/drivers/net/mac89x0.c --- old/linux/drivers/net/mac89x0.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/mac89x0.c Mon Jan 31 19:34:12 2000 @@ -0,0 +1,678 @@ +/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 11 Grant St., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. + + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + David Huggins-Daines + + Split this off into mac89x0.c, and gutted it of all parts which are + not relevant to the existing CS8900 cards on the Macintosh + (i.e. basically the Daynaport CS and LC cards). To be precise: + + * Removed all the media-detection stuff, because these cards are + TP-only. + + * Lobotomized the ISA interrupt bogosity, because these cards use + a hardwired NuBus interrupt and a magic ISAIRQ value in the card. + + * Basically eliminated everything not relevant to getting the + cards minimally functioning on the Macintosh. + + I might add that these cards are badly designed even from the Mac + standpoint, in that Dayna, in their infinite wisdom, used NuBus slot + I/O space and NuBus interrupts for these cards, but neglected to + provide anything even remotely resembling a NuBus ROM. Therefore we + have to probe for them in a brain-damaged ISA-like fashion. +*/ + +static char *version = +"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; + +/* ======================= configure the driver here ======================= */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* ======================= end of configuration ======================= */ + + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define PRINTK(x) printk x + +/* + Sources: + + Crynwr packet driver epktisa. + + Crystal Semiconductor data sheets. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "cs89x0.h" + +static unsigned int net_debug = NET_DEBUG; + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + int chip_type; /* one of: CS8900, CS8920, CS8920M */ + char chip_revision; /* revision letter of the chip ('A'...) */ + int send_cmd; /* the propercommand used to send a packet. */ + int rx_mode; + int curr_rx_cfg; + int send_underrun; /* keep track of how many underruns in a row we get */ + struct sk_buff *skb; +}; + +/* Index to functions, as function prototypes. */ + +extern int mac89x0_probe(struct net_device *dev); +extern void reset_chip(struct net_device *dev); +static int net_open(struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void set_multicast_list(struct net_device *dev); +static void net_rx(struct net_device *dev); +static int net_close(struct net_device *dev); +static struct net_device_stats *net_get_stats(struct net_device *dev); +static int set_mac_address(struct net_device *dev, void *addr); + + +/* Example routines you must write ;->. */ +#define tx_done(dev) 1 + +/* For reading/writing registers ISA-style */ +static int inline +readreg_io(struct net_device *dev, int portno) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + return swab16(readw(dev->base_addr + DATA_PORT)); +} + +static void inline +writereg_io(struct net_device *dev, int portno, int value) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + writew(swab16(value), dev->base_addr + DATA_PORT); +} + +/* These are for reading/writing registers in shared memory */ +static int inline +readreg(struct net_device *dev, int portno) +{ + return swab16(readw(dev->mem_start + portno)); +} + +static void inline +writereg(struct net_device *dev, int portno, int value) +{ + writew(swab16(value), dev->mem_start + portno); +} + +/* Probe for the CS8900 card in slot E. We won't bother looking + anywhere else until we have a really good reason to do so. */ +int __init mac89x0_probe(struct net_device *dev) +{ + static int once_is_enough = 0; + struct net_local *lp; + static unsigned version_printed = 0; + int i, slot; + unsigned rev_type = 0; + unsigned long ioaddr; + unsigned short sig; + + if (once_is_enough) + return ENODEV; + once_is_enough = 1; + + /* We might have to parameterize this later */ + slot = 0xE; + /* Get out now if there's a real NuBus card in slot E */ + if (nubus_find_slot(slot, NULL) != NULL) + return ENODEV; + + /* The pseudo-ISA bits always live at offset 0x300 (gee, + wonder why...) */ + ioaddr = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); + { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*) ioaddr+4) + && hwreg_present((void*) ioaddr + DATA_PORT); + restore_flags(flags); + + if (!card_present) + return ENODEV; + } + + writew(0, ioaddr + ADD_PORT); + sig = readw(ioaddr + DATA_PORT); + if (sig != swab16(CHIP_EISA_ID_SIG)) + return ENODEV; + + /* Initialize the net_device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + } + lp = (struct net_local *)dev->priv; + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->mem_start = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); + dev->mem_end = dev->mem_start + 0x1000; + + /* Turn on shared memory */ + writereg_io(dev, PP_BusCTL, MEMORY_ON); + + /* get the chip type */ + rev_type = readreg(dev, PRODUCT_ID_ADD); + lp->chip_type = rev_type &~ REVISON_BITS; + lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + /* Check the chip type and revision in order to set the correct send command + CS8920 revision C and CS8900 revision F can use the faster send. */ + lp->send_cmd = TX_AFTER_381; + if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') + lp->send_cmd = TX_NOW; + if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') + lp->send_cmd = TX_NOW; + + if (net_debug && version_printed++ == 0) + printk(version); + + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx", + dev->name, + lp->chip_type==CS8900?'0':'2', + lp->chip_type==CS8920M?"M":"", + lp->chip_revision, + dev->base_addr); + + /* Try to read the MAC address */ + if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { + printk("\nmac89x0: No EEPROM, giving up now.\n"); + return ENODEV; + } else { + for (i = 0; i < ETH_ALEN; i += 2) { + /* Big-endian (why??!) */ + unsigned short s = readreg(dev, PP_IA + i); + dev->dev_addr[i] = s >> 8; + dev->dev_addr[i+1] = s & 0xff; + } + } + + dev->irq = SLOT2IRQ(slot); + printk(" IRQ %d ADDR ", dev->irq); + + /* print the ethernet address. */ + for (i = 0; i < ETH_ALEN; i++) + printk("%2.2x%s", dev->dev_addr[i], + ((i < ETH_ALEN-1) ? ":" : "")); + + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &set_mac_address; + + /* Fill in the fields of the net_device structure with ethernet values. */ + ether_setup(dev); + + printk("\n"); + return 0; +} + +/* This is useful for something, but I don't know what yet. */ +void __init reset_chip(struct net_device *dev) +{ + int reset_start_time; + + writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); + + /* wait 30 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(30*HZ/1000); + + /* Wait until the chip is reset */ + reset_start_time = jiffies; + while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) + ; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int +net_open(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int i; + + /* Disable the interrupt for now */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); + + /* Grab the interrupt */ + if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) + return -EAGAIN; + + /* Set up the IRQ - Apparently magic */ + if (lp->chip_type == CS8900) + writereg(dev, PP_CS8900_ISAINT, 0); + else + writereg(dev, PP_CS8920_ISAINT, 0); + + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + /* Turn on both receive and transmit operations */ + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Receive only error free packets addressed to this card */ + lp->rx_mode = 0; + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); + + lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + + writereg(dev, PP_RxCFG, lp->curr_rx_cfg); + + writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + + writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); + + /* now that we've got our act together, enable everything */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + return 0; +} + +static int +net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + save_flags(flags); + cli(); + + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ + restore_flags(flags); + return 1; + } + + /* Write the contents of the packet */ + memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); + + restore_flags(flags); + dev->trans_start = jiffies; + } + dev_kfree_skb (skb); + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct net_local *lp; + int ioaddr, status; + + if (dev == NULL) { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return; + } + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* we MUST read all the events out of the ISQ, otherwise we'll never + get interrupted again. As a consequence, we can't have any limit + on the number of times we loop in the interrupt handler. The + hardware guarantees that eventually we'll run out of events. Of + course, if you're on a slow machine, and packets are arriving + faster than you can read them off, you're screwed. Hasta la + vista, baby! */ + while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) { + if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); + switch(status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + /* Got a packet(s). */ + net_rx(dev); + break; + case ISQ_TRANSMITTER_EVENT: + lp->stats.tx_packets++; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + break; + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + /* we tried to transmit a packet earlier, + but inexplicably ran out of buffers. + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); + lp->send_underrun++; + if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; + else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + } + break; + case ISQ_RX_MISS_EVENT: + lp->stats.rx_missed_errors += (status >>6); + break; + case ISQ_TX_COL_EVENT: + lp->stats.collisions += (status >>6); + break; + } + } + dev->interrupt = 0; + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +net_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + + status = readreg(dev, PP_RxStatus); + if ((status & RX_OK) == 0) { + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; + } + + length = readreg(dev, PP_RxLength); + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return; + } + skb->len = length; + skb->dev = dev; + + memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); + + if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes+=skb->len; + return; +} + +/* The inverse routine to net_open(). */ +static int +net_close(struct net_device *dev) +{ + + writereg(dev, PP_RxCFG, 0); + writereg(dev, PP_TxCFG, 0); + writereg(dev, PP_BufCFG, 0); + writereg(dev, PP_BusCTL, 0); + + dev->start = 0; + + free_irq(dev->irq, dev); + + /* Update the statistics here. */ + + MOD_DEC_USE_COUNT; + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +net_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + cli(); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); + lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); + sti(); + + return &lp->stats; +} + +static void set_multicast_list(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if(dev->flags&IFF_PROMISC) + { + lp->rx_mode = RX_ALL_ACCEPT; + } + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { + /* The multicast-accept list is initialized to accept-all, and we + rely on higher-level filtering for now. */ + lp->rx_mode = RX_MULTCAST_ACCEPT; + } + else + lp->rx_mode = 0; + + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); + + /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ + writereg(dev, PP_RxCFG, lp->curr_rx_cfg | + (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); +} + + +static int set_mac_address(struct net_device *dev, void *addr) +{ + int i; + if (dev->start) + return -EBUSY; + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + return 0; +} + +#ifdef MODULE + +static char namespace[16] = ""; +static struct net_device dev_cs89x0 = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; + +static int debug=0; + +MODULE_PARM(debug, "i"); + +EXPORT_NO_SYMBOLS; + +int +init_module(void) +{ + struct net_local *lp; + + net_debug = debug; + dev_cs89x0.name = namespace; + dev_cs89x0.init = mac89x0_probe; + dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); + lp = (struct net_local *)dev_cs89x0.priv; + + if (register_netdev(&dev_cs89x0) != 0) { + printk(KERN_WARNING "mac89x0.c: No card found\n"); + return -ENXIO; + } + return 0; +} + +void +cleanup_module(void) +{ + +#endif +#ifdef MODULE + writew(0, dev_cs89x0.base_addr + ADD_PORT); +#endif +#ifdef MODULE + + if (dev_cs89x0.priv != NULL) { + /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); + kfree(dev_cs89x0.priv); + dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ + } +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * + */ diff -ur --new-file old/linux/drivers/net/macmace.c new/linux/drivers/net/macmace.c --- old/linux/drivers/net/macmace.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/macmace.c Mon Jan 31 19:34:12 2000 @@ -0,0 +1,825 @@ +/* + * Driver for the Macintosh 68K onboard MACE controller with PSC + * driven DMA. The MACE driver code is derived from mace.c. The + * Mac68k theory of operation is courtesy of the MacBSD wizards. + * + * 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. + * + * Copyright (C) 1996 Paul Mackerras. + * Copyright (C) 1998 Alan Cox + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mace.h" + +#define N_RX_RING 8 +#define N_TX_RING 2 +#define MAX_TX_ACTIVE 1 +#define NCMDS_TX 1 /* dma commands per element in tx ring */ +#define RX_BUFLEN (ETH_FRAME_LEN + 8) +#define TX_TIMEOUT HZ /* 1 second */ + +/* Bits in transmit DMA status */ +#define TX_DMA_ERR 0x80 + +/* The MACE is simply wired down on a Mac68K box */ + +#define MACE_BASE (void *)(0x50F1C000) +#define MACE_PROM (void *)(0x50F08001) + +struct mace68k_data +{ + volatile struct mace *mace; + volatile unsigned char *tx_ring; + volatile unsigned char *rx_ring; + int dma_intr; + unsigned char maccc; + struct net_device_stats stats; + struct timer_list tx_timeout; + int timeout_active; + int rx_slot, rx_done; + int tx_slot, tx_count; +}; + +struct mace_frame +{ + u16 len; + u16 status; + u16 rntpc; + u16 rcvcc; + u32 pad1; + u32 pad2; + u8 data[1]; + /* And frame continues.. */ +}; + +#define PRIV_BYTES sizeof(struct mace68k_data) + +extern void psc_debug_dump(void); + +static int mace68k_open(struct net_device *dev); +static int mace68k_close(struct net_device *dev); +static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *mace68k_stats(struct net_device *dev); +static void mace68k_set_multicast(struct net_device *dev); +static void mace68k_reset(struct net_device *dev); +static int mace68k_set_address(struct net_device *dev, void *addr); +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_set_timeout(struct net_device *dev); +static void mace68k_tx_timeout(unsigned long data); + +/* + * PSC DMA engine control. As you'd expect on a macintosh its + * more like a lawnmower engine supplied without instructions + * + * The basic theory of operation appears to be as follows. + * + * There are two sets of receive DMA registers and two sets + * of transmit DMA registers. Instead of the more traditional + * "ring buffer" approach the Mac68K DMA engine expects you + * to be loading one chain while the other runs, and then + * to flip register set. Each entry in the chain is a fixed + * length. + */ + +/* + * Load a receive DMA channel with a base address and ring length + */ + +static void psc_load_rxdma_base(int set, void *base) +{ + psc_write_word(PSC_ENETRD_CMD + set, 0x0100); + psc_write_long(PSC_ENETRD_ADDR + set, (u32)base); + psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); + psc_write_word(PSC_ENETRD_CMD + set, 0x9800); +} + +/* + * Reset the receive DMA subsystem + */ + +static void mace68k_rxdma_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + /* + * Turn off receive + */ + + mcc&=~ENRCV; + mace->maccc=mcc; + + /* + * Program the DMA + */ + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + mace->maccc=mcc|ENRCV; + +#if 0 + psc_write_word(PSC_ENETRD_CTL, 0x9800); + psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800); +#endif +} + +/* + * Reset the transmit DMA subsystem + */ + +static void mace68k_txdma_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + psc_write_word(PSC_ENETWR_CTL,0x8800); + + mace->maccc = mcc&~ENXMT; + psc_write_word(PSC_ENETWR_CTL,0x0400); + mace->maccc = mcc; +} + +/* + * Disable DMA + */ + +static void mace68k_dma_off(struct net_device *dev) +{ + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_write_word(PSC_ENETRD_CTL, 0x1000); + psc_write_word(PSC_ENETRD_CMD, 0x1100); + psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100); + + psc_write_word(PSC_ENETWR_CTL, 0x8800); + psc_write_word(PSC_ENETWR_CTL, 0x1000); + psc_write_word(PSC_ENETWR_CMD, 0x1100); + psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100); +} + +/* Bit-reverse one byte of an ethernet hardware address. */ + +static int bitrev(int b) +{ + int d = 0, i; + + for (i = 0; i < 8; ++i, b >>= 1) + d = (d << 1) | (b & 1); + return d; +} + +/* + * Not really much of a probe. The hardware table tells us if this + * model of Macintrash has a MACE (AV macintoshes) + */ + +int mace68k_probe(struct net_device *unused) +{ + int j; + static int once=0; + struct mace68k_data *mp; + unsigned char *addr; + struct net_device *dev; + unsigned char checksum = 0; + + /* + * There can be only one... + */ + + if (once) return -ENODEV; + + once = 1; + + if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + + printk("MACE ethernet should be present "); + + dev = init_etherdev(0, PRIV_BYTES); + if(dev==NULL) + { + printk("no free memory.\n"); + return -ENOMEM; + } + mp = (struct mace68k_data *) dev->priv; + dev->base_addr = (u32)MACE_BASE; + mp->mace = (volatile struct mace *) MACE_BASE; + + printk("at 0x%p", mp->mace); + + /* + * 16K RX ring and 4K TX ring should do nicely + */ + + mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2); + mp->tx_ring=(void *)__get_free_page(GFP_KERNEL); + + printk("."); + + if(mp->tx_ring==NULL || mp->rx_ring==NULL) + { + if(mp->tx_ring) + free_page((u32)mp->tx_ring); +// if(mp->rx_ring) +// __free_pages(mp->rx_ring,2); + printk("\nNo memory for ring buffers.\n"); + return -ENOMEM; + } + + /* We want the receive data to be uncached. We dont care about the + byte reading order */ + + printk("."); + kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER); + + printk("."); + /* The transmit buffer needs to be write through */ + kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH); + + printk(" Ok\n"); + dev->irq = IRQ_MAC_MACE; + printk(KERN_INFO "%s: MACE at", dev->name); + + /* + * The PROM contains 8 bytes which total 0xFF when XOR'd + * together. Due to the usual peculiar apple brain damage + * the bytes are spaced out in a strange boundary and the + * bits are reversed. + */ + + addr = (void *)MACE_PROM; + + for (j = 0; j < 6; ++j) + { + u8 v=bitrev(addr[j<<4]); + checksum^=v; + dev->dev_addr[j] = v; + printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]); + } + for (; j < 8; ++j) + { + checksum^=bitrev(addr[j<<4]); + } + + if(checksum!=0xFF) + { + printk(" (invalid checksum)\n"); + return -ENODEV; + } + printk("\n"); + + memset(&mp->stats, 0, sizeof(mp->stats)); + init_timer(&mp->tx_timeout); + mp->timeout_active = 0; + + dev->open = mace68k_open; + dev->stop = mace68k_close; + dev->hard_start_xmit = mace68k_xmit_start; + dev->get_stats = mace68k_stats; + dev->set_multicast_list = mace68k_set_multicast; + dev->set_mac_address = mace68k_set_address; + + ether_setup(dev); + + mp = (struct mace68k_data *) dev->priv; + mp->maccc = ENXMT | ENRCV; + mp->dma_intr = IRQ_MAC_MACE_DMA; + + psc_write_word(PSC_ENETWR_CTL, 0x9000); + psc_write_word(PSC_ENETRD_CTL, 0x9000); + psc_write_word(PSC_ENETWR_CTL, 0x0400); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + /* apple's driver doesn't seem to do this */ + /* except at driver shutdown time... */ +#if 0 + mace68k_dma_off(dev); +#endif + + return 0; +} + +/* + * Reset a MACE controller + */ + +static void mace68k_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + + /* soft-reset the chip */ + i = 200; + while (--i) { + mb->biucc = SWRST; + if (mb->biucc & SWRST) { + udelay(10); + continue; + } + break; + } + if (!i) { + printk(KERN_ERR "mace: cannot reset chip!\n"); + return; + } + + mb->biucc = XMTSP_64; + mb->imr = 0xff; /* disable all intrs for now */ + i = mb->ir; + mb->maccc = 0; /* turn off tx, rx */ + mb->utr = RTRD; + mb->fifocc = RCVFW_64; + mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ + + /* load up the hardware address */ + + mb->iac = ADDRCHG | PHYADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i]; + + /* clear the multicast filter */ + mb->iac = ADDRCHG | LOGADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = 0; + + mb->plscc = PORTSEL_GPSI + ENPLSIO; +} + +/* + * Load the address on a mace controller. + */ + +static int mace68k_set_address(struct net_device *dev, void *addr) +{ + unsigned char *p = addr; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* load up the hardware address */ + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i] = p[i]; + /* note: setting ADDRCHG clears ENRCV */ + mb->maccc = mp->maccc; + restore_flags(flags); + return 0; +} + +/* + * Open the Macintosh MACE. Most of this is playing with the DMA + * engine. The ethernet chip is quite friendly. + */ + +static int mace68k_open(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* reset the chip */ + mace68k_reset(dev); + + mp->rx_done = 0; + mace68k_rxdma_reset(dev); + + /* + * The interrupt is fixed and comes off the PSC. + */ + + if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* + * Ditto the DMA interrupt. + */ + + if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA", + dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA); + return -EAGAIN; + } + + /* Activate the Mac DMA engine */ + + mp->tx_slot = 0; /* Using register set 0 */ + mp->tx_count = 1; /* 1 Buffer ready for use */ + mace68k_txdma_reset(dev); + + /* turn it on! */ + mb->maccc = mp->maccc; + /* enable all interrupts except receive interrupts */ + mb->imr = RCVINT; + return 0; +} + +/* + * Shut down the mace and its interrupt channel + */ + +static int mace68k_close(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* disable rx and tx */ + mb->maccc = 0; + mb->imr = 0xff; /* disable all intrs */ + + /* disable rx and tx dma */ + + mace68k_dma_off(dev); + + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); + return 0; +} + +static inline void mace68k_set_timeout(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + if (mp->timeout_active) + del_timer(&mp->tx_timeout); + mp->tx_timeout.expires = jiffies + TX_TIMEOUT; + mp->tx_timeout.function = mace68k_tx_timeout; + mp->tx_timeout.data = (unsigned long) dev; + add_timer(&mp->tx_timeout); + mp->timeout_active = 1; + restore_flags(flags); +} + +/* + * Transmit a frame + */ + +static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + /* + * This may need atomic types ??? + */ + + printk("mace68k_xmit_start: mp->tx_count = %d, dev->tbusy = %d, mp->tx_ring = %p (%p)\n", + mp->tx_count, dev->tbusy, + mp->tx_ring, virt_to_bus(mp->tx_ring)); + psc_debug_dump(); + + if(mp->tx_count == 0) + { + dev->tbusy=1; + mace68k_dma_intr(IRQ_MAC_MACE_DMA, dev, NULL); + return 1; + } + mp->tx_count--; + + /* + * FIXME: + * This is hackish. The memcpy probably isnt needed but + * the rules for alignment are not known. Ideally we'd like + * to just blast the skb directly to ethernet. We also don't + * use the ring properly - just a one frame buffer. That + * also requires cache pushes ;). + */ + memcpy((void *)mp->tx_ring, skb, skb->len); + psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring)); + psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); + mp->stats.tx_packets++; + mp->stats.tx_bytes+=skb->len; + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *mace68k_stats(struct net_device *dev) +{ + struct mace68k_data *p = (struct mace68k_data *) dev->priv; + return &p->stats; +} + +/* + * CRC polynomial - used in working out multicast filter bits. + */ +#define CRC_POLY 0xedb88320 + +static void mace68k_set_multicast(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i, j, k, b; + unsigned long crc; + + mp->maccc &= ~PROM; + if (dev->flags & IFF_PROMISC) + { + mp->maccc |= PROM; + } else + { + unsigned char multicast_filter[8]; + struct dev_mc_list *dmi = dev->mc_list; + + if (dev->flags & IFF_ALLMULTI) + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0xff; + } else + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0; + for (i = 0; i < dev->mc_count; i++) + { + crc = ~0; + for (j = 0; j < 6; ++j) + { + b = dmi->dmi_addr[j]; + for (k = 0; k < 8; ++k) + { + if ((crc ^ b) & 1) + crc = (crc >> 1) ^ CRC_POLY; + else + crc >>= 1; + b >>= 1; + } + } + j = crc >> 26; /* bit number in multicast_filter */ + multicast_filter[j >> 3] |= 1 << (j & 7); + dmi = dmi->next; + } + } +#if 0 + printk("Multicast filter :"); + for (i = 0; i < 8; i++) + printk("%02x ", multicast_filter[i]); + printk("\n"); +#endif + + mb->iac = ADDRCHG | LOGADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = multicast_filter[i]; + } + /* reset maccc */ + mb->maccc = mp->maccc; +} + +/* + * Miscellaneous interrupts are handled here. We may end up + * having to bash the chip on the head for bad errors + */ + +static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr) +{ + volatile struct mace *mb = mp->mace; + static int mace68k_babbles, mace68k_jabbers; + + if (intr & MPCO) + mp->stats.rx_missed_errors += 256; + mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + if (intr & RNTPCO) + mp->stats.rx_length_errors += 256; + mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + if (intr & CERR) + ++mp->stats.tx_heartbeat_errors; + if (intr & BABBLE) + if (mace68k_babbles++ < 4) + printk(KERN_DEBUG "mace: babbling transmitter\n"); + if (intr & JABBER) + if (mace68k_jabbers++ < 4) + printk(KERN_DEBUG "mace: jabbering transceiver\n"); +} + +/* + * A transmit error has occured. (We kick the transmit side from + * the DMA completion) + */ + +static void mace68k_xmit_error(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 xmtfs, xmtrc; + + xmtfs = mb->xmtfs; + xmtrc = mb->xmtrc; + + if(xmtfs & XMTSV) + { + if(xmtfs & UFLO) + { + printk("%s: DMA underrun.\n", dev->name); + mp->stats.tx_errors++; + mp->stats.tx_fifo_errors++; + mace68k_reset(dev); + } + if(xmtfs & RTRY) + mp->stats.collisions++; + } + mark_bh(NET_BH); +} + +/* + * A receive interrupt occured. + */ + +static void mace68k_recv_interrupt(struct net_device *dev) +{ +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Process the chip interrupt + */ + +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 ir; + + ir = mb->ir; + mace68k_handle_misc_intrs(mp, ir); + + if(ir&XMTINT) + mace68k_xmit_error(dev); + if(ir&RCVINT) + mace68k_recv_interrupt(dev); +} + +static void mace68k_tx_timeout(unsigned long data) +{ +// struct net_device *dev = (struct net_device *) data; +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Handle a newly arrived frame + */ + +static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct sk_buff *skb; + + if(mf->status&RS_OFLO) + { + printk("%s: fifo overflow.\n", dev->name); + mp->stats.rx_errors++; + mp->stats.rx_fifo_errors++; + } + if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) + mp->stats.rx_errors++; + + if(mf->status&RS_CLSN) + mp->stats.collisions++; + if(mf->status&RS_FRAMERR) + mp->stats.rx_frame_errors++; + if(mf->status&RS_FCSERR) + mp->stats.rx_crc_errors++; + + skb = dev_alloc_skb(mf->len+2); + if(skb==NULL) + { + mp->stats.rx_dropped++; + return; + } + skb_reserve(skb,2); + memcpy(skb_put(skb, mf->len), mf->data, mf->len); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + mp->stats.rx_packets++; + mp->stats.rx_bytes+=mf->len; +} + +/* + * The PSC has passed us a DMA interrupt event. + */ + +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + +#if 0 + u32 psc_status; + + /* It seems this must be allowed to stabilise ?? */ + + while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804)); + + /* + * Was this an ethernet event ? + */ + + if(psc_status&0x60000000) + { +#endif + /* + * Process the read queue + */ + + u16 psc_status = psc_read_word(PSC_ENETRD_CTL); + + printk("mace68k_dma_intr: PSC_ENETRD_CTL = %04X\n", (uint) psc_status); + + if (psc_status & 0x2000) { + mace68k_rxdma_reset(dev); + mp->rx_done = 0; + } else if (psc_status & 0x100) { + int left; + + psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); + left=psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); + /* read packets */ + + while(mp->rx_done < left) + { + struct mace_frame *mf=((struct mace_frame *) + mp->rx_ring)+mp->rx_done++; + mace_dma_rx_frame(dev, mf); + } + + if(left == 0) /* Out of DMA room */ + { + psc_load_rxdma_base(mp->rx_slot, + (void *)virt_to_phys(mp->rx_ring)); + mp->rx_slot^=16; + mp->rx_done = 0; + } + else + { + psc_write_word(PSC_ENETRD_CMD+mp->rx_slot, + 0x9800); + } + + } + + /* + * Process the write queue + */ + + psc_status = psc_read_word(PSC_ENETWR_CTL); + printk("mace68k_dma_intr: PSC_ENETWR_CTL = %04X\n", (uint) psc_status); + + /* apple's driver seems to loop over this until neither */ + /* condition is true. - jmt */ + + if (psc_status & 0x2000) { + mace68k_txdma_reset(dev); + } else if (psc_status & 0x0100) { + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x0100); + mp->tx_slot ^=16; + mp->tx_count++; + dev->tbusy = 0; + mark_bh(NET_BH); + } +#if 0 + } +#endif +} diff -ur --new-file old/linux/drivers/net/macsonic.c new/linux/drivers/net/macsonic.c --- old/linux/drivers/net/macsonic.c Thu Aug 26 23:29:08 1999 +++ new/linux/drivers/net/macsonic.c Tue Feb 1 08:43:51 2000 @@ -42,153 +42,245 @@ #include #include #include +#include #include #include +#include +#include #include #include #include #include - -#include +#include #define SREGS_PAD(n) u16 n; #include "sonic.h" -extern int mac_onboard_sonic_probe(void); +static int sonic_debug = 0; +static int sonic_version_printed = 0; -static int setup_debug = -1; -static int setup_offset = -1; -static int setup_shift = -1; +extern int macsonic_probe(struct net_device* dev); +extern int mac_onboard_sonic_probe(struct net_device* dev); +extern int mac_nubus_sonic_probe(struct net_device* dev); + +/* For onboard SONIC */ +#define ONBOARD_SONIC_REGISTERS 0x50F0A000 +#define ONBOARD_SONIC_PROM_BASE 0x50f08000 + +enum macsonic_type { + MACSONIC_DUODOCK, + MACSONIC_APPLE, + MACSONIC_APPLE16, + MACSONIC_DAYNA, + MACSONIC_DAYNALINK +}; + +/* For the built-in SONIC in the Duo Dock */ +#define DUODOCK_SONIC_REGISTERS 0xe10000 +#define DUODOCK_SONIC_PROM_BASE 0xe12000 + +/* For Apple-style NuBus SONIC */ +#define APPLE_SONIC_REGISTERS 0 +#define APPLE_SONIC_PROM_BASE 0x40000 + +/* Daynalink LC SONIC */ +#define DAYNALINK_PROM_BASE 0x400000 + +/* For Dayna-style NuBus SONIC (haven't seen one yet) */ +#define DAYNA_SONIC_REGISTERS 0x180000 +/* This is what OpenBSD says. However, this is definitely in NuBus + ROM space so we should be able to get it by walking the NuBus + resource directories */ +#define DAYNA_SONIC_MAC_ADDR 0xffe004 -/* - * This seems to be the right default for the Q800 - */ +#define SONIC_READ_PROM(addr) readb(prom_addr+addr) -static int reg_offset = 0; -static int reg_shift = 0; +int __init macsonic_probe(struct net_device* dev) +{ + int rv; -/* - * Macros to access SONIC registers - */ - -#define MAC_SONIC_REGISTERS 0x50F0A000 -#define MAC_SONIC_PROM_BASE 0x50f08000 -#define MAC_SONIC_IRQ 9 /* Nubus 9 */ + /* This will catch fatal stuff like -ENOMEM as well as success */ + if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) + return rv; + return mac_nubus_sonic_probe(dev); +} /* - * FIXME: We may need to invert the byte ordering. These should - * be ok for other aspects as they are uncached spaces. - * The original macros from jazzsonic.c works for me - * on my LC 630, YMMV /Andreas Ehliar + * For reversing the PROM address */ -#if 0 -#define SONIC_READ(reg) \ - *((volatile unsigned int *)base_addr+((reg)<<2)+2) +static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, + 1, 9, 5, 13, 3, 11, 7, 15}; -#define SONIC_WRITE(reg,val) \ - *((volatile unsigned int *)base_addr+((reg)<<2)+2) = val -#else -#define SONIC_READ(reg) \ - *((volatile unsigned int *)base_addr+reg) +static inline void bit_reverse_addr(unsigned char addr[6]) +{ + int i; -#define SONIC_WRITE(reg,val) \ - *((volatile unsigned int *)base_addr+reg) = val -#endif + for(i = 0; i < 6; i++) + addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | + nibbletab[(addr[i] >> 4) &0xf]); +} -#define SONIC_READ_PROM(addr) \ - *((volatile unsigned char *)prom_addr+addr) -/* - * Function : mac_sonic_setup(char *str, int *ints) - * - * Purpose : booter command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - * Currently unused in the new driver; need to add settable parameters to the - * detect function. - * - */ +int __init macsonic_init(struct net_device* dev) +{ + struct sonic_local* lp = (struct sonic_local *)dev->priv; + int i; -void mac_sonic_setup(char *str, int *ints) { - /* Format of macsonic parameter is: - * macsonic=,, - * Negative values mean don't change. - */ - - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ + /* Allocate the entire chunk of memory for the descriptors. + Note that this cannot cross a 64K boundary. */ + for (i = 0; i < 20; i++) { + unsigned long desc_base, desc_top; + if ((lp->sonic_desc = + kmalloc(SIZEOF_SONIC_DESC + * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); + } + desc_base = (unsigned long) lp->sonic_desc; + desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); + if ((desc_top & 0xffff) >= (desc_base & 0xffff)) + break; + /* Hmm. try again (FIXME: does this actually work?) */ + kfree(lp->sonic_desc); + printk(KERN_DEBUG + "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", + dev->name, desc_base, desc_top); + } + + if (lp->sonic_desc == NULL) { + printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", + dev->name); + return -ENOMEM; + } - int i = ints[0]+1, fact; + /* Now set up the pointers to point to the appropriate places */ + lp->cda = lp->sonic_desc; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + + /* FIXME, maybe we should use skbs */ + if ((lp->rba = (char *) + kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + return -ENOMEM; + } - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; + { + int rs, ds; + + /* almost always 12*4096, but let's not take chances */ + rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; + /* almost always under a page, but let's not take chances */ + ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096; + kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); + kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER); } - ints[0] = i-1; - if (ints[0] < 1) { - printk( "mac_sonic_setup: no arguments!\n" ); - return; - } - - if (ints[0] >= 1) { - /* 0 <= n <= 2 */ - if (ints[1] >= 0 && ints[1] <= 8) - setup_debug = ints[1]; - else if (ints[1] > 16) - printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] ); - } - if (ints[0] >= 2) { - /* 0 <= n <= 2 */ - if (ints[2] >= 0 && ints[2] <= 16) - setup_offset = ints[2]; - else if (ints[2] > 16) - printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] ); - } - if (ints[0] >= 3) { - /* 0 <= n <= 2 */ - if (ints[3] >= 0 && ints[3] <= 16) - setup_shift = ints[3]; - else if (ints[3] > 16) - printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] ); - } +#if 0 + flush_cache_all(); +#endif + + dev->open = sonic_open; + dev->stop = sonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; + + /* + * clear tally counter + */ + sonic_write(dev, SONIC_CRCT, 0xffff); + sonic_write(dev, SONIC_FAET, 0xffff); + sonic_write(dev, SONIC_MPT, 0xffff); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; } -static int sonic_debug = 0; +int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) +{ + const int prom_addr = ONBOARD_SONIC_PROM_BASE; + int i; -/* - * For reversing the PROM address - */ + /* On NuBus boards we can sometimes look in the ROM resources. + No such luck for comm-slot/onboard. */ + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); + + /* Most of the time, the address is bit-reversed. The NetBSD + source has a rather long and detailed historical account of + why this is so. */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + bit_reverse_addr(dev->dev_addr); + else + return 0; + + /* If we still have what seems to be a bogus address, we'll + look in the CAM. The top entry should be ours. */ + /* Danger! This only works if MacOS has already initialized + the card... */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + unsigned short val; -static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, - 1, 9, 5, 13, 3, 11, 7, 15}; + printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); + + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_CEP, 15); + + val = sonic_read(dev, SONIC_CAP2); + dev->dev_addr[5] = val >> 8; + dev->dev_addr[4] = val & 0xff; + val = sonic_read(dev, SONIC_CAP1); + dev->dev_addr[3] = val >> 8; + dev->dev_addr[2] = val & 0xff; + val = sonic_read(dev, SONIC_CAP0); + dev->dev_addr[1] = val >> 8; + dev->dev_addr[0] = val & 0xff; + + printk(KERN_INFO "HW Address from CAM 15: "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk("\n"); + } else return 0; -int __init mac_onboard_sonic_probe(void) + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + /* + * Still nonsense ... messed up someplace! + */ + printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n"); + return -EIO; + } else return 0; +} + +int __init mac_onboard_sonic_probe(struct net_device* dev) { - struct net_device *dev; - unsigned int silicon_revision; - unsigned int val; - struct sonic_local *lp; + /* Bwahahaha */ + static int once_is_more_than_enough = 0; + struct sonic_local* lp; int i; - int base_addr = MAC_SONIC_REGISTERS; - int prom_addr = MAC_SONIC_PROM_BASE; - static int one=0; - if (!MACH_IS_MAC) + if (once_is_more_than_enough) return -ENODEV; + once_is_more_than_enough = 1; - if(++one!=1) /* Only one is allowed */ + if (!MACH_IS_MAC) return -ENODEV; printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); @@ -198,288 +290,332 @@ printk("none.\n"); return -ENODEV; } - - printk("yes\n"); - - if (setup_debug >= 0) - sonic_debug = setup_debug; - - /* - * This may depend on the actual Mac model ... works for me. - */ - reg_offset = - (setup_offset >= 0) ? setup_offset : 0; - reg_shift = - (setup_shift >= 0) ? setup_shift : 0; - /* - * get the Silicon Revision ID. If this is one of the known - * one assume that we found a SONIC ethernet controller at - * the expected location. - * (This is not implemented in the Macintosh driver yet; need - * to collect values from various sources. Mine is 0x4 ...) - */ + /* Bogus probing, on the models which may or may not have + Ethernet (BTW, the Ethernet *is* always at the same + address, and nothing else lives there, at least if Apple's + documentation is to be believed) */ + if (macintosh_config->ident == MAC_MODEL_Q630 || + macintosh_config->ident == MAC_MODEL_P588 || + macintosh_config->ident == MAC_MODEL_C610) { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); + restore_flags(flags); + + if (!card_present) { + printk("none.\n"); + return -ENODEV; + } + } - silicon_revision = SONIC_READ(SONIC_SR); - if (sonic_debug > 1) - printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision); + printk("yes\n"); + + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); + } - /* - * We need to allocate sonic_local later on, making sure it's - * aligned on a 64k boundary. So, no space for dev->priv allocated - * here ... - */ - dev = init_etherdev(0,0); - - if(dev==NULL) + if (dev == NULL) return -ENOMEM; - printk("%s: %s found at 0x%08x, ", - dev->name, "SONIC ethernet", base_addr); + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ + + dev->base_addr = ONBOARD_SONIC_REGISTERS; + if (via_alt_mapping) + dev->irq = IRQ_AUTO_3; + else + dev->irq = IRQ_NUBUS_9; + + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", + dev->name, dev->base_addr); + + /* Now do a song and dance routine in an attempt to determine + the bus width */ + + /* The PowerBook's SONIC is 16 bit always. */ + if (macintosh_config->ident == MAC_MODEL_PB520) { + lp->reg_offset = 0; + lp->dma_bitmode = 0; + } else { + /* Some of the comm-slot cards are 16 bit. But some + of them are not. The 32-bit cards use offset 2 and + pad with zeroes or sometimes ones (I think...) + Therefore, if we try offset 0 and get a silicon + revision of 0, we assume 16 bit. */ + int sr; + + /* Technically this is not necessary since we zeroed + it above */ + lp->reg_offset = 0; + lp->dma_bitmode = 0; + sr = sonic_read(dev, SONIC_SR); + if (sr == 0 || sr == 0xffff) { + lp->reg_offset = 2; + /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ + sr = sonic_read(dev, SONIC_SR); + lp->dma_bitmode = 1; + + } + printk(KERN_INFO + "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset); + } + + + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | + (lp->dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the + extended programmable output bits */ + sonic_write(dev, SONIC_DCR2, 0); + + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); - if (sonic_debug > 1) - printk("using offset %d shift %d,", reg_offset, reg_shift); - - /* Fill in the 'dev' fields. */ - dev->base_addr = base_addr; - dev->irq = MAC_SONIC_IRQ; + /* Now look for the MAC address. */ + if (mac_onboard_sonic_ethernet_addr(dev) != 0) + return -ENODEV; - /* - * Put the sonic into software reset, then - * retrieve and print the ethernet address. - */ + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } - SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + printk(" IRQ %d\n", dev->irq); - /* - * We can't trust MacOS to initialise things it seems. - */ + /* Shared init code */ + return macsonic_init(dev); +} - if (sonic_debug > 1) - printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR)); - - SONIC_WRITE(SONIC_DCR, - SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW); +int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, + unsigned long prom_addr, + int id) +{ + int i; + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); + /* For now we are going to assume that they're all bit-reversed */ + bit_reverse_addr(dev->dev_addr); - /* - * We don't want floating spare IRQ's around, not on - * level triggered systems! - * Strange though - writing to the ISR only clears currently - * pending IRQs, but doesn't disable them... Does this make - * a difference?? Seems it does ... - */ -#if 1 - SONIC_WRITE(SONIC_ISR,0x7fff); - SONIC_WRITE(SONIC_IMR,0); -#else - SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT); -#endif - - /* This is how it is done in jazzsonic.c - * It doesn't seem to work here though. - */ - if (sonic_debug > 2) { - printk("Retreiving CAM entry 0. This should be the HW address.\n"); - - SONIC_WRITE(SONIC_CEP, 0); - for (i = 0; i < 3; i++) - { - val = SONIC_READ(SONIC_CAP0 - i); - dev->dev_addr[i * 2] = val; - dev->dev_addr[i * 2 + 1] = val >> 8; - } + return 0; +} - printk("HW Address from CAM 0: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); +int __init macsonic_ident(struct nubus_dev* ndev) +{ + if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && + ndev->dr_sw == NUBUS_DRSW_SONIC_LC) + return MACSONIC_DAYNALINK; + if (ndev->dr_hw == NUBUS_DRHW_SONIC && + ndev->dr_sw == NUBUS_DRSW_APPLE) { + /* There has to be a better way to do this... */ + if (strstr(ndev->board->name, "DuoDock")) + return MACSONIC_DUODOCK; + else + return MACSONIC_APPLE; + } + return -1; +} - printk("Retreiving CAM entry 15. Another candidate...\n"); +int __init mac_nubus_sonic_probe(struct net_device* dev) +{ + static int slots = 0; + struct nubus_dev* ndev = NULL; + struct sonic_local* lp; + unsigned long base_addr, prom_addr; + u16 sonic_dcr; + int id; + int i; + int reg_offset, dma_bitmode; - /* - * MacOS seems to use CAM entry 15 ... - */ - SONIC_WRITE(SONIC_CEP, 15); - for (i = 0; i < 3; i++) - { - val = SONIC_READ(SONIC_CAP0 - i); - dev->dev_addr[i * 2] = val; - dev->dev_addr[i * 2 + 1] = val >> 8; - } + /* Find the first SONIC that hasn't been initialized already */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) + { + /* Have we seen it already? */ + if (slots & (1<board->slot)) + continue; + slots |= 1<board->slot; - printk("HW Address from CAM 15: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); + /* Is it one of ours? */ + if ((id = macsonic_ident(ndev)) != -1) + break; } - /* - * if we can read the PROM, we're safe :-) - */ - if (sonic_debug > 1) - printk("Retreiving HW address from the PROM: "); + if (ndev == NULL) + return -ENODEV; - for(i=0;i<6;i++){ - dev->dev_addr[i]=SONIC_READ_PROM(i); - } - if (sonic_debug > 1) { - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); + switch (id) { + case MACSONIC_DUODOCK: + base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 + | SONIC_DCR_TFT0; + reg_offset = 2; + dma_bitmode = 1; + break; + case MACSONIC_APPLE: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; + reg_offset = 0; + dma_bitmode = 1; + break; + case MACSONIC_APPLE16: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNALINK: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; + sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNA: + base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; + sonic_dcr = SONIC_DCR_BMS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; + reg_offset = 0; + dma_bitmode = 0; + break; + default: + printk(KERN_ERR "macsonic: WTF, id is %d\n", id); + return -ENODEV; } - /* - * If its not one of these we have - * screwed up on this Mac model - */ - if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && - memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && - memcmp(dev->dev_addr, "\x00\x05\x02", 3)) - { - /* - * Try bit reversed - */ - for(i=0;i<6;i++){ - val = SONIC_READ_PROM(i); - dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) | - nibbletab[(val >> 4) &0xf]; - } - if (sonic_debug > 1) { - printk("Trying bit reversed: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); - } - if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && - memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && - memcmp(dev->dev_addr, "\x00\x05\x02", 3)) - { - /* - * Still nonsense ... messed up someplace! - */ - printk("ERROR (INVALID MAC)\n"); - return -EIO; - } + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); } - printk(" MAC "); - for (i = 0; i < 6; i++) - { + if (dev == NULL) + return -ENOMEM; + + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ + lp->reg_offset = reg_offset; + lp->dma_bitmode = dma_bitmode; + dev->base_addr = base_addr; + dev->irq = SLOT2IRQ(ndev->board->slot); + + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: %s in slot %X\n", + dev->name, ndev->board->name, ndev->board->slot); + printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, sonic_dcr + | (dma_bitmode ? SONIC_DCR_DW : 0)); + + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); + + /* Now look for the MAC address. */ + if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) + return -ENODEV; + + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { printk("%2.2x", dev->dev_addr[i]); if (i < 5) printk(":"); } + printk(" IRQ %d\n", dev->irq); - printk(" IRQ %d\n", MAC_SONIC_IRQ); + /* Shared init code */ + return macsonic_init(dev); +} - /* Initialize the device structure. */ - if (dev->priv == NULL) - { - if (sonic_debug > 2) { - printk("Allocating memory for dev->priv aka lp\n"); - printk("Memory to allocate: %d\n",sizeof(*lp)); - } - /* - * the memory be located in the same 64kb segment - */ - lp = NULL; - i = 0; - do - { - lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL); - if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16) - { - /* FIXME, free the memory later */ - kfree(lp); - lp = NULL; - } - } - while (lp == NULL && i++ < 20); +#ifdef MODULE +static char namespace[16] = ""; +static struct net_device dev_macsonic = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; - if (lp == NULL) - { - printk("%s: couldn't allocate memory for descriptors\n", - dev->name); - return -ENOMEM; - } +MODULE_PARM(sonic_debug, "i"); - if (sonic_debug > 2) { - printk("Memory allocated after %d tries\n",i); - } +EXPORT_NO_SYMBOLS; - /* XXX sonic_local has the TDA, RRA, RDA, don't cache */ - kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER); - memset(lp, 0, sizeof(struct sonic_local)); - - lp->cda_laddr = (u32)lp; - if (sonic_debug > 2) { - printk("memory allocated for sonic at 0x%x\n",lp); - } - lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda); - lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda); - lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra); - - /* allocate receive buffer area */ - /* FIXME, maybe we should use skbs */ - if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) - { - printk("%s: couldn't allocate receive buffers\n", dev->name); - return -ENOMEM; - } - /* XXX RBA written by Sonic, not cached either */ - kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER); - lp->rba_laddr = (u32)lp->rba; - flush_cache_all(); - dev->priv = (struct sonic_local *) lp; - } - lp = (struct sonic_local *) dev->priv; - dev->open = sonic_open; - dev->stop = sonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; +int +init_module(void) +{ + dev_macsonic.name = namespace; + dev_macsonic.init = macsonic_probe; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + if (register_netdev(&dev_macsonic) != 0) { + printk(KERN_WARNING "macsonic.c: No card found\n"); + return -ENXIO; + } return 0; } -/* - * SONIC uses a nubus IRQ - */ +void +cleanup_module(void) +{ + if (dev_macsonic.priv != NULL) { + unregister_netdev(&dev_macsonic); + kfree(dev_macsonic.priv); + dev_macsonic.priv = NULL; + } +} +#endif /* MODULE */ -#define sonic_request_irq(irq, vec, flags, name, dev) \ - nubus_request_irq(irq, dev, vec) -#define sonic_free_irq(irq,id) nubus_free_irq(irq) -/* - * No funnies on memory mapping. - */ +#define vdma_alloc(foo, bar) ((u32)foo) +#define vdma_free(baz) +#define sonic_chiptomem(bat) (bat) +#define PHYSADDR(quux) (quux) -#define sonic_chiptomem(x) (x) +#include "sonic.c" /* - * No VDMA on a Macintosh. So we need request no such facility. + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * */ - -#define vdma_alloc(x,y) ((u32)(x)) -#define vdma_free(x) -#define PHYSADDR(x) (x) - -#include "sonic.c" diff -ur --new-file old/linux/drivers/net/sun3lance.c new/linux/drivers/net/sun3lance.c --- old/linux/drivers/net/sun3lance.c Wed Sep 8 20:20:42 1999 +++ new/linux/drivers/net/sun3lance.c Mon Jan 31 19:30:00 2000 @@ -21,7 +21,7 @@ */ -static char *version = "sun3lance.c: v1.0 12/12/96 Sam Creasey (sammy@users.qual.net)\n"; +static char *version = "sun3lance.c: v1.1 11/17/1999 Sam Creasey (sammy@oh.verio.com)\n"; #include @@ -263,6 +263,8 @@ int i; static int did_version = 0; int found = 0; + volatile unsigned short *ioaddr_probe; + unsigned short tmp1, tmp2; /* LANCE_OBIO can be found within the IO pmeg with some effort */ for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + @@ -281,6 +283,23 @@ if(!found) return 0; + + /* test to see if there's really a lance here */ + /* (CSRO_INIT shouldn't be readable) */ + + ioaddr_probe = (volatile unsigned short *)ioaddr; + tmp1 = ioaddr_probe[0]; + tmp2 = ioaddr_probe[1]; + + ioaddr_probe[1] = CSR0; + ioaddr_probe[0] = CSR0_INIT | CSR0_STOP; + + if(ioaddr_probe[0] != CSR0_STOP) { + ioaddr_probe[0] = tmp1; + ioaddr_probe[1] = tmp2; + + return 0; + } init_etherdev( dev, sizeof(struct lance_private) ); if (!dev->priv) diff -ur --new-file old/linux/drivers/net/sunbmac.c new/linux/drivers/net/sunbmac.c --- old/linux/drivers/net/sunbmac.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/net/sunbmac.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.12 1999/12/15 14:07:58 davem Exp $ +/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) diff -ur --new-file old/linux/drivers/net/sunhme.c new/linux/drivers/net/sunhme.c --- old/linux/drivers/net/sunhme.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/net/sunhme.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.84 1999/12/15 14:08:03 davem Exp $ +/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. diff -ur --new-file old/linux/drivers/net/sunlance.c new/linux/drivers/net/sunlance.c --- old/linux/drivers/net/sunlance.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/net/sunlance.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.92 1999/12/15 14:08:09 davem Exp $ +/* $Id: sunlance.c,v 1.93 2000/01/28 13:42:31 jj Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza diff -ur --new-file old/linux/drivers/net/sunqe.c new/linux/drivers/net/sunqe.c --- old/linux/drivers/net/sunqe.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/net/sunqe.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.40 1999/12/15 14:08:13 davem Exp $ +/* $Id: sunqe.c,v 1.41 2000/01/28 13:42:30 jj Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed diff -ur --new-file old/linux/drivers/sbus/audio/cs4231.c new/linux/drivers/sbus/audio/cs4231.c --- old/linux/drivers/sbus/audio/cs4231.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/sbus/audio/cs4231.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: cs4231.c,v 1.41 1999/12/19 23:28:03 davem Exp $ +/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $ * drivers/sbus/audio/cs4231.c * * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) diff -ur --new-file old/linux/drivers/sbus/audio/dbri.c new/linux/drivers/sbus/audio/dbri.c --- old/linux/drivers/sbus/audio/dbri.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/sbus/audio/dbri.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: dbri.c,v 1.17 2000/01/20 07:57:47 anton Exp $ +/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $ * drivers/sbus/audio/dbri.c * * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) diff -ur --new-file old/linux/drivers/sbus/char/zs.c new/linux/drivers/sbus/char/zs.c --- old/linux/drivers/sbus/char/zs.c Tue Dec 21 07:06:42 1999 +++ new/linux/drivers/sbus/char/zs.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.52 1999/12/15 14:29:20 davem Exp $ +/* $Id: zs.c,v 1.53 2000/01/29 01:29:38 anton Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1928,7 +1928,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.52 $"; + char *revision = "$Revision: 1.53 $"; char *version, *p; version = strchr(revision, ' '); @@ -2076,11 +2076,6 @@ static int irq = 0; int chipid = chip; -#if CONFIG_AP1000 - printk("No zs chip\n"); - return NULL; -#endif - iospace = 0; if(chip < 0 || chip >= NUM_SERIAL) panic("get_zs bogon zs chip number"); @@ -2406,11 +2401,6 @@ unsigned long flags; struct sun_serial *info; char dummy; - -#if CONFIG_AP1000 - printk("not doing zs_init()\n"); - return 0; -#endif /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); diff -ur --new-file old/linux/drivers/scsi/esp.c new/linux/drivers/scsi/esp.c --- old/linux/drivers/scsi/esp.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/scsi/esp.c Tue Feb 1 08:37:19 2000 @@ -1,4 +1,4 @@ -/* $Id: esp.c,v 1.89 1999/12/23 01:46:14 davem Exp $ +/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $ * esp.c: EnhancedScsiProcessor Sun SCSI driver code. * * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) diff -ur --new-file old/linux/drivers/scsi/scsi_merge.c new/linux/drivers/scsi/scsi_merge.c --- old/linux/drivers/scsi/scsi_merge.c Thu Jan 27 17:58:15 2000 +++ new/linux/drivers/scsi/scsi_merge.c Tue Feb 1 10:31:04 2000 @@ -87,7 +87,7 @@ * Dump the information that we have. We know we have an * inconsistency. */ - printk("nr_segments is %lx\n", req->nr_segments); + printk("nr_segments is %x\n", req->nr_segments); printk("counted segments is %x\n", segments); printk("Flags %d %d\n", use_clustering, dma_host); for (bh = req->bh; bh->b_reqnext != NULL; bh = bh->b_reqnext) diff -ur --new-file old/linux/drivers/scsi/sd.c new/linux/drivers/scsi/sd.c --- old/linux/drivers/scsi/sd.c Fri Jan 21 18:48:12 2000 +++ new/linux/drivers/scsi/sd.c Sat Jan 29 09:17:38 2000 @@ -373,6 +373,7 @@ static int sd_open(struct inode *inode, struct file *filp) { int target; + Scsi_Device * SDev; target = DEVICE_NR(inode->i_rdev); SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max)); @@ -412,13 +413,14 @@ if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) return -EROFS; } + SDev = rscsi_disks[target].device; /* * It is possible that the disk changing stuff resulted in the device * being taken offline. If this is the case, report this to the user, * and don't pretend that * the open actually succeeded. */ - if (!rscsi_disks[target].device->online) { + if (!SDev->online) { return -ENXIO; } /* @@ -428,13 +430,14 @@ if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) return -ENXIO; - if (rscsi_disks[target].device->removable) - if (!rscsi_disks[target].device->access_count) - sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); - - rscsi_disks[target].device->access_count++; - if (rscsi_disks[target].device->host->hostt->module) - __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if (SDev->removable) + if (!SDev->access_count) + if (scsi_block_when_processing_errors(SDev)) + scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); + + SDev->access_count++; + if (SDev->host->hostt->module) + __MOD_INC_USE_COUNT(SDev->host->hostt->module); if (sd_template.module) __MOD_INC_USE_COUNT(sd_template.module); return 0; @@ -443,17 +446,20 @@ static int sd_release(struct inode *inode, struct file *file) { int target; + Scsi_Device * SDev; target = DEVICE_NR(inode->i_rdev); + SDev = rscsi_disks[target].device; - rscsi_disks[target].device->access_count--; + SDev->access_count--; - if (rscsi_disks[target].device->removable) { - if (!rscsi_disks[target].device->access_count) - sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + if (SDev->removable) { + if (!SDev->access_count) + if (scsi_block_when_processing_errors(SDev)) + scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL); } - if (rscsi_disks[target].device->host->hostt->module) - __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if (SDev->host->hostt->module) + __MOD_DEC_USE_COUNT(SDev->host->hostt->module); if (sd_template.module) __MOD_DEC_USE_COUNT(sd_template.module); return 0; @@ -580,17 +586,17 @@ { int retval; int target; - struct inode inode; int flag = 0; + Scsi_Device * SDev; target = DEVICE_NR(full_dev); + SDev = rscsi_disks[target].device; - if (target >= sd_template.dev_max || - !rscsi_disks[target].device) { + if (target >= sd_template.dev_max || !SDev) { printk("SCSI disk request error: invalid device.\n"); return 0; } - if (!rscsi_disks[target].device->removable) + if (!SDev->removable) return 0; /* @@ -599,13 +605,12 @@ * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ - if (rscsi_disks[target].device->online == FALSE) { + if (SDev->online == FALSE) { rscsi_disks[target].ready = 0; - rscsi_disks[target].device->changed = 1; + SDev->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ } - inode.i_rdev = full_dev; /* This is all we really need here */ /* Using Start/Stop enables differentiation between drive with * no cartridge loaded - NOT READY, drive with changed cartridge - @@ -613,7 +618,9 @@ * This also handles drives that auto spin down. eg iomega jaz 1GB * as this will spin up the drive. */ - retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0); + retval = -ENODEV; + if (scsi_block_when_processing_errors(SDev)) + retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL); if (retval) { /* Unable to test, unit probably not ready. * This usually means there is no disc in the @@ -622,7 +629,7 @@ * again. */ rscsi_disks[target].ready = 0; - rscsi_disks[target].device->changed = 1; + SDev->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ } @@ -634,9 +641,9 @@ rscsi_disks[target].ready = 1; /* FLOPTICAL */ - retval = rscsi_disks[target].device->changed; + retval = SDev->changed; if (!flag) - rscsi_disks[target].device->changed = 0; + SDev->changed = 0; return retval; } diff -ur --new-file old/linux/drivers/sound/Config.in new/linux/drivers/sound/Config.in --- old/linux/drivers/sound/Config.in Mon Dec 27 04:34:04 1999 +++ new/linux/drivers/sound/Config.in Sat Jan 29 04:36:23 2000 @@ -26,7 +26,7 @@ dep_tristate ' SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND fi -dep_tristate ' Trident 4DWave-DX/NX' CONFIG_SOUND_TRIDENT $CONFIG_SOUND +dep_tristate ' Trident 4DWave DX/NX or SiS 7018 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND dep_tristate ' Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then diff -ur --new-file old/linux/drivers/sound/Makefile new/linux/drivers/sound/Makefile --- old/linux/drivers/sound/Makefile Fri Jan 7 00:01:56 2000 +++ new/linux/drivers/sound/Makefile Sat Jan 29 04:36:23 2000 @@ -25,7 +25,7 @@ export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ msnd.o opl3.o sb_card.o sequencer_syms.o \ sound_core.o sound_syms.o uart401.o ad1816.o \ - nm256_audio.o ac97.o + nm256_audio.o ac97.o ac97_codec.o @@ -84,7 +84,7 @@ obj-$(CONFIG_SOUND_ES1371) += es1371.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o -obj-$(CONFIG_SOUND_TRIDENT) += trident.o +obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o # Declare multi-part drivers. diff -ur --new-file old/linux/drivers/sound/ac97_codec.c new/linux/drivers/sound/ac97_codec.c --- old/linux/drivers/sound/ac97_codec.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/ac97_codec.c Tue Feb 1 08:43:51 2000 @@ -0,0 +1,440 @@ +/* + * ac97_codec.c: Generic AC97 mixer module + * + * Derived from ac97 mixer in maestro and trident driver. + * + * Copyright 2000 Silicon Integrated System Corporation + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * History + * Jan 14 2000 Ollie Lho + * Isloated from trident.c to support multiple ac97 codec + */ +#include +#include +#include + +#include "ac97_codec.h" + +static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); +static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, + unsigned int left, unsigned int right); +static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ); +static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); +static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); + +static struct { + unsigned int id; + char *name; + int (*init) (struct ac97_codec *codec); +} snd_ac97_codec_ids[] = { + {0x414B4D00, "Asahi Kasei AK4540" , NULL}, + {0x41445340, "Analog Devices AD1881" , NULL}, + {0x43525900, "Cirrus Logic CS4297" , NULL}, + {0x43525913, "Cirrus Logic CS4297A" , NULL}, + {0x43525931, "Cirrus Logic CS4299" , NULL}, + {0x4e534331, "National Semiconductor LM4549", NULL}, + {0x83847600, "SigmaTel STAC????" , NULL}, + {0x83847604, "SigmaTel STAC9701/3/4/5", NULL}, + {0x83847605, "SigmaTel STAC9704" , NULL}, + {0x83847608, "SigmaTel STAC9708" , NULL}, + {0x83847609, "SigmaTel STAC9721/23" , NULL}, + {0x00000000, NULL, NULL} +}; + + +/* this table has default mixer values for all OSS mixers. */ +static struct mixer_defaults { + int mixer; + unsigned int value; +} mixer_defaults[SOUND_MIXER_NRDEVICES] = { + /* all values 0 -> 100 in bytes */ + {SOUND_MIXER_VOLUME, 0x3232}, + {SOUND_MIXER_BASS, 0x3232}, + {SOUND_MIXER_TREBLE, 0x3232}, + {SOUND_MIXER_PCM, 0x3232}, + {SOUND_MIXER_SPEAKER, 0x3232}, + {SOUND_MIXER_LINE, 0x3232}, + {SOUND_MIXER_MIC, 0x3232}, + {SOUND_MIXER_CD, 0x3232}, + {SOUND_MIXER_ALTPCM, 0x3232}, + {SOUND_MIXER_IGAIN, 0x3232}, + {SOUND_MIXER_LINE1, 0x3232}, + {SOUND_MIXER_PHONEIN, 0x3232}, + {SOUND_MIXER_PHONEOUT, 0x3232}, + {SOUND_MIXER_VIDEO, 0x3232}, + {-1,0} +}; + +/* table to scale scale from OSS mixer value to AC97 mixer register value */ +static struct ac97_mixer_hw { + unsigned char offset; + int scale; +} ac97_hw[SOUND_MIXER_NRDEVICES]= { + [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63}, + [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15}, + [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, + [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31}, + [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, + [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31}, + [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31}, + [SOUND_MIXER_CD] = {AC97_CD_VOL, 31}, + [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 63}, + [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31}, + [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31}, + [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 15}, + [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 63}, + [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31}, +}; + +/* the following tables allow us to go from OSS <-> ac97 quickly. */ +enum ac97_recsettings { + AC97_REC_MIC=0, + AC97_REC_CD, + AC97_REC_VIDEO, + AC97_REC_AUX, + AC97_REC_LINE, + AC97_REC_STEREO, /* combination of all enabled outputs.. */ + AC97_REC_MONO, /*.. or the mono equivalent */ + AC97_REC_PHONE +}; + +static unsigned int ac97_rm2oss[] = { + [AC97_REC_MIC] = SOUND_MIXER_MIC, + [AC97_REC_CD] = SOUND_MIXER_CD, + [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, + [AC97_REC_AUX] = SOUND_MIXER_LINE1, + [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN +}; + +/* indexed by bit position */ +static unsigned int ac97_oss_rm[] = { + [SOUND_MIXER_MIC] = AC97_REC_MIC, + [SOUND_MIXER_CD] = AC97_REC_CD, + [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, + [SOUND_MIXER_LINE1] = AC97_REC_AUX, + [SOUND_MIXER_LINE] = AC97_REC_LINE, + [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE +}; + +/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows + about that given mixer, and should be holding a spinlock for the card */ +static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) +{ + u16 val; + int ret = 0; + struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; + + val = codec->codec_read(codec , mh->offset); + + if (AC97_STEREO_MASK & (1 << oss_channel)) { + /* nice stereo mixers .. */ + int left,right; + + left = (val >> 8) & 0x7f; + right = val & 0x7f; + + if (oss_channel == SOUND_MIXER_IGAIN) { + right = (right * 100) / mh->scale; + left = (left * 100) / mh->scale; + } else { + right = 100 - ((right * 100) / mh->scale); + left = 100 - ((left * 100) / mh->scale); + } + + ret = left | (right << 8); + } else if (oss_channel == SOUND_MIXER_SPEAKER) { + ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_MIC) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + /* the low bit is optional in the tone sliders and masking + it lets us avoid the 0xf 'bypass'.. */ + } else if (oss_channel == SOUND_MIXER_BASS) { + ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_TREBLE) { + ret = 100 - (((val & 0xe) * 100) / mh->scale); + } + +#ifdef DEBUG + printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), " + "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret); +#endif + + return ret; +} + +/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to + make sure all is well in arg land, call with spinlock held */ +static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, + unsigned int left, unsigned int right) +{ + u16 val = 0; + struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; + +#ifdef DEBUG + printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), " + "left vol:%2d, right vol:%2d:", + oss_channel, codec->id ? "Secondary" : "Primary", + mh->offset, left, right); +#endif + + if (AC97_STEREO_MASK & (1 << oss_channel)) { + /* stereo mixers */ + if (oss_channel == SOUND_MIXER_IGAIN) { + right = (right * mh->scale) / 100; + left = (left * mh->scale) / 100; + } else { + right = ((100 - right) * mh->scale) / 100; + left = ((100 - left) * mh->scale) / 100; + } + val = (left << 8) | right; + } else if (oss_channel == SOUND_MIXER_SPEAKER) { + val = (((100 - left) * mh->scale) / 100) << 1; + } else if (oss_channel == SOUND_MIXER_MIC) { + val = codec->codec_read(codec , mh->offset) & ~0x801f; + val |= (((100 - left) * mh->scale) / 100); + /* the low bit is optional in the tone sliders and masking + it lets us avoid the 0xf 'bypass'.. */ + } else if (oss_channel == SOUND_MIXER_BASS) { + val = codec->codec_read(codec , mh->offset) & ~0x0f00; + val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; + } else if (oss_channel == SOUND_MIXER_TREBLE) { + val = codec->codec_read(codec , mh->offset) & ~0x000f; + val |= (((100 - left) * mh->scale) / 100) & 0x000e; + } + +#ifdef DEBUG + printk(" 0x%04x", val); +#endif + codec->codec_write(codec, mh->offset, val); + +#ifdef DEBUG + val = codec->codec_read(codec, mh->offset); + printk(" -> 0x%04x\n", val); +#endif +} + +/* a thin wrapper for write_mixer */ +static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) +{ + unsigned int left,right; + + /* cleanse input a little */ + right = ((val >> 8) & 0xff) ; + left = (val & 0xff) ; + + if (right > 100) right = 100; + if (left > 100) left = 100; + + codec->mixer_state[oss_mixer] = (right << 8) | left; + codec->write_mixer(codec, oss_mixer, left, right); +} + +/* read or write the recmask, the ac97 can really have left and right recording + inputs independantly set, but OSS doesn't seem to want us to express that to + the user. the caller guarantees that we have a supported bit set, and they + must be holding the card's spinlock */ +static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) +{ + unsigned int val; + + if (rw) { + /* read it from the card */ + val = codec->codec_read(codec, 0x1a) & 0x7; + return ac97_rm2oss[val]; + } + + /* else, write the first set in the mask as the + output */ + + val = ffs(mask); + val = ac97_oss_rm[val-1]; + val |= val << 8; /* set both channels */ + +#ifdef DEBUG + printk("ac97_codec: setting ac97 recmask to 0x%x\n", val); +#endif + + codec->codec_write(codec, 0x1a, val); + + return 0; +}; + +static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) +{ + int i, val = 0; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, codec->name, sizeof(info.id)); + strncpy(info.name, codec->name, sizeof(info.name)); + info.modify_counter = codec->modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, codec->name, sizeof(info.id)); + strncpy(info.name, codec->name, sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* give them the current record source */ + if (!codec->recmask_io) { + val = 0; + } else { + val = codec->recmask_io(codec, 1, 0); + } + break; + + case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ + val = codec->supported_mixers; + break; + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + val = codec->record_sources; + break; + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + val = codec->stereo_mixers; + break; + + case SOUND_MIXER_CAPS: + val = SOUND_CAP_EXCL_INPUT; + break; + + default: /* read a specific mixer */ + i = _IOC_NR(cmd); + + if (!supported_mixer(codec, i)) + return -EINVAL; + + /* do we ever want to touch the hardware? */ + /* val = codec->read_mixer(card,i); */ + val = codec->mixer_state[i]; + break; + } + return put_user(val,(int *)arg); + } + + if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { + codec->modcnt++; + get_user_ret(val, (int *)arg, -EFAULT); + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + if (!codec->recmask_io) return -EINVAL; + if (!(val &= codec->record_sources)) return -EINVAL; + + codec->recmask_io(codec, 0, val); + + return 0; + default: /* write a specific mixer */ + i = _IOC_NR(cmd); + + if (!supported_mixer(codec, i)) + return -EINVAL; + + ac97_set_mixer(codec, i, val); + + return 0; + } + } + return -EINVAL; +} + +int ac97_probe_codec(struct ac97_codec *codec) +{ + u16 id1, id2, cap; + int i; + + /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should + be read zero. Probing of AC97 in this way is not reliable, it is not even SAFE !! */ + codec->codec_write(codec, AC97_RESET, 0L); + if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000) + return 0; + + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); + id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) { + if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->name = snd_ac97_codec_ids[i].name; + codec->codec_init = snd_ac97_codec_ids[i].init; + break; + } + } + if (codec->name == NULL) + codec->name = "Unknown"; + printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n", + id1, id2, codec->name); + printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap); + + /* mixer masks */ + codec->supported_mixers = AC97_SUPPORTED_MASK; + codec->stereo_mixers = AC97_STEREO_MASK; + codec->record_sources = AC97_RECORD_MASK; + if (!(cap & 0x04)) + codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); + + /* generic OSS to AC97 wrapper */ + codec->read_mixer = ac97_read_mixer; + codec->write_mixer = ac97_write_mixer; + codec->recmask_io = ac97_recmask_io; + codec->mixer_ioctl = ac97_mixer_ioctl; + + /* initialize volume level */ + codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0L); + codec->codec_write(codec, AC97_PCMOUT_VOL, 0L); + + /* codec specific initialization for 4-6 channel output */ + if (codec->id != 0 && codec->codec_init != NULL) { + codec->codec_init(codec); + } + + /* initilize mixer channel volumes */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + struct mixer_defaults *md = &mixer_defaults[i]; + if (md->mixer == -1) + break; + if (!supported_mixer(codec, md->mixer)) + continue; + ac97_set_mixer(codec, md->mixer, md->value); + } + + return 1; +} + +static int sigmatel_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); + /* initialize SigmaTel STAC9721/23 */ + codec->codec_write(codec, 0x74, 0x01); + return 1; +} + +EXPORT_SYMBOL(ac97_probe_codec); diff -ur --new-file old/linux/drivers/sound/ac97_codec.h new/linux/drivers/sound/ac97_codec.h --- old/linux/drivers/sound/ac97_codec.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/ac97_codec.h Sat Jan 29 04:36:23 2000 @@ -0,0 +1,157 @@ +#ifndef _AC97_CODEC_H_ +#define _AC97_CODEC_H_ + +#include "sound_config.h" +#include "sound_calls.h" + +/* AC97 1.0 */ +#define AC97_RESET 0x0000 // +#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out +#define AC97_HEADPHONE_VOL 0x0004 // +#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output +#define AC97_MASTER_TONE 0x0008 // +#define AC97_PCBEEP_VOL 0x000a // none +#define AC97_PHONE_VOL 0x000c // TAD Input (mono) +#define AC97_MIC_VOL 0x000e // MIC Input (mono) +#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo) +#define AC97_CD_VOL 0x0012 // CD Input (stereo) +#define AC97_VIDEO_VOL 0x0014 // none +#define AC97_AUX_VOL 0x0016 // Aux Input (stereo) +#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo) +#define AC97_RECORD_SELECT 0x001a // +#define AC97_RECORD_GAIN 0x001c +#define AC97_RECORD_GAIN_MIC 0x001e +#define AC97_GENERAL_PURPOSE 0x0020 +#define AC97_3D_CONTROL 0x0022 +#define AC97_MODEM_RATE 0x0024 +#define AC97_POWER_CONTROL 0x0026 + +/* AC'97 2.0 */ +#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */ +#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */ +#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */ +#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */ +#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */ +#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */ +#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */ +#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */ +#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */ +#define AC97_RESERVED_3A 0x003A /* Reserved */ + +/* range 0x3c-0x58 - MODEM */ + +/* registers 0x005a - 0x007a are vendor reserved */ + +#define AC97_VENDOR_ID1 0x007c +#define AC97_VENDOR_ID2 0x007e + +/* volume control bit defines */ +#define AC97_MUTE 0x8000 +#define AC97_MICBOOST 0x0040 +#define AC97_LEFTVOL 0x3f00 +#define AC97_RIGHTVOL 0x003f + +/* record mux defines */ +#define AC97_RECMUX_MIC 0x0000 +#define AC97_RECMUX_CD 0x0101 +#define AC97_RECMUX_VIDEO 0x0202 /* not used */ +#define AC97_RECMUX_AUX 0x0303 +#define AC97_RECMUX_LINE 0x0404 +#define AC97_RECMUX_STEREO_MIX 0x0505 +#define AC97_RECMUX_MONO_MIX 0x0606 +#define AC97_RECMUX_PHONE 0x0707 + + +/* general purpose register bit defines */ +#define AC97_GP_LPBK 0x0080 /* Loopback mode */ +#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */ +#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */ +#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */ +#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */ +#define AC97_GP_LD 0x1000 /* Loudness 1=on */ +#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */ +#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */ +#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ + + +/* powerdown control and status bit defines */ + +/* status */ +#define AC97_PWR_MDM 0x0010 /* Modem section ready */ +#define AC97_PWR_REF 0x0008 /* Vref nominal */ +#define AC97_PWR_ANL 0x0004 /* Analog section ready */ +#define AC97_PWR_DAC 0x0002 /* DAC section ready */ +#define AC97_PWR_ADC 0x0001 /* ADC section ready */ + +/* control */ +#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */ +#define AC97_PWR_PR1 0x0200 /* DAC powerdown */ +#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */ +#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */ +#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */ +#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */ +#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */ +#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */ + +/* useful power states */ +#define AC97_PWR_D0 0x0000 /* everything on */ +#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4 +#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 +#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 +#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */ + +/* Total number of defined registers. */ +#define AC97_REG_CNT 64 + + +/* OSS interface to the ac97s.. */ +#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\ + SOUND_MASK_LINE|SOUND_MASK_CD|\ + SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\ + SOUND_MASK_LINE1|SOUND_MASK_VIDEO) + +#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ + SOUND_MASK_BASS|SOUND_MASK_TREBLE|\ + SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\ + SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT) + +#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ + SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ + SOUND_MASK_PHONEIN) + +#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1< - * adapt to 2.3.x new __setup/__initcall + * adapt to 2.3.x new __setup/__init call * v0.04 Dec 31 1999 Ollie Lho - * Multiple Open, useing Middle Loop Interrupt to smooth playback + * Multiple Open, using Middle Loop Interrupt to smooth playback * v0.03 Dec 24 1999 Ollie Lho * mem leak in prog_dmabuf and dealloc_dmabuf removed * v0.02 Dec 15 1999 Ollie Lho * SiS 7018 support added, playback O.K. * v0.01 Alan Cox et. al. * Initial Release in kernel 2.3.30, does not work + * + * ToDo + * Clean up of low level channel register access code. (done) + * Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done) + * Dual AC97 codecs support (done partially, need channel binding to test) + * Recording support + * Mmap support + * "Channel Binding" ioctl extension */ #include @@ -66,34 +86,40 @@ #endif #include "trident.h" -#include "ac97.h" +#include "ac97_codec.h" #undef DEBUG -#define DRIVER_VERSION "0.05" - -#define TRIDENT_FMT_STEREO 0x01 -#define TRIDENT_FMT_16BIT 0x02 -#define TRIDENT_FMT_MASK 0x03 -#define TRIDENT_DAC_SHIFT 0 -#define TRIDENT_ADC_SHIFT 4 - -#define TRIDENT_ENABLE_PE 1 -#define TRIDENT_ENABLE_RE 2 -#define DAC_RUNNING 1 -#define ADC_RUNNING 2 +#define DRIVER_VERSION "0.11" +/* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ -/* number of instances of opening /dev/dsp, can your CPU handle this ? */ -#define NR_DSPS 32 +/* The first 32 channels are called Bank A. They are (should be) reserved + for MIDI synthesizer. But since that is not supported yet, we can (ab)use + them to play PCM samples */ +#undef ABUSE_BANK_A + +/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ? + NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW + channels */ +#ifdef ABUSE_BANK_A +#define NR_HW_CH 64 +#else +#define NR_HW_CH 32 +#endif + +/* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only + have 2 SDATA_IN lines (currently) */ +#define NR_AC97 2 +/* minor number of /dev/dspW */ #define SND_DEV_DSP16 5 static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; -static const char *sample_format[] = {"8 bits Mono", "8 bits Stereo", "16 bits Mono", "16 bits Stereo"}; + static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n"; struct pci_audio_info { @@ -108,52 +134,12 @@ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"} }; -static struct { - unsigned int id; - char *name; -} snd_ac97_codec_ids[] = { - {0x414B4D00, "Asahi Kasei AK4540" }, - {0x41445340, "Analog Devices AD1881" }, - {0x43525900, "Cirrus Logic CS4297" }, - {0x43525913, "Cirrus Logic CS4297A" }, - {0x43525931, "Cirrus Logic CS4299" }, - {0x4e534331, "National Semiconductor LM4549"}, - {0x83847600, "SigmaTel STAC????" }, - {0x83847604, "SigmaTel STAC9701/3/4/5"}, - {0x83847605, "SigmaTel STAC9704" }, - {0x83847608, "SigmaTel STAC9708" }, - {0x83847609, "SigmaTel STAC9721/23" }, - {0x00000000, NULL} -}; - -typedef struct tChannelControl -{ - // register data - unsigned int * lpChStart; - unsigned int * lpChStop; - unsigned int * lpChAint; - unsigned int * lpChAinten; - - // register addresses - unsigned int * lpAChStart; - unsigned int * lpAChStop; - unsigned int * lpAChAint; - unsigned int * lpAChAinten; - - unsigned int data[16]; - -} CHANNELCONTROL; - /* "software" or virtual channel, an instance of opened /dev/dsp */ struct trident_state { unsigned int magic; struct trident_card *card; /* Card info */ - /* wave stuff */ - unsigned int rateadc, ratedac; - unsigned char fmt, enable; - - /* single opne lock mechanism, should be removed */ + /* single open lock mechanism, only used for recording */ struct semaphore open_sem; wait_queue_head_t open_wait; @@ -164,26 +150,33 @@ int virt; struct dmabuf { + /* wave sample stuff */ + unsigned int rate; + unsigned char fmt, enable; + + /* hardware channel */ + struct trident_channel *channel; + + /* OSS buffer manangemeent stuff */ void *rawbuf; unsigned buforder; unsigned numfrag; unsigned fragshift; - /* hardware channel number */ - int chan; + /* our buffer acts like a circular ring */ + unsigned hwptr; /* where dma last started, update by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be comsumed by dma machine */ + unsigned total_bytes; /* total bytes dmaed by hardware */ - /* XXX zab - swptr only in here so that it can be referenced by - clear_advance, as far as I can tell :( */ - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; + unsigned error; /* number of over/underruns */ + wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; unsigned fragsamples; + /* OSS stuff */ unsigned mapped:1; unsigned ready:1; @@ -192,44 +185,45 @@ int ossmaxfrags; unsigned subdivision; } dma_dac, dma_adc; - - u8 bDMAStart; - }; /* hardware channels */ struct trident_channel { - int chan; /* channel number */ - u32 lba; - u32 eso; + int num; /* channel number */ + u32 lba; /* reg 0xe4 */ + u32 eso; /* reg 0xe8 */ u32 delta; - u16 attribute; - + u16 attribute; /* reg 0xec */ + u16 fm_vol; + u32 control; /* reg 0xf0 */ }; -struct trident_pcm_bank { - /* registers to control bank operations */ +struct trident_pcm_bank_address { u32 start; u32 stop; u32 aint; u32 aint_en; +}; +static struct trident_pcm_bank_address bank_a_addrs = +{ + T4D_START_A, + T4D_STOP_A, + T4D_AINT_A, + T4D_AINTEN_A +}; +static struct trident_pcm_bank_address bank_b_addrs = +{ + T4D_START_B, + T4D_STOP_B, + T4D_AINT_B, + T4D_AINTEN_B +}; +struct trident_pcm_bank { + /* register addresses to control bank operations */ + struct trident_pcm_bank_address *addresses; /* each bank has 32 channels */ u32 bitmap; /* channel allocation bitmap */ - //struct trident_channel channels[32]; -}; - -struct trident_mixer { - int modcnt; - int supported_mixers; - int stereo_mixers; - int record_sources; - - /* the caller must guarantee arg sanity before calling these */ - /* int (*read_mixer)(struct trident_card *card, int index);*/ - void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left, - unsigned int right); - int (*recmask_io)(struct trident_card *card,int rw,int mask); - unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; + struct trident_channel channels[32]; }; struct trident_card { @@ -239,7 +233,7 @@ struct trident_card *next; /* The trident has a certain amount of cross channel interaction - so we use a single per card lock */ + so we use a single per card lock */ spinlock_t lock; /* PCI device stuff */ @@ -249,286 +243,225 @@ /* soundcore stuff */ int dev_audio; - int dev_mixer; - struct trident_mixer mix; - struct trident_state *channels[NR_DSPS]; + /* structures for abstraction of hardware facilities, codecs, banks and channels*/ + struct ac97_codec *ac97_codec[NR_AC97]; + struct trident_pcm_bank banks[NR_BANKS]; + struct trident_state *states[NR_HW_CH]; /* hardware resources */ unsigned long iobase; u32 irq; - - /* hardware channel allocation bitmap */ - u32 bitmap[2]; - - /* ugly stupid thing, remove ASAP */ - CHANNELCONTROL ChRegs; - int ChanDwordCount; }; static struct trident_card *devs = NULL; -/* - * Trident support library routines - */ - -/*--------------------------------------------------------------------------- - void ResetAinten( struct trident_state *trident, int ChannelNum) - - Description: This routine will disable interrupts and ack any - existing interrupts for specified channel. - - Parameters: trident - pointer to target device class for 4DWave. - ChannelNum - channel number - - returns: TRUE if everything went ok, else FALSE. - - ---------------------------------------------------------------------------*/ - -static void ResetAinten(struct trident_card * trident, int ChannelNum) -{ - unsigned int dwMask; - unsigned int x = ChannelNum >> 5; - unsigned int ChanDwordCount = trident->ChanDwordCount; - - IReadAinten(&trident->ChRegs); - dwMask = 1 << (ChannelNum & 0x1f); - trident->ChRegs.lpChAinten[x] &= ~dwMask; - IWriteAinten(&trident->ChRegs); - // Ack the channel in case the interrupt was set before we disable it. - outl(dwMask, TRID_REG(trident, trident->ChRegs.lpAChAint[x])); -} - -/*--------------------------------------------------------------------------- - void EnableEndInterrupts( struct trident_card *trident) - - Description: This routine will enable end of loop interrupts. - End of loop interrupts will occur when a running - channel reaches ESO. - - Parameters: trident - pointer to target device class for 4DWave. - - returns: TRUE if everything went ok, else FALSE. - - ---------------------------------------------------------------------------*/ +static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); +static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg); -static int trident_enable_end_interrupts(struct trident_card * trident) +static int trident_open_mixdev(struct inode *inode, struct file *file); +static int trident_release_mixdev(struct inode *inode, struct file *file); +static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +static loff_t trident_llseek(struct file *file, loff_t offset, int origin); + +static int trident_enable_loop_interrupts(struct trident_card * card) { u32 global_control; - global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR)); + global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR)); - switch (trident->pci_id) + switch (card->pci_id) { case PCI_DEVICE_ID_SI_7018: - global_control |= (ENDLP_IE | BANK_B_EN); + global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - global_control |= ENDLP_IE; + global_control |= (ENDLP_IE | MIDLP_IE); break; default: return FALSE; } - outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR)); + outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR)); #ifdef DEBUG - printk("trident: Enable End Interrupts, globctl = 0x%08X\n", global_control); + printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n", + global_control); #endif return (TRUE); } -static int trident_enable_middle_interrupts(struct trident_card * trident) +static int trident_disable_loop_interrupts(struct trident_card * card) { u32 global_control; - global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR)); - - switch (trident->pci_id) - { - case PCI_DEVICE_ID_SI_7018: - global_control |= (MIDLP_IE | BANK_B_EN); - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - default: - global_control |= MIDLP_IE; - break; - } - - outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR)); + global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR)); + global_control &= ~(ENDLP_IE | MIDLP_IE); + outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR)); #ifdef DEBUG - printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", global_control); + printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n", + global_control); #endif return (TRUE); } -/*--------------------------------------------------------------------------- - void DisableEndInterrupts( struct trident_card *trident) - - Description: This routine will disable end of loop interrupts. - End of loop interrupts will occur when a running - channel reaches ESO. - - Parameters: - trident - pointer to target device class for 4DWave. - - returns: TRUE if everything went ok, else FALSE. - - ---------------------------------------------------------------------------*/ -static int trident_disable_end_interrupts(struct trident_card * trident) +static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel) { - u32 global_control; + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 reg, addr = bank->addresses->aint_en; - global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR)); - global_control &= ~ENDLP_IE; - outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR)); + reg = inl(TRID_REG(card, addr)); + reg |= mask; + outl(reg, TRID_REG(card, addr)); #ifdef DEBUG - printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", global_control); + reg = inl(TRID_REG(card, T4D_AINTEN_B)); + printk("trident: enabled IRQ on channel %d, AINTEN_B = 0x%08x\n", + channel, reg); #endif - return (TRUE); } -static int trident_disable_middle_interrupts(struct trident_card * trident) +static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel) { - u32 global_control; - - global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR)); - global_control &= ~MIDLP_IE; - outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR)); + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 reg, addr = bank->addresses->aint_en; + + reg = inl(TRID_REG(card, addr)); + reg &= ~mask; + outl(reg, TRID_REG(card, addr)); + + /* Ack the channel in case the interrupt was set before we disable it. */ + outl(mask, TRID_REG(card, bank->addresses->aint)); #ifdef DEBUG - printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", global_control); + reg = inl(TRID_REG(card, T4D_AINTEN_B)); + printk("trident: disabled IRQ on channel %d, AINTEN_B = 0x%08x\n", + channel, reg); #endif - return (TRUE); } -/*--------------------------------------------------------------------------- - void trident_enable_voice_irq( unsigned int HwChannel ) - - Description: Enable an interrupt channel, any channel 0 thru n. - This routine automatically handles the fact that there are - more than 32 channels available. - - Parameters : HwChannel - Channel number 0 thru n. - trident - pointer to target device class for 4DWave. - - Return Value: None. - - ---------------------------------------------------------------------------*/ -void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel) -{ - unsigned int bank, mask, ChanDwordCount; - u32 reg; - bank = channel >> 5; - mask = 1 << (channel & 0x1f); +static void trident_start_voice(struct trident_card * card, unsigned int channel) +{ + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 addr = bank->addresses->start; - ChanDwordCount = trident->ChanDwordCount; +#ifdef DEBUG + u32 reg; +#endif - IReadAinten(&trident->ChRegs); - trident->ChRegs.lpChAinten[bank] |= mask; - IWriteAinten(&trident->ChRegs); + outl(mask, TRID_REG(card, addr)); #ifdef DEBUG - reg = inl(TRID_REG(trident, T4D_AINTEN_B)); - printk("trident: enabled IRQ on channel %d\n", channel); + reg = inl(TRID_REG(card, T4D_START_B)); + printk("trident: start voice on channel %d, START_B = 0x%08x\n", + channel, reg); #endif } -/*--------------------------------------------------------------------------- - void trident_disable_voice_irq( unsigned int HwChannel ) - - Description: Disable an interrupt channel, any channel 0 thru n. - This routine automatically handles the fact that there are - more than 32 channels available. - - Parameters : HwChannel - Channel number 0 thru n. - trident - pointer to target device class for 4DWave. - - Return Value: None. - - ---------------------------------------------------------------------------*/ -void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel) +static void trident_stop_voice(struct trident_card * card, unsigned int channel) { - unsigned int bank, mask, ChanDwordCount; + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 addr = bank->addresses->stop; + +#ifdef DEBUG u32 reg; +#endif - bank = channel >> 5; - mask = 1 << (channel & 0x1f); + outl(mask, TRID_REG(card, addr)); + +#ifdef DEBUG + reg = inl(TRID_REG(card, T4D_STOP_B)); + printk("trident: stop voice on channel %d, STOP_B = 0x%08x\n", + channel, reg); +#endif +} + +static int trident_check_channel_interrupt(struct trident_card * card, int channel) +{ + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 reg, addr = bank->addresses->aint; - ChanDwordCount = trident->ChanDwordCount; - IReadAinten(&trident->ChRegs); - trident->ChRegs.lpChAinten[bank] &= ~mask; - IWriteAinten(&trident->ChRegs); + reg = inl(TRID_REG(card, addr)); #ifdef DEBUG - reg = inl(TRID_REG(trident, T4D_AINTEN_B)); - printk("trident: disabled IRQ on channel %d\n", channel); + if (reg & mask) + printk("trident: channel %d has interrupt, AINT_B = 0x%08x\n", + channel, reg); #endif + return (reg & mask) ? TRUE : FALSE; } -/*--------------------------------------------------------------------------- - unsigned int AllocateChannelPCM( void ) - - Description: Allocate hardware channel by reverse order (63-0). - - Parameters : trident - pointer to target device class for 4DWave. - - Return Value: hardware channel - 0-63 or -1 when no channel is available - - ---------------------------------------------------------------------------*/ +static void trident_ack_channel_interrupt(struct trident_card * card, int channel) +{ + unsigned int mask = 1 << (channel & 0x1f); + struct trident_pcm_bank *bank = &card->banks[channel >> 5]; + u32 reg, addr = bank->addresses->aint; + + reg = inl(TRID_REG(card, addr)); + reg &= mask; + outl(reg, TRID_REG(card, addr)); + +#ifdef DEBUG + reg = inl(TRID_REG(card, T4D_AINT_B)); + printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n", + channel, reg); +#endif +} -static int trident_alloc_pcm_channel(struct trident_card *trident) +static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card) { + struct trident_pcm_bank *bank; int idx; - if (trident->bitmap[BANK_B] == ~0UL) { + bank = &card->banks[BANK_B]; + if (bank->bitmap == ~0UL) { /* no more free channels avaliable */ printk(KERN_ERR "trident: no more channels available on Bank B.\n"); - return -1; +#ifdef ABUSE_BANK_A + goto bank_a; +#endif + return NULL; } for (idx = 31; idx >= 0; idx--) { - if (!(trident->bitmap[BANK_B] & (1 << idx))) { - trident->bitmap[BANK_B] |= 1 << idx; - return idx + 32; + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx + 32; + return channel; } } #ifdef ABUSE_BANK_A /* channels in Bank A should be reserved for synthesizer not for normal use (channels in Bank A can't record) */ - if (trident->bitmap[BANK_A] == ~0UL) { + bank_a: + bank = &card->banks[BANK_A]; + if (bank->bitmap == ~0UL) { /* no more free channels avaliable */ - printk(KERN_ERR "trident: no channels available on Bank A.\n"); - return -1; + printk(KERN_ERR "trident: no more channels available on Bank A.\n"); + return NULL; } for (idx = 31; idx >= 0; idx--) { - if (!(trident->bitmap[BANK_A] & (1 << idx))) { - trident->bitmap[BANK_A] |= 1 << idx; - return idx; + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + banks->bitmap |= 1 << idx; + channel->num = idx; + return channels; } } #endif - - return -1; + return NULL; } -/*--------------------------------------------------------------------------- - void FreeChannelPCM( int channel ) - - Description: Free hardware channel. - - Parameters : trident - pointer to target device class for 4DWave. - channel - hardware channel number 0-63 - - Return Value: none - - ---------------------------------------------------------------------------*/ - -static void trident_free_pcm_channel(struct trident_card *trident, int channel) +static void trident_free_pcm_channel(struct trident_card *card, int channel) { int bank; @@ -543,236 +476,74 @@ bank = channel >> 5; channel = channel & 0x1f; - if (trident->bitmap[bank] & (1 << (channel))) { - trident->bitmap[bank] &= ~(1 << (channel)); + if (card->banks[bank].bitmap & (1 << (channel))) { + card->banks[bank].bitmap &= ~(1 << (channel)); } } -/*--------------------------------------------------------------------------- - void trident_start_voice( ULONG HwChannel ) - - Description: Start a channel, any channel 0 thru n. - This routine automatically handles the fact that there are - more than 32 channels available. - - Parameters : HwChannel - Channel number 0 thru n. - trident - pointer to target device class for 4DWave. - - Return Value: None. - - ---------------------------------------------------------------------------*/ -void trident_start_voice(struct trident_card * trident, unsigned int channel) +/* called with spin lock held */ +static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel) { - unsigned int bank = channel >> 5; - unsigned int mask = 1 << (channel & 0x1f); + int i; - outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank])); -#ifdef DEBUG - printk("trident: start voice on channel %d\n", channel); -#endif -} + if (channel > 63) + return FALSE; -/*--------------------------------------------------------------------------- - void trident_stop_voice( ULONG HwChannel ) - - Description: Stop a channel, any channel 0 thru n. - This routine automatically handles the fact that there are - more than 32 channels available. - - Parameters : HwChannel - Channel number 0 thru n. - trident - pointer to target device class for 4DWave. - - Return Value: None. - - ---------------------------------------------------------------------------*/ -void trident_stop_voice(struct trident_card * trident, unsigned int channel) -{ - unsigned int bank = channel >> 5; - unsigned int mask = 1 << (channel & 0x1f); + /* select hardware channel to write */ + outb(channel, TRID_REG(card, T4D_LFO_GC_CIR)); + /* output the channel registers */ + for (i = 0; i < CHANNEL_REGS; i++) { + outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); + } - outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank])); -#ifdef DEBUG - printk("trident: stop voice on channel %d\n", channel); -#endif + return TRUE; } -/*--------------------------------------------------------------------------- - int DidChannelInterrupt( ) - - Description: Check if interrupt channel occurred. - - Parameters : trident - pointer to target device class for 4DWave. - - Return Value: TRUE if interrupt occurred, else FALSE. - - ---------------------------------------------------------------------------*/ -static int trident_check_channel_interrupt(struct trident_card * trident, int channel) +/* called with spin lock held */ +static int trident_write_voice_regs(struct trident_state *state, unsigned int rec) { - unsigned int ChanDwordCount = NUM_BANKS; - unsigned int bank = channel >> 5; - unsigned int mask = 1 << (channel & 0x1f); - - ReadAint(&trident->ChRegs); - -#ifdef DEBUG - if (trident->ChRegs.lpChAint[bank] & mask) - printk("trident: channel %d has interrupt\n", channel); -#endif - return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE; -} + unsigned int data[CHANNEL_REGS + 1]; + struct trident_channel *channel; -/*--------------------------------------------------------------------------- - void AckChannelInterrupt( ) - - Description: Acknowledge the interrupt bit for channel intrs. - - Parameters : trident - pointer to target device class for 4DWave. - - Return Value: None - - ---------------------------------------------------------------------------*/ -static void trident_ack_channel_interrupt(struct trident_card * trident, int channel) -{ - unsigned int ChanDwordCount = NUM_BANKS; - unsigned int bank = channel >> 5; - unsigned int mask = 1 << (channel & 0x1f); + if (rec) + channel = state->dma_adc.channel; + else + channel = state->dma_dac.channel; - ReadAint(&trident->ChRegs); - trident->ChRegs.lpChAint[bank] &= mask; - IWriteAint(&trident->ChRegs); -} - -/*--------------------------------------------------------------------------- - int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta ) - - Description: This routine writes Delta to the hardware. - - Parameters: Delta - data to write (2 Bytes only) - HwChannel - Hardware channel to write to. - trident - pointer to target device class for 4DWave. - - Returns: TRUE if all goes well, else FALSE. - - ---------------------------------------------------------------------------*/ -static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel, - unsigned short delta) -{ - /* select a channel for output */ - outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR)); + data[1] = channel->lba; + data[4] = channel->control; - switch (trident->pci_id) + switch (state->card->pci_id) { case PCI_DEVICE_ID_SI_7018: + data[0] = 0; /* Current Sample Offset */ + data[2] = (channel->eso << 16) | (channel->delta & 0xffff); + data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff); + break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA)); + data[0] = 0; /* Current Sample Offset */ + data[2] = (channel->eso << 16) | (channel->delta & 0xffff); + data[3] = channel->fm_vol & 0xffff; break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - outb(delta & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3)); - outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3)); + data[0] = (channel->delta << 24); + data[2] = ((channel->delta << 24) & 0xff000000) | (channel->eso & 0x00ffffff); + data[3] = channel->fm_vol & 0xffff; break; default: return FALSE; } - return TRUE; -} -/*--------------------------------------------------------------------------- - int LoadVirtualChannel( ULONG *Data, ULONG HwChannel) - - Description: This routine writes all required channel registers to hardware. - - Parameters: *Data - a pointer to the data to write (5 ULONGS always). - HwChannel - Hardware channel to write to. - trident - pointer to target device class for 4DWave. - - Returns: TRUE if all goes well, else FALSE. - - ---------------------------------------------------------------------------*/ -static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel) -{ - unsigned int ChanData[CHANNEL_REGS]; - unsigned int ULONGSToDo = CHANNEL_REGS; - unsigned int i; - unsigned int Address = CHANNEL_START; - - /* Copy the data first... Hack... Before mucking with Volume! */ - memcpy((unsigned char *) ChanData, (unsigned char *) Data, ULONGSToDo * 4); - - outb((unsigned char) HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR)); - - for (i = 0; i < ULONGSToDo; i++, Address += 4) - outl(ChanData[i], TRID_REG(trident, Address)); -#ifdef DEBUG - printk("(trident) load virtual channel %d\n", HwChannel); -#endif - return TRUE; -} - -/*--------------------------------------------------------------------------- - trident_write_voice_regs - - Description: This routine will write the 5 hardware channel registers - to hardware. - - Paramters: trident - pointer to target device class for 4DWave. - Channel - Real or Virtual channel number. - Each register field. - - Returns: TRUE if all goes well, else FALSE. - - ---------------------------------------------------------------------------*/ -int trident_write_voice_regs(struct trident_card * trident, - unsigned int Channel, - unsigned int LBA, - unsigned int CSO, - unsigned int ESO, - unsigned int DELTA, - unsigned int ALPHA_FMS, - unsigned int FMC_RVOL_CVOL, - unsigned int GVSEL, - unsigned int PAN, - unsigned int VOL, - unsigned int CTRL, - unsigned int EC) -{ - unsigned int ChanData[CHANNEL_REGS + 1], FmcRvolCvol; - - ChanData[1] = LBA; - ChanData[4] = (GVSEL << 31) | - ((PAN & 0x0000007f) << 24) | - ((VOL & 0x000000ff) << 16) | - ((CTRL & 0x0000000f) << 12) | - (EC & 0x00000fff); - - FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff; - - switch (trident->pci_id) - { - case PCI_DEVICE_ID_SI_7018: - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff); - ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff); - ChanData[3] = FmcRvolCvol; - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff); - ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff); - ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol; - break; - } - - LoadVirtualChannel(trident, ChanData, Channel); - - return TRUE; + return trident_load_channel_registers(state->card, data, channel->num); } static int compute_rate(u32 rate) { int delta; - // We special case 44100 and 8000 since rounding with the equation - // does not give us an accurate enough value. For 11025 and 22050 - // the equation gives us the best answer. All other frequencies will - // also use the equation. JDW + /* We special case 44100 and 8000 since rounding with the equation + does not give us an accurate enough value. For 11025 and 22050 + the equation gives us the best answer. All other frequencies will + also use the equation. JDW */ if (rate == 44100) delta = 0xeb3; else if (rate == 8000) @@ -784,838 +555,267 @@ return delta; } -/*--------------------------------------------------------------------------- - trident_set_dac_rate - - Description: This routine will set the sample rate for playback. - - Paramters: trident - pointer to target device class for 4DWave. - rate - desired sample rate - set - actually write hardware if set is true. - - Returns: The rate allowed by device. - - ---------------------------------------------------------------------------*/ - -static unsigned int trident_set_dac_rate(struct trident_state * trident, - unsigned int rate, int set) -{ - u16 delta; +/* set playback sample rate */ +static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dma_dac; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; - delta = compute_rate(rate); - trident->ratedac = rate; + dmabuf->rate = rate; + dmabuf->channel->delta = compute_rate(rate); + + trident_write_voice_regs(state, 0); - if (set) - trident_load_hw_delta(trident->card, trident->dma_dac.chan, - delta); -#ifdef DEBUG - printk("trident: called trident_set_dac_rate : rate = %d, " - "set = %d, delta = 0x%04x\n", rate, set, delta); +#ifdef DEBUG + printk("trident: called trident_set_dac_rate : rate = %d\n", rate); #endif return rate; } -/*--------------------------------------------------------------------------- - trident_set_adc_rate - - Description: This routine will set the sample rate for capture. - - Paramters: trident - pointer to target device class for 4DWave. - rate - desired sample rate - set - actually write hardware if set is true. - - Returns: The rate allowed by device. - - ---------------------------------------------------------------------------*/ - -static unsigned int trident_set_adc_rate(struct trident_state * trident, - unsigned int rate, int set) +/* set recording sample rate */ +static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate) { - u16 delta; - + struct dmabuf *dmabuf = &state->dma_adc; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; - delta = compute_rate(rate); - trident->ratedac = rate; + dmabuf->rate = rate; + dmabuf->channel->delta = compute_rate(rate); -#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */ - if (set) - trident_load_hw_delta(trident->card, trident->dma_adc.chan, - delta); -#endif -#ifdef DEBUG - printk("trident: called trident_set_adc_rate : rate = %d, " - "set = %d, delta = 0x%04x\n", rate, set, delta); + trident_write_voice_regs(state, 1); + +#ifdef DEBUG + printk("trident: called trident_set_adc_rate : rate = %d\n", rate); #endif return rate; } - -extern __inline__ unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* Write AC97 mixer registers */ -static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val) -{ - unsigned int address, mask, busy; - unsigned short count = 0xffff; - u32 data; - - data = ((u32) val) << 16; - - switch (trident->pci_id) - { - default: - case PCI_DEVICE_ID_SI_7018: - address = SI_AC97_WRITE; - mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY; - busy = SI_AC97_BUSY_WRITE; - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - address = DX_ACR0_AC97_W; - mask = busy = DX_AC97_BUSY_WRITE; - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - address = NX_ACR1_AC97_W; - mask = busy = NX_AC97_BUSY_WRITE; - break; - } - - do { - if ((inw(TRID_REG(trident, address)) & busy) == 0) - break; - } while (count--); - - data |= (mask | (cmd & AC97_REG_ADDR)); - - if (count == 0) { - printk(KERN_ERR "trident: AC97 CODEC write timed out.\n"); - return; - } - outl(data, TRID_REG(trident, address)); -} -/* Read AC97 codec registers */ -static u16 trident_ac97_get(struct trident_card *trident, u8 cmd) +/* prepare channel attributes for playback */ +static void trident_play_setup(struct trident_state *state) { - unsigned int address, mask, busy; - unsigned short count = 0xffff; - u32 data; + struct dmabuf *dmabuf = &state->dma_dac; + struct trident_channel *channel = dmabuf->channel; - switch (trident->pci_id) - { - default: - case PCI_DEVICE_ID_SI_7018: - address = SI_AC97_READ; - mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY; - busy = SI_AC97_BUSY_READ; - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - address = DX_ACR1_AC97_R; - mask = busy = DX_AC97_BUSY_READ; - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - address = NX_ACR2_AC97_R_PRIMARY; - mask = NX_AC97_BUSY_READ; - busy = 0x0c00; - break; - } - - data = (mask | (cmd & AC97_REG_ADDR)); - outl(data, TRID_REG(trident, address)); - - do { - data = inl(TRID_REG(trident, address)); - if ((data & busy) == 0) - break; - } while (count--); + channel->lba = virt_to_bus(dmabuf->rawbuf); + channel->delta = compute_rate(dmabuf->rate); - if (count == 0) { - printk(KERN_ERR "trident: AC97 CODEC read timed out.\n"); - data = 0; + channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; + channel->eso -= 1; + + if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { + /* FIXME: channel attributes are configured by ioctls, but it is not implemented + so just set to ZERO for the moment */ + channel->attribute = 0; + } else { + channel->attribute = 0; } - return ((u16) (data >> 16)); -} - -/* OSS interface to the ac97s.. */ -#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\ - SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN) - -#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ - SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\ - SOUND_MASK_SPEAKER) - -#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ - SOUND_MASK_PHONEIN) - -#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1< 100 in bytes */ - {SOUND_MIXER_VOLUME, 0x3232}, - {SOUND_MIXER_BASS, 0x3232}, - {SOUND_MIXER_TREBLE, 0x3232}, - {SOUND_MIXER_SPEAKER, 0x3232}, - {SOUND_MIXER_MIC, 0x3232}, - {SOUND_MIXER_LINE, 0x3232}, - {SOUND_MIXER_CD, 0x3232}, - {SOUND_MIXER_VIDEO, 0x3232}, - {SOUND_MIXER_LINE1, 0x3232}, - {SOUND_MIXER_PCM, 0x3232}, - {SOUND_MIXER_IGAIN, 0x3232}, - {-1,0} -}; + channel->fm_vol = 0x0; -static struct ac97_mixer_hw { - unsigned char offset; - int scale; -} ac97_hw[SOUND_MIXER_NRDEVICES]= { - [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63}, - [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, - [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31}, - [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31}, - [SOUND_MIXER_CD] = {AC97_CD_VOL, 31}, - [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31}, - [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31}, - [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31}, - [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31} -}; - -#if 0 /* *shrug* removed simply because we never used it. - feel free to implement again if needed */ - -/* reads the given OSS mixer from the ac97 - the caller must have insured that the ac97 knows - about that given mixer, and should be holding a - spinlock for the card */ -static int ac97_read_mixer(struct trident_card *card, int mixer) -{ - u16 val; - int ret = 0; - struct ac97_mixer_hw *mh = &ac97_hw[mixer]; - - val = trident_ac97_get(card , mh->offset); - - if (AC97_STEREO_MASK & (1<> 8) & 0x7f; - right = val & 0x7f; - - if (mixer == SOUND_MIXER_IGAIN) { - right = (right * 100) / mh->scale; - left = (left * 100) / mh->scale; - else { - right = 100 - ((right * 100) / mh->scale); - left = 100 - ((left * 100) / mh->scale); - } - - ret = left | (right << 8); - } else if (mixer == SOUND_MIXER_SPEAKER) { - ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_TREBLE) { - ret = 100 - (((val & 0xe) * 100) / mh->scale); - } - -#ifdef DEBUG - printk("trident: read OSS mixer %2d (ac97 register 0x%02x), " - "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret); -#endif - - return ret; -} -#endif - -/* write the OSS encoded volume to the given OSS encoded mixer, - again caller's job to make sure all is well in arg land, - call with spinlock held */ -static void ac97_write_mixer(struct trident_card *card, int mixer, - unsigned int left, unsigned int right) -{ - u16 val = 0; - struct ac97_mixer_hw *mh = &ac97_hw[mixer]; - -#ifdef DEBUG - printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), " - "left vol:%2d, right vol:%2d:", - mixer, mh->offset, left, right); -#endif - - if (AC97_STEREO_MASK & (1 << mixer)) { - /* stereo mixers */ - if (mixer == SOUND_MIXER_IGAIN) { - right = (right * mh->scale) / 100; - left = (left * mh->scale) / 100; - } else { - right = ((100 - right) * mh->scale) / 100; - left = ((100 - left) * mh->scale) / 100; - } - - val = (left << 8) | right; - } else if (mixer == SOUND_MIXER_SPEAKER) { - val = (((100 - left) * mh->scale) / 100) << 1; - } else if (mixer == SOUND_MIXER_MIC) { - val = trident_ac97_get(card , mh->offset) & ~0x801f; - val |= (((100 - left) * mh->scale) / 100); - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - val = trident_ac97_get(card , mh->offset) & ~0x0f00; - val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (mixer == SOUND_MIXER_TREBLE) { - val = trident_ac97_get(card , mh->offset) & ~0x000f; - val |= (((100 - left) * mh->scale) / 100) & 0x000e; + channel->control = CHANNEL_LOOP; + if (dmabuf->fmt & TRIDENT_FMT_16BIT) { + /* 16-bits */ + channel->control |= CHANNEL_16BITS; + /* signed */ + channel->control |= CHANNEL_SIGNED; } - -#ifdef DEBUG - printk(" 0x%04x", val); -#endif - trident_ac97_set(card, mh->offset, val); - + if (dmabuf->fmt & TRIDENT_FMT_STEREO) + /* stereo */ + channel->control |= CHANNEL_STEREO; #ifdef DEBUG - val = trident_ac97_get(card, mh->offset); - printk(" -> 0x%04x\n", val); + printk("trident: trident_play_setup, LBA = 0x%08x, " + "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", + channel->lba, channel->delta, channel->eso, channel->control); #endif + trident_write_voice_regs(state, 0); } -/* the following tables allow us to go from - OSS <-> ac97 quickly. */ - -enum ac97_recsettings { - AC97_REC_MIC=0, - AC97_REC_CD, - AC97_REC_VIDEO, - AC97_REC_AUX, - AC97_REC_LINE, - AC97_REC_STEREO, /* combination of all enabled outputs.. */ - AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE -}; - -static unsigned int ac97_rm2oss[] = { - [AC97_REC_MIC] = SOUND_MIXER_MIC, - [AC97_REC_CD] = SOUND_MIXER_CD, - [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, - [AC97_REC_AUX] = SOUND_MIXER_LINE1, - [AC97_REC_LINE] = SOUND_MIXER_LINE, - [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN -}; - -/* indexed by bit position */ -static unsigned int ac97_oss_rm[] = { - [SOUND_MIXER_MIC] = AC97_REC_MIC, - [SOUND_MIXER_CD] = AC97_REC_CD, - [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, - [SOUND_MIXER_LINE1] = AC97_REC_AUX, - [SOUND_MIXER_LINE] = AC97_REC_LINE, - [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE -}; - -/* read or write the recmask - the ac97 can really have left and right recording - inputs independantly set, but OSS doesn't seem to - want us to express that to the user. - the caller guarantees that we have a supported bit set, - and they must be holding the card's spinlock */ -static int ac97_recmask_io(struct trident_card *card, int rw, int mask) -{ - unsigned int val; - - if (rw) { - /* read it from the card */ - val = trident_ac97_get(card, 0x1a) & 0x7; - return ac97_rm2oss[val]; - } - - /* else, write the first set in the mask as the - output */ - - val = ffs(mask); - val = ac97_oss_rm[val-1]; - val |= val << 8; /* set both channels */ -#ifdef DEBUG - printk("trident: setting ac97 recmask to 0x%x\n", val); -#endif - trident_ac97_set(card, 0x1a, val); - - return 0; -}; - -/* AC97 codec initialisation. */ -static u16 trident_ac97_init(struct trident_card *trident) +/* prepare channel attributes for recording */ +static void trident_rec_setup(struct trident_state *state) { - u16 id1, id2; - char *ac97_name = NULL; - int i; + u16 w; + struct trident_card *card = state->card; + struct dmabuf *dmabuf = &state->dma_adc; + struct trident_channel *channel = dmabuf->channel; - /* initialize controller side of AC link */ - switch (trident->pci_id) + /* Enable AC-97 ADC (capture) */ + switch (card->pci_id) { case PCI_DEVICE_ID_SI_7018: - /* disable AC97 GPIO interrupt */ - outl(0x00, TRID_REG(trident, SI_AC97_GPIO)); - /* stop AC97 cold reset process */ - outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); + /* for 7018, the ac97 is always in playback/record (duplex) mode */ break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - /* playback on */ - outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT)); + w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT)); + outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT)); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */ - outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); + w = inw(TRID_REG(card, T4D_MISCINT)); + outw(w | 0x1000, TRID_REG(card, T4D_MISCINT)); break; + default: + return; } - /* get some information about our AC97 codec */ - id1 = trident_ac97_get(trident, AC97_VENDOR_ID1); - id2 = trident_ac97_get(trident, AC97_VENDOR_ID2); - for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) { - if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) { - ac97_name = snd_ac97_codec_ids[i].name; - break; - } - } - if (ac97_name == NULL) - ac97_name = "Unknown"; - printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n", - id1, id2, ac97_name); - - /* initialize volume level */ - trident_ac97_set(trident, AC97_RESET, 0L); - trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L); - trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L); - - /* set appropriate masks and function pointers */ - trident->mix.supported_mixers = AC97_SUPPORTED_MASK; - trident->mix.stereo_mixers = AC97_STEREO_MASK; - trident->mix.record_sources = AC97_RECORD_MASK; - /* FIXME: trident->mix.read_mixer = ac97_read_mixer; */ - trident->mix.write_mixer = ac97_write_mixer; - trident->mix.recmask_io = ac97_recmask_io; + channel->lba = virt_to_bus(dmabuf->rawbuf); + channel->delta = compute_rate(dmabuf->rate); - return 0; -} + channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; + channel->eso -= 1; -/* this function only update fmt field in trident_state, the hardware channel attribute - will be update in trident_play(rec)_setup() which will be called every time a new - sample is played(recorded) */ -static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data) -{ - s->fmt = (s->fmt & mask) | data; -} - -/* the mode passed should be already shifted and masked */ -/* trident_play_setup: initialize channel for play back, mode specify the format of samples to - be played. - default values: -*/ + if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { + /* FIXME: channel attributes are configured by ioctls, but it is not implemented + so just set to ZERO for the moment */ + channel->attribute = 0; + } else { + channel->attribute = 0; + } -static void trident_play_setup(struct trident_state *trident, int mode, u32 rate, - void *buffer, int size) -{ - unsigned int LBA; - unsigned int Delta; - unsigned int ESO; - unsigned int CTRL; - unsigned int FMC_RVOL_CVOL; - unsigned int GVSEL; - unsigned int PAN; - unsigned int VOL; - unsigned int EC; - - /* set Loop Begin Address */ - LBA = virt_to_bus(buffer); - Delta = compute_rate(rate); - - /* set ESO */ - ESO = size; - if (mode & TRIDENT_FMT_16BIT) - ESO /= 2; - if (mode & TRIDENT_FMT_STEREO) - ESO /= 2; - ESO = ESO - 1; - - /* loop mode enable */ - CTRL = 0x00000001; - if (mode & TRIDENT_FMT_16BIT) { + channel->fm_vol = 0x0; + + channel->control = CHANNEL_LOOP; + if (dmabuf->fmt & TRIDENT_FMT_16BIT) { /* 16-bits */ - CTRL |= 0x00000008; + channel->control |= CHANNEL_16BITS; /* signed */ - CTRL |= 0x00000002; + channel->control |= CHANNEL_SIGNED; } - if (mode & TRIDENT_FMT_STEREO) + if (dmabuf->fmt & TRIDENT_FMT_STEREO) /* stereo */ - CTRL |= 0x00000004; - - /* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */ - /* right vol: mute, ledt vol: mute */ - FMC_RVOL_CVOL = 0x0000ffff; - GVSEL = 1; - PAN = 0; - VOL = 0; - EC = 0; - - trident_write_voice_regs(trident->card, - trident->dma_dac.chan, - LBA, - 0, /* cso */ - ESO, - Delta, - 0, /* alpha */ - FMC_RVOL_CVOL, - GVSEL, - PAN, - VOL, - CTRL, - EC); - -} - -/* - * Native record driver - */ -/* FIXME: Not exammed yet */ -/* again, passed mode is alrady shifted/masked */ - -static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate, - void *buffer, int size) -{ - unsigned int LBA; - unsigned int Delta; - unsigned int ESO; - unsigned int CTRL; - unsigned int FMC_RVOL_CVOL; - unsigned int GVSEL; - unsigned int PAN; - unsigned int VOL; - unsigned int EC; - unsigned char bValue; - unsigned short wValue; - unsigned int dwValue; - unsigned short wRecCODECSamples; - unsigned int dwChanFlags; - struct trident_card *card = trident->card; - + channel->control |= CHANNEL_STEREO; #ifdef DEBUG - printk("trident: trident_rec_setup called\n"); + printk("trident: trident_rec_setup, LBA = 0x%08x, " + "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", + channel->lba, channel->delta, channel->eso, channel->control); #endif - - // Enable AC-97 ADC (capture), disable capture interrupt - switch (card->pci_id) - { - case PCI_DEVICE_ID_SI_7018: - /* for 7018, the ac97 is always in playback/record (duplex) mode */ - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT)); - outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT)); - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - wValue = inw(TRID_REG(card, T4D_MISCINT)); - outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT)); - break; - } - - // Initilize the channel and set channel Mode - outb(0, TRID_REG(card, LEGACY_DMAR15)); - - // Set DMA channel operation mode register - bValue = inb(TRID_REG(card, LEGACY_DMAR11)) & 0x03; - outb(bValue | 0x54, TRID_REG(card, LEGACY_DMAR11)); - - // Set channel buffer Address - LBA = virt_to_bus(buffer); - outl(LBA, TRID_REG(card, LEGACY_DMAR0)); - - /* set ESO */ - ESO = size; - - dwValue = inl(TRID_REG(card, LEGACY_DMAR4)) & 0xff000000; - dwValue |= (ESO - 1) & 0x0000ffff; - outl(dwValue, TRID_REG(card, LEGACY_DMAR4)); - - // Set channel sample rate , 4.12 format - dwValue = (((unsigned int) 48000L << 12) / (unsigned long) (rate)); - outw((unsigned short) dwValue, TRID_REG(card, T4D_SBDELTA_DELTA_R)); - - // Set channel interrupt blk length - if (mode & TRIDENT_FMT_16BIT) { - wRecCODECSamples = (unsigned short) ((ESO >> 1) - 1); - dwChanFlags = 0xffffb000; - } else { - wRecCODECSamples = (unsigned short) (ESO - 1); - dwChanFlags = 0xffff1000; - } - - dwValue = ((unsigned int) wRecCODECSamples) << 16; - dwValue |= (unsigned int) (wRecCODECSamples) & 0x0000ffff; - outl(dwValue, TRID_REG(card, T4D_SBBL_SBCL)); - - // Right now, set format and start to run capturing, - // continuous run loop enable. - trident->bDMAStart = 0x19; // 0001 1001b - - if (mode & TRIDENT_FMT_16BIT) - trident->bDMAStart |= 0xa0; - if (mode & TRIDENT_FMT_STEREO) - trident->bDMAStart |= 0x40; - - // Prepare capture intr channel - - Delta = ((((unsigned int) rate) << 12) / ((unsigned long) (48000L))); - - /* set Loop Back Address */ - LBA = virt_to_bus(buffer); - - /* set ESO */ - ESO = size; - if (mode & TRIDENT_FMT_16BIT) - ESO /= 2; - if (mode & TRIDENT_FMT_STEREO) - ESO /= 2; - - ESO = ESO - 1; - //snd_printk("trid: ESO = %d\n", ESO); - - /* set ctrl mode - CTRL default: 8-bit (unsigned) mono, loop mode enabled - */ - CTRL = 0x00000001; - if (mode & TRIDENT_FMT_16BIT) - CTRL |= 0x00000008; // 16-bit data - /* XXX DO UNSIGNED XXX */ - //if (!(mode & SND_PCM1_MODE_U)) - // CTRL |= 0x00000002; // signed data - if (mode& TRIDENT_FMT_STEREO) - CTRL |= 0x00000004; // stereo data - - FMC_RVOL_CVOL = 0x0000ffff; - GVSEL = 1; - PAN = 0xff; - VOL = 0xff; - EC = 0; - - trident_write_voice_regs(card, - trident->dma_adc.chan, - LBA, - 0, /* cso */ - ESO, - Delta, - 0, /* alpha */ - FMC_RVOL_CVOL, - GVSEL, - PAN, - VOL, - CTRL, - EC); - + trident_write_voice_regs(state, 1); } -/* get current playback pointer */ -__inline__ unsigned int get_dmaa(struct trident_state *trident) +/* get current playback/recording dma buffer pointer (byte offset from LBA), + called with spinlock held! */ +extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec) { + struct dmabuf *dmabuf; u32 cso; - u32 eso; -#if 0 - /* FIXME: does this mean that FULL duplex is not supported ? */ - if (!(trident->enable & ADC_RUNNING)) + + if (rec) + dmabuf = &state->dma_adc; + else + dmabuf = &state->dma_dac; + + if (!dmabuf->enable) return 0; -#endif - outb(trident->dma_dac.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR)); - switch (trident->card->pci_id) + outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR)); + + switch (state->card->pci_id) { case PCI_DEVICE_ID_SI_7018: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: /* 16 bits ESO, CSO for 7018 and DX */ - cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2)); - eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2)); + cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2)); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: /* 24 bits ESO, CSO for NX */ - cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff; - eso = inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff; + cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff; break; default: return 0; } #ifdef DEBUG - printk("trident: get_dmaa: chip reported channel: %d, cso = %d, eso = %d\n", - trident->dma_dac.chan, cso, eso); + printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n", + dmabuf->channel->num, cso); #endif /* ESO and CSO are in units of Samples, convert to byte offset */ - if (cso > eso) - cso = eso; - if (trident->fmt & TRIDENT_FMT_16BIT) - cso *= 2; - if (trident->fmt & TRIDENT_FMT_STEREO) - cso *= 2; - return cso; + cso <<= sample_shift[dmabuf->fmt]; + + return (cso % dmabuf->dmasize); } -/* get current recording pointer */ -extern __inline__ unsigned get_dmac(struct trident_state *trident) +/* Stop recording (lock held) */ +extern __inline__ void __stop_adc(struct trident_state *state) { - u32 cso; -#if 0 - /* FIXME: does this mean that FULL duplex is not supported ? */ - if (!(trident->enable & DAC_RUNNING)) - return 0; -#endif - outb(trident->dma_adc.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR)); - - switch (trident->card->pci_id) - { - default: - case PCI_DEVICE_ID_SI_7018: - case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: - /* 16 bits ESO, CSO for 7018 and DX */ - cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2)); - break; - case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: - /* 24 bits ESO, CSO for NX */ - cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff; - break; - } + struct dmabuf *dmabuf = &state->dma_adc; + unsigned int chan_num = dmabuf->channel->num; + struct trident_card *card = state->card; -#ifdef DEBUG - printk("(trident) get_dmac: chip reported cso = %d\n", cso); -#endif - /* ESO and CSO are in units of Samples, convert to byte offset */ - if (trident->fmt & TRIDENT_FMT_16BIT) - cso *= 2; - if (trident->fmt & TRIDENT_FMT_STEREO) - cso *= 2; - return cso; + dmabuf->enable &= ~DMA_RUNNING; + trident_stop_voice(card, chan_num); + trident_disable_voice_irq(card, chan_num); } -/* Stop recording (lock held) */ -extern inline void __stop_adc(struct trident_state *s) -{ - struct trident_card *trident = s->card; -#ifdef DEBUG - printk("(trident) stopping ADC\n"); -#endif - s->enable &= ~ADC_RUNNING; - trident_disable_voice_irq(trident, s->dma_adc.chan); - outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD)); - trident_disable_voice_irq(trident, s->dma_adc.chan); - trident_stop_voice(trident, s->dma_adc.chan); - ResetAinten(trident, s->dma_adc.chan); -} +static void stop_adc(struct trident_state *state) +{ + struct trident_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} -extern inline void stop_adc(struct trident_state *s) +static void start_adc(struct trident_state *state) { + struct dmabuf *dmabuf = &state->dma_adc; + unsigned int chan_num = dmabuf->channel->num; + struct trident_card *card = state->card; unsigned long flags; - struct trident_card *trident = s->card; - spin_lock_irqsave(&trident->lock, flags); - __stop_adc(s); - spin_unlock_irqrestore(&trident->lock, flags); -} + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || + dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize)) + && dmabuf->ready) { + dmabuf->enable |= DMA_RUNNING; + trident_enable_voice_irq(card, chan_num); + trident_start_voice(card, chan_num); + } + spin_unlock_irqrestore(&card->lock, flags); +} /* stop playback (lock held) */ -extern inline void __stop_dac(struct trident_state *state) +extern __inline__ void __stop_dac(struct trident_state *state) { - struct trident_card *trident = state->card; - trident_stop_voice(trident, state->dma_dac.chan); - trident_disable_voice_irq(trident, state->dma_dac.chan); - state->enable &= ~DAC_RUNNING; -} + struct dmabuf *dmabuf = &state->dma_dac; + unsigned int chan_num = dmabuf->channel->num; + struct trident_card *card = state->card; -extern inline void stop_dac(struct trident_state *state) + dmabuf->enable &= ~DMA_RUNNING; + trident_stop_voice(card, chan_num); + trident_disable_voice_irq(card, chan_num); +} + +static void stop_dac(struct trident_state *state) { - struct trident_card *trident = state->card; + struct trident_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&trident->lock, flags); + spin_lock_irqsave(&card->lock, flags); __stop_dac(state); - spin_unlock_irqrestore(&trident->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); } static void start_dac(struct trident_state *state) { - unsigned long flags; - struct trident_card *trident = state->card; - - spin_lock_irqsave(&state->card->lock, flags); - if ((state->dma_dac.mapped || state->dma_dac.count > 0) && state->dma_dac.ready) { - state->enable |= DAC_RUNNING; - trident_enable_voice_irq(trident, state->dma_dac.chan); - trident_start_voice(trident, state->dma_dac.chan); - } - spin_unlock_irqrestore(&state->card->lock, flags); -} - -static void start_adc(struct trident_state *s) -{ + struct dmabuf *dmabuf = &state->dma_dac; + unsigned int chan_num = dmabuf->channel->num; + struct trident_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&s->card->lock, flags); - if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->enable |= ADC_RUNNING; - trident_enable_voice_irq(s->card, s->dma_adc.chan); - outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD)); - trident_start_voice(s->card, s->dma_adc.chan); -#ifdef DEBUG - printk("(trident) starting ADC\n"); -#endif + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + dmabuf->enable |= DMA_RUNNING; + trident_enable_voice_irq(card, chan_num); + trident_start_voice(card, chan_num); } - spin_unlock_irqrestore(&s->card->lock, flags); -} + spin_unlock_irqrestore(&card->lock, flags); +} #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_MINORDER 1 @@ -1623,10 +823,16 @@ /* allocate DMA buffer, playback and recording buffer should be allocated seperately */ static int alloc_dmabuf(struct trident_state *state, unsigned rec) { + struct dmabuf *dmabuf; void *rawbuf; int order; unsigned long map, mapend; + if (rec) + dmabuf = &state->dma_adc; + else + dmabuf = &state->dma_dac; + /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) @@ -1634,7 +840,7 @@ if (!rawbuf) return -ENOMEM; #ifdef DEBUG - printk("trident: allocated %ld (%d) bytes at %p\n", + printk("trident: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); #endif @@ -1648,17 +854,10 @@ return -ENOMEM; } - if (rec) { - state->dma_adc.ready = state->dma_adc.mapped = 0; - state->dma_adc.rawbuf = rawbuf; - state->dma_adc.buforder = order; - } - else { - state->dma_dac.ready = state->dma_dac.mapped = 0; - state->dma_dac.rawbuf = rawbuf; - state->dma_dac.buforder = order; - } - + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->rawbuf = rawbuf; + dmabuf->buforder = order; + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1); for (map = MAP_NR(rawbuf); map <= mapend; map++) @@ -1668,180 +867,237 @@ } /* free DMA buffer */ -static void dealloc_dmabuf(struct dmabuf *db) +static void dealloc_dmabuf(struct dmabuf *dmabuf) { unsigned long map, mapend; - if (db->rawbuf) { + if (dmabuf->rawbuf) { /* undo marking the pages as reserved */ - mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)db->rawbuf, db->buforder); + free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder); } - db->rawbuf = NULL; - db->mapped = db->ready = 0; + dmabuf->rawbuf = NULL; + dmabuf->mapped = dmabuf->ready = 0; } static int prog_dmabuf(struct trident_state *state, unsigned rec) { - struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac; - unsigned rate = rec ? state->rateadc : state->ratedac; + struct dmabuf *dmabuf; unsigned bytepersec; - unsigned bufs; - unsigned char fmt; + unsigned bufsize; unsigned long flags; int ret; + if (rec) + dmabuf = &state->dma_adc; + else + dmabuf = &state->dma_dac; + spin_lock_irqsave(&state->card->lock, flags); - fmt = state->fmt; - if (rec) { - state->enable &= ~TRIDENT_ENABLE_RE; - fmt >>= TRIDENT_ADC_SHIFT; - } else { - state->enable &= ~TRIDENT_ENABLE_PE; - fmt >>= TRIDENT_DAC_SHIFT; - } + dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); - fmt &= TRIDENT_FMT_MASK; - - db->hwptr = db->swptr = db->total_bytes = 0; - db->count = db->error = db->endcleared = 0; - /* allocate DMA buffer if not allocated yet */ - if (!db->rawbuf) + if (!dmabuf->rawbuf) if ((ret = alloc_dmabuf(state, rec))) return ret; - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); + /* FIXME: figure out all this OSS fragment stuff */ + bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + bufsize = PAGE_SIZE << dmabuf->buforder; + if (dmabuf->ossfragshift) { + if ((1000 << dmabuf->ossfragshift) < bytepersec) + dmabuf->fragshift = ld2(bytepersec/1000); else - db->fragshift = db->ossfragshift; + dmabuf->fragshift = dmabuf->ossfragshift; } else { /* lets hand out reasonable big ass buffers by default */ - db->fragshift = (db->buforder + PAGE_SHIFT -2); + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { + dmabuf->fragshift--; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + } + dmabuf->fragsize = 1 << dmabuf->fragshift; + if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + dmabuf->numfrag = dmabuf->ossmaxfrags; + dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize); + memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, + dmabuf->dmasize); spin_lock_irqsave(&state->card->lock, flags); if (rec) { - trident_rec_setup(state, fmt, state->rateadc, - db->rawbuf, db->numfrag << db->fragshift); + trident_rec_setup(state); } else { - trident_play_setup(state, fmt, state->ratedac, - db->rawbuf, db->numfrag << db->fragshift); + trident_play_setup(state); } spin_unlock_irqrestore(&state->card->lock, flags); /* set the ready flag for the dma buffer */ - db->ready = 1; + dmabuf->ready = 1; #ifdef DEBUG printk("trident: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " "fragsize = %d dmasize = %d\n", - rate, fmt, db->numfrag, db->fragsize, db->dmasize); + dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, + dmabuf->fragsize, dmabuf->dmasize); #endif return 0; } -extern __inline__ void clear_advance(struct trident_state *s) +/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e. + |------------|------------| or |xxxxxxxxxxxx|------------| or |xxxxxxxxxxxx|xxxxxxxxxxxx| + but we almost always get this + |xxxxxx------|------------| or |xxxxxxxxxxxx|xxxxx-------| + so we have to clear the tail space to "silence" + |xxxxxx000000|------------| or |xxxxxxxxxxxx|xxxxxx000000| +*/ +static void trident_clear_tail(struct trident_state *state) +{ + struct dmabuf *dmabuf = &state->dma_dac; + unsigned swptr; + unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80; + unsigned int len; + unsigned long flags; + + spin_lock_irqsave(&state->card->lock, flags); + swptr = dmabuf->swptr; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize) + return; + + + if (swptr < dmabuf->dmasize/2) + len = dmabuf->dmasize/2 - swptr; + else + len = dmabuf->dmasize - swptr; + + memset(dmabuf->rawbuf + swptr, silence, len); + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr += len; + dmabuf->count += len; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* restart the dma machine in case it is halted */ + start_dac(state); +} + +static int drain_dac(struct trident_state *state, int nonblock) { - unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80; - unsigned char *buf = s->dma_dac.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - /* account for wrapping? */ - bptr = 0; - len -= x; + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dma_dac; + unsigned long flags; + unsigned long tmo; + int count; + + if (dmabuf->mapped || !dmabuf->ready) + return 0; + + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + /* It seems that we have to set the current state to TASK_INTERRUPTIBLE + every time to make the process really go to sleep */ + current->state = TASK_INTERRUPTIBLE; + + spin_lock_irqsave(&state->card->lock, flags); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (count <= 0) + break; + + if (signal_pending(current)) + break; + + if (nonblock) { + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + + /* No matter how much data left in the buffer, we have to wait untill + CSO == ESO/2 or CSO == ESO when address engine interrupts */ + tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + tmo >>= sample_shift[dmabuf->fmt]; + if (!schedule_timeout(tmo ? tmo : 1) && tmo){ + printk(KERN_ERR "trident: drain_dac, dma timeout?\n"); + break; + } } - memset(buf + bptr, c, len); + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + + return 0; } /* call with spinlock held! */ -static void trident_update_ptr(struct trident_state *s) +static void trident_update_ptr(struct trident_state *state) { + struct dmabuf *dmabuf; unsigned hwptr; int diff; /* update ADC pointer */ - if (s->dma_adc.ready) { - hwptr = get_dmac(s) % s->dma_adc.dmasize; - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % - s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->enable &= ~TRIDENT_ENABLE_RE; - __stop_adc(s); - s->dma_adc.error++; + if (state->dma_adc.ready) { + dmabuf = &state->dma_adc; + hwptr = trident_get_dma_addr(state, 1); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count += diff; + + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + if (!dmabuf->mapped) { + if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) { + __stop_adc(state); + dmabuf->error++; } } } /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = get_dmaa(s) % s->dma_dac.dmasize; - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % - s->dma_dac.dmasize; - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - wake_up(&s->dma_dac.wait); - } + if (state->dma_dac.ready) { + dmabuf = &state->dma_dac; + hwptr = trident_get_dma_addr(state, 0); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + + if (dmabuf->mapped) { + dmabuf->count += diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { - s->dma_dac.count -= diff; - if (s->dma_dac.count <= 0) { - s->enable &= ~TRIDENT_ENABLE_PE; - /* Lock already held */ - __stop_dac(s); - /* brute force everyone back in sync, sigh */ - s->dma_dac.count = 0; - s->dma_dac.swptr = 0; - s->dma_dac.hwptr = 0; - s->dma_dac.error++; - } - else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && - !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; + dmabuf->count -= diff; + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_dac(state); + dmabuf->error++; } - - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) - wake_up(&s->dma_dac.wait); + /* since dma machine only interrupts at ESO and ESO/2, we sure have at + least half of dma buffer free, so wake up the process unconditionally */ + wake_up(&dmabuf->wait); } } } -/* - * Trident interrupt handlers. - */ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct trident_state *state; @@ -1858,19 +1114,17 @@ if (event & ADDRESS_IRQ) { /* Update the pointers for all channels we are running. */ - /* FIXME: improve interrupt latency !!! */ - for (i = 0; i < NR_DSPS; i++) { - state = card->channels[i]; + /* FIXME: should read interrupt status only once */ + for (i = 0; i < NR_HW_CH; i++) { if (trident_check_channel_interrupt(card, 63 - i)) { trident_ack_channel_interrupt(card, 63 - i); - if (state != NULL) + if ((state = card->states[i]) != NULL) { trident_update_ptr(state); - else { - /* Spurious ? */ - printk("trident: spurious channel irq %d.\n", + } else { + printk("trident: spurious channel irq %d.\n", 63 - i); trident_stop_voice(card, i); - trident_disable_voice_irq(card, i); + trident_disable_voice_irq(card, i); } } } @@ -1886,254 +1140,29 @@ spin_unlock(&card->lock); } -static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val ) -{ - unsigned int left,right; - - /* cleanse input a little */ - right = ((val >> 8) & 0xff) ; - left = (val & 0xff) ; - - if (right > 100) right = 100; - if (left > 100) left = 100; - - card->mix.mixer_state[mixer] = (right << 8) | left; - card->mix.write_mixer(card, mixer, left, right); -} - -static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - int i, val = 0; - - VALIDATE_CARD(card); - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strncpy(info.id, card->pci_info->name, sizeof(info.id)); - strncpy(info.name, card->pci_info->name, sizeof(info.name)); - info.modify_counter = card->mix.modcnt; - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strncpy(info.id, card->pci_info->name, sizeof(info.id)); - strncpy(info.name, card->pci_info->name, sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *)arg); - - if (_IOC_DIR(cmd) == _IOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* give them the current record source */ - if (!card->mix.recmask_io) { - val = 0; - } else { - spin_lock_irqsave(&card->lock, flags); - val = card->mix.recmask_io(card,1,0); - spin_unlock_irqrestore(&card->lock, flags); - } - break; - - case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ - val = card->mix.supported_mixers; - break; - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - val = card->mix.record_sources; - break; - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - val = card->mix.stereo_mixers; - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: /* read a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(card,i)) - return -EINVAL; - - /* do we ever want to touch the hardware? */ - /* spin_lock_irqsave(&s->lock, flags); - val = card->mix.read_mixer(card,i); - spin_unlock_irqrestore(&s->lock, flags);*/ - - val = card->mix.mixer_state[i]; - /* printk("returned 0x%x for mixer %d\n",val,i);*/ - break; - } - return put_user(val,(int *)arg); - } - - if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { - card->mix.modcnt++; - get_user_ret(val, (int *)arg, -EFAULT); - - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (!card->mix.recmask_io) return -EINVAL; - if (!(val &= card->mix.record_sources)) return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - card->mix.recmask_io(card, 0, val); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; - default: /* write a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(card, i)) - return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - set_mixer(card, i, val); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; - } - } - return -EINVAL; -} - -static int trident_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - struct trident_card *card = devs; - - while (card && card->dev_mixer != minor) - card = card->next; - if (!card) - return -ENODEV; - - file->private_data = card; - - //FIXME put back in - //MOD_INC_USE_COUNT; - return 0; -} - -static int trident_release_mixdev(struct inode *inode, struct file *file) -{ - struct trident_card *card = (struct trident_card *)file->private_data; - - VALIDATE_CARD(card); - - //FIXME put back in - //MOD_DEC_USE_COUNT; - return 0; -} - -static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct trident_card *card = (struct trident_card *)file->private_data; - - VALIDATE_CARD(card); - return mixer_ioctl(card, cmd, arg); -} - static loff_t trident_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } -static /*const*/ struct file_operations trident_mixer_fops = { - &trident_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &trident_ioctl_mixdev, - NULL, /* mmap */ - &trident_open_mixdev, - NULL, /* flush */ - &trident_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ -}; - -/* drain the DAC buffer - FIXME: This function will block (forever ??) when using - XMMS Qsound plugin and direct cat sample.wav > /dev/dsp - This behavior is when drain_dac is called by trident_release. */ -static int drain_dac(struct trident_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count; - signed long tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - spin_lock_irqsave(&s->card->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->card->lock, flags); - - if (count <= 0) - break; - - if (signal_pending(current)) - break; - - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - - tmo = (count * HZ) / s->ratedac; - tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK]; - - /* XXX this is just broken. someone is waking us up alot, - or schedule_timeout is broken. - or something. who cares. - zach */ - if (!schedule_timeout(tmo ? tmo : 1) && tmo) - printk(KERN_ERR "trident: drain_dac, " - "dma timed out? jiffies = %ld\n", - jiffies); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - if (signal_pending(current)) - return -ERESTARTSYS; - - return 0; -} - /* in this loop, dma_adc.count signifies the amount of data thats waiting to be copied to the user's buffer. it is filled by the interrupt handler and drained by this loop. */ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dma_dac; ssize_t ret; unsigned long flags; unsigned swptr; int cnt; - + VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; - if (state->dma_adc.mapped) + if (dmabuf->mapped) return -ENXIO; - if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; @@ -2141,12 +1170,10 @@ while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); - /* remember, all these things are expressed in bytes to be - sent to the user.. hence the evil / 2 down below */ - swptr = state->dma_adc.swptr; - cnt = state->dma_adc.dmasize - swptr; - if (state->dma_adc.count < cnt) - cnt = state->dma_adc.count; + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count < cnt) + cnt = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); if (cnt > count) @@ -2158,20 +1185,17 @@ ret = ret ? ret : -EAGAIN; return ret; } - if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) { - printk(KERN_DEBUG "(trident) read: chip lockup? " + if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) { + printk(KERN_ERR + "(trident) read: chip lockup? " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - state->dma_adc.dmasize, - state->dma_adc.fragsize, - state->dma_adc.count, - state->dma_adc.hwptr, - state->dma_adc.swptr); + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); stop_adc(state); - spin_lock_irqsave(&state->card->lock, flags); - state->dma_adc.count = 0; - state->dma_adc.hwptr = 0; - state->dma_adc.swptr = 0; + dmabuf->count = 0; + dmabuf->hwptr = 0; + dmabuf->swptr = 0; spin_unlock_irqrestore(&state->card->lock, flags); } if (signal_pending(current)) { @@ -2180,17 +1204,19 @@ } continue; } - - if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) { + + if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { ret = ret ? ret : -EFAULT; return ret; } - swptr = (swptr + cnt) % state->dma_adc.dmasize; + swptr = (swptr + cnt) % dmabuf->dmasize; + spin_lock_irqsave(&state->card->lock, flags); - state->dma_adc.swptr = swptr; - state->dma_adc.count -= cnt; + dmabuf->swptr = swptr; + dmabuf->count -= cnt; spin_unlock_irqrestore(&state->card->lock, flags); + count -= cnt; buffer += cnt; ret += cnt; @@ -2203,11 +1229,11 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dma_dac; ssize_t ret; unsigned long flags; unsigned swptr; int cnt; - int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK; #ifdef DEBUG printk("trident: trident_write called, count = %d\n", count); @@ -2216,9 +1242,9 @@ VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; - if (state->dma_dac.mapped) + if (dmabuf->mapped) return -ENXIO; - if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; @@ -2226,41 +1252,47 @@ while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); - if (state->dma_dac.count < 0) { - state->dma_dac.count = 0; - state->dma_dac.swptr = state->dma_dac.hwptr; - } - swptr = state->dma_dac.swptr; - cnt = state->dma_dac.dmasize - swptr; - if (state->dma_dac.count + cnt > state->dma_dac.dmasize) - cnt = state->dma_dac.dmasize - state->dma_dac.count; + if (dmabuf->count < 0) { + /* buffer underrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr */ + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count + cnt > dmabuf->dmasize) + cnt = dmabuf->dmasize - dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { - /* buffer is full, wait for it to be played */ + unsigned long tmo; + /* buffer is full, start the dma machine and wait for data to be played */ start_dac(state); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } - if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) { - printk(KERN_ERR - "trident: write: chip lockup? " - "dmasz %u fragsz %u count %i " - "hwptr %u swptr %u\n", - state->dma_dac.dmasize, - state->dma_dac.fragsize, - state->dma_dac.count, - state->dma_dac.hwptr, - state->dma_dac.swptr); - stop_dac(state); - spin_lock_irqsave(&state->card->lock, flags); - state->dma_dac.count = 0; - state->dma_dac.hwptr = 0; - state->dma_dac.swptr = 0; - spin_unlock_irqrestore(&state->card->lock, flags); + /* No matter how much data left in the buffer, we have to wait untill + CSO == ESO/2 or CSO == ESO when address engine interrupts */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when the + interrupt is serviced correctly and the process is waked up by ISR ON TIME. + Another is when timeout is expired, which means that either interrupt is NOT + serviced correctly (pending interrupt) or it is TOO LATE for the process to + be scheduled to run (scheduler latency) which results in a (potential) buffer + underrun. And worse, there is NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "trident: schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer underrun, we delay the recovery untill next time the + while loop begin and we REALLY have data to play */ } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; @@ -2268,18 +1300,17 @@ } continue; } - if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; return ret; } - swptr = (swptr + cnt) % state->dma_dac.dmasize; + swptr = (swptr + cnt) % dmabuf->dmasize; spin_lock_irqsave(&state->card->lock, flags); - state->dma_dac.swptr = swptr; - state->dma_dac.count += cnt; - state->dma_dac.endcleared = 0; + dmabuf->swptr = swptr; + dmabuf->count += cnt; + dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; @@ -2304,7 +1335,6 @@ spin_lock_irqsave(&s->card->lock, flags); trident_update_ptr(s); - if (file->f_mode & FMODE_READ) { if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; @@ -2319,56 +1349,56 @@ } } spin_unlock_irqrestore(&s->card->lock, flags); + return mask; } -/* this needs to be fixed to deal with the dual apus/buffers */ -#if 0 static int trident_mmap(struct file *file, struct vm_area_struct *vma) { - struct trident_state *s = (struct trident_state *)file->private_data; - struct dmabuf *db; + struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf; int ret; unsigned long size; - VALIDATE_STATE(s); + VALIDATE_STATE(state); if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 0)) != 0) + if ((ret = prog_dmabuf(state, 0)) != 0) return ret; - db = &s->dma_dac; + dmabuf = &state->dma_dac; } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 1)) != 0) + if ((ret = prog_dmabuf(state, 1)) != 0) return ret; - db = &s->dma_adc; + dmabuf = &state->dma_adc; } else return -EINVAL; - if (vma->vm_offset != 0) + + if (vma->vm_pgoff != 0) return -EINVAL; size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) + if (size > (PAGE_SIZE << dmabuf->buforder)) return -EINVAL; - if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), + size, vma->vm_page_prot)) return -EAGAIN; - db->mapped = 1; + dmabuf->mapped = 1; + return 0; } -#endif static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct trident_state *s = (struct trident_state *)file->private_data; + struct trident_state *state = (struct trident_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret; - unsigned char fmtm, fmtd; - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + VALIDATE_STATE(state); + mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && state->dma_adc.mapped); #ifdef DEBUG - printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",_IOC_NR(cmd), - arg ? *(int *)arg : 0); + printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", + _IOC_NR(cmd), arg ? *(int *)arg : 0); #endif switch (cmd) @@ -2378,189 +1408,218 @@ case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { - stop_dac(s); + stop_dac(state); synchronize_irq(); - s->dma_dac.swptr = s->dma_dac.hwptr = 0; - s->dma_dac.count = s->dma_dac.total_bytes = 0; + state->dma_dac.ready = 0; + state->dma_dac.swptr = state->dma_dac.hwptr = 0; + state->dma_dac.count = state->dma_dac.total_bytes = 0; } if (file->f_mode & FMODE_READ) { - stop_adc(s); + stop_adc(state); synchronize_irq(); - s->dma_adc.swptr = s->dma_adc.hwptr = 0; - s->dma_adc.count = s->dma_adc.total_bytes = 0; + state->dma_adc.ready = 0; + state->dma_adc.swptr = state->dma_adc.hwptr = 0; + state->dma_adc.count = state->dma_adc.total_bytes = 0; } return 0; case SNDCTL_DSP_SYNC: if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); + return drain_dac(state, file->f_flags & O_NONBLOCK); return 0; - case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_SPEED: /* set smaple rate */ get_user_ret(val, (int *)arg, -EFAULT); if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - trident_set_adc_rate(s, val, 1); - } if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - trident_set_dac_rate(s, val, 1); + stop_dac(state); + state->dma_dac.ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + trident_set_dac_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + state->dma_adc.ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + trident_set_adc_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); } } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, + return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : + state->dma_dac.rate, (int *)arg); - case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ get_user_ret(val, (int *)arg, -EFAULT); - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + state->dma_dac.ready = 0; if (val) - fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT; + state->dma_dac.fmt |= TRIDENT_FMT_STEREO; else - fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT); + state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; + if (file->f_mode & FMODE_READ) { + stop_adc(state); + state->dma_adc.ready = 0; if (val) - fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT; + state->dma_adc.fmt |= TRIDENT_FMT_STEREO; else - fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT); + state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; } - set_fmt(s, fmtm, fmtd); return 0; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) + if ((val = prog_dmabuf(state, 0))) return val; - return put_user(s->dma_dac.fragsize, (int *)arg); + return put_user(state->dma_dac.fragsize, (int *)arg); + } + if (file->f_mode & FMODE_READ) { + if ((val = prog_dmabuf(state, 1))) + return val; + return put_user(state->dma_adc.fragsize, (int *)arg); } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, (int *)arg); - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg); - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Select sample format */ get_user_ret(val, (int *)arg, -EFAULT); if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - /* fixed at 16bit for now */ - fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; -#if 0 + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + state->dma_dac.ready = 0; if (val == AFMT_S16_LE) - fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; + state->dma_dac.fmt |= TRIDENT_FMT_16BIT; else - fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT); -#endif + state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT; } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; + if (file->f_mode & FMODE_READ) { + stop_adc(state); + state->dma_adc.ready = 0; if (val == AFMT_S16_LE) - fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT; + state->dma_adc.fmt |= TRIDENT_FMT_16BIT; else - fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT); + state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT; } - set_fmt(s, fmtm, fmtd); } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : - (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? - AFMT_S16_LE : AFMT_S8, (int *)arg); + if (file->f_mode & FMODE_WRITE) + return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); + else + return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); if (val != 0) { - fmtd = 0; - fmtm = ~0; - - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + state->dma_dac.ready = 0; if (val >= 2) - fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT; + state->dma_dac.fmt |= TRIDENT_FMT_STEREO; else - fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT); + state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; } - - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; + if (file->f_mode & FMODE_READ) { + stop_adc(state); + state->dma_adc.ready = 0; if (val >= 2) - fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT; + state->dma_adc.fmt |= TRIDENT_FMT_STEREO; else - fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT); + state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; } - set_fmt(s, fmtm, fmtd); } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : - (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg); + if (file->f_mode & FMODE_WRITE) + return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + else + return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ return 0; case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision)) return -EINVAL; get_user_ret(val, (int *)arg, -EFAULT); if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; + state->dma_adc.subdivision = val; if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; + state->dma_dac.subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; + state->dma_adc.ossfragshift = val & 0xffff; + state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (state->dma_adc.ossfragshift < 4) + state->dma_adc.ossfragshift = 4; + if (state->dma_adc.ossfragshift > 15) + state->dma_adc.ossfragshift = 15; + if (state->dma_adc.ossmaxfrags < 4) + state->dma_adc.ossmaxfrags = 4; } if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; + state->dma_dac.ossfragshift = val & 0xffff; + state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (state->dma_dac.ossfragshift < 4) + state->dma_dac.ossfragshift = 4; + if (state->dma_dac.ossfragshift > 15) + state->dma_dac.ossfragshift = 15; + if (state->dma_dac.ossmaxfrags < 4) + state->dma_dac.ossmaxfrags = 4; } return 0; - case SNDCTL_DSP_GETCAPS: - return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */, - (int *)arg); - - case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); + abinfo.fragsize = state->dma_dac.fragsize; + abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count; + abinfo.fragstotal = state->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); + abinfo.fragsize = state->dma_adc.fragsize; + abinfo.bytes = state->dma_adc.count; + abinfo.fragstotal = state->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; return 0; + case SNDCTL_DSP_GETCAPS: + return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, + (int *)arg); + case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE) + if (file->f_mode & FMODE_READ && state->dma_adc.enable) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE) + if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); @@ -2568,106 +1627,86 @@ get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1))) return ret; - start_adc(s); + start_adc(state); } else - stop_adc(s); + stop_adc(state); } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0))) return ret; - start_dac(s); + start_dac(state); } else - stop_dac(s); + stop_dac(state); } return 0; - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->card->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) - return val; - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->card->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->card->lock, flags); - return put_user(val, (int *)arg); - case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->card->lock, flags); + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); + cinfo.bytes = state->dma_adc.total_bytes; + cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift; + cinfo.ptr = state->dma_adc.hwptr; + if (state->dma_adc.mapped) + state->dma_adc.count &= state->dma_adc.fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->card->lock, flags); + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); + cinfo.bytes = state->dma_dac.total_bytes; + cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift; + cinfo.ptr = state->dma_dac.hwptr; + if (state->dma_dac.mapped) + state->dma_dac.count &= state->dma_dac.fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_SETDUPLEX: + /* XXX fix */ + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); + val = state->dma_dac.count; + spin_unlock_irqrestore(&state->card->lock, flags); + return put_user(val, (int *)arg); + case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : + state->dma_dac.rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : - (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg); + if (file->f_mode & FMODE_WRITE) + return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + else + return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : - (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg); - - case SOUND_PCM_WRITE_FILTER: + if (file->f_mode & FMODE_WRITE) + return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); + else + return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2681,13 +1720,12 @@ int minor = MINOR(inode->i_rdev); struct trident_card *card = devs; struct trident_state *state = NULL; - unsigned char fmtm = ~0, fmts = 0; /* find an avaiable virtual channel (instance of /dev/dsp) */ while (card != NULL) { - for (i = 0; i < NR_DSPS; i++) { - if (card->channels[i] == NULL) { - state = card->channels[i] = (struct trident_state *) + for (i = 0; i < NR_HW_CH; i++) { + if (card->states[i] == NULL) { + state = card->states[i] = (struct trident_state *) kmalloc(sizeof(struct trident_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; @@ -2704,18 +1742,18 @@ found_virt: /* found a free virtual channel, allocate hardware channels */ if (file->f_mode & FMODE_READ) - if ((state->dma_adc.chan = trident_alloc_pcm_channel(card)) == -1) { - kfree (card->channels[i]); - card->channels[i] = NULL;; + if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; return -ENODEV; } if (file->f_mode & FMODE_WRITE) - if ((state->dma_dac.chan = trident_alloc_pcm_channel(card)) == -1) { - kfree (card->channels[i]); - card->channels[i] = NULL; + if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL; if (file->f_mode & FMODE_READ) /* free previously allocated hardware channel */ - trident_free_pcm_channel(card, state->dma_adc.chan); + trident_free_pcm_channel(card, state->dma_adc.channel->num); return -ENODEV; } @@ -2732,30 +1770,27 @@ /* set default sample format, Refer to OSS Programmer's Guide */ if (file->f_mode & FMODE_READ) { - /* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */ - fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT; + /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */ + state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT; state->dma_adc.ossfragshift = 0; state->dma_adc.ossmaxfrags = 0; state->dma_adc.subdivision = 0; - trident_set_adc_rate(state, 8000, 0); + trident_set_adc_rate(state, 48000); } /* according to OSS document, /dev/dsp should be default to unsigned 8-bits, mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */ if (file->f_mode & FMODE_WRITE) { - fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT); + state->dma_dac.fmt &= ~TRIDENT_FMT_MASK; if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT; + state->dma_dac.fmt |= TRIDENT_FMT_16BIT; state->dma_dac.ossfragshift = 0; state->dma_dac.ossmaxfrags = 0; state->dma_dac.subdivision = 0; - trident_set_dac_rate(state, 8000, 1); + trident_set_dac_rate(state, 8000); } - set_fmt(state, fmtm, fmts); - state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&state->open_sem); //FIXME put back in @@ -2768,8 +1803,12 @@ struct trident_state *state = (struct trident_state *)file->private_data; VALIDATE_STATE(state); - if (file->f_mode & FMODE_WRITE) + + + if (file->f_mode & FMODE_WRITE) { + trident_clear_tail(state); drain_dac(state, file->f_flags & O_NONBLOCK); + } /* stop DMA state machine and free DMA buffers/channels */ down(&state->open_sem); @@ -2777,16 +1816,16 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); dealloc_dmabuf(&state->dma_dac); - trident_free_pcm_channel(state->card, state->dma_dac.chan); + trident_free_pcm_channel(state->card, state->dma_dac.channel->num); } if (file->f_mode & FMODE_READ) { stop_adc(state); dealloc_dmabuf(&state->dma_adc); - trident_free_pcm_channel(state->card, state->dma_adc.chan); + trident_free_pcm_channel(state->card, state->dma_adc.channel->num); } - kfree(state->card->channels[state->virt]); - state->card->channels[state->virt] = NULL; + kfree(state->card->states[state->virt]); + state->card->states[state->virt] = NULL; state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); /* we're covered by the open_sem */ @@ -2796,6 +1835,7 @@ //MOD_DEC_USE_COUNT; return 0; } + static /*const*/ struct file_operations trident_audio_fops = { &trident_llseek, &trident_read, @@ -2803,7 +1843,7 @@ NULL, /* readdir */ &trident_poll, &trident_ioctl, - NULL, /* XXX &trident_mmap, */ + &trident_mmap, &trident_open, NULL, /* flush */ &trident_release, @@ -2812,15 +1852,238 @@ NULL, /* lock */ }; -/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill open time */ -static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info) +/* trident specific AC97 functions */ +/* Write AC97 mixer registers */ +static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) +{ + struct trident_card *card = (struct trident_card *)codec->private_data; + unsigned int address, mask, busy; + unsigned short count = 0xffff; + unsigned long flags; + u32 data; + + data = ((u32) val) << 16; + + switch (card->pci_id) + { + default: + case PCI_DEVICE_ID_SI_7018: + address = SI_AC97_WRITE; + mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY; + if (codec->id) + mask |= SI_AC97_SECONDARY; + busy = SI_AC97_BUSY_WRITE; + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: + address = DX_ACR0_AC97_W; + mask = busy = DX_AC97_BUSY_WRITE; + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: + address = NX_ACR1_AC97_W; + mask = NX_AC97_BUSY_WRITE; + if (codec->id) + mask |= NX_AC97_WRITE_SECONDARY; + busy = NX_AC97_BUSY_WRITE; + break; + } + + spin_lock_irqsave(&card->lock, flags); + do { + if ((inw(TRID_REG(card, address)) & busy) == 0) + break; + } while (count--); + + + data |= (mask | (reg & AC97_REG_ADDR)); + + if (count == 0) { + printk(KERN_ERR "trident: AC97 CODEC write timed out.\n"); + spin_unlock_irqrestore(&card->lock, flags); + return; + } + + outl(data, TRID_REG(card, address)); + spin_unlock_irqrestore(&card->lock, flags); +} + +/* Read AC97 codec registers */ +static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg) +{ + struct trident_card *card = (struct trident_card *)codec->private_data; + unsigned int address, mask, busy; + unsigned short count = 0xffff; + unsigned long flags; + u32 data; + + switch (card->pci_id) + { + default: + case PCI_DEVICE_ID_SI_7018: + address = SI_AC97_READ; + mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY; + if (codec->id) + mask |= SI_AC97_SECONDARY; + busy = SI_AC97_BUSY_READ; + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: + address = DX_ACR1_AC97_R; + mask = busy = DX_AC97_BUSY_READ; + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: + if (codec->id) + address = NX_ACR3_AC97_R_SECONDARY; + else + address = NX_ACR2_AC97_R_PRIMARY; + mask = NX_AC97_BUSY_READ; + busy = 0x0c00; + break; + } + + data = (mask | (reg & AC97_REG_ADDR)); + + spin_lock_irqsave(&card->lock, flags); + outl(data, TRID_REG(card, address)); + do { + data = inl(TRID_REG(card, address)); + if ((data & busy) == 0) + break; + } while (count--); + spin_unlock_irqrestore(&card->lock, flags); + + if (count == 0) { + printk(KERN_ERR "trident: AC97 CODEC read timed out.\n"); + data = 0; + } + return ((u16) (data >> 16)); +} + +/* OSS /dev/mixer file operation methods */ +static int trident_open_mixdev(struct inode *inode, struct file *file) { int i; + int minor = MINOR(inode->i_rdev); + struct trident_card *card = devs; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; + + match: + file->private_data = card->ac97_codec[i]; + + //FIXME put back in + //MOD_INC_USE_COUNT; + return 0; +} + +static int trident_release_mixdev(struct inode *inode, struct file *file) +{ + //struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + //FIXME put back in + //MOD_DEC_USE_COUNT; + return 0; +} + +static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations trident_mixer_fops = { + &trident_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &trident_ioctl_mixdev, + NULL, /* mmap */ + &trident_open_mixdev, + NULL, /* flush */ + &trident_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* lock */ +}; + +/* AC97 codec initialisation. */ +static int __init trident_ac97_init(struct trident_card *card) +{ + int num_ac97 = 0; + int ready_2nd = 0; + struct ac97_codec *codec; + + /* initialize controller side of AC link, and find out if secondary codes + really exist */ + switch (card->pci_id) + { + case PCI_DEVICE_ID_SI_7018: + /* disable AC97 GPIO interrupt */ + outl(0x00, TRID_REG(card, SI_AC97_GPIO)); + /* stop AC97 cold reset process */ + outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL)); + ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); + ready_2nd &= SI_AC97_SECONDARY_READY; + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: + /* playback on */ + outl(DX_AC97_PLAYBACK, TRID_REG(card, DX_ACR2_AC97_COM_STAT)); + break; + case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: + /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */ + outl(NX_AC97_PCM_OUTPUT, TRID_REG(card, NX_ACR0_AC97_COM_STAT)); + ready_2nd = inl(TRID_REG(card, NX_ACR0_AC97_COM_STAT)); + ready_2nd &= NX_AC97_SECONDARY_READY; + break; + } + + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -1; + memset(codec, 0, sizeof(struct ac97_codec)); + + /* initialize some basic codec information, other fields will be filled + in ac97_probe_codec */ + codec->private_data = card; + codec->id = num_ac97; + /* controller specific low level AC97 access function */ + codec->codec_read = trident_ac97_get; + codec->codec_write = trident_ac97_set; + + if (ac97_probe_codec(codec) == 0) + break; + + if ((codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) { + printk(KERN_ERR "trident: couldn't register mixer!\n"); + kfree(codec); + break; + } + + card->ac97_codec[num_ac97] = codec; + + /* if there is no secondary codec at all, don't probe any more */ + if (!ready_2nd) + return num_ac97+1; + } + + return num_ac97; +} + +/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered + untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */ +static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info) +{ u16 w; unsigned long iobase; struct trident_card *card; - u32 ChanDwordCount; iobase = pcidev->resource[0].start; if (check_region(iobase, 256)) { @@ -2847,30 +2110,12 @@ card->irq = pcidev->irq; card->next = devs; card->magic = TRIDENT_CARD_MAGIC; + card->banks[BANK_A].addresses = &bank_a_addrs; + card->banks[BANK_A].bitmap = 0UL; + card->banks[BANK_B].addresses = &bank_b_addrs; + card->banks[BANK_B].bitmap = 0UL; spin_lock_init(&card->lock); - devs = card; - - /* ungly stupid thing, remove ASAP */ - ChanDwordCount = card->ChanDwordCount = 2; - card->ChRegs.lpChStart = card->ChRegs.data; - card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount; - card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount; - card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount; - card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount; - card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount; - card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount; - card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount; - // Assign Bank A addresses. - card->ChRegs.lpAChStart[0] = T4D_START_A; - card->ChRegs.lpAChStop[0] = T4D_STOP_A; - card->ChRegs.lpAChAint[0] = T4D_AINT_A; - card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A; - /* Assign Bank B addresses */ - card->ChRegs.lpAChStart[1] = T4D_START_B; - card->ChRegs.lpAChStop[1] = T4D_STOP_B; - card->ChRegs.lpAChAint[1] = T4D_AINT_B; - card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B; - + devs = card; printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", card->pci_info->name, card->iobase, card->irq); @@ -2883,11 +2128,6 @@ kfree(card); return 0; } - - /* initilize AC97 codec */ - trident_ac97_init(card); - outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); - /* register /dev/dsp */ if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) { printk(KERN_ERR "trident: coundn't register DSP device!\n"); @@ -2896,29 +2136,18 @@ kfree(card); return 0; } - /* register /dev/mixer */ - if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) { - printk(KERN_ERR "trident: couldn't register mixer!\n"); + /* initilize AC97 codec and register /dev/mixer */ + if (trident_ac97_init(card) <= 0) { unregister_sound_dsp(card->dev_audio); release_region(iobase, 256); free_irq(card->irq, card); kfree(card); return 0; - } else { - /* initilize mixer channels */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - struct mixer_defaults *md = &mixer_defaults[i]; - if (md->mixer == -1) - break; - if (!supported_mixer(card, md->mixer)) - continue; - set_mixer(card, md->mixer, md->value); - } } + outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); /* Enable Address Engine Interrupts */ - trident_enable_end_interrupts(card); - trident_enable_middle_interrupts(card); + trident_enable_loop_interrupts(card); return 1; } @@ -2952,23 +2181,23 @@ MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho"); MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver"); -#ifdef DEBUG -MODULE_PARM(debug,"i"); -#endif - static void __exit cleanup_trident(void) { while (devs != NULL) { + int i; /* Kill interrupts, and SP/DIF */ - trident_disable_end_interrupts(devs); - trident_enable_middle_interrupts(devs); + trident_disable_loop_interrupts(devs); /* free hardware resources */ free_irq(devs->irq, devs); release_region(devs->iobase, 256); /* unregister audio devices */ - unregister_sound_mixer(devs->dev_mixer); + for (i = 0; i < NR_AC97; i++) + if (devs->ac97_codec[i] != NULL) { + unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer); + kfree (devs->ac97_codec[i]); + } unregister_sound_dsp(devs->dev_audio); kfree(devs); @@ -2978,5 +2207,3 @@ module_init(init_trident); module_exit(cleanup_trident); - - diff -ur --new-file old/linux/drivers/sound/trident.h new/linux/drivers/sound/trident.h --- old/linux/drivers/sound/trident.h Fri Jan 7 00:01:56 2000 +++ new/linux/drivers/sound/trident.h Sat Jan 29 04:36:23 2000 @@ -23,6 +23,7 @@ * */ +/* PCI vendor and device ID */ #ifndef PCI_VENDOR_ID_TRIDENT #define PCI_VENDOR_ID_TRIDENT 0x1023 #endif @@ -43,118 +44,101 @@ #define PCI_DEVICE_ID_SI_7018 0x7018 #endif -/* - * Direct registers - */ - #ifndef FALSE -#define FALSE 0 -#define TRUE 1 +#define FALSE 0 +#define TRUE 1 #endif -#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) ) - #define CHANNEL_REGS 5 #define CHANNEL_START 0xe0 // The first bytes of the contiguous register space. -#define BANK_A 0 -#define BANK_B 1 -#define NUM_BANKS 2 - -#define ID_4DWAVE_DX 0x2000 -#define ID_4DWAVE_NX 0x2001 -#define ID_SI_7018 0x7018 - -// Register definitions - -// Global registers - -// T2 legacy dma control registers. -#define LEGACY_DMAR0 0x00 // ADR0 -#define LEGACY_DMAR4 0x04 // CNT0 -#define LEGACY_DMAR11 0x0b // MOD -#define LEGACY_DMAR15 0x0f // MMR - -#define T4D_START_A 0x80 -#define T4D_STOP_A 0x84 -#define T4D_DLY_A 0x88 -#define T4D_SIGN_CSO_A 0x8c -#define T4D_CSPF_A 0x90 -#define T4D_CEBC_A 0x94 -#define T4D_AINT_A 0x98 -#define T4D_EINT_A 0x9c -#define T4D_LFO_GC_CIR 0xa0 -#define T4D_AINTEN_A 0xa4 -#define T4D_MUSICVOL_WAVEVOL 0xa8 -#define T4D_SBDELTA_DELTA_R 0xac -#define T4D_MISCINT 0xb0 -#define T4D_START_B 0xb4 -#define T4D_STOP_B 0xb8 -#define T4D_CSPF_B 0xbc -#define T4D_SBBL_SBCL 0xc0 -#define T4D_SBCTRL_SBE2R_SBDD 0xc4 -#define T4D_STIMER 0xc8 -#define T4D_LFO_B_I2S_DELTA 0xcc -#define T4D_AINT_B 0xd8 -#define T4D_AINTEN_B 0xdc - -// MPU-401 UART -#define T4D_MPU401_BASE 0x20 -#define T4D_MPUR0 0x20 -#define T4D_MPUR1 0x21 -#define T4D_MPUR2 0x22 -#define T4D_MPUR3 0x23 - -// S/PDIF Registers -#define NX_SPCTRL_SPCSO 0x24 -#define NX_SPLBA 0x28 -#define NX_SPESO 0x2c -#define NX_SPCSTATUS 0x64 - -// Channel Registers - -#define CH_DX_CSO_ALPHA_FMS 0xe0 -#define CH_DX_ESO_DELTA 0xe8 -#define CH_DX_FMC_RVOL_CVOL 0xec - -#define CH_NX_DELTA_CSO 0xe0 -#define CH_NX_DELTA_ESO 0xe8 -#define CH_NX_ALPHA_FMS_FMC_RVOL_CVOL 0xec - -#define CH_LBA 0xe4 -#define CH_GVSEL_PAN_VOL_CTRL_EC 0xf0 - -// AC-97 Registers - -#define DX_ACR0_AC97_W 0x40 -#define DX_ACR1_AC97_R 0x44 -#define DX_ACR2_AC97_COM_STAT 0x48 - -#define NX_ACR0_AC97_COM_STAT 0x40 -#define NX_ACR1_AC97_W 0x44 -#define NX_ACR2_AC97_R_PRIMARY 0x48 -#define NX_ACR3_AC97_R_SECONDARY 0x4c - -#define SI_AC97_WRITE 0x40 -#define SI_AC97_READ 0x44 -#define SI_SERIAL_INTF_CTRL 0x48 -#define SI_AC97_GPIO 0x4c +#define BANK_A 0 +#define BANK_B 1 +#define NR_BANKS 2 + +#define TRIDENT_FMT_STEREO 0x01 +#define TRIDENT_FMT_16BIT 0x02 +#define TRIDENT_FMT_MASK 0x03 + +#define DMA_ENABLE 0x01 +#define DMA_RUNNING 0x02 + +/* Register Addresses */ + +/* operational registers common to DX, NX, 7018 */ +enum trident_op_registers { + T4D_START_A = 0x80, T4D_STOP_A = 0x84, + T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c, + T4D_CSPF_A = 0x90, T4D_CEBC_A = 0x94, + T4D_AINT_A = 0x98, T4D_EINT_A = 0x9c, + T4D_LFO_GC_CIR = 0xa0, T4D_AINTEN_A = 0xa4, + T4D_MUSICVOL_WAVEVOL = 0xa8, T4D_SBDELTA_DELTA_R = 0xac, + T4D_MISCINT = 0xb0, T4D_START_B = 0xb4, + T4D_STOP_B = 0xb8, T4D_CSPF_B = 0xbc, + T4D_SBBL_SBCL = 0xc0, T4D_SBCTRL_SBE2R_SBDD = 0xc4, + T4D_STIMER = 0xc8, T4D_LFO_B_I2S_DELTA = 0xcc, + T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc +}; -#define AC97_SIGMATEL_DAC2INVERT 0x6E -#define AC97_SIGMATEL_BIAS1 0x70 -#define AC97_SIGMATEL_BIAS2 0x72 -#define AC97_SIGMATEL_CIC1 0x76 -#define AC97_SIGMATEL_CIC2 0x78 +/* S/PDIF Operational Registers for 4D-NX */ +enum nx_spdif_registers { + NX_SPCTRL_SPCSO = 0x24, NX_SPLBA = 0x28, + NX_SPESO = 0x2c, NX_SPCSTATUS = 0x64 +}; + +/* OP registers to access each hardware channel */ +enum channel_registers { + CH_DX_CSO_ALPHA_FMS = 0xe0, CH_DX_ESO_DELTA = 0xe8, + CH_DX_FMC_RVOL_CVOL = 0xec, + CH_NX_DELTA_CSO = 0xe0, CH_NX_DELTA_ESO = 0xe8, + CH_NX_ALPHA_FMS_FMC_RVOL_CVOL = 0xec, + CH_LBA = 0xe4, + CH_GVSEL_PAN_VOL_CTRL_EC = 0xf0 +}; + +/* registers to read/write/control AC97 codec */ +enum dx_ac97_registers { + DX_ACR0_AC97_W = 0x40, DX_ACR1_AC97_R = 0x44, + DX_ACR2_AC97_COM_STAT = 0x48 +}; + +enum nx_ac97_registers { + NX_ACR0_AC97_COM_STAT = 0x40, NX_ACR1_AC97_W = 0x44, + NX_ACR2_AC97_R_PRIMARY = 0x48, NX_ACR3_AC97_R_SECONDARY = 0x4c +}; + +enum si_ac97_registers { + SI_AC97_WRITE = 0x40, SI_AC97_READ = 0x44, + SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c +}; -#define SI_AC97_BUSY_WRITE 0x8000 -#define SI_AC97_AUDIO_BUSY 0x4000 -#define DX_AC97_BUSY_WRITE 0x8000 -#define NX_AC97_BUSY_WRITE 0x0800 -#define SI_AC97_BUSY_READ 0x8000 -#define DX_AC97_BUSY_READ 0x8000 -#define NX_AC97_BUSY_READ 0x0800 +/* Bit mask for operational registers */ #define AC97_REG_ADDR 0x000000ff +enum sis7018_ac97_bits { + SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000, + SI_AC97_AUDIO_BUSY = 0x4000, SI_AC97_MODEM_BUSY = 0x2000, + SI_AC97_SECONDARY = 0x0080 +}; + +enum trident_dx_ac97_bits { + DX_AC97_BUSY_WRITE = 0x8000, DX_AC97_BUSY_READ = 0x8000, + DX_AC97_READY = 0x0010, DX_AC97_RECORD = 0x0008, + DX_AC97_PLAYBACK = 0x0002 +}; + +enum trident_nx_ac97_bits { + /* ACR1-3 */ + NX_AC97_BUSY_WRITE = 0x0800, NX_AC97_BUSY_READ = 0x0800, + NX_AC97_WRITE_SECONDARY = 0x0100, + /* ACR0 */ + NX_AC97_SECONDARY_READY = 0x0040, NX_AC97_SECONDARY_RECORD = 0x0020, + NX_AC97_SURROUND_OUTPUT = 0x0010, + NX_AC97_PRIMARY_READY = 0x0008, NX_AC97_PRIMARY_RECORD = 0x0004, + NX_AC97_PCM_OUTPUT = 0x0002, + NX_AC97_WARM_RESET = 0x0001 +}; + enum serial_intf_ctrl_bits { WARM_REST = 0x00000001, COLD_RESET = 0x00000002, I2S_CLOCK = 0x00000004, PCM_SEC_AC97= 0x00000008, @@ -162,6 +146,16 @@ I2S_OUTPUT_EN = 0x00000040, I2S_INPUT_EN = 0x00000080, PCMIN = 0x00000100, LINE1IN = 0x00000200, MICIN = 0x00000400, LINE2IN = 0x00000800, + HEAD_SET_IN = 0x00001000, GPIOIN = 0x00002000, + /* 7018 spec says id = 01 but the demo board routed to 10 + SECONDARY_ID= 0x00008000, */ + SECONDARY_ID= 0x00004000, + PCMOUT = 0x00010000, SURROUT = 0x00020000, + CENTEROUT = 0x00040000, LFEOUT = 0x00080000, + LINE1OUT = 0x00100000, LINE2OUT = 0x00200000, + GPIOOUT = 0x00400000, + SI_AC97_PRIMARY_READY = 0x01000000, + SI_AC97_SECONDARY_READY = 0x02000000, }; enum global_control_bits { @@ -173,6 +167,18 @@ EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000 }; +enum channel_control_bits { + CHANNEL_LOOP = 0x00001000, CHANNEL_SIGNED = 0x00002000, + CHANNEL_STEREO = 0x00004000, CHANNEL_16BITS = 0x00008000, +}; + +enum channel_attribute { + MODEM_LINE1, MODEM_LINE2, PCM_LR, HSET, + I2SLR, CENTER_LFE, SURR_LR, SPDIF_LR, + CHANNEL_PB = 0x00000000, CHANNEL_SPC_PB = 0x40000000, + CHANNEL_REC = 0x80000000, CHANNEL_REC_PB = 0xc0000000 +}; + enum miscint_bits { PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002, SB_IRQ = 0x00000004, MPU401_IRQ = 0x00000008, @@ -184,31 +190,13 @@ ST_IRQ_EN = 0x00800000, ACGPIO_IRQ = 0x01000000 }; -#define IWriteAinten( x ) \ - {int i; \ - for( i= 0; i < ChanDwordCount; i++) \ - outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));} - -#define IReadAinten( x ) \ - {int i; \ - for( i= 0; i < ChanDwordCount; i++) \ - (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));} - -#define ReadAint( x ) \ - IReadAint( x ) - -#define WriteAint( x ) \ - IWriteAint( x ) - -#define IWriteAint( x ) \ - {int i; \ - for( i= 0; i < ChanDwordCount; i++) \ - outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));} - -#define IReadAint( x ) \ - {int i; \ - for( i= 0; i < ChanDwordCount; i++) \ - (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));} +#define AC97_SIGMATEL_DAC2INVERT 0x6E +#define AC97_SIGMATEL_BIAS1 0x70 +#define AC97_SIGMATEL_BIAS2 0x72 +#define AC97_SIGMATEL_CIC1 0x76 +#define AC97_SIGMATEL_CIC2 0x78 + +#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) ) #define VALIDATE_MAGIC(FOO,MAG) \ ({ \ @@ -220,6 +208,32 @@ #define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC) #define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC) + + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} #endif /* __TRID4DWAVE_H */ diff -ur --new-file old/linux/drivers/usb/Config.in new/linux/drivers/usb/Config.in --- old/linux/drivers/usb/Config.in Thu Jan 27 16:40:16 2000 +++ new/linux/drivers/usb/Config.in Mon Jan 31 19:10:07 2000 @@ -9,6 +9,7 @@ comment 'USB Controllers' dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB + dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB comment 'Miscellaneous USB options' diff -ur --new-file old/linux/drivers/usb/Makefile new/linux/drivers/usb/Makefile --- old/linux/drivers/usb/Makefile Thu Jan 27 16:40:16 2000 +++ new/linux/drivers/usb/Makefile Mon Jan 31 19:10:07 2000 @@ -45,6 +45,7 @@ obj-$(CONFIG_USB) += usbcore.o obj-$(CONFIG_USB_UHCI) += usb-uhci.o +obj-$(CONFIG_USB_UHCI_ALT) += uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o @@ -107,3 +108,4 @@ usb-storage.o: $(usb-storage-objs) $(LD) -r -o $@ $(usb-storage-objs) + diff -ur --new-file old/linux/drivers/usb/acm.c new/linux/drivers/usb/acm.c --- old/linux/drivers/usb/acm.c Tue Jan 18 01:24:48 2000 +++ new/linux/drivers/usb/acm.c Mon Jan 31 19:09:22 2000 @@ -1,5 +1,5 @@ /* - * acm.c Version 0.14 + * acm.c Version 0.15 * * Copyright (c) 1999 Armin Fuerst * Copyright (c) 1999 Pavel Machek @@ -17,6 +17,7 @@ * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced * v0.13 - added termios, added hangup * v0.14 - sized down struct acm + * v0.15 - fixed flow control again - characters could be lost */ /* @@ -137,6 +138,7 @@ unsigned int writesize; /* max packet size for the output bulk endpoint */ unsigned int used; /* someone has this acm's device open */ unsigned int minor; /* acm minor number */ + unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ }; @@ -210,8 +212,6 @@ dr->request, dr->index, dr->length, data[0], data[1]); return; } - - return; } static void acm_read_bulk(struct urb *urb) @@ -219,24 +219,25 @@ struct acm *acm = urb->context; struct tty_struct *tty = acm->tty; unsigned char *data = urb->transfer_buffer; - int i; + int i = 0; if (!ACM_READY(acm)) return; - if (!urb->status) { - - for (i = 0; i < urb->actual_length; i++) + if (!urb->status & !acm->throttle) { + for (i = 0; i < urb->actual_length && !acm->throttle; i++) tty_insert_flip_char(tty, data[i], 0); - tty_flip_buffer_push(tty); - } else dbg("nonzero read bulk status received: %d", urb->status); - if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); - - return; + if (!acm->throttle) { + urb->actual_length = 0; + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + } else { + memmove(data, data + i, urb->actual_length - i); + urb->actual_length -= i; + } } static void acm_write_bulk(struct urb *urb) @@ -253,8 +254,6 @@ (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); - - return; } /* @@ -347,15 +346,16 @@ { struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return; - usb_unlink_urb(&acm->readurb); + acm->throttle = 1; } static void acm_tty_unthrottle(struct tty_struct *tty) { struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return; - if (usb_submit_urb(&acm->readurb)) - dbg("usb_submit_urb(read bulk) in unthrottle() failed"); + acm->throttle = 0; + if (acm->readurb.status != -EINPROGRESS) + acm_read_bulk(&acm->readurb); } static void acm_tty_break_ctl(struct tty_struct *tty, int state) diff -ur --new-file old/linux/drivers/usb/ov511.c new/linux/drivers/usb/ov511.c --- old/linux/drivers/usb/ov511.c Mon Jan 24 07:39:14 2000 +++ new/linux/drivers/usb/ov511.c Mon Jan 31 19:09:30 2000 @@ -931,7 +931,7 @@ err("ov511_init_isoc: usb_run_isoc(0) ret %d", err); err = usb_submit_urb(ov511->sbuf[1].urb); if (err) - err("ov511_init_isoc: usb_run_isoc(1) ret %d\n", err); + err("ov511_init_isoc: usb_run_isoc(1) ret %d", err); ov511->streaming = 1; diff -ur --new-file old/linux/drivers/usb/printer.c new/linux/drivers/usb/printer.c --- old/linux/drivers/usb/printer.c Thu Jan 20 18:49:41 2000 +++ new/linux/drivers/usb/printer.c Mon Jan 31 19:09:35 2000 @@ -125,15 +125,15 @@ if (status & LP_PERRORP) { if (status & LP_POUTPA) { - printk(KERN_INFO "usblp%d: out of paper", usblp->minor); + info("usblp%d: out of paper", usblp->minor); return -ENOSPC; } if (~status & LP_PSELECD) { - printk(KERN_INFO "usblp%d: off-line", usblp->minor); + info("usblp%d: off-line", usblp->minor); return -EIO; } if (~status & LP_PERRORP) { - printk(KERN_INFO "usblp%d: on fire", usblp->minor); + info("usblp%d: on fire", usblp->minor); return -EIO; } } @@ -229,18 +229,19 @@ if (usblp->writeurb.status == -EINPROGRESS) { usb_unlink_urb(&usblp->writeurb); - printk(KERN_ERR "usblp%d: timed out\n", usblp->minor); + err("usblp%d: timed out", usblp->minor); return -EIO; } if (!usblp->dev) return -ENODEV; - if (!usblp->writeurb.status) + if (!usblp->writeurb.status) { writecount += usblp->writeurb.transfer_buffer_length; - else { + usblp->writeurb.transfer_buffer_length = 0; + } else { if (!(retval = usblp_check_status(usblp))) { - printk(KERN_ERR "usblp%d: error %d writing to printer\n", + err("usblp%d: error %d writing to printer", usblp->minor, usblp->writeurb.status); return -EIO; } @@ -287,7 +288,7 @@ return -ENODEV; if (usblp->readurb.status) { - printk(KERN_ERR "usblp%d: error %d reading from printer\n", + err("usblp%d: error %d reading from printer", usblp->minor, usblp->readurb.status); usb_submit_urb(&usblp->readurb); return -EIO; @@ -389,7 +390,7 @@ buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp); } - printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d if %d alt %d\n", + info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); return usblp_table[minor] = usblp; diff -ur --new-file old/linux/drivers/usb/scanner.c new/linux/drivers/usb/scanner.c --- old/linux/drivers/usb/scanner.c Fri Jan 28 01:40:53 2000 +++ new/linux/drivers/usb/scanner.c Mon Jan 31 19:09:41 2000 @@ -331,7 +331,6 @@ int ep_cnt; - char *ident; char valid_device = 0; char have_bulk_in, have_bulk_out, have_intr; diff -ur --new-file old/linux/drivers/usb/uhci-debug.h new/linux/drivers/usb/uhci-debug.h --- old/linux/drivers/usb/uhci-debug.h Mon Jan 24 07:39:14 2000 +++ new/linux/drivers/usb/uhci-debug.h Mon Jan 31 19:10:07 2000 @@ -1,195 +1,260 @@ -#ifdef DEBUG +/* + * UHCI-specific debugging code. Invaluable when something + * goes wrong, but don't get in my face. + * + * Kernel visible pointers are surrounded in []'s and bus + * visible pointers are surrounded in ()'s + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt + */ -static void uhci_show_qh (puhci_desc_t qh) +#include +#include + +#include "uhci.h" + +void uhci_show_td(struct uhci_td * td) { - if (qh->type != QH_TYPE) { - dbg("qh has not QH_TYPE"); - return; + char *spid; + + printk("%08x ", td->link); + printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", + ((td->status >> 27) & 3), + (td->status & TD_CTRL_SPD) ? "SPD " : "", + (td->status & TD_CTRL_LS) ? "LS " : "", + (td->status & TD_CTRL_IOC) ? "IOC " : "", + (td->status & TD_CTRL_ACTIVE) ? "Active " : "", + (td->status & TD_CTRL_STALLED) ? "Stalled " : "", + (td->status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", + (td->status & TD_CTRL_BABBLE) ? "Babble " : "", + (td->status & TD_CTRL_NAK) ? "NAK " : "", + (td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", + (td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", + td->status & 0x7ff); + + switch (td->info & 0xff) { + case USB_PID_SETUP: + spid = "SETUP"; + break; + case USB_PID_OUT: + spid = "OUT"; + break; + case USB_PID_IN: + spid = "IN"; + break; + default: + spid = "?"; + break; } - dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh)); - if (qh->hw.qh.head & UHCI_PTR_TERM) - dbg("Head Terminate"); - else { - if (qh->hw.qh.head & UHCI_PTR_QH) - dbg("Head points to QH"); - else - dbg("Head points to TD"); + printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", + td->info >> 21, + ((td->info >> 19) & 1), + (td->info >> 15) & 15, + (td->info >> 8) & 127, + (td->info & 0xff), + spid); + printk("(buf=%08x)\n", td->buffer); +} - dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS); - } - if (qh->hw.qh.element & UHCI_PTR_TERM) - dbg("Element Terminate"); - else { +static void uhci_show_sc(int port, unsigned short status) +{ + printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", + port, + status, + (status & USBPORTSC_SUSP) ? "PortSuspend " : "", + (status & USBPORTSC_PR) ? "PortReset " : "", + (status & USBPORTSC_LSDA) ? "LowSpeed " : "", + (status & USBPORTSC_RD) ? "ResumeDetect " : "", + (status & USBPORTSC_PEC) ? "EnableChange " : "", + (status & USBPORTSC_PE) ? "PortEnabled " : "", + (status & USBPORTSC_CSC) ? "ConnectChange " : "", + (status & USBPORTSC_CCS) ? "PortConnected " : ""); +} - if (qh->hw.qh.element & UHCI_PTR_QH) - dbg("Element points to QH"); - else - dbg("Element points to TD"); - dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS); - } +void uhci_show_status(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + unsigned short usbcmd, usbstat, usbint, usbfrnum; + unsigned int flbaseadd; + unsigned char sof; + unsigned short portsc1, portsc2; + + usbcmd = inw(io_addr + 0); + usbstat = inw(io_addr + 2); + usbint = inw(io_addr + 4); + usbfrnum = inw(io_addr + 6); + flbaseadd = inl(io_addr + 8); + sof = inb(io_addr + 12); + portsc1 = inw(io_addr + 16); + portsc2 = inw(io_addr + 18); + + printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", + usbcmd, + (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", + (usbcmd & USBCMD_CF) ? "CF " : "", + (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", + (usbcmd & USBCMD_FGR) ? "FGR " : "", + (usbcmd & USBCMD_EGSM) ? "EGSM " : "", + (usbcmd & USBCMD_GRESET) ? "GRESET " : "", + (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", + (usbcmd & USBCMD_RS) ? "RS " : ""); + + printk(" usbstat = %04x %s%s%s%s%s%s\n", + usbstat, + (usbstat & USBSTS_HCH) ? "HCHalted " : "", + (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", + (usbstat & USBSTS_HSE) ? "HostSystemError " : "", + (usbstat & USBSTS_RD) ? "ResumeDetect " : "", + (usbstat & USBSTS_ERROR) ? "USBError " : "", + (usbstat & USBSTS_USBINT) ? "USBINT " : ""); + + printk(" usbint = %04x\n", usbint); + printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, + 0xfff & (4*(unsigned int)usbfrnum)); + printk(" flbaseadd = %08x\n", flbaseadd); + printk(" sof = %02x\n", sof); + uhci_show_sc(1, portsc1); + uhci_show_sc(2, portsc2); } -#endif -static void uhci_show_td (puhci_desc_t td) +#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) + +struct uhci_td *uhci_link_to_td(unsigned int link) { - char *spid; - warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td)); + if (link & UHCI_PTR_TERM) + return NULL; - switch (td->hw.td.info & 0xff) { - case USB_PID_SETUP: - spid = "SETUP"; - break; - case USB_PID_OUT: - spid = " OUT "; - break; - case USB_PID_IN: - spid = " IN "; - break; - default: - spid = " ? "; - break; - } - - warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)", - td->hw.td.info >> 21, - ((td->hw.td.info >> 19) & 1), - (td->hw.td.info >> 15) & 15, - (td->hw.td.info >> 8) & 127, - (td->hw.td.info & 0xff), - spid, - td->hw.td.buffer); - - warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s", - td->hw.td.status & 0x7ff, - ((td->hw.td.status >> 27) & 3), - (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "", - (td->hw.td.status & TD_CTRL_LS) ? "LS " : "", - (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "", - (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "", - (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "", - (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", - (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "", - (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "", - (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", - (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : "" - ); -#if 1 - if (td->hw.td.link & UHCI_PTR_TERM) - warn("Link Terminate"); - else { - if (td->hw.td.link & UHCI_PTR_QH) - warn("%s, link points to QH @ %08x", - (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"), - td->hw.td.link & ~UHCI_PTR_BITS); - else - warn("%s, link points to TD @ %08x", - (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"), - td->hw.td.link & ~UHCI_PTR_BITS); - } -#endif -} -#ifdef DEBUG -static void uhci_show_td_queue (puhci_desc_t td) -{ - dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td)); - while (1) { - uhci_show_td (td); - if (td->hw.td.link & UHCI_PTR_TERM) - break; - //if(!(td->hw.td.link&UHCI_PTR_DEPTH)) - // break; - if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS)) - td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS); - else { - dbg("td points to itself!"); - break; - } -// schedule(); - } + return bus_to_virt(link & ~UHCI_PTR_BITS); } -static void uhci_show_queue (puhci_desc_t qh) +void uhci_show_queue(struct uhci_qh *qh) { - dbg("uhci_show_queue %p:", qh); - while (1) { - uhci_show_qh (qh); + struct uhci_td *td, *first; + int i = 0, count = 1000; - if (qh->hw.qh.element & UHCI_PTR_QH) - dbg("Warning: qh->element points to qh!"); - else if (!(qh->hw.qh.element & UHCI_PTR_TERM)) - uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS)); + if (qh->element & UHCI_PTR_QH) + printk(" Element points to QH (bug?)\n"); - if (qh->hw.qh.head & UHCI_PTR_TERM) - break; + if (qh->element & UHCI_PTR_DEPTH) + printk(" Depth traverse\n"); - if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS)) - qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS); - else { - dbg("qh points to itself!"); + if (qh->element & UHCI_PTR_TERM) + printk(" Terminate\n"); + + if (!(qh->element & ~UHCI_PTR_BITS)) { + printk(" td 0: [NULL]\n"); + return; + } + + first = uhci_link_to_td(qh->element); + + /* Make sure it doesn't runaway */ + for (td = first; td && count > 0; + td = uhci_link_to_td(td->link), --count) { + printk(" td %d: [%p]\n", i++, td); + printk(" "); + uhci_show_td(td); + + if (td == uhci_link_to_td(td->link)) { + printk(KERN_ERR "td links to itself!\n"); break; } } } -static void uhci_show_sc (int port, unsigned short status) +static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td) { - dbg(" stat%d = %04x %s%s%s%s%s%s%s%s", - port, - status, - (status & USBPORTSC_SUSP) ? "PortSuspend " : "", - (status & USBPORTSC_PR) ? "PortReset " : "", - (status & USBPORTSC_LSDA) ? "LowSpeed " : "", - (status & USBPORTSC_RD) ? "ResumeDetect " : "", - (status & USBPORTSC_PEC) ? "EnableChange " : "", - (status & USBPORTSC_PE) ? "PortEnabled " : "", - (status & USBPORTSC_CSC) ? "ConnectChange " : "", - (status & USBPORTSC_CCS) ? "PortConnected " : ""); + int j; + + for (j = 0; j < UHCI_NUM_SKELTD; j++) + if (td == uhci->skeltd + j) + return 1; + + return 0; } -void uhci_show_status (puhci_t s) +static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) { - unsigned int io_addr = s->io_addr; - unsigned short usbcmd, usbstat, usbint, usbfrnum; - unsigned int flbaseadd; - unsigned char sof; - unsigned short portsc1, portsc2; + int j; + + for (j = 0; j < UHCI_NUM_SKELQH; j++) + if (qh == uhci->skelqh + j) + return 1; - usbcmd = inw (io_addr + 0); - usbstat = inw (io_addr + 2); - usbint = inw (io_addr + 4); - usbfrnum = inw (io_addr + 6); - flbaseadd = inl (io_addr + 8); - sof = inb (io_addr + 12); - portsc1 = inw (io_addr + 16); - portsc2 = inw (io_addr + 18); - - dbg(" usbcmd = %04x %s%s%s%s%s%s%s%s", - usbcmd, - (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", - (usbcmd & USBCMD_CF) ? "CF " : "", - (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", - (usbcmd & USBCMD_FGR) ? "FGR " : "", - (usbcmd & USBCMD_EGSM) ? "EGSM " : "", - (usbcmd & USBCMD_GRESET) ? "GRESET " : "", - (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", - (usbcmd & USBCMD_RS) ? "RS " : ""); - - dbg(" usbstat = %04x %s%s%s%s%s%s", - usbstat, - (usbstat & USBSTS_HCH) ? "HCHalted " : "", - (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", - (usbstat & USBSTS_HSE) ? "HostSystemError " : "", - (usbstat & USBSTS_RD) ? "ResumeDetect " : "", - (usbstat & USBSTS_ERROR) ? "USBError " : "", - (usbstat & USBSTS_USBINT) ? "USBINT " : ""); - - dbg(" usbint = %04x", usbint); - dbg(" usbfrnum = (%d)%03x", (usbfrnum >> 10) & 1, - 0xfff & (4 * (unsigned int) usbfrnum)); - dbg(" flbaseadd = %08x", flbaseadd); - dbg(" sof = %02x", sof); - uhci_show_sc (1, portsc1); - uhci_show_sc (2, portsc2); + return 0; } -#endif + +static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4", + "interrupt8", "interrupt16", "interrupt32", + "interrupt64", "interrupt128", "interrupt256" }; +static const char *qh_names[] = { "control", "bulk" }; + +void uhci_show_queues(struct uhci *uhci) +{ + int i, isqh; + struct uhci_qh *qh; + struct uhci_td *td; + + for (i = 0; i < UHCI_NUMFRAMES; ++i) { + int shown = 0; + + td = uhci_link_to_td(uhci->fl->frame[i]); + if (td) + isqh = uhci->fl->frame[i] & UHCI_PTR_QH; + while (td && !isqh) { + if (uhci_is_skeleton_td(uhci, td)) + break; + + if (!shown) { + printk(" Frame %d\n", i); + shown = 1; + } + + printk("[%p] ", td); + + uhci_show_td(td); + td = uhci_link_to_td(td->link); + if (td) + isqh = td->link & UHCI_PTR_QH; + } + } + for (i = 0; i < UHCI_NUM_SKELTD; ++i) { + printk(" %s: [%p] (%08x)\n", td_names[i], + &uhci->skeltd[i], + uhci->skeltd[i].link); + + td = uhci_link_to_td(uhci->skeltd[i].link); + if (td) + isqh = uhci->skeltd[i].link & UHCI_PTR_QH; + while (td && !isqh) { + if (uhci_is_skeleton_td(uhci, td)) + break; + + printk("[%p] ", td); + + uhci_show_td(td); + td = uhci_link_to_td(td->link); + if (td) + isqh = td->link & UHCI_PTR_QH; + } + } + for (i = 0; i < UHCI_NUM_SKELQH; ++i) { + printk(" %s: [%p] (%08x) (%08x)\n", qh_names[i], + &uhci->skelqh[i], + uhci->skelqh[i].link, uhci->skelqh[i].element); + + qh = uhci_link_to_qh(uhci->skelqh[i].link); + for (; qh; qh = uhci_link_to_qh(qh->link)) { + if (uhci_is_skeleton_qh(uhci, qh)) + break; + + printk(" [%p] (%08x) (%08x)\n", + qh, qh->link, qh->element); + + uhci_show_queue(qh); + } + } +} + diff -ur --new-file old/linux/drivers/usb/uhci.c new/linux/drivers/usb/uhci.c --- old/linux/drivers/usb/uhci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/uhci.c Tue Feb 1 01:42:02 2000 @@ -0,0 +1,2214 @@ +/* + * Universal Host Controller Interface driver for USB. + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@in.tum.de + * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de + * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch + * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DEBUG +#include "usb.h" + +#include "uhci.h" +#include "uhci-debug.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +#endif + +static int debug = 1; +MODULE_PARM(debug, "i"); + +static kmem_cache_t *uhci_td_cachep; +static kmem_cache_t *uhci_qh_cachep; + +static LIST_HEAD(uhci_list); + +static int rh_submit_urb(urb_t *urb); +static int rh_unlink_urb(urb_t *urb); +static int uhci_get_current_frame_number(struct usb_device *usb_dev); + +#define min(a,b) (((a)<(b))?(a):(b)) + +/* + * Only the USB core should call uhci_alloc_dev and uhci_free_dev + */ +static int uhci_alloc_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev; + + /* Allocate the UHCI device private data */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -1; + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + atomic_set(&dev->refcnt, 1); + + if (usb_dev->parent) + dev->uhci = usb_to_uhci(usb_dev->parent)->uhci; + + return 0; +} + +static int uhci_free_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + + if (atomic_dec_and_test(&dev->refcnt)) + kfree(dev); + + return 0; +} + +static void uhci_inc_dev_use(struct uhci_device *dev) +{ + atomic_inc(&dev->refcnt); +} + +static void uhci_dec_dev_use(struct uhci_device *dev) +{ + uhci_free_dev(dev->usb); +} + +/* + * UHCI interrupt list operations.. + */ +static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td) +{ + unsigned long flags; + + nested_lock(&uhci->irqlist_lock, flags); + list_add(&td->irq_list, &uhci->interrupt_list); + nested_unlock(&uhci->irqlist_lock, flags); +} + +static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td) +{ + unsigned long flags; + + nested_lock(&uhci->irqlist_lock, flags); + if (td->irq_list.next != &td->irq_list) { + list_del(&td->irq_list); + INIT_LIST_HEAD(&td->irq_list); + } + nested_unlock(&uhci->irqlist_lock, flags); +} + +static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->urblist_lock, flags); + list_add(&urb->urb_list, &uhci->urb_list); + spin_unlock_irqrestore(&uhci->urblist_lock, flags); +} + +static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->urblist_lock, flags); + if (urb->urb_list.next != &urb->urb_list) { + list_del(&urb->urb_list); + INIT_LIST_HEAD(&urb->urb_list); + } + spin_unlock_irqrestore(&uhci->urblist_lock, flags); +} + +/* + * We insert Isochronous transfers directly into the frame list at the + * beginning + * The layout looks as follows: + * frame list pointer -> iso td's (if any) -> + * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh + */ + +static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum) +{ + unsigned long flags; + struct uhci_td *nexttd; + + framenum %= UHCI_NUMFRAMES; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + td->frameptr = &uhci->fl->frame[framenum]; + td->link = uhci->fl->frame[framenum]; + if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { + nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link); + td->nexttd = nexttd; + nexttd->prevtd = td; + nexttd->frameptr = NULL; + } + uhci->fl->frame[framenum] = virt_to_bus(td); + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + if (td->frameptr) { + *(td->frameptr) = td->link; + if (td->nexttd) { + td->nexttd->frameptr = td->frameptr; + td->nexttd->prevtd = NULL; + td->nexttd = NULL; + } + td->frameptr = NULL; + } else { + if (td->prevtd) { + td->prevtd->nexttd = td->nexttd; + td->prevtd->link = td->link; + } + if (td->nexttd) + td->nexttd->prevtd = td->prevtd; + td->prevtd = td->nexttd = NULL; + } + td->link = UHCI_PTR_TERM; + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + + /* Fix the linked list pointers */ + td->nexttd = skeltd->nexttd; + td->prevtd = skeltd; + if (skeltd->nexttd) + skeltd->nexttd->prevtd = td; + skeltd->nexttd = td; + + td->link = skeltd->link; + skeltd->link = virt_to_bus(td); + + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +/* + * Inserts a td into qh list at the top. + */ +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin) +{ + struct uhci_td *td, *prevtd; + + if (!begin) /* Nothing to do */ + return; + + /* Grab the first TD and add it to the QH */ + td = begin; + qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH; + + /* Go through the rest of the TD's, link them together */ + prevtd = td; + td = td->next; + while (td) { + prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; + + prevtd = td; + td = td->next; + } + + prevtd->link = UHCI_PTR_TERM; +} + +static struct uhci_td *uhci_td_alloc(struct uhci_device *dev) +{ + struct uhci_td *td; + + td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + if (!td) + return NULL; + + td->link = UHCI_PTR_TERM; + td->buffer = 0; + + td->frameptr = NULL; + td->nexttd = td->prevtd = NULL; + td->next = NULL; + td->dev = dev; + INIT_LIST_HEAD(&td->irq_list); + INIT_LIST_HEAD(&td->list); + + uhci_inc_dev_use(dev); + + return td; +} + +static void uhci_td_free(struct uhci_td *td) +{ + kmem_cache_free(uhci_td_cachep, td); + + if (td->dev) + uhci_dec_dev_use(td->dev); +} + +static void uhci_schedule_delete_td(struct uhci *uhci, struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->freelist_lock, flags); + list_add(&td->list, &uhci->td_free_list); + if (td->dev) { + uhci_dec_dev_use(td->dev); + td->dev = NULL; + } + spin_unlock_irqrestore(&uhci->freelist_lock, flags); +} + +static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev) +{ + struct uhci_qh *qh; + + qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + if (!qh) + return NULL; + + qh->element = UHCI_PTR_TERM; + qh->link = UHCI_PTR_TERM; + + qh->dev = dev; + qh->prevqh = qh->nextqh = NULL; + + INIT_LIST_HEAD(&qh->list); + + uhci_inc_dev_use(dev); + + return qh; +} + +static void uhci_qh_free(struct uhci_qh *qh) +{ + kmem_cache_free(uhci_qh_cachep, qh); + + if (qh->dev) + uhci_dec_dev_use(qh->dev); +} + +static void uhci_schedule_delete_qh(struct uhci *uhci, struct uhci_qh *qh) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->freelist_lock, flags); + list_add(&qh->list, &uhci->qh_free_list); + if (qh->dev) { + uhci_dec_dev_use(qh->dev); + qh->dev = NULL; + } + spin_unlock_irqrestore(&uhci->freelist_lock, flags); +} + +static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + + /* Fix the linked list pointers */ + qh->nextqh = skelqh->nextqh; + qh->prevqh = skelqh; + if (skelqh->nextqh) + skelqh->nextqh->prevqh = qh; + skelqh->nextqh = qh; + + qh->link = skelqh->link; + skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH; + + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + if (qh->prevqh) { + qh->prevqh->nextqh = qh->nextqh; + qh->prevqh->link = qh->link; + } + if (qh->nextqh) + qh->nextqh->prevqh = qh->prevqh; + qh->prevqh = qh->nextqh = NULL; + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +static void inline uhci_fill_td(struct uhci_td *td, __u32 status, + __u32 info, __u32 buffer) +{ + td->status = status; + td->info = info; + td->buffer = buffer; +} + +static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + + td->urb = urb; + + if (urbp->end) + urbp->end->next = td; + + urbp->end = td; + + if (!urbp->begin) + urbp->begin = td; +} + +/* + * Map status to standard result codes + * + * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)] + * is True for output TDs and False for input TDs. + */ +static int uhci_map_status(int status, int dir_out) +{ + if (!status) + return 0; + if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ + return -EPROTO; + if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ + if (dir_out) + return -ETIMEDOUT; + else + return -EILSEQ; + } + if (status & TD_CTRL_NAK) /* NAK */ + return -ETIMEDOUT; + if (status & TD_CTRL_BABBLE) /* Babble */ + return -EPIPE; + if (status & TD_CTRL_DBUFERR) /* Buffer error */ + return -ENOSR; + if (status & TD_CTRL_STALLED) /* Stalled */ + return -EPIPE; + if (status & TD_CTRL_ACTIVE) /* Active */ + return 0; + + return -EINVAL; +} + +/* + * Control transfers + */ +static int uhci_submit_control(urb_t *urb) +{ + struct uhci_td *td; + struct uhci_qh *qh; + unsigned long destination, status; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int len = urb->transfer_buffer_length; + unsigned char *data = urb->transfer_buffer; + struct urb_priv *urbp; + + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; + + /* 3 errors */ + status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); + + urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!urbp) + return -ENOMEM; + + urbp->begin = urbp->end = NULL; + + urb->hcpriv = urbp; + + /* + * Build the TD for the control request + */ + td = uhci_td_alloc(dev); + if (!td) + return -ENOMEM; + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status, destination | (7 << 21), + virt_to_bus(urb->setup_packet)); + + /* + * If direction is "send", change the frame from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69). + */ + destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe)); + + if (!(urb->transfer_flags & USB_DISABLE_SPD)) + status |= TD_CTRL_SPD; + + /* + * Build the DATA TD's + */ + td = uhci_td_alloc(dev); + if (!td) { + /* FIXME: Free the TD's */ + return -ENOMEM; + } + + while (len > 0) { + int pktsze = len; + + if (pktsze > maxsze) + pktsze = maxsze; + + /* Alternate Data0/1 (start with Data1) */ + destination ^= 1 << TD_TOKEN_TOGGLE; + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status, destination | ((pktsze - 1) << 21), + virt_to_bus(data)); + + data += pktsze; + len -= pktsze; + + td = uhci_td_alloc(dev); + if (!td) + /* FIXME: Free all of the previously allocated td's */ + return -ENOMEM; + } + + /* + * Build the final TD for control status + * + * It's IN if the pipe is an output pipe or we're not expecting + * data back. + */ + destination &= ~TD_PID; + if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) + destination |= USB_PID_IN; + else + destination |= USB_PID_OUT; + + destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ + + status &= ~TD_CTRL_SPD; + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status | TD_CTRL_IOC, + destination | (UHCI_NULL_DATA_SIZE << 21), 0); + + uhci_add_irq_list(uhci, td); + + qh = uhci_qh_alloc(dev); + if (!qh) { + /* FIXME: Free all of the TD's */ + return -ENOMEM; + } + uhci_insert_tds_in_qh(qh, urbp->begin); + + uhci_insert_qh(uhci, &uhci->skel_control_qh, qh); + urbp->qh = qh; + + uhci_add_urb_list(uhci, urb); + + usb_inc_dev_use(urb->dev); + + return -EINPROGRESS; +} + +static int uhci_unlink_control(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci_td *td; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + + if (!urbp) + return -EINVAL; + + uhci_remove_qh(uhci, urbp->qh); + uhci_schedule_delete_qh(uhci, urbp->qh); + + /* Go through the rest of the TD's, deleting them, then scheduling */ + /* their deletion */ + td = urbp->begin; + while (td) { + struct uhci_td *next = td->next; + + if (td->status & TD_CTRL_IOC) + uhci_remove_irq_list(uhci, td); + + uhci_schedule_delete_td(uhci, td); + + td = next; + } + + kfree(urbp); + urb->hcpriv = NULL; + + uhci_remove_urb_list(uhci, urb); + + return 0; +} + +static int uhci_result_control(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci_td *td; + unsigned int status; + int ret; + + td = urbp->begin; + if (!td) /* Nothing to do */ + return -EINVAL; + + /* The first TD is the SETUP phase, check the status, but skip */ + /* the count */ + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + if (status) + goto td_error; + + urb->actual_length = 0; + + /* The rest of the TD's (but the last) are data */ + td = td->next; + while (td && td->next) { + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + urb->actual_length += uhci_actual_length(td->status); + + /* If SPD is set then we received a short packet */ + /* There will be no status phase at the end */ + if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) + goto td_success; + + if (status) + goto td_error; + + td = td->next; + } + + /* Control status phase */ + status = uhci_status_bits(td->status); + + /* APC BackUPS Pro kludge */ + /* It tries to send all of the descriptor instead of */ + /* the amount we requested */ + if (td->status & TD_CTRL_IOC && + status & TD_CTRL_ACTIVE && + status & TD_CTRL_NAK) + goto td_success; + + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + if (status) + goto td_error; + +td_success: + uhci_unlink_control(urb); + + return 0; + +td_error: + /* Some debugging code */ + if (debug) { + dbg("uhci_result_control() failed with status %x", + status); + + /* Print the chain for debugging purposes */ + uhci_show_queue(urbp->qh); + } + + if (status & TD_CTRL_STALLED) { + /* endpoint has stalled - mark it halted */ + usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info)); + uhci_unlink_control(urb); + + return -EPIPE; + } + + ret = uhci_map_status(status, uhci_packetout(td->info)); + + uhci_unlink_control(urb); + + return ret; +} + +/* + * Interrupt transfers + */ +static int uhci_submit_interrupt(urb_t *urb) +{ + struct uhci_td *td; + unsigned long destination, status; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + struct urb_priv *urbp; + + if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) + return -EINVAL; + + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + + status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | + TD_CTRL_IOC; + + urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!urbp) + return -ENOMEM; + + urbp->begin = urbp->end = NULL; + + urb->hcpriv = urbp; + + td = uhci_td_alloc(dev); + if (!td) + return -ENOMEM; + + destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); + destination |= ((urb->transfer_buffer_length - 1) << 21); + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status, destination, + virt_to_bus(urb->transfer_buffer)); + + uhci_add_irq_list(uhci, td); + + uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td); + + uhci_add_urb_list(uhci, urb); + + usb_inc_dev_use(urb->dev); + + return -EINPROGRESS; +} + +static int uhci_unlink_interrupt(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci_td *td; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + + if (!urbp) + return -EINVAL; + + td = urbp->begin; + uhci_remove_td(uhci, td); + if (td->status & TD_CTRL_IOC) + uhci_remove_irq_list(uhci, td); + uhci_schedule_delete_td(uhci, td); + + kfree(urbp); + urb->hcpriv = NULL; + + uhci_remove_urb_list(uhci, urb); + + return 0; +} + +static int uhci_result_interrupt(urb_t *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td; + int status; + + if (!urbp) + return -EINVAL; + + td = urbp->begin; + if (!td) + return -EINVAL; + + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + if (status) + return uhci_map_status(status, uhci_packetout(td->info)); + + urb->actual_length += uhci_actual_length(td->status); + + return 0; +} + +static void uhci_reset_interrupt(urb_t *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td; + + if (urb->interval) { + td = urbp->begin; + + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; + td->info &= ~(1 << TD_TOKEN_TOGGLE); + td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); + + urb->status = -EINPROGRESS; + } else + uhci_unlink_interrupt(urb); +} + +/* + * Bulk transfers + */ +static int uhci_submit_bulk(urb_t *urb) +{ + struct uhci_td *td; + struct uhci_qh *qh; + unsigned long destination, status; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int len = urb->transfer_buffer_length; + unsigned char *data = urb->transfer_buffer; + struct urb_priv *urbp; + + if (len < 0) + return -EINVAL; + + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + + /* 3 errors */ + status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); + if (!(urb->transfer_flags & USB_DISABLE_SPD)) + status |= TD_CTRL_SPD; + + urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!urbp) + return -ENOMEM; + + urbp->begin = urbp->end = NULL; + + urb->hcpriv = urbp; + + /* + * Build the DATA TD's + */ + while (len > 0) { + int pktsze = len; + + if (pktsze > maxsze) + pktsze = maxsze; + + td = uhci_td_alloc(dev); + if (!td) { + /* FIXME: Free the TD's */ + return -ENOMEM; + } + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) | + (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE), + virt_to_bus(data)); + + data += pktsze; + len -= maxsze; + + if (len <= 0) { + td->status |= TD_CTRL_IOC; + uhci_add_irq_list(uhci, td); + } + + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); + } + + qh = uhci_qh_alloc(dev); + if (!qh) { + /* FIXME: Free all of the TD's */ + return -ENOMEM; + } + uhci_insert_tds_in_qh(qh, urbp->begin); + + uhci_insert_qh(dev->uhci, &dev->uhci->skel_bulk_qh, qh); + urbp->qh = qh; + + uhci_add_urb_list(uhci, urb); + + usb_inc_dev_use(urb->dev); + + return -EINPROGRESS; +} + +/* We can use the control unlink since they're identical */ +#define uhci_unlink_bulk uhci_unlink_control + +static int uhci_result_bulk(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci_td *td; + unsigned int status; + + urb->actual_length = 0; + + /* The rest of the TD's (but the last) are data */ + for (td = urbp->begin; td; td = td->next) { + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + urb->actual_length += uhci_actual_length(td->status); + + /* If SPD is set then we received a short packet */ + if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) { + usb_settoggle(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info), + uhci_toggle(td->info) ^ 1); + + goto td_success; + } + + if (status) + goto td_error; + } + +td_success: + uhci_unlink_bulk(urb); + + return 0; + +td_error: + /* Some debugging code */ + if (debug) { + dbg("uhci_result_bulk() failed with status %x", + status); + + /* Print the chain for debugging purposes */ + uhci_show_queue(urbp->qh); + } + + if (status & TD_CTRL_STALLED) { + /* endpoint has stalled - mark it halted */ + usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info)); + return -EPIPE; + } + + return uhci_map_status(status, uhci_packetout(td->info)); +} + +/* + * Isochronous transfers + */ +static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end) +{ + urb_t *u, *last_urb = NULL; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct list_head *tmp, *head = &uhci->urb_list; + unsigned long flags; + + spin_lock_irqsave(&uhci->urblist_lock, flags); + tmp = head->next; + while (tmp != head) { + u = list_entry(tmp, urb_t, urb_list); + + /* look for pending URB's with identical pipe handle */ + if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && + (u->status == -EINPROGRESS) && (u != urb)) { + if (!last_urb) + *start = u->start_frame; + last_urb = u; + } + tmp = tmp->next; + } + spin_unlock_irqrestore(&uhci->urblist_lock, flags); + + if (last_urb) { + *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023; + return 0; + } else + return -1; // no previous urb found + +} + +static int isochronous_find_start(urb_t *urb) +{ + int limits; + unsigned int start = 0, end = 0; + + if (urb->number_of_packets > 900) /* 900? Why? */ + return -EFBIG; + + limits = isochronous_find_limits(urb, &start, &end); + + if (urb->transfer_flags & USB_ISO_ASAP) { + if (limits) { + int curframe; + + curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES; + urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES; + } else + urb->start_frame = end; + } else { + urb->start_frame %= UHCI_NUMFRAMES; + /* FIXME: Sanity check */ + } + + return 0; +} + +static int uhci_submit_isochronous(urb_t *urb) +{ + struct uhci_td *td; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + struct urb_priv *urbp; + int i, ret, framenum; + int status, destination; + + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + + ret = isochronous_find_start(urb); + if (ret) + return ret; + + urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!urbp) + return -ENOMEM; + + urbp->begin = urbp->end = NULL; + + urb->hcpriv = urbp; + + framenum = urb->start_frame; + for (i = 0; i < urb->number_of_packets; i++, framenum++) { + if (!urb->iso_frame_desc[i].length) + continue; + + td = uhci_td_alloc(dev); + if (!td) { + /* FIXME: Free the TD's */ + return -ENOMEM; + } + + uhci_add_td_to_urb(urb, td); + uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21), + virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset)); + + if (i + 1 >= urb->number_of_packets) { + td->status |= TD_CTRL_IOC; + uhci_add_irq_list(uhci, td); + } + + uhci_insert_td_frame_list(uhci, td, framenum); + } + + uhci_add_urb_list(uhci, urb); + + usb_inc_dev_use(urb->dev); + + return -EINPROGRESS; +} + +static int uhci_unlink_isochronous(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci_td *td; + struct uhci_device *dev = usb_to_uhci(urb->dev); + struct uhci *uhci = dev->uhci; + + if (!urbp) + return -EINVAL; + + /* Go through the rest of the TD's, deleting them, then scheduling */ + /* their deletion */ + td = urbp->begin; + while (td) { + struct uhci_td *next = td->next; + + uhci_remove_td(uhci, td); + + if (td->status & TD_CTRL_IOC) + uhci_remove_irq_list(uhci, td); + uhci_schedule_delete_td(uhci, td); + + td = next; + } + + kfree(urbp); + urb->hcpriv = NULL; + + uhci_remove_urb_list(uhci, urb); + + return 0; +} + +static int uhci_result_isochronous(urb_t *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td; + int status; + int i, ret = 0; + + td = urbp->end; + if (!td) /* Nothing to do */ + return -EINVAL; + + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + + /* Assume no errors, we'll overwrite this if not */ + urb->status = 0; + + urb->actual_length = 0; + for (i = 0, td = urbp->begin; td; i++, td = td->next) { + int actlength; + + actlength = uhci_actual_length(td->status); + urb->iso_frame_desc[i].actual_length = actlength; + urb->actual_length += actlength; + + status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe)); + urb->iso_frame_desc[i].status = status; + if (status != 0) { + urb->error_count++; + ret = status; + } + } + + uhci_unlink_isochronous(urb); + + return status; +} + +static int uhci_submit_urb(urb_t *urb) +{ + int ret = -EINVAL; + struct uhci *uhci; + + if (!urb) + return -EINVAL; + + if (!urb->dev || !urb->dev->bus) + return -ENODEV; + + uhci = (struct uhci *)urb->dev->bus->hcpriv; + + if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) + return rh_submit_urb(urb); /* Virtual root hub */ + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + ret = uhci_submit_control(urb); + break; + case PIPE_INTERRUPT: + ret = uhci_submit_interrupt(urb); + break; + case PIPE_BULK: + ret = uhci_submit_bulk(urb); + break; + case PIPE_ISOCHRONOUS: + ret = uhci_submit_isochronous(urb); + break; + } + + urb->status = ret; + if (ret == -EINPROGRESS) { + usb_inc_dev_use(urb->dev); + + return 0; + } + + return ret; +} + +/* + * Return the result of a transfer + */ +static void uhci_transfer_result(urb_t *urb) +{ + urb_t *turb; + int proceed = 0, is_ring = 0; + int ret = -EINVAL; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + ret = uhci_result_control(urb); + break; + case PIPE_INTERRUPT: + /* Interrupts are an exception */ + urb->status = uhci_result_interrupt(urb); + if (urb->status != -EINPROGRESS) { + urb->complete(urb); + uhci_reset_interrupt(urb); + } + return; + case PIPE_BULK: + ret = uhci_result_bulk(urb); + break; + case PIPE_ISOCHRONOUS: + ret = uhci_result_isochronous(urb); + break; + } + + urb->status = ret; + if (urb->status == -EINPROGRESS) + return; + + if (urb->next) { + turb = urb->next; + do { + if (turb->status != -EINPROGRESS) { + proceed = 1; + break; + } + + turb = turb->next; + } while (turb && turb != urb && turb != urb->next); + + if (turb == urb || turb == urb->next) + is_ring = 1; + } + + if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) { + urb->complete(urb); + if (!proceed && is_ring) + uhci_submit_urb(urb); + } + + if (proceed && urb->next) { + turb = urb->next; + do { + if (turb->status != -EINPROGRESS && + uhci_submit_urb(turb) != 0) + + turb = turb->next; + } while (turb && turb != urb->next); + + if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) + urb->complete(urb); + } + + usb_dec_dev_use(urb->dev); +} + +static int uhci_unlink_urb(urb_t *urb) +{ + struct uhci *uhci; + int ret = 0; + + if (!urb) + return -EINVAL; + + uhci = (struct uhci *)urb->dev->bus->hcpriv; + + if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) + return rh_unlink_urb(urb); + + if (urb->status == -EINPROGRESS) { + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + ret = uhci_unlink_control(urb); + break; + case PIPE_INTERRUPT: + ret = uhci_unlink_interrupt(urb); + break; + case PIPE_BULK: + ret = uhci_unlink_bulk(urb); + break; + case PIPE_ISOCHRONOUS: + ret = uhci_unlink_isochronous(urb); + break; + } + + if (urb->complete) + urb->complete(urb); + + if (in_interrupt()) { /* wait at least 1 frame */ + int errorcount = 10; + + if (errorcount--) + dbg("uhci_unlink_urb called from interrupt for urb %p", urb); + udelay(1000); + } else + schedule_timeout(1+1*HZ/1000); + + usb_dec_dev_use(urb->dev); + } + + urb->status = -ENOENT; + + return ret; +} + +/* + * uhci_get_current_frame_number() + * + * returns the current frame number for a USB bus/controller. + */ +static int uhci_get_current_frame_number(struct usb_device *usb_dev) +{ + struct uhci_device *dev = (struct uhci_device *)usb_dev->hcpriv; + + return inw(dev->uhci->io_addr + USBFRNUM); +} + +struct usb_operations uhci_device_operations = { + uhci_alloc_dev, + uhci_free_dev, + uhci_get_current_frame_number, + uhci_submit_urb, + uhci_unlink_urb +}; + +/* ------------------------------------------------------------------- + Virtual Root Hub + ------------------------------------------------------------------- */ + +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x00, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, + Bit 5 Remote-wakeup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static __u8 root_hub_hub_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +/*-------------------------------------------------------------------------*/ +/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ +static int rh_send_irq(urb_t *urb) +{ + int i, len = 1; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + unsigned int io_addr = uhci->io_addr; + __u16 data = 0; + + for (i = 0; i < uhci->rh.numports; i++) { + data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); + len = (i + 1) / 8 + 1; + } + + *(__u16 *) urb->transfer_buffer = cpu_to_le16(data); + urb->actual_length = len; + urb->status = USB_ST_NOERROR; + + if ((data > 0) && (uhci->rh.send != 0)) { +#ifdef DEBUG /* JE */ +static int foo=5; +if (foo--) +#endif + dbg("root-hub INT complete: port1: %x port2: %x data: %x", + inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data); + urb->complete(urb); + } + + return USB_ST_NOERROR; +} + +/*-------------------------------------------------------------------------*/ +/* Virtual Root Hub INTs are polled by this timer every "interval" ms */ +static int rh_init_int_timer(urb_t *urb); + +static void rh_int_timer_do(unsigned long ptr) +{ + int len; + urb_t *urb = (urb_t *)ptr; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + + if (uhci->rh.send) { + len = rh_send_irq(urb); + if (len > 0) { + urb->actual_length = len; + if (urb->complete) + urb->complete(urb); + } + } + + rh_init_int_timer(urb); +} + +/*-------------------------------------------------------------------------*/ +/* Root Hub INTs are polled by this timer */ +static int rh_init_int_timer(urb_t *urb) +{ + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + + uhci->rh.interval = urb->interval; + init_timer(&uhci->rh.rh_int_timer); + uhci->rh.rh_int_timer.function = rh_int_timer_do; + uhci->rh.rh_int_timer.data = (unsigned long)urb; + uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000; + add_timer(&uhci->rh.rh_int_timer); + + return 0; +} + +/*-------------------------------------------------------------------------*/ +#define OK(x) len = (x); break + +#define CLR_RH_PORTSTAT(x) \ + status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ + status = (status & 0xfff5) & ~(x); \ + outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) + +#define SET_RH_PORTSTAT(x) \ + status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ + status = (status & 0xfff5) | (x); \ + outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) + + +/*-------------------------------------------------------------------------*/ +/************************* + ** Root Hub Control Pipe + *************************/ + +static int rh_submit_urb(urb_t *urb) +{ + struct usb_device *usb_dev = urb->dev; + struct uhci *uhci = (struct uhci *)usb_dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + devrequest *cmd = (devrequest *)urb->setup_packet; + void *data = urb->transfer_buffer; + int leni = urb->transfer_buffer_length; + int len = 0; + int status = 0; + int stat = USB_ST_NOERROR; + int i; + unsigned int io_addr = uhci->io_addr; + __u16 cstatus; + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + + if (usb_pipetype(pipe) == PIPE_INTERRUPT) { + uhci->rh.urb = urb; + uhci->rh.send = 1; + uhci->rh.interval = urb->interval; + rh_init_int_timer(urb); + + return USB_ST_NOERROR; + } + + bmRType_bReq = cmd->requesttype | cmd->request << 8; + wValue = le16_to_cpu(cmd->value); + wIndex = le16_to_cpu(cmd->index); + wLength = le16_to_cpu(cmd->length); + + for (i = 0; i < 8; i++) + uhci->rh.c_p_r[i] = 0; + + switch (bmRType_bReq) { + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(__u16 *)data = cpu_to_le16(1); + OK(2); + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *)data = cpu_to_le16(0); + OK(2); + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *)data = cpu_to_le16(0); + OK(2); + case RH_GET_STATUS | RH_CLASS: + *(__u32 *)data = cpu_to_le32(0); + OK(4); /* hub power */ + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1)); + cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) | + ((status & USBPORTSC_PEC) >> (3 - 1)) | + (uhci->rh.c_p_r[wIndex - 1] << (0 + 4)); + status = (status & USBPORTSC_CCS) | + ((status & USBPORTSC_PE) >> (2 - 1)) | + ((status & USBPORTSC_SUSP) >> (12 - 2)) | + ((status & USBPORTSC_PR) >> (9 - 4)) | + (1 << 8) | /* power on */ + ((status & USBPORTSC_LSDA) << (-8 + 9)); + + *(__u16 *)data = cpu_to_le16(status); + *(__u16 *)(data + 2) = cpu_to_le16(cstatus); + OK(4); + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case RH_ENDPOINT_STALL: + OK(0); + } + break; + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case RH_C_HUB_OVER_CURRENT: + OK(0); /* hub power over current */ + } + break; + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case RH_PORT_ENABLE: + CLR_RH_PORTSTAT(USBPORTSC_PE); + OK(0); + case RH_PORT_SUSPEND: + CLR_RH_PORTSTAT(USBPORTSC_SUSP); + OK(0); + case RH_PORT_POWER: + OK(0); /* port power */ + case RH_C_PORT_CONNECTION: + SET_RH_PORTSTAT(USBPORTSC_CSC); + OK(0); + case RH_C_PORT_ENABLE: + SET_RH_PORTSTAT(USBPORTSC_PEC); + OK(0); + case RH_C_PORT_SUSPEND: + /*** WR_RH_PORTSTAT(RH_PS_PSSC); */ + OK(0); + case RH_C_PORT_OVER_CURRENT: + OK(0); /* port power over current */ + case RH_C_PORT_RESET: + uhci->rh.c_p_r[wIndex - 1] = 0; + OK(0); + } + break; + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case RH_PORT_SUSPEND: + SET_RH_PORTSTAT(USBPORTSC_SUSP); + OK(0); + case RH_PORT_RESET: + SET_RH_PORTSTAT(USBPORTSC_PR); + wait_ms(10); + uhci->rh.c_p_r[wIndex - 1] = 1; + CLR_RH_PORTSTAT(USBPORTSC_PR); + udelay(10); + SET_RH_PORTSTAT(USBPORTSC_PE); + wait_ms(10); + SET_RH_PORTSTAT(0xa); + OK(0); + case RH_PORT_POWER: + OK(0); /* port power ** */ + case RH_PORT_ENABLE: + SET_RH_PORTSTAT (USBPORTSC_PE); + OK(0); + } + break; + case RH_SET_ADDRESS: + uhci->rh.devnum = wValue; + OK(0); + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case 0x01: /* device descriptor */ + len = min(leni, min(sizeof(root_hub_dev_des), wLength)); + memcpy(data, root_hub_dev_des, len); + OK(len); + case 0x02: /* configuration descriptor */ + len = min(leni, min(sizeof(root_hub_config_des), wLength)); + memcpy (data, root_hub_config_des, len); + OK(len); + case 0x03: /* string descriptors */ + stat = -EPIPE; + } + break; + case RH_GET_DESCRIPTOR | RH_CLASS: + root_hub_hub_des[2] = uhci->rh.numports; + len = min(leni, min(sizeof(root_hub_hub_des), wLength)); + memcpy(data, root_hub_hub_des, len); + OK(len); + case RH_GET_CONFIGURATION: + *(__u8 *)data = 0x01; + OK(1); + case RH_SET_CONFIGURATION: + OK(0); + default: + stat = -EPIPE; + } + + urb->actual_length = len; + urb->status = stat; + if (urb->complete) + urb->complete(urb); + + return USB_ST_NOERROR; +} +/*-------------------------------------------------------------------------*/ + +static int rh_unlink_urb(urb_t *urb) +{ + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + + uhci->rh.send = 0; + del_timer(&uhci->rh.rh_int_timer); + + return 0; +} +/*-------------------------------------------------------------------*/ + +/* + * This is just incredibly fragile. The timings must be just + * right, and they aren't really documented very well. + * + * Note the short delay between disabling reset and enabling + * the port.. + */ +static void uhci_reset_port(unsigned int port) +{ + unsigned short status; + + status = inw(port); + outw(status | USBPORTSC_PR, port); /* reset port */ + wait_ms(10); + outw(status & ~USBPORTSC_PR, port); + udelay(50); + + status = inw(port); + outw(status | USBPORTSC_PE, port); /* enable port */ + wait_ms(10); + + status = inw(port); + if (!(status & USBPORTSC_PE)) { + outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ + wait_ms(50); + } + +} + +void uhci_free_pending(struct uhci *uhci) +{ + struct list_head *tmp, *head; + + /* Free all of the pending QH's and TD's */ + head = &uhci->td_free_list; + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + + tmp = tmp->next; + + list_del(&td->list); + INIT_LIST_HEAD(&td->list); + + uhci_td_free(td); + } + + head = &uhci->qh_free_list; + tmp = head->next; + while (tmp != head) { + struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, list); + + tmp = tmp->next; + + list_del(&qh->list); + INIT_LIST_HEAD(&qh->list); + + uhci_qh_free(qh); + } +} + +static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) +{ + struct uhci *uhci = __uhci; + unsigned int io_addr = uhci->io_addr; + unsigned short status; + unsigned long flags; + struct list_head *tmp, *head; + urb_t *urb; + + /* + * Read the interrupt status, and write it back to clear the + * interrupt cause + */ + status = inw(io_addr + USBSTS); + if (!status) /* shared interrupt, not mine */ + return; + outw(status, io_addr + USBSTS); + + if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) { + if (status & USBSTS_RD) + printk(KERN_INFO "uhci: resume detected, not implemented\n"); + if (status & USBSTS_HSE) + printk(KERN_ERR "uhci: host system error, PCI problems?\n"); + if (status & USBSTS_HCPE) + printk(KERN_ERR "uhci: host controller process error. something bad happened\n"); + if (status & USBSTS_HCH) { + printk(KERN_ERR "uhci: host controller halted. very bad\n"); + /* FIXME: Reset the controller, fix the offending TD */ + } + } + + /* Free all of the pending QH's and TD's */ + spin_lock(&uhci->freelist_lock); + uhci_free_pending(uhci); + spin_unlock(&uhci->freelist_lock); + + /* Walk the list of pending TD's to see which ones completed.. */ + nested_lock(&uhci->irqlist_lock, flags); + head = &uhci->interrupt_list; + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); + + urb = td->urb; + + tmp = tmp->next; + + /* Checks the status and does all of the magic necessary */ + uhci_transfer_result(urb); + } + nested_unlock(&uhci->irqlist_lock, flags); +} + +static void reset_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + + /* Global reset for 50ms */ + outw(USBCMD_GRESET, io_addr + USBCMD); + wait_ms(50); + outw(0, io_addr + USBCMD); + wait_ms(10); +} + +static void start_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + int timeout = 1000; + + /* + * Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(USBCMD_HCRESET, io_addr + USBCMD); + while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { + if (!--timeout) { + printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n"); + break; + } + } + + /* Turn on all interrupts */ + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, + io_addr + USBINTR); + + /* Start at frame 0 */ + outw(0, io_addr + USBFRNUM); + outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD); + + /* Run and mark it configured with a 64-byte max packet */ + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); +} + +/* + * Allocate a frame list, and then setup the skeleton + * + * The hardware doesn't really know any difference + * in the queues, but the order does matter for the + * protocols higher up. The order is: + * + * - any isochronous events handled before any + * of the queues. We don't do that here, because + * we'll create the actual TD entries on demand. + * - The first queue is the "interrupt queue". + * - The second queue is the "control queue". + * - The third queue is "bulk data". + */ +static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) +{ + int i, port; + struct uhci *uhci; + struct usb_bus *bus; + + uhci = kmalloc(sizeof(*uhci), GFP_KERNEL); + if (!uhci) + return NULL; + + memset(uhci, 0, sizeof(*uhci)); + + uhci->irq = -1; + uhci->io_addr = io_addr; + uhci->io_size = io_size; + + INIT_LIST_HEAD(&uhci->interrupt_list); + INIT_LIST_HEAD(&uhci->urb_list); + INIT_LIST_HEAD(&uhci->td_free_list); + INIT_LIST_HEAD(&uhci->qh_free_list); + + spin_lock_init(&uhci->urblist_lock); + spin_lock_init(&uhci->framelist_lock); + spin_lock_init(&uhci->freelist_lock); + nested_init(&uhci->irqlist_lock); + + /* We need exactly one page (per UHCI specs), how convenient */ + /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */ + uhci->fl = (void *)__get_free_page(GFP_KERNEL); + if (!uhci->fl) + goto au_free_uhci; + + bus = usb_alloc_bus(&uhci_device_operations); + if (!bus) + goto au_free_fl; + + uhci->bus = bus; + bus->hcpriv = uhci; + + /* Initialize the root hub */ + + /* UHCI specs says devices must have 2 ports, but goes on to say */ + /* they may have more but give no way to determine how many they */ + /* have. However, according to the UHCI spec, Bit 7 is always set */ + /* to 1. So we try to use this to our advantage */ + for (port = 0; port < (io_size - 0x10) / 2; port++) { + unsigned int portstatus; + + portstatus = inw(io_addr + 0x10 + (port * 2)); + if (!(portstatus & 0x0080)) + break; + } + if (debug) + info("detected %d ports", port); + + /* This is experimental so anything less than 2 or greater than 8 is */ + /* something weird and we'll ignore it */ + if (port < 2 || port > 8) { + info("port count misdetected? forcing to 2 ports"); + port = 2; + } + + uhci->rh.numports = port; + + /* + * 9 Interrupt queues; link int2 to int1, int4 to int2, etc + * then link int1 to control and control to bulk + */ + for (i = 1; i < 9; i++) { + struct uhci_td *td = &uhci->skeltd[i]; + + uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); + td->link = virt_to_bus(&uhci->skeltd[i - 1]); + } + + + uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); + uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH; + + uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH; + uhci->skel_control_qh.element = UHCI_PTR_TERM; + + uhci->skel_bulk_qh.link = UHCI_PTR_TERM; + uhci->skel_bulk_qh.element = UHCI_PTR_TERM; + + /* + * Fill the frame list: make all entries point to + * the proper interrupt queue. + * + * This is probably silly, but it's a simple way to + * scatter the interrupt queues in a way that gives + * us a reasonable dynamic range for irq latencies. + */ + for (i = 0; i < 1024; i++) { + struct uhci_td *irq = &uhci->skel_int2_td; + + if (i & 1) { + irq++; + if (i & 2) { + irq++; + if (i & 4) { + irq++; + if (i & 8) { + irq++; + if (i & 16) { + irq++; + if (i & 32) { + irq++; + if (i & 64) + irq++; + } + } + } + } + } + } + + /* Only place we don't use the frame list routines */ + uhci->fl->frame[i] = virt_to_bus(irq); + } + + return uhci; + +/* + * error exits: + */ +au_free_fl: + free_page((unsigned long)uhci->fl); +au_free_uhci: + kfree(uhci); + + return NULL; +} + +/* + * De-allocate all resources.. + */ +static void release_uhci(struct uhci *uhci) +{ + if (uhci->irq >= 0) { + free_irq(uhci->irq, uhci); + uhci->irq = -1; + } + + if (uhci->fl) { + free_page((unsigned long)uhci->fl); + uhci->fl = NULL; + } + + usb_free_bus(uhci->bus); + kfree(uhci); +} + +int uhci_start_root_hub(struct uhci *uhci) +{ + struct usb_device *usb_dev; + + usb_dev = usb_alloc_dev(NULL, uhci->bus); + if (!usb_dev) + return -1; + + usb_to_uhci(usb_dev)->uhci = uhci; + + uhci->bus->root_hub = usb_dev; + usb_connect(usb_dev); + + if (usb_new_device(usb_dev) != 0) { + usb_free_dev(usb_dev); + + return -1; + } + + return 0; +} + +/* + * If we've successfully found a UHCI, now is the time to increment the + * module usage count, and return success.. + */ +static int setup_uhci(int irq, unsigned int io_addr, unsigned int io_size) +{ + int retval; + struct uhci *uhci; + + uhci = alloc_uhci(io_addr, io_size); + if (!uhci) + return -ENOMEM; + + INIT_LIST_HEAD(&uhci->uhci_list); + list_add(&uhci->uhci_list, &uhci_list); + + request_region(uhci->io_addr, io_size, "usb-uhci"); + + reset_hc(uhci); + + usb_register_bus(uhci->bus); + start_hc(uhci); + + retval = -EBUSY; + if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) { + uhci->irq = irq; + + if (!uhci_start_root_hub(uhci)) + return 0; + } + + /* Couldn't allocate IRQ if we got here */ + list_del(&uhci->uhci_list); + INIT_LIST_HEAD(&uhci->uhci_list); + + reset_hc(uhci); + release_region(uhci->io_addr, uhci->io_size); + release_uhci(uhci); + + return retval; +} + +static int found_uhci(struct pci_dev *dev) +{ + int i; + + /* Search for the IO base address.. */ + for (i = 0; i < 6; i++) { + unsigned int io_addr = dev->resource[i].start; + unsigned int io_size = + dev->resource[i].end - dev->resource[i].start + 1; + + /* IO address? */ + if (!(dev->resource[i].flags & 1)) + continue; + + /* Is it already in use? */ + if (check_region(io_addr, io_size)) + break; + + /* disable legacy emulation */ + pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + + pci_enable_device(dev); + + if (!dev->irq) { + err("found UHCI device with no IRQ assigned. check BIOS settings!"); + continue; + } + + return setup_uhci(dev->irq, io_addr, io_size); + } + + return -1; +} + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + dbg("received extra suspend event"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + dbg("received bogus resume event"); + break; + } + down = 0; + break; + } + return 0; +} +#endif + +int uhci_init(void) +{ + int retval; + struct pci_dev *dev; + u8 type; + + retval = -ENOMEM; + + /* We throw all of the TD's and QH's into a kmem cache */ + /* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */ + /* does this for us */ + uhci_td_cachep = kmem_cache_create("uhci_td", + sizeof(struct uhci_td), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + + if (!uhci_td_cachep) + goto td_failed; + + uhci_qh_cachep = kmem_cache_create("uhci_qh", + sizeof(struct uhci_qh), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + + if (!uhci_qh_cachep) + goto qh_failed; + + retval = -ENODEV; + dev = NULL; + for (;;) { + dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev); + if (!dev) + break; + + /* Is it the UHCI programming interface? */ + pci_read_config_byte(dev, PCI_CLASS_PROG, &type); + if (type != 0) + continue; + + /* Ok set it up */ + retval = found_uhci(dev); + } + + /* We only want to return an error code if ther was an error */ + /* and we didn't find a UHCI controller */ + if (retval && uhci_list.next == &uhci_list) + goto init_failed; + +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; + +init_failed: + if (kmem_cache_destroy(uhci_qh_cachep)) + printk(KERN_INFO "uhci: not all QH's were freed\n"); + +qh_failed: + if (kmem_cache_destroy(uhci_td_cachep)) + printk(KERN_INFO "uhci: not all TD's were freed\n"); + +td_failed: + return retval; +} + +void uhci_cleanup(void) +{ + struct list_head *next, *tmp, *head = &uhci_list; + int i; + unsigned long flags; + + tmp = head->next; + while (tmp != head) { + struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list); + + next = tmp->next; + + list_del(&uhci->uhci_list); + INIT_LIST_HEAD(&uhci->uhci_list); + + if (uhci->bus->root_hub) + usb_disconnect(&uhci->bus->root_hub); + + usb_deregister_bus(uhci->bus); + + reset_hc(uhci); + release_region(uhci->io_addr, uhci->io_size); + + /* Free any outstanding TD's and QH's */ + spin_lock_irqsave(&uhci->freelist_lock, flags); + uhci_free_pending(uhci); + spin_unlock_irqrestore(&uhci->freelist_lock, flags); + + release_uhci(uhci); + + tmp = next; + } + + if (kmem_cache_destroy(uhci_qh_cachep)) + printk(KERN_INFO "uhci: not all QH's were freed\n"); + + if (kmem_cache_destroy(uhci_td_cachep)) + printk(KERN_INFO "uhci: not all TD's were freed\n"); +} + +#ifdef MODULE +int init_module(void) +{ + return uhci_init(); +} + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif + uhci_cleanup(); +} +#endif //MODULE + diff -ur --new-file old/linux/drivers/usb/uhci.h new/linux/drivers/usb/uhci.h --- old/linux/drivers/usb/uhci.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/uhci.h Tue Feb 1 01:42:02 2000 @@ -0,0 +1,425 @@ +#ifndef __LINUX_UHCI_H +#define __LINUX_UHCI_H + +#include + +#include "usb.h" + +/* + * This nested spinlock code is courtesy of Davide Libenzi + */ +struct s_nested_lock { + spinlock_t lock; + void *uniq; + short int count; +}; + +#define nested_init(snl) \ + spin_lock_init(&(snl)->lock); \ + (snl)->uniq = NULL; \ + (snl)->count = 0; + +#define nested_lock(snl, flags) \ + if ((snl)->uniq == current) { \ + (snl)->count++; \ + flags = 0; /* No warnings */ \ + } else { \ + spin_lock_irqsave(&(snl)->lock, flags); \ + (snl)->count++; \ + (snl)->uniq = current; \ + } + +#define nested_unlock(snl, flags) \ + if (!--(snl)->count) { \ + (snl)->uniq = NULL; \ + spin_unlock_irqrestore(&(snl)->lock, flags); \ + } + +/* + * Universal Host Controller Interface data structures and defines + */ + +/* Command register */ +#define USBCMD 0 +#define USBCMD_RS 0x0001 /* Run/Stop */ +#define USBCMD_HCRESET 0x0002 /* Host reset */ +#define USBCMD_GRESET 0x0004 /* Global reset */ +#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define USBCMD_FGR 0x0010 /* Force Global Resume */ +#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ +#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ +#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 +#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ +#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ +#define USBSTS_RD 0x0004 /* Resume Detect */ +#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */ +#define USBSTS_HCH 0x0020 /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 +#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ +#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ +#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ +#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ + +#define USBFRNUM 6 +#define USBFLBASEADD 8 +#define USBSOF 12 + +/* USB port status and control registers */ +#define USBPORTSC1 16 +#define USBPORTSC2 18 +#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */ +#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ +#define USBPORTSC_PE 0x0004 /* Port Enable */ +#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ +#define USBPORTSC_LS 0x0030 /* Line Status */ +#define USBPORTSC_RD 0x0040 /* Resume Detect */ +#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ +#define USBPORTSC_PR 0x0200 /* Port Reset */ +#define USBPORTSC_SUSP 0x1000 /* Suspend */ + +/* Legacy support register */ +#define USBLEGSUP 0xc0 +#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ + +#define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */ + +#define UHCI_PTR_BITS 0x000F +#define UHCI_PTR_TERM 0x0001 +#define UHCI_PTR_QH 0x0002 +#define UHCI_PTR_DEPTH 0x0004 + +#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ +#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ +#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ + +struct uhci_td; + +struct uhci_qh { + /* Hardware fields */ + __u32 link; /* Next queue */ + __u32 element; /* Queue element pointer */ + + /* Software fields */ + struct uhci_qh *prevqh, *nextqh; /* Previous and next TD in queue */ + + struct uhci_device *dev; /* The owning device */ + + struct list_head list; +} __attribute__((aligned(16))); + +struct uhci_framelist { + __u32 frame[UHCI_NUMFRAMES]; +} __attribute__((aligned(4096))); + +/* + * for TD : + */ +#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ +#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ +#define TD_CTRL_LS (1 << 26) /* Low Speed Device */ +#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ +#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ +#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */ +#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */ +#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ +#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ +#define TD_CTRL_NAK (1 << 19) /* NAK Received */ +#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ +#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ +#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */ + +#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ + TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) + +#define uhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000) +#define uhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ + +#define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS) + +/* + * for TD : (a.k.a. Token) + */ +#define TD_TOKEN_TOGGLE 19 +#define TD_PID 0xFF + +#define uhci_maxlen(token) ((token) >> 21) +#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ +#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) +#define uhci_endpoint(token) (((token) >> 15) & 0xf) +#define uhci_devaddr(token) (((token) >> 8) & 0x7f) +#define uhci_devep(token) (((token) >> 8) & 0x7ff) +#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) +#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) + +/* + * The documentation says "4 words for hardware, 4 words for software". + * + * That's silly, the hardware doesn't care. The hardware only cares that + * the hardware words are 16-byte aligned, and we can have any amount of + * sw space after the TD entry as far as I can tell. + * + * But let's just go with the documentation, at least for 32-bit machines. + * On 64-bit machines we probably want to take advantage of the fact that + * hw doesn't really care about the size of the sw-only area. + * + * Alas, not anymore, we have more than 4 words for software, woops + */ +struct uhci_td { + /* Hardware fields */ + __u32 link; + __u32 status; + __u32 info; + __u32 buffer; + + /* Software fields */ + unsigned int *frameptr; /* Frame list pointer */ + struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */ + + struct uhci_device *dev; + struct urb *urb; /* URB this TD belongs to */ + struct uhci_td *next; /* List of chained TD's for an URB */ + + struct list_head irq_list; /* Active interrupt list.. */ + struct list_head list; +} __attribute__((aligned(16))); + +/* + * Note the alignment requirements of the entries + * + * Each UHCI device has pre-allocated QH and TD entries. + * You can use more than the pre-allocated ones, but I + * don't see you usually needing to. + */ +struct uhci; + +struct uhci_device { + struct usb_device *usb; + + atomic_t refcnt; + + struct uhci *uhci; /* HC this device is connected to */ +}; + +#define uhci_to_usb(uhci) ((uhci)->usb) +#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv) + +/* + * There are various standard queues. We set up several different + * queues for each of the three basic queue types: interrupt, + * control, and bulk. + * + * - There are various different interrupt latencies: ranging from + * every other USB frame (2 ms apart) to every 256 USB frames (ie + * 256 ms apart). Make your choice according to how obnoxious you + * want to be on the wire, vs how critical latency is for you. + * - The control list is done every frame. + * - There are 4 bulk lists, so that up to four devices can have a + * bulk list of their own and when run concurrently all four lists + * will be be serviced. + * + * This is a bit misleading, there are various interrupt latencies, but they + * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the + * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor + * problem + * + * In the case of the root hub, these QH's are just head's of qh's. Don't + * be scared, it kinda makes sense. Look at this wonderful picture care of + * Linus: + * + * generic- -> dev1- -> generic- -> dev1- -> control- -> bulk- -> ... + * iso-QH iso-QH irq-QH irq-QH QH QH + * | | | | | | + * End dev1-iso-TD1 End dev1-irq-TD1 ... ... + * | + * dev1-iso-TD2 + * | + * .... + * + * This may vary a bit (the UHCI docs don't explicitly say you can put iso + * transfers in QH's and all of their pictures don't have that either) but + * other than that, that is what we're doing now + * + * And now we don't put Iso transfers in QH's, so we don't waste one on it + * --jerdfelt + * + * To keep with Linus' nomenclature, this is called the QH skeleton. These + * labels (below) are only signficant to the root hub's QH's + */ + +#define UHCI_NUM_SKELTD 9 +#define skel_int1_td skeltd[0] +#define skel_int2_td skeltd[1] +#define skel_int4_td skeltd[2] +#define skel_int8_td skeltd[3] +#define skel_int16_td skeltd[4] +#define skel_int32_td skeltd[5] +#define skel_int64_td skeltd[6] +#define skel_int128_td skeltd[7] +#define skel_int256_td skeltd[8] + +#define UHCI_NUM_SKELQH 2 +#define skel_control_qh skelqh[0] +#define skel_bulk_qh skelqh[1] + +/* + * Search tree for determining where fits in the + * skelqh[] skeleton. + * + * An interrupt request should be placed into the slowest skelqh[] + * which meets the interval/period/frequency requirement. + * An interrupt request is allowed to be faster than but not slower. + * + * For a given , this function returns the appropriate/matching + * skelqh[] index value. + * + * NOTE: For UHCI, we don't really need int256_qh since the maximum interval + * is 255 ms. However, we do need an int1_qh since 1 is a valid interval + * and we should meet that frequency when requested to do so. + * This will require some change(s) to the UHCI skeleton. + */ +static inline int __interval_to_skel(int interval) +{ + if (interval < 16) { + if (interval < 4) { + if (interval < 2) + return 0; /* int1 for 0-1 ms */ + return 1; /* int2 for 2-3 ms */ + } + if (interval < 8) + return 2; /* int4 for 4-7 ms */ + return 3; /* int8 for 8-15 ms */ + } + if (interval < 64) { + if (interval < 32) + return 4; /* int16 for 16-31 ms */ + return 5; /* int32 for 32-63 ms */ + } + if (interval < 128) + return 6; /* int64 for 64-127 ms */ + return 7; /* int128 for 128-255 ms (Max.) */ +} + +struct virt_root_hub { + int devnum; /* Address of Root Hub endpoint */ + void *urb; + void *int_addr; + int send; + int interval; + int numports; + int c_p_r[8]; + struct timer_list rh_int_timer; +}; + +/* + * This describes the full uhci information. + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. + */ +struct uhci { + int irq; + unsigned int io_addr; + unsigned int io_size; + + struct list_head uhci_list; + + struct usb_bus *bus; + + struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */ + struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ + + struct uhci_framelist *fl; /* Frame list */ + + struct s_nested_lock irqlist_lock; + struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ + + spinlock_t urblist_lock; + struct list_head urb_list; + + spinlock_t framelist_lock; + + spinlock_t freelist_lock; + struct list_head td_free_list; + struct list_head qh_free_list; + + struct virt_root_hub rh; /* private data of the virtual root hub */ +}; + +struct urb_priv { + struct uhci_qh *qh; /* QH for this URB */ + struct uhci_td *begin; + struct uhci_td *end; +}; + +/* ------------------------------------------------------------------------- + Virtual Root HUB + ------------------------------------------------------------------------- */ +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +/* needed for the debugging code */ +struct uhci_td *uhci_link_to_td(unsigned int element); + +/* Debugging code */ +void uhci_show_td(struct uhci_td *td); +void uhci_show_status(struct uhci *uhci); +void uhci_show_queue(struct uhci_qh *qh); +void uhci_show_queues(struct uhci *uhci); + +#endif + diff -ur --new-file old/linux/drivers/usb/usb-core.c new/linux/drivers/usb/usb-core.c --- old/linux/drivers/usb/usb-core.c Thu Jan 27 16:40:16 2000 +++ new/linux/drivers/usb/usb-core.c Mon Jan 31 19:10:07 2000 @@ -132,6 +132,9 @@ #ifdef CONFIG_USB_UHCI uhci_init(); #endif +#ifdef CONFIG_USB_UHCI_ALT + uhci_init(); +#endif #ifdef CONFIG_USB_OHCI ohci_hcd_init(); #endif diff -ur --new-file old/linux/drivers/usb/usb-serial.c new/linux/drivers/usb/usb-serial.c --- old/linux/drivers/usb/usb-serial.c Wed Jan 26 22:15:02 2000 +++ new/linux/drivers/usb/usb-serial.c Mon Jan 31 19:09:56 2000 @@ -996,7 +996,7 @@ // dbg("whiteheat_writememory %x, %d", address, length); if (!transfer_buffer) { - err("whiteheat_writememory: kmalloc(%d) failed.\n", length); + err("whiteheat_writememory: kmalloc(%d) failed.", length); return -ENOMEM; } memcpy (transfer_buffer, data, length); @@ -1078,7 +1078,7 @@ response = whiteheat_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { - err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)\n", + err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)", response, record->address, record->data, record->data_size); break; } @@ -1127,7 +1127,7 @@ dbg("visor_serial_close port %d", port); if (!transfer_buffer) { - err("visor_serial_close: kmalloc(%d) failed.\n", 0x12); + err("visor_serial_close: kmalloc(%d) failed.", 0x12); } else { /* send a shutdown message to the device */ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, @@ -1175,7 +1175,7 @@ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL); if (!transfer_buffer) { - err("visor_startup: kmalloc(%d) failed.\n", 256); + err("visor_startup: kmalloc(%d) failed.", 256); return -ENOMEM; } diff -ur --new-file old/linux/drivers/usb/usb-uhci-debug.h new/linux/drivers/usb/usb-uhci-debug.h --- old/linux/drivers/usb/usb-uhci-debug.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/usb-uhci-debug.h Mon Jan 31 19:10:07 2000 @@ -0,0 +1,195 @@ +#ifdef DEBUG + +static void uhci_show_qh (puhci_desc_t qh) +{ + if (qh->type != QH_TYPE) { + dbg("qh has not QH_TYPE"); + return; + } + dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh)); + + if (qh->hw.qh.head & UHCI_PTR_TERM) + dbg("Head Terminate"); + else { + if (qh->hw.qh.head & UHCI_PTR_QH) + dbg("Head points to QH"); + else + dbg("Head points to TD"); + + dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS); + } + if (qh->hw.qh.element & UHCI_PTR_TERM) + dbg("Element Terminate"); + else { + + if (qh->hw.qh.element & UHCI_PTR_QH) + dbg("Element points to QH"); + else + dbg("Element points to TD"); + dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS); + } +} +#endif + +static void uhci_show_td (puhci_desc_t td) +{ + char *spid; + warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td)); + + switch (td->hw.td.info & 0xff) { + case USB_PID_SETUP: + spid = "SETUP"; + break; + case USB_PID_OUT: + spid = " OUT "; + break; + case USB_PID_IN: + spid = " IN "; + break; + default: + spid = " ? "; + break; + } + + warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)", + td->hw.td.info >> 21, + ((td->hw.td.info >> 19) & 1), + (td->hw.td.info >> 15) & 15, + (td->hw.td.info >> 8) & 127, + (td->hw.td.info & 0xff), + spid, + td->hw.td.buffer); + + warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s", + td->hw.td.status & 0x7ff, + ((td->hw.td.status >> 27) & 3), + (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "", + (td->hw.td.status & TD_CTRL_LS) ? "LS " : "", + (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "", + (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "", + (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "", + (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", + (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "", + (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "", + (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", + (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : "" + ); +#if 1 + if (td->hw.td.link & UHCI_PTR_TERM) + warn("Link Terminate"); + else { + if (td->hw.td.link & UHCI_PTR_QH) + warn("%s, link points to QH @ %08x", + (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"), + td->hw.td.link & ~UHCI_PTR_BITS); + else + warn("%s, link points to TD @ %08x", + (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"), + td->hw.td.link & ~UHCI_PTR_BITS); + } +#endif +} +#ifdef DEBUG +static void uhci_show_td_queue (puhci_desc_t td) +{ + dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td)); + while (1) { + uhci_show_td (td); + if (td->hw.td.link & UHCI_PTR_TERM) + break; + //if(!(td->hw.td.link&UHCI_PTR_DEPTH)) + // break; + if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS)) + td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS); + else { + dbg("td points to itself!"); + break; + } +// schedule(); + } +} + +static void uhci_show_queue (puhci_desc_t qh) +{ + dbg("uhci_show_queue %p:", qh); + while (1) { + uhci_show_qh (qh); + + if (qh->hw.qh.element & UHCI_PTR_QH) + dbg("Warning: qh->element points to qh!"); + else if (!(qh->hw.qh.element & UHCI_PTR_TERM)) + uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS)); + + if (qh->hw.qh.head & UHCI_PTR_TERM) + break; + + if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS)) + qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS); + else { + dbg("qh points to itself!"); + break; + } + } +} + +static void uhci_show_sc (int port, unsigned short status) +{ + dbg(" stat%d = %04x %s%s%s%s%s%s%s%s", + port, + status, + (status & USBPORTSC_SUSP) ? "PortSuspend " : "", + (status & USBPORTSC_PR) ? "PortReset " : "", + (status & USBPORTSC_LSDA) ? "LowSpeed " : "", + (status & USBPORTSC_RD) ? "ResumeDetect " : "", + (status & USBPORTSC_PEC) ? "EnableChange " : "", + (status & USBPORTSC_PE) ? "PortEnabled " : "", + (status & USBPORTSC_CSC) ? "ConnectChange " : "", + (status & USBPORTSC_CCS) ? "PortConnected " : ""); +} + +void uhci_show_status (puhci_t s) +{ + unsigned int io_addr = s->io_addr; + unsigned short usbcmd, usbstat, usbint, usbfrnum; + unsigned int flbaseadd; + unsigned char sof; + unsigned short portsc1, portsc2; + + usbcmd = inw (io_addr + 0); + usbstat = inw (io_addr + 2); + usbint = inw (io_addr + 4); + usbfrnum = inw (io_addr + 6); + flbaseadd = inl (io_addr + 8); + sof = inb (io_addr + 12); + portsc1 = inw (io_addr + 16); + portsc2 = inw (io_addr + 18); + + dbg(" usbcmd = %04x %s%s%s%s%s%s%s%s", + usbcmd, + (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", + (usbcmd & USBCMD_CF) ? "CF " : "", + (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", + (usbcmd & USBCMD_FGR) ? "FGR " : "", + (usbcmd & USBCMD_EGSM) ? "EGSM " : "", + (usbcmd & USBCMD_GRESET) ? "GRESET " : "", + (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", + (usbcmd & USBCMD_RS) ? "RS " : ""); + + dbg(" usbstat = %04x %s%s%s%s%s%s", + usbstat, + (usbstat & USBSTS_HCH) ? "HCHalted " : "", + (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", + (usbstat & USBSTS_HSE) ? "HostSystemError " : "", + (usbstat & USBSTS_RD) ? "ResumeDetect " : "", + (usbstat & USBSTS_ERROR) ? "USBError " : "", + (usbstat & USBSTS_USBINT) ? "USBINT " : ""); + + dbg(" usbint = %04x", usbint); + dbg(" usbfrnum = (%d)%03x", (usbfrnum >> 10) & 1, + 0xfff & (4 * (unsigned int) usbfrnum)); + dbg(" flbaseadd = %08x", flbaseadd); + dbg(" sof = %02x", sof); + uhci_show_sc (1, portsc1); + uhci_show_sc (2, portsc2); +} +#endif diff -ur --new-file old/linux/drivers/usb/usb-uhci.c new/linux/drivers/usb/usb-uhci.c --- old/linux/drivers/usb/usb-uhci.c Mon Jan 24 07:39:14 2000 +++ new/linux/drivers/usb/usb-uhci.c Mon Jan 31 19:10:07 2000 @@ -43,7 +43,7 @@ #include "usb.h" #include "usb-uhci.h" -#include "uhci-debug.h" +#include "usb-uhci-debug.h" #ifdef CONFIG_APM #include diff -ur --new-file old/linux/drivers/usb/usb.c new/linux/drivers/usb/usb.c --- old/linux/drivers/usb/usb.c Fri Jan 28 01:40:53 2000 +++ new/linux/drivers/usb/usb.c Mon Jan 31 19:10:02 2000 @@ -1595,17 +1595,34 @@ tbuf = kmalloc(256, GFP_KERNEL); if (!tbuf) return -ENOMEM; + + /* get langid for strings if it's not yet known */ + if (!dev->have_langid) { + err = usb_get_string(dev, 0, 0, tbuf, 4); + if (err < 0) { + err("error getting string descriptor 0 (error=%d)", err); + goto errout; + } else if (tbuf[0] < 4) { + err("string descriptor 0 too short"); + err = -EINVAL; + goto errout; + } else { + dev->have_langid = -1; + dev->string_langid = tbuf[2] | (tbuf[3]<< 8); + /* always use the first langid listed */ + info("USB device number %d default language ID 0x%x", + dev->devnum, dev->string_langid); + } + } + /* - * is this two step process necessary? can't we just - * ask for a maximum length string and then take the length - * that was returned? + * Just ask for a maximum length string and then take the length + * that was returned. */ - err = usb_get_string(dev, dev->string_langid, index, tbuf, 4); - if (err < 0) - goto errout; - err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]); + err = usb_get_string(dev, dev->string_langid, index, tbuf, 255); if (err < 0) goto errout; + info("actual string desc. length = %d", err); size--; /* leave room for trailing NULL char in output buffer */ for (idx = 0, u = 2; u < err; u += 2) { @@ -1633,7 +1650,6 @@ */ int usb_new_device(struct usb_device *dev) { - unsigned char *buf; int addr, err; int tmp; @@ -1708,21 +1724,6 @@ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { err("failed to set default configuration"); return -1; - } - /* get langid for strings */ - buf = kmalloc(256, GFP_KERNEL); - if (!buf) { - err("out of memory\n"); - } else { - err = usb_get_string(dev, 0, 0, buf, 4); - if (err < 0) { - err("error getting string descriptor 0 (error=%d)\n", err); - } else if (buf[0] < 4) { - err("string descriptpr 0 too short\n"); - } else - dev->string_langid = buf[2] | (buf[3]<< 8); - kfree(buf); - info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid); } if (dev->descriptor.iManufacturer) diff -ur --new-file old/linux/drivers/usb/usb.h new/linux/drivers/usb/usb.h --- old/linux/drivers/usb/usb.h Tue Jan 25 20:41:20 2000 +++ new/linux/drivers/usb/usb.h Mon Jan 31 19:10:07 2000 @@ -509,6 +509,7 @@ struct usb_device_descriptor descriptor;/* Descriptor */ struct usb_config_descriptor *config; /* All of the configs */ + int have_langid; /* whether string_langid is valid yet */ int string_langid; /* language ID for strings */ void *hcpriv; /* Host Controller private data */ diff -ur --new-file old/linux/drivers/video/dn_accel.h new/linux/drivers/video/dn_accel.h --- old/linux/drivers/video/dn_accel.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/video/dn_accel.h Mon Jan 31 19:30:00 2000 @@ -0,0 +1,9 @@ +#ifndef _DN_ACCEL_H_ +#define _DN_ACCEL_H_ + +#include + +void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest, + int x_count, int y_count); + +#endif diff -ur --new-file old/linux/drivers/video/dn_cfb4.c new/linux/drivers/video/dn_cfb4.c --- old/linux/drivers/video/dn_cfb4.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/video/dn_cfb4.c Tue Feb 1 08:43:51 2000 @@ -0,0 +1,546 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include