diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Sat Apr 3 19:38:54 2004 +++ b/CREDITS Sat Apr 3 19:38:54 2004 @@ -82,13 +82,13 @@ S: USA N: Erik Andersen -E: andersee@debian.org -W: http://www.xmission.com/~andersen -P: 1024/FC4CFFED 78 3C 6A 19 FA 5D 92 5A FB AC 7B A5 A5 E1 FF 8E +E: andersen@codepoet.org +W: http://www.codepoet.org/ +P: 1024D/30D39057 1BC4 2742 E885 E4DE 9301 0C82 5F9B 643E 30D3 9057 D: Maintainer of ide-cd and Uniform CD-ROM driver, D: ATAPI CD-Changer support, Major 2.1.x CD-ROM update. -S: 4538 South Carnegie Tech Street -S: Salt Lake City, Utah 84120 +S: 352 North 525 East +S: Springville, Utah 84663 S: USA N: Michael Ang @@ -673,11 +673,6 @@ S: NN1 3QT S: United Kingdom -N: Stephane Dalton -E: sdalton@videotron.ca -D: Tieman Voyager USB Braille display driver. -S: Québec, Canada - N: Uwe Dannowski E: Uwe.Dannowski@ira.uka.de W: http://i30www.ira.uka.de/~dannowsk/ @@ -797,11 +792,6 @@ W: http://www.fsmlabs.com/linuxppcbk.html D: PowerPC -N: Stéphane Doyon -E: s.doyon@videotron.ca -D: Tieman Voyager USB Braille display driver. -S: Québec, Canada - N: Oleg Drokin E: green@ccssu.crimea.ua W: http://www.ccssu.crimea.ua/~green @@ -975,8 +965,7 @@ E: bfennema@falcon.csc.calpoly.edu W: http://www.csc.calpoly.edu/~bfennema D: UDF filesystem -S: 21760 Irma Lyle Drive -S: Los Gatos, CA 95033-8942 +S: (ask for current address) S: USA N: Jürgen Fischer @@ -1677,7 +1666,7 @@ S: Germany N: Alain L. Knaff -E: Alain.Knaff@poboxes.com +E: Alain.Knaff@lll.lu D: floppy driver S: 19, rue Jean l'Aveugle S: L-1148 Luxembourg-City @@ -1875,6 +1864,13 @@ S: D53424 Remagen S: Germany +N: Colin Leroy +E: colin@colino.net +W: http://www.geekounet.org/ +D: PowerMac adt7467 fan driver +S: Toulouse +S: France + N: Achim Leubner E: achim_leubner@adaptec.com D: GDT Disk Array Controller/Storage RAID controller driver @@ -3515,9 +3511,9 @@ W: http://www.yoshifuji.org/~hideaki/ P: 1024D/E0620EEA 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA D: IPv6 and other networking related stuff -D: USAGI/WIDE Project, The University of Tokyo -S: Green House #102, 1-15-5, Nishikata, -S: Bunkyo, Tokyo 113-0024 +D: USAGI/WIDE Project, Keio University +S: Jeunet Palace Kawasaki #1-201, 10-2, Furukawa-cho, Saiwai-ku +S: Kawasaki, Kanagawa 212-0025 S: Japan N: Eric Youngdale diff -Nru a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt --- a/Documentation/DMA-API.txt Sat Apr 3 19:38:43 2004 +++ b/Documentation/DMA-API.txt Sat Apr 3 19:38:43 2004 @@ -279,6 +279,18 @@ cache width is. int +dma_mapping_error(dma_addr_t dma_addr) + +int +pci_dma_mapping_error(dma_addr_t dma_addr) + +In some circumstances dma_map_single and dma_map_page will fail to create +a mapping. A driver can check for these errors by testing the returned +dma address with dma_mapping_error(). A non zero return value means the mapping +could not be created and the driver should take appropriate action (eg +reduce current DMA mapping usage or delay and try again later). + +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) int @@ -291,6 +303,15 @@ than passed in if the block layer determines that some elements of the scatter/gather list are physically adjacent and thus may be mapped with a single entry). + +Please note that the sg cannot be mapped again if it has been mapped once. +The mapping process is allowed to destroy information in the sg. + +As with the other mapping interfaces, dma_map_sg can fail. When it +does, 0 is returned and a driver must take appropriate action. It is +critical that the driver do something, in the case of a block driver +aborting the request or even oopsing is better than doing nothing and +corrupting the filesystem. void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt --- a/Documentation/DMA-mapping.txt Sat Apr 3 19:38:43 2004 +++ b/Documentation/DMA-mapping.txt Sat Apr 3 19:38:43 2004 @@ -283,7 +283,7 @@ in order to get correct behavior on all platforms. - Streaming DMA mappings which are usually mapped for one DMA transfer, - unmapped right after it (unless you use pci_dma_sync below) and for which + unmapped right after it (unless you use pci_dma_sync_* below) and for which hardware can optimize for sequential accesses. This of "streaming" as "asynchronous" or "outside the coherency @@ -519,7 +519,7 @@ ends and the second one starts on a page boundary - in fact this is a huge advantage for cards which either cannot do scatter-gather or have very limited number of scatter-gather entries) and returns the actual number -of sg entries it mapped them to. +of sg entries it mapped them to. On failure 0 is returned. Then you should loop count times (note: this can be less than nents times) and use sg_dma_address() and sg_dma_len() macros where you previously @@ -543,14 +543,30 @@ all bus addresses. If you need to use the same streaming DMA region multiple times and touch -the data in between the DMA transfers, just map it with -pci_map_{single,sg}, and after each DMA transfer call either: +the data in between the DMA transfers, the buffer needs to be synced +properly in order for the cpu and device to see the most uptodate and +correct copy of the DMA buffer. - pci_dma_sync_single(dev, dma_handle, size, direction); +So, firstly, just map it with pci_map_{single,sg}, and after each DMA +transfer call either: + + pci_dma_sync_single_for_cpu(dev, dma_handle, size, direction); + +or: + + pci_dma_sync_sg_for_cpu(dev, sglist, nents, direction); + +as appropriate. + +Then, if you wish to let the device get at the DMA area again, +finish accessing the data with the cpu, and then before actually +giving the buffer to the hardware call either: + + pci_dma_sync_single_for_device(dev, dma_handle, size, direction); or: - pci_dma_sync_sg(dev, sglist, nents, direction); + pci_dma_sync_sg_for_device(dev, sglist, nents, direction); as appropriate. @@ -590,8 +606,9 @@ * the DMA transfer with the CPU first * so that we see updated contents. */ - pci_dma_sync_single(cp->pdev, cp->rx_dma, cp->rx_len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(cp->pdev, cp->rx_dma, + cp->rx_len, + PCI_DMA_FROMDEVICE); /* Now it is safe to examine the buffer. */ hp = (struct my_card_header *) cp->rx_buf; @@ -601,7 +618,13 @@ pass_to_upper_layers(cp->rx_buf); make_and_setup_new_rx_buf(cp); } else { - /* Just give the buffer back to the card. */ + /* Just sync the buffer and give it back + * to the card. + */ + pci_dma_sync_single_for_device(cp->pdev, + cp->rx_dma, + cp->rx_len, + PCI_DMA_FROMDEVICE); give_rx_buf_to_card(cp); } } @@ -709,12 +732,21 @@ When the DMA transfer is complete, invoke: - void pci_dac_dma_sync_single(struct pci_dev *pdev, - dma64_addr_t dma_addr, - size_t len, int direction); + void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, + size_t len, int direction); This must be done before the CPU looks at the buffer again. -This interface behaves identically to pci_dma_sync_{single,sg}(). +This interface behaves identically to pci_dma_sync_{single,sg}_for_cpu(). + +And likewise, if you wish to let the device get back at the buffer after +the cpu has read/written it, invoke: + + void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, + dma64_addr_t dma_addr, + size_t len, int direction); + +before letting the device access the DMA area again. If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t the following interfaces are provided: @@ -809,6 +841,27 @@ deleted. 2) More to come... + + Handling Errors + +DMA address space is limited on some architectures and an allocation +failure can be determined by: + +- checking if pci_alloc_consistent returns NULL or pci_map_sg returns 0 + +- checking the returned dma_addr_t of pci_map_single and pci_map_page + by using pci_dma_mapping_error(): + + dma_addr_t dma_handle; + + dma_handle = pci_map_single(dev, addr, size, direction); + if (pci_dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + } Closing diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile Sat Apr 3 19:38:43 2004 +++ b/Documentation/DocBook/Makefile Sat Apr 3 19:38:43 2004 @@ -47,7 +47,7 @@ ### #External programs used KERNELDOC = scripts/kernel-doc -DOCPROC = scripts/docproc +DOCPROC = scripts/basic/docproc SPLITMAN = $(PERL) $(srctree)/scripts/split-man MAKEMAN = $(PERL) $(srctree)/scripts/makeman @@ -149,12 +149,18 @@ cmd_fig2eps = fig2dev -Leps $< $@ %.eps: %.fig + @(which fig2dev > /dev/null 2>&1) || \ + (echo "*** You need to install transfig ***"; \ + exit 1) $(call cmd,fig2eps) quiet_cmd_fig2png = FIG2PNG $@ cmd_fig2png = fig2dev -Lpng $< $@ %.png: %.fig + @(which fig2dev > /dev/null 2>&1) || \ + (echo "*** You need to install transfig ***"; \ + exit 1) $(call cmd,fig2png) ### diff -Nru a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl --- a/Documentation/DocBook/gadget.tmpl Sat Apr 3 19:38:43 2004 +++ b/Documentation/DocBook/gadget.tmpl Sat Apr 3 19:38:43 2004 @@ -454,6 +454,7 @@ !Edrivers/usb/gadget/usbstring.c +!Edrivers/usb/gadget/config.c diff -Nru a/Documentation/DocBook/parportbook.tmpl b/Documentation/DocBook/parportbook.tmpl --- a/Documentation/DocBook/parportbook.tmpl Sat Apr 3 19:38:41 2004 +++ b/Documentation/DocBook/parportbook.tmpl Sat Apr 3 19:38:41 2004 @@ -2730,7 +2730,7 @@ diff -Nru a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers --- a/Documentation/SubmittingDrivers Sat Apr 3 19:38:54 2004 +++ b/Documentation/SubmittingDrivers Sat Apr 3 19:38:54 2004 @@ -51,6 +51,13 @@ to be useful to other communities such as BSD you may well wish to release under multiple licenses. +Copyright: The copyright owner must agree to use of GPL. + It's best if the submitter and copyright owner + are the same person/entity. If not, the name of + the person/entity authorizing use of GPL should be + listed in case it's necessary to verify the will of + the copright owner. + Interfaces: If your driver uses existing interfaces and behaves like other drivers in the same class it will be much more likely to be accepted than if it invents gratuitous new ones. diff -Nru a/Documentation/arm/README b/Documentation/arm/README --- a/Documentation/arm/README Sat Apr 3 19:38:42 2004 +++ b/Documentation/arm/README Sat Apr 3 19:38:42 2004 @@ -1,14 +1,17 @@ - ARM Linux 2.4 + ARM Linux 2.6 ============= - Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates. + Please check for + updates. Compilation of kernel --------------------- In order to compile ARM Linux, you will need a compiler capable of - generating ARM ELF code with GNU extensions. GCC 2.95.1 and EGCS 1.1.2 - are good compilers. + generating ARM ELF code with GNU extensions. GCC 2.95.1, EGCS + 1.1.2, and GCC 3.3 are known to be good compilers. Fortunately, you + needn't guess. The kernel will report an error if your compiler is + a recognized offender. To build ARM Linux natively, you shouldn't have to alter the ARCH = line in the top level Makefile. However, if you don't have the ARM Linux ELF @@ -147,22 +150,49 @@ are welcome. +CONFIG_MACH_ and CONFIG_ARCH_ +----------------------------- + A change was made in 2003 to the macro names for new machines. + Historically, CONFIG_ARCH_ was used for the bonafide architecture, + e.g. SA1100, as well as implementations of the architecture, + e.g. Assabet. It was decided to change the implementation macros + to read CONFIG_MACH_ for clarity. Moreover, a retroactive fixup has + not been made because it would complicate patching. + + Previous registrations may be found online. + + + Kernel entry (head-armv.S) -------------------------- - The initial entry into the kernel made via head-armv.S uses architecture - independent code. The architecture is selected by the value of 'r1' on - entry, which must be kept unique. You can register a new architecture - by mailing the following details to rmk@arm.linux.org.uk Please give - the mail a subject of 'Register new architecture': - - Name: - ArchDir: - Type: - Description: - + The initial entry into the kernel is via head-armv.S, which uses machine + independent code. The machine is selected by the value of 'r1' on + entry, which must be kept unique. + + Due to the large number of machines which the ARM port of Linux provides + for, we have a method to manage this which ensures that we don't end up + duplicating large amounts of code. + + We group machine (or platform) support code into machine classes. A + class typically based around one or more system on a chip devices, and + acts as a natural container around the actual implementations. These + classes are given directories - arch/arm/mach- and + include/asm-arm/arch- - which contain the source files to + support the machine class. This directories also contain any machine + specific supporting code. + + For example, the SA1100 class is based upon the SA1100 and SA1110 SoC + devices, and contains the code to support the way the on-board and off- + board devices are used, or the device is setup, and provides that + machine specific "personality." + + This fine-grained machine specific selection is controlled by the machine + type ID, which acts both as a run-time and a compile-time code selection + method. + + You can register a new machine via the web site at: - Please follow this format - it is an automated system. You should - receive a reply in short order. + --- -Russell King (26/01/2001) +Russell King (15/03/2004) diff -Nru a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/memory.txt Sat Apr 3 19:38:57 2004 @@ -0,0 +1,74 @@ + Kernel Memory Layout on ARM Linux + + Russell King + April 27, 2003 (2.5.68) + +This document describes the virtual memory layout which the Linux +kernel uses for ARM processors. It indicates which regions are +free for platforms to use, and which are used by generic code. + +The ARM CPU is capable of addressing a maximum of 4GB virtual memory +space, and this must be shared between user space processes, the +kernel, and hardware devices. + +As the ARM architecture matures, it becomes necessary to reserve +certain regions of VM space for use for new facilities; therefore +this document may reserve more VM space over time. + +Start End Use +-------------------------------------------------------------------------- +ffff8000 ffffffff copy_user_page / clear_user_page use. + For SA11xx and Xscale, this is used to + setup a minicache mapping. + +ffff1000 ffff7fff Reserved. + Platforms must not use this address range. + +ffff0000 ffff0fff CPU vector page. + The CPU vectors are mapped here if the + CPU supports vector relocation (control + register V bit.) + +ffe00000 fffeffff Free for platform use, not recommended. + +ffc00000 ffdfffff 2MB consistent memory mapping. + Memory returned by the consistent_alloc + low level function will be dynamically + mapped here. + +ff000000 ffbfffff Free for platform use, not recommended. + +VMALLOC_END ff000000 Free for platform use, recommended. + +VMALLOC_START VMALLOC_END vmalloc() / ioremap() space. + Memory returned by vmalloc/ioremap will + be dynamically placed in this region. + VMALLOC_START may be based upon the value + of the high_memory variable. + +PAGE_OFFSET high_memory Kernel direct-mapped RAM region. + This maps the platforms RAM, and typically + maps all platform RAM in a 1:1 relationship. + +TASK_SIZE PAGE_OFFSET Kernel module space + Kernel modules inserted via insmod are + placed here using dynamic mappings. + +00001000 TASK_SIZE User space mappings + Per-thread mappings are placed here via + the mmap() system call. + +00000000 00000fff CPU vector page / null pointer trap + CPUs which do not support vector remapping + place their vector page here. NULL pointer + dereferences by both the kernel and user + space are also caught via this mapping. + +Please note that mappings which collide with the above areas may result +in a non-bootable kernel, or may cause the kernel to (eventually) panic +at run time. + +Since future CPUs may impact the kernel mapping layout, user programs +must not access any memory which is not mapped inside their 0x0001000 +to TASK_SIZE address range. If they wish to access these areas, they +must set up their own mappings using open() and mmap(). diff -Nru a/Documentation/computone.txt b/Documentation/computone.txt --- a/Documentation/computone.txt Sat Apr 3 19:38:55 2004 +++ b/Documentation/computone.txt Sat Apr 3 19:38:55 2004 @@ -261,7 +261,7 @@ management of symbolic links from the devfs name space to the conventional names. More details on devfs can be found on the DEVFS home site at or in the file kernel -documentation files, .../linux/Documentation/filesystems/devfs/REAME. +documentation files, .../linux/Documentation/filesystems/devfs/README. If you are using devfs, existing devices are automatically created within the devfs name space. Normal devices will be tts/F0 - tts/F255 and callout diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt --- a/Documentation/crypto/api-intro.txt Sat Apr 3 19:38:54 2004 +++ b/Documentation/crypto/api-intro.txt Sat Apr 3 19:38:54 2004 @@ -187,6 +187,7 @@ Brian Gladman (AES) Kartikey Mahendra Bhatt (CAST6) Jon Oberheide (ARC4) + Jouni Malinen (Michael MIC) SHA1 algorithm contributors: Jean-Francois Dive diff -Nru a/Documentation/devices.txt b/Documentation/devices.txt --- a/Documentation/devices.txt Sat Apr 3 19:38:43 2004 +++ b/Documentation/devices.txt Sat Apr 3 19:38:43 2004 @@ -1,8 +1,9 @@ LINUX ALLOCATED DEVICES - Maintained by H. Peter Anvin - Last revised: 3 June 2001 + Maintained by John Cagle + + Last revised: 15 March 2004 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -85,6 +86,7 @@ 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device number + See block major 144, 145, 146 for expansion areas. 1 char Memory devices 1 = /dev/mem Physical memory access @@ -98,7 +100,7 @@ 9 = /dev/urandom Faster, less secure random number gen. 10 = /dev/aio Asyncronous I/O notification interface 11 = /dev/kmsg Writes to this come out as printk's - block RAM disk + 1 block RAM disk 0 = /dev/ram0 First RAM disk 1 = /dev/ram1 Second RAM disk ... @@ -127,7 +129,7 @@ master multiplex (/dev/ptmx) to acquire a PTY on demand. - block Floppy disks + 2 block Floppy disks 0 = /dev/fd0 Controller 0, drive 0, autodetect 1 = /dev/fd1 Controller 0, drive 1, autodetect 2 = /dev/fd2 Controller 0, drive 2, autodetect @@ -193,7 +195,7 @@ These are the old-style (BSD) PTY devices; Unix98 devices are on major 136 and above. - block First MFM, RLL and IDE hard disk/CD-ROM interface + 3 block First MFM, RLL and IDE hard disk/CD-ROM interface 0 = /dev/hda Master: whole disk (or CD-ROM) 64 = /dev/hdb Slave: whole disk (or CD-ROM) @@ -225,6 +227,12 @@ number for BSD PTY devices. As of Linux 2.1.115, this is no longer supported. Use major numbers 2 and 3. + 4 block Aliases for dynamically allocated major devices to be used + when its not possible to create the real device nodes + because the root filesystem is mounted read-only. + + 0 = /dev/root + 5 char Alternate TTY devices 0 = /dev/tty Current TTY device 1 = /dev/console System console @@ -258,7 +266,7 @@ NOTE: These devices permit both read and write access. - block Loopback devices + 7 block Loopback devices 0 = /dev/loop0 First loopback device 1 = /dev/loop1 Second loopback device ... @@ -309,7 +317,7 @@ ioctl()'s can be used to rewind the tape regardless of the device used to access it. - block Metadisk (RAID) devices + 9 block Metadisk (RAID) devices 0 = /dev/md0 First metadisk group 1 = /dev/md1 Second metadisk group ... @@ -355,6 +363,7 @@ 149 = /dev/input/mouse Linux/SGI Irix emulation mouse 150 = /dev/input/keyboard Linux/SGI Irix emulation keyboard 151 = /dev/led Front panel LEDs + 152 = /dev/kpoll Kernel Poll Driver 153 = /dev/mergemem Memory merge device 154 = /dev/pmu Macintosh PowerBook power manager 155 = /dev/isictl MultiTech ISICom serial control @@ -372,7 +381,7 @@ 167 = /dev/specialix_sxctl Specialix serial control 168 = /dev/tcldrv Technology Concepts serial control 169 = /dev/specialix_rioctl Specialix RIO serial control - 170 = /dev/smapi IBM Thinkpad SMAPI + 170 = /dev/thinkpad/thinkpad IBM Thinkpad devices 171 = /dev/srripc QNX4 API IPC manager 172 = /dev/usemaclone Semaphore clone device 173 = /dev/ipmikcs Intelligent Platform Management @@ -385,7 +394,7 @@ 180 = /dev/vrbuttons Vr41xx button input device 181 = /dev/toshiba Toshiba laptop SMM support 182 = /dev/perfctr Performance-monitoring counters - 183 = /dev/intel_rng Intel i8x0 random number generator + 183 = /dev/hwrng Generic random number generator 184 = /dev/cpu/microcode CPU microcode update interface 186 = /dev/atomicps Atomic shapshot of process state data 187 = /dev/irnet IrNET device @@ -421,20 +430,27 @@ 221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver 222 = /dev/mvista/hasi Montavista PICMG high availability 223 = /dev/input/uinput User level driver support for input - 240-255 Reserved for local use + 224 = /dev/tpm TCPA TPM driver + 225 = /dev/pps Pulse Per Second driver + 226 = /dev/systrace Systrace device + 227 = /dev/mcelog X86_64 Machine Check Exception driver + 240-254 Reserved for local use + 255 Reserved for MISC_DYNAMIC_MINOR - 11 char Raw keyboard device + 11 char Raw keyboard device (Linux/SPARC only) 0 = /dev/kbd Raw keyboard device - The raw keyboard device is used on Linux/SPARC only. + 11 char Serial Mux device (Linux/PA-RISC only) + 0 = /dev/ttyB0 First mux port + 1 = /dev/ttyB1 Second mux port + ... - block SCSI CD-ROM devices - 0 = /dev/sr0 First SCSI CD-ROM - 1 = /dev/sr1 Second SCSI CD-ROM + 11 block SCSI CD-ROM devices + 0 = /dev/scd0 First SCSI CD-ROM + 1 = /dev/scd1 Second SCSI CD-ROM ... - The prefix /dev/scd instead of /dev/sr has been used - as well, and might make more sense. + The prefix /dev/sr (instead of /dev/scd) has been deprecated. 12 char QIC-02 tape 2 = /dev/ntpqic11 QIC-11, no rewind-on-close @@ -449,7 +465,7 @@ The device names specified are proposed -- if there are "standard" names for these devices, please let me know. - block MSCDEX CD-ROM callback support {2.6} + 12 block MSCDEX CD-ROM callback support {2.6} 0 = /dev/dos_cd0 First MSCDEX CD-ROM 1 = /dev/dos_cd1 Second MSCDEX CD-ROM ... @@ -468,7 +484,7 @@ Each device type has 5 bits (32 minors). - block 8-bit MFM/RLL/IDE controller + 13 block 8-bit MFM/RLL/IDE controller 0 = /dev/xda First XT disk whole disk 64 = /dev/xdb Second XT disk whole disk @@ -492,7 +508,7 @@ 33 = /dev/patmgr1 Sequencer patch manager 34 = /dev/midi02 Third MIDI port 50 = /dev/midi03 Fourth MIDI port - block BIOS harddrive callback support {2.6} + 14 block BIOS harddrive callback support {2.6} 0 = /dev/dos_hda First BIOS harddrive whole disk 64 = /dev/dos_hdb Second BIOS harddrive whole disk 128 = /dev/dos_hdc Third BIOS harddrive whole disk @@ -508,33 +524,33 @@ 128 = /dev/djs0 First digital joystick 129 = /dev/djs1 Second digital joystick ... - block Sony CDU-31A/CDU-33A CD-ROM + 15 block Sony CDU-31A/CDU-33A CD-ROM 0 = /dev/sonycd Sony CDU-31a CD-ROM 16 char Non-SCSI scanners 0 = /dev/gs4500 Genius 4500 handheld scanner - block GoldStar CD-ROM + 16 block GoldStar CD-ROM 0 = /dev/gscd GoldStar CD-ROM 17 char Chase serial card 0 = /dev/ttyH0 First Chase port 1 = /dev/ttyH1 Second Chase port ... - block Optics Storage CD-ROM + 17 block Optics Storage CD-ROM 0 = /dev/optcd Optics Storage CD-ROM 18 char Chase serial card - alternate devices 0 = /dev/cuh0 Callout device for ttyH0 1 = /dev/cuh1 Callout device for ttyH1 ... - block Sanyo CD-ROM + 18 block Sanyo CD-ROM 0 = /dev/sjcd Sanyo CD-ROM 19 char Cyclades serial card 0 = /dev/ttyC0 First Cyclades port ... 31 = /dev/ttyC31 32nd Cyclades port - block "Double" compressed disk + 19 block "Double" compressed disk 0 = /dev/double0 First compressed disk ... 7 = /dev/double7 Eighth compressed disk @@ -549,7 +565,7 @@ 0 = /dev/cub0 Callout device for ttyC0 ... 31 = /dev/cub31 Callout device for ttyC31 - block Hitachi CD-ROM (under development) + 20 block Hitachi CD-ROM (under development) 0 = /dev/hitcd Hitachi CD-ROM 21 char Generic SCSI access @@ -562,7 +578,7 @@ the system and is counter to standard Linux device-naming practice. - block Acorn MFM hard drive interface + 21 block Acorn MFM hard drive interface 0 = /dev/mfma First MFM drive whole disk 64 = /dev/mfmb Second MFM drive whole disk @@ -574,7 +590,7 @@ 0 = /dev/ttyD0 First Digiboard port 1 = /dev/ttyD1 Second Digiboard port ... - block Second IDE hard disk/CD-ROM interface + 22 block Second IDE hard disk/CD-ROM interface 0 = /dev/hdc Master: whole disk (or CD-ROM) 64 = /dev/hdd Slave: whole disk (or CD-ROM) @@ -585,7 +601,7 @@ 0 = /dev/cud0 Callout device for ttyD0 1 = /dev/cud1 Callout device for ttyD1 ... - block Mitsumi proprietary CD-ROM + 23 block Mitsumi proprietary CD-ROM 0 = /dev/mcd Mitsumi CD-ROM 24 char Stallion serial card @@ -601,7 +617,7 @@ 192 = /dev/ttyE192 Stallion port 0 card 3 193 = /dev/ttyE193 Stallion port 1 card 3 ... - block Sony CDU-535 CD-ROM + 24 block Sony CDU-535 CD-ROM 0 = /dev/cdu535 Sony CDU-535 CD-ROM 25 char Stallion serial card - alternate devices @@ -617,7 +633,7 @@ 192 = /dev/cue192 Callout device for ttyE192 193 = /dev/cue193 Callout device for ttyE193 ... - block First Matsushita (Panasonic/SoundBlaster) CD-ROM + 25 block First Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd0 Panasonic CD-ROM controller 0 unit 0 1 = /dev/sbpcd1 Panasonic CD-ROM controller 0 unit 1 2 = /dev/sbpcd2 Panasonic CD-ROM controller 0 unit 2 @@ -625,7 +641,7 @@ 26 char Quanta WinVision frame grabber {2.6} 0 = /dev/wvisfgrab Quanta WinVision frame grabber - block Second Matsushita (Panasonic/SoundBlaster) CD-ROM + 26 block Second Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd4 Panasonic CD-ROM controller 1 unit 0 1 = /dev/sbpcd5 Panasonic CD-ROM controller 1 unit 1 2 = /dev/sbpcd6 Panasonic CD-ROM controller 1 unit 2 @@ -656,7 +672,7 @@ 37 = /dev/nrawqft1 Unit 1, no rewind-on-close, no file marks 38 = /dev/nrawqft2 Unit 2, no rewind-on-close, no file marks 39 = /dev/nrawqft3 Unit 3, no rewind-on-close, no file marks - block Third Matsushita (Panasonic/SoundBlaster) CD-ROM + 27 block Third Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd8 Panasonic CD-ROM controller 2 unit 0 1 = /dev/sbpcd9 Panasonic CD-ROM controller 2 unit 1 2 = /dev/sbpcd10 Panasonic CD-ROM controller 2 unit 2 @@ -667,16 +683,16 @@ 1 = /dev/staliomem1 Second Stallion card I/O memory 2 = /dev/staliomem2 Third Stallion card I/O memory 3 = /dev/staliomem3 Fourth Stallion card I/O memory - char Atari SLM ACSI laser printer (68k/Atari) + 28 char Atari SLM ACSI laser printer (68k/Atari) 0 = /dev/slm0 First SLM laser printer 1 = /dev/slm1 Second SLM laser printer ... - block Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM + 28 block Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd12 Panasonic CD-ROM controller 3 unit 0 1 = /dev/sbpcd13 Panasonic CD-ROM controller 3 unit 1 2 = /dev/sbpcd14 Panasonic CD-ROM controller 3 unit 2 3 = /dev/sbpcd15 Panasonic CD-ROM controller 3 unit 3 - block ACSI disk (68k/Atari) + 28 block ACSI disk (68k/Atari) 0 = /dev/ada First ACSI disk whole disk 16 = /dev/adb Second ACSI disk whole disk 32 = /dev/adc Third ACSI disk whole disk @@ -693,23 +709,41 @@ ... 31 = /dev/fb31 32nd frame buffer - block Aztech/Orchid/Okano/Wearnes CD-ROM + 29 block Aztech/Orchid/Okano/Wearnes CD-ROM 0 = /dev/aztcd Aztech CD-ROM 30 char iBCS-2 compatibility devices 0 = /dev/socksys Socket access 1 = /dev/spx SVR3 local X interface - 2 = /dev/inet/arp Network access - 2 = /dev/inet/icmp Network access - 2 = /dev/inet/ip Network access - 2 = /dev/inet/udp Network access - 2 = /dev/inet/tcp Network access - - Additionally, iBCS-2 requires /dev/nfsd to be a link - to /dev/socksys, and /dev/X0R to be a link to - /dev/null. + 32 = /dev/inet/ip Network access + 33 = /dev/inet/icmp + 34 = /dev/inet/ggp + 35 = /dev/inet/ipip + 36 = /dev/inet/tcp + 37 = /dev/inet/egp + 38 = /dev/inet/pup + 39 = /dev/inet/udp + 40 = /dev/inet/idp + 41 = /dev/inet/rawip + + Additionally, iBCS-2 requires the following links: + + /dev/ip -> /dev/inet/ip + /dev/icmp -> /dev/inet/icmp + /dev/ggp -> /dev/inet/ggp + /dev/ipip -> /dev/inet/ipip + /dev/tcp -> /dev/inet/tcp + /dev/egp -> /dev/inet/egp + /dev/pup -> /dev/inet/pup + /dev/udp -> /dev/inet/udp + /dev/idp -> /dev/inet/idp + /dev/rawip -> /dev/inet/rawip + /dev/inet/arp -> /dev/inet/udp + /dev/inet/rip -> /dev/inet/udp + /dev/nfsd -> /dev/socksys + /dev/X0R -> /dev/null (? apparently not required ?) - block Philips LMS CM-205 CD-ROM + 30 block Philips LMS CM-205 CD-ROM 0 = /dev/cm205cd Philips LMS CM-205 CD-ROM /dev/lmscd is an older name for this device. This @@ -718,7 +752,7 @@ 31 char MPU-401 MIDI 0 = /dev/mpu401data MPU-401 data port 1 = /dev/mpu401stat MPU-401 status port - block ROM/flash memory card + 31 block ROM/flash memory card 0 = /dev/rom0 First ROM card (rw) ... 7 = /dev/rom7 Eighth ROM card (rw) @@ -741,14 +775,14 @@ 0 = /dev/ttyX0 First Specialix port 1 = /dev/ttyX1 Second Specialix port ... - block Philips LMS CM-206 CD-ROM + 32 block Philips LMS CM-206 CD-ROM 0 = /dev/cm206cd Philips LMS CM-206 CD-ROM 33 char Specialix serial card - alternate devices 0 = /dev/cux0 Callout device for ttyX0 1 = /dev/cux1 Callout device for ttyX1 ... - block Third IDE hard disk/CD-ROM interface + 33 block Third IDE hard disk/CD-ROM interface 0 = /dev/hde Master: whole disk (or CD-ROM) 64 = /dev/hdf Slave: whole disk (or CD-ROM) @@ -766,7 +800,7 @@ /dev/sc1 for /dev/scc0, /dev/sc2 for /dev/scc1, and so on. - block Fourth IDE hard disk/CD-ROM interface + 34 block Fourth IDE hard disk/CD-ROM interface 0 = /dev/hdg Master: whole disk (or CD-ROM) 64 = /dev/hdh Slave: whole disk (or CD-ROM) @@ -786,7 +820,7 @@ 129 = /dev/smpte1 Second MIDI port, SMPTE timed 130 = /dev/smpte2 Third MIDI port, SMPTE timed 131 = /dev/smpte3 Fourth MIDI port, SMPTE timed - block Slow memory ramdisk + 35 block Slow memory ramdisk 0 = /dev/slram Slow memory ramdisk 36 char Netlink support @@ -796,7 +830,7 @@ 16 = /dev/tap0 First Ethertap device ... 31 = /dev/tap15 16th Ethertap device - block MCA ESDI hard disk + 36 block MCA ESDI hard disk 0 = /dev/eda First ESDI disk whole disk 64 = /dev/edb Second ESDI disk whole disk ... @@ -814,7 +848,7 @@ Currently, only one IDE tape drive is supported. - block Zorro II ramdisk + 37 block Zorro II ramdisk 0 = /dev/z2ram Zorro II ramdisk 38 char Myricom PCI Myrinet board @@ -826,7 +860,7 @@ and "user level packet I/O." This board is also accessible as a standard networking "eth" device. - block Reserved for Linux/AP+ + 38 block Reserved for Linux/AP+ 39 char ML-16P experimental I/O board 0 = /dev/ml16pa-a0 First card, first analog channel @@ -846,11 +880,11 @@ 50 = /dev/ml16pb-c1 Second card, second counter/timer 51 = /dev/ml16pb-c2 Second card, third counter/timer ... - block Reserved for Linux/AP+ + 39 block Reserved for Linux/AP+ 40 char Matrox Meteor frame grabber {2.6} 0 = /dev/mmetfgrab Matrox Meteor frame grabber - block Syquest EZ135 parallel port removable drive + 40 block Syquest EZ135 parallel port removable drive 0 = /dev/eza Parallel EZ135 drive, whole disk This device is obsolete and will be removed in a @@ -861,14 +895,15 @@ 41 char Yet Another Micro Monitor 0 = /dev/yamm Yet Another Micro Monitor - block MicroSolutions BackPack parallel port CD-ROM + 41 block MicroSolutions BackPack parallel port CD-ROM 0 = /dev/bpcd BackPack CD-ROM This device is obsolete and will be removed in a future version of Linux. It has been replaced with the parallel port ATAPI CD-ROM driver at major number 46. - 42 Demo/sample use + 42 char Demo/sample use + 42 block Demo/sample use This number is intended for use in sample code, as well as a general "example" device number. It @@ -885,7 +920,7 @@ 0 = /dev/ttyI0 First virtual modem ... 63 = /dev/ttyI63 64th virtual modem - block Network block devices + 43 block Network block devices 0 = /dev/nb0 First network block device 1 = /dev/nb1 Second network block device ... @@ -901,7 +936,7 @@ 0 = /dev/cui0 Callout device for ttyI0 ... 63 = /dev/cui63 Callout device for ttyI63 - block Flash Translatio Layer (FTL) filesystems + 44 block Flash Translation Layer (FTL) filesystems 0 = /dev/ftla FTL on first Memory Technology Device 16 = /dev/ftlb FTL on second Memory Technology Device 32 = /dev/ftlc FTL on third Memory Technology Device @@ -925,7 +960,7 @@ 191 = /dev/ippp63 64th SyncPPP device 255 = /dev/isdninfo ISDN monitor interface - block Parallel port IDE disk devices + 45 block Parallel port IDE disk devices 0 = /dev/pda First parallel port IDE disk 16 = /dev/pdb Second parallel port IDE disk 32 = /dev/pdc Third parallel port IDE disk @@ -939,7 +974,7 @@ 0 = /dev/ttyR0 First Rocketport port 1 = /dev/ttyR1 Second Rocketport port ... - block Parallel port ATAPI CD-ROM devices + 46 block Parallel port ATAPI CD-ROM devices 0 = /dev/pcd0 First parallel port ATAPI CD-ROM 1 = /dev/pcd1 Second parallel port ATAPI CD-ROM 2 = /dev/pcd2 Third parallel port ATAPI CD-ROM @@ -949,7 +984,7 @@ 0 = /dev/cur0 Callout device for ttyR0 1 = /dev/cur1 Callout device for ttyR1 ... - block Parallel port ATAPI disk devices + 47 block Parallel port ATAPI disk devices 0 = /dev/pf0 First parallel port ATAPI disk 1 = /dev/pf1 Second parallel port ATAPI disk 2 = /dev/pf2 Third parallel port ATAPI disk @@ -962,7 +997,7 @@ 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port ... - block Mylex DAC960 PCI RAID controller; first controller + 48 block Mylex DAC960 PCI RAID controller; first controller 0 = /dev/rd/c0d0 First disk, whole disk 8 = /dev/rd/c0d1 Second disk, whole disk ... @@ -978,7 +1013,7 @@ 0 = /dev/cul0 Callout device for ttyL0 1 = /dev/cul1 Callout device for ttyL1 ... - block Mylex DAC960 PCI RAID controller; second controller + 49 block Mylex DAC960 PCI RAID controller; second controller 0 = /dev/rd/c1d0 First disk, whole disk 8 = /dev/rd/c1d1 Second disk, whole disk ... @@ -988,17 +1023,17 @@ 50 char Reserved for GLINT - block Mylex DAC960 PCI RAID controller; third controller + 50 block Mylex DAC960 PCI RAID controller; third controller 0 = /dev/rd/c2d0 First disk, whole disk 8 = /dev/rd/c2d1 Second disk, whole disk ... 248 = /dev/rd/c2d31 32nd disk, whole disk - 51 char Baycom radio modem + 51 char Baycom radio modem OR Radio Tech BIM-XXX-RS232 radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem ... - block Mylex DAC960 PCI RAID controller; fourth controller + 51 block Mylex DAC960 PCI RAID controller; fourth controller 0 = /dev/rd/c3d0 First disk, whole disk 8 = /dev/rd/c3d1 Second disk, whole disk ... @@ -1011,7 +1046,7 @@ 1 = /dev/dcbri1 Second DataComm card 2 = /dev/dcbri2 Third DataComm card 3 = /dev/dcbri3 Fourth DataComm card - block Mylex DAC960 PCI RAID controller; fifth controller + 52 block Mylex DAC960 PCI RAID controller; fifth controller 0 = /dev/rd/c4d0 First disk, whole disk 8 = /dev/rd/c4d1 Second disk, whole disk ... @@ -1033,7 +1068,7 @@ Domain Interface and ICD is the commercial interface by P&E. - block Mylex DAC960 PCI RAID controller; sixth controller + 53 block Mylex DAC960 PCI RAID controller; sixth controller 0 = /dev/rd/c5d0 First disk, whole disk 8 = /dev/rd/c5d1 Second disk, whole disk ... @@ -1050,7 +1085,7 @@ to transfer data from Holter 24-hour heart monitoring equipment. - block Mylex DAC960 PCI RAID controller; seventh controller + 54 block Mylex DAC960 PCI RAID controller; seventh controller 0 = /dev/rd/c6d0 First disk, whole disk 8 = /dev/rd/c6d1 Second disk, whole disk ... @@ -1060,7 +1095,7 @@ 55 char DSP56001 digital signal processor 0 = /dev/dsp56k First DSP56001 - block Mylex DAC960 PCI RAID controller; eigth controller + 55 block Mylex DAC960 PCI RAID controller; eigth controller 0 = /dev/rd/c7d0 First disk, whole disk 8 = /dev/rd/c7d1 Second disk, whole disk ... @@ -1074,7 +1109,7 @@ Additional devices will be added to this number, all starting with /dev/adb. - block Fifth IDE hard disk/CD-ROM interface + 56 block Fifth IDE hard disk/CD-ROM interface 0 = /dev/hdi Master: whole disk (or CD-ROM) 64 = /dev/hdj Slave: whole disk (or CD-ROM) @@ -1086,7 +1121,7 @@ 1 = /dev/ttyP1 Second ESP port ... - block Sixth IDE hard disk/CD-ROM interface + 57 block Sixth IDE hard disk/CD-ROM interface 0 = /dev/hdk Master: whole disk (or CD-ROM) 64 = /dev/hdl Slave: whole disk (or CD-ROM) @@ -1097,12 +1132,12 @@ 0 = /dev/cup0 Callout device for ttyP0 1 = /dev/cup1 Callout device for ttyP1 ... - block Reserved for logical volume manager + 58 block Reserved for logical volume manager 59 char sf firewall package 0 = /dev/firewall Communication with sf kernel module - block Generic PDA filesystem device + 59 block Generic PDA filesystem device 0 = /dev/pda0 First PDA device 1 = /dev/pda1 Second PDA device ... @@ -1115,14 +1150,30 @@ NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc - 60-63 LOCAL/EXPERIMENTAL USE + 60-63 char LOCAL/EXPERIMENTAL USE + 60-63 block LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not assigned official numbers, these ranges should be - used, in order to avoid conflicting with future assignments. + used in order to avoid conflicting with future assignments. 64 char ENskip kernel encryption package 0 = /dev/enskip Communication with ENskip kernel module + 64 block Scramdisk/DriveCrypt encrypted devices + 0 = /dev/scramdisk/master Master node for ioctls + 1 = /dev/scramdisk/1 First encrypted device + 2 = /dev/scramdisk/2 Second encrypted device + ... + 255 = /dev/scramdisk/255 255th encrypted device + + The filename of the encrypted container and the passwords + are sent via ioctls (using the sdmount tool) to the master + node which then activates them via one of the + /dev/scramdisk/x nodes for loopback mounting (all handled + through the sdmount tool). + + Requested by: andy@scramdisklinux.org + 65 char Sundance "plink" Transputer boards 0 = /dev/plink0 First plink device 1 = /dev/plink1 Second plink device @@ -1144,10 +1195,10 @@ This is a commercial driver; contact James Howes for information. - block SCSI disk devices (16-31) - 0 = /dev/sdq 16th SCSI disk whole disk - 16 = /dev/sdr 17th SCSI disk whole disk - 32 = /dev/sds 18th SCSI disk whole disk + 65 block SCSI disk devices (16-31) + 0 = /dev/sdq 17th SCSI disk whole disk + 16 = /dev/sdr 18th SCSI disk whole disk + 32 = /dev/sds 19th SCSI disk whole disk ... 240 = /dev/sdaf 32nd SCSI disk whole disk @@ -1160,7 +1211,7 @@ 1 = /dev/yppcpci1 Second YARC card ... - block SCSI disk devices (32-47) + 66 block SCSI disk devices (32-47) 0 = /dev/sdag 33th SCSI disk whole disk 16 = /dev/sdah 34th SCSI disk whole disk 32 = /dev/sdai 35th SCSI disk whole disk @@ -1176,7 +1227,7 @@ See http://www.coda.cs.cmu.edu for information about Coda. - block SCSI disk devices (48-63) + 67 block SCSI disk devices (48-63) 0 = /dev/sdaw 49th SCSI disk whole disk 16 = /dev/sdax 50th SCSI disk whole disk 32 = /dev/sday 51st SCSI disk whole disk @@ -1197,10 +1248,10 @@ ISDN CAPI 2.0 driver for use with CAPI 2.0 applications; currently supports the AVM B1 card. - block SCSI disk devices (64-79) - 0 = /dev/sdbm 64th SCSI disk whole disk - 16 = /dev/sdbn 65th SCSI disk whole disk - 32 = /dev/sdbo 66th SCSI disk whole disk + 68 block SCSI disk devices (64-79) + 0 = /dev/sdbm 65th SCSI disk whole disk + 16 = /dev/sdbn 66th SCSI disk whole disk + 32 = /dev/sdbo 67th SCSI disk whole disk ... 240 = /dev/sdcb 80th SCSI disk whole disk @@ -1211,7 +1262,7 @@ 69 char MA16 numeric accelerator card 0 = /dev/ma16 Board memory access - block SCSI disk devices (80-95) + 69 block SCSI disk devices (80-95) 0 = /dev/sdcc 81st SCSI disk whole disk 16 = /dev/sdcd 82nd SCSI disk whole disk 32 = /dev/sdce 83th SCSI disk whole disk @@ -1231,7 +1282,7 @@ 65 = /dev/apsasync Async command interface 128 = /dev/apsmon Monitor interface - block SCSI disk devices (96-111) + 70 block SCSI disk devices (96-111) 0 = /dev/sdcs 97th SCSI disk whole disk 16 = /dev/sdct 98th SCSI disk whole disk 32 = /dev/sdcu 99th SCSI disk whole disk @@ -1260,7 +1311,7 @@ ... 255 = /dev/ttyF255 IntelliPort II board 3, port 63 - block SCSI disk devices (112-127) + 71 block SCSI disk devices (112-127) 0 = /dev/sddi 113th SCSI disk whole disk 16 = /dev/sddj 114th SCSI disk whole disk 32 = /dev/sddk 115th SCSI disk whole disk @@ -1289,7 +1340,7 @@ ... 255 = /dev/cuf255 Callout device for ttyF255 - block Compaq Intelligent Drive Array, first controller + 72 block Compaq Intelligent Drive Array, first controller 0 = /dev/ida/c0d0 First logical drive whole disk 16 = /dev/ida/c0d1 Second logical drive whole disk ... @@ -1309,7 +1360,7 @@ 12 = /dev/ip2ipl3 Loadware device for board 3 13 = /dev/ip2stat3 Status device for board 3 - block Compaq Intelligent Drive Array, second controller + 73 block Compaq Intelligent Drive Array, second controller 0 = /dev/ida/c1d0 First logical drive whole disk 16 = /dev/ida/c1d1 Second logical drive whole disk ... @@ -1327,7 +1378,7 @@ Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. - block Compaq Intelligent Drive Array, third controller + 74 block Compaq Intelligent Drive Array, third controller 0 = /dev/ida/c2d0 First logical drive whole disk 16 = /dev/ida/c2d1 Second logical drive whole disk ... @@ -1344,7 +1395,7 @@ 8 = /dev/ttyW8 First IO8+ port, second card ... - block Compaq Intelligent Drive Array, fourth controller + 75 block Compaq Intelligent Drive Array, fourth controller 0 = /dev/ida/c3d0 First logical drive whole disk 16 = /dev/ida/c3d1 Second logical drive whole disk ... @@ -1361,7 +1412,7 @@ 8 = /dev/cuw8 Callout device for ttyW8 ... - block Compaq Intelligent Drive Array, fifth controller + 76 block Compaq Intelligent Drive Array, fifth controller 0 = /dev/ida/c4d0 First logical drive whole disk 16 = /dev/ida/c4d1 Second logical drive whole disk ... @@ -1375,7 +1426,7 @@ 77 char ComScire Quantum Noise Generator 0 = /dev/qng ComScire Quantum Noise Generator - block Compaq Intelligent Drive Array, sixth controller + 77 block Compaq Intelligent Drive Array, sixth controller 0 = /dev/ida/c5d0 First logical drive whole disk 16 = /dev/ida/c5d1 Second logical drive whole disk ... @@ -1391,7 +1442,7 @@ 1 = /dev/ttyM1 Second PAM modem ... - block Compaq Intelligent Drive Array, seventh controller + 78 block Compaq Intelligent Drive Array, seventh controller 0 = /dev/ida/c6d0 First logical drive whole disk 16 = /dev/ida/c6d1 Second logical drive whole disk ... @@ -1407,7 +1458,7 @@ 1 = /dev/cum1 Callout device for ttyM1 ... - block Compaq Intelligent Drive Array, eigth controller + 79 block Compaq Intelligent Drive Array, eigth controller 0 = /dev/ida/c7d0 First logical drive whole disk 16 = /dev/ida/c7d1 Second logical drive whole disk ... @@ -1421,7 +1472,7 @@ 80 char Photometrics AT200 CCD camera 0 = /dev/at200 Photometrics AT200 CCD camera - block I2O hard disk + 80 block I2O hard disk 0 = /dev/i2o/hda First I2O hard disk, whole disk 16 = /dev/i2o/hdb Second I2O hard disk, whole disk ... @@ -1445,7 +1496,7 @@ ... 255 = /dev/vbi31 Vertical blank interrupt - block I2O hard disk + 81 block I2O hard disk 0 = /dev/i2o/hdq 17th I2O hard disk, whole disk 16 = /dev/i2o/hdr 18th I2O hard disk, whole disk ... @@ -1463,7 +1514,7 @@ The driver and documentation may be obtained from http://www.proximity.com.au/~brian/winradio/ - block I2O hard disk + 82 block I2O hard disk 0 = /dev/i2o/hdag 33rd I2O hard disk, whole disk 16 = /dev/i2o/hdah 34th I2O hard disk, whole disk ... @@ -1480,7 +1531,7 @@ Devices for the driver contained in the VideoteXt package. More information on http://home.pages.de/~videotext/ - block I2O hard disk + 83 block I2O hard disk 0 = /dev/i2o/hdaw 49th I2O hard disk, whole disk 16 = /dev/i2o/hdax 50th I2O hard disk, whole disk ... @@ -1494,7 +1545,7 @@ 0 = /dev/ihcp0 First Greensheet port 1 = /dev/ihcp1 Second Greensheet port - block I2O hard disk + 84 block I2O hard disk 0 = /dev/i2o/hdbm 65th I2O hard disk, whole disk 16 = /dev/i2o/hdbn 66th I2O hard disk, whole disk ... @@ -1510,7 +1561,7 @@ 2 = /dev/qcntl1 Second device pushed ... - block I2O hard disk + 85 block I2O hard disk 0 = /dev/i2o/hdcc 81st I2O hard disk, whole disk 16 = /dev/i2o/hdcd 82nd I2O hard disk, whole disk ... @@ -1525,7 +1576,7 @@ 1 = /dev/sch1 Second SCSI media changer ... - block I2O hard disk + 86 block I2O hard disk 0 = /dev/i2o/hdcs 97th I2O hard disk, whole disk 16 = /dev/i2o/hdct 98th I2O hard disk, whole disk ... @@ -1540,7 +1591,7 @@ 1 = /dev/controla1 Second device on chain ... - block I2O hard disk + 87 block I2O hard disk 0 = /dev/i2o/hddi 113rd I2O hard disk, whole disk 16 = /dev/i2o/hddj 114th I2O hard disk, whole disk ... @@ -1555,7 +1606,7 @@ 1 = /dev/comx1 COMX channel 1 ... - block Seventh IDE hard disk/CD-ROM interface + 88 block Seventh IDE hard disk/CD-ROM interface 0 = /dev/hdm Master: whole disk (or CD-ROM) 64 = /dev/hdn Slave: whole disk (or CD-ROM) @@ -1567,7 +1618,7 @@ 1 = /dev/i2c-1 Second I2C adapter ... - block Eighth IDE hard disk/CD-ROM interface + 89 block Eighth IDE hard disk/CD-ROM interface 0 = /dev/hdo Master: whole disk (or CD-ROM) 64 = /dev/hdp Slave: whole disk (or CD-ROM) @@ -1581,7 +1632,7 @@ 30 = /dev/mtd15 16th MTD (rw) 31 = /dev/mtdr15 16th MTD (ro) - block Ninth IDE hard disk/CD-ROM interface + 90 block Ninth IDE hard disk/CD-ROM interface 0 = /dev/hdq Master: whole disk (or CD-ROM) 64 = /dev/hdr Slave: whole disk (or CD-ROM) @@ -1593,7 +1644,7 @@ 1 = /dev/can1 Second CAN-Bus controller ... - block Tenth IDE hard disk/CD-ROM interface + 91 block Tenth IDE hard disk/CD-ROM interface 0 = /dev/hds Master: whole disk (or CD-ROM) 64 = /dev/hdt Slave: whole disk (or CD-ROM) @@ -1602,7 +1653,7 @@ 92 char Reserved for ith Kommunikationstechnik MIC ISDN card - block PPDD encrypted disk driver + 92 block PPDD encrypted disk driver 0 = /dev/ppdd0 First encrypted disk 1 = /dev/ppdd1 Second encrypted disk ... @@ -1619,7 +1670,7 @@ 129 = /dev/isccctl1 Second Smart Capture Card control ... - block NAND Flash Translation Layer filesystem + 93 block NAND Flash Translation Layer filesystem 0 = /dev/nftla First NFTL layer 16 = /dev/nftlb Second NFTL layer ... @@ -1630,16 +1681,11 @@ 1 = /dev/dcxx1 Second capture card ... - block IBM S/390 DASD block storage - 0 = /dev/dasda First DASD device, major - 1 = /dev/dasda1 First DASD device, block 1 - 2 = /dev/dasda2 First DASD device, block 2 - 3 = /dev/dasda3 First DASD device, block 3 - 4 = /dev/dasdb Second DASD device, major - 5 = /dev/dasdb1 Second DASD device, block 1 - 6 = /dev/dasdb2 Second DASD device, block 2 - 7 = /dev/dasdb3 Second DASD device, block 3 + 94 block Inverse NAND Flash Translation Layer + 0 = /dev/inftla First INFTL layer + 16 = /dev/inftlb Second INFTL layer ... + 240 = /dev/inftlp 16th INTFL layer 95 char IP filter 0 = /dev/ipl Filter control device/log file @@ -1648,9 +1694,15 @@ 3 = /dev/ipauth Authentication control device/log file ... - block IBM S/390 VM/ESA minidisk - 0 = /dev/mnda First VM/ESA minidisk - 1 = /dev/mndb Second VM/ESA minidisk + 95 block IBM S/390 DASD block storage + 0 = /dev/dasd0 First DASD device, major + 1 = /dev/dasd0a First DASD device, block 1 + 2 = /dev/dasd0b First DASD device, block 2 + 3 = /dev/dasd0c First DASD device, block 3 + 4 = /dev/dasd1 Second DASD device, major + 5 = /dev/dasd1a Second DASD device, block 1 + 6 = /dev/dasd1b Second DASD device, block 2 + 7 = /dev/dasd1c Second DASD device, block 3 ... 96 char Parallel port ATAPI tape devices @@ -1661,6 +1713,11 @@ 129 = /dev/npt1 Second p.p. ATAPI tape, no rewind ... + 96 block IBM S/390 VM/ESA minidisk + 0 = /dev/msd0 First VM/ESA minidisk + 1 = /dev/msd1 Second VM/ESA minidisk + ... + 97 char Parallel port generic ATAPI interface 0 = /dev/pg0 First parallel port ATAPI device 1 = /dev/pg1 Second parallel port ATAPI device @@ -1670,7 +1727,7 @@ These devices support the same API as the generic SCSI devices. - block Packet writing for CD/DVD devices + 97 block Packet writing for CD/DVD devices 0 = /dev/pktcdvd0 First packet-writing module 1 = /dev/pktcdvd1 Second packet-writing module ... @@ -1682,7 +1739,7 @@ See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/. - block User-mode virtual block device + 98 block User-mode virtual block device 0 = /dev/ubd0 First user-mode block device 1 = /dev/ubd1 Second user-mode block device ... @@ -1694,7 +1751,7 @@ 1 = /dev/parport1 Second parallel port ... - block JavaStation flash disk + 99 block JavaStation flash disk 0 = /dev/jsfd JavaStation flash disk 100 char Telephony for Linux @@ -1708,7 +1765,7 @@ ... 16 = /dev/mdsp16 16th DSP board I/O controls - block AMI HyperDisk RAID controller +101 block AMI HyperDisk RAID controller 0 = /dev/amiraid/ar0 First array whole disk 16 = /dev/amiraid/ar1 Second array whole disk ... @@ -1727,7 +1784,7 @@ 2 = /dev/tlk2 Third Teletext decoder 3 = /dev/tlk3 Fourth Teletext decoder - block Compressed block device +102 block Compressed block device 0 = /dev/cbd/a First compressed block device, whole device 16 = /dev/cbd/b Second compressed block device, whole device ... @@ -1747,12 +1804,12 @@ to the arla announce mailing list by sending a mail to . - block Audit device +103 block Audit device 0 = /dev/audit Audit device 104 char Flash BIOS support - block Compaq Next Generation Drive Array, first controller +104 block Compaq Next Generation Drive Array, first controller 0 = /dev/cciss/c0d0 First logical drive, whole disk 16 = /dev/cciss/c0d1 Second logical drive, whole disk ... @@ -1767,7 +1824,7 @@ 1 = /dev/ttyV1 Second VS-1000 port ... - block Compaq Next Generation Drive Array, second controller +105 block Compaq Next Generation Drive Array, second controller 0 = /dev/cciss/c1d0 First logical drive, whole disk 16 = /dev/cciss/c1d1 Second logical drive, whole disk ... @@ -1782,7 +1839,7 @@ 1 = /dev/cuv1 Second VS-1000 port ... - block Compaq Next Generation Drive Array, third controller +106 block Compaq Next Generation Drive Array, third controller 0 = /dev/cciss/c2d0 First logical drive, whole disk 16 = /dev/cciss/c2d1 Second logical drive, whole disk ... @@ -1795,7 +1852,7 @@ 107 char 3Dfx Voodoo Graphics device 0 = /dev/3dfx Primary 3Dfx graphics device - block Compaq Next Generation Drive Array, fourth controller +107 block Compaq Next Generation Drive Array, fourth controller 0 = /dev/cciss/c3d0 First logical drive, whole disk 16 = /dev/cciss/c3d1 Second logical drive, whole disk ... @@ -1808,7 +1865,7 @@ 108 char Device independent PPP interface 0 = /dev/ppp Device independent PPP interface - block Compaq Next Generation Drive Array, fifth controller +108 block Compaq Next Generation Drive Array, fifth controller 0 = /dev/cciss/c4d0 First logical drive, whole disk 16 = /dev/cciss/c4d1 Second logical drive, whole disk ... @@ -1820,7 +1877,7 @@ 109 char Reserved for logical volume manager - block Compaq Next Generation Drive Array, sixth controller +109 block Compaq Next Generation Drive Array, sixth controller 0 = /dev/cciss/c5d0 First logical drive, whole disk 16 = /dev/cciss/c5d1 Second logical drive, whole disk ... @@ -1835,7 +1892,7 @@ 1 = /dev/srnd1 Second miroMEDIA Surround board ... - block Compaq Next Generation Drive Array, seventh controller +110 block Compaq Next Generation Drive Array, seventh controller 0 = /dev/cciss/c6d0 First logical drive, whole disk 16 = /dev/cciss/c6d1 Second logical drive, whole disk ... @@ -1850,7 +1907,7 @@ 1 = /dev/av1 Second A/V card ... - block Compaq Next Generation Drive Array, eigth controller +111 block Compaq Next Generation Drive Array, eigth controller 0 = /dev/cciss/c7d0 First logical drive, whole disk 16 = /dev/cciss/c7d1 Second logical drive, whole disk ... @@ -1868,14 +1925,14 @@ There is currently a device-naming conflict between these and PAM multimodems (major 78). - block IBM iSeries virtual disk +112 block IBM iSeries virtual disk 0 = /dev/iseries/vda First virtual disk, whole disk 8 = /dev/iseries/vdb Second virtual disk, whole disk ... 200 = /dev/iseries/vdz 26th virtual disk, whole disk 208 = /dev/iseries/vdaa 27th virtual disk, whole disk ... - 240 = /dev/iseries/vdaf 32nd virtual disk, whole disk + 248 = /dev/iseries/vdaf 32nd virtual disk, whole disk Partitions are handled in the same way as for IDE disks (see major number 3) except that the limit on @@ -1886,7 +1943,7 @@ 1 = /dev/cum1 Callout device for ttyM1 ... - block IBM iSeries virtual CD-ROM +113 block IBM iSeries virtual CD-ROM 0 = /dev/iseries/vcda First virtual CD-ROM 1 = /dev/iseries/vcdb Second virtual CD-ROM @@ -1905,13 +1962,69 @@ I/O access to the board, the /dev/isex0 nodes command nodes used to control the board. -115 char Console driver speaker - 0 = /dev/speaker Speaker device file +114 block IDE BIOS powered software RAID interfaces such as the + Promise Fastrak - Plays music using IBM BASIC style strings. + 0 = /dev/ataraid/d0 + 1 = /dev/ataraid/d0p1 + 2 = /dev/ataraid/d0p2 + ... + 16 = /dev/ataraid/d1 + 17 = /dev/ataraid/d1p1 + 18 = /dev/ataraid/d1p2 + ... + 255 = /dev/ataraid/d15p15 + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + +115 char TI link cable devices (115 was formerly the console driver speaker) + 0 = /dev/tipar0 Parallel cable on first parallel port + ... + 7 = /dev/tipar7 Parallel cable on seventh parallel port + + 8 = /dev/tiser0 Serial cable on first serial port + ... + 15 = /dev/tiser7 Serial cable on seventh serial port + + 16 = /dev/tiusb0 First USB cable + ... + 47 = /dev/tiusb31 32nd USB cable + +115 block NetWare (NWFS) Devices (0-255) + + The NWFS (NetWare) devices are used to present a + collection of NetWare Mirror Groups or NetWare + Partitions as a logical storage segment for + use in mounting NetWare volumes. A maximum of + 256 NetWare volumes can be supported in a single + machine. + + http://www.kernel.org/pub/linux/kernel/people/jmerkey/nwfs + + 0 = /dev/nwfs/v0 First NetWare (NWFS) Logical Volume + 1 = /dev/nwfs/v1 Second NetWare (NWFS) Logical Volume + 2 = /dev/nwfs/v2 Third NetWare (NWFS) Logical Volume + ... + 255 = /dev/nwfs/v255 Last NetWare (NWFS) Logical Volume 116 char Advanced Linux Sound Driver (ALSA) +116 block MicroMemory battery backed RAM adapter (NVRAM) + Supports 16 boards, 15 paritions each. + Requested by neilb at cse.unsw.edu.au. + + 0 = /dev/umem/d0 Whole of first board + 1 = /dev/umem/d0p1 First partition of first board + 2 = /dev/umem/d0p2 Second partition of first board + 15 = /dev/umem/d0p15 15th partition of first board + + 16 = /dev/umem/d1 Whole of second board + 17 = /dev/umem/d1p1 First partition of second board + ... + 255= /dev/umem/d15p15 15th partition of 16th board. + 117 char COSA/SRP synchronous serial card 0 = /dev/cosa0c0 1st board, 1st channel 1 = /dev/cosa0c1 1st board, 2nd channel @@ -1920,6 +2033,32 @@ 17 = /dev/cosa1c1 2nd board, 2nd channel ... +117 block Enterprise Volume Management System (EVMS) + + The EVMS driver uses a layered, plug-in model to provide + unparalleled flexibility and extensibility in managing + storage. This allows for easy expansion or customization + of various levels of volume management. Requested by + Mark Peloquin (peloquin at us.ibm.com). + + Note: EVMS populates and manages all the devnodes in + /dev/evms. + + http://sf.net/projects/evms + + 0 = /dev/evms/block_device EVMS block device + 1 = /dev/evms/legacyname1 First EVMS legacy device + 2 = /dev/evms/legacyname2 Second EVMS legacy device + ... + Both ranges can grow (down or up) until they meet. + ... + 254 = /dev/evms/EVMSname2 Second EVMS native device + 255 = /dev/evms/EVMSname1 First EVMS native device + + Note: legacyname(s) are derived from the normal legacy + device names. For example, /dev/hda5 would become + /dev/evms/hda5. + 118 char Solidum ??? 0 = /dev/solnp0 1 = /dev/solnp1 @@ -1933,14 +2072,114 @@ 1 = /dev/vnet1 2nd virtual network ... -120-127 LOCAL/EXPERIMENTAL USE +120-127 char LOCAL/EXPERIMENTAL USE +120-127 block LOCAL/EXPERIMENTAL USE + Allocated for local/experimental use. For devices not + assigned official numbers, these ranges should be + used in order to avoid conflicting with future assignments. -128-135 char Unix98 PTY masters +128-135 char Unix98 PTY masters These devices should not have corresponding device nodes; instead they should be accessed through the /dev/ptmx cloning interface. + +128 block SCSI disk devices (128-143) + 0 = /dev/sddy 129th SCSI disk whole disk + 16 = /dev/sddz 130th SCSI disk whole disk + 32 = /dev/sdea 131th SCSI disk whole disk + ... + 240 = /dev/sden 144th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +129 block SCSI disk devices (144-159) + 0 = /dev/sdeo 145th SCSI disk whole disk + 16 = /dev/sdep 146th SCSI disk whole disk + 32 = /dev/sdeq 147th SCSI disk whole disk + ... + 240 = /dev/sdfd 160th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +130 block SCSI disk devices (160-175) + 0 = /dev/sdfe 161st SCSI disk whole disk + 16 = /dev/sdff 162nd SCSI disk whole disk + 32 = /dev/sdfg 163rd SCSI disk whole disk + ... + 240 = /dev/sdft 176th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + +131 block SCSI disk devices (176-191) + 0 = /dev/sdfu 177th SCSI disk whole disk + 16 = /dev/sdfv 178th SCSI disk whole disk + 32 = /dev/sdfw 179th SCSI disk whole disk + ... + 240 = /dev/sdgj 192nd SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +132 block SCSI disk devices (192-207) + 0 = /dev/sdgk 193rd SCSI disk whole disk + 16 = /dev/sdgl 194th SCSI disk whole disk + 32 = /dev/sdgm 195th SCSI disk whole disk + ... + 240 = /dev/sdgz 208th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +133 block SCSI disk devices (208-223) + 0 = /dev/sdha 209th SCSI disk whole disk + 16 = /dev/sdhb 210th SCSI disk whole disk + 32 = /dev/sdhc 211th SCSI disk whole disk + ... + 240 = /dev/sdhp 224th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +134 block SCSI disk devices (224-239) + 0 = /dev/sdhq 225th SCSI disk whole disk + 16 = /dev/sdhr 226th SCSI disk whole disk + 32 = /dev/sdhs 227th SCSI disk whole disk + ... + 240 = /dev/sdif 240th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + +135 block SCSI disk devices (240-255) + 0 = /dev/sdig 241st SCSI disk whole disk + 16 = /dev/sdih 242nd SCSI disk whole disk + 32 = /dev/sdih 243rd SCSI disk whole disk + ... + 240 = /dev/sdiv 256th SCSI disk whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + + 136-143 char Unix98 PTY slaves 0 = /dev/pts/0 First Unix98 pseudo-TTY 1 = /dev/pts/1 Second Unix98 pesudo-TTY @@ -1953,6 +2192,70 @@ *most* distributions the appropriate options are "mode=0620,gid=".) +136 block Mylex DAC960 PCI RAID controller; ninth controller + 0 = /dev/rd/c8d0 First disk, whole disk + 8 = /dev/rd/c8d1 Second disk, whole disk + ... + 248 = /dev/rd/c8d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +137 block Mylex DAC960 PCI RAID controller; tenth controller + 0 = /dev/rd/c9d0 First disk, whole disk + 8 = /dev/rd/c9d1 Second disk, whole disk + ... + 248 = /dev/rd/c9d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +138 block Mylex DAC960 PCI RAID controller; eleventh controller + 0 = /dev/rd/c10d0 First disk, whole disk + 8 = /dev/rd/c10d1 Second disk, whole disk + ... + 248 = /dev/rd/c10d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +139 block Mylex DAC960 PCI RAID controller; twelfth controller + 0 = /dev/rd/c11d0 First disk, whole disk + 8 = /dev/rd/c11d1 Second disk, whole disk + ... + 248 = /dev/rd/c11d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +140 block Mylex DAC960 PCI RAID controller; thirteenth controller + 0 = /dev/rd/c12d0 First disk, whole disk + 8 = /dev/rd/c12d1 Second disk, whole disk + ... + 248 = /dev/rd/c12d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +141 block Mylex DAC960 PCI RAID controller; fourteenth controller + 0 = /dev/rd/c13d0 First disk, whole disk + 8 = /dev/rd/c13d1 Second disk, whole disk + ... + 248 = /dev/rd/c13d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +142 block Mylex DAC960 PCI RAID controller; fifteenth controller + 0 = /dev/rd/c14d0 First disk, whole disk + 8 = /dev/rd/c14d1 Second disk, whole disk + ... + 248 = /dev/rd/c14d31 32nd disk, whole disk + + Partitions are handled as for major 48. + +143 block Mylex DAC960 PCI RAID controller; sixteenth controller + 0 = /dev/rd/c15d0 First disk, whole disk + 8 = /dev/rd/c15d1 Second disk, whole disk + ... + 248 = /dev/rd/c15d31 32nd disk, whole disk + + Partitions are handled as for major 48. + 144 char Encapsulated PPP 0 = /dev/pppox0 First PPP over Ethernet ... @@ -1963,6 +2266,10 @@ The SST 5136-DN DeviceNet interface driver has been relocated to major 183 due to an unfortunate conflict. +144 block Expansion Area #1 for more non-device (e.g. NFS) mounts + 0 = mounted device 256 + 255 = mounted device 511 + 145 char SAM9407-based soundcard 0 = /dev/sam0_mixer 1 = /dev/sam0_sequencer @@ -1984,12 +2291,20 @@ addons, which are sam9407 specific. OSS can be operated simultaneously, taking care of the codec. +145 block Expansion Area #2 for more non-device (e.g. NFS) mounts + 0 = mounted device 512 + 255 = mounted device 767 + 146 char SYSTRAM SCRAMNet mirrored-memory network 0 = /dev/scramnet0 First SCRAMNet device 1 = /dev/scramnet1 Second SCRAMNet device ... -147 char Aueral Semiconductor Vortex Audio device +146 block Expansion Area #3 for more non-device (e.g. NFS) mounts + 0 = mounted device 768 + 255 = mounted device 1023 + +147 char Aureal Semiconductor Vortex Audio device 0 = /dev/aureal0 First Aureal Vortex 1 = /dev/aureal1 Second Aureal Vortex ... @@ -2014,6 +2329,22 @@ 1 = /dev/dpti1 Second DPT I2O adapter ... +152 char EtherDrive Control Device + 0 = /dev/etherd/ctl Connect/Disconnect an EtherDrive + 1 = /dev/etherd/err Monitor errors + 2 = /dev/etherd/raw Raw AoE packet monitor + +152 block EtherDrive Block Devices + 0 = /dev/etherd/0 EtherDrive 0 + ... + 255 = /dev/etherd/255 EtherDrive 255 + +153 char SPI Bus Interface (sometimes referred to as MicroWire) + 0 = /dev/spi0 First SPI device on the bus + 1 = /dev/spi1 Second SPI device on the bus + ... + 15 = /dev/spi15 Sixteenth SPI device on the bus + 154 char Specialix RIO serial card 0 = /dev/ttySR0 First RIO port ... @@ -2046,6 +2377,21 @@ 1 = /dev/gpib1 Second GPIB bus ... +160 block Carmel 8-port SATA Disks on First Controller + 0 = /dev/carmel/0 SATA disk 0 whole disk + 1 = /dev/carmel/0p1 SATA disk 0 partition 1 + ... + 31 = /dev/carmel/0p31 SATA disk 0 partition 31 + + 32 = /dev/carmel/1 SATA disk 1 whole disk + 64 = /dev/carmel/2 SATA disk 2 whole disk + ... + 224 = /dev/carmel/7 SATA disk 7 whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 31. + 161 char IrCOMM devices (IrDA serial/parallel emulation) 0 = /dev/ircomm0 First IrCOMM device 1 = /dev/ircomm1 Second IrCOMM device @@ -2054,16 +2400,28 @@ 17 = /dev/irlpt1 Second IrLPT device ... +161 block Carmel 8-port SATA Disks on Second Controller + 0 = /dev/carmel/8 SATA disk 8 whole disk + 1 = /dev/carmel/8p1 SATA disk 8 partition 1 + ... + 31 = /dev/carmel/8p31 SATA disk 8 partition 31 + + 32 = /dev/carmel/9 SATA disk 9 whole disk + 64 = /dev/carmel/10 SATA disk 10 whole disk + ... + 224 = /dev/carmel/15 SATA disk 15 whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 31. + 162 char Raw block device interface 0 = /dev/rawctl Raw I/O control device 1 = /dev/raw/raw1 First raw I/O device 2 = /dev/raw/raw2 Second raw I/O device ... -163 char Radio Tech BIM-XXX-RS232 radio modem - 0 = /dev/bimrt0 First BIM radio modem - 1 = /dev/bimrt1 Second BIM radio modem - ... +163 char UNASSIGNED (was Radio Tech BIM-XXX-RS232 radio modem - see 51) 164 char Chase Research AT/PCI-Fast serial card 0 = /dev/ttyCH0 AT/PCI-Fast board 0, port 0 @@ -2175,6 +2533,9 @@ ... 63 = /dev/usb/scanner15 16th USB scanner 64 = /dev/usb/rio500 Diamond Rio 500 + 65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de) + 66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD) + 181 char Conrad Electronic parallel port radio clocks 0 = /dev/pcfclock0 First Conrad radio clock @@ -2295,9 +2656,10 @@ 0 = /dev/vx/rdsk/*/* First volume 1 = /dev/vx/rdsk/*/* Second volume ... - block Veritas volume manager (VxVM) volumes + +199 block Veritas volume manager (VxVM) volumes 0 = /dev/vx/dsk/*/* First volume - 1 = /dev/vx/dsk/*/* First volume + 1 = /dev/vx/dsk/*/* Second volume ... The namespace in these directories is maintained by @@ -2315,7 +2677,7 @@ 0 = /dev/vx/rdmp/* First multipath device 1 = /dev/vx/rdmp/* Second multipath device ... - block Veritas VxVM dynamic multipathing driver +201 block Veritas VxVM dynamic multipathing driver 0 = /dev/vx/dmp/* First multipath device 1 = /dev/vx/dmp/* Second multipath device ... @@ -2469,6 +2831,26 @@ 1 = /dev/addinum/cpci1500/1 Second CPCI1500 card ... +212 char LinuxTV.org DVB driver subsystem + + 0 = /dev/dvb/adapter0/video0 first video decoder of first card + 1 = /dev/dvb/adapter0/audio0 first audio decoder of first card + 2 = /dev/dvb/adapter0/sec0 (obsolete/unused) + 3 = /dev/dvb/adapter0/frontend0 first frontend device of first card + 4 = /dev/dvb/adapter0/demux0 first demux device of first card + 5 = /dev/dvb/adapter0/dvr0 first digital video recoder device of first card + 6 = /dev/dvb/adapter0/ca0 first common access port of first card + 7 = /dev/dvb/adapter0/net0 first network device of first card + 8 = /dev/dvb/adapter0/osd0 first on-screen-display device of first card + 9 = /dev/dvb/adapter0/video1 second video decoder of first card + ... + 64 = /dev/dvb/adapter1/video0 first video decoder of second card + ... + 128 = /dev/dvb/adapter2/video0 first video decoder of third card + ... + 196 = /dev/dvb/adapter3/video0 first video decoder of fourth card + + 216 char USB BlueTooth devices 0 = /dev/ttyUB0 First USB BlueTooth device 1 = /dev/ttyUB1 Second USB BlueTooth device @@ -2575,9 +2957,14 @@ 231-239 UNASSIGNED -240-254 LOCAL/EXPERIMENTAL USE +240-254 char LOCAL/EXPERIMENTAL USE +240-254 block LOCAL/EXPERIMENTAL USE + Allocated for local/experimental use. For devices not + assigned official numbers, these ranges should be + used in order to avoid conflicting with future assignments. -255 RESERVED +255 char RESERVED +255 block RESERVED This major is reserved to assist the expansion to a larger number space. No device nodes with this major diff -Nru a/Documentation/filesystems/udf.txt b/Documentation/filesystems/udf.txt --- a/Documentation/filesystems/udf.txt Sat Apr 3 19:38:55 2004 +++ b/Documentation/filesystems/udf.txt Sat Apr 3 19:38:55 2004 @@ -1,7 +1,7 @@ * * ./Documentation/filesystems/udf.txt * -UDF Filesystem version 0.9.5 +UDF Filesystem version 0.9.8.1 If you encounter problems with reading UDF discs using this driver, please report them to linux_udf@hpesjro.fc.hp.com, which is the @@ -16,7 +16,7 @@ gid= Set the default group. umask= Set the default umask. uid= Set the default user. - bs= Set the block size. + bs= Set the block size. unhide Show otherwise hidden files. undelete Show deleted files in lists. adinicb Embed data in the inode (default) @@ -47,15 +47,11 @@ ------------------------------------------------------------------------------- -For more information see: - http://www.trylinux.com/projects/udf/index.html - For the latest version and toolset see: - http://www.csc.calpoly.edu/~bfennema/udf.html http://linux-udf.sourceforge.net/ Documentation on UDF and ECMA 167 is available FREE from: - http://www.osta.org/ - http://www.ecma.ch/ + http://www.osta.org/ + http://www.ecma-international.org/ Ben Fennema diff -Nru a/Documentation/filesystems/ufs.txt b/Documentation/filesystems/ufs.txt --- a/Documentation/filesystems/ufs.txt Sat Apr 3 19:38:54 2004 +++ b/Documentation/filesystems/ufs.txt Sat Apr 3 19:38:54 2004 @@ -20,6 +20,9 @@ 44bsd used in FreeBSD, NetBSD, OpenBSD supported os read-write + ufs2 used in FreeBSD 5.x + supported os read-only + sun used in SunOS (Solaris) supported as read-write diff -Nru a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface --- a/Documentation/i2c/sysfs-interface Sat Apr 3 19:38:41 2004 +++ b/Documentation/i2c/sysfs-interface Sat Apr 3 19:38:41 2004 @@ -3,22 +3,44 @@ The libsensors library offers an interface to the raw sensors data through the sysfs interface. See libsensors documentation and source for -more further information. +more further information. As of writing this document, libsensors +(from lm_sensors 2.8.3) is heavily chip-dependant. Adding or updating +support for any given chip requires modifying the library's code. +This is because libsensors was written for the procfs interface +older kernel modules were using, which wasn't standardized enough. +Recent versions of libsensors (from lm_sensors 2.8.2 and later) have +support for the sysfs interface, though. + +The new sysfs interface was designed to be as chip-independant as +possible. + +Note that motherboards vary widely in the connections to sensor chips. +There is no standard that ensures, for example, that the second +temperature sensor is connected to the CPU, or that the second fan is on +the CPU. Also, some values reported by the chips need some computation +before they make full sense. For example, most chips can only measure +voltages between 0 and +4V. Other voltages are scaled back into that +range using external resistors. Since the values of these resistors +can change from motherboard to motherboard, the conversions cannot be +hard coded into the driver and have to be done in user space. + +For this reason, even if we aim at a chip-independant libsensors, it will +still require a configuration file (e.g. /etc/sensors.conf) for proper +values conversion, labeling of inputs and hiding of unused inputs. An alternative method that some programs use is to access the sysfs files directly. This document briefly describes the standards that the drivers follow, so that an application program can scan for entries and -access this data in a simple and consistent way. +access this data in a simple and consistent way. That said, such programs +will have to implement conversion, labeling and hiding of inputs. For +this reason, it is still not recommended to bypass the library. If you are developing a userspace application please send us feedback on this standard. -Note that motherboards vary widely in the connections to sensor chips. -There is no standard that ensures, for example, that the second -temperature sensor is connected to the CPU, or that the second fan is on -the CPU. Therefore, programs must provide a facility for the user to -label or bind /proc entries for display. Sensor chips often have unused -inputs that should be ignored by user programs. +Note that this standard isn't completely established yet, so it is subject +to changes, even important ones. One more reason to use the library instead +of accessing sysfs files directly. Each chip gets its own directory in the sysfs /sys/devices tree. To find all sensor chips, it is easier to follow the symlinks from @@ -28,6 +50,15 @@ of the values, you should divide by the specified value. There is only one value per file, unlike the older /proc specification. +The common scheme for files naming is: _. Usual +types for sensor chips are "in" (voltage), "temp" (temperature) and +"fan" (fan). Usual items are "input" (measured value), "max" (high +threshold, "min" (low threshold). Numbering usually starts from 1, +except for voltages which start from 0 (because most data sheets use +this). A number is always used for elements that can be present more +than once, even if there is a single element of the given type on the +specific chip. Other files do not refer to a specific element, so +they have a simple name, and no number. Alarms are direct indications read from the chips. The drivers do NOT make comparisons of readings to thresholds. This allows violations @@ -38,71 +69,21 @@ ------------------------------------------------------------------------- -sysfs entries are as follows: - - -Entry Function ------ -------- -alarms Alarm bitmask. - Read only. - Integer representation of one to four bytes. - A '1' bit means an alarm. - Chips should be programmed for 'comparator' mode so that - the alarm will 'come back' after you read the register - if it is still valid. - Generally a direct representation of a chip's internal - alarm registers; there is no standard for the position - of individual bits. - Bits are defined in kernel/include/sensors.h. - -beep_enable Beep/interrupt enable - 0 to disable. - 1 to enable. - Read/Write - -beep_mask Bitmask for beep. - Same format as 'alarms' with the same bit locations. - Read only. - -curr_max[1-n] Current max value - Fixed point XXXXX, divide by 1000 to get Amps. - Read/Write. - -curr_min[1-n] Current min value. - Fixed point XXXXX, divide by 1000 to get Amps. - Read/Write. - -curr_input[1-n] Current input value - Fixed point XXXXX, divide by 1000 to get Amps. - Read only. +************ +* Voltages * +************ -eeprom Raw EEPROM data in binary form. - Read only. - -fan_min[1-3] Fan minimum value - Integer value indicating RPM - Read/Write. - -fan_input[1-3] Fan input value. - Integer value indicating RPM - Read only. - -fan_div[1-3] Fan divisor. - Integers in powers of two (1,2,4,8,16,32,64,128). - Some chips only support values 1,2,4,8. - See doc/fan-divisors for details. - -in_min[0-8] Voltage min value. +in[0-8]_min Voltage min value. Fixed point value in form XXXX. Divide by 1000 to get Volts. Read/Write -in_max[0-8] Voltage max value. +in[0-8]_max Voltage max value. Fixed point value in form XXXX. Divide by 1000 to get Volts. Read/Write -in_input[0-8] Voltage input value. +in[0-8]_input Voltage input value. Fixed point value in form XXXX. Divide by 1000 to get Volts. Read only @@ -116,76 +97,156 @@ These drivers will output the actual voltage. First two values are read/write and third is read only. Typical usage: - in_*0 CPU #1 voltage (not scaled) - in_*1 CPU #1 voltage (not scaled) - in_*2 3.3V nominal (not scaled) - in_*3 5.0V nominal (scaled) - in_*4 12.0V nominal (scaled) - in_*5 -12.0V nominal (scaled) - in_*6 -5.0V nominal (scaled) - in_*7 varies - in_*8 varies + in0_* CPU #1 voltage (not scaled) + in1_* CPU #1 voltage (not scaled) + in2_* 3.3V nominal (not scaled) + in3_* 5.0V nominal (scaled) + in4_* 12.0V nominal (scaled) + in5_* -12.0V nominal (scaled) + in6_* -5.0V nominal (scaled) + in7_* varies + in8_* varies + +in0_ref CPU core reference voltage. + Read only. + Fixed point value in form XXXX corresponding to CPU core + voltage as told to the sensor chip. Divide by 1000 to + get Volts. Not always correct. + +vrm Voltage Regulator Module version number. + Read only. + Two digit number (XX), first is major version, second is + minor version. + Affects the way the driver calculates the core voltage from + the vid pins. See doc/vid for details. + + +******** +* Fans * +******** + +fan[1-3]_min Fan minimum value + Integer value indicating RPM + Read/Write. + +fan[1-3]_input Fan input value. + Integer value indicating RPM + Read only. + +fan[1-3]_div Fan divisor. + Integers in powers of two (1,2,4,8,16,32,64,128). + Some chips only support values 1,2,4,8. + See doc/fan-divisors for details. -pwm[1-3] Pulse width modulation fan control. +fan[1-3]_pwm Pulse width modulation fan control. Integer 0 - 255 Read/Write 255 is max or 100%. Corresponds to the fans 1-3. -pwm_enable[1-3] pwm enable - not always present even if pwm* is. +fan[1-3]_pwm_enable + Switch PWM on and off. + Not always present even if fan*_pwm is. 0 to turn off 1 to turn on Read/Write -sensor[1-3] Sensor type selection. + +**************** +* Temperatures * +**************** + +temp[1-3]_type Sensor type selection. Integers 1,2,3, or thermistor Beta value (3435) Read/Write. -temp_max[1-4] Temperature max value. +temp[1-4]_max Temperature max value. Fixed point value in form XXXXX and should be divided by 1000 to get degrees Celsius. Read/Write value. -temp_min[1-3] Temperature min value. +temp[1-3]_min Temperature min value. Fixed point value in form XXXXX and should be divided by 1000 to get degrees Celsius. Read/Write value. -temp_hyst[1-3] Temperature hysteresis value. +temp[1-3]_max_hyst + Temperature hysteresis value for max limit. Fixed point value in form XXXXX and should be divided by 1000 to get degrees Celsius. Must be reported as an absolute temperature, NOT a delta from the max value. Read/Write value. -temp_input[1-4] Temperature input value. +temp[1-4]_input Temperature input value. Fixed point value in form XXXXX and should be divided by 1000 to get degrees Celsius. Read only value. -temp_crit Temperature critical value, typically greater than all - temp_max values. +temp[1-4]_crit Temperature critical value, typically greater than + corresponding temp_max values. Fixed point value in form XXXXX and should be divided by 1000 to get degrees Celsius. - Common to all temperature channels. Read/Write value. - If there are multiple temperature sensors, temp_*1 is +temp[1-2]_crit_hyst + Temperature hysteresis value for critical limit. + Fixed point value in form XXXXX and should be divided by + 1000 to get degrees Celsius. Must be reported as an + absolute temperature, NOT a delta from the critical value. + Read/Write value. + + If there are multiple temperature sensors, temp1_* is generally the sensor inside the chip itself, generally - reported as "motherboard temperature". temp_*2 to - temp_*4 are generally sensors external to the chip + reported as "motherboard temperature". temp2_* to + temp4_* are generally sensors external to the chip itself, for example the thermal diode inside the CPU or a thermistor nearby. -vid CPU core voltage. + +************ +* Currents * +************ + +Note that no known chip provides current measurements as of writing, +so this part is theoretical, so to say. + +curr[1-n]_max Current max value + Fixed point XXXXX, divide by 1000 to get Amps. + Read/Write. + +curr[1-n]_min Current min value. + Fixed point XXXXX, divide by 1000 to get Amps. + Read/Write. + +curr[1-n]_input Current input value + Fixed point XXXXX, divide by 1000 to get Amps. Read only. - Fixed point value in form XXXX corresponding to CPU core - voltage as told to the sensor chip. Divide by 1000 to - get Volts. Not always correct. -vrm Voltage Regulator Module version number. + +********* +* Other * +********* + +alarms Alarm bitmask. + Read only. + Integer representation of one to four bytes. + A '1' bit means an alarm. + Chips should be programmed for 'comparator' mode so that + the alarm will 'come back' after you read the register + if it is still valid. + Generally a direct representation of a chip's internal + alarm registers; there is no standard for the position + of individual bits. + Bits are defined in kernel/include/sensors.h. + +beep_enable Beep/interrupt enable + 0 to disable. + 1 to enable. + Read/Write + +beep_mask Bitmask for beep. + Same format as 'alarms' with the same bit locations. + Read only. + +eeprom Raw EEPROM data in binary form. Read only. - Two digit number (XX), first is major version, second is - minor version. - Affects the way the driver calculates the core voltage from - the vid pins. See doc/vid for details. diff -Nru a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt --- a/Documentation/i386/zero-page.txt Sat Apr 3 19:38:42 2004 +++ b/Documentation/i386/zero-page.txt Sat Apr 3 19:38:42 2004 @@ -1,7 +1,7 @@ -Summary of empty_zero_page layout (kernel point of view) +Summary of boot_params layout (kernel point of view) ( collected by Hans Lermen and Martin Mares ) -The contents of empty_zero_page are used to pass parameters from the +The contents of boot_params are used to pass parameters from the 16-bit realmode code of the kernel to the 32-bit part. References/settings to it mainly are in: @@ -75,10 +75,4 @@ 0x2cc 4 bytes DISK80_SIG_BUFFER (setup.S) 0x2d0 - 0x600 E820MAP 0x600 - 0x7ff EDDBUF (setup.S) for disk signature read sector -0x600 - 0x7d3 EDDBUF (setup.S) for edd data - -0x800 string, 2K max COMMAND_LINE, the kernel commandline as - copied using CL_OFFSET. - Note: this will be copied once more by setup.c - into a local buffer which is only 256 bytes long. - ( #define COMMAND_LINE_SIZE 256 ) +0x600 - 0x7eb EDDBUF (setup.S) for edd data diff -Nru a/Documentation/ide.txt b/Documentation/ide.txt --- a/Documentation/ide.txt Sat Apr 3 19:38:45 2004 +++ b/Documentation/ide.txt Sat Apr 3 19:38:45 2004 @@ -249,8 +249,6 @@ "hdx=scsi" : the return of the ide-scsi flag, this is useful for allowing ide-floppy, ide-tape, and ide-cdrom|writers to use ide-scsi emulation on a device specific option. - - "hdxlun=xx" : set the drive last logical unit "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, where "xx" is between 20 and 66 inclusive, diff -Nru a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt --- a/Documentation/input/joystick-parport.txt Sat Apr 3 19:38:56 2004 +++ b/Documentation/input/joystick-parport.txt Sat Apr 3 19:38:56 2004 @@ -434,7 +434,7 @@ Using gamecon.c you can connect up to five devices to one parallel port. It uses the following kernel/module command line: - gc=port,pad1,pad2,pad3,pad4,pad5 + gamecon.map=port,pad1,pad2,pad3,pad4,pad5 Where 'port' the number of the parport interface (eg. 0 for parport0). @@ -457,15 +457,15 @@ your controller plugged in before initializing. Should you want to use more than one of parallel ports at once, you can use -gc_2 and gc_3 as additional command line parameters for two more parallel -ports. +gamecon.map2 and gamecon.map3 as additional command line parameters for two +more parallel ports. 3.2 db9.c ~~~~~~~~~ Apart from making an interface, there is nothing difficult on using the db9.c driver. It uses the following kernel/module command line: - db9=port,type + db9.dev=port,type Where 'port' is the number of the parport interface (eg. 0 for parport0). @@ -489,14 +489,14 @@ 10 | Amiga CD32 pad Should you want to use more than one of these joysticks/pads at once, you -can use db9_2 and db9_3 as additional command line parameters for two +can use db9.dev2 and db9.dev3 as additional command line parameters for two more joysticks/pads. 3.3 turbografx.c ~~~~~~~~~~~~~~~~ The turbografx.c driver uses a very simple kernel/module command line: - tgfx=port,js1,js2,js3,js4,js5,js6,js7 + turbografx.map=port,js1,js2,js3,js4,js5,js6,js7 Where 'port' is the number of the parport interface (eg. 0 for parport0). @@ -504,8 +504,8 @@ interface ports 1-7 have. For a standard multisystem joystick, this is 1. Should you want to use more than one of these interfaces at once, you can -use tgfx_2 and tgfx_3 as additional command line parameters for two more -interfaces. +use turbografx.map2 and turbografx.map3 as additional command line parameters +for two more interfaces. 3.4 PC parallel port pinout ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -Nru a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt --- a/Documentation/input/joystick.txt Sat Apr 3 19:38:55 2004 +++ b/Documentation/input/joystick.txt Sat Apr 3 19:38:55 2004 @@ -111,7 +111,7 @@ alias tty-ldisc-2 serport alias char-major-13 input above input joydev ns558 analog - options analog js=gamepad + options analog map=gamepad,none,2btn 2.5 Verifying that it works ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -185,7 +185,7 @@ module command line, when inserting analog.o into the kernel. The parameters are: - js=type,type,type,.... + analog.map=,,,.... 'type' is type of the joystick from the table below, defining joysticks present on gameports in the system, starting with gameport0, second 'type' @@ -419,7 +419,7 @@ Amiga joysticks, connected to an Amiga, are supported by the amijoy.c driver. Since they can't be autodetected, the driver has a command line. - amijoy=a,b + amijoy.map=, a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of the Amiga. diff -Nru a/Documentation/java.txt b/Documentation/java.txt --- a/Documentation/java.txt Sat Apr 3 19:38:45 2004 +++ b/Documentation/java.txt Sat Apr 3 19:38:45 2004 @@ -22,7 +22,7 @@ the kernel (CONFIG_BINFMT_MISC) and set it up properly. If you choose to compile it as a module, you will have to insert it manually with modprobe/insmod, as kmod - can not easy be supported with binfmt_misc. + can not easily be supported with binfmt_misc. Read the file 'binfmt_misc.txt' in this directory to know more about the configuration process. diff -Nru a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt --- a/Documentation/kbuild/makefiles.txt Sat Apr 3 19:38:54 2004 +++ b/Documentation/kbuild/makefiles.txt Sat Apr 3 19:38:54 2004 @@ -119,7 +119,7 @@ obj-y += foo.o This tell kbuild that there is one object in that directory named - foo.o. foo.o will be build from foo.c or foo.S. + foo.o. foo.o will be built from foo.c or foo.S. If foo.o shall be built as a module, the variable obj-m is used. Therefore the following pattern is often used: @@ -334,7 +334,7 @@ --- 3.9 Dependency tracking - Kbuild track dependencies on the following: + Kbuild tracks dependencies on the following: 1) All prerequisite files (both *.c and *.h) 2) CONFIG_ options used in all prerequisite files 3) Command-line used to compile target @@ -411,7 +411,7 @@ --- 4.2 Composite Host Programs Host programs can be made up based on composite objects. - The syntax used to define composite objetcs for host programs is + The syntax used to define composite objects for host programs is similar to the syntax used for kernel objects. $(-objs) list all objects used to link the final executable. @@ -811,7 +811,7 @@ extra-y - extra-y specify additional targets created in current + extra-y specify additional targets created in the current directory, in addition to any targets specified by obj-*. Listing all targets in extra-y is required for two purposes: @@ -829,7 +829,7 @@ --- 6.6 Commands useful for building a boot image - Kbuild provide a few macros that are useful when building a + Kbuild provides a few macros that are useful when building a boot image. if_changed @@ -872,7 +872,7 @@ $(obj)/setup $(obj)/bootsect: %: %.o FORCE $(call if_changed,ld) - In this example there is two possible targets, requiring different + In this example there are two possible targets, requiring different options to the linker. the linker options are specified using the LDFLAGS_$@ syntax - one for each potential target. $(targets) are assinged all potential targets, herby kbuild knows diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Sat Apr 3 19:38:57 2004 +++ b/Documentation/kernel-parameters.txt Sat Apr 3 19:38:57 2004 @@ -98,11 +98,13 @@ strictly ACPI specification compliant. See also Documentation/pm.txt. + + acpi_sleep= [HW,ACPI] Sleep options + Format: { s3_bios, s3_mode } + See Documentation/power/video.txt - acpi_pic_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode - Format: { level | edge } - level Force PIC-mode SCI to Level Trigger (default) - edge Force PIC-mode SCI to Edge Trigge + acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode + Format: { level | edge | high | low } acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs default in APIC mode @@ -116,6 +118,10 @@ acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA Format: ,... + acpi_osi= [HW,ACPI] empty param disables _OSI + + acpi_serialize [HW,ACPI] force serialization of AML methods + ad1816= [HW,OSS] Format: ,,, See also Documentation/sound/oss/AD1816. @@ -154,7 +160,15 @@ Format: ,,, See also header of drivers/scsi/AM53C974.c. - amijoy= [HW,JOY] Amiga joystick support + amijoy.map= [HW,JOY] Amiga joystick support + Map of devices attached to JOY0DAT and JOY1DAT + Format: , + See also Documentation/kernel/input/joystick.txt + + analog.map= [HW,JOY] Analog joystick and gamepad support + Specifies type or capabilities of an analog joystick + connected to one of 16 gameports + Format: ,,.. apc= [HW,SPARC] Power management functions (SPARCstation-4/5 + deriv.) Format: noidle @@ -177,11 +191,18 @@ atascsi= [HW,SCSI] Atari SCSI - atkbd.set= [HW] Select keyboard code set - Format: + atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey + and similar keyboards + + atkbd.reset= [HW] Reset keyboard during initialization + + atkbd.set= [HW] Select keyboard code set + Format: (2 = AT (default) 3 = PS/2) + + atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar keyboards + atkbd.softrepeat= [HW] Use software keyboard repeat - atkbd.reset= [HW] Reset keyboard during initialization autotest [IA64] @@ -283,10 +304,11 @@ dasd= [HW,NET] See header of drivers/s390/block/dasd_devmap.c. - db9= [HW,JOY] - db9_2= - db9_3= - + db9.dev[2|3]= [HW,JOY] Multisystem joystick support via parallel port + (one device per port) + Format: , + See also Documentation/input/joystick-parport.txt + debug [KNL] Enable kernel debugging (events log level). decnet= [HW,NET] @@ -380,12 +402,14 @@ ftape= [HW] Floppy Tape subsystem debugging options. See Documentation/ftape.txt. + gamecon.map[2|3]= + [HW,JOY] Multisystem joystick and NES/SNES/PSX pad + support via parallel port (up to 5 devices per port) + Format: ,,,,, + See also Documentation/input/joystick-parport.txt + gamma= [HW,DRM] - gc= [HW,JOY] - gc_2= See Documentation/input/joystick-parport.txt. - gc_3= - gdth= [HW,SCSI] See header of drivers/scsi/gdth.c. @@ -612,9 +636,9 @@ mga= [HW,DRM] - mousedev.xres [MOUSE] Horizontal screen resolution, used for devices + mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices reporting absolute coordinates, such as tablets - mousedev.yres [MOUSE] Vertical screen resolution, used for devices + mousedev.yres= [MOUSE] Vertical screen resolution, used for devices reporting absolute coordinates, such as tablets mpu401= [HW,OSS] @@ -1159,10 +1183,6 @@ See header of drivers/scsi/t128.c. tdfx= [HW,DRM] - - tgfx= [HW,JOY] TurboGraFX parallel port interface - tgfx_2= See Documentation/input/joystick-parport.txt. - tgfx_3= thash_entries= [KNL,NET] Set number of hash buckets for TCP connection @@ -1185,8 +1205,13 @@ trix= [HW,OSS] MediaTrix AudioTrix Pro Format: ,,,,,,,, - tsdev.xres [TS] Horizontal screen resolution. - tsdev.yres [TS] Vertical screen resolution. + tsdev.xres= [TS] Horizontal screen resolution. + tsdev.yres= [TS] Vertical screen resolution. + + turbografx.map[2|3]= + [HW,JOY] TurboGraFX parallel port interface + Format: ,,,,,,, + See also Documentation/input/joystick-parport.txt u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter See header of drivers/scsi/u14-34f.c. diff -Nru a/Documentation/mono.txt b/Documentation/mono.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/mono.txt Sat Apr 3 19:38:57 2004 @@ -0,0 +1,66 @@ + Mono(tm) Binary Kernel Support for Linux + ----------------------------------------- + +To configure Linux to automatically execute Mono-based .NET binaries +(in the form of .exe files) without the need to use the mono CLR +wrapper, you can use the BINFMT_MISC kernel support. + +This will allow you to execute Mono-based .NET binaries just like any +other program after you have done the following: + +1) You MUST FIRST install the Mono CLR support, either by downloading + a binary package, a source tarball or by installing from CVS. Binary + packages for several distributions can be found at: + + http://go-mono.com/download.html + + Instructions for compiling Mono can be found at: + + http://www.go-mono.com/compiling.html + + Once the Mono CLR support has been installed, just check that + /usr/bin/mono (which could be located elsewhere, for example + /usr/local/bin/mono) is working. + +2) You have to compile BINFMT_MISC either as a module or into + the kernel (CONFIG_BINFMT_MISC) and set it up properly. + If you choose to compile it as a module, you will have + to insert it manually with modprobe/insmod, as kmod + can not be easily supported with binfmt_misc. + Read the file 'binfmt_misc.txt' in this directory to know + more about the configuration process. + +3) Add the following enries to /etc/rc.local or similar script + to be run at system startup: + +# Insert BINFMT_MISC module into the kernel +if [ ! -e /proc/sys/fs/binfmt_misc/register ]; then + /sbin/modprobe binfmt_misc + # Some distributions, like Fedora Core, perform + # the following command automatically when the + # binfmt_misc module is loaded into the kernel. + # Thus, it is possible that the following line + # is not needed at all. Look at /etc/modprobe.conf + # to check whether this is applicable or not. + mount -t binfmt_misc none /proc/sys/fs/binfmt_misc +fi + +# Register support for .NET CLR binaries +if [ -e /proc/sys/fs/binfmt_misc/register ]; then + # Replace /usr/bin/mono with the correct pathname to + # the Mono CLR runtime (usually /usr/local/bin/mono + # when compiling from sources or CVS). + echo ':CLR:M::MZ::/usr/bin/mono:' > /proc/sys/fs/binfmt_misc/register +else + echo "No binfmt_misc support" + exit 1 +fi + +4) Check that .exe binaries can be ran without the need of a + wrapper script, simply by launching the .exe file directly + from a command prompt, for example: + + /usr/bin/xsd.exe + + NOTE: If this fails with a permission denied error, check + that the .exe file has execute permissions. diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt --- a/Documentation/networking/bonding.txt Sat Apr 3 19:38:42 2004 +++ b/Documentation/networking/bonding.txt Sat Apr 3 19:38:42 2004 @@ -55,8 +55,9 @@ -------------------------------------- This version of the bonding driver requires updated ifenslave program. The original one from extreme-linux and beowulf will not work. Kernels 2.4.12 -and above include the updated version of ifenslave.c in Documentation/network -directory. For older kernels, please follow the links at the end of this file. +and above include the updated version of ifenslave.c in +Documentation/networking directory. For older kernels, please follow the +links at the end of this file. IMPORTANT!!! If you are running on Redhat 7.1 or greater, you need to be careful because /usr/include/linux is no longer a symbolic link diff -Nru a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt --- a/Documentation/networking/e100.txt Sat Apr 3 19:38:55 2004 +++ b/Documentation/networking/e100.txt Sat Apr 3 19:38:55 2004 @@ -1,7 +1,7 @@ Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters ============================================================== -November 19, 2002 +March 15, 2004 Contents @@ -9,9 +9,6 @@ - In This Release - Supported Adapters -- Command Line Parameters -- CPU Cycle Saver -- Additional Configurations - Support @@ -19,64 +16,13 @@ =============== This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of -Adapters, version 2.2.x. This driver includes support for Itanium(TM)-based +Adapters, version 3.x.x. This driver includes support for Itanium(TM)-based systems. Supported Adapters ================== -The following Intel network adapters are compatible with the drivers -in this release: - -Controller Adapter Name Board IDs ----------- ------------ --------- - -82558 PRO/100+ PCI Adapter 668081-xxx, 689661-xxx - -82558 PRO/100+ Management Adapter 691334-xxx, 701738-xxx, - 721383-xxx - -82558 PRO/100+ Dual Port Server Adapter 714303-xxx, 711269-xxx, - A28276-xxx - -82558 PRO/100+ PCI Server Adapter 710550-xxx - -82550 PRO/100 S Server Adapter 752438-xxx (82550) -82559 A56831-xxx, A10563-xxx, - A12171-xxx, A12321-xxx, - A12320-xxx, A12170-xxx - 748568-xxx (82559) - 748565-xxx (82559) - - -82550 PRO/100 S Desktop Adapter 751767-xxx (82550) -82559 748592-xxx, A12167-xxx, - A12318-xxx, A12317-xxx, - A12165-xxx - 748569-xxx (82559) - - - -82559 PRO/100+ Server Adapter 729757-xxx - -82559 PRO/100 S Management Adapter 748566-xxx, 748564-xxx - -82550 PRO/100 S Dual Port Server Adapter A56831-xxx - -82551 PRO/100 M Desktop Adapter A80897-xxx - - PRO/100 S Advanced Management Adapter 747842-xxx, 745171-xxx - -CNR PRO/100 VE Desktop Adapter A10386-xxx, A10725-xxx, - A23801-xxx, A19716-xxx - - - PRO/100 VM Desktop Adapter A14323-xxx, A19725-xxx, - A23801-xxx, A22220-xxx, - A23796-xxx - - To verify that your adapter is supported, find the board ID number on the adapter. Look for a label that has a barcode and a number in the format A12345-001. Match this to the list of numbers above. @@ -89,143 +35,6 @@ For the latest Intel PRO/100 network driver for Linux, see: http://downloadfinder.intel.com/scripts-df/support_intel.asp - - -Command Line Parameters -======================= - -If the driver is built as a module, the following optional parameters are -used by entering them on the command line with the modprobe or insmod command -using this syntax: - - modprobe e100 [, (default is 0,1)"); + +__obsolete_setup("amijoy="); + static int amijoy_used[2] = { 0, 0 }; static struct input_dev amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; @@ -100,17 +106,6 @@ if (!--(*used)) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); } - -static int __init amijoy_setup(char *str) -{ - int i; - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1]; - return 1; -} -__setup("amijoy=", amijoy_setup); static int __init amijoy_init(void) { diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c --- a/drivers/input/joystick/analog.c Sat Apr 3 19:38:55 2004 +++ b/drivers/input/joystick/analog.c Sat Apr 3 19:38:55 2004 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -50,9 +51,12 @@ #define ANALOG_PORTS 16 static char *js[ANALOG_PORTS]; +static int js_nargs; static int analog_options[ANALOG_PORTS]; -MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s"); -MODULE_PARM_DESC(js, "Analog joystick options"); +module_param_array_named(map, js, charp, js_nargs, 0); +MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); + +__obsolete_setup("js="); /* * Times, feature definitions. @@ -711,7 +715,7 @@ int i, j; char *end; - for (i = 0; i < ANALOG_PORTS && js[i]; i++) { + for (i = 0; i < js_nargs; i++) { for (j = 0; analog_types[j].name; j++) if (!strcmp(analog_types[j].name, js[i])) { @@ -741,24 +745,6 @@ .connect = analog_connect, .disconnect = analog_disconnect, }; - -#ifndef MODULE -static int __init analog_setup(char *str) -{ - char *s = str; - int i = 0; - - if (!str || !*str) return 0; - - while ((str = s) && (i < ANALOG_PORTS)) { - if ((s = strchr(str,','))) *s++ = 0; - js[i++] = str; - } - - return 1; -} -__setup("js=", analog_setup); -#endif int __init analog_init(void) { diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c --- a/drivers/input/joystick/db9.c Sat Apr 3 19:38:42 2004 +++ b/drivers/input/joystick/db9.c Sat Apr 3 19:38:42 2004 @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -42,9 +43,24 @@ MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(db9, "2i"); -MODULE_PARM(db9_2, "2i"); -MODULE_PARM(db9_3, "2i"); +static int db9[] __initdata = { -1, 0 }; +static int db9_nargs __initdata = 0; +module_param_array_named(dev, db9, int, db9_nargs, 0); +MODULE_PARM_DESC(dev, "Describes first attached device (,)"); + +static int db9_2[] __initdata = { -1, 0 }; +static int db9_nargs_2 __initdata = 0; +module_param_array_named(dev2, db9_2, int, db9_nargs_2, 0); +MODULE_PARM_DESC(dev2, "Describes second attached device (,)"); + +static int db9_3[] __initdata = { -1, 0 }; +static int db9_nargs_3 __initdata = 0; +module_param_array_named(dev3, db9_3, int, db9_nargs_3, 0); +MODULE_PARM_DESC(dev3, "Describes third attached device (,)"); + +__obsolete_setup("db9="); +__obsolete_setup("db9_2="); +__obsolete_setup("db9_3="); #define DB9_MULTI_STICK 0x01 #define DB9_MULTI2_STICK 0x02 @@ -76,10 +92,6 @@ #define DB9_GENESIS6_DELAY 14 #define DB9_REFRESH_TIME HZ/100 -static int db9[] __initdata = { -1, 0 }; -static int db9_2[] __initdata = { -1, 0 }; -static int db9_3[] __initdata = { -1, 0 }; - struct db9 { struct input_dev dev[DB9_MAX_DEVICES]; struct timer_list timer; @@ -518,7 +530,7 @@ } } -static struct db9 __init *db9_probe(int *config) +static struct db9 __init *db9_probe(int *config, int nargs) { struct db9 *db9; struct parport *pp; @@ -526,6 +538,12 @@ if (config[0] < 0) return NULL; + + if (nargs < 2) { + printk(KERN_ERR "db9.c: Device type must be specified.\n"); + return NULL; + } + if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { printk(KERN_ERR "db9.c: bad config\n"); return NULL; @@ -601,38 +619,11 @@ return db9; } -#ifndef MODULE -static int __init db9_setup(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1]; - return 1; -} -static int __init db9_setup_2(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1]; - return 1; -} -static int __init db9_setup_3(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1]; - return 1; -} -__setup("db9=", db9_setup); -__setup("db9_2=", db9_setup_2); -__setup("db9_3=", db9_setup_3); -#endif - int __init db9_init(void) { - db9_base[0] = db9_probe(db9); - db9_base[1] = db9_probe(db9_2); - db9_base[2] = db9_probe(db9_3); + db9_base[0] = db9_probe(db9, db9_nargs); + db9_base[1] = db9_probe(db9_2, db9_nargs_2); + db9_base[2] = db9_probe(db9_3, db9_nargs_3); if (db9_base[0] || db9_base[1] || db9_base[2]) return 0; diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c --- a/drivers/input/joystick/gamecon.c Sat Apr 3 19:38:56 2004 +++ b/drivers/input/joystick/gamecon.c Sat Apr 3 19:38:56 2004 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,10 +44,26 @@ MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(gc, "2-6i"); -MODULE_PARM(gc_2,"2-6i"); -MODULE_PARM(gc_3,"2-6i"); -MODULE_PARM(gc_psx_delay, "i"); +static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs __initdata = 0; +module_param_array_named(map, gc, int, gc_nargs, 0); +MODULE_PARM_DESC(map, "Describers first set of devices (,,,..)"); + +static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs_2 __initdata = 0; +module_param_array_named(map2, gc_2, int, gc_nargs_2, 0); +MODULE_PARM_DESC(map2, "Describers second set of devices"); + +static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs_3 __initdata = 0; +module_param_array_named(map3, gc_3, int, gc_nargs_3, 0); +MODULE_PARM_DESC(map3, "Describers third set of devices"); + +__obsolete_setup("gc="); +__obsolete_setup("gc_2="); +__obsolete_setup("gc_3="); + +/* see also gs_psx_delay parameter in PSX support section */ #define GC_SNES 1 #define GC_NES 2 @@ -71,10 +88,6 @@ static struct gc *gc_base[3]; -static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; - static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", @@ -232,6 +245,11 @@ #define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */ static int gc_psx_delay = GC_PSX_DELAY; +module_param_named(psx_delay, gc_psx_delay, uint, 0); +MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)"); + +__obsolete_setup("gc_psx_delay="); + static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; @@ -468,7 +486,7 @@ } } -static struct gc __init *gc_probe(int *config) +static struct gc __init *gc_probe(int *config, int nargs) { struct gc *gc; struct parport *pp; @@ -478,6 +496,11 @@ if (config[0] < 0) return NULL; + if (nargs < 2) { + printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); + return NULL; + } + pp = parport_find_number(config[0]); if (!pp) { @@ -507,7 +530,7 @@ gc->timer.data = (long) gc; gc->timer.function = gc_timer; - for (i = 0; i < 5; i++) { + for (i = 0; i < nargs - 1; i++) { if (!config[i + 1]) continue; @@ -632,44 +655,11 @@ return gc; } -#ifndef MODULE -static int __init gc_setup(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1]; - return 1; -} -static int __init gc_setup_2(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1]; - return 1; -} -static int __init gc_setup_3(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1]; - return 1; -} -static int __init gc_psx_setup(char *str) -{ - get_option(&str, &gc_psx_delay); - return 1; -} -__setup("gc=", gc_setup); -__setup("gc_2=", gc_setup_2); -__setup("gc_3=", gc_setup_3); -__setup("gc_psx_delay=", gc_psx_setup); -#endif - int __init gc_init(void) { - gc_base[0] = gc_probe(gc); - gc_base[1] = gc_probe(gc_2); - gc_base[2] = gc_probe(gc_3); + gc_base[0] = gc_probe(gc, gc_nargs); + gc_base[1] = gc_probe(gc_2, gc_nargs_2); + gc_base[2] = gc_probe(gc_3, gc_nargs_3); if (gc_base[0] || gc_base[1] || gc_base[2]) return 0; diff -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c --- a/drivers/input/joystick/gf2k.c Sat Apr 3 19:38:45 2004 +++ b/drivers/input/joystick/gf2k.c Sat Apr 3 19:38:45 2004 @@ -109,7 +109,7 @@ local_irq_save(flags); gameport_trigger(gameport); - v = gameport_read(gameport);; + v = gameport_read(gameport); while (t > 0 && i < length) { t--; u = v; diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c --- a/drivers/input/joystick/iforce/iforce-usb.c Sat Apr 3 19:38:55 2004 +++ b/drivers/input/joystick/iforce/iforce-usb.c Sat Apr 3 19:38:55 2004 @@ -135,7 +135,7 @@ struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; - interface = &intf->altsetting[intf->act_altsetting]; + interface = intf->cur_altsetting; epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; diff -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c --- a/drivers/input/joystick/turbografx.c Sat Apr 3 19:38:54 2004 +++ b/drivers/input/joystick/turbografx.c Sat Apr 3 19:38:54 2004 @@ -35,15 +35,31 @@ #include #include #include +#include #include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(tgfx, "2-8i"); -MODULE_PARM(tgfx_2, "2-8i"); -MODULE_PARM(tgfx_3, "2-8i"); +static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs __initdata = 0; +module_param_array_named(map, tgfx, int, tgfx_nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); + +static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs_2 __initdata = 0; +module_param_array_named(map2, tgfx_2, int, tgfx_nargs_2, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); + +static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs_3 __initdata = 0; +module_param_array_named(map3, tgfx_3, int, tgfx_nargs_3, 0); +MODULE_PARM_DESC(map3, "Describes third set of devices"); + +__obsolete_setup("tgfx="); +__obsolete_setup("tgfx_2="); +__obsolete_setup("tgfx_3="); #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ @@ -58,10 +74,6 @@ #define TGFX_TOP 0x01 #define TGFX_TOP2 0x08 -static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; - static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; static char *tgfx_name = "TurboGraFX Multisystem joystick"; @@ -133,7 +145,7 @@ * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int *config) +static struct tgfx __init *tgfx_probe(int *config, int nargs) { struct tgfx *tgfx; struct parport *pp; @@ -142,6 +154,11 @@ if (config[0] < 0) return NULL; + if (nargs < 2) { + printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); + return NULL; + } + pp = parport_find_number(config[0]); if (!pp) { @@ -171,7 +188,7 @@ tgfx->sticks = 0; - for (i = 0; i < 7; i++) + for (i = 0; i < nargs - 1; i++) if (config[i+1] > 0 && config[i+1] < 6) { tgfx->sticks |= (1 << i); @@ -212,38 +229,11 @@ return tgfx; } -#ifndef MODULE -static int __init tgfx_setup(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1]; - return 1; -} -static int __init tgfx_setup_2(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1]; - return 1; -} -static int __init tgfx_setup_3(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1]; - return 1; -} -__setup("tgfx=", tgfx_setup); -__setup("tgfx_2=", tgfx_setup_2); -__setup("tgfx_3=", tgfx_setup_3); -#endif - int __init tgfx_init(void) { - tgfx_base[0] = tgfx_probe(tgfx); - tgfx_base[1] = tgfx_probe(tgfx_2); - tgfx_base[2] = tgfx_probe(tgfx_3); + tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); + tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); + tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) return 0; diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig --- a/drivers/input/keyboard/Kconfig Sat Apr 3 19:38:56 2004 +++ b/drivers/input/keyboard/Kconfig Sat Apr 3 19:38:56 2004 @@ -17,6 +17,7 @@ depends on INPUT && INPUT_KEYBOARD select SERIO select SERIO_I8042 if PC + select SERIO_GSCPS2 if GSC help Say Y here if you want to use a standard AT or PS/2 keyboard. Usually you'll need this, unless you have a different type keyboard (USB, ADB @@ -39,6 +40,19 @@ To compile this driver as a module, choose M here: the module will be called sunkbd. + +config KEYBOARD_LKKBD + tristate "DECstation/VAXstation LK201/LK401 keyboard support" + depends on INPUT && INPUT_KEYBOARD + select SERIO + help + Say Y here if you want to use a LK201 or LK401 style serial + keyboard. This keyboard is also useable on PCs if you attach + it with the inputattach program. The connector pinout is + described within lkkbd.c. + + To compile this driver as a module, choose M here: the + module will be called lkkbd. config KEYBOARD_XTKBD tristate "XT Keyboard support" diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile --- a/drivers/input/keyboard/Makefile Sat Apr 3 19:38:57 2004 +++ b/drivers/input/keyboard/Makefile Sat Apr 3 19:38:57 2004 @@ -7,6 +7,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o +obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c --- a/drivers/input/keyboard/atkbd.c Sat Apr 3 19:38:55 2004 +++ b/drivers/input/keyboard/atkbd.c Sat Apr 3 19:38:55 2004 @@ -30,21 +30,17 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); -MODULE_PARM(atkbd_set, "1i"); -MODULE_PARM(atkbd_reset, "1i"); -MODULE_PARM(atkbd_softrepeat, "1i"); MODULE_LICENSE("GPL"); static int atkbd_set = 2; module_param_named(set, atkbd_set, int, 0); -MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)"); +MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); + #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) static int atkbd_reset; #else static int atkbd_reset = 1; #endif -static int atkbd_softrepeat; - module_param_named(reset, atkbd_reset, bool, 0); MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); @@ -52,6 +48,18 @@ module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_scroll; +module_param_named(scroll, atkbd_scroll, bool, 0); +MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); + +static int atkbd_extra; +module_param_named(extra, atkbd_extra, bool, 0); +MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); + +__obsolete_setup("atkbd_set="); +__obsolete_setup("atkbd_reset"); +__obsolete_setup("atkbd_softrepeat="); + /* * Scancode to keycode tables. These are just the default setting, and * are loadable via an userland utility. @@ -127,11 +135,11 @@ #define ATKBD_CMD_EX_SETLEDS 0x20eb #define ATKBD_CMD_OK_GETID 0x02e8 + #define ATKBD_RET_ACK 0xfa #define ATKBD_RET_NAK 0xfe #define ATKBD_RET_BAT 0xaa #define ATKBD_RET_EMUL0 0xe0 -#define ATKBD_RET_EMULX 0x80 #define ATKBD_RET_EMUL1 0xe1 #define ATKBD_RET_RELEASE 0xf0 #define ATKBD_RET_HANGUEL 0xf1 @@ -141,6 +149,22 @@ #define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_NULL 255 +#define ATKBD_SCR_1 254 +#define ATKBD_SCR_2 253 +#define ATKBD_SCR_4 252 +#define ATKBD_SCR_8 251 +#define ATKBD_SCR_CLICK 250 + +#define ATKBD_SPECIAL 250 + +static unsigned char atkbd_scroll_keys[5][2] = { + { ATKBD_SCR_1, 0x45 }, + { ATKBD_SCR_2, 0x29 }, + { ATKBD_SCR_4, 0x36 }, + { ATKBD_SCR_8, 0x27 }, + { ATKBD_SCR_CLICK, 0x60 }, +}; + /* * The atkbd control structure */ @@ -155,6 +179,7 @@ unsigned char cmdbuf[4]; unsigned char cmdcnt; unsigned char set; + unsigned char extra; unsigned char release; int lastkey; volatile signed char ack; @@ -189,6 +214,7 @@ { struct atkbd *atkbd = serio->private; unsigned int code = data; + int scroll = 0, click = -1; int value; #ifdef ATKBD_DEBUG @@ -202,7 +228,7 @@ atkbd->resend = 1; goto out; } - + if (!flags && data == ATKBD_RET_ACK) atkbd->resend = 0; #endif @@ -276,7 +302,7 @@ case ATKBD_KEY_UNKNOWN: printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", atkbd->release ? "released" : "pressed", - atkbd->translated ? "translated" : "raw", + atkbd->translated ? "translated" : "raw", atkbd->set, code, serio->phys); if (atkbd->translated && atkbd->set == 2 && code == 0x7a) printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access" @@ -284,6 +310,21 @@ else printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x ' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); break; + case ATKBD_SCR_1: + scroll = 1 - atkbd->release * 2; + break; + case ATKBD_SCR_2: + scroll = 2 - atkbd->release * 4; + break; + case ATKBD_SCR_4: + scroll = 4 - atkbd->release * 8; + break; + case ATKBD_SCR_8: + scroll = 8 - atkbd->release * 16; + break; + case ATKBD_SCR_CLICK: + click = !atkbd->release; + break; default: value = atkbd->release ? 0 : (1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); @@ -305,6 +346,13 @@ atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); } + if (scroll || click != -1) { + input_regs(&atkbd->dev, regs); + input_report_key(&atkbd->dev, BTN_MIDDLE, click); + input_report_rel(&atkbd->dev, REL_WHEEL, scroll); + input_sync(&atkbd->dev); + } + atkbd->release = 0; out: return IRQ_HANDLED; @@ -353,7 +401,7 @@ if (receive && param) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; - + if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) return (atkbd->cmdcnt = 0) - 1; @@ -373,7 +421,7 @@ atkbd->cmdcnt = 0; break; } - + udelay(1); } @@ -420,7 +468,7 @@ | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); - if (atkbd->set == 4) { + if (atkbd->extra) { param[0] = 0; param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) @@ -466,7 +514,7 @@ */ if (atkbd_reset) - if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys); /* @@ -529,20 +577,21 @@ return 3; } - if (atkbd_set != 2) - if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) { - atkbd->id = param[0] << 8 | param[1]; + if (atkbd_extra) { + param[0] = 0x71; + if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) { + atkbd->extra = 1; return 2; } - - if (atkbd_set == 4) { - param[0] = 0x71; - if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) - return 4; } - if (atkbd_set != 3) + if (atkbd_set != 3) + return 2; + + if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) { + atkbd->id = param[0] << 8 | param[1]; return 2; + } param[0] = 3; if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET)) @@ -637,7 +686,7 @@ switch (serio->type & SERIO_TYPE) { - case SERIO_8042_XL: + case SERIO_8042_XL: atkbd->translated = 1; case SERIO_8042: if (serio->write) @@ -650,7 +699,7 @@ kfree(atkbd); return; } - + if (atkbd->write) { atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); @@ -687,7 +736,7 @@ kfree(atkbd); return; } - + atkbd->set = atkbd_set_3(atkbd); atkbd_enable(atkbd); @@ -696,24 +745,32 @@ atkbd->id = 0xab00; } - if (atkbd->set == 4) { + if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); - sprintf(atkbd->name, "AT Set 2 Extended keyboard"); + sprintf(atkbd->name, "AT Set 2 Extra keyboard"); } else sprintf(atkbd->name, "AT %s Set %d keyboard", atkbd->translated ? "Translated" : "Raw", atkbd->set); sprintf(atkbd->phys, "%s/input0", serio->phys); + if (atkbd_scroll) { + for (i = 0; i < 5; i++) + atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0]; + atkbd->dev.evbit[0] |= BIT(EV_REL); + atkbd->dev.relbit[0] = BIT(REL_WHEEL); + set_bit(BTN_MIDDLE, atkbd->dev.keybit); + } + if (atkbd->translated) { for (i = 0; i < 128; i++) { atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; } - } else if (atkbd->set == 2) { - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); - } else { + } else if (atkbd->set == 3) { memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + } else { + memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); } atkbd->dev.name = atkbd->name; @@ -724,7 +781,7 @@ atkbd->dev.id.version = atkbd->id; for (i = 0; i < 512; i++) - if (atkbd->keycode[i] && atkbd->keycode[i] < 255) + if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) set_bit(atkbd->keycode[i], atkbd->dev.keybit); input_register_device(&atkbd->dev); @@ -741,45 +798,28 @@ { struct atkbd *atkbd = serio->private; struct serio_dev *dev = serio->dev; - int i; + unsigned char param[1]; - if (!dev) { - printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); - return -1; - } + if (!dev) { + printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } if (atkbd->write) { + param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) + | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) + | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); + if (atkbd_probe(atkbd)) return -1; - - atkbd->set = atkbd_set_3(atkbd); + if (atkbd->set != atkbd_set_3(atkbd)) + return -1; + atkbd_enable(atkbd); - } else { - atkbd->set = 2; - atkbd->id = 0xab00; - } - /* - * Here we probably should check if the keyboard has the same set that - * it had before and bail out if it's different. But this will most likely - * cause new keyboard device be created... and for the user it will look - * like keyboard is lost - */ - - if (atkbd->translated) { - for (i = 0; i < 128; i++) { - atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - } - } else if (atkbd->set == 2) { - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); - } else { - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) + return -1; } - - for (i = 0; i < 512; i++) - if (atkbd->keycode[i] && atkbd->keycode[i] < 255) - set_bit(atkbd->keycode[i], atkbd->dev.keybit); return 0; } diff -Nru a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h --- a/drivers/input/keyboard/hpps2atkbd.h Sat Apr 3 19:38:41 2004 +++ b/drivers/input/keyboard/hpps2atkbd.h Sat Apr 3 19:38:41 2004 @@ -4,14 +4,9 @@ * Copyright (c) 2004 Helge Deller * Copyright (c) 2002 Laurent Canet * Copyright (c) 2002 Thibaut Varene + * Copyright (c) 2000 Xavier Debacker * - * based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries - * Copyright (c) 1999-2000 Philipp Rumpf - * Copyright (c) 2000 Xavier Debacker - * Copyright (c) 2000-2001 Thomas Marteau - * - * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations + * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops * * 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 @@ -19,87 +14,100 @@ */ -#define KBD_UNKNOWN 0 - -/* Raw SET 2 scancode table */ +/* undefine if you have a RDI PRECISIONBOOK */ +#define STANDARD_KEYBOARD -#if 0 - /* conflicting keys between a RDI Precisionbook keyboard and a normal HP keyboard */ - keytable[0x07] = KEY_F1; /* KEY_F12 */ - keytable[0x11] = KEY_LEFTCTRL; /* KEY_LEFTALT */ - keytable[0x14] = KEY_CAPSLOCK; /* KEY_LEFTCTRL */ - keytable[0x61] = KEY_LEFT; /* KEY_102ND */ +#if defined(STANDARD_KEYBOARD) +# define CONFLICT(x,y) x +#else +# define CONFLICT(x,y) y #endif +/* sadly RDI (Tadpole) decided to ship a different keyboard layout + than HP for their PS/2 laptop keyboard which leads to conflicting + keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook. + HP: RDI: */ +#define C_07 CONFLICT( KEY_F12, KEY_F1 ) +#define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL ) +#define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK ) +#define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL ) +#define C_61 CONFLICT( KEY_102ND, KEY_LEFT ) -static unsigned char atkbd_set2_keycode[512] = { +/* Raw SET 2 scancode table */ - /* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F1, - /* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, - /* 10 */ KBD_UNKNOWN, KEY_LEFTCTRL, KEY_LEFTSHIFT, KBD_UNKNOWN, KEY_CAPSLOCK, KEY_Q, KEY_1, KEY_F3, - /* 18 */ KBD_UNKNOWN, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, - /* 20 */ KBD_UNKNOWN, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, - /* 28 */ KBD_UNKNOWN, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, - /* 30 */ KBD_UNKNOWN, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, - /* 38 */ KBD_UNKNOWN, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, - /* 40 */ KBD_UNKNOWN, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, - /* 48 */ KBD_UNKNOWN, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_APOSTROPHE,KBD_UNKNOWN, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, - /* 58 */ KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, - /* 60 */ KEY_DOWN, KEY_LEFT, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, - /* 68 */ KBD_UNKNOWN, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, - /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, - /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - - /* These are offset for escaped keycodes: */ - - /* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_LEFTMETA, KEY_RIGHTMETA, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPSLASH, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPENTER, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_END, KBD_UNKNOWN, KEY_LEFT, KEY_HOME, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KBD_UNKNOWN, KEY_RIGHT, KEY_UP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 78 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_PAGEDOWN, KBD_UNKNOWN, KEY_SYSRQ, KEY_PAGEUP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN +/* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07, +/* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, +/* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3, +/* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, +/* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, +/* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, +/* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, +/* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, +/* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, +/* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, +/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, +/* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, +/* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, +/* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, +/* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, +/* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, +/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 90 */ KEY_RESERVED, KEY_RIGHTALT, KEY_SYSRQ, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA, +/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA, +/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE, +/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE, +/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED, + +/* These are offset for escaped keycodes: */ + +/* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED + +#undef STANDARD_KEYBOARD +#undef CONFLICT +#undef C_07 +#undef C_11 +#undef C_14 +#undef C_58 +#undef C_61 -}; diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/keyboard/lkkbd.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2004 by Jan-Benedict Glaw + */ + +/* + * LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik + */ + +/* + * DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations + * and VAXstations, but can also be used on any standard RS232 with an + * adaptor). + * + * DISCLAUNER: This works for _me_. If you break anything by using the + * information given below, I will _not_ be lieable! + * + * RJ11 pinout: To DB9: Or DB25: + * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) + * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND) + * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD) + * 3 - +12V (from HDD drive connector), DON'T connect to DB9 or DB25!!! + * + * Pin numbers for DB9 and DB25 are noted on the plug (quite small:). For + * RJ11, it's like this: + * + * __=__ Hold the plug in front of you, cable downwards, + * /___/| nose is hidden behind the plug. Now, pin 1 is at + * |1234|| the left side, pin 4 at the right and 2 and 3 are + * |IIII|| in between, of course:) + * | || + * |____|/ + * || So the adaptor consists of three connected cables + * || for data transmission (RxD and TxD) and signal ground. + * Additionally, you have to get +12V from somewhere. + * Most easily, you'll get that from a floppy or HDD power connector. + * It's the yellow cable there (black is ground and red is +5V). + */ + +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * email or by paper mail: + * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), + * Germany. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR ("Jan-Benedict Glaw "); +MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_LICENSE ("GPL"); + +/* + * Known parameters: + * bell_volume + * keyclick_volume + * ctrlclick_volume + * + * Please notice that there's not yet an API to set these at runtime. + */ +static int bell_volume = 100; /* % */ +module_param (bell_volume, int, 0); +MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); + +static int keyclick_volume = 100; /* % */ +module_param (keyclick_volume, int, 0); +MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); + +static int ctrlclick_volume = 100; /* % */ +module_param (ctrlclick_volume, int, 0); +MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); + + + +#undef LKKBD_DEBUG +#ifdef LKKBD_DEBUG +#define DBG(x...) printk (x) +#else +#define DBG(x...) do {} while (0) +#endif + +/* LED control */ +#define LK_LED_WAIT 0x81 +#define LK_LED_COMPOSE 0x82 +#define LK_LED_SHIFTLOCK 0x84 +#define LK_LED_SCROLLLOCK 0x88 +#define LK_CMD_LED_ON 0x13 +#define LK_CMD_LED_OFF 0x11 + +/* Mode control */ +#define LK_MODE_DOWN 0x80 +#define LK_MODE_AUTODOWN 0x82 +#define LK_MODE_UPDOWN 0x86 +#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) + +/* Misc commands */ +#define LK_CMD_ENABLE_KEYCLICK 0x1b +#define LK_CMD_DISABLE_KEYCLICK 0x99 +#define LK_CMD_DISABLE_BELL 0xa1 +#define LK_CMD_SOUND_BELL 0xa7 +#define LK_CMD_ENABLE_BELL 0x23 +#define LK_CMD_DISABLE_CTRCLICK 0xb9 +#define LK_CMD_ENABLE_CTRCLICK 0xbb +#define LK_CMD_SET_DEFAULTS 0xd3 +#define LK_CMD_POWERCYCLE_RESET 0xfd +#define LK_CMD_ENABLE_LK401 0xe9 + +/* Misc responses from keyboard */ +#define LK_ALL_KEYS_UP 0xb3 +#define LK_METRONOME 0xb4 +#define LK_OUTPUT_ERROR 0xb5 +#define LK_INPUT_ERROR 0xb6 +#define LK_KBD_LOCKED 0xb7 +#define LK_KBD_TEST_MODE_ACK 0xb8 +#define LK_PREFIX_KEY_DOWN 0xb9 +#define LK_MODE_CHANGE_ACK 0xba +#define LK_RESPONSE_RESERVED 0xbb + +#define LK_NUM_KEYCODES 256 +typedef u_int16_t lk_keycode_t; + + + +static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { + [0x56] = KEY_F1, + [0x57] = KEY_F2, + [0x58] = KEY_F3, + [0x59] = KEY_F4, + [0x5a] = KEY_F5, + [0x64] = KEY_F6, + [0x65] = KEY_F7, + [0x66] = KEY_F8, + [0x67] = KEY_F9, + [0x68] = KEY_F10, + [0x71] = KEY_F11, + [0x72] = KEY_F12, + [0x73] = KEY_F13, + [0x74] = KEY_F14, + [0x7c] = KEY_F15, + [0x7d] = KEY_F16, + [0x80] = KEY_F17, + [0x81] = KEY_F18, + [0x82] = KEY_F19, + [0x83] = KEY_F20, + [0x8a] = KEY_FIND, + [0x8b] = KEY_INSERT, + [0x8c] = KEY_DELETE, + [0x8d] = KEY_SELECT, + [0x8e] = KEY_PAGEUP, + [0x8f] = KEY_PAGEDOWN, + [0x92] = KEY_KP0, + [0x94] = KEY_KPDOT, + [0x95] = KEY_KPENTER, + [0x96] = KEY_KP1, + [0x97] = KEY_KP2, + [0x98] = KEY_KP3, + [0x99] = KEY_KP4, + [0x9a] = KEY_KP5, + [0x9b] = KEY_KP6, + [0x9c] = KEY_KPCOMMA, + [0x9d] = KEY_KP7, + [0x9e] = KEY_KP8, + [0x9f] = KEY_KP9, + [0xa0] = KEY_KPMINUS, + [0xa1] = KEY_PROG1, + [0xa2] = KEY_PROG2, + [0xa3] = KEY_PROG3, + [0xa4] = KEY_PROG4, + [0xa7] = KEY_LEFT, + [0xa8] = KEY_RIGHT, + [0xa9] = KEY_DOWN, + [0xaa] = KEY_UP, + [0xab] = KEY_RIGHTSHIFT, + [0xac] = KEY_LEFTALT, + [0xad] = KEY_COMPOSE, /* Right Compose, that is. */ + [0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */ + [0xaf] = KEY_LEFTCTRL, + [0xb0] = KEY_CAPSLOCK, + [0xb1] = KEY_COMPOSE, /* Left Compose, that is. */ + [0xb2] = KEY_RIGHTALT, + [0xbc] = KEY_BACKSPACE, + [0xbd] = KEY_ENTER, + [0xbe] = KEY_TAB, + [0xbf] = KEY_ESC, + [0xc0] = KEY_1, + [0xc1] = KEY_Q, + [0xc2] = KEY_A, + [0xc3] = KEY_Z, + [0xc5] = KEY_2, + [0xc6] = KEY_W, + [0xc7] = KEY_S, + [0xc8] = KEY_X, + [0xc9] = KEY_102ND, + [0xcb] = KEY_3, + [0xcc] = KEY_E, + [0xcd] = KEY_D, + [0xce] = KEY_C, + [0xd0] = KEY_4, + [0xd1] = KEY_R, + [0xd2] = KEY_F, + [0xd3] = KEY_V, + [0xd4] = KEY_SPACE, + [0xd6] = KEY_5, + [0xd7] = KEY_T, + [0xd8] = KEY_G, + [0xd9] = KEY_B, + [0xdb] = KEY_6, + [0xdc] = KEY_Y, + [0xdd] = KEY_H, + [0xde] = KEY_N, + [0xe0] = KEY_7, + [0xe1] = KEY_U, + [0xe2] = KEY_J, + [0xe3] = KEY_M, + [0xe5] = KEY_8, + [0xe6] = KEY_I, + [0xe7] = KEY_K, + [0xe8] = KEY_COMMA, + [0xea] = KEY_9, + [0xeb] = KEY_O, + [0xec] = KEY_L, + [0xed] = KEY_DOT, + [0xef] = KEY_0, + [0xf0] = KEY_P, + [0xf2] = KEY_SEMICOLON, + [0xf3] = KEY_SLASH, + [0xf5] = KEY_EQUAL, + [0xf6] = KEY_RIGHTBRACE, + [0xf7] = KEY_BACKSLASH, + [0xf9] = KEY_MINUS, + [0xfa] = KEY_LEFTBRACE, + [0xfb] = KEY_APOSTROPHE, +}; + +#define CHECK_LED(LED, BITS) do { \ + if (test_bit (LED, lk->dev.led)) \ + leds_on |= BITS; \ + else \ + leds_off |= BITS; \ + } while (0) + +/* + * Per-keyboard data + */ +struct lkkbd { + lk_keycode_t keycode[LK_NUM_KEYCODES]; + int ignore_bytes; + struct input_dev dev; + struct serio *serio; + struct work_struct tq; + char name[64]; + char phys[32]; + char type; + int bell_volume; + int keyclick_volume; + int ctrlclick_volume; +}; + +/* + * Calculate volume parameter byte for a given volume. + */ +static unsigned char +volume_to_hw (int volume_percent) +{ + unsigned char ret = 0; + + if (volume_percent < 0) + volume_percent = 0; + if (volume_percent > 100) + volume_percent = 100; + + if (volume_percent >= 0) + ret = 7; + if (volume_percent >= 13) /* 12.5 */ + ret = 6; + if (volume_percent >= 25) + ret = 5; + if (volume_percent >= 38) /* 37.5 */ + ret = 4; + if (volume_percent >= 50) + ret = 3; + if (volume_percent >= 63) /* 62.5 */ + ret = 2; /* This is the default volume */ + if (volume_percent >= 75) + ret = 1; + if (volume_percent >= 88) /* 87.5 */ + ret = 0; + + ret |= 0x80; + + return ret; +} + +/* + * lkkbd_interrupt() is called by the low level driver when a character + * is received. + */ +static irqreturn_t +lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, + struct pt_regs *regs) +{ + struct lkkbd *lk = serio->private; + int i; + + DBG (KERN_INFO "Got byte 0x%02x\n", data); + + if (lk->ignore_bytes > 0) { + DBG (KERN_INFO "Ignoring a byte on %s\n", + lk->name); + lk->ignore_bytes--; + return IRQ_HANDLED; + } + + switch (data) { + case LK_ALL_KEYS_UP: + input_regs (&lk->dev, regs); + for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) + if (lk->keycode[i] != KEY_RESERVED) + input_report_key (&lk->dev, lk->keycode[i], 0); + input_sync (&lk->dev); + break; + case LK_METRONOME: + DBG (KERN_INFO "Got LK_METRONOME and don't " + "know how to handle...\n"); + break; + case LK_OUTPUT_ERROR: + DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't " + "know how to handle...\n"); + break; + case LK_INPUT_ERROR: + DBG (KERN_INFO "Got LK_INPUT_ERROR and don't " + "know how to handle...\n"); + break; + case LK_KBD_LOCKED: + DBG (KERN_INFO "Got LK_KBD_LOCKED and don't " + "know how to handle...\n"); + break; + case LK_KBD_TEST_MODE_ACK: + DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't " + "know how to handle...\n"); + break; + case LK_PREFIX_KEY_DOWN: + DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't " + "know how to handle...\n"); + break; + case LK_MODE_CHANGE_ACK: + DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored " + "it properly...\n"); + break; + case LK_RESPONSE_RESERVED: + DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't " + "know how to handle...\n"); + break; + case 0x01: + DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); + lk->ignore_bytes = 3; + schedule_work (&lk->tq); + break; + + default: + if (lk->keycode[data] != KEY_RESERVED) { + input_regs (&lk->dev, regs); + if (!test_bit (lk->keycode[data], lk->dev.key)) + input_report_key (&lk->dev, lk->keycode[data], 1); + else + input_report_key (&lk->dev, lk->keycode[data], 0); + input_sync (&lk->dev); + } else + printk (KERN_WARNING "%s: Unknown key with " + "scancode %02x on %s.\n", + __FILE__, data, lk->name); + } + + return IRQ_HANDLED; +} + +/* + * lkkbd_event() handles events from the input module. + */ +static int +lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, + int value) +{ + struct lkkbd *lk = dev->private; + unsigned char leds_on = 0; + unsigned char leds_off = 0; + + switch (type) { + case EV_LED: + CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_ON); + lk->serio->write (lk->serio, leds_on); + } + if (leds_off != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_OFF); + lk->serio->write (lk->serio, leds_off); + } + return 0; + + case EV_SND: + switch (code) { + case SND_CLICK: + if (value == 0) { + DBG ("%s: Deactivating key clicks\n", __FUNCTION__); + lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + } else { + DBG ("%s: Activating key clicks\n", __FUNCTION__); + lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); + lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + } + return 0; + + case SND_BELL: + if (value != 0) + lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); + + return 0; + } + break; + + default: + printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", + __FUNCTION__, type, code, value); + } + + return -1; +} + +/* + * lkkbd_reinit() sets leds and beeps to a state the computer remembers they + * were in. + */ +static void +lkkbd_reinit (void *data) +{ + struct lkkbd *lk = data; + int division; + unsigned char leds_on = 0; + unsigned char leds_off = 0; + + /* Reset parameters */ + lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); + + /* Set LEDs */ + CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_ON); + lk->serio->write (lk->serio, leds_on); + } + if (leds_off != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_OFF); + lk->serio->write (lk->serio, leds_off); + } + + /* + * Try to activate extended LK401 mode. This command will + * only work with a LK401 keyboard and grants access to + * LAlt, RAlt, RCompose and RShift. + */ + lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); + + /* Set all keys to UPDOWN mode */ + for (division = 1; division <= 14; division++) + lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, + division)); + + /* Enable bell and set volume */ + lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); + lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); + + /* Enable/disable keyclick (and possibly set volume) */ + if (test_bit (SND_CLICK, lk->dev.snd)) { + lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); + lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + } else { + lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + } + + /* Sound the bell if needed */ + if (test_bit (SND_BELL, lk->dev.snd)) + lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); +} + +/* + * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. + */ +static void +lkkbd_connect (struct serio *serio, struct serio_dev *dev) +{ + struct lkkbd *lk; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + if (!(serio->type & SERIO_PROTO)) + return; + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD) + return; + + if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) + return; + memset (lk, 0, sizeof (struct lkkbd)); + + init_input_dev (&lk->dev); + + lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP); + lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP); + lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL); + + lk->serio = serio; + + INIT_WORK (&lk->tq, lkkbd_reinit, lk); + + lk->bell_volume = bell_volume; + lk->keyclick_volume = keyclick_volume; + lk->ctrlclick_volume = ctrlclick_volume; + + lk->dev.keycode = lk->keycode; + lk->dev.keycodesize = sizeof (lk_keycode_t); + lk->dev.keycodemax = LK_NUM_KEYCODES; + + lk->dev.event = lkkbd_event; + lk->dev.private = lk; + + serio->private = lk; + + if (serio_open (serio, dev)) { + kfree (lk); + return; + } + + sprintf (lk->name, "LK keyboard"); + + memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); + for (i = 0; i < LK_NUM_KEYCODES; i++) + set_bit (lk->keycode[i], lk->dev.keybit); + + sprintf (lk->name, "%s/input0", serio->phys); + + lk->dev.name = lk->name; + lk->dev.phys = lk->phys; + lk->dev.id.bustype = BUS_RS232; + lk->dev.id.vendor = SERIO_LKKBD; + lk->dev.id.product = 0; + lk->dev.id.version = 0x0100; + + input_register_device (&lk->dev); + + printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); + lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); +} + +/* + * lkkbd_disconnect() unregisters and closes behind us. + */ +static void +lkkbd_disconnect (struct serio *serio) +{ + struct lkkbd *lk = serio->private; + + input_unregister_device (&lk->dev); + serio_close (serio); + kfree (lk); +} + +static struct serio_dev lkkbd_dev = { + .interrupt = lkkbd_interrupt, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, +}; + +/* + * The functions for insering/removing us as a module. + */ +int __init +lkkbd_init (void) +{ + serio_register_device (&lkkbd_dev); + return 0; +} + +void __exit +lkkbd_exit (void) +{ + serio_unregister_device (&lkkbd_dev); +} + +module_init (lkkbd_init); +module_exit (lkkbd_exit); + diff -Nru a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c --- a/drivers/input/keyboard/maple_keyb.c Sat Apr 3 19:38:42 2004 +++ b/drivers/input/keyboard/maple_keyb.c Sat Apr 3 19:38:42 2004 @@ -1,5 +1,5 @@ /* - * $Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $ * SEGA Dreamcast keyboard driver * Based on drivers/usb/usbkbd.c */ @@ -125,8 +125,11 @@ kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + init_input_dev(&kbd->dev); + for (i=0; i<255; i++) set_bit(dc_kbd_keycode[i], kbd->dev.keybit); + clear_bit(0, kbd->dev.keybit); kbd->dev.private = kbd; @@ -141,10 +144,7 @@ maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); - printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", - kbd->dev.number, data, kbd->dev.name); - - MOD_INC_USE_COUNT; + printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name); return 0; } @@ -155,10 +155,7 @@ struct dc_kbd *kbd = dev->private_data; input_unregister_device(&kbd->dev); - kfree(kbd); - - MOD_DEC_USE_COUNT; } diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c --- a/drivers/input/keyboard/sunkbd.c Sat Apr 3 19:38:40 2004 +++ b/drivers/input/keyboard/sunkbd.c Sat Apr 3 19:38:40 2004 @@ -77,6 +77,7 @@ struct input_dev dev; struct serio *serio; struct work_struct tq; + wait_queue_head_t wait; char name[64]; char phys[32]; char type; @@ -96,11 +97,13 @@ if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + wake_up_interruptible(&sunkbd->wait); goto out; } if (sunkbd->layout == -1) { sunkbd->layout = data; + wake_up_interruptible(&sunkbd->wait); goto out; } @@ -176,22 +179,19 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) { - int t; - - t = 1000; sunkbd->reset = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); - while (sunkbd->reset < 0 && --t) mdelay(1); - if (!t) return -1; + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); + if (sunkbd->reset <0) + return -1; sunkbd->type = sunkbd->reset; if (sunkbd->type == 4) { /* Type 4 keyboard */ - t = 250; sunkbd->layout = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); - while (sunkbd->layout < 0 && --t) mdelay(1); - if (!t) return -1; + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); + if (sunkbd->layout < 0) return -1; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; } @@ -206,9 +206,8 @@ static void sunkbd_reinit(void *data) { struct sunkbd *sunkbd = data; - int t = 1000; - while (sunkbd->reset < 0 && --t) mdelay(1); + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, @@ -239,6 +238,7 @@ memset(sunkbd, 0, sizeof(struct sunkbd)); init_input_dev(&sunkbd->dev); + init_waitqueue_head(&sunkbd->wait); sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); @@ -275,7 +275,7 @@ set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); clear_bit(0, sunkbd->dev.keybit); - sprintf(sunkbd->name, "%s/input", serio->phys); + sprintf(sunkbd->phys, "%s/input0", serio->phys); sunkbd->dev.name = sunkbd->name; sunkbd->dev.phys = sunkbd->phys; diff -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig --- a/drivers/input/misc/Kconfig Sat Apr 3 19:38:43 2004 +++ b/drivers/input/misc/Kconfig Sat Apr 3 19:38:43 2004 @@ -54,12 +54,3 @@ To compile this driver as a module, choose M here: the module will be called uinput. -config INPUT_GSC - tristate "PA-RISC GSC PS/2 keyboard/mouse support" - depends on GSC && INPUT && INPUT_MISC - help - Say Y here if you have a PS/2 keyboard and/or mouse attached - to your PA-RISC box. HP run the keyboard in AT mode rather than - XT mode like everyone else, so we need our own driver. - Furthermore, the GSC PS/2 controller shares IRQ between mouse and - keyboard. diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile --- a/drivers/input/misc/Makefile Sat Apr 3 19:38:44 2004 +++ b/drivers/input/misc/Makefile Sat Apr 3 19:38:44 2004 @@ -9,4 +9,3 @@ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o -obj-$(CONFIG_INPUT_GSC) += gsc_ps2.o diff -Nru a/drivers/input/misc/gsc_ps2.c b/drivers/input/misc/gsc_ps2.c --- a/drivers/input/misc/gsc_ps2.c Sat Apr 3 19:38:42 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,712 +0,0 @@ -/* - * drivers/input/misc/gsc_ps2.c - * - * Copyright (c) 2002 Laurent Canet - * Copyright (c) 2002 Thibaut Varene - * - * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries - * Copyright (c) 1999-2000 Philipp Rumpf - * Copyright (c) 2000 Xavier Debacker - * Copyright (c) 2000-2001 Thomas Marteau - * - * HP PS/2 Keyboard, found in PA/RISC Workstations - * very similar to AT keyboards, but without i8042 - * - * 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, 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. - * - * STATUS: - * 11/09: lc: Only basic keyboard is supported, mouse still needs to be done. - * 11/12: tv: switching iomapping; cleaning code; improving module stuff. - * 11/13: lc & tv: leds aren't working. auto_repeat/meta are. Generaly good behavior. - * 11/15: tv: 2AM: leds ARE working ! - * 11/16: tv: 3AM: escaped keycodes emulation *handled*, some keycodes are - * still deliberately ignored (18), what are they used for ? - * 11/21: lc: mouse is now working - * 11/29: tv: first try for error handling in init sequence - * - * TODO: - * Error handling in init sequence - * SysRq handling - * Pause key handling - * Intellimouse & other rodents handling (at least send an error when - * such a mouse is plugged : it will totally fault) - * Mouse: set scaling / Dino testing - * Bug chasing... - * - */ - -#include -#include -#include -#include /* interrupt.h wants struct pt_regs defined */ -#include -#include /* for request_irq/free_irq */ -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Debugging stuff */ -#undef KBD_DEBUG -#ifdef KBD_DEBUG - #define DPRINTK(fmt,args...) printk(KERN_DEBUG __FILE__ ":" fmt, ##args) -#else - #define DPRINTK(x,...) -#endif - - -/* - * Driver constants - */ - -/* PS/2 keyboard and mouse constants */ -#define AUX_RECONNECT 0xAA /* PS/2 Mouse end of test successful */ -#define AUX_REPLY_ACK 0xFA -#define AUX_ENABLE_DEV 0xF4 /* Enables aux device */ - -/* Order of the mouse bytes coming to the host */ -#define PACKET_X 1 -#define PACKET_Y 2 -#define PACKET_CTRL 0 - -#define GSC_MOUSE_OFFSET 0x0100 /* offset from keyboard to mouse port */ -#define GSC_DINO_OFFSET 0x800 /* offset for DINO controller versus LASI one */ - -#define GSC_ID 0x00 /* ID and reset port offsets */ -#define GSC_RESET 0x00 -#define GSC_RCVDATA 0x04 /* receive and transmit port offsets */ -#define GSC_XMTDATA 0x04 -#define GSC_CONTROL 0x08 /* see: control register bits */ -#define GSC_STATUS 0x0C /* see: status register bits */ - -/* Control register bits */ -#define GSC_CTRL_ENBL 0x01 /* enable interface */ -#define GSC_CTRL_LPBXR 0x02 /* loopback operation */ -#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ -#define GSC_CTRL_DATDIR 0x40 /* data line direct control */ -#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ - -/* Status register bits */ -#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ -#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ -#define GSC_STAT_TERR 0x04 /* Timeout Error */ -#define GSC_STAT_PERR 0x08 /* Parity Error */ -#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt */ -#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ -#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ - -/* Keycode map */ -#define KBD_ESCAPE0 0xe0 -#define KBD_ESCAPE1 0xe1 -#define KBD_RELEASE 0xf0 -#define KBD_ACK 0xfa -#define KBD_RESEND 0xfe -#define KBD_UNKNOWN 0 - -#define KBD_TBLSIZE 512 - -/* Mouse */ -#define MOUSE_LEFTBTN 0x1 -#define MOUSE_MIDBTN 0x4 -#define MOUSE_RIGHTBTN 0x2 -#define MOUSE_ALWAYS1 0x8 -#define MOUSE_XSIGN 0x10 -#define MOUSE_YSIGN 0x20 -#define MOUSE_XOVFLOW 0x40 -#define MOUSE_YOVFLOW 0x80 - -/* Remnant of pc_keyb.h */ -#define KBD_CMD_SET_LEDS 0xED /* Sets keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Sets typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enables scanning */ -#define KBD_CMD_DISABLE 0xF5 -#define KBD_CMD_RESET 0xFF - -static unsigned char hpkeyb_keycode[KBD_TBLSIZE] = -{ - /* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, - /* 08 */ KBD_UNKNOWN, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_LEFTALT, KEY_LEFTSHIFT, KBD_UNKNOWN, KEY_LEFTCTRL, KEY_Q, KEY_1, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_APOSTROPHE,KBD_UNKNOWN, KEY_LEFTBRACE, KEY_EQUAL, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KBD_UNKNOWN, KEY_BACKSLASH,KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_BACKSPACE, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_KP1, KBD_UNKNOWN, KEY_KP4, KEY_KP7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, - /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_ESCAPE0, KBD_ESCAPE1, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_ACK, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_RESEND, KBD_UNKNOWN, -/* These are offset for escaped keycodes */ - /* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPSLASH, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPENTER, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_END, KBD_UNKNOWN, KEY_LEFT, KEY_HOME, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KBD_UNKNOWN, KEY_RIGHT, KEY_UP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 78 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_PAGEDOWN, KBD_UNKNOWN, KEY_SYSRQ, KEY_PAGEUP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN -}; - - -/* Keyboard struct */ -static struct { - struct input_dev dev; - char * addr; - unsigned int irq; - unsigned int scancode; - unsigned int escaped; - unsigned int released; - unsigned int initialized; -} -hpkeyb = { - .escaped = 0, - .released = 0, - .initialized = 0 -}; - -/* Mouse struct */ -static struct { - struct input_dev dev; - char * addr; - unsigned long irq; - unsigned long initialized; - int nbread; - unsigned char bytes[3]; - unsigned long last; -} -hpmouse = { - .initialized = 0, - .nbread = 0 -}; - -static spinlock_t gscps2_lock = SPIN_LOCK_UNLOCKED; - - -/* - * Various HW level routines - */ - -#define gscps2_readb_input(x) readb(x+GSC_RCVDATA) -#define gscps2_readb_control(x) readb(x+GSC_CONTROL) -#define gscps2_readb_status(x) readb(x+GSC_STATUS) -#define gscps2_writeb_control(x, y) writeb(x, y+GSC_CONTROL) - -static inline void gscps2_writeb_output(u8 val, char * addr) -{ - int wait = 250; /* Keyboard is expected to react within 250ms */ - - while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { - if (!--wait) - return; /* This should not happen */ - mdelay(1); - } - writeb(val, addr+GSC_XMTDATA); -} - -static inline unsigned char gscps2_wait_input(char * addr) -{ - int wait = 250; /* Keyboard is expected to react within 250ms */ - - while (!(gscps2_readb_status(addr) & GSC_STAT_RBNE)) { - if (!--wait) - return 0; /* This should not happen */ - mdelay(1); - } - return gscps2_readb_input(addr); -} - -static int gscps2_writeb_safe_output(u8 val) -{ - /* This function waits for keyboard's ACK */ - u8 scanread = KBD_UNKNOWN; - int loop = 5; - - while (hpkeyb_keycode[scanread]!=KBD_ACK && --loop > 0) { - gscps2_writeb_output(val, hpkeyb.addr); - mdelay(5); - scanread = gscps2_wait_input(hpkeyb.addr); - } - - if (loop <= 0) - return -1; - - return 0; -} - -/* Reset the PS2 port */ -static void __init gscps2_reset(char * addr) -{ - /* reset the interface */ - writeb(0xff, addr+GSC_RESET); - writeb(0x0 , addr+GSC_RESET); - - /* enable it */ - gscps2_writeb_control(gscps2_readb_control(addr) | GSC_CTRL_ENBL, addr); -} - - -/** - * gscps2_kbd_docode() - PS2 Keyboard basic handler - * - * Receives a keyboard scancode, analyses it and sends it to the input layer. - */ - -static void gscps2_kbd_docode(struct pt_regs *regs) -{ - int scancode = gscps2_readb_input(hpkeyb.addr); - DPRINTK("rel=%d scancode=%d, esc=%d ", hpkeyb.released, scancode, hpkeyb.escaped); - - /* Handle previously escaped scancodes */ - if (hpkeyb.escaped == KBD_ESCAPE0) - scancode |= 0x100; /* jump to the next 256 chars of the table */ - - switch (hpkeyb_keycode[scancode]) { - case KBD_RELEASE: - DPRINTK("release\n"); - hpkeyb.released = 1; - break; - case KBD_RESEND: - DPRINTK("resend request\n"); - break; - case KBD_ACK: - DPRINTK("ACK\n"); - break; - case KBD_ESCAPE0: - case KBD_ESCAPE1: - DPRINTK("escape code %d\n", hpkeyb_keycode[scancode]); - hpkeyb.escaped = hpkeyb_keycode[scancode]; - break; - case KBD_UNKNOWN: - DPRINTK("received unknown scancode %d, escape %d.\n", - scancode, hpkeyb.escaped); /* This is a DPRINTK atm since we do not handle escaped scancodes cleanly */ - if (hpkeyb.escaped) - hpkeyb.escaped = 0; - if (hpkeyb.released) - hpkeyb.released = 0; - return; - default: - hpkeyb.scancode = scancode; - DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released); - /*input_regs(regs);*/ - input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released); - input_sync(&hpkeyb.dev); - if (hpkeyb.escaped) - hpkeyb.escaped = 0; - if (hpkeyb.released) - hpkeyb.released = 0; - break; - } -} - - -/** - * gscps2_mouse_docode() - PS2 Mouse basic handler - * - * Receives mouse codes, processes them by packets of three, and sends - * correct events to the input layer. - */ - -static void gscps2_mouse_docode(struct pt_regs *regs) -{ - int xrel, yrel; - - /* process BAT (end of basic tests) command */ - if ((hpmouse.nbread == 1) && (hpmouse.bytes[0] == AUX_RECONNECT)) - hpmouse.nbread--; - - /* stolen from psmouse.c */ - if (hpmouse.nbread && time_after(jiffies, hpmouse.last + HZ/2)) { - printk(KERN_DEBUG "%s:%d : Lost mouse synchronization, throwing %d bytes away.\n", __FILE__, __LINE__, - hpmouse.nbread); - hpmouse.nbread = 0; - } - - hpmouse.last = jiffies; - hpmouse.bytes[hpmouse.nbread++] = gscps2_readb_input(hpmouse.addr); - - /* process packet */ - if (hpmouse.nbread == 3) { - - if (!(hpmouse.bytes[PACKET_CTRL] & MOUSE_ALWAYS1)) - DPRINTK("Mouse: error on packet always1 bit checking\n"); - /* XXX should exit now, bad data on the line! */ - - if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW))) - DPRINTK("Mouse: position overflow\n"); - - /*input_regs(regs);*/ - - input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN); - input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN); - input_report_key(&hpmouse.dev, BTN_RIGHT, hpmouse.bytes[PACKET_CTRL] & MOUSE_RIGHTBTN); - - xrel = hpmouse.bytes[PACKET_X]; - yrel = hpmouse.bytes[PACKET_Y]; - - /* Data sent by mouse are 9-bit signed, the sign bit is in the control packet */ - if (xrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_XSIGN)) - xrel = xrel - 0x100; - if (yrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_YSIGN)) - yrel = yrel - 0x100; - - input_report_rel(&hpmouse.dev, REL_X, xrel); - input_report_rel(&hpmouse.dev, REL_Y, -yrel); /* Y axis is received upside-down */ - - input_sync(&hpmouse.dev); - - hpmouse.nbread = 0; - } -} - - -/** - * gscps2_interrupt() - Interruption service routine - * - * This processes the list of scancodes queued and sends appropriate - * key value to the system. - */ - -static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *reg) -{ - /* process mouse actions */ - while (gscps2_readb_status(hpmouse.addr) & GSC_STAT_RBNE) - gscps2_mouse_docode(reg); - - /* process keyboard scancode */ - while (gscps2_readb_status(hpkeyb.addr) & GSC_STAT_RBNE) - gscps2_kbd_docode(reg); - - return IRQ_HANDLED; -} - - -/** - * gscps2_hpkeyb_event() - Event handler - * @return: success/error report - * - * Currently only updates leds on keyboard - */ - -int gscps2_hpkeyb_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - DPRINTK("Calling %s, type=%d, code=%d, value=%d\n", - __FUNCTION__, type, code, value); - - if (!hpkeyb.initialized) - return -1; - - if (type == EV_LED) { - u8 leds[2]; - - if (gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("KBD_CMD_SET_LEDS\n"); - - *leds = (test_bit(LED_SCROLLL, dev->led) ? LED_SCR : 0) - | (test_bit(LED_NUML, dev->led) ? LED_NUM : 0) - | (test_bit(LED_CAPSL, dev->led) ? LED_CAP : 0); - DPRINTK("Sending leds=%x\n", *leds); - - if (gscps2_writeb_safe_output(*leds)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("leds sent\n"); - - if (gscps2_writeb_safe_output(KBD_CMD_ENABLE)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("End\n"); - - return 0; - - } - return -1; -} - - -/** - * gscps2_kbd_probe() - Probes keyboard device and init input_dev structure - * @return: number of device initialized (1, 0 on error) - */ - -static int __init gscps2_kbd_probe(void) -{ - int i, res = 0; - unsigned long flags; - - if (hpkeyb.initialized) { - printk(KERN_ERR "GSC PS/2 keyboard driver already registered\n"); - return 0; - } - - spin_lock_irqsave(&gscps2_lock, flags); - - if (!gscps2_writeb_safe_output(KBD_CMD_SET_LEDS) && - !gscps2_writeb_safe_output(0) && - !gscps2_writeb_safe_output(KBD_CMD_ENABLE)) - res = 1; - - spin_unlock_irqrestore(&gscps2_lock, flags); - - if (!res) - printk(KERN_ERR "Keyboard initialization sequence failled\n"); - - init_input_dev(&hpkeyb.dev); - - for (i = 0; i < KBD_TBLSIZE; i++) - if (hpkeyb_keycode[i] != KBD_UNKNOWN) - set_bit(hpkeyb_keycode[i], hpkeyb.dev.keybit); - - hpkeyb.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - hpkeyb.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - hpkeyb.dev.keycode = hpkeyb_keycode; - hpkeyb.dev.keycodesize = sizeof(unsigned char); - hpkeyb.dev.keycodemax = KBD_TBLSIZE; - hpkeyb.dev.name = "GSC Keyboard"; - hpkeyb.dev.phys = "hpkbd/input0"; - - hpkeyb.dev.event = gscps2_hpkeyb_event; - - /* TODO These need some adjustement, are they really useful ? */ - hpkeyb.dev.id.bustype = BUS_GSC; - hpkeyb.dev.id.vendor = PCI_VENDOR_ID_HP; - hpkeyb.dev.id.product = 0x0001; - hpkeyb.dev.id.version = 0x0010; - hpkeyb.initialized = 1; - - return 1; -} - - -/** - * gscps2_mouse_probe() - Probes mouse device and init input_dev structure - * @return: number of device initialized (1, 0 on error) - * - * Currently no check on initialization is performed - */ - -static int __init gscps2_mouse_probe(void) -{ - if (hpmouse.initialized) { - printk(KERN_ERR "GSC PS/2 Mouse driver already registered\n"); - return 0; - } - - init_input_dev(&hpmouse.dev); - - hpmouse.dev.name = "GSC Mouse"; - hpmouse.dev.phys = "hpmouse/input0"; - hpmouse.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - hpmouse.dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - hpmouse.dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - hpmouse.last = 0; - - gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); - /* Try it a second time, this will give status if the device is available */ - gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); - - /* TODO These need some adjustement, are they really useful ? */ - hpmouse.dev.id.bustype = BUS_GSC; - hpmouse.dev.id.vendor = 0x0001; - hpmouse.dev.id.product = 0x0001; - hpmouse.dev.id.version = 0x0010; - hpmouse.initialized = 1; - return 1; /* XXX: we don't check if initialization failed */ -} - - -/** - * gscps2_probe() - Probes PS2 devices - * @return: success/error report - */ - -static int __init gscps2_probe(struct parisc_device *dev) -{ - u8 id; - char *addr, *name; - int ret = 0, device_found = 0; - unsigned long hpa = dev->hpa; - - if (!dev->irq) - goto fail_pitifully; - - /* Offset for DINO PS/2. Works with LASI even */ - if (dev->id.sversion == 0x96) - hpa += GSC_DINO_OFFSET; - - addr = ioremap(hpa, 256); - - if (!hpmouse.initialized || !hpkeyb.initialized) - gscps2_reset(addr); - - ret = -EINVAL; - id = readb(addr+GSC_ID) & 0x0f; - switch (id) { - case 0: /* keyboard */ - hpkeyb.addr = addr; - name = "keyboard"; - device_found = gscps2_kbd_probe(); - break; - case 1: /* mouse */ - hpmouse.addr = addr; - name = "mouse"; - device_found = gscps2_mouse_probe(); - break; - default: - printk(KERN_WARNING "%s: Unsupported PS/2 port (id=%d) ignored\n", - __FUNCTION__, id); - goto fail_miserably; - } - - /* No valid device found */ - ret = -ENODEV; - if (!device_found) - goto fail_miserably; - - /* Here we claim only if we have a device attached */ - /* Allocate the irq and memory region for that device */ - ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, 0, name, NULL)) - goto fail_miserably; - - if (!request_mem_region(hpa, GSC_STATUS + 4, name)) - goto fail_request_mem; - - /* Finalize input struct and register it */ - switch (id) { - case 0: /* keyboard */ - hpkeyb.irq = dev->irq; - input_register_device(&hpkeyb.dev); - break; - case 1: /* mouse */ - hpmouse.irq = dev->irq; - input_register_device(&hpmouse.dev); - break; - default: - break; - } - - printk(KERN_INFO "input: PS/2 %s port at 0x%08lx (irq %d) found and attached\n", - name, hpa, dev->irq); - - return 0; - -fail_request_mem: free_irq(dev->irq, NULL); -fail_miserably: iounmap(addr); -fail_pitifully: return ret; -} - - - -static struct parisc_device_id gscps2_device_tbl[] = { - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ -/* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, DINO PS/2 (XXX Not yet tested) */ - { 0, } /* 0 terminated list */ -}; - -static struct parisc_driver gscps2_driver = { - .name = "GSC PS2", - .id_table = gscps2_device_tbl, - .probe = gscps2_probe, -}; - -static int __init gscps2_init(void) -{ - if (register_parisc_driver(&gscps2_driver)) - return -EBUSY; - return 0; -} - -static void __exit gscps2_exit(void) -{ - /* TODO this is probably not very good and needs to be checked */ - if (hpkeyb.initialized) { - free_irq(hpkeyb.irq, gscps2_interrupt); - iounmap(hpkeyb.addr); - hpkeyb.initialized = 0; - input_unregister_device(&hpkeyb.dev); - } - if (hpmouse.initialized) { - free_irq(hpmouse.irq, gscps2_interrupt); - iounmap(hpmouse.addr); - hpmouse.initialized = 0; - input_unregister_device(&hpmouse.dev); - } - unregister_parisc_driver(&gscps2_driver); -} - - -MODULE_AUTHOR("Laurent Canet , Thibaut Varene "); -MODULE_DESCRIPTION("GSC PS/2 keyboard/mouse driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); - - -module_init(gscps2_init); -module_exit(gscps2_exit); diff -Nru a/drivers/input/mouse/98busmouse.c b/drivers/input/mouse/98busmouse.c --- a/drivers/input/mouse/98busmouse.c Sat Apr 3 19:38:55 2004 +++ b/drivers/input/mouse/98busmouse.c Sat Apr 3 19:38:55 2004 @@ -74,6 +74,8 @@ module_param_named(irq, pc98bm_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (13=default)"); +__obsolete_setup("pc98bm_irq="); + static int pc98bm_used = 0; static irqreturn_t pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig --- a/drivers/input/mouse/Kconfig Sat Apr 3 19:38:55 2004 +++ b/drivers/input/mouse/Kconfig Sat Apr 3 19:38:55 2004 @@ -17,6 +17,7 @@ depends on INPUT && INPUT_MOUSE select SERIO select SERIO_I8042 if PC + select SERIO_GSCPS2 if GSC ---help--- Say Y here if you have a PS/2 mouse connected to your system. This includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 @@ -116,6 +117,19 @@ To compile this driver as a module, choose M here: the module will be called rpcmouse. + +config MOUSE_VSXXXAA + tristate "DEC VSXXX-AA/GA mouse and tablet" + depends on INPUT && INPUT_MOUSE + select SERIO + help + Say Y (or M) if you want to use a DEC VSXXX-AA (hockey + puck) or a VSXXX-GA (rectangular) mouse. Theses mice are + typically used on DECstations or VAXstations, but can also + be used on any box capable of RS232 (with some adaptor + described in the source file). This driver should, in theory, + also work with the digitizer DEC produced, but it isn't tested + with that (I don't have the hardware yet). config MOUSE_PC9800 tristate "NEC PC-9800 busmouse" diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile --- a/drivers/input/mouse/Makefile Sat Apr 3 19:38:41 2004 +++ b/drivers/input/mouse/Makefile Sat Apr 3 19:38:41 2004 @@ -13,5 +13,6 @@ obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o psmouse-objs := psmouse-base.o logips2pp.o synaptics.o diff -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c --- a/drivers/input/mouse/inport.c Sat Apr 3 19:38:43 2004 +++ b/drivers/input/mouse/inport.c Sat Apr 3 19:38:43 2004 @@ -85,6 +85,8 @@ module_param_named(irq, inport_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); +__obsolete_setup("inport_irq="); + static int inport_used; static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c --- a/drivers/input/mouse/logibm.c Sat Apr 3 19:38:43 2004 +++ b/drivers/input/mouse/logibm.c Sat Apr 3 19:38:43 2004 @@ -75,6 +75,8 @@ module_param_named(irq, logibm_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); +__obsolete_setup("logibm_irq="); + static int logibm_used = 0; static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c --- a/drivers/input/mouse/maplemouse.c Sat Apr 3 19:38:55 2004 +++ b/drivers/input/mouse/maplemouse.c Sat Apr 3 19:38:55 2004 @@ -1,5 +1,5 @@ /* - * $Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $ * SEGA Dreamcast mouse driver * Based on drivers/usb/usbmouse.c */ @@ -74,22 +74,21 @@ mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); + init_input_dev(&mouse->dev); + mouse->dev.private = mouse; mouse->dev.open = dc_mouse_open; mouse->dev.close = dc_mouse_close; mouse->dev.event = NULL; mouse->dev.name = dev->product_name; - mouse->dev.idbus = BUS_MAPLE; + mouse->dev.id.bustype = BUS_MAPLE; input_register_device(&mouse->dev); maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); - printk(KERN_INFO "input%d: mouse(0x%lx): %s\n", - mouse->dev.number, data, mouse->dev.name); - - MOD_INC_USE_COUNT; + printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name); return 0; } @@ -100,10 +99,7 @@ struct dc_mouse *mouse = dev->private_data; input_unregister_device(&mouse->dev); - kfree(mouse); - - MOD_DEC_USE_COUNT; } diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c Sat Apr 3 19:38:42 2004 +++ b/drivers/input/mouse/psmouse-base.c Sat Apr 3 19:38:42 2004 @@ -47,6 +47,12 @@ module_param_named(resetafter, psmouse_resetafter, uint, 0); MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never)."); +__obsolete_setup("psmouse_noext"); +__obsolete_setup("psmouse_resolution="); +__obsolete_setup("psmouse_smartscroll="); +__obsolete_setup("psmouse_resetafter="); +__obsolete_setup("psmouse_rate="); + static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; /* @@ -163,14 +169,14 @@ psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->pktcnt = 0; } - + psmouse->last = jiffies; psmouse->packet[psmouse->pktcnt++] = data; if (psmouse->packet[0] == PSMOUSE_RET_BAT) { if (psmouse->pktcnt == 1) goto out; - + if (psmouse->pktcnt == 2) { if (psmouse->packet[1] == PSMOUSE_RET_ID) { psmouse->state = PSMOUSE_IGNORE; @@ -258,7 +264,7 @@ return (psmouse->cmdcnt = 0) - 1; while (psmouse->cmdcnt && timeout--) { - + if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) /* do not run in a endless loop */ timeout = 100000; /* 1 sec */ @@ -281,6 +287,24 @@ return 0; } + +/* + * psmouse_reset() resets the mouse into power-on state. + */ +int psmouse_reset(struct psmouse *psmouse) +{ + unsigned char param[2]; + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT)) + return -1; + + if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID) + return -1; + + return 0; +} + + /* * Genius NetMouse magic init. */ @@ -365,6 +389,10 @@ */ psmouse_max_proto = PSMOUSE_IMEX; } +/* + * Make sure that touchpad is in relative mode, gestures (taps) are enabled + */ + synaptics_reset(psmouse); } if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { @@ -410,6 +438,7 @@ * pass through port it could get disabled while probing for protocol * extensions. */ + psmouse_reset(psmouse); psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS); } @@ -442,7 +471,7 @@ */ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) - return -1; + printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); /* * And here we try to determine if it has any extensions over the @@ -497,7 +526,7 @@ static void psmouse_initialize(struct psmouse *psmouse) { unsigned char param[2]; - + /* * We set the mouse report rate, resolution and scaling. */ @@ -534,8 +563,8 @@ static void psmouse_cleanup(struct serio *serio) { struct psmouse *psmouse = serio->private; - unsigned char param[2]; - psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT); + + psmouse_reset(psmouse); } /* @@ -546,7 +575,7 @@ { struct psmouse *psmouse = serio->private; - psmouse->state = PSMOUSE_IGNORE; + psmouse->state = PSMOUSE_CMD_MODE; if (psmouse->ptport) { if (psmouse->ptport->deactivate) @@ -559,6 +588,8 @@ if (psmouse->disconnect) psmouse->disconnect(psmouse); + psmouse->state = PSMOUSE_IGNORE; + input_unregister_device(&psmouse->dev); serio_close(serio); kfree(psmouse); @@ -571,7 +602,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) { struct psmouse *psmouse; - + if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; @@ -586,7 +617,7 @@ psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->state = PSMOUSE_NEW_DEVICE; + psmouse->state = PSMOUSE_CMD_MODE; psmouse->serio = serio; psmouse->dev.private = psmouse; @@ -603,7 +634,7 @@ serio->private = NULL; return; } - + sprintf(psmouse->devname, "%s %s %s", psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); sprintf(psmouse->phys, "%s/input0", @@ -617,7 +648,7 @@ psmouse->dev.id.version = psmouse->model; input_register_device(&psmouse->dev); - + printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); psmouse_initialize(psmouse); @@ -637,14 +668,16 @@ { struct psmouse *psmouse = serio->private; struct serio_dev *dev = serio->dev; - int old_type = psmouse->type; + int old_type; - if (!dev) { + if (!dev || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } - psmouse->state = PSMOUSE_NEW_DEVICE; + old_type = psmouse->type; + + psmouse->state = PSMOUSE_CMD_MODE; psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0; if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h --- a/drivers/input/mouse/psmouse.h Sat Apr 3 19:38:55 2004 +++ b/drivers/input/mouse/psmouse.h Sat Apr 3 19:38:55 2004 @@ -5,7 +5,7 @@ #define PSMOUSE_CMD_SETRES 0x10e8 #define PSMOUSE_CMD_GETINFO 0x03e9 #define PSMOUSE_CMD_SETSTREAM 0x00ea -#define PSMOUSE_CMD_POLL 0x03eb +#define PSMOUSE_CMD_POLL 0x03eb #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 @@ -18,7 +18,7 @@ #define PSMOUSE_RET_NAK 0xfe /* psmouse states */ -#define PSMOUSE_NEW_DEVICE 0 +#define PSMOUSE_CMD_MODE 0 #define PSMOUSE_ACTIVATED 1 #define PSMOUSE_IGNORE 2 @@ -65,6 +65,7 @@ #define PSMOUSE_SYNAPTICS 7 int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); +int psmouse_reset(struct psmouse *psmouse); extern int psmouse_smartscroll; extern unsigned int psmouse_rate; diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c --- a/drivers/input/mouse/synaptics.c Sat Apr 3 19:38:42 2004 +++ b/drivers/input/mouse/synaptics.c Sat Apr 3 19:38:42 2004 @@ -92,17 +92,6 @@ return 0; } -static int synaptics_reset(struct psmouse *psmouse) -{ - unsigned char r[2]; - - if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT)) - return -1; - if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID) - return 0; - return -1; -} - /* * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros @@ -197,7 +186,7 @@ { int retries = 0; - while ((retries++ < 3) && synaptics_reset(psmouse)) + while ((retries++ < 3) && psmouse_reset(psmouse)) printk(KERN_ERR "synaptics reset failed\n"); if (synaptics_identify(psmouse)) @@ -368,9 +357,15 @@ clear_bit(REL_Y, dev->relbit); } -static void synaptics_disconnect(struct psmouse *psmouse) +void synaptics_reset(struct psmouse *psmouse) { + /* reset touchpad back to relative mode, gestures enabled */ synaptics_mode_cmd(psmouse, 0); +} + +static void synaptics_disconnect(struct psmouse *psmouse) +{ + synaptics_reset(psmouse); kfree(psmouse->private); } @@ -435,6 +430,8 @@ goto init_fail; } + priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities)) synaptics_pt_create(psmouse); @@ -602,19 +599,42 @@ input_sync(dev); } -static int synaptics_validate_byte(struct psmouse *psmouse) +static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) { - static unsigned char newabs_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - struct synaptics_data *priv = psmouse->private; - int idx = psmouse->pktcnt - 1; + static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; + static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; + static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; + static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; + static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + + switch (pkt_type) { + case SYN_NEWABS: + case SYN_NEWABS_RELAXED: + return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; - if (SYN_MODEL_NEWABS(priv->model_id)) - return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; - else - return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; + case SYN_NEWABS_STRICT: + return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; + + case SYN_OLDABS: + return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; + + default: + printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); + return 0; + } +} + +static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) +{ + int i; + + for (i = 0; i < 5; i++) + if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) { + printk(KERN_INFO "synaptics: using relaxed packet validation\n"); + return SYN_NEWABS_RELAXED; + } + + return SYN_NEWABS_STRICT; } void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) @@ -630,13 +650,17 @@ printk(KERN_NOTICE "Synaptics driver resynced.\n"); } + if (unlikely(priv->pkt_type == SYN_NEWABS)) + priv->pkt_type = synaptics_detect_pkt_type(psmouse); + if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); else synaptics_process_packet(psmouse); psmouse->pktcnt = 0; - } else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) { + } else if (psmouse->pktcnt && + !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) { printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); psmouse->pktcnt = 0; if (++priv->out_of_sync == psmouse_resetafter) { diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h --- a/drivers/input/mouse/synaptics.h Sat Apr 3 19:38:43 2004 +++ b/drivers/input/mouse/synaptics.h Sat Apr 3 19:38:43 2004 @@ -12,6 +12,7 @@ extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs); extern int synaptics_detect(struct psmouse *psmouse); extern int synaptics_init(struct psmouse *psmouse); +extern void synaptics_reset(struct psmouse *psmouse); /* synaptics queries */ #define SYN_QUE_IDENTIFY 0x00 @@ -70,6 +71,12 @@ #define SYN_PS_SET_MODE2 0x14 #define SYN_PS_CLIENT_CMD 0x28 +/* synaptics packet types */ +#define SYN_NEWABS 0 +#define SYN_NEWABS_STRICT 1 +#define SYN_NEWABS_RELAXED 2 +#define SYN_OLDABS 3 + /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -103,6 +110,7 @@ /* Data for normal processing */ unsigned int out_of_sync; /* # of packets out of sync */ int old_w; /* Previous w value */ + unsigned char pkt_type; /* packet type - old, new, etc */ }; #endif /* _SYNAPTICS_H */ diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/mouse/vsxxxaa.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,550 @@ +/* + * DEC VSXXX-AA and VSXXX-GA mouse driver. + * + * Copyright (C) 2003-2004 by Jan-Benedict Glaw + * + * The packet format was taken from a patch to GPM which is (C) 2001 + * by Karsten Merker + * and Maciej W. Rozycki + */ + +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Building an adaptor to DB9 / DB25 RS232 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for + * anything if you break your mouse, your computer or whatever! + * + * In theory, this mouse is a simple RS232 device. In practice, it has got + * a quite uncommon plug and the requirement to additionally get a power + * supply at +5V and -12V. + * + * If you look at the socket/jack (_not_ at the plug), we use this pin + * numbering: + * _______ + * / 7 6 5 \ + * | 4 --- 3 | + * \ 2 1 / + * ------- + * + * DEC socket DB9 DB25 Note + * 1 (GND) 5 7 - + * 2 (RxD) 3 3 - + * 3 (TxD) 2 2 - + * 4 (-12V) - - Somewhere from the PSU. At ATX, it's + * the blue wire at pin 12 of the ATX + * power connector. Please note that the + * docs say this should be +12V! However, + * I measured -12V... + * 5 (+5V) - - PSU (red wire of ATX power connector + * on pin 4, 6, 19 or 20) or HDD power + * connector (also red wire) + * 6 (not conn.) - - - + * 7 (dev. avail.) - - The mouse shorts this one to pin 1. + * This way, the host computer can detect + * the mouse. To use it with the adaptor, + * simply don't connect this pin. + * + * So to get a working adaptor, you need to connect the mouse with three + * wires to a RS232 port and two additional wires for +5V and -12V to the + * PSU. + * + * Flow specification for the link is 4800, 8o1. + */ + +/* + * TODO list: + * - Automatically attach to a given serial port (no need for inputattach). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR ("Jan-Benedict Glaw "); +MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_LICENSE ("GPL"); + +#undef VSXXXAA_DEBUG +#ifdef VSXXXAA_DEBUG +#define DBG(x...) printk (x) +#else +#define DBG(x...) do {} while (0) +#endif + +#define VSXXXAA_INTRO_MASK 0x80 +#define VSXXXAA_INTRO_HEAD 0x80 +#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ + == VSXXXAA_INTRO_HEAD) + +#define VSXXXAA_PACKET_MASK 0xe0 +#define VSXXXAA_PACKET_REL 0x80 +#define VSXXXAA_PACKET_ABS 0xc0 +#define VSXXXAA_PACKET_POR 0xa0 +#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == type) + + + +struct vsxxxaa { + struct input_dev dev; + struct serio *serio; +#define BUFLEN 15 /* At least 5 is needed for a full tablet packet */ + unsigned char buf[BUFLEN]; + unsigned char count; + unsigned char version; + unsigned char country; + unsigned char type; + char phys[32]; +}; + +static void +vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num) +{ + if (num >= mouse->count) + mouse->count = 0; + else { + memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); + mouse->count -= num; + } +} + +static void +vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) +{ + if (mouse->count == BUFLEN) { + printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", + mouse->dev.name, mouse->dev.phys); + vsxxxaa_drop_bytes (mouse, 1); + } + + mouse->buf[mouse->count++] = byte; +} + +static void +vsxxxaa_report_mouse (struct vsxxxaa *mouse) +{ + char *devtype; + + switch (mouse->type) { + case 0x02: devtype = "DEC mouse"; break; + case 0x04: devtype = "DEC tablet"; break; + default: devtype = "unknown DEC device"; break; + } + + printk (KERN_INFO "Found %s version 0x%x from country 0x%x " + "on port %s\n", devtype, mouse->version, + mouse->country, mouse->dev.phys); +} + +/* + * Returns number of bytes to be dropped, 0 if packet is okay. + */ +static int +vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len) +{ + int i; + + /* First byte must be a header byte */ + if (!IS_HDR_BYTE (mouse->buf[0])) { + DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); + return 1; + } + + /* Check all following bytes */ + if (packet_len > 1) { + for (i = 1; i < packet_len; i++) { + if (IS_HDR_BYTE (mouse->buf[i])) { + printk (KERN_ERR "Need to drop %d bytes " + "of a broken packet.\n", + i - 1); + DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", + packet_len, i, mouse->buf[i]); + return i - 1; + } + } + } + + return 0; +} + +static __inline__ int +vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) +{ + return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type); +} + +static void +vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right; + int dx, dy; + + /* + * Check for normal stream packets. This is three bytes, + * with the first byte's 3 MSB set to 100. + * + * [0]: 1 0 0 SignX SignY Left Middle Right + * [1]: 0 dx dx dx dx dx dx dx + * [2]: 0 dy dy dy dy dy dy dy + */ + + /* + * Low 7 bit of byte 1 are abs(dx), bit 7 is + * 0, bit 4 of byte 0 is direction. + */ + dx = buf[1] & 0x7f; + dx *= ((buf[0] >> 4) & 0x01)? -1: 1; + + /* + * Low 7 bit of byte 2 are abs(dy), bit 7 is + * 0, bit 3 of byte 0 is direction. + */ + dy = buf[2] & 0x7f; + dy *= ((buf[0] >> 3) & 0x01)? -1: 1; + + /* + * Get button state. It's the low three bits + * (for three buttons) of byte 0. + */ + left = (buf[0] & 0x04)? 1: 0; + middle = (buf[0] & 0x02)? 1: 0; + right = (buf[0] & 0x01)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 3); + + DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", + mouse->dev.name, mouse->dev.phys, dx, dy, + left? "L": "l", middle? "M": "m", right? "R": "r"); + + /* + * Report what we've found so far... + */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_report_rel (dev, REL_X, dx); + input_report_rel (dev, REL_Y, dy); + input_sync (dev); +} + +static void +vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right, extra; + int x, y; + + /* + * Tablet position / button packet + * + * [0]: 1 1 0 B4 B3 B2 B1 Pr + * [1]: 0 0 X5 X4 X3 X2 X1 X0 + * [2]: 0 0 X11 X10 X9 X8 X7 X6 + * [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0 + * [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6 + */ + + /* + * Get X/Y position + */ + x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f); + y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f); + + /* + * Get button state. It's bits <4..1> of byte 0. + */ + left = (buf[0] & 0x02)? 1: 0; + middle = (buf[0] & 0x04)? 1: 0; + right = (buf[0] & 0x08)? 1: 0; + extra = (buf[0] & 0x10)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 5); + + DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", + mouse->dev.name, mouse->dev.phys, x, y, + left? "L": "l", middle? "M": "m", + right? "R": "r", extra? "E": "e"); + + /* + * Report what we've found so far... + */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_EXTRA, extra); + input_report_abs (dev, ABS_X, x); + input_report_abs (dev, ABS_Y, y); + input_sync (dev); +} + +static void +vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right; + unsigned char error; + + /* + * Check for Power-On-Reset packets. These are sent out + * after plugging the mouse in, or when explicitely + * requested by sending 'T'. + * + * [0]: 1 0 1 0 R3 R2 R1 R0 + * [1]: 0 M2 M1 M0 D3 D2 D1 D0 + * [2]: 0 E6 E5 E4 E3 E2 E1 E0 + * [3]: 0 0 0 0 0 Left Middle Right + * + * M: manufacturer location code + * R: revision code + * E: Error code. I'm not sure about these, but gpm's sources, + * which support this mouse, too, tell about them: + * E = [0x00 .. 0x1f]: no error, byte #3 is button state + * E = 0x3d: button error, byte #3 tells which one. + * E = : other error + * D: <0010> == mouse, <0100> == tablet + * + */ + + mouse->version = buf[0] & 0x0f; + mouse->country = (buf[1] >> 4) & 0x07; + mouse->type = buf[1] & 0x07; + error = buf[2] & 0x7f; + + /* + * Get button state. It's the low three bits + * (for three buttons) of byte 0. Maybe even the bit <3> + * has some meaning if a tablet is attached. + */ + left = (buf[0] & 0x04)? 1: 0; + middle = (buf[0] & 0x02)? 1: 0; + right = (buf[0] & 0x01)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 4); + vsxxxaa_report_mouse (mouse); + + if (error <= 0x1f) { + /* No error. Report buttons */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_sync (dev); + } else { + printk (KERN_ERR "Your %s on %s reports an undefined error, " + "please check it...\n", mouse->dev.name, + mouse->dev.phys); + } + + /* + * If the mouse was hot-plugged, we need to + * force differential mode now... + */ + printk (KERN_NOTICE "%s on %s: Forceing standard packet format and " + "streaming mode\n", mouse->dev.name, mouse->dev.phys); + mouse->serio->write (mouse->serio, 'S'); + mouse->serio->write (mouse->serio, 'R'); +} + +static void +vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + unsigned char *buf = mouse->buf; + int stray_bytes; + + /* + * Parse buffer to death... + */ + do { + /* + * Out of sync? Throw away what we don't understand. Each + * packet starts with a byte whose bit 7 is set. Unhandled + * packets (ie. which we don't know about or simply b0rk3d + * data...) will get shifted out of the buffer after some + * activity on the mouse. + */ + while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { + printk (KERN_ERR "%s on %s: Dropping a byte to regain " + "sync with mouse data stream...\n", + mouse->dev.name, mouse->dev.phys); + vsxxxaa_drop_bytes (mouse, 1); + } + + /* + * Check for packets we know about. + */ + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 3); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_REL_packet (mouse, regs); + continue; /* More to parse? */ + } + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 5); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_ABS_packet (mouse, regs); + continue; /* More to parse? */ + } + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 4); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_POR_packet (mouse, regs); + continue; /* More to parse? */ + } + + break; /* No REL, ABS or POR packet found */ + } while (1); +} + +static irqreturn_t +vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags, + struct pt_regs *regs) +{ + struct vsxxxaa *mouse = serio->private; + + vsxxxaa_queue_byte (mouse, data); + vsxxxaa_parse_buffer (mouse, regs); + + return IRQ_HANDLED; +} + +static void +vsxxxaa_disconnect (struct serio *serio) +{ + struct vsxxxaa *mouse = serio->private; + + input_unregister_device (&mouse->dev); + serio_close (serio); + kfree (mouse); +} + +static void +vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +{ + struct vsxxxaa *mouse; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA) + return; + + if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL))) + return; + + memset (mouse, 0, sizeof (struct vsxxxaa)); + + init_input_dev (&mouse->dev); + set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ + set_bit (EV_REL, mouse->dev.evbit); /* We can move */ + set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ + set_bit (BTN_MIDDLE, mouse->dev.keybit); + set_bit (BTN_RIGHT, mouse->dev.keybit); + set_bit (BTN_EXTRA, mouse->dev.keybit); /* ...and Tablet */ + set_bit (REL_X, mouse->dev.relbit); /* We can move in */ + set_bit (REL_Y, mouse->dev.relbit); /* two dimensions */ + set_bit (ABS_X, mouse->dev.absbit); /* DEC tablet support */ + set_bit (ABS_Y, mouse->dev.absbit); + + mouse->dev.absmin[ABS_X] = 0; + mouse->dev.absmax[ABS_X] = 1023; + mouse->dev.absmin[ABS_Y] = 0; + mouse->dev.absmax[ABS_Y] = 1023; + + mouse->dev.private = mouse; + serio->private = mouse; + + sprintf (mouse->phys, "%s/input0", serio->phys); + mouse->dev.phys = mouse->phys; + mouse->dev.name = "DEC VSXXX-AA/GA mouse or DEC tablet"; + mouse->dev.id.bustype = BUS_RS232; + mouse->serio = serio; + + if (serio_open (serio, dev)) { + kfree (mouse); + return; + } + + /* + * Request selftest and differential stream mode. + */ + mouse->serio->write (mouse->serio, 'T'); /* Test */ + mouse->serio->write (mouse->serio, 'R'); /* Differential stream */ + + input_register_device (&mouse->dev); + + printk (KERN_INFO "input: %s on %s\n", mouse->dev.name, serio->phys); +} + +static struct serio_dev vsxxxaa_dev = { + .interrupt = vsxxxaa_interrupt, + .connect = vsxxxaa_connect, + .disconnect = vsxxxaa_disconnect +}; + +int __init +vsxxxaa_init (void) +{ + serio_register_device (&vsxxxaa_dev); + return 0; +} + +void __exit +vsxxxaa_exit (void) +{ + serio_unregister_device (&vsxxxaa_dev); +} + +module_init (vsxxxaa_init); +module_exit (vsxxxaa_exit); + diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig --- a/drivers/input/serio/Kconfig Sat Apr 3 19:38:43 2004 +++ b/drivers/input/serio/Kconfig Sat Apr 3 19:38:43 2004 @@ -20,6 +20,7 @@ tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y select SERIO + depends on !PARISC ---help--- i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -48,6 +49,7 @@ config SERIO_CT82C710 tristate "ct82c710 Aux port controller" depends on SERIO + depends on !PARISC ---help--- Say Y here if you have a Texas Instruments TravelMate notebook equipped with the ct82c710 chip and want to use a mouse connected @@ -104,6 +106,20 @@ To compile this driver as a module, choose M here: the module will be called 98kbd-io. + +config SERIO_GSCPS2 + tristate "HP GSC PS/2 keyboard and PS/2 mouse controller" + depends on GSC && SERIO + default y + help + This driver provides support for the PS/2 ports on PA-RISC machines + over which HP PS/2 keyboards and PS/2 mice may be connected. + If you use these devices, you'll need to say Y here. + + It's safe to enable this driver, so if unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called gscps2. config SERIO_PCIPS2 tristate "PCI PS/2 keyboard and PS/2 mouse controller" diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile --- a/drivers/input/serio/Makefile Sat Apr 3 19:38:41 2004 +++ b/drivers/input/serio/Makefile Sat Apr 3 19:38:41 2004 @@ -14,4 +14,5 @@ obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o +obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o diff -Nru a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/gscps2.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,470 @@ +/* + * drivers/input/serio/gscps2.c + * + * Copyright (c) 2004 Helge Deller + * Copyright (c) 2002 Laurent Canet + * Copyright (c) 2002 Thibaut Varene + * + * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c + * Copyright (c) 1999 Alex deVries + * Copyright (c) 1999-2000 Philipp Rumpf + * Copyright (c) 2000 Xavier Debacker + * Copyright (c) 2000-2001 Thomas Marteau + * + * HP GSC PS/2 port driver, found in PA/RISC Workstations + * + * 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. + * + * TODO: + * - Dino testing (did HP ever shipped a machine on which this port + * was usable/enabled ?) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Laurent Canet , Thibaut Varene , Helge Deller "); +MODULE_DESCRIPTION("HP GSC PS/2 port driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); + +#define PFX "gscps2.c: " + +/* + * Driver constants + */ + +/* various constants */ +#define ENABLE 1 +#define DISABLE 0 + +#define GSC_DINO_OFFSET 0x0800 /* offset for DINO controller versus LASI one */ + +/* PS/2 IO port offsets */ +#define GSC_ID 0x00 /* device ID offset (see: GSC_ID_XXX) */ +#define GSC_RESET 0x00 /* reset port offset */ +#define GSC_RCVDATA 0x04 /* receive port offset */ +#define GSC_XMTDATA 0x04 /* transmit port offset */ +#define GSC_CONTROL 0x08 /* see: Control register bits */ +#define GSC_STATUS 0x0C /* see: Status register bits */ + +/* Control register bits */ +#define GSC_CTRL_ENBL 0x01 /* enable interface */ +#define GSC_CTRL_LPBXR 0x02 /* loopback operation */ +#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ +#define GSC_CTRL_DATDIR 0x40 /* data line direct control */ +#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ + +/* Status register bits */ +#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ +#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ +#define GSC_STAT_TERR 0x04 /* Timeout Error */ +#define GSC_STAT_PERR 0x08 /* Parity Error */ +#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt = irq on any port */ +#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ +#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ + +/* IDs returned by GSC_ID port register */ +#define GSC_ID_KEYBOARD 0 /* device ID values */ +#define GSC_ID_MOUSE 1 + + +static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); + +#define BUFFER_SIZE 0x0f + +/* GSC PS/2 port device struct */ +struct gscps2port { + struct list_head node; + struct parisc_device *padev; + struct serio port; + spinlock_t lock; + char *addr; + u8 act, append; /* position in buffer[] */ + struct { + u8 data; + u8 str; + } buffer[BUFFER_SIZE+1]; + int id; + char name[32]; +}; + +/* + * Various HW level routines + */ + +#define gscps2_readb_input(x) readb((x)+GSC_RCVDATA) +#define gscps2_readb_control(x) readb((x)+GSC_CONTROL) +#define gscps2_readb_status(x) readb((x)+GSC_STATUS) +#define gscps2_writeb_control(x, y) writeb((x), (y)+GSC_CONTROL) + + +/* + * wait_TBE() - wait for Transmit Buffer Empty + */ + +static int wait_TBE(char *addr) +{ + int timeout = 25000; /* device is expected to react within 250 msec */ + while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { + if (!--timeout) + return 0; /* This should not happen */ + udelay(10); + } + return 1; +} + + +/* + * gscps2_flush() - flush the receive buffer + */ + +static void gscps2_flush(struct gscps2port *ps2port) +{ + while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) + gscps2_readb_input(ps2port->addr); + ps2port->act = ps2port->append = 0; +} + +/* + * gscps2_writeb_output() - write a byte to the port + * + * returns 1 on sucess, 0 on error + */ + +static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) +{ + unsigned long flags; + char *addr = ps2port->addr; + + if (!wait_TBE(addr)) { + printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data); + return 0; + } + + while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) + /* wait */; + + spin_lock_irqsave(&ps2port->lock, flags); + writeb(data, addr+GSC_XMTDATA); + spin_unlock_irqrestore(&ps2port->lock, flags); + + /* this is ugly, but due to timing of the port it seems to be necessary. */ + mdelay(6); + + /* make sure any received data is returned as fast as possible */ + /* this is important e.g. when we set the LEDs on the keyboard */ + gscps2_interrupt(0, NULL, NULL); + + return 1; +} + + +/* + * gscps2_enable() - enables or disables the port + */ + +static void gscps2_enable(struct gscps2port *ps2port, int enable) +{ + unsigned long flags; + u8 data; + + /* now enable/disable the port */ + spin_lock_irqsave(&ps2port->lock, flags); + gscps2_flush(ps2port); + data = gscps2_readb_control(ps2port->addr); + if (enable) + data |= GSC_CTRL_ENBL; + else + data &= ~GSC_CTRL_ENBL; + gscps2_writeb_control(data, ps2port->addr); + spin_unlock_irqrestore(&ps2port->lock, flags); + wait_TBE(ps2port->addr); + gscps2_flush(ps2port); +} + +/* + * gscps2_reset() - resets the PS/2 port + */ + +static void gscps2_reset(struct gscps2port *ps2port) +{ + char *addr = ps2port->addr; + unsigned long flags; + + /* reset the interface */ + spin_lock_irqsave(&ps2port->lock, flags); + gscps2_flush(ps2port); + writeb(0xff, addr+GSC_RESET); + gscps2_flush(ps2port); + spin_unlock_irqrestore(&ps2port->lock, flags); + + /* enable it */ + gscps2_enable(ps2port, ENABLE); +} + +static LIST_HEAD(ps2port_list); + +/** + * gscps2_interrupt() - Interruption service routine + * + * This function reads received PS/2 bytes and processes them on + * all interfaces. + * The problematic part here is, that the keyboard and mouse PS/2 port + * share the same interrupt and it's not possible to send data if any + * one of them holds input data. To solve this problem we try to receive + * the data as fast as possible and handle the reporting to the upper layer + * later. + */ + +static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + struct gscps2port *ps2port; + + list_for_each_entry(ps2port, &ps2port_list, node) { + + unsigned long flags; + spin_lock_irqsave(&ps2port->lock, flags); + + while ( (ps2port->buffer[ps2port->append].str = + gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { + ps2port->buffer[ps2port->append].data = + gscps2_readb_input(ps2port->addr); + ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); + } + + spin_unlock_irqrestore(&ps2port->lock, flags); + + } /* list_for_each_entry */ + + /* all data was read from the ports - now report the data to upper layer */ + + list_for_each_entry(ps2port, &ps2port_list, node) { + + while (ps2port->act != ps2port->append) { + + unsigned int rxflags; + u8 data, status; + + /* Did new data arrived while we read existing data ? + If yes, exit now and let the new irq handler start over again */ + if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) + return IRQ_HANDLED; + + status = ps2port->buffer[ps2port->act].str; + data = ps2port->buffer[ps2port->act].data; + + ps2port->act = ((ps2port->act+1) & BUFFER_SIZE); + rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | + ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); + + serio_interrupt(&ps2port->port, data, rxflags, regs); + + } /* while() */ + + } /* list_for_each_entry */ + + return IRQ_HANDLED; +} + + +/* + * gscps2_write() - send a byte out through the aux interface. + */ + +static int gscps2_write(struct serio *port, unsigned char data) +{ + struct gscps2port *ps2port = port->driver; + + if (!gscps2_writeb_output(ps2port, data)) { + printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); + return -1; + } + return 0; +} + +/* + * gscps2_open() is called when a port is opened by the higher layer. + * It resets and enables the port. + */ + +static int gscps2_open(struct serio *port) +{ + struct gscps2port *ps2port = port->driver; + + gscps2_reset(ps2port); + + gscps2_interrupt(0, NULL, NULL); + + return 0; +} + +/* + * gscps2_close() disables the port + */ + +static void gscps2_close(struct serio *port) +{ + struct gscps2port *ps2port = port->driver; + gscps2_enable(ps2port, DISABLE); +} + +static struct serio gscps2_serio_port = +{ + .name = "GSC PS/2", + .idbus = BUS_GSC, + .idvendor = PCI_VENDOR_ID_HP, + .idproduct = 0x0001, + .idversion = 0x0010, + .type = SERIO_8042, + .write = gscps2_write, + .open = gscps2_open, + .close = gscps2_close, +}; + +/** + * gscps2_probe() - Probes PS2 devices + * @return: success/error report + */ + +static int __init gscps2_probe(struct parisc_device *dev) +{ + struct gscps2port *ps2port; + unsigned long hpa = dev->hpa; + int ret; + + if (!dev->irq) + return -ENODEV; + + /* Offset for DINO PS/2. Works with LASI even */ + if (dev->id.sversion == 0x96) + hpa += GSC_DINO_OFFSET; + + ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); + if (!ps2port) + return -ENOMEM; + + dev_set_drvdata(&dev->dev, ps2port); + + memset(ps2port, 0, sizeof(struct gscps2port)); + ps2port->padev = dev; + ps2port->addr = ioremap(hpa, GSC_STATUS + 4); + spin_lock_init(&ps2port->lock); + + gscps2_reset(ps2port); + ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; + snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", + gscps2_serio_port.name, + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); + + memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); + ps2port->port.driver = ps2port; + ps2port->port.name = ps2port->name; + ps2port->port.phys = dev->dev.bus_id; + + list_add_tail(&ps2port->node, &ps2port_list); + + ret = -EBUSY; + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + goto fail_miserably; + + if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", + hpa, ps2port->id); + ret = -ENODEV; + goto fail; + } + +#if 0 + if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name)) + goto fail; +#endif + + printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", + ps2port->name, + ps2port->addr, + ps2port->padev->irq, + ps2port->port.phys); + + serio_register_port(&ps2port->port); + + return 0; + +fail: + free_irq(dev->irq, ps2port); + +fail_miserably: + list_del(&ps2port->node); + iounmap(ps2port->addr); + release_mem_region(dev->hpa, GSC_STATUS + 4); + kfree(ps2port); + return ret; +} + +/** + * gscps2_remove() - Removes PS2 devices + * @return: success/error report + */ + +static int __devexit gscps2_remove(struct parisc_device *dev) +{ + struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); + + serio_unregister_port(&ps2port->port); + free_irq(dev->irq, ps2port); + gscps2_flush(ps2port); + list_del(&ps2port->node); + iounmap(ps2port->addr); +#if 0 + release_mem_region(dev->hpa, GSC_STATUS + 4); +#endif + dev_set_drvdata(&dev->dev, NULL); + kfree(ps2port); + return 0; +} + + +static struct parisc_device_id gscps2_device_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ +#ifdef DINO_TESTED + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ +#endif + { 0, } /* 0 terminated list */ +}; + +static struct parisc_driver parisc_ps2_driver = { + .name = "GSC PS/2", + .id_table = gscps2_device_tbl, + .probe = gscps2_probe, + .remove = gscps2_remove, +}; + +static int __init gscps2_init(void) +{ + register_parisc_driver(&parisc_ps2_driver); + return 0; +} + +static void __exit gscps2_exit(void) +{ + unregister_parisc_driver(&parisc_ps2_driver); +} + + +module_init(gscps2_init); +module_exit(gscps2_exit); + diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h --- a/drivers/input/serio/i8042-io.h Sat Apr 3 19:38:40 2004 +++ b/drivers/input/serio/i8042-io.h Sat Apr 3 19:38:40 2004 @@ -25,6 +25,9 @@ #elif defined(__ia64__) # define I8042_KBD_IRQ isa_irq_to_vector(1) # define I8042_AUX_IRQ isa_irq_to_vector(12) +#elif defined(__arm__) +/* defined in include/asm-arm/arch-xxx/irqs.h */ +#include #else # define I8042_KBD_IRQ 1 # define I8042_AUX_IRQ 12 diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c Sat Apr 3 19:38:41 2004 +++ b/drivers/input/serio/i8042.c Sat Apr 3 19:38:41 2004 @@ -52,6 +52,13 @@ module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +__obsolete_setup("i8042_noaux"); +__obsolete_setup("i8042_nomux"); +__obsolete_setup("i8042_unlock"); +__obsolete_setup("i8042_reset"); +__obsolete_setup("i8042_direct"); +__obsolete_setup("i8042_dumbkbd"); + #undef DEBUG #include "i8042.h" @@ -379,6 +386,8 @@ unsigned int dfl; int ret; + mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); + spin_lock_irqsave(&i8042_lock, flags); str = i8042_read_status(); if (str & I8042_STR_OBF) @@ -433,7 +442,6 @@ irq_ret: ret = 1; out: - mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); return IRQ_RETVAL(ret); } @@ -521,6 +529,11 @@ unsigned char mux_version; if (i8042_enable_mux_mode(values, &mux_version)) + return -1; + + /* Workaround for broken chips which seem to support MUX, but in reality don't. */ + /* They all report version 12.10 */ + if (mux_version == 0xCA) return -1; printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c --- a/drivers/input/serio/serio.c Sat Apr 3 19:38:40 2004 +++ b/drivers/input/serio/serio.c Sat Apr 3 19:38:40 2004 @@ -195,6 +195,9 @@ ret = serio->dev->interrupt(serio, data, flags, regs); } else { if (!flags) { + if ((serio->type == SERIO_8042 || + serio->type == SERIO_8042_XL) && (data != 0xaa)) + return ret; serio_rescan(serio); ret = IRQ_HANDLED; } diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c --- a/drivers/isdn/capi/capi.c Sat Apr 3 19:38:56 2004 +++ b/drivers/isdn/capi/capi.c Sat Apr 3 19:38:56 2004 @@ -1,4 +1,4 @@ -/* $Id: capi.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ +/* $Id: capi.c,v 1.1.2.4 2004/03/29 10:38:02 armin Exp $ * * CAPI 2.0 Interface for Linux * @@ -44,7 +44,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.1.2.3 $"; +static char *revision = "$Revision: 1.1.2.4 $"; MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); @@ -200,7 +200,6 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) { struct capiminor *mp, *p; - struct list_head *l; unsigned int minor = 0; unsigned long flags; @@ -219,26 +218,31 @@ skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->outqueue); + /* Allocate the least unused minor number. + */ write_lock_irqsave(&capiminor_list_lock, flags); - if (list_empty(&capiminor_list)) { + if (list_empty(&capiminor_list)) list_add(&mp->list, &capiminor_list); - write_unlock_irqrestore(&capiminor_list_lock, flags); - } else { - list_for_each(l, &capiminor_list) { - p = list_entry(l, struct capiminor, list); - if (p->minor > minor) { - mp->minor = minor; - list_add_tail(&mp->list, &p->list); + else { + list_for_each_entry(p, &capiminor_list, list) { + if (p->minor > minor) break; - } minor++; } + + if (minor < capi_ttyminors) { + mp->minor = minor; + list_add(&mp->list, p->list.prev); + } + } write_unlock_irqrestore(&capiminor_list_lock, flags); - if (l == &capiminor_list) { + + if (!(minor < capi_ttyminors)) { + printk(KERN_NOTICE "capi: out of minors\n"); kfree(mp); - return NULL; - } + return 0; } + return mp; } diff -Nru a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c --- a/drivers/isdn/capi/kcapi.c Sat Apr 3 19:38:55 2004 +++ b/drivers/isdn/capi/kcapi.c Sat Apr 3 19:38:55 2004 @@ -1,4 +1,4 @@ -/* $Id: kcapi.c,v 1.1.2.4 2004/02/10 01:07:11 keil Exp $ +/* $Id: kcapi.c,v 1.1.2.7 2004/03/16 08:01:47 armin Exp $ * * Kernel CAPI 2.0 Module * @@ -31,7 +31,7 @@ #include #endif -static char *revision = "$Revision: 1.1.2.4 $"; +static char *revision = "$Revision: 1.1.2.7 $"; /* ------------------------------------------------------------- */ @@ -45,7 +45,7 @@ /* ------------------------------------------------------------- */ struct capi_notifier { - struct capi_notifier *next; + struct work_struct work; unsigned int cmd; u32 controller; u16 applid; @@ -69,7 +69,6 @@ static int ncards; static struct sk_buff_head recv_queue; -static struct work_struct tq_state_notify; static struct work_struct tq_recv_notify; /* -------- controller ref counting -------------------------------------- */ @@ -161,79 +160,6 @@ capi_ctr_put(card); } - -/* -------- Notifier handling --------------------------------- */ - -static struct capi_notifier_list{ - struct capi_notifier *head; - struct capi_notifier *tail; -} notifier_list; - -static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED; - -static inline void notify_enqueue(struct capi_notifier *np) -{ - struct capi_notifier_list *q = ¬ifier_list; - unsigned long flags; - - spin_lock_irqsave(¬ifier_lock, flags); - if (q->tail) { - q->tail->next = np; - q->tail = np; - } else { - q->head = q->tail = np; - } - spin_unlock_irqrestore(¬ifier_lock, flags); -} - -static inline struct capi_notifier *notify_dequeue(void) -{ - struct capi_notifier_list *q = ¬ifier_list; - struct capi_notifier *np = 0; - unsigned long flags; - - spin_lock_irqsave(¬ifier_lock, flags); - if (q->head) { - np = q->head; - if ((q->head = np->next) == 0) - q->tail = 0; - np->next = 0; - } - spin_unlock_irqrestore(¬ifier_lock, flags); - return np; -} - -static int notify_push(unsigned int cmd, u32 controller, - u16 applid, u32 ncci) -{ - struct capi_notifier *np; - - if (!try_module_get(THIS_MODULE)) { - printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__); - return -1; - } - np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC); - if (!np) { - module_put(THIS_MODULE); - return -1; - } - memset(np, 0, sizeof(struct capi_notifier)); - np->cmd = cmd; - np->controller = controller; - np->applid = applid; - np->ncci = ncci; - notify_enqueue(np); - /* - * The notifier will result in adding/deleteing - * of devices. Devices can only removed in - * user process, not in bh. - */ - __module_get(THIS_MODULE); - if (schedule_work(&tq_state_notify) == 0) - module_put(THIS_MODULE); - return 0; -} - /* -------- KCI_CONTRUP --------------------------------------- */ static void notify_up(u32 contr) @@ -242,7 +168,9 @@ struct capi20_appl *ap; u16 applid; - printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); + } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { ap = get_capi_appl_by_nr(applid); @@ -258,7 +186,9 @@ struct capi20_appl *ap; u16 applid; - printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); + } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { ap = get_capi_appl_by_nr(applid); @@ -267,31 +197,43 @@ } } -/* ------------------------------------------------------------ */ - -static inline void notify_doit(struct capi_notifier *np) +static void notify_handler(void *data) { + struct capi_notifier *np = data; + switch (np->cmd) { - case KCI_CONTRUP: - notify_up(np->controller); - break; - case KCI_CONTRDOWN: - notify_down(np->controller); - break; + case KCI_CONTRUP: + notify_up(np->controller); + break; + case KCI_CONTRDOWN: + notify_down(np->controller); + break; } + + kfree(np); } -static void notify_handler(void *dummy) +/* + * The notifier will result in adding/deleteing of devices. Devices can + * only removed in user process, not in bh. + */ +static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) { - struct capi_notifier *np; + struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC); - while ((np = notify_dequeue()) != 0) { - notify_doit(np); - kfree(np); - module_put(THIS_MODULE); - } - module_put(THIS_MODULE); + if (!np) + return -ENOMEM; + + INIT_WORK(&np->work, notify_handler, np); + np->cmd = cmd; + np->controller = controller; + np->applid = applid; + np->ncci = ncci; + + schedule_work(&np->work); + return 0; } + /* -------- Receiver ------------------------------------------ */ @@ -304,7 +246,7 @@ ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); if (!ap) { printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n", - ap->applid, capi_message2str(skb->data)); + CAPIMSG_APPID(skb->data), capi_message2str(skb->data)); kfree_skb(skb); continue; } @@ -565,7 +507,9 @@ continue; register_appl(capi_cards[i], applid, &ap->rparam); } - printk(KERN_DEBUG "kcapi: appl %d up\n", applid); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "kcapi: appl %d up\n", applid); + } return CAPI_NOERROR; } @@ -584,7 +528,9 @@ release_appl(capi_cards[i], ap->applid); } capi_applications[ap->applid - 1] = NULL; - printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid); + } return CAPI_NOERROR; } @@ -981,7 +927,6 @@ skb_queue_head_init(&recv_queue); - INIT_WORK(&tq_state_notify, notify_handler, NULL); INIT_WORK(&tq_recv_notify, recv_handler, NULL); kcapi_proc_init(); @@ -1001,6 +946,9 @@ static void __exit kcapi_exit(void) { kcapi_proc_exit(); + + /* make sure all notifiers are finished */ + flush_scheduled_work(); } module_init(kcapi_init); diff -Nru a/drivers/isdn/hardware/eicon/adapter.h b/drivers/isdn/hardware/eicon/adapter.h --- a/drivers/isdn/hardware/eicon/adapter.h Sat Apr 3 19:38:55 2004 +++ b/drivers/isdn/hardware/eicon/adapter.h Sat Apr 3 19:38:55 2004 @@ -1,4 +1,4 @@ -/* $Id: adapter.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */ +/* $Id: adapter.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */ #ifndef __DIVA_USER_MODE_IDI_ADAPTER_H__ #define __DIVA_USER_MODE_IDI_ADAPTER_H__ @@ -6,10 +6,10 @@ #define DIVA_UM_IDI_ADAPTER_REMOVED 0x00000001 typedef struct _diva_um_idi_adapter { - diva_entity_link_t link; + struct list_head link; DESCRIPTOR d; int adapter_nr; - diva_entity_queue_t entity_q; /* entities linked to this adapter */ + struct list_head entity_q; /* entities linked to this adapter */ dword status; } diva_um_idi_adapter_t; diff -Nru a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c --- a/drivers/isdn/hardware/eicon/capifunc.c Sat Apr 3 19:38:55 2004 +++ b/drivers/isdn/hardware/eicon/capifunc.c Sat Apr 3 19:38:55 2004 @@ -1,4 +1,4 @@ -/* $Id: capifunc.c,v 1.48 2004/01/11 19:20:54 armin Exp $ +/* $Id: capifunc.c,v 1.61 2004/03/26 19:48:48 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -39,9 +39,9 @@ extern word api_put(APPL *, CAPI_MSG *); static diva_os_spin_lock_t api_lock; -static diva_os_spin_lock_t ll_lock; -static diva_card *cards; +static LIST_HEAD(cards); + static dword notify_handle; static void DIRequest(ENTITY * e); static DESCRIPTOR MAdapter; @@ -152,26 +152,15 @@ static int find_free_id(void) { int num = 0; - diva_card *p; - diva_os_spin_lock_magic_t old_irql; + DIVA_CAPI_ADAPTER *a; - diva_os_enter_spin_lock(&ll_lock, &old_irql, "find free id"); - while (num < 100) { - num++; - p = cards; - while (p) { - if (p->Id == num) + while (num < MAX_DESCRIPTORS) { + a = &adapter[num]; + if (!a->Id) break; - p = p->next; - } - if(!p) { - diva_os_leave_spin_lock(&ll_lock, &old_irql, - "find free id"); - return (num); - } + num++; } - diva_os_leave_spin_lock(&ll_lock, &old_irql, "find free id"); - return (999); + return(num + 1); } /* @@ -179,21 +168,17 @@ */ static diva_card *find_card_by_ctrl(word controller) { - diva_card *p; - diva_os_spin_lock_magic_t old_irql; - - diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card ctrl"); - p = cards; + struct list_head *tmp; + diva_card *card; - while (p) { - if (ControllerMap[p->Id] == controller) { - diva_os_leave_spin_lock(&ll_lock, &old_irql, - "find card ctrl"); - return p; + list_for_each(tmp, &cards) { + card = list_entry(tmp, diva_card, list); + if (ControllerMap[card->Id] == controller) { + if (card->remove_in_progress) + card = NULL; + return(card); } - p = p->next; } - diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card ctrl"); return (diva_card *) 0; } @@ -358,28 +343,18 @@ /* * cleanup adapter */ -static void clean_adapter(int id) +static void clean_adapter(int id, struct list_head *free_mem_q) { DIVA_CAPI_ADAPTER *a; -#if IMPLEMENT_LINE_INTERCONNECT2 int i, k; -#endif /* IMPLEMENT_LINE_INTERCONNECT2 */ a = &adapter[id]; -#if IMPLEMENT_LINE_INTERCONNECT - if (a->li_pri) { - if (a->li_config.pri) - diva_os_free(0, a->li_config.pri); - } else { - if (a->li_config.bri) - diva_os_free(0, a->li_config.bri); - } -#endif /* IMPLEMENT_LINE_INTERCONNECT */ -#if IMPLEMENT_LINE_INTERCONNECT2 k = li_total_channels - a->li_channels; if (k == 0) { - diva_os_free(0, li_config_table); + if (li_config_table) { + list_add((struct list_head *)li_config_table, free_mem_q); li_config_table = NULL; + } } else { if (a->li_base < k) { memmove(&li_config_table[a->li_base], @@ -401,9 +376,8 @@ if (adapter[i].request) adapter[i].li_base -= a->li_channels; } -#endif /* IMPLEMENT_LINE_INTERCONNECT2 */ if (a->plci) - diva_os_free(0, a->plci); + list_add((struct list_head *)a->plci, free_mem_q); memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER)); while ((max_adapter != 0) && !adapter[max_adapter - 1].request) @@ -411,67 +385,85 @@ } /* - * remove cards + * remove a card, but ensures consistent state of LI tables + * in the time adapter is removed */ -static void DIVA_EXIT_FUNCTION divacapi_remove_cards(void) +static void divacapi_remove_card(DESCRIPTOR * d) { - diva_card *last; - diva_card *card; + diva_card *card = NULL; diva_os_spin_lock_magic_t old_irql; + LIST_HEAD(free_mem_q); + struct list_head *link; + struct list_head *tmp; + + /* + * Set "remove in progress flag". + * Ensures that there is no call from sendf to CAPI in + * the time CAPI controller is about to be removed. + */ + diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); + list_for_each(tmp, &cards) { + card = list_entry(tmp, diva_card, list); + if (card->d.request == d->request) { + card->remove_in_progress = 1; + list_del(tmp); + break; + } + } + diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); - diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove cards"); - card = cards; - - while (card) { + if (card) { + /* + * Detach CAPI. Sendf cannot call to CAPI any more. + * After detach no call to send_message() is done too. + */ detach_capi_ctr(&card->capi_ctrl); - clean_adapter(card->Id - 1); - DBG_TRC(("adapter remove, max_adapter=%d", max_adapter)); - card = card->next; - } - card = cards; - while (card) { - last = card; - card = card->next; - diva_os_free(0, last); + /* + * Now get API lock (to ensure stable state of LI tables) + * and update the adapter map/LI table. + */ + diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); + + clean_adapter(card->Id - 1, &free_mem_q); + DBG_TRC(("DelAdapterMap (%d) -> (%d)", + ControllerMap[card->Id], card->Id)) + ControllerMap[card->Id] = 0; + DBG_TRC(("adapter remove, max_adapter=%d", + max_adapter)); + diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); + + /* After releasing the lock, we can free the memory */ + diva_os_free (0, card); + } + + /* free queued memory areas */ + list_for_each_safe(link, tmp, &free_mem_q) { + list_del(link); + diva_os_free(0, link); } - diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove cards"); } /* - * remove a card + * remove cards */ -static void divacapi_remove_card(DESCRIPTOR * d) +static void divacapi_remove_cards(void) { - diva_card *last; + DESCRIPTOR d; + struct list_head *tmp; diva_card *card; diva_os_spin_lock_magic_t old_irql; - diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card"); - last = card = cards; - while (card) { - if (card->d.request == d->request) { - detach_capi_ctr(&card->capi_ctrl); - clean_adapter(card->Id - 1); - DBG_TRC( - ("DelAdapterMap (%d) -> (%d)", - ControllerMap[card->Id], card->Id)) - ControllerMap[card->Id] = 0; - DBG_TRC( - ("adapter remove, max_adapter=%d", - max_adapter)); - if (card == last) - cards = card->next; - else - last->next = card->next; - - diva_os_free(0, card); - break; - } - last = card; - card = card->next; +rescan: + diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards"); + list_for_each(tmp, &cards) { + card = list_entry(tmp, diva_card, list); + diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); + d.request = card->d.request; + divacapi_remove_card(&d); + goto rescan; } - diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card"); + diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); } /* @@ -500,10 +492,9 @@ DIVA_CAPI_ADAPTER *a = NULL; IDI_SYNC_REQ sync_req; char serial[16]; -#if IMPLEMENT_LINE_INTERCONNECT2 + void* mem_to_free; LI_CONFIG *new_li_config_table; int j; -#endif /* IMPLEMENT_LINE_INTERCONNECT2 */ if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) { DBG_ERR(("diva_add_card: failed to allocate card struct.")) @@ -529,7 +520,11 @@ diva_os_free(0, card); return (0); } + + diva_os_enter_spin_lock(&api_lock, &old_irql, "find id"); card->Id = find_free_id(); + diva_os_leave_spin_lock(&api_lock, &old_irql, "find id"); + strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu)); ctrl->version.majorversion = 2; ctrl->version.minorversion = 0; @@ -600,9 +595,7 @@ #if IMPLEMENT_DTMF a->profile.Global_Options |= 0x8; #endif /* IMPLEMENT_DTMF */ -#if (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2) - a->profile.Global_Options |= 0x80; -#endif /* (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2) */ + a->profile.Global_Options |= 0x80; /* Line Interconnect */ #if IMPLEMENT_ECHO_CANCELLER a->profile.Global_Options |= 0x100; #endif /* IMPLEMENT_ECHO_CANCELLER */ @@ -620,25 +613,6 @@ a->manufacturer_features = 0; } -#if IMPLEMENT_LINE_INTERCONNECT - a->li_pri = (a->profile.Channels > 2); - if (a->li_pri) { - if (!(a->li_config.pri = (LI_CONFIG_PRI *) diva_os_malloc(0, sizeof(LI_CONFIG_PRI)))) { - DBG_ERR(("diva_add_card: failed alloc li_config.pri struct.")) - memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); - return (0); - } - memset(a->li_config.pri, 0, sizeof(LI_CONFIG_PRI)); - } else - if (!(a->li_config.bri = (LI_CONFIG_BRI *) diva_os_malloc(0, sizeof(LI_CONFIG_BRI)))) { - DBG_ERR(("diva_add_card: failed alloc li_config.bri struct.")) - memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); - return (0); - } - memset(a->li_config.bri, 0, sizeof(LI_CONFIG_BRI)); - } -#endif /* IMPLEMENT_LINE_INTERCONNECT */ -#if IMPLEMENT_LINE_INTERCONNECT2 a->li_pri = (a->profile.Channels > 2); a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI; a->li_base = 0; @@ -654,6 +628,10 @@ memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); return (0); } + + /* Prevent access to line interconnect table in process update */ + diva_os_enter_spin_lock(&api_lock, &old_irql, "add card"); + j = 0; for (i = 0; i < k; i++) { if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) @@ -694,25 +672,26 @@ } li_total_channels = k; - if (li_config_table != NULL) - diva_os_free(0, li_config_table); + mem_to_free = li_config_table; li_config_table = new_li_config_table; for (i = card->Id; i < max_adapter; i++) { if (adapter[i].request) adapter[i].li_base += a->li_channels; } -#endif /* IMPLEMENT_LINE_INTERCONNECT2 */ if (a == &adapter[max_adapter]) max_adapter++; - diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card"); - card->next = cards; - cards = card; - diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card"); - + list_add(&(card->list), &cards); AutomaticLaw(a); + + diva_os_leave_spin_lock(&api_lock, &old_irql, "add card"); + + if (mem_to_free) { + diva_os_free (0, mem_to_free); + } + i = 0; while (i++ < 30) { if (a->automatic_law > 3) @@ -863,6 +842,7 @@ { diva_os_spin_lock_magic_t old_irql; APPL *this = &application[appl - 1]; + void *mem_to_free = NULL; DBG_TRC(("application %d(%d) cleanup", this->Id, appl)) @@ -874,13 +854,15 @@ diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl"); if (this->Id) { CapiRelease(this->Id); - if (this->DataNCCI) - diva_os_free(0, this->DataNCCI); + mem_to_free = this->DataNCCI; this->DataNCCI = NULL; this->Id = 0; } diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl"); + if (mem_to_free) + diva_os_free(0, mem_to_free); + } /* @@ -906,7 +888,15 @@ } DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command)) + if (card->remove_in_progress) { + DBG_ERR(("CAPI_SEND_MSG - remove in progress!")) + return CAPI_REGOSRESOURCEERR; + } + + diva_os_enter_spin_lock(&api_lock, &old_irql, "send message"); + if (!this->Id) { + diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); return CAPI_ILLAPPNR; } @@ -914,8 +904,6 @@ msg->header.controller = ControllerMap[card->Id] | (msg->header.controller & 0x80); /* preserve external controller bit */ - diva_os_enter_spin_lock(&api_lock, &old_irql, "send message"); - switch (command) { default: xlog("\x00\x02", msg, 0x80, clength); @@ -1163,11 +1151,30 @@ } /* + * api_remove_start + */ +static void do_api_remove_start(void) +{ + diva_os_spin_lock_magic_t old_irql; + int ret = 1, count = 100; + + do { + diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start"); + ret = api_remove_start(); + diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start"); + + diva_os_sleep(10); + } while (ret && count--); + + if (ret) + DBG_ERR(("could not remove signaling ID's")) +} + +/* * init */ int DIVA_INIT_FUNCTION init_capifunc(void) { - diva_os_initialize_spin_lock(&ll_lock, "capifunc"); diva_os_initialize_spin_lock(&api_lock, "capifunc"); memset(ControllerMap, 0, MAX_DESCRIPTORS + 1); max_adapter = 0; @@ -1175,12 +1182,16 @@ if (!init_main_structs()) { DBG_ERR(("init: failed to init main structs.")) + diva_os_destroy_spin_lock(&api_lock, "capifunc"); return (0); } if (!divacapi_connect_didd()) { DBG_ERR(("init: failed to connect to DIDD.")) + do_api_remove_start(); + divacapi_remove_cards(); remove_main_structs(); + diva_os_destroy_spin_lock(&api_lock, "capifunc"); return (0); } @@ -1192,21 +1203,9 @@ */ void DIVA_EXIT_FUNCTION finit_capifunc(void) { - int count = 100; - word ret = 1; - - while (ret && count--) { - ret = api_remove_start(); - diva_os_sleep(10); - } - if (ret) - DBG_ERR(("could not remove signaling ID's")) - + do_api_remove_start(); divacapi_disconnect_didd(); divacapi_remove_cards(); - remove_main_structs(); - diva_os_destroy_spin_lock(&api_lock, "capifunc"); - diva_os_destroy_spin_lock(&ll_lock, "capifunc"); } diff -Nru a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h --- a/drivers/isdn/hardware/eicon/capifunc.h Sat Apr 3 19:38:54 2004 +++ b/drivers/isdn/hardware/eicon/capifunc.h Sat Apr 3 19:38:54 2004 @@ -1,4 +1,4 @@ -/* $Id: capifunc.h,v 1.10 2003/08/25 10:06:37 schindler Exp $ +/* $Id: capifunc.h,v 1.11 2004/03/20 17:19:58 armin Exp $ * * ISDN interface module for Eicon active cards DIVA. * CAPI Interface common functions @@ -24,8 +24,9 @@ extern char DRIVERRELEASE_CAPI[]; typedef struct _diva_card { + struct list_head list; + int remove_in_progress; int Id; - struct _diva_card *next; struct capi_ctr capi_ctrl; DIVA_CAPI_ADAPTER *adapter; DESCRIPTOR d; diff -Nru a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c --- a/drivers/isdn/hardware/eicon/diva.c Sat Apr 3 19:38:55 2004 +++ b/drivers/isdn/hardware/eicon/diva.c Sat Apr 3 19:38:55 2004 @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.17 2003/09/09 06:52:01 schindler Exp $ */ +/* $Id: diva.c,v 1.21 2004/03/21 17:30:25 armin Exp $ */ #define CARDTYPE_H_WANT_DATA 1 #define CARDTYPE_H_WANT_IDI_DATA 0 @@ -8,7 +8,6 @@ #include "platform.h" #include "debuglib.h" #include "cardtype.h" -#include "dlist.h" #include "pc.h" #include "di_defs.h" #include "di.h" @@ -75,14 +74,9 @@ struct pt_regs; /* - * include queue functions - */ -#include "dlist.c" - -/* ** LOCALS */ -diva_entity_queue_t adapter_queue; +static LIST_HEAD(adapter_queue); typedef struct _diva_get_xlog { word command; @@ -158,6 +152,16 @@ return (0); } +static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what) +{ + diva_os_xdi_adapter_t *a = NULL; + + if (what && !list_empty(what)) + a = list_entry(what->next, diva_os_xdi_adapter_t, link); + + return(a); +} + /* -------------------------------------------------------------------------- Add card to the card list -------------------------------------------------------------------------- */ @@ -204,7 +208,7 @@ diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card"); pa = pdiva; for (j = 1; j < nr; j++) { /* slave adapters, if any */ - pa = (diva_os_xdi_adapter_t *) diva_q_get_next(&pa->link); + pa = diva_q_get_next(&pa->link); if (pa && !pa->interface.cleanup_adapter_proc) { pa->controller = i + 1 + j; pa->xdi_adapter.ANum = pa->controller; @@ -246,7 +250,6 @@ int divasa_xdi_driver_entry(void) { diva_os_initialize_spin_lock(&adapter_lock, "adapter"); - diva_q_init(&adapter_queue); memset(&IoAdapters[0], 0x00, sizeof(IoAdapters)); diva_init_request_array(); @@ -259,12 +262,14 @@ static diva_os_xdi_adapter_t *get_and_remove_from_queue(void) { diva_os_spin_lock_magic_t old_irql; - diva_os_xdi_adapter_t *a; + diva_os_xdi_adapter_t *a = NULL; diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload"); - if ((a = (diva_os_xdi_adapter_t *) diva_q_get_head(&adapter_queue))) - diva_q_remove(&adapter_queue, &a->link); + if (!list_empty(&adapter_queue)) { + a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link); + list_del(adapter_queue.next); + } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload"); return (a); @@ -286,7 +291,7 @@ diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter"); for (i = 1; i < 4; i++) { - if ((pa = (diva_os_xdi_adapter_t *) diva_q_get_next(&pa->link)) + if ((pa = diva_q_get_next(&pa->link)) && !pa->interface.cleanup_adapter_proc) { a[i] = pa; } else { @@ -295,7 +300,7 @@ } for (i = 0; ((i < 4) && a[i]); i++) { - diva_q_remove(&adapter_queue, &a[i]->link); + list_del(&a[i]->link); } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload"); @@ -345,12 +350,12 @@ numbers as master adapter */ diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); - diva_q_add_tail(&adapter_queue, &a->link); + list_add_tail(&a->link, &adapter_queue); diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); if ((*(pI->init_card)) (a)) { diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); - diva_q_remove(&adapter_queue, &a->link); + list_del(&a->link); diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); diva_os_free(0, a); DBG_ERR(("A: can't get adapter resources")); @@ -383,21 +388,14 @@ /* ** Receive and process command from user mode utility */ -static int cmp_adapter_nr(const void *what, const diva_entity_link_t * p) -{ - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) p; - dword nr = (dword) (unsigned long) what; - - return (nr != a->controller); -} - void *diva_xdi_open_adapter(void *os_handle, const void *src, int length, divas_xdi_copy_from_user_fn_t cp_fn) { diva_xdi_um_cfg_cmd_t msg; - diva_os_xdi_adapter_t *a; + diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; + struct list_head *tmp; if (length < sizeof(diva_xdi_um_cfg_cmd_t)) { DBG_ERR(("A: A(?) open, msg too small (%d < %d)", @@ -409,10 +407,12 @@ return (0); } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); - a = (diva_os_xdi_adapter_t *) diva_q_find(&adapter_queue, - (void *) (unsigned long) - msg.adapter, - cmp_adapter_nr); + list_for_each(tmp, &adapter_queue) { + a = list_entry(tmp, diva_os_xdi_adapter_t, link); + if (a->controller == (int)msg.adapter) + break; + a = NULL; + } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { @@ -611,7 +611,7 @@ diva_os_spin_lock_magic_t old_irql; diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave"); - diva_q_add_tail(&adapter_queue, &a->link); + list_add_tail(&a->link, &adapter_queue); diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave"); } diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c --- a/drivers/isdn/hardware/eicon/divasmain.c Sat Apr 3 19:38:41 2004 +++ b/drivers/isdn/hardware/eicon/divasmain.c Sat Apr 3 19:38:41 2004 @@ -1,4 +1,4 @@ -/* $Id: divasmain.c,v 1.48 2004/02/24 17:46:28 armin Exp $ +/* $Id: divasmain.c,v 1.54 2004/04/02 18:59:22 armin Exp $ * * Low level driver for Eicon DIVA Server ISDN cards. * @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #undef ID_MASK #undef N_DATA #include "pc.h" -#include "dlist.h" #include "di_defs.h" #include "divasync.h" #include "diva.h" @@ -41,7 +41,7 @@ #include "diva_dma.h" #include "diva_pci.h" -static char *main_revision = "$Revision: 1.48 $"; +static char *main_revision = "$Revision: 1.54 $"; static int major; @@ -69,7 +69,7 @@ extern void divasfunc_exit(void); typedef struct _diva_os_thread_dpc { - struct work_struct divas_task; + struct tasklet_struct divas_task; struct work_struct trap_script_task; diva_os_soft_isr_t *psoft_isr; int card_failed; @@ -552,7 +552,7 @@ /* -------------------------------------------------------------------------- DPC framework implementation -------------------------------------------------------------------------- */ -static void diva_os_dpc_proc(void *context) +static void diva_os_dpc_proc(unsigned long context) { diva_os_thread_dpc_t *psoft_isr = (diva_os_thread_dpc_t *) context; diva_os_soft_isr_t *pisr = psoft_isr->psoft_isr; @@ -575,7 +575,7 @@ psoft_isr->callback_context = callback_context; pdpc->psoft_isr = psoft_isr; INIT_WORK(&pdpc->trap_script_task, diva_adapter_trapped, pdpc); - INIT_WORK(&pdpc->divas_task, diva_os_dpc_proc, pdpc); + tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc); return (0); } @@ -586,7 +586,7 @@ diva_os_thread_dpc_t *pdpc = (diva_os_thread_dpc_t *) psoft_isr->object; - schedule_work(&pdpc->divas_task); + tasklet_schedule(&pdpc->divas_task); } return (1); @@ -600,8 +600,11 @@ void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr) { if (psoft_isr && psoft_isr->object) { + diva_os_thread_dpc_t *pdpc = + (diva_os_thread_dpc_t *) psoft_isr->object; void *mem; + tasklet_kill(&pdpc->divas_task); flush_scheduled_work(); mem = psoft_isr->object; psoft_isr->object = 0; diff -Nru a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c --- a/drivers/isdn/hardware/eicon/divasproc.c Sat Apr 3 19:38:54 2004 +++ b/drivers/isdn/hardware/eicon/divasproc.c Sat Apr 3 19:38:54 2004 @@ -1,4 +1,4 @@ -/* $Id: divasproc.c,v 1.18 2003/09/09 06:46:29 schindler Exp $ +/* $Id: divasproc.c,v 1.19 2004/03/21 17:26:01 armin Exp $ * * Low level driver for Eicon DIVA Server ISDN cards. * /proc functions @@ -15,10 +15,10 @@ #include #include #include +#include #include "platform.h" #include "debuglib.h" -#include "dlist.h" #undef ID_MASK #undef N_DATA #include "pc.h" @@ -33,7 +33,6 @@ extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; -extern diva_entity_queue_t adapter_queue; extern void divas_get_version(char *); extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf); diff -Nru a/drivers/isdn/hardware/eicon/dlist.c b/drivers/isdn/hardware/eicon/dlist.c --- a/drivers/isdn/hardware/eicon/dlist.c Sat Apr 3 19:38:40 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,76 +0,0 @@ -/* $Id: dlist.c,v 1.6 2003/08/25 16:03:35 schindler Exp $ */ - -#include "platform.h" -#include "dlist.h" - -/* -** Initialize linked list -*/ - -static void diva_q_init(diva_entity_queue_t * q) -{ - memset(q, 0x00, sizeof(*q)); -} - -/* -** Remove element from linked list -*/ -static void diva_q_remove(diva_entity_queue_t * q, diva_entity_link_t * what) -{ - if (!what->prev) { - if ((q->head = what->next)) { - q->head->prev = 0; - } else { - q->tail = 0; - } - } else if (!what->next) { - q->tail = what->prev; - q->tail->next = 0; - } else { - what->prev->next = what->next; - what->next->prev = what->prev; - } - what->prev = what->next = 0; -} - -/* -** Add element to the tail of linked list -*/ -static void diva_q_add_tail(diva_entity_queue_t * q, diva_entity_link_t * what) -{ - what->next = 0; - if (!q->head) { - what->prev = 0; - q->head = q->tail = what; - } else { - what->prev = q->tail; - q->tail->next = what; - q->tail = what; - } -} - -static diva_entity_link_t *diva_q_find(const diva_entity_queue_t * q, - const void *what, diva_q_cmp_fn_t cmp_fn) -{ - diva_entity_link_t *diva_current = q->head; - - while (diva_current) { - if (!(*cmp_fn) (what, diva_current)) { - break; - } - diva_current = diva_current->next; - } - - return (diva_current); -} - -static diva_entity_link_t *diva_q_get_head(diva_entity_queue_t * q) -{ - return (q->head); -} - -static diva_entity_link_t *diva_q_get_next(diva_entity_link_t * what) -{ - return ((what) ? what->next : 0); -} - diff -Nru a/drivers/isdn/hardware/eicon/dlist.h b/drivers/isdn/hardware/eicon/dlist.h --- a/drivers/isdn/hardware/eicon/dlist.h Sat Apr 3 19:38:56 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* $Id: dlist.h,v 1.5 2003/08/25 16:03:35 schindler Exp $ */ - -#ifndef __DIVA_LINK_H__ -#define __DIVA_LINK_H__ - -struct _diva_entity_link; -typedef struct _diva_entity_link { - struct _diva_entity_link *prev; - struct _diva_entity_link *next; -} diva_entity_link_t; - -typedef struct _diva_entity_queue { - diva_entity_link_t *head; - diva_entity_link_t *tail; -} diva_entity_queue_t; - -typedef int (*diva_q_cmp_fn_t) (const void *what, - const diva_entity_link_t *); - -#endif diff -Nru a/drivers/isdn/hardware/eicon/entity.h b/drivers/isdn/hardware/eicon/entity.h --- a/drivers/isdn/hardware/eicon/entity.h Sat Apr 3 19:38:44 2004 +++ b/drivers/isdn/hardware/eicon/entity.h Sat Apr 3 19:38:44 2004 @@ -1,4 +1,4 @@ -/* $Id: entity.h,v 1.1.2.1 2001/02/08 12:25:43 armin Exp $ */ +/* $Id: entity.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */ #ifndef __DIVAS_USER_MODE_IDI_ENTITY__ #define __DIVAS_USER_MODE_IDI_ENTITY__ @@ -10,7 +10,7 @@ #define DIVA_UM_IDI_ASSIGN_PENDING 0x00000010 typedef struct _divas_um_idi_entity { - diva_entity_link_t link; /* should be first */ + struct list_head link; diva_um_idi_adapter_t* adapter; /* Back to adapter */ ENTITY e; void* os_ref; diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.c b/drivers/isdn/hardware/eicon/i4l_idi.c --- a/drivers/isdn/hardware/eicon/i4l_idi.c Sat Apr 3 19:38:43 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,3135 +0,0 @@ -/* $Id: i4l_idi.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ - * - * ISDN interface module for Eicon active cards. - * I4L - IDI Interface - * - * Copyright 1998-2000 by Armin Schindler (mac@melware.de) - * Copyright 1999-2002 Cytronics & Melware (info@melware.de) - * - * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH - * for sponsoring and testing fax - * capabilities with Diva Server cards. - * (dor@deutschemailbox.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include -#include "i4lididrv.h" - -#undef EICON_FULL_SERVICE_OKTETT - -char *eicon_idi_revision = "$Revision: 1.1.2.2 $"; - -eicon_manifbuf *manbuf; - -static int eicon_idi_manage_assign(eicon_card *card); -static int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer); - -static int -idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) -{ - int l = 0; - int tmp; - - tmp = 0; - if (!signet) { - /* Signal Layer */ - reqbuf->XBuffer.P[l++] = CAI; - reqbuf->XBuffer.P[l++] = 1; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = KEY; - reqbuf->XBuffer.P[l++] = 3; - reqbuf->XBuffer.P[l++] = 'I'; - reqbuf->XBuffer.P[l++] = '4'; - reqbuf->XBuffer.P[l++] = 'L'; - reqbuf->XBuffer.P[l++] = SHIFT|6; - reqbuf->XBuffer.P[l++] = SIN; - reqbuf->XBuffer.P[l++] = 2; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = 0; /* end */ - reqbuf->Req = ASSIGN; - reqbuf->ReqCh = 0; - reqbuf->ReqId = DSIG_ID; - reqbuf->XBuffer.length = l; - reqbuf->Reference = 0; /* Sig Entity */ - } - else { - /* Network Layer */ - reqbuf->XBuffer.P[l++] = CAI; - reqbuf->XBuffer.P[l++] = 1; - reqbuf->XBuffer.P[l++] = chan->e.D3Id; - reqbuf->XBuffer.P[l++] = LLC; - reqbuf->XBuffer.P[l++] = 2; - switch(chan->l2prot) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_TRANS: - reqbuf->XBuffer.P[l++] = 2; /* transparent */ - break; - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - reqbuf->XBuffer.P[l++] = 5; /* X.75 */ - break; - case ISDN_PROTO_L2_MODEM: - if (chan->fsm_state == EICON_STATE_IWAIT) - reqbuf->XBuffer.P[l++] = 9; /* V.42 incoming */ - else - reqbuf->XBuffer.P[l++] = 10; /* V.42 */ - break; - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_FAX: - if (chan->fsm_state == EICON_STATE_IWAIT) - reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */ - else - reqbuf->XBuffer.P[l++] = 2; /* transparent */ - break; - default: - reqbuf->XBuffer.P[l++] = 1; - } - switch(chan->l3prot) { - case ISDN_PROTO_L3_FCLASS2: -#ifdef CONFIG_ISDN_TTY_FAX - reqbuf->XBuffer.P[l++] = 6; - reqbuf->XBuffer.P[l++] = NLC; - tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]); - reqbuf->XBuffer.P[l++] = tmp; - l += tmp; - break; -#endif - case ISDN_PROTO_L3_TRANS: - default: - reqbuf->XBuffer.P[l++] = 4; - } - /* Additional DLC element */ - switch(chan->l2prot) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_FAX: - reqbuf->XBuffer.P[l++] = DLC; - reqbuf->XBuffer.P[l++] = 2; - reqbuf->XBuffer.P[l++] = (2138 % 256); /* max. info (lo byte) */ - reqbuf->XBuffer.P[l++] = (2138 / 256); /* max. info (hi byte) */ - break; - } - reqbuf->XBuffer.P[l++] = 0; /* end */ - reqbuf->Req = ASSIGN; - reqbuf->ReqCh = 0; - reqbuf->ReqId = NL_ID; - reqbuf->XBuffer.length = l; - reqbuf->Reference = 1; /* Net Entity */ - } - return(0); -} - -static int -idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) -{ - reqbuf->Req = rq; - reqbuf->ReqCh = Ch; - reqbuf->ReqId = 1; - reqbuf->XBuffer.length = 1; - reqbuf->XBuffer.P[0] = 0; - reqbuf->Reference = signet; - return(0); -} - -static int -idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) -{ - reqbuf->Req = SUSPEND; - reqbuf->ReqCh = 0; - reqbuf->ReqId = 1; - reqbuf->XBuffer.P[0] = CAI; - reqbuf->XBuffer.P[1] = 1; - reqbuf->XBuffer.P[2] = chan->No; - reqbuf->XBuffer.P[3] = 0; - reqbuf->XBuffer.length = 4; - reqbuf->Reference = 0; /* Sig Entity */ - return(0); -} - -static int -idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) -{ - int l = 9; - reqbuf->Req = CALL_RES; - reqbuf->ReqCh = 0; - reqbuf->ReqId = 1; - reqbuf->XBuffer.P[0] = CAI; - reqbuf->XBuffer.P[1] = 6; - reqbuf->XBuffer.P[2] = 9; - reqbuf->XBuffer.P[3] = 0; - reqbuf->XBuffer.P[4] = 0; - reqbuf->XBuffer.P[5] = 0; - reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 0; - switch(chan->l2prot) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - reqbuf->XBuffer.P[1] = 1; - reqbuf->XBuffer.P[2] = 0x05; - l = 4; - break; - case ISDN_PROTO_L2_V11096: - reqbuf->XBuffer.P[2] = 0x0d; - reqbuf->XBuffer.P[3] = 5; - reqbuf->XBuffer.P[4] = 0; - break; - case ISDN_PROTO_L2_V11019: - reqbuf->XBuffer.P[2] = 0x0d; - reqbuf->XBuffer.P[3] = 6; - reqbuf->XBuffer.P[4] = 0; - break; - case ISDN_PROTO_L2_V11038: - reqbuf->XBuffer.P[2] = 0x0d; - reqbuf->XBuffer.P[3] = 7; - reqbuf->XBuffer.P[4] = 0; - break; - case ISDN_PROTO_L2_MODEM: - /* reqbuf->XBuffer.P[1] = 12; */ - reqbuf->XBuffer.P[2] = 0x11; - reqbuf->XBuffer.P[3] = 9; - reqbuf->XBuffer.P[4] = 0; - reqbuf->XBuffer.P[5] = 0; - reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 0; - break; - case ISDN_PROTO_L2_FAX: - reqbuf->XBuffer.P[2] = 0x10; - reqbuf->XBuffer.P[3] = 0; - reqbuf->XBuffer.P[4] = 0; - reqbuf->XBuffer.P[5] = 0; - reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 0; - break; - case ISDN_PROTO_L2_TRANS: - switch(chan->l3prot) { - case ISDN_PROTO_L3_TRANSDSP: - reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */ - } - break; - } - reqbuf->XBuffer.P[l-1] = 0; - reqbuf->XBuffer.length = l; - reqbuf->Reference = 0; /* Sig Entity */ - eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No); - return(0); -} - -int -idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) -{ - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan_ptr *chan2; - - skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); - eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig"); - if (layer) cmd |= 0x700; - switch(cmd) { - case ASSIGN: - case ASSIGN|0x700: - idi_assign_req(reqbuf, layer, chan); - break; - case REMOVE: - case REMOVE|0x700: - idi_put_req(reqbuf, REMOVE, layer, 0); - break; - case INDICATE_REQ: - idi_put_req(reqbuf, INDICATE_REQ, 0, 0); - break; - case HANGUP: - idi_put_req(reqbuf, HANGUP, 0, 0); - break; - case SUSPEND: - idi_put_suspend_req(reqbuf, chan); - break; - case RESUME: - idi_put_req(reqbuf, RESUME, 0 ,0); - break; - case REJECT: - idi_put_req(reqbuf, REJECT, 0 ,0); - break; - case CALL_ALERT: - idi_put_req(reqbuf, CALL_ALERT, 0, 0); - break; - case CALL_RES: - idi_call_res_req(reqbuf, chan); - break; - case CALL_HOLD: - idi_put_req(reqbuf, CALL_HOLD, 0, 0); - break; - case N_CONNECT|0x700: - idi_put_req(reqbuf, N_CONNECT, 1, 0); - break; - case N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); - break; - case N_DISC|0x700: - idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); - break; - case N_DISC_ACK|0x700: - idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); - break; - default: - eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); - dev_kfree_skb(skb); - dev_kfree_skb(skb2); - return(-1); - } - - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_tx_request(card); - return(0); -} - -int -eicon_idi_listen_req(eicon_card *card, eicon_chan *chan) -{ - if ((!card) || (!chan)) - return 1; - - eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask); - if (!chan->e.D3Id) { - idi_do_req(card, chan, ASSIGN, 0); - } - if (chan->fsm_state == EICON_STATE_NULL) { - if (!(chan->statectrl & HAVE_CONN_REQ)) { - idi_do_req(card, chan, INDICATE_REQ, 0); - chan->fsm_state = EICON_STATE_LISTEN; - } - } - return(0); -} - -static unsigned char -idi_si2bc(int si1, int si2, char *bc, char *hlc) -{ - hlc[0] = 0; - switch(si1) { - case 1: - bc[0] = 0x90; /* 3,1 kHz audio */ - bc[1] = 0x90; /* 64 kbit/s */ - bc[2] = 0xa3; /* G.711 A-law */ -#ifdef EICON_FULL_SERVICE_OKTETT - if (si2 == 1) { - bc[0] = 0x80; /* Speech */ - hlc[0] = 0x02; /* hlc len */ - hlc[1] = 0x91; /* first hic */ - hlc[2] = 0x81; /* Telephony */ - } -#endif - return(3); - case 2: - bc[0] = 0x90; /* 3,1 kHz audio */ - bc[1] = 0x90; /* 64 kbit/s */ - bc[2] = 0xa3; /* G.711 A-law */ -#ifdef EICON_FULL_SERVICE_OKTETT - if (si2 == 2) { - hlc[0] = 0x02; /* hlc len */ - hlc[1] = 0x91; /* first hic */ - hlc[2] = 0x84; /* Fax Gr.2/3 */ - } -#endif - return(3); - case 5: - case 7: - default: - bc[0] = 0x88; - bc[1] = 0x90; - return(2); - } - return (0); -} - -int -idi_hangup(eicon_card *card, eicon_chan *chan) -{ - if ((!card) || (!chan)) - return 1; - - if ((chan->fsm_state == EICON_STATE_ACTIVE) || - (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); - } - if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); - if (chan->fsm_state != EICON_STATE_NULL) { - chan->statectrl |= WAITING_FOR_HANGUP; - idi_do_req(card, chan, HANGUP, 0); - chan->fsm_state = EICON_STATE_NULL; - } - eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No); -#ifdef CONFIG_ISDN_TTY_FAX - chan->fax = 0; -#endif - return(0); -} - -int -capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) -{ - if ((cm->para[0] != 3) || (cm->para[1] != 0)) - return -1; - if (cm->para[2] < 3) - return -1; - if (cm->para[4] != 0) - return -1; - switch(cm->para[3]) { - case 4: /* Suspend */ - eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); - if (cm->para[5]) { - idi_do_req(card, chan, SUSPEND, 0); - } else { - idi_do_req(card, chan, CALL_HOLD, 0); - } - break; - case 5: /* Resume */ - eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); - idi_do_req(card, chan, RESUME, 0); - break; - } - return 0; -} - -int -idi_connect_res(eicon_card *card, eicon_chan *chan) -{ - if ((!card) || (!chan)) - return 1; - - chan->fsm_state = EICON_STATE_IWAIT; - - /* check if old NetID has been removed */ - if (chan->e.B2Id) { - eicon_log(card, 1, "idi_conn_res: Ch%d: old net_id %x still exist, removing.\n", - chan->No, chan->e.B2Id); - idi_do_req(card, chan, REMOVE, 1); - } - - idi_do_req(card, chan, ASSIGN, 1); - idi_do_req(card, chan, CALL_RES, 0); - return(0); -} - -int -idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, - char *eazmsn, int si1, int si2) -{ - int l = 0; - int i; - unsigned char tmp; - unsigned char *sub, *sp; - unsigned char bc[5]; - unsigned char hlc[5]; - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan_ptr *chan2; - - if ((!card) || (!chan)) - return 1; - - skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); - reqbuf->Req = CALL_REQ; - reqbuf->ReqCh = 0; - reqbuf->ReqId = 1; - - sub = NULL; - sp = phone; - while (*sp) { - if (*sp == '.') { - sub = sp + 1; - *sp = 0; - } else - sp++; - } - reqbuf->XBuffer.P[l++] = CPN; - reqbuf->XBuffer.P[l++] = strlen(phone) + 1; - reqbuf->XBuffer.P[l++] = 0x81; - for(i=0; iXBuffer.P[l++] = phone[i] & 0x7f; - if (sub) { - reqbuf->XBuffer.P[l++] = DSA; - reqbuf->XBuffer.P[l++] = strlen(sub) + 2; - reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */ - reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */ - while (*sub) - reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; - } - - sub = NULL; - sp = eazmsn; - while (*sp) { - if (*sp == '.') { - sub = sp + 1; - *sp = 0; - } else - sp++; - } - reqbuf->XBuffer.P[l++] = OAD; - reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2; - reqbuf->XBuffer.P[l++] = 0x01; - reqbuf->XBuffer.P[l++] = 0x80; - for(i=0; iXBuffer.P[l++] = eazmsn[i] & 0x7f; - if (sub) { - reqbuf->XBuffer.P[l++] = OSA; - reqbuf->XBuffer.P[l++] = strlen(sub) + 2; - reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */ - reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */ - while (*sub) - reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; - } - - if (si2 > 2) { - reqbuf->XBuffer.P[l++] = SHIFT|6; - reqbuf->XBuffer.P[l++] = SIN; - reqbuf->XBuffer.P[l++] = 2; - reqbuf->XBuffer.P[l++] = si1; - reqbuf->XBuffer.P[l++] = si2; - } - else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { - reqbuf->XBuffer.P[l++] = BC; - reqbuf->XBuffer.P[l++] = tmp; - for(i=0; iXBuffer.P[l++] = bc[i]; - if ((tmp=hlc[0])) { - reqbuf->XBuffer.P[l++] = HLC; - reqbuf->XBuffer.P[l++] = tmp; - for(i=1; i<=tmp;i++) - reqbuf->XBuffer.P[l++] = hlc[i]; - } - } - - reqbuf->XBuffer.P[l++] = CAI; - reqbuf->XBuffer.P[l++] = 6; - reqbuf->XBuffer.P[l++] = 0x09; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = 0; - reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 0; - switch(chan->l2prot) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - reqbuf->XBuffer.P[l-6] = 5; - reqbuf->XBuffer.P[l-7] = 1; - l -= 5; - break; - case ISDN_PROTO_L2_V11096: - reqbuf->XBuffer.P[l-7] = 3; - reqbuf->XBuffer.P[l-6] = 0x0d; - reqbuf->XBuffer.P[l-5] = 5; - reqbuf->XBuffer.P[l-4] = 0; - l -= 3; - break; - case ISDN_PROTO_L2_V11019: - reqbuf->XBuffer.P[l-7] = 3; - reqbuf->XBuffer.P[l-6] = 0x0d; - reqbuf->XBuffer.P[l-5] = 6; - reqbuf->XBuffer.P[l-4] = 0; - l -= 3; - break; - case ISDN_PROTO_L2_V11038: - reqbuf->XBuffer.P[l-7] = 3; - reqbuf->XBuffer.P[l-6] = 0x0d; - reqbuf->XBuffer.P[l-5] = 7; - reqbuf->XBuffer.P[l-4] = 0; - l -= 3; - break; - case ISDN_PROTO_L2_MODEM: - /* reqbuf->XBuffer.P[l-7] = 12; */ - reqbuf->XBuffer.P[l-6] = 0x11; - reqbuf->XBuffer.P[l-5] = 7; - reqbuf->XBuffer.P[l-4] = 0; - reqbuf->XBuffer.P[l-3] = 0; - reqbuf->XBuffer.P[l-2] = 32; - reqbuf->XBuffer.P[l-1] = 0; - break; - case ISDN_PROTO_L2_FAX: - reqbuf->XBuffer.P[l-6] = 0x10; - reqbuf->XBuffer.P[l-5] = 0; - reqbuf->XBuffer.P[l-4] = 0; - reqbuf->XBuffer.P[l-3] = 0; - reqbuf->XBuffer.P[l-2] = 32; - reqbuf->XBuffer.P[l-1] = 0; - break; - case ISDN_PROTO_L2_TRANS: - switch(chan->l3prot) { - case ISDN_PROTO_L3_TRANSDSP: - reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */ - } - break; - } - - reqbuf->XBuffer.P[l++] = 0; /* end */ - reqbuf->XBuffer.length = l; - reqbuf->Reference = 0; /* Sig Entity */ - - if (chan->statectrl & WAITING_FOR_HANGUP) { - /* If the line did not disconnect yet, - we have to delay this command */ - eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No); - chan->statectrl |= HAVE_CONN_REQ; - chan->tskb1 = skb; - chan->tskb2 = skb2; - } else { - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_tx_request(card); - } - - eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone); - return(0); -} - - -static void -idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsigned char *buffer, int len) -{ - int i,j; - int pos = 0; - int codeset = 0; - int wlen = 0; - int lock = 0; - __u8 w; - __u16 code; - isdn_ctrl cmd; - - memset(message, 0, sizeof(idi_ind_message)); - - if ((!len) || (!buffer[pos])) return; - - while(pos <= len) { - w = buffer[pos++]; - if (!w) return; - if (w & 0x80) { - wlen = 0; - } - else { - wlen = buffer[pos++]; - } - - if (pos > len) return; - - if (lock & 0x80) lock &= 0x7f; - else codeset = lock; - - if((w&0xf0) == SHIFT) { - codeset = w; - if(!(codeset & 0x08)) lock = codeset & 7; - codeset &= 7; - lock |= 0x80; - } - else { - if (w==ESC && wlen >=2) { - code = buffer[pos++]|0x800; - wlen--; - } - else code = w; - code |= (codeset<<8); - - if (pos + wlen > len) { - eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No, - wlen, code, (pos + wlen) - len); - return; - } - - switch(code) { - case OAD: - if (wlen > sizeof(message->oad)) { - pos += wlen; - break; - } - j = 1; - if (wlen) { - message->plan = buffer[pos++]; - if (message->plan &0x80) - message->screen = 0; - else { - message->screen = buffer[pos++]; - j = 2; - } - } - for(i=0; i < wlen-j; i++) - message->oad[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, - message->plan, message->screen, message->oad); - break; - case RDN: - if (wlen > sizeof(message->rdn)) { - pos += wlen; - break; - } - j = 1; - if (wlen) { - if (!(buffer[pos++] & 0x80)) { - pos++; - j = 2; - } - } - for(i=0; i < wlen-j; i++) - message->rdn[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No, - message->rdn); - break; - case CPN: - if (wlen > sizeof(message->cpn)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->cpn[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No, - (__u8)message->cpn[0], message->cpn + 1); - break; - case DSA: - if (wlen > sizeof(message->dsa)) { - pos += wlen; - break; - } - pos += 2; - for(i=0; i < wlen-2; i++) - message->dsa[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa); - break; - case OSA: - if (wlen > sizeof(message->osa)) { - pos += wlen; - break; - } - pos += 2; - for(i=0; i < wlen-2; i++) - message->osa[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa); - break; - case CAD: - pos += wlen; - eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", - chan->No, wlen); - break; - case BC: - if (wlen > sizeof(message->bc)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->bc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No, - message->bc[0],message->bc[1],message->bc[2]); - break; - case 0x800|BC: - if (wlen > sizeof(message->e_bc)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->e_bc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]); - break; - case LLC: - if (wlen > sizeof(message->llc)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], - message->llc[1],message->llc[2],message->llc[3]); - break; - case HLC: - if (wlen > sizeof(message->hlc)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, - message->hlc[0], message->hlc[1], - message->hlc[2], message->hlc[3], message->hlc[4]); - break; - case DSP: - case 0x600|DSP: - if (wlen > sizeof(message->display)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->display[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No, - message->display); - break; - case 0x600|KEY: - if (wlen > sizeof(message->keypad)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->keypad[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No, - message->keypad); - break; - case NI: - case 0x600|NI: - if (wlen) { - switch(buffer[pos] & 127) { - case 0: - eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No); - break; - case 1: - eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No); - break; - case 2: - eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No); - break; - default: - eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n", - chan->No, buffer[pos] & 127); - } - pos += wlen; - } - break; - case PI: - case 0x600|PI: - if (wlen > 1) { - switch(buffer[pos+1] & 127) { - case 1: - eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No); - break; - case 2: - eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No); - break; - case 3: - eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No); - break; - case 4: - eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No); - break; - case 5: - eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No); - break; - case 8: - eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No); - break; - default: - eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n", - chan->No, buffer[pos+1] & 127); - } - } - pos += wlen; - break; - case CAU: - if (wlen > sizeof(message->cau)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->cau[i] = buffer[pos++]; - memcpy(&chan->cause, &message->cau, 2); - eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No, - message->cau[0],message->cau[1]); - break; - case 0x800|CAU: - if (wlen > sizeof(message->e_cau)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->e_cau[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No, - message->e_cau[0],message->e_cau[1]); - break; - case 0x800|CHI: - if (wlen > sizeof(message->e_chi)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->e_chi[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No, - message->e_cau[0]); - break; - case 0x800|0x7a: - pos ++; - message->e_mt=buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt); - break; - case DT: - if (wlen > sizeof(message->dt)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->dt[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No, - message->dt[2], message->dt[1], message->dt[0], - message->dt[3], message->dt[4], message->dt[5]); - break; - case 0x600|SIN: - if (wlen > sizeof(message->sin)) { - pos += wlen; - break; - } - for(i=0; i < wlen; i++) - message->sin[i] = buffer[pos++]; - eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No, - message->sin[0],message->sin[1]); - break; - case 0x600|CPS: - eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No); - pos += wlen; - break; - case 0x600|CIF: - for (i = 0; i < wlen; i++) - if (buffer[pos + i] != '0') break; - memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i); - cmd.parm.num[wlen - i] = 0; - eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num); - pos += wlen; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_CINF; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - break; - case 0x600|DATE: - eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No); - pos += wlen; - break; - case 0xa1: - eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No); - pos += wlen; - break; - case 0xe08: - case 0xe7a: - case 0xe04: - case 0xe00: - /* *** TODO *** */ - case CHA: - /* Charge advice */ - case FTY: - case 0x600|FTY: - case CHI: - case 0x800: - /* Not yet interested in this */ - pos += wlen; - break; - case 0x880: - /* Managment Information Element */ - if (!manbuf) { - eicon_log(ccard, 1, "idi_err: manbuf not allocated\n"); - } - else { - memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen); - manbuf->length[manbuf->count] = wlen; - manbuf->count++; - manbuf->pos += wlen; - } - pos += wlen; - break; - default: - pos += wlen; - eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", - chan->No, code, wlen); - } - } - } -} - -static void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) -{ - si1[0] = 0; - si2[0] = 0; - - switch (bc[0] & 0x7f) { - case 0x00: /* Speech */ - si1[0] = 1; -#ifdef EICON_FULL_SERVICE_OKTETT - si1[0] = sin[0]; - si2[0] = sin[1]; -#endif - break; - case 0x10: /* 3.1 Khz audio */ - si1[0] = 1; -#ifdef EICON_FULL_SERVICE_OKTETT - si1[0] = sin[0]; - si2[0] = sin[1]; -#endif - break; - case 0x08: /* Unrestricted digital information */ - si1[0] = 7; - si2[0] = sin[1]; - break; - case 0x09: /* Restricted digital information */ - si1[0] = 2; - break; - case 0x11: - /* Unrestr. digital information with - * tones/announcements ( or 7 kHz audio - */ - si1[0] = 3; - break; - case 0x18: /* Video */ - si1[0] = 4; - break; - } - switch (bc[1] & 0x7f) { - case 0x40: /* packed mode */ - si1[0] = 8; - break; - case 0x10: /* 64 kbit */ - case 0x11: /* 2*64 kbit */ - case 0x13: /* 384 kbit */ - case 0x15: /* 1536 kbit */ - case 0x17: /* 1920 kbit */ - /* moderate = bc[1] & 0x7f; */ - break; - } -} - -/********************* FAX stuff ***************************/ - -#ifdef CONFIG_ISDN_TTY_FAX - -static int -idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer) -{ - eicon_t30_s *t30 = (eicon_t30_s *) buffer; - - if (!chan->fax) { - eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n"); - return 0; - } - memset(t30, 0, sizeof(eicon_t30_s)); - t30->station_id_len = EICON_FAXID_LEN; - memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN); - t30->resolution = chan->fax->resolution; - t30->rate = chan->fax->rate + 1; /* eicon rate starts with 1 */ - t30->format = T30_FORMAT_SFF; - t30->pages_low = 0; - t30->pages_high = 0; - t30->atf = 1; /* optimised for AT+F command set */ - t30->code = 0; - t30->feature_bits_low = 0; - t30->feature_bits_high = 0; - t30->control_bits_low = 0; - t30->control_bits_high = 0; - - if (chan->fax->nbc) { - /* set compression by DCC value */ - switch(chan->fax->compression) { - case (0): /* 1-D modified */ - break; - case (1): /* 2-D modified Read */ - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING; - t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING; - break; - case (2): /* 2-D uncompressed */ - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING; - t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED; - t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING; - break; - case (3): /* 2-D modified Read */ - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR; - t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED; - t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING; - t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM; - t30->feature_bits_low |= T30_FEATURE_BIT_ECM; - break; - } - } else { - /* set compression to best */ - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR; - t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED; - t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING; - t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING; - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM; - t30->feature_bits_low |= T30_FEATURE_BIT_ECM; - } - switch(chan->fax->ecm) { - case (0): /* disable ECM */ - break; - case (1): - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM; - t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES; - t30->feature_bits_low |= T30_FEATURE_BIT_ECM; - t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES; - break; - case (2): - t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM; - t30->feature_bits_low |= T30_FEATURE_BIT_ECM; - break; - } - - if (DebugVar & 128) { - char st[40]; - eicon_log(NULL, 128, "sT30:code = %x\n", t30->code); - eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate); - eicon_log(NULL, 128, "sT30:res = %x\n", t30->resolution); - eicon_log(NULL, 128, "sT30:format = %x\n", t30->format); - eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low); - eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high); - eicon_log(NULL, 128, "sT30:atf = %x\n", t30->atf); - eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low); - eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high); - eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low); - eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high); - //eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5); - //eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6); - //eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7); - eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len); - eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len); - strlcpy(st, t30->station_id, t30->station_id_len + 1); - eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st); - } - return(sizeof(eicon_t30_s)); -} - -/* send fax struct */ -static int -idi_send_edata(eicon_card *card, eicon_chan *chan) -{ - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan_ptr *chan2; - - if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) { - eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state); - return -ENODEV; - } - eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No); - - skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - - reqbuf->Req = N_EDATA; - reqbuf->ReqCh = chan->e.IndCh; - reqbuf->ReqId = 1; - - reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P); - reqbuf->Reference = 1; /* Net Entity */ - - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_tx_request(card); - return (0); -} - -static void -idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len) -{ - eicon_t30_s *p = (eicon_t30_s *)buffer; - int i; - - if (DebugVar & 128) { - char st[40]; - eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s)); - eicon_log(ccard, 128, "rT30:code = %x\n", p->code); - eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate); - eicon_log(ccard, 128, "rT30:res = %x\n", p->resolution); - eicon_log(ccard, 128, "rT30:format = %x\n", p->format); - eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low); - eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high); - eicon_log(ccard, 128, "rT30:atf = %x\n", p->atf); - eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low); - eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high); - eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low); - eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high); - //eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5); - //eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6); - //eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7); - eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len); - eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len); - strlcpy(st, p->station_id, p->station_id_len + 1); - eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st); - } - if (!chan->fax) { - eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n"); - return; - } - chan->fax->code = p->code; - i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1); - memcpy(chan->fax->r_id, p->station_id, i); - chan->fax->r_id[i] = 0; - chan->fax->r_resolution = p->resolution; - chan->fax->r_rate = p->rate - 1; - chan->fax->r_binary = 0; /* no binary support */ - chan->fax->r_width = 0; - chan->fax->r_length = 2; - chan->fax->r_scantime = 0; - chan->fax->r_compression = 0; - chan->fax->r_ecm = 0; - if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) { - chan->fax->r_compression = 1; - if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) { - chan->fax->r_compression = 2; - } - } - if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) { - chan->fax->r_compression = 3; - } - - if (p->feature_bits_low & T30_FEATURE_BIT_ECM) { - chan->fax->r_ecm = 2; - if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES) - chan->fax->r_ecm = 1; - } -} - -static void -idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header) -{ - static __u16 wd2sff[] = { - 1728, 2048, 2432, 1216, 864 - }; - static __u16 ln2sff[2][3] = { - { 1143, 1401, 0 } , { 2287, 2802, 0 } - }; - struct sk_buff *skb; - eicon_sff_dochead *doc; - eicon_sff_pagehead *page; - u_char *docp; - - if (!chan->fax) { - eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n"); - return; - } - if (header == 2) { /* DocHeader + PageHeader */ - skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC); - } else { - skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC); - } - if (!skb) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No); - return; - } - - if (header == 2) { /* DocHeader + PageHeader */ - docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead)); - doc = (eicon_sff_dochead *) docp; - page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead)); - memset(docp, 0,sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead)); - doc->id = 0x66666653; - doc->version = 0x01; - doc->off1pagehead = sizeof(eicon_sff_dochead); - } else { - page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead)); - memset(page, 0, sizeof(eicon_sff_pagehead)); - } - - switch(header) { - case 1: /* PageHeaderEnd */ - page->pageheadid = 254; - page->pageheadlen = 0; - break; - case 0: /* PageHeader */ - case 2: /* DocHeader + PageHeader */ - page->pageheadid = 254; - page->pageheadlen = sizeof(eicon_sff_pagehead) - 2; - page->resvert = chan->fax->resolution; - page->reshoriz = 0; /* always 203 dpi */ - page->coding = 0; /* always 1D */ - page->linelength = wd2sff[chan->fax->width]; - page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length]; - eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength); - eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); - break; - } - idi_send_data(card, chan, 0, skb, 0, 0); -} - -void -idi_fax_cmd(eicon_card *card, eicon_chan *chan) -{ - isdn_ctrl cmd; - - if ((!card) || (!chan)) - return; - - if (!chan->fax) { - eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n"); - return; - } - switch (chan->fax->code) { - case ISDN_TTY_FAX_DT: - if (chan->fax->phase == ISDN_FAX_PHASE_B) { - idi_send_edata(card, chan); - break; - } - if (chan->fax->phase == ISDN_FAX_PHASE_D) { - idi_send_edata(card, chan); - break; - } - break; - - case ISDN_TTY_FAX_DR: - if (chan->fax->phase == ISDN_FAX_PHASE_B) { - idi_send_edata(card, chan); - - cmd.driver = card->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_CFR; - card->interface.statcallb(&cmd); - - cmd.driver = card->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_RID; - card->interface.statcallb(&cmd); - - /* telling 1-D compression */ - chan->fax->r_compression = 0; - cmd.driver = card->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_DCS; - card->interface.statcallb(&cmd); - - chan->fax2.NextObject = FAX_OBJECT_DOCU; - chan->fax2.PrevObject = FAX_OBJECT_DOCU; - - break; - } - if (chan->fax->phase == ISDN_FAX_PHASE_D) { - idi_send_edata(card, chan); - break; - } - break; - - case ISDN_TTY_FAX_ET: - switch(chan->fax->fet) { - case 0: - case 1: - idi_fax_send_header(card, chan, 0); - break; - case 2: - idi_fax_send_header(card, chan, 1); - break; - } - break; - } -} - -static void -idi_edata_rcveop(eicon_card *card, eicon_chan *chan) -{ - isdn_ctrl cmd; - - if (!chan->fax) { - eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n"); - return; - } - cmd.driver = card->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_ET; - card->interface.statcallb(&cmd); -} - -static void -idi_reset_fax_stat(eicon_chan *chan) -{ - chan->fax2.LineLen = 0; - chan->fax2.LineData = 0; - chan->fax2.LineDataLen = 0; - chan->fax2.NullByteExist = 0; - chan->fax2.Dle = 0; - chan->fax2.PageCount = 0; - chan->fax2.Eop = 0; -} - -static void -idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) -{ - isdn_ctrl cmd; - - if (!chan->fax) { - eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n"); - return; - } - if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) { - idi_parse_edata(ccard, chan, buffer, len); - - if (chan->fax->phase == ISDN_FAX_PHASE_A) { - idi_reset_fax_stat(chan); - - chan->fsm_state = EICON_STATE_ACTIVE; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BCONN; - cmd.arg = chan->No; - strcpy(cmd.parm.num, ""); - ccard->interface.statcallb(&cmd); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_FCON; - ccard->interface.statcallb(&cmd); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_RID; - ccard->interface.statcallb(&cmd); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_DIS; - ccard->interface.statcallb(&cmd); - - if (chan->fax->r_compression != 0) { - /* telling fake compression in second DIS message */ - chan->fax->r_compression = 0; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_DIS; - ccard->interface.statcallb(&cmd); - } - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */ - ccard->interface.statcallb(&cmd); - } else - if (chan->fax->phase == ISDN_FAX_PHASE_D) { - - if ((chan->fax->code == EDATA_T30_MCF) && - (chan->fax->fet != 2)) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_PTS; - ccard->interface.statcallb(&cmd); - } - - switch(chan->fax->fet) { - case 0: /* new page */ - /* stay in phase D , wait on cmd +FDT */ - break; - case 1: /* new document */ - /* link-level switch to phase B */ - break; - case 2: /* session end */ - default: - /* send_edata produces error on some */ - /* fax-machines here, so we don't */ - /* idi_send_edata(ccard, chan); */ - break; - } - } - } - - if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) { - idi_parse_edata(ccard, chan, buffer, len); - - if ((chan->fax->code == EDATA_T30_DCS) && - (chan->fax->phase == ISDN_FAX_PHASE_A)) { - idi_reset_fax_stat(chan); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BCONN; - cmd.arg = chan->No; - strcpy(cmd.parm.num, ""); - ccard->interface.statcallb(&cmd); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_FCON_I; - ccard->interface.statcallb(&cmd); - } else - if ((chan->fax->code == EDATA_T30_TRAIN_OK) && - (chan->fax->phase == ISDN_FAX_PHASE_A)) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_RID; - ccard->interface.statcallb(&cmd); - - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK; - ccard->interface.statcallb(&cmd); - } else - if ((chan->fax->code == EDATA_T30_TRAIN_OK) && - (chan->fax->phase == ISDN_FAX_PHASE_B)) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK; - ccard->interface.statcallb(&cmd); - } else - if (chan->fax->phase == ISDN_FAX_PHASE_C) { - switch(chan->fax->code) { - case EDATA_T30_TRAIN_OK: - idi_send_edata(ccard, chan); - break; - case EDATA_T30_MPS: - chan->fax->fet = 0; - idi_edata_rcveop(ccard, chan); - break; - case EDATA_T30_EOM: - chan->fax->fet = 1; - idi_edata_rcveop(ccard, chan); - break; - case EDATA_T30_EOP: - chan->fax->fet = 2; - idi_edata_rcveop(ccard, chan); - break; - } - } - } -} - -static void -fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len) -{ - struct sk_buff *skb; - - skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC); - if (!skb) { - eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No); - return; - } - skb_reserve(skb, MAX_HEADER_LEN); - memcpy(skb_put(skb, len), Data, len); - ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb); -} - -static void -idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) -{ - eicon_OBJBUFFER InBuf; - eicon_OBJBUFFER LineBuf; - unsigned int Length = 0; - unsigned int aLength = 0; - unsigned int ObjectSize = 0; - unsigned int ObjHeadLen = 0; - unsigned int ObjDataLen = 0; - __u8 Recordtype; - __u8 PageHeaderLen; - __u8 Event; - eicon_sff_pagehead *ob_page; - - __u16 Cl2Eol = 0x8000; - -# define EVENT_NONE 0 -# define EVENT_NEEDDATA 1 - - if (!chan->fax) { - eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n"); - return; - } - - - - if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) { - InBuf.Data = skb->data; - InBuf.Size = skb->len; - InBuf.Len = 0; - InBuf.Next = InBuf.Data; - LineBuf.Data = chan->fax2.abLine; - LineBuf.Size = sizeof(chan->fax2.abLine); - LineBuf.Len = chan->fax2.LineLen; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - - Event = EVENT_NONE; - while (Event == EVENT_NONE) { - switch(chan->fax2.NextObject) { - case FAX_OBJECT_DOCU: - Length = LineBuf.Len + (InBuf.Size - InBuf.Len); - if (Length < sizeof(eicon_sff_dochead)) { - Event = EVENT_NEEDDATA; - break; - } - ObjectSize = sizeof(eicon_sff_dochead); - Length = ObjectSize; - if (LineBuf.Len < Length) { - Length -= LineBuf.Len; - LineBuf.Len = 0; - LineBuf.Next = LineBuf.Data; - InBuf.Len += Length; - InBuf.Next += Length; - } else { - LineBuf.Len -= Length; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len); - } - chan->fax2.PrevObject = FAX_OBJECT_DOCU; - chan->fax2.NextObject = FAX_OBJECT_PAGE; - break; - - case FAX_OBJECT_PAGE: - Length = LineBuf.Len + (InBuf.Size - InBuf.Len); - if (Length < 2) { - Event = EVENT_NEEDDATA; - break; - } - if (LineBuf.Len == 0) { - *LineBuf.Next++ = *InBuf.Next++; - LineBuf.Len++; - InBuf.Len++; - } - if (LineBuf.Len == 1) { - *LineBuf.Next++ = *InBuf.Next++; - LineBuf.Len++; - InBuf.Len++; - } - PageHeaderLen = *(LineBuf.Data + 1); - ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead); - if (Length < ObjectSize) { - Event = EVENT_NEEDDATA; - break; - } - Length = ObjectSize; - /* extract page dimensions */ - if (LineBuf.Len < Length) { - aLength = Length - LineBuf.Len; - memcpy(LineBuf.Next, InBuf.Next, aLength); - LineBuf.Next += aLength; - InBuf.Next += aLength; - LineBuf.Len += aLength; - InBuf.Len += aLength; - } - if (Length > 2) { - ob_page = (eicon_sff_pagehead *)LineBuf.Data; - switch(ob_page->linelength) { - case 2048: - chan->fax->r_width = 1; - break; - case 2432: - chan->fax->r_width = 2; - break; - case 1216: - chan->fax->r_width = 3; - break; - case 864: - chan->fax->r_width = 4; - break; - case 1728: - default: - chan->fax->r_width = 0; - } - switch(ob_page->pagelength) { - case 1143: - case 2287: - chan->fax->r_length = 0; - break; - case 1401: - case 2802: - chan->fax->r_length = 1; - break; - default: - chan->fax->r_length = 2; - } - eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength); - eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength); - } - LineBuf.Len -= Length; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len); - - chan->fax2.PrevObject = FAX_OBJECT_PAGE; - chan->fax2.NextObject = FAX_OBJECT_LINE; - break; - - case FAX_OBJECT_LINE: - Length = LineBuf.Len + (InBuf.Size - InBuf.Len); - if (Length < 1) { - Event = EVENT_NEEDDATA; - break; - } - if (LineBuf.Len == 0) { - *LineBuf.Next++ = *InBuf.Next++; - LineBuf.Len++; - InBuf.Len++; - } - Recordtype = *LineBuf.Data; - if (Recordtype == 0) { - /* recordtype pixel row (2 byte length) */ - ObjHeadLen = 3; - if (Length < ObjHeadLen) { - Event = EVENT_NEEDDATA; - break; - } - while (LineBuf.Len < ObjHeadLen) { - *LineBuf.Next++ = *InBuf.Next++; - LineBuf.Len++; - InBuf.Len++; - } - ObjDataLen = *((__u16*) (LineBuf.Data + 1)); - ObjectSize = ObjHeadLen + ObjDataLen; - if (Length < ObjectSize) { - Event = EVENT_NEEDDATA; - break; - } - } else - if ((Recordtype >= 1) && (Recordtype <= 216)) { - /* recordtype pixel row (1 byte length) */ - ObjHeadLen = 1; - ObjDataLen = Recordtype; - ObjectSize = ObjHeadLen + ObjDataLen; - if (Length < ObjectSize) { - Event = EVENT_NEEDDATA; - break; - } - } else - if ((Recordtype >= 217) && (Recordtype <= 253)) { - /* recordtype empty lines */ - ObjHeadLen = 1; - ObjDataLen = 0; - ObjectSize = ObjHeadLen + ObjDataLen; - LineBuf.Len--; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len); - break; - } else - if (Recordtype == 254) { - /* recordtype page header */ - chan->fax2.PrevObject = FAX_OBJECT_LINE; - chan->fax2.NextObject = FAX_OBJECT_PAGE; - break; - } else { - /* recordtype user information */ - ObjHeadLen = 2; - if (Length < ObjHeadLen) { - Event = EVENT_NEEDDATA; - break; - } - while (LineBuf.Len < ObjHeadLen) { - *LineBuf.Next++ = *InBuf.Next++; - LineBuf.Len++; - InBuf.Len++; - } - ObjDataLen = *(LineBuf.Data + 1); - ObjectSize = ObjHeadLen + ObjDataLen; - if (ObjDataLen == 0) { - /* illegal line coding */ - LineBuf.Len -= ObjHeadLen; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len); - break; - } else { - /* user information */ - if (Length < ObjectSize) { - Event = EVENT_NEEDDATA; - break; - } - Length = ObjectSize; - if (LineBuf.Len < Length) { - Length -= LineBuf.Len; - LineBuf.Len = 0; - LineBuf.Next = LineBuf.Data; - InBuf.Len += Length; - InBuf.Next += Length; - } else { - LineBuf.Len -= Length; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len); - } - } - break; - } - Length = ObjectSize; - if (LineBuf.Len > ObjHeadLen) { - fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen, - (LineBuf.Len - ObjHeadLen)); - } - Length -= LineBuf.Len; - LineBuf.Len = 0; - LineBuf.Next = LineBuf.Data; - if (Length > 0) { - fax_put_rcv(ccard, chan, InBuf.Next, Length); - InBuf.Len += Length; - InBuf.Next += Length; - } - fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol)); - break; - } /* end of switch (chan->fax2.NextObject) */ - } /* end of while (Event==EVENT_NONE) */ - if (InBuf.Len < InBuf.Size) { - Length = InBuf.Size - InBuf.Len; - if ((LineBuf.Len + Length) > LineBuf.Size) { - eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No, - Length); - } else { - memcpy(LineBuf.Next, InBuf.Next, Length); - LineBuf.Len += Length; - } - } - chan->fax2.LineLen = LineBuf.Len; - } else { /* CONN_OUT */ - /* On CONN_OUT we do not need incoming data, drop it */ - /* maybe later for polling */ - } - -# undef EVENT_NONE -# undef EVENT_NEEDDATA - - return; -} - -static int -idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf) -{ - struct sk_buff *skb; - - skb = alloc_skb(OutBuf->Len, GFP_ATOMIC); - if (!skb) { - eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No); - return(-1); - } - memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len); - - OutBuf->Len = 0; - OutBuf->Next = OutBuf->Data; - - return(idi_send_data(ccard, chan, 0, skb, 1, 0)); -} - -int -idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) -{ - isdn_ctrl cmd; - eicon_OBJBUFFER InBuf; - __u8 InData; - __u8 InMask; - eicon_OBJBUFFER OutBuf; - eicon_OBJBUFFER LineBuf; - __u32 LineData; - unsigned int LineDataLen; - __u8 Byte; - __u8 Event; - int ret = 1; - -# define EVENT_NONE 0 -# define EVENT_EOD 1 -# define EVENT_EOL 2 -# define EVENT_EOP 3 - - if ((!ccard) || (!chan)) - return -1; - - if (!chan->fax) { - eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n"); - return -1; - } - - if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) { - /* Simply ignore any data written in data mode when receiving a fax. */ - /* This is not completely correct because only XON's should come here. */ - dev_kfree_skb(skb); - return 1; - } - - if (chan->fax->phase != ISDN_FAX_PHASE_C) { - dev_kfree_skb(skb); - return 1; - } - - if (chan->queued + skb->len > 1200) - return 0; - if (chan->pqueued > 1) - return 0; - - InBuf.Data = skb->data; - InBuf.Size = skb->len; - InBuf.Len = 0; - InBuf.Next = InBuf.Data; - InData = 0; - InMask = 0; - - LineBuf.Data = chan->fax2.abLine; - LineBuf.Size = sizeof(chan->fax2.abLine); - LineBuf.Len = chan->fax2.LineLen; - LineBuf.Next = LineBuf.Data + LineBuf.Len; - LineData = chan->fax2.LineData; - LineDataLen = chan->fax2.LineDataLen; - - OutBuf.Data = chan->fax2.abFrame; - OutBuf.Size = sizeof(chan->fax2.abFrame); - OutBuf.Len = 0; - OutBuf.Next = OutBuf.Data; - - Event = EVENT_NONE; - - chan->fax2.Eop = 0; - - for (;;) { - for (;;) { - if (InMask == 0) { - if (InBuf.Len >= InBuf.Size) { - Event = EVENT_EOD; - break; - } - if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) { - chan->fax2.Dle = _DLE_; - InBuf.Next++; - InBuf.Len++; - if (InBuf.Len >= InBuf.Size) { - Event = EVENT_EOD; - break; - } - } - if (chan->fax2.Dle == _DLE_) { - chan->fax2.Dle = 0; - if (*InBuf.Next == _ETX_) { - Event = EVENT_EOP; - break; - } else - if (*InBuf.Next == _DLE_) { - /* do nothing */ - } else { - eicon_log(ccard, 1, - "idi_err: Ch%d: unknown DLE escape %02x found\n", - chan->No, *InBuf.Next); - InBuf.Next++; - InBuf.Len++; - if (InBuf.Len >= InBuf.Size) { - Event = EVENT_EOD; - break; - } - } - } - InBuf.Len++; - InData = *InBuf.Next++; - InMask = (chan->fax->bor) ? 0x80 : 0x01; - } - while (InMask) { - LineData >>= 1; - LineDataLen++; - if (InData & InMask) - LineData |= 0x80000000; - if (chan->fax->bor) - InMask >>= 1; - else - InMask <<= 1; - - if ((LineDataLen >= T4_EOL_BITSIZE) && - ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) { - Event = EVENT_EOL; - if (LineDataLen > T4_EOL_BITSIZE) { - Byte = (__u8) - ((LineData & ~T4_EOL_MASK_DWORD) >> - (32 - LineDataLen)); - if (Byte == 0) { - if (! chan->fax2.NullByteExist) { - chan->fax2.NullBytesPos = LineBuf.Len; - chan->fax2.NullByteExist = 1; - } - } else { - chan->fax2.NullByteExist = 0; - } - if (LineBuf.Len < LineBuf.Size) { - *LineBuf.Next++ = Byte; - LineBuf.Len++; - } - } - LineDataLen = 0; - break; - } - if (LineDataLen >= T4_EOL_BITSIZE + 8) { - Byte = (__u8) - ((LineData & ~T4_EOL_MASK_DWORD) >> - (32 - T4_EOL_BITSIZE - 8)); - LineData &= T4_EOL_MASK_DWORD; - LineDataLen = T4_EOL_BITSIZE; - if (Byte == 0) { - if (! chan->fax2.NullByteExist) { - chan->fax2.NullBytesPos = LineBuf.Len; - chan->fax2.NullByteExist = 1; - } - } else { - chan->fax2.NullByteExist = 0; - } - if (LineBuf.Len < LineBuf.Size) { - *LineBuf.Next++ = Byte; - LineBuf.Len++; - } - } - } - if (Event != EVENT_NONE) - break; - } - - if ((Event != EVENT_EOL) && (Event != EVENT_EOP)) - break; - - if ((Event == EVENT_EOP) && (LineDataLen > 0)) { - LineData >>= 32 - LineDataLen; - LineDataLen = 0; - while (LineData != 0) { - Byte = (__u8) LineData; - LineData >>= 8; - if (Byte == 0) { - if (! chan->fax2.NullByteExist) { - chan->fax2.NullBytesPos = LineBuf.Len; - chan->fax2.NullByteExist = 1; - } - } else { - chan->fax2.NullByteExist = 0; - } - if (LineBuf.Len < LineBuf.Size) { - *LineBuf.Next++ = Byte; - LineBuf.Len++; - } - - } - } - if (chan->fax2.NullByteExist) { - if (chan->fax2.NullBytesPos == 0) { - LineBuf.Len = 0; - } else { - LineBuf.Len = chan->fax2.NullBytesPos + 1; - } - } - if (LineBuf.Len > 0) { - if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) { - ret = idi_fax_send_outbuf(ccard, chan, &OutBuf); - } - if (LineBuf.Len <= 216) { - *OutBuf.Next++ = (__u8) LineBuf.Len; - OutBuf.Len++; - } else { - *OutBuf.Next++ = 0; - *((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len; - OutBuf.Len += 3; - } - memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len); - OutBuf.Next += LineBuf.Len; - OutBuf.Len += LineBuf.Len; - } - LineBuf.Len = 0; - LineBuf.Next = LineBuf.Data; - chan->fax2.NullByteExist = 0; - if (Event == EVENT_EOP) - break; - - Event = EVENT_NONE; - } - - if (Event == EVENT_EOP) { - chan->fax2.Eop = 1; - chan->fax2.PageCount++; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_EOP; - ccard->interface.statcallb(&cmd); - } - if (OutBuf.Len > 0) { - ret = idi_fax_send_outbuf(ccard, chan, &OutBuf); - } - - chan->fax2.LineLen = LineBuf.Len; - chan->fax2.LineData = LineData; - chan->fax2.LineDataLen = LineDataLen; - -# undef EVENT_NONE -# undef EVENT_EOD -# undef EVENT_EOL -# undef EVENT_EOP - - if (ret >= 0) - dev_kfree_skb(skb); - if (ret == 0) - ret = 1; - return(ret); -} - -static void -idi_fax_hangup(eicon_card *ccard, eicon_chan *chan) -{ - isdn_ctrl cmd; - - if (!chan->fax) { - eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n"); - return; - } - if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) && - (chan->fax->code == 0)) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_PTS; - ccard->interface.statcallb(&cmd); - } - if ((chan->fax->code > 1) && (chan->fax->code < 120)) - chan->fax->code += 120; - eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); - chan->fax->r_code = ISDN_TTY_FAX_HNG; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); -} - -#endif /******** FAX ********/ - -static int -idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len) -{ - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan_ptr *chan2; - - if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) { - eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state); - return -ENODEV; - } - eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No, - UReq, buffer[0], buffer[1], buffer[2], buffer[3]); - - skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - - reqbuf->Req = N_UDATA; - reqbuf->ReqCh = chan->e.IndCh; - reqbuf->ReqId = 1; - - reqbuf->XBuffer.length = len + 1; - reqbuf->XBuffer.P[0] = UReq; - memcpy(&reqbuf->XBuffer.P[1], buffer, len); - reqbuf->Reference = 1; /* Net Entity */ - - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_tx_request(card); - return (0); -} - -void -idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value) -{ - u_char buf[6]; - struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf; - - if ((!ccard) || (!chan)) - return; - - memset(buf, 0, 6); - switch(cmd) { - case ISDN_AUDIO_SETDD: - if (value[0]) { - dtmf_buf->tone = (__u16) (value[1] * 5); - dtmf_buf->gap = (__u16) (value[1] * 5); - idi_send_udata(ccard, chan, - DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER, - buf, 4); - } else { - idi_send_udata(ccard, chan, - DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER, - buf, 0); - } - break; - } -} - -static void -idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len) -{ - isdn_ctrl cmd; - eicon_dsp_ind *p = (eicon_dsp_ind *) (&buffer[1]); - static char *connmsg[] = - {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34", - "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90", - "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex", - "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL", - "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110", - "Baudot45", "Baudot47", "Baudot50", "DTMF" }; - static u_char dtmf_code[] = { - '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D' - }; - - if ((!ccard) || (!chan)) - return; - - switch (buffer[0]) { - case DSP_UDATA_INDICATION_SYNC: - eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time); - break; - case DSP_UDATA_INDICATION_DCD_OFF: - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time); - break; - case DSP_UDATA_INDICATION_DCD_ON: - if ((chan->l2prot == ISDN_PROTO_L2_MODEM) && - ((chan->fsm_state == EICON_STATE_IBWAIT) || - (chan->fsm_state == EICON_STATE_WMCONN))) { - chan->fsm_state = EICON_STATE_ACTIVE; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BCONN; - cmd.arg = chan->No; - if (p->norm > 34) { - sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm); - } else { - sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); - } - ccard->interface.statcallb(&cmd); - } - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time); - eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No, - p->norm, p->options, p->speed, p->delay); - break; - case DSP_UDATA_INDICATION_CTS_OFF: - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time); - break; - case DSP_UDATA_INDICATION_CTS_ON: - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time); - eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No, - p->norm, p->options, p->speed, p->delay); - break; - case DSP_UDATA_INDICATION_DISCONNECT: - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]); - break; - case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED: - eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No, - dtmf_code[buffer[1]]); - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_AUDIO; - cmd.parm.num[0] = ISDN_AUDIO_DTMF; - cmd.parm.num[1] = dtmf_code[buffer[1]]; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - break; - default: - eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]); - } -} - -static void -eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len) -{ - int i,j,n; - int buflen = len * 3 + 30; - char *p; - struct trace_s { - unsigned long time; - unsigned short size; - unsigned short code; - unsigned char data[1]; - } *q; - - if (!(p = kmalloc(buflen, GFP_ATOMIC))) { - eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); - return; - } - memset(p, 0, buflen); - q = (struct trace_s *)buffer; - - if (DebugVar & 512) { - if ((q->code == 3) || (q->code == 4)) { - n = (short) *(q->data); - if (n) { - j = sprintf(p, "DTRC:"); - for (i = 0; i < n; i++) { - j += sprintf(p + j, "%02x ", q->data[i+2]); - } - j += sprintf(p + j, "\n"); - } - } - } else { - j = sprintf(p, "XLOG: %lx %04x %04x ", - q->time, q->size, q->code); - - for (i = 0; i < q->size; i++) { - j += sprintf(p + j, "%02x ", q->data[i]); - } - j += sprintf(p + j, "\n"); - } - if (strlen(p)) - eicon_putstatus(ccard, p); - kfree(p); -} - -void -idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) -{ - int tmp; - char tnum[64]; - int dlev; - int free_buff; - eicon_IND *ind = (eicon_IND *)skb->data; - eicon_chan *chan; - idi_ind_message message; - isdn_ctrl cmd; - - if (!ccard) { - eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n"); - dev_kfree_skb(skb); - return; - } - - if ((chan = ccard->IdTable[ind->IndId]) == NULL) { - eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n"); - dev_kfree_skb(skb); - return; - } - - if ((ind->Ind != 8) && (ind->Ind != 0xc)) - dlev = 144; - else - dlev = 128; - - eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No, - ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); - - free_buff = 1; - /* Signal Layer */ - if (chan->e.D3Id == ind->IndId) { - idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); - switch(ind->Ind) { - case HANGUP: - eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No); - skb_queue_purge(&chan->e.X); - chan->queued = 0; - chan->pqueued = 0; - chan->waitq = 0; - chan->waitpq = 0; - if (message.e_cau[0] & 0x7f) { - cmd.driver = ccard->myid; - cmd.arg = chan->No; - sprintf(cmd.parm.num,"E%02x%02x", - chan->cause[0]&0x7f, message.e_cau[0]&0x7f); - cmd.command = ISDN_STAT_CAUSE; - ccard->interface.statcallb(&cmd); - } - chan->cause[0] = 0; - if ((chan->fsm_state == EICON_STATE_ACTIVE) || - ((chan->l2prot == ISDN_PROTO_L2_FAX) && - (chan->fsm_state == EICON_STATE_OBWAIT))) { - chan->fsm_state = EICON_STATE_NULL; - } else { - if (chan->e.B2Id) - idi_do_req(ccard, chan, REMOVE, 1); - chan->statectrl &= ~WAITING_FOR_HANGUP; - chan->statectrl &= ~IN_HOLD; - if (chan->statectrl & HAVE_CONN_REQ) { - eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); - chan->statectrl &= ~HAVE_CONN_REQ; - if ((chan->tskb1) && (chan->tskb2)) { - skb_queue_tail(&chan->e.X, chan->tskb1); - skb_queue_tail(&ccard->sndq, chan->tskb2); - } - chan->tskb1 = NULL; - chan->tskb2 = NULL; - } else { - chan->fsm_state = EICON_STATE_NULL; - cmd.driver = ccard->myid; - cmd.arg = chan->No; - cmd.command = ISDN_STAT_DHUP; - ccard->interface.statcallb(&cmd); - eicon_idi_listen_req(ccard, chan); -#ifdef CONFIG_ISDN_TTY_FAX - chan->fax = 0; -#endif - } - } - break; - case INDICATE_IND: - eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No); - if (chan->fsm_state != EICON_STATE_LISTEN) { - eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n", - chan->No, chan->fsm_state); - idi_do_req(ccard, chan, HANGUP, 0); - break; - } - chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); - strcpy(chan->cpn, message.cpn + 1); - strcpy(chan->oad, message.oad); - strcpy(chan->dsa, message.dsa); - strcpy(chan->osa, message.osa); - chan->plan = message.plan; - chan->screen = message.screen; - try_stat_icall_again: - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_ICALL; - cmd.arg = chan->No; - cmd.parm.setup.si1 = chan->si1; - cmd.parm.setup.si2 = chan->si2; - strcpy(tnum, chan->cpn); - if (strlen(chan->dsa)) { - strcat(tnum, "."); - strcat(tnum, chan->dsa); - } - tnum[ISDN_MSNLEN - 1] = 0; - strcpy(cmd.parm.setup.eazmsn, tnum); - strcpy(tnum, chan->oad); - if (strlen(chan->osa)) { - strcat(tnum, "."); - strcat(tnum, chan->osa); - } - tnum[ISDN_MSNLEN - 1] = 0; - strcpy(cmd.parm.setup.phone, tnum); - cmd.parm.setup.plan = chan->plan; - cmd.parm.setup.screen = chan->screen; - tmp = ccard->interface.statcallb(&cmd); - switch(tmp) { - case 0: /* no user responding */ - idi_do_req(ccard, chan, HANGUP, 0); - chan->fsm_state = EICON_STATE_NULL; - break; - case 1: /* alert */ - eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No); - if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) { - chan->fsm_state = EICON_STATE_ICALL; - idi_do_req(ccard, chan, CALL_ALERT, 0); - } - break; - case 2: /* reject */ - eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No); - idi_do_req(ccard, chan, REJECT, 0); - break; - case 3: /* incomplete number */ - eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No); - chan->fsm_state = EICON_STATE_ICALLW; - break; - } - break; - case INFO_IND: - eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No); - if ((chan->fsm_state == EICON_STATE_ICALLW) && - (message.cpn[0])) { - strcat(chan->cpn, message.cpn + 1); - goto try_stat_icall_again; - } - break; - case CALL_IND: - eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No); - if ((chan->fsm_state == EICON_STATE_ICALL) || - (chan->fsm_state == EICON_STATE_WMCONN) || - (chan->fsm_state == EICON_STATE_IWAIT)) { - chan->fsm_state = EICON_STATE_IBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - switch(chan->l2prot) { - case ISDN_PROTO_L2_FAX: -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->fax) - chan->fax->phase = ISDN_FAX_PHASE_A; -#endif - break; - case ISDN_PROTO_L2_MODEM: - /* do nothing, wait for connect */ - break; - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, N_CONNECT, 1); - break; - default: - /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, N_CONNECT, 1); */ - break; - } - } else { - if (chan->fsm_state != EICON_STATE_ACTIVE) - idi_hangup(ccard, chan); - } - break; - case CALL_CON: - eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); - if (chan->fsm_state == EICON_STATE_OCALL) { - /* check if old NetID has been removed */ - if (chan->e.B2Id) { - eicon_log(ccard, 1, "idi_ind: Ch%d: old net_id %x still exist, removing.\n", - chan->No, chan->e.B2Id); - idi_do_req(ccard, chan, REMOVE, 1); - } -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (chan->fax) { - chan->fax->phase = ISDN_FAX_PHASE_A; - } else { - eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); - idi_hangup(ccard, chan); - break; - } - } -#endif - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - - idi_do_req(ccard, chan, ASSIGN, 1); - idi_do_req(ccard, chan, N_CONNECT, 1); - } else - idi_hangup(ccard, chan); - break; - case AOC_IND: - eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); - break; - case CALL_HOLD_ACK: - chan->statectrl |= IN_HOLD; - eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); - break; - case SUSPEND_REJ: - eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); - break; - case SUSPEND: - eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); - break; - case RESUME: - eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); - break; - default: - eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); - } - } - /* Network Layer */ - else if (chan->e.B2Id == ind->IndId) { - - if (chan->No == ccard->nchannels) { - /* Management Indication */ - if (ind->Ind == 0x04) { /* Trace_Ind */ - eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length); - } else { - idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); - chan->fsm_state = 1; - } - } - else - switch(ind->Ind) { - case N_CONNECT_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); - if (chan->l2prot == ISDN_PROTO_L2_MODEM) { - chan->fsm_state = EICON_STATE_WMCONN; - break; - } - if (chan->l2prot == ISDN_PROTO_L2_FAX) { -#ifdef CONFIG_ISDN_TTY_FAX - chan->fsm_state = EICON_STATE_ACTIVE; - idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); - if (chan->fax) { - if (chan->fax->phase == ISDN_FAX_PHASE_B) { - idi_fax_send_header(ccard, chan, 2); - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_DCS; - ccard->interface.statcallb(&cmd); - } - } - else { - eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); - } -#endif - break; - } - chan->fsm_state = EICON_STATE_ACTIVE; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BCONN; - cmd.arg = chan->No; - strcpy(cmd.parm.num, "64000"); - ccard->interface.statcallb(&cmd); - break; - case N_CONNECT: - eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); - chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); - if (chan->l2prot == ISDN_PROTO_L2_FAX) { - break; - } - if (chan->l2prot == ISDN_PROTO_L2_MODEM) { - chan->fsm_state = EICON_STATE_WMCONN; - break; - } - chan->fsm_state = EICON_STATE_ACTIVE; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BCONN; - cmd.arg = chan->No; - strcpy(cmd.parm.num, "64000"); - ccard->interface.statcallb(&cmd); - break; - case N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); - if (chan->e.B2Id) { - skb_queue_purge(&chan->e.X); - idi_do_req(ccard, chan, N_DISC_ACK, 1); - idi_do_req(ccard, chan, REMOVE, 1); - } -#ifdef CONFIG_ISDN_TTY_FAX - if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ - idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); - idi_fax_hangup(ccard, chan); - } -#endif - chan->e.IndCh = 0; - chan->queued = 0; - chan->pqueued = 0; - chan->waitq = 0; - chan->waitpq = 0; - if (!(chan->statectrl & IN_HOLD)) { - idi_do_req(ccard, chan, HANGUP, 0); - } - if (chan->fsm_state == EICON_STATE_ACTIVE) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BHUP; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - chan->fsm_state = EICON_STATE_NULL; - if (!(chan->statectrl & IN_HOLD)) { - chan->statectrl |= WAITING_FOR_HANGUP; - } - } -#ifdef CONFIG_ISDN_TTY_FAX - chan->fax = 0; -#endif - break; - case N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No); -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { - idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); - idi_fax_hangup(ccard, chan); - } -#endif - break; - case N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); - break; - case N_DATA: - skb_pull(skb, sizeof(eicon_IND) - 1); - eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); - if (chan->l2prot == ISDN_PROTO_L2_FAX) { -#ifdef CONFIG_ISDN_TTY_FAX - idi_faxdata_rcv(ccard, chan, skb); -#endif - } else { - ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb); - free_buff = 0; - } - break; - case N_UDATA: - idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); - break; -#ifdef CONFIG_ISDN_TTY_FAX - case N_EDATA: - idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); - break; -#endif - default: - eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind); - } - } - else { - eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No); - } - if (free_buff) - dev_kfree_skb(skb); -} - -static int -idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) -{ - isdn_ctrl cmd; - int tqueued = 0; - int twaitpq = 0; - - if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { - /* I don't know why this happens, should not ! */ - /* just ignoring this RC */ - eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, - ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); - return 1; - } - - /* Management Interface */ - if (chan->No == ccard->nchannels) { - /* Managementinterface: changing state */ - if (chan->e.Req != 0x02) - chan->fsm_state = 1; - } - - /* Remove an Id */ - if (chan->e.Req == REMOVE) { - if (ack->Reference != chan->e.ref) { - /* This should not happen anymore */ - eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, - ack->Reference, chan->e.ref); - } - ccard->IdTable[ack->RcId] = NULL; - if (!chan->e.ReqCh) - chan->e.D3Id = 0; - else - chan->e.B2Id = 0; - eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, - ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); - return 1; - } - - /* Signal layer */ - if (!chan->e.ReqCh) { - eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, - ack->RcId, ack->RcCh, ack->Reference); - } else { - /* Network layer */ - switch(chan->e.Req & 0x0f) { - case N_CONNECT: - chan->e.IndCh = ack->RcCh; - eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, - ack->RcId, ack->RcCh, ack->Reference); - break; - case N_MDATA: - case N_DATA: - tqueued = chan->queued; - twaitpq = chan->waitpq; - if ((chan->e.Req & 0x0f) == N_DATA) { - chan->waitpq = 0; - if(chan->pqueued) - chan->pqueued--; -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (((chan->queued - chan->waitq) < 1) && - (chan->fax2.Eop)) { - chan->fax2.Eop = 0; - if (chan->fax) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_FAXIND; - cmd.arg = chan->No; - chan->fax->r_code = ISDN_TTY_FAX_SENT; - ccard->interface.statcallb(&cmd); - } - else { - eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n"); - } - } - } -#endif - } - chan->queued -= chan->waitq; - if (chan->queued < 0) chan->queued = 0; - if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BSENT; - cmd.arg = chan->No; - cmd.parm.length = twaitpq; - ccard->interface.statcallb(&cmd); - } - break; - default: - eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, - ack->RcId, ack->RcCh, ack->Reference); - } - } - return 1; -} - -void -idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) -{ - int j; - eicon_RC *ack = (eicon_RC *)skb->data; - eicon_chan *chan; - isdn_ctrl cmd; - int dCh = -1; - - if (!ccard) { - eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n"); - dev_kfree_skb(skb); - return; - } - - if ((chan = ccard->IdTable[ack->RcId]) != NULL) - dCh = chan->No; - - switch (ack->Rc) { - case OK_FC: - case N_FLOW_CONTROL: - case ASSIGN_RC: - eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n", - dCh, ack->Rc); - break; - case READY_INT: - case TIMER_INT: - /* we do nothing here */ - break; - - case OK: - if (!chan) { - eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh); - break; - } - if (!idi_handle_ack_ok(ccard, chan, ack)) - chan = NULL; - break; - - case ASSIGN_OK: - if (chan) { - eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", - chan->No, chan->e.D3Id, chan->e.B2Id); - } - for(j = 0; j < ccard->nchannels + 1; j++) { - if ((ccard->bch[j].e.ref == ack->Reference) && - (ccard->bch[j].e.Req == ASSIGN)) { - if (!ccard->bch[j].e.ReqCh) - ccard->bch[j].e.D3Id = ack->RcId; - else - ccard->bch[j].e.B2Id = ack->RcId; - ccard->IdTable[ack->RcId] = &ccard->bch[j]; - chan = &ccard->bch[j]; - break; - } - } - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); - if (j > ccard->nchannels) { - eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", - ack->Reference, ack->RcId); - } - break; - - case OUT_OF_RESOURCES: - case UNKNOWN_COMMAND: - case WRONG_COMMAND: - case WRONG_ID: - case 0x08: /* ADAPTER_DEAD */ - case WRONG_CH: - case UNKNOWN_IE: - case WRONG_IE: - default: - if (!chan) { - eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh); - break; - } else - switch (chan->e.Req) { - case 12: /* Alert */ - eicon_log(ccard, 2, "idi_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n", - dCh, ack->Rc, ack->RcId, ack->RcCh); - break; - default: - if (dCh != ccard->nchannels) - eicon_log(ccard, 1, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", - dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); - } - if (dCh == ccard->nchannels) { /* Management */ - chan->fsm_state = 2; - eicon_log(ccard, 8, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", - dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); - } else if (dCh >= 0) { - /* any other channel */ - /* card reports error: we hangup */ - idi_hangup(ccard, chan); - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DHUP; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - } - } - if (chan) { - chan->e.ref = 0; - chan->e.busy = 0; - } - dev_kfree_skb(skb); -} - -int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) -{ - struct sk_buff *xmit_skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan_ptr *chan2; - int len, plen = 0, offset = 0; - - if ((!card) || (!chan)) { - eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n"); - return -1; - } - - if (chan->fsm_state != EICON_STATE_ACTIVE) { - eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state); - return -ENODEV; - } - - len = skb->len; - if (len > EICON_MAX_QUEUE) /* too much for the shared memory */ - return -1; - if (!len) - return 0; - - if ((chk) && (chan->pqueued > 1)) - return 0; - - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", - chan->No, len, chan->pqueued); - while(offset < len) { - - plen = ((len - offset) > 270) ? 270 : len - offset; - - xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!xmit_skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); - if (xmit_skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if ((len - offset) > 270) { - reqbuf->Req = N_MDATA; - } else { - reqbuf->Req = N_DATA; - /* if (ack) reqbuf->Req |= N_D_BIT; */ - } - reqbuf->ReqCh = chan->e.IndCh; - reqbuf->ReqId = 1; - memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen); - reqbuf->XBuffer.length = plen; - reqbuf->Reference = 1; /* Net Entity */ - - skb_queue_tail(&chan->e.X, xmit_skb); - skb_queue_tail(&card->sndq, skb2); - - offset += plen; - } - if (que) { - chan->queued += len; - chan->pqueued++; - } - eicon_tx_request(card); - dev_kfree_skb(skb); - return len; -} - - -static int -eicon_idi_manage_assign(eicon_card *card) -{ - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan *chan; - eicon_chan_ptr *chan2; - - chan = &(card->bch[card->nchannels]); - - skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n"); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); - - reqbuf->XBuffer.P[0] = 0; - reqbuf->Req = ASSIGN; - reqbuf->ReqCh = 0; - reqbuf->ReqId = MAN_ID; - reqbuf->XBuffer.length = 1; - reqbuf->Reference = 2; /* Man Entity */ - - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_tx_request(card); - return(0); -} - -int -eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) -{ - int l = 0; - int ret = 0; - int timeout; - int i; - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_REQ *reqbuf; - eicon_chan *chan; - eicon_chan_ptr *chan2; - - chan = &(card->bch[card->nchannels]); - - if (!(chan->e.D3Id)) { - chan->e.D3Id = 1; - skb_queue_purge(&chan->e.X); - chan->e.busy = 0; - - if ((ret = eicon_idi_manage_assign(card))) { - chan->e.D3Id = 0; - return(ret); - } - - timeout = jiffies + 50; - while (time_before(jiffies, timeout)) { - if (chan->e.B2Id) break; - SLEEP(10); - } - if (!chan->e.B2Id) { - chan->e.D3Id = 0; - return -EIO; - } - } - - chan->fsm_state = 0; - - if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) { - eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n"); - return -ENOMEM; - } - if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) { - kfree(manbuf); - return -EFAULT; - } - - skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); - skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); - - if ((!skb) || (!skb2)) { - eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n"); - if (skb) - dev_kfree_skb(skb); - if (skb2) - dev_kfree_skb(skb2); - kfree(manbuf); - return -ENOMEM; - } - - chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); - chan2->ptr = chan; - - reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); - - reqbuf->XBuffer.P[l++] = ESC; - reqbuf->XBuffer.P[l++] = 6; - reqbuf->XBuffer.P[l++] = 0x80; - for (i = 0; i < manbuf->length[0]; i++) - reqbuf->XBuffer.P[l++] = manbuf->data[i]; - reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; - - reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; - reqbuf->ReqCh = 0; - reqbuf->ReqId = 1; - reqbuf->XBuffer.length = l; - reqbuf->Reference = 2; /* Man Entity */ - - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - - manbuf->count = 0; - manbuf->pos = 0; - - eicon_tx_request(card); - - timeout = jiffies + 50; - while (time_before(jiffies, timeout)) { - if (chan->fsm_state) break; - SLEEP(10); - } - if ((!chan->fsm_state) || (chan->fsm_state == 2)) { - kfree(manbuf); - return -EIO; - } - if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) { - kfree(manbuf); - return -EFAULT; - } - - kfree(manbuf); - return(0); -} diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.h b/drivers/isdn/hardware/eicon/i4l_idi.h --- a/drivers/isdn/hardware/eicon/i4l_idi.h Sat Apr 3 19:38:41 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,381 +0,0 @@ -/* $Id: i4l_idi.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ - * - * ISDN interface module for Eicon active cards. - * I4L - IDI Interface - * - * Copyright 1998-2000 by Armin Schindler (mac@melware.de) - * Copyright 1999-2002 Cytronics & Melware (info@melware.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef E_IDI_H -#define E_IDI_H - -#include - -#undef N_DATA -#undef ID_MASK - -#include "pc.h" - -#define AOC_IND 26 /* Advice of Charge */ -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ - -/* defines for statectrl */ -#define WAITING_FOR_HANGUP 0x01 -#define HAVE_CONN_REQ 0x02 -#define IN_HOLD 0x04 - -typedef struct { - char cpn[32]; - char oad[32]; - char dsa[32]; - char osa[32]; - __u8 plan; - __u8 screen; - __u8 sin[4]; - __u8 chi[4]; - __u8 e_chi[4]; - __u8 bc[12]; - __u8 e_bc[12]; - __u8 llc[18]; - __u8 hlc[5]; - __u8 cau[4]; - __u8 e_cau[2]; - __u8 e_mt; - __u8 dt[6]; - char display[83]; - char keypad[35]; - char rdn[32]; -} idi_ind_message; - -typedef struct { - __u16 next __attribute__ ((packed)); - __u8 Req __attribute__ ((packed)); - __u8 ReqId __attribute__ ((packed)); - __u8 ReqCh __attribute__ ((packed)); - __u8 Reserved1 __attribute__ ((packed)); - __u16 Reference __attribute__ ((packed)); - __u8 Reserved[8] __attribute__ ((packed)); - eicon_PBUFFER XBuffer; -} eicon_REQ; - -typedef struct { - __u16 next __attribute__ ((packed)); - __u8 Rc __attribute__ ((packed)); - __u8 RcId __attribute__ ((packed)); - __u8 RcCh __attribute__ ((packed)); - __u8 Reserved1 __attribute__ ((packed)); - __u16 Reference __attribute__ ((packed)); - __u8 Reserved2[8] __attribute__ ((packed)); -} eicon_RC; - -typedef struct { - __u16 next __attribute__ ((packed)); - __u8 Ind __attribute__ ((packed)); - __u8 IndId __attribute__ ((packed)); - __u8 IndCh __attribute__ ((packed)); - __u8 MInd __attribute__ ((packed)); - __u16 MLength __attribute__ ((packed)); - __u16 Reference __attribute__ ((packed)); - __u8 RNR __attribute__ ((packed)); - __u8 Reserved __attribute__ ((packed)); - __u32 Ack __attribute__ ((packed)); - eicon_PBUFFER RBuffer; -} eicon_IND; - -typedef struct { - __u8 *Data; - unsigned int Size; - unsigned int Len; - __u8 *Next; -} eicon_OBJBUFFER; - -extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer); -extern int idi_hangup(eicon_card *card, eicon_chan *chan); -extern int idi_connect_res(eicon_card *card, eicon_chan *chan); -extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan); -extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, - char *eazmsn, int si1, int si2); - -extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); -extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); -extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); -extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); -extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); -extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); -#ifdef CONFIG_ISDN_TTY_FAX -extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan); -extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb); -#endif - -#include "dsp_defs.h" - -#define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 -/* -parameters: - transmit framer type - receive framer type -*/ - -#define DSP_REQUEST_SWITCH_FRAMER_HDLC 0 -#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT 1 -#define DSP_REQUEST_SWITCH_FRAMER_ASYNC 2 - - -#define DSP_UDATA_REQUEST_CLEARDOWN 2 -/* -parameters: - - none - -*/ - - -#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON 3 -/* -parameters: - - none - -*/ - - -#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF 4 -/* -parameters: - - none - -*/ - -typedef struct eicon_dsp_ind { - __u16 time __attribute__ ((packed)); - __u8 norm __attribute__ ((packed)); - __u16 options __attribute__ ((packed)); - __u32 speed __attribute__ ((packed)); - __u16 delay __attribute__ ((packed)); - __u32 txspeed __attribute__ ((packed)); - __u32 rxspeed __attribute__ ((packed)); -} eicon_dsp_ind; - -#define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 -#define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 -#define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 -#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - -#define DSP_UDATA_INDICATION_DISCONNECT 5 -/* -returns: - cause -*/ - -#define DSP_DISCONNECT_CAUSE_NONE 0x00 -#define DSP_DISCONNECT_CAUSE_BUSY_TONE 0x01 -#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE 0x02 -#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY 0x03 -#define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 -#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - -#define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 -/* -returns: - confirmation number -*/ - - -#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS 16 -/* -parameters: - tone duration (ms) - gap duration (ms) - digit 0 tone code - ... - digit n tone code -*/ - -#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH 5 - -#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ 0x00 -#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ 0x01 -#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ 0x02 -#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ 0x03 -#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK 0x03 -#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ 0x00 -#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ 0x04 -#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ 0x08 -#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ 0x0c -#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK 0x0c - -#define DSP_DTMF_DIGIT_TONE_CODE_0 0x07 -#define DSP_DTMF_DIGIT_TONE_CODE_1 0x00 -#define DSP_DTMF_DIGIT_TONE_CODE_2 0x04 -#define DSP_DTMF_DIGIT_TONE_CODE_3 0x08 -#define DSP_DTMF_DIGIT_TONE_CODE_4 0x01 -#define DSP_DTMF_DIGIT_TONE_CODE_5 0x05 -#define DSP_DTMF_DIGIT_TONE_CODE_6 0x09 -#define DSP_DTMF_DIGIT_TONE_CODE_7 0x02 -#define DSP_DTMF_DIGIT_TONE_CODE_8 0x06 -#define DSP_DTMF_DIGIT_TONE_CODE_9 0x0a -#define DSP_DTMF_DIGIT_TONE_CODE_STAR 0x03 -#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK 0x0b -#define DSP_DTMF_DIGIT_TONE_CODE_A 0x0c -#define DSP_DTMF_DIGIT_TONE_CODE_B 0x0d -#define DSP_DTMF_DIGIT_TONE_CODE_C 0x0e -#define DSP_DTMF_DIGIT_TONE_CODE_D 0x0f - - -#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT 16 -/* -returns: - - none - - One indication will be sent for every request. -*/ - - -#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER 17 -/* -parameters: - tone duration (ms) - gap duration (ms) -*/ -typedef struct enable_dtmf_s { - __u16 tone; - __u16 gap; -} enable_dtmf_s; - -#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18 -/* -parameters: - - none - -*/ - -#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17 -/* -returns: - digit 0 tone code - ... - digit n tone code -*/ - -#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH 1 - - -#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18 -/* -returns: - - none - -*/ - -#define DSP_UDATA_INDICATION_FAX_CALLING_TONE 19 -/* -returns: - - none - -*/ - -#define DSP_UDATA_INDICATION_ANSWER_TONE 20 -/* -returns: - - none - -*/ - -/* ============= FAX ================ */ - -#define EICON_FAXID_LEN 20 - -typedef struct eicon_t30_s { - __u8 code; - __u8 rate; - __u8 resolution; - __u8 format; - __u8 pages_low; - __u8 pages_high; - __u8 atf; - __u8 control_bits_low; - __u8 control_bits_high; - __u8 feature_bits_low; - __u8 feature_bits_high; - __u8 universal_5; - __u8 universal_6; - __u8 universal_7; - __u8 station_id_len; - __u8 head_line_len; - __u8 station_id[EICON_FAXID_LEN]; -/* __u8 head_line[]; */ -} eicon_t30_s; - - /* EDATA transmit messages */ -#define EDATA_T30_DIS 0x01 -#define EDATA_T30_FTT 0x02 -#define EDATA_T30_MCF 0x03 - - /* EDATA receive messages */ -#define EDATA_T30_DCS 0x81 -#define EDATA_T30_TRAIN_OK 0x82 -#define EDATA_T30_EOP 0x83 -#define EDATA_T30_MPS 0x84 -#define EDATA_T30_EOM 0x85 -#define EDATA_T30_DTC 0x86 - -#define T30_FORMAT_SFF 0 -#define T30_FORMAT_ASCII 1 -#define T30_FORMAT_COUNT 2 - -#define T30_CONTROL_BIT_DISABLE_FINE 0x0001 -#define T30_CONTROL_BIT_ENABLE_ECM 0x0002 -#define T30_CONTROL_BIT_ECM_64_BYTES 0x0004 -#define T30_CONTROL_BIT_ENABLE_2D_CODING 0x0008 -#define T30_CONTROL_BIT_ENABLE_T6_CODING 0x0010 -#define T30_CONTROL_BIT_ENABLE_UNCOMPR 0x0020 -#define T30_CONTROL_BIT_ACCEPT_POLLING 0x0040 -#define T30_CONTROL_BIT_REQUEST_POLLING 0x0080 -#define T30_CONTROL_BIT_MORE_DOCUMENTS 0x0100 - -#define T30_CONTROL_BIT_ALL_FEATURES\ - (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\ - T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR) - -#define T30_FEATURE_BIT_FINE 0x0001 -#define T30_FEATURE_BIT_ECM 0x0002 -#define T30_FEATURE_BIT_ECM_64_BYTES 0x0004 -#define T30_FEATURE_BIT_2D_CODING 0x0008 -#define T30_FEATURE_BIT_T6_CODING 0x0010 -#define T30_FEATURE_BIT_UNCOMPR_ENABLED 0x0020 -#define T30_FEATURE_BIT_POLLING 0x0040 - -#define FAX_OBJECT_DOCU 1 -#define FAX_OBJECT_PAGE 2 -#define FAX_OBJECT_LINE 3 - -#define T4_EOL 0x800 -#define T4_EOL_BITSIZE 12 -#define T4_EOL_DWORD (T4_EOL << (32 - T4_EOL_BITSIZE)) -#define T4_EOL_MASK_DWORD ((__u32) -1 << (32 - T4_EOL_BITSIZE)) - -#define SFF_LEN_FLD_SIZE 3 - -#define _DLE_ 0x10 -#define _ETX_ 0x03 - -typedef struct eicon_sff_dochead { - __u32 id __attribute__ ((packed)); - __u8 version __attribute__ ((packed)); - __u8 reserved1 __attribute__ ((packed)); - __u16 userinfo __attribute__ ((packed)); - __u16 pagecount __attribute__ ((packed)); - __u16 off1pagehead __attribute__ ((packed)); - __u32 offnpagehead __attribute__ ((packed)); - __u32 offdocend __attribute__ ((packed)); -} eicon_sff_dochead; - -typedef struct eicon_sff_pagehead { - __u8 pageheadid __attribute__ ((packed)); - __u8 pageheadlen __attribute__ ((packed)); - __u8 resvert __attribute__ ((packed)); - __u8 reshoriz __attribute__ ((packed)); - __u8 coding __attribute__ ((packed)); - __u8 reserved2 __attribute__ ((packed)); - __u16 linelength __attribute__ ((packed)); - __u16 pagelength __attribute__ ((packed)); - __u32 offprevpage __attribute__ ((packed)); - __u32 offnextpage __attribute__ ((packed)); -} eicon_sff_pagehead; - -#endif /* E_IDI_H */ diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.c b/drivers/isdn/hardware/eicon/i4lididrv.c --- a/drivers/isdn/hardware/eicon/i4lididrv.c Sat Apr 3 19:38:56 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1418 +0,0 @@ -/* $Id: i4lididrv.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ - * - * ISDN interface module for Eicon active cards. - * I4L - IDI Interface - * - * Copyright 1998-2000 by Armin Schindler (mac@melware.de) - * Copyright 1999-2002 Cytronics & Melware (info@melware.de) - * - * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH - * for sponsoring and testing fax - * capabilities with Diva Server cards. - * (dor@deutschemailbox.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include -#include -#include -#include -#include - -#include "i4lididrv.h" -#include -#include "divasync.h" - -#include "../avmb1/capicmd.h" /* this should be moved in a common place */ - -#define INCLUDE_INLINE_FUNCS - -static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains - start of card-list */ - -static char *DRIVERNAME = "Eicon Diva - native I4L Interface driver (http://www.melware.net)"; -static char *DRIVERLNAME = "diva2i4l"; -static char *DRIVERRELEASE = "2.0"; -static char *eicon_revision = "$Revision: 1.1.2.2 $"; -extern char *eicon_idi_revision; - -#define EICON_CTRL_VERSION 2 - -ulong DebugVar; - -static spinlock_t status_lock; -static spinlock_t ll_lock; - -#define MAX_DESCRIPTORS 32 -extern void DIVA_DIDD_Read(DESCRIPTOR *, int); - -static dword notify_handle; -static DESCRIPTOR DAdapter; -static DESCRIPTOR MAdapter; - -/* Parameter to be set by insmod */ -static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -static int debug = 1; - -MODULE_DESCRIPTION( "ISDN4Linux Interface for Eicon active card driver"); -MODULE_AUTHOR( "Armin Schindler"); -MODULE_SUPPORTED_DEVICE( "ISDN subsystem and Eicon active card driver"); -MODULE_PARM_DESC(id, "ID-String for ISDN4Linux"); -MODULE_PARM(id, "s"); -MODULE_PARM_DESC(debug, "Initial debug value"); -MODULE_PARM(debug, "i"); -MODULE_LICENSE("GPL"); - -void no_printf (unsigned char * x ,...) -{ - /* dummy debug function */ -} -DIVA_DI_PRINTF dprintf = no_printf; - -#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) -#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) -#include "debuglib.c" - -static char * -eicon_getrev(const char *revision) -{ - char *rev; - char *p; - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else rev = "1.0"; - return rev; - -} - -static void -stop_dbg(void) -{ - DbgDeregister(); - memset(&MAdapter, 0, sizeof(MAdapter)); - dprintf = no_printf; -} - -static eicon_chan * -find_channel(eicon_card *card, int channel) -{ - if ((channel >= 0) && (channel < card->nchannels)) - return &(card->bch[channel]); - eicon_log(card, 1, "%s: Invalid channel %d\n", DRIVERLNAME, channel); - return NULL; -} - -static void -eicon_rx_request(struct eicon_card *card) -{ - struct sk_buff *skb, *skb2, *skb_new; - eicon_IND *ind, *ind2, *ind_new; - eicon_chan *chan; - - if (!card) { - eicon_log(card, 1, "%s: NULL card in rcv_dispatch !\n", DRIVERLNAME); - return; - } - - while((skb = skb_dequeue(&card->rcvq))) { - ind = (eicon_IND *)skb->data; - - if ((chan = card->IdTable[ind->IndId]) == NULL) { - if (DebugVar & 1) { - switch(ind->Ind) { - case N_DISC_ACK: - /* doesn't matter if this happens */ - break; - default: - eicon_log(card, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId); - eicon_log(card, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", - ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); - } - } - dev_kfree_skb(skb); - continue; - } - - if (chan->e.complete) { /* check for rec-buffer chaining */ - if (ind->MLength == ind->RBuffer.length) { - chan->e.complete = 1; - idi_handle_ind(card, skb); - continue; - } - else { - chan->e.complete = 0; - ind->Ind = ind->MInd; - skb_queue_tail(&chan->e.R, skb); - continue; - } - } - else { - if (!(skb2 = skb_dequeue(&chan->e.R))) { - chan->e.complete = 1; - eicon_log(card, 1, "%s: buffer incomplete, but 0 in queue\n", DRIVERLNAME); - dev_kfree_skb(skb); - continue; - } - ind2 = (eicon_IND *)skb2->data; - skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), - GFP_ATOMIC); - if (!skb_new) { - eicon_log(card, 1, "%s: skb_alloc failed in rcv_dispatch()\n", DRIVERLNAME); - dev_kfree_skb(skb); - dev_kfree_skb(skb2); - continue; - } - ind_new = (eicon_IND *)skb_put(skb_new, - ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length)); - ind_new->Ind = ind2->Ind; - ind_new->IndId = ind2->IndId; - ind_new->IndCh = ind2->IndCh; - ind_new->MInd = ind2->MInd; - ind_new->MLength = ind2->MLength; - ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length; - memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length); - memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length); - dev_kfree_skb(skb); - dev_kfree_skb(skb2); - if (ind->MLength == ind->RBuffer.length) { - chan->e.complete = 2; - idi_handle_ind(card, skb_new); - continue; - } - else { - chan->e.complete = 0; - skb_queue_tail(&chan->e.R, skb_new); - continue; - } - } - } -} - -static void -eicon_ack_request(struct eicon_card *card) -{ - struct sk_buff *skb; - - if (!card) { - eicon_log(card, 1, "%s: NULL card in ack_dispatch!\n", DRIVERLNAME); - return; - } - while((skb = skb_dequeue(&card->rackq))) { - idi_handle_ack(card, skb); - } -} - -/* - * IDI-Callback function - */ -static void -eicon_idi_callback(ENTITY *de) -{ - eicon_card *ccard = (eicon_card *)de->R; - struct sk_buff *skb; - eicon_RC *ack; - eicon_IND *ind; - int len = 0; - - if (de->complete == 255) { - /* Return Code */ - skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); - if (!skb) { - eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME); - } else { - ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); - ack->Rc = de->Rc; - if (de->Rc == ASSIGN_OK) { - ack->RcId = de->Id; - de->user[1] = de->Id; - } else { - ack->RcId = de->user[1]; - } - ack->RcCh = de->RcCh; - ack->Reference = de->user[0]; - skb_queue_tail(&ccard->rackq, skb); - eicon_ack_request(ccard); - eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", - de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); - DBG_TRC(("idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x", - de->user[0], de->Rc, ack->RcId, de->RLength, de->complete)) - de->Rc = 0; - } - } else { - /* Indication */ - if (de->complete) { - len = de->RLength; - } else { - len = 270; - if (de->RLength <= 270) - eicon_log(ccard, 1, "idi_cbk: ind not complete but <= 270\n"); - } - skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); - if (!skb) { - eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME); - } else { - ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); - ind->Ind = de->Ind; - ind->IndId = de->user[1]; - ind->IndCh = de->IndCh; - ind->MInd = de->Ind; - ind->RBuffer.length = len; - ind->MLength = de->RLength; - memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); - skb_queue_tail(&ccard->rcvq, skb); - eicon_rx_request(ccard); - eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", - de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); - DBG_TRC(("idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x", - de->user[0], de->Ind, ind->IndId, de->RLength, de->complete)) - de->Ind = 0; - } - } - de->RNum = 0; - de->RNR = 0; - eicon_tx_request(ccard); -} - -/* -** Kernel thread to prevent in_interrupt -*/ -static DECLARE_TASK_QUEUE(tq_divad); -static struct semaphore diva_thread_sem; -static struct semaphore diva_thread_end; -static int divad_pid = -1; -static int divad_thread(void * data); -static void diva_tx(void *data); -static atomic_t thread_running; - -static void __init -diva_init_thread(void) -{ - int pid = 0; - - pid = kernel_thread(divad_thread, NULL, CLONE_KERNEL); - if (pid >= 0) { - divad_pid = pid; - } -} - -static int -divad_thread(void * data) -{ - atomic_inc(&thread_running); - if (atomic_read(&thread_running) > 1) { - printk(KERN_WARNING"%s: thread already running\n", DRIVERLNAME); - return(0); - } - - printk(KERN_INFO "%s: thread started with pid %d\n", DRIVERLNAME, current->pid); - exit_mm(current); - exit_files(current); - exit_fs(current); - - /* Set to RealTime */ - current->policy = SCHED_FIFO; - current->rt_priority = 33; - - strcpy(current->comm, "kdiva2i4ld"); - - for(;;) { - down_interruptible(&diva_thread_sem); - if(!(atomic_read(&thread_running))) - break; - if(signal_pending(current)) { - flush_signals(current); - } else { - run_task_queue(&tq_divad); - } - } - up(&diva_thread_end); - divad_pid = -1; - return 0; -} - -static void -stop_diva_thread(void) -{ - if (divad_pid >= 0) { - atomic_set(&thread_running, 0); - up(&diva_thread_sem); - down_interruptible(&diva_thread_end); - } -} - -void -eicon_tx_request(struct eicon_card *card) -{ - card->tq.routine = diva_tx; - card->tq.data = (void *)card; - queue_task(&card->tq, &tq_divad); - up(&diva_thread_sem); -} - -static void -diva_tx(void *data) -{ - struct eicon_card *card = (eicon_card *) data; - struct sk_buff *skb; - struct sk_buff *skb2; - eicon_chan *chan; - eicon_chan_ptr *chan2; - eicon_REQ *reqbuf = 0; - int ReqCount = 0; - int tmpid = 0; - int quloop = 1; - int dlev = 0; - ENTITY *ep = 0; - - if (!card) { - eicon_log(card, 1, "%s: NULL card in transmit !\n", DRIVERLNAME); - return; - } - - ReqCount = 0; - if (!(skb2 = skb_dequeue(&card->sndq))) - quloop = 0; - while(quloop) { - chan2 = (eicon_chan_ptr *)skb2->data; - chan = chan2->ptr; - if (!chan->e.busy) { - if((skb = skb_dequeue(&chan->e.X))) { - - reqbuf = (eicon_REQ *)skb->data; - if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { - eicon_log(card, 16, "%s: transmit: error Id=0 on %d (Net)\n", DRIVERLNAME, chan->No); - } else { - dlev = 160; - if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ - - if (!reqbuf->Reference) { /* Signal Layer */ - ep = &chan->de; - tmpid = chan->e.D3Id; - chan->e.ReqCh = 0; - } - else { /* Net Layer */ - ep = &chan->be; - tmpid = chan->e.B2Id; - chan->e.ReqCh = 1; - if (((reqbuf->Req & 0x0f) == 0x08) || - ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ - chan->waitq = reqbuf->XBuffer.length; - chan->waitpq += reqbuf->XBuffer.length; - dlev = 128; - } - } - - } else { /* It is an ASSIGN */ - if (!reqbuf->Reference) - ep = &chan->de; - else - ep = &chan->be; - ep->Id = reqbuf->ReqId; - tmpid = reqbuf->ReqId; - - if (!reqbuf->Reference) - chan->e.ReqCh = 0; - else - chan->e.ReqCh = 1; - } - - chan->e.ref = chan->No; - chan->e.Req = reqbuf->Req; - ReqCount++; - if (ep) { - ep->callback = eicon_idi_callback; - ep->R = (BUFFERS *)card; - ep->user[0] = (word)chan->No; - ep->user[1] = (word)tmpid; - ep->XNum = 1; - ep->RNum = 0; - ep->RNR = 0; - ep->Rc = 0; - ep->Ind = 0; - ep->X->PLength = reqbuf->XBuffer.length; - memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); - ep->ReqCh = reqbuf->ReqCh; - ep->Req = reqbuf->Req; - } - chan->e.busy = 1; - eicon_log(card, dlev, "idi: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, tmpid, - reqbuf->ReqCh, reqbuf->XBuffer.length, - chan->e.ref); - if (ep) { - card->d.request(ep); - if (ep->Rc) - eicon_idi_callback(ep); - } - } - dev_kfree_skb(skb); - } - dev_kfree_skb(skb2); - } - else { - skb_queue_tail(&card->sackq, skb2); - eicon_log(card, 128, "%s: transmit: busy chan %d\n", DRIVERLNAME, chan->No); - } - if (!(skb2 = skb_dequeue(&card->sndq))) - quloop = 0; - } - while((skb = skb_dequeue(&card->sackq))) { - skb_queue_tail(&card->sndq, skb); - } -} - -static int -eicon_command(eicon_card * card, isdn_ctrl * c) -{ - ulong a; - eicon_chan *chan; - isdn_ctrl cmd; - int ret = 0; - - eicon_log(card, 16, "%s_cmd 0x%x with arg 0x%lx (0x%lx)\n", DRIVERLNAME, - c->command, c->arg, (ulong) *c->parm.num); - - switch (c->command) { - case ISDN_CMD_IOCTL: - memcpy(&a, c->parm.num, sizeof(ulong)); - switch (c->arg) { - case EICON_IOCTL_GETVER: - return(EICON_CTRL_VERSION); - case EICON_IOCTL_MANIF: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!card->d.features & DI_MANAGE) - return -ENODEV; - ret = eicon_idi_manage( - card, - (eicon_manifbuf *)a); - return ret; - - case EICON_IOCTL_GETXLOG: - return -ENODEV; - case EICON_IOCTL_DEBUGVAR: - DebugVar = a; - eicon_log(card, 1, "%s: Debug Value set to %ld\n", DRIVERLNAME, DebugVar); - return 0; - case EICON_IOCTL_LOADPCI: - eicon_log(card, 1, "%s: Wrong version of load-utility,\n", DRIVERLNAME); - eicon_log(card, 1, "%s: re-compile eiconctrl !\n", DRIVERLNAME); - eicon_log(card, 1, "%s: Maybe update of utility is necessary !\n", DRIVERLNAME); - return -EINVAL; - default: - return -EINVAL; - } - break; - case ISDN_CMD_DIAL: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - eicon_log(card, 1, "%s: Dial on channel %d with state %d\n", DRIVERLNAME, - chan->No, chan->fsm_state); - return -EBUSY; - } - chan->fsm_state = EICON_STATE_OCALL; - - ret = idi_connect_req(card, chan, c->parm.setup.phone, - c->parm.setup.eazmsn, - c->parm.setup.si1, - c->parm.setup.si2); - if (ret) { - cmd.driver = card->myid; - cmd.command = ISDN_STAT_DHUP; - cmd.arg &= 0x1f; - card->interface.statcallb(&cmd); - } - return ret; - case ISDN_CMD_ACCEPTD: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - if (chan->fsm_state == EICON_STATE_ICALL) { - idi_connect_res(card, chan); - } - return 0; - case ISDN_CMD_ACCEPTB: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - return 0; - case ISDN_CMD_HANGUP: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - idi_hangup(card, chan); - return 0; - case ISDN_CMD_SETEAZ: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - chan->eazmask = 0x3ff; - eicon_idi_listen_req(card, chan); - return 0; - case ISDN_CMD_CLREAZ: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - chan->eazmask = 0; - eicon_idi_listen_req(card, chan); - return 0; - case ISDN_CMD_SETL2: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - chan->l2prot = (c->arg >> 8); - memcpy(chan->a_para, c->parm.aux.para, sizeof(chan->a_para)); - return 0; - case ISDN_CMD_SETL3: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - chan->l3prot = (c->arg >> 8); -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { - chan->fax = c->parm.fax; - eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); - } -#endif - return 0; -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_CMD_FAXCMD: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - if (!chan->fax) - break; - idi_fax_cmd(card, chan); - return 0; -#endif - case ISDN_CMD_AUDIO: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); - return 0; - case CAPI_PUT_MESSAGE: - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, c->arg & 0x1f))) - break; - if (c->parm.cmsg.Length < 8) - break; - switch(c->parm.cmsg.Command) { - case CAPI_FACILITY: - if (c->parm.cmsg.Subcommand == CAPI_REQ) - return(capipmsg(card, chan, &c->parm.cmsg)); - break; - case CAPI_MANUFACTURER: - default: - break; - } - return 0; - } - - return -EINVAL; -} - -static int -find_free_number(void) -{ - int num = 0; - char cid[40]; - eicon_card *p; - ulong flags; - - spin_lock_irqsave(&ll_lock, flags); - while(num < 100) { - sprintf(cid, "%s%d", id, num); - num++; - p = cards; - while (p) { - if (!strcmp(p->regname, cid)) - break; - p = p->next; - } - if (p) - { - spin_unlock_irqrestore(&ll_lock, flags); - return(num - 1); - } - } - spin_unlock_irqrestore(&ll_lock, flags); - return(999); -} - -/* - * Find card with given driverId - */ -static inline eicon_card * -eicon_findcard(int driverid) -{ - eicon_card *p; - ulong flags; - - spin_lock_irqsave(&ll_lock, flags); - p = cards; - while (p) { - if (p->myid == driverid) { - spin_unlock_irqrestore(&ll_lock, flags); - return p; - } - p = p->next; - } - spin_unlock_irqrestore(&ll_lock, flags); - return (eicon_card *) 0; -} - -/* - * Wrapper functions for interface to linklevel - */ -static int -if_command(isdn_ctrl * c) -{ - eicon_card *card = eicon_findcard(c->driver); - - if (card) - return (eicon_command(card, c)); - printk(KERN_ERR - "%s: if_command %d called with invalid driverId %d!\n", DRIVERLNAME, - c->command, c->driver); - return -ENODEV; -} - -static int -if_writecmd(const u_char * buf, int len, int user, int id, int channel) -{ - /* Not used */ - return (len); -} - -static int -if_readstatus(u_char * buf, int len, int user, int id, int channel) -{ - int count = 0; - int cnt = 0; - u_char *p = buf; - struct sk_buff *skb; - ulong flags; - - eicon_card *card = eicon_findcard(id); - - if (card) { - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - - spin_lock_irqsave(&status_lock, flags); - while((skb = skb_dequeue(&card->statq))) { - - if ((skb->len + count) > len) - cnt = len - count; - else - cnt = skb->len; - - if (user) - copy_to_user(p, skb->data, cnt); - else - memcpy(p, skb->data, cnt); - - count += cnt; - p += cnt; - - if (cnt == skb->len) { - dev_kfree_skb(skb); - if (card->statq_entries > 0) - card->statq_entries--; - } else { - skb_pull(skb, cnt); - skb_queue_head(&card->statq, skb); - spin_unlock_irqrestore(&status_lock, flags); - return count; - } - } - card->statq_entries = 0; - spin_unlock_irqrestore(&status_lock, flags); - return count; - } - printk(KERN_ERR - "%s: if_readstatus called with invalid driverId!\n", DRIVERLNAME); - return 0; -} - -static int -if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) -{ - eicon_card *card = eicon_findcard(id); - eicon_chan *chan; - int ret = 0; - int len; - - len = skb->len; - - if (card) { - if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; - if (!(chan = find_channel(card, channel))) - return -ENODEV; - - if (chan->fsm_state == EICON_STATE_ACTIVE) { -#ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if ((ret = idi_faxdata_send(card, chan, skb)) > 0) - ret = len; - } - else -#endif - ret = idi_send_data(card, chan, ack, skb, 1, 1); - return (ret); - } else { - return -ENODEV; - } - } - printk(KERN_ERR - "%s: if_sendbuf called with invalid driverId!\n", DRIVERLNAME); - return -ENODEV; -} - -/* jiftime() copied from HiSax */ -static inline int jiftime(char *s, long mark) -{ - s += 8; - - *s-- = '\0'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = '.'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 6 + '0'; - mark /= 6; - *s-- = ':'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - return(8); -} - -void -eicon_putstatus(eicon_card * card, char * buf) -{ - int count; - isdn_ctrl cmd; - u_char *p; - struct sk_buff *skb; - ulong flags; - - if (!card) { - if (!(card = cards)) - return; - } - - spin_lock_irqsave(&status_lock, flags); - count = strlen(buf); - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) { - spin_unlock_irqrestore(&status_lock, flags); - printk(KERN_ERR "%s: could not alloc skb in putstatus\n", DRIVERLNAME); - return; - } - p = skb_put(skb, count); - memcpy(p, buf, count); - - skb_queue_tail(&card->statq, skb); - - if (card->statq_entries >= MAX_STATUS_BUFFER) { - if ((skb = skb_dequeue(&card->statq))) { - count -= skb->len; - dev_kfree_skb(skb); - } else - count = 0; - } else - card->statq_entries++; - - spin_unlock_irqrestore(&status_lock, flags); - if (count) { - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = count; - card->interface.statcallb(&cmd); - } -} - -/* - * Debug and Log - */ -void -eicon_log(eicon_card * card, int level, const char *fmt, ...) -{ - va_list args; - char Line[160]; - u_char *p; - - - if ((DebugVar & level) || (DebugVar & 256)) { - va_start(args, fmt); - - if (DebugVar & level) { - if (DebugVar & 256) { - /* log-buffer */ - p = Line; - p += jiftime(p, jiffies); - *p++ = 32; - p += vsprintf(p, fmt, args); - *p = 0; - eicon_putstatus(card, Line); - } else { - /* printk, syslogd */ - vsprintf(Line, fmt, args); - printk(KERN_DEBUG "%s", Line); - } - } - - va_end(args); - } -} - - -/* - * Allocate a new card-struct, initialize it - * link it into cards-list. - */ -static void -eicon_alloccard(DESCRIPTOR *d) -{ - int j; - char cid[40]; - eicon_card *card; - ulong flags; - - sprintf(cid, "%s%d", id, find_free_number()); - if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) { - eicon_log(card, 1, - "%s: (%s) Could not allocate card-struct.\n", DRIVERLNAME, cid); - return; - } - memset((char *) card, 0, sizeof(eicon_card)); - skb_queue_head_init(&card->sndq); - skb_queue_head_init(&card->rcvq); - skb_queue_head_init(&card->rackq); - skb_queue_head_init(&card->sackq); - skb_queue_head_init(&card->statq); - card->statq_entries = 0; - card->interface.owner = THIS_MODULE; - card->interface.maxbufsize = 4000; - card->interface.command = if_command; - card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = if_writecmd; - card->interface.readstat = if_readstatus; - card->interface.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_L3_TRANSDSP | - ISDN_FEATURE_P_UNKNOWN; - card->interface.hl_hdrlen = 20; - card->ptype = ISDN_PTYPE_UNKNOWN; - strcpy(card->interface.id, cid); - card->myid = -1; - card->type = d->type; - - if (d->features & (DI_FAX3 | DI_EXTD_FAX)) - card->interface.features |= (ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_FCLASS2); - if (d->features & DI_MODEM) - card->interface.features |= ISDN_FEATURE_L2_MODEM; - if (d->features & DI_V110) - card->interface.features |= (ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038); - - card->flags = 0; - card->nchannels = d->channels; - card->interface.channels = d->channels; - if (!(card->bch = (eicon_chan *) vmalloc(sizeof(eicon_chan) * (card->nchannels + 1)))) { - eicon_log(card, 1, - "%s: (%s) Could not allocate bch-struct.\n", DRIVERLNAME, cid); - kfree(card); - return; - } - for (j=0; j< (card->nchannels + 1); j++) { - memset((char *)&card->bch[j], 0, sizeof(eicon_chan)); - card->bch[j].statectrl = 0; - card->bch[j].l2prot = ISDN_PROTO_L2_X75I; - card->bch[j].l3prot = ISDN_PROTO_L3_TRANS; - card->bch[j].e.D3Id = 0; - card->bch[j].e.B2Id = 0; - card->bch[j].e.Req = 0; - card->bch[j].No = j; - card->bch[j].tskb1 = NULL; - card->bch[j].tskb2 = NULL; - skb_queue_head_init(&card->bch[j].e.X); - skb_queue_head_init(&card->bch[j].e.R); - } - - if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 - , GFP_KERNEL))) { - eicon_log(card, 1, - "%s: (%s) Could not allocate DBUFFER-struct.\n", DRIVERLNAME, cid); - kfree(card); - vfree(card->bch); - return; - } - if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { - eicon_log(card, 1, - "%s: (%s) Could not allocate BUFFERS-struct.\n", DRIVERLNAME, cid); - kfree(card); - vfree(card->bch); - kfree(card->dbuf); - return; - } - if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { - eicon_log(card, 1, - "%s: (%s) Could not allocate BUFFERSP-struct.\n", DRIVERLNAME, cid); - kfree(card); - vfree(card->bch); - kfree(card->dbuf); - kfree(card->sbuf); - return; - } - for (j=0; j< (card->nchannels + 1); j++) { - memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); - card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; - memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); - card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; - - memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); - card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; - memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); - card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; - - memset((char *)&card->sbufp[j], 0, 270); - card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; - memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); - card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; - } - memcpy(&card->d, d, sizeof(*d)); /* DESCRIPTOR entries */ - - /* initializing some variables */ - card->lock = SPIN_LOCK_UNLOCKED; - card->ReadyInt = 0; - - for(j = 0; j < 256; j++) - card->IdTable[j] = NULL; - - for(j = 0; j < (card->d.channels + 1); j++) { - card->bch[j].e.busy = 0; - card->bch[j].e.D3Id = 0; - card->bch[j].e.B2Id = 0; - card->bch[j].e.ref = 0; - card->bch[j].e.Req = 0; - card->bch[j].e.complete = 1; - card->bch[j].fsm_state = EICON_STATE_NULL; - } - printk(KERN_INFO "%s: registered card '%s' with %d channels\n", - DRIVERLNAME, cid, d->channels); - - spin_lock_irqsave(&ll_lock, flags); - card->next = cards; - cards = card; - spin_unlock_irqrestore(&ll_lock, flags); -} - -/* - * register card at linklevel - */ -static int -eicon_registercard(eicon_card * card) -{ - isdn_ctrl cmd; - - if (!register_isdn(&card->interface)) { - printk(KERN_WARNING - "%s: Unable to register %s\n", DRIVERLNAME, - card->interface.id); - return -1; - } - card->myid = card->interface.channels; - sprintf(card->regname, "%s", card->interface.id); - - /* after register we start it */ - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - - return 0; -} - -static void -unregister_card(eicon_card * card, int rme) -{ - int count; - int channel; - isdn_ctrl cmd; - eicon_chan *chan; - - if(rme) { - /* before unload we need to remove the signal entity */ - for(channel = 0; channel < card->nchannels; channel++) - { - chan = &(card->bch[channel]); - if (chan->e.D3Id) { - idi_do_req(card, chan, REMOVE, 0); - count = 100; - while(count--) { - if (!chan->e.D3Id) - break; - SLEEP(2); - } - if (!count) - printk(KERN_WARNING"%s: ch:%d unlink to diva module not successful !\n", - DRIVERLNAME, chan->No); - } - } - } - - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - DBG_TRC(("channel entities freed")); -} - -static void -eicon_freecard(eicon_card *card) { - int i; - - for(i = 0; i < (card->nchannels + 1); i++) { - skb_queue_purge(&card->bch[i].e.X); - skb_queue_purge(&card->bch[i].e.R); - } - skb_queue_purge(&card->sndq); - skb_queue_purge(&card->rcvq); - skb_queue_purge(&card->rackq); - skb_queue_purge(&card->sackq); - skb_queue_purge(&card->statq); - - kfree(card->sbufp); - kfree(card->sbuf); - kfree(card->dbuf); - vfree(card->bch); - kfree(card); - DBG_TRC(("card structures freed")); -} - -static int -eicon_addcard(DESCRIPTOR *d) -{ - eicon_card *p; - eicon_card *q = NULL; - int registered; - int added = 0; - int failed = 0; - ulong flags; - - eicon_alloccard(d); - p = cards; - while (p) { - registered = 0; - if (!p->interface.statcallb) { - /* Not yet registered. - * Try to register and activate it. - */ - added++; - if (!eicon_registercard(p)) - registered = 1; - } else { - /* Card already registered */ - registered = 1; - } - - if (registered) { - /* Init OK, next card ... */ - spin_lock_irqsave(&ll_lock, flags); - q = p; - p = p->next; - spin_unlock_irqrestore(&ll_lock, flags); - } else { - /* registering failed, remove card from list, free memory */ - printk(KERN_ERR - "%s: Initialization of %s failed\n", DRIVERLNAME, - p->interface.id); - spin_lock_irqsave(&ll_lock, flags); - if (q) { - q->next = p->next; - eicon_freecard(p); - p = q->next; - } else { - cards = p->next; - eicon_freecard(p); - p = cards; - } - spin_unlock_irqrestore(&ll_lock, flags); - failed++; - } - } - return (added - failed); -} - -static void * -didd_callback(void *context, DESCRIPTOR* adapter, int removal) -{ - eicon_card *cp = NULL, *lastcp = NULL; - ulong flags; - - if (adapter->type == IDI_DADAPTER) - { - printk(KERN_ERR "%s: Change in DAdapter ? Oops ?.\n", DRIVERLNAME); - DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); - return(NULL); - } - else if (adapter->type == IDI_DIMAINT) - { - if (removal) - { - stop_dbg(); - } - else - { - memcpy(&MAdapter, adapter, sizeof(MAdapter)); - dprintf = (DIVA_DI_PRINTF)MAdapter.request; - DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT); - } - } - else if ((adapter->type > 0) && - (adapter->type < 16)) - { /* IDI Adapter */ - if (removal) - { - spin_lock_irqsave(&ll_lock, flags); - lastcp = cp = cards; - while (cp) { - if (cp->d.request == adapter->request) - { - spin_unlock_irqrestore(&ll_lock, flags); - DBG_LOG(("remove adapter from list")); - unregister_card(cp, 0); - spin_lock_irqsave(&ll_lock, flags); - if (cp == lastcp) - cards = cp->next; - else - lastcp->next = cp->next; - eicon_freecard(cp); - break; - } - lastcp = cp; - cp = cp->next; - } - spin_unlock_irqrestore(&ll_lock, flags); - } - else - { - if (adapter->channels) { - DBG_LOG(("add adapter to list")); - eicon_addcard(adapter); - } - } - } - return(NULL); -} - -static int __init -connect_didd(void) -{ - int x = 0; - int dadapter = 0; - IDI_SYNC_REQ req; - DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; - - DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); - - for (x = 0; x < MAX_DESCRIPTORS; x++) - { - if (DIDD_Table[x].type == IDI_DADAPTER) - { /* DADAPTER found */ - dadapter = 1; - memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); - req.didd_notify.e.Req = 0; - req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; - req.didd_notify.info.callback = didd_callback; - req.didd_notify.info.context = 0; - DAdapter.request((ENTITY *)&req); - if (req.didd_notify.e.Rc != 0xff) - { - stop_dbg(); - return(0); - } - notify_handle = req.didd_notify.info.handle; - } - else if (DIDD_Table[x].type == IDI_DIMAINT) - { /* MAINT found */ - memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); - dprintf = (DIVA_DI_PRINTF)MAdapter.request; - DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT); - } - else if ((DIDD_Table[x].type > 0) && - (DIDD_Table[x].type < 16)) - { /* IDI Adapter found */ - if (DIDD_Table[x].channels) { - eicon_addcard(&DIDD_Table[x]); - } - } - } - - if (!dadapter) { - stop_dbg(); - } - - return(dadapter); -} - -static void __exit -disconnect_didd(void) -{ - IDI_SYNC_REQ req; - - stop_dbg(); - - req.didd_notify.e.Req = 0; - req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; - req.didd_notify.info.handle = notify_handle; - DAdapter.request((ENTITY *)&req); -} - -/* -** proc entry -*/ -extern struct proc_dir_entry *proc_net_isdn_eicon; -static struct proc_dir_entry *i4lidi_proc_entry = NULL; - -static int -i4lidi_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - int len = 0; - char tmprev[32]; - - len += sprintf(page+len, "%s\n", DRIVERNAME); - len += sprintf(page+len, "name : %s\n", DRIVERLNAME); - len += sprintf(page+len, "release : %s\n", DRIVERRELEASE); - strcpy(tmprev, eicon_revision); - len += sprintf(page+len, "revision : %s/", eicon_getrev(tmprev)); - strcpy(tmprev, eicon_idi_revision); - len += sprintf(page+len, "%s\n", eicon_getrev(tmprev)); - - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return((count < len-off) ? count : len-off); -} - -static void __init -create_proc(void) -{ - if(!(i4lidi_proc_entry = create_proc_entry(DRIVERLNAME, - S_IFREG | S_IRUGO | S_IWUSR, proc_net_isdn_eicon))) - { - printk(KERN_WARNING "%s: failed to create proc entry.\n", DRIVERLNAME); - return; - } - i4lidi_proc_entry->read_proc = i4lidi_proc_read; - i4lidi_proc_entry->owner = THIS_MODULE; -} - -static void __exit -remove_proc(void) -{ - if(i4lidi_proc_entry) - remove_proc_entry(DRIVERLNAME, proc_net_isdn_eicon); -} - -/* -** load / unload -*/ -static int __init -i4l_idi_init(void) -{ - int ret = 0; - char tmprev[50]; - - status_lock = SPIN_LOCK_UNLOCKED; - ll_lock = SPIN_LOCK_UNLOCKED; - - if (strlen(id) < 1) - strcpy(id, "diva"); - - DebugVar = debug; - - init_MUTEX_LOCKED(&diva_thread_sem); - init_MUTEX_LOCKED(&diva_thread_end); - - printk(KERN_INFO "%s\n", DRIVERNAME); - printk(KERN_INFO "%s: Rel:%s Rev:",DRIVERLNAME , DRIVERRELEASE); - strcpy(tmprev, eicon_revision); - printk("%s/", eicon_getrev(tmprev)); - strcpy(tmprev, eicon_idi_revision); - printk("%s\n", eicon_getrev(tmprev)); - - diva_init_thread(); - - if(!connect_didd()) { - printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME); - stop_diva_thread(); - ret = -EIO; - goto out; - } - create_proc(); - -out: - return(ret); -} - -static void __exit -i4l_idi_exit(void) -{ - eicon_card *card, *last, *cc; - ulong flags; - - spin_lock_irqsave(&ll_lock, flags); - cc = cards; - card = cc; - cards = NULL; - spin_unlock_irqrestore(&ll_lock, flags); - - remove_proc(); - - while (card) { - unregister_card(card, 1); - card = card->next; - } - - stop_diva_thread(); - disconnect_didd(); - - card = cc; - while (card) { - last = card; - card = card->next; - eicon_freecard(last); - } - printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME); -} - -module_init(i4l_idi_init); -module_exit(i4l_idi_exit); diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.h b/drivers/isdn/hardware/eicon/i4lididrv.h --- a/drivers/isdn/hardware/eicon/i4lididrv.h Sat Apr 3 19:38:42 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,272 +0,0 @@ -/* $Id: i4lididrv.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ - * - * ISDN interface module for Eicon active cards. - * I4L - IDI Interface - * - * Copyright 1998-2000 by Armin Schindler (mac@melware.de) - * Copyright 1999-2002 Cytronics & Melware (info@melware.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - - -#ifndef i4lididrv_h -#define i4lididrv_h - -#include -#include - -#include "platform.h" -#include "di_defs.h" - -#define EICON_IOCTL_GETTYPE 6 -#define EICON_IOCTL_LOADPCI 7 -#define EICON_IOCTL_GETVER 9 -#define EICON_IOCTL_GETXLOG 10 - -#define EICON_IOCTL_MANIF 90 - -#define EICON_IOCTL_FREEIT 97 -#define EICON_IOCTL_TEST 98 -#define EICON_IOCTL_DEBUGVAR 99 - -/* Constants for describing Card-Type */ -#define EICON_CTYPE_S 0 -#define EICON_CTYPE_SX 1 -#define EICON_CTYPE_SCOM 2 -#define EICON_CTYPE_QUADRO 3 -#define EICON_CTYPE_S2M 4 -#define EICON_CTYPE_MAESTRA 5 -#define EICON_CTYPE_MAESTRAQ 6 -#define EICON_CTYPE_MAESTRAQ_U 7 -#define EICON_CTYPE_MAESTRAP 8 -#define EICON_CTYPE_ISABRI 0x10 -#define EICON_CTYPE_ISAPRI 0x20 -#define EICON_CTYPE_MASK 0x0f -#define EICON_CTYPE_QUADRO_NR(n) (n<<4) - -#define MAX_HEADER_LEN 10 - -#define MAX_STATUS_BUFFER 150 - -/* Data for Management interface */ -typedef struct { - int count; - int pos; - int length[50]; - unsigned char data[700]; -} eicon_manifbuf; - -#define TRACE_OK (1) - -#ifdef __KERNEL__ - -/* Macro for delay via schedule() */ -#define SLEEP(j) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - schedule_timeout(j); \ -} - -/* Kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - __u16 length __attribute__ ((packed)); /* length of data/parameter field */ - __u8 P[1]; /* data/parameter field */ -} eicon_PBUFFER; - -typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - -typedef struct { - __u8 Req; /* pending request */ - __u8 Rc; /* return code received */ - __u8 Ind; /* indication received */ - __u8 ReqCh; /* channel of current Req */ - __u8 RcCh; /* channel of current Rc */ - __u8 IndCh; /* channel of current Ind */ - __u8 D3Id; /* ID used by this entity */ - __u8 B2Id; /* ID used by this entity */ - __u8 GlobalId; /* reserved field */ - __u8 XNum; /* number of X-buffers */ - __u8 RNum; /* number of R-buffers */ - struct sk_buff_head X; /* X-buffer queue */ - struct sk_buff_head R; /* R-buffer queue */ - __u8 RNR; /* receive not ready flag */ - __u8 complete; /* receive complete status */ - __u8 busy; /* busy flag */ - __u16 ref; /* saved reference */ -} entity; - -#define FAX_MAX_SCANLINE 2500 - -typedef struct { - __u8 PrevObject; - __u8 NextObject; - __u8 abLine[FAX_MAX_SCANLINE]; - __u8 abFrame[FAX_MAX_SCANLINE]; - unsigned int LineLen; - unsigned int LineDataLen; - __u32 LineData; - unsigned int NullBytesPos; - __u8 NullByteExist; - int PageCount; - __u8 Dle; - __u8 Eop; -} eicon_ch_fax_buf; - -typedef struct { - int No; /* Channel Number */ - unsigned short fsm_state; /* Current D-Channel state */ - unsigned short statectrl; /* State controling bits */ - unsigned short eazmask; /* EAZ-Mask for this Channel */ - int queued; /* User-Data Bytes in TX queue */ - int pqueued; /* User-Data Packets in TX queue */ - int waitq; /* User-Data Bytes in wait queue */ - int waitpq; /* User-Data Bytes in packet queue */ - struct sk_buff *tskb1; /* temp skb 1 */ - struct sk_buff *tskb2; /* temp skb 2 */ - unsigned char l2prot; /* Layer 2 protocol */ - unsigned char l3prot; /* Layer 3 protocol */ -#ifdef CONFIG_ISDN_TTY_FAX - T30_s *fax; /* pointer to fax data in LL */ - eicon_ch_fax_buf fax2; /* fax related struct */ -#endif - entity e; /* Native Entity */ - ENTITY de; /* Divas D Entity */ - ENTITY be; /* Divas B Entity */ - char cpn[32]; /* remember cpn */ - char oad[32]; /* remember oad */ - char dsa[32]; /* remember dsa */ - char osa[32]; /* remember osa */ - unsigned char cause[2]; /* Last Cause */ - unsigned char si1; - unsigned char si2; - unsigned char plan; - unsigned char screen; - unsigned char a_para[8]; /* Additional parameter */ -} eicon_chan; - -typedef struct { - eicon_chan *ptr; -} eicon_chan_ptr; - - -#define EICON_FLAGS_RUNNING 1 /* Cards driver activated */ -#define EICON_FLAGS_LOADED 8 /* Firmware loaded */ - -/* D-Channel states */ -#define EICON_STATE_NULL 0 -#define EICON_STATE_ICALL 1 -#define EICON_STATE_OCALL 2 -#define EICON_STATE_IWAIT 3 -#define EICON_STATE_OWAIT 4 -#define EICON_STATE_IBWAIT 5 -#define EICON_STATE_OBWAIT 6 -#define EICON_STATE_BWAIT 7 -#define EICON_STATE_BHWAIT 8 -#define EICON_STATE_BHWAIT2 9 -#define EICON_STATE_DHWAIT 10 -#define EICON_STATE_DHWAIT2 11 -#define EICON_STATE_BSETUP 12 -#define EICON_STATE_ACTIVE 13 -#define EICON_STATE_ICALLW 14 -#define EICON_STATE_LISTEN 15 -#define EICON_STATE_WMCONN 16 - -#define EICON_MAX_QUEUE 2138 - -typedef struct { - __u8 ret; - __u8 id; - __u8 ch; -} eicon_ack; - -typedef struct { - __u8 code; - __u8 id; - __u8 ch; -} eicon_req; - -typedef struct { - __u8 ret; - __u8 id; - __u8 ch; - __u8 more; -} eicon_indhdr; - -/* - * Per card driver data - */ -typedef struct eicon_card { - DESCRIPTOR d; /* IDI Descriptor */ - u_char ptype; /* Protocol type (1TR6 or Euro) */ - u_char type; /* Cardtype (EICON_CTYPE_...) */ - struct eicon_card *qnext; /* Pointer to next quadro adapter */ - int Feature; /* Protocol Feature Value */ - struct eicon_card *next; /* Pointer to next device struct */ - int myid; /* Driver-Nr. assigned by linklevel */ - unsigned long flags; /* Statusflags */ - struct sk_buff_head rcvq; /* Receive-Message queue */ - struct sk_buff_head sndq; /* Send-Message queue */ - struct sk_buff_head rackq; /* Req-Ack-Message queue */ - struct sk_buff_head sackq; /* Data-Ack-Message queue */ - struct sk_buff_head statq; /* Status-Message queue */ - int statq_entries; - eicon_chan* IdTable[256]; /* Table to find entity */ - __u16 ref_in; - __u16 ref_out; - int nchannels; /* Number of B-Channels */ - int ReadyInt; /* Ready Interrupt */ - eicon_chan *bch; /* B-Channel status/control */ - DBUFFER *dbuf; /* Dbuffer for Diva Server */ - BUFFERS *sbuf; /* Buffer for Diva Server */ - char *sbufp; /* Data Buffer for Diva Server */ - isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Drivers card name */ - spinlock_t lock; /* spin lock per card */ - struct tq_struct tq; /* task queue for thread */ -} eicon_card; - -#include "i4l_idi.h" - -extern eicon_card *cards; -extern char *eicon_ctype_name[]; - -extern ulong DebugVar; -extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); -extern void eicon_putstatus(eicon_card * card, char * buf); - -extern void eicon_tx_request(struct eicon_card *); - -extern spinlock_t eicon_lock; - -#endif /* __KERNEL__ */ - -#endif /* i4lididrv_h */ diff -Nru a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c --- a/drivers/isdn/hardware/eicon/idifunc.c Sat Apr 3 19:38:56 2004 +++ b/drivers/isdn/hardware/eicon/idifunc.c Sat Apr 3 19:38:56 2004 @@ -1,4 +1,4 @@ -/* $Id: idifunc.c,v 1.13 2003/08/25 14:49:53 schindler Exp $ +/* $Id: idifunc.c,v 1.14 2004/03/21 18:13:43 armin Exp $ * * Driver for Eicon DIVA Server ISDN cards. * User Mode IDI Interface @@ -49,76 +49,37 @@ } typedef struct _udiva_card { - struct _udiva_card *next; + struct list_head list; int Id; DESCRIPTOR d; } udiva_card; -static udiva_card *cards; +static LIST_HEAD(cards); static diva_os_spin_lock_t ll_lock; /* - * add card to list - */ -static void add_card_to_list(udiva_card * c) -{ - diva_os_spin_lock_magic_t old_irql; - - diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card"); - c->next = cards; - cards = c; - diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card"); -} - -/* * find card in list */ static udiva_card *find_card_in_list(DESCRIPTOR * d) { udiva_card *card; + struct list_head *tmp; diva_os_spin_lock_magic_t old_irql; diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card"); - card = cards; - while (card) { + list_for_each(tmp, &cards) { + card = list_entry(tmp, udiva_card, list); if (card->d.request == d->request) { diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card"); return (card); } - card = card->next; } diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card"); return ((udiva_card *) NULL); } /* - * remove card from list - */ -static void remove_card_from_list(udiva_card * c) -{ - udiva_card *list = NULL, *last; - diva_os_spin_lock_magic_t old_irql; - - diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card"); - list = cards; - last = list; - while (list) { - if (list == c) { - if (cards == c) { - cards = c->next; - } else { - last->next = c->next; - } - break; - } - last = list; - list = list->next; - } - diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card"); -} - -/* * new card */ static void um_new_card(DESCRIPTOR * d) @@ -126,6 +87,7 @@ int adapter_nr = 0; udiva_card *card = NULL; IDI_SYNC_REQ sync_req; + diva_os_spin_lock_magic_t old_irql; if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) { DBG_ERR(("cannot get buffer for card")); @@ -140,7 +102,9 @@ sync_req.xdi_logical_adapter_number.info.logical_adapter_number; card->Id = adapter_nr; if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) { - add_card_to_list(card); + diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card"); + list_add_tail(&card->list, &cards); + diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card"); } else { DBG_ERR(("could not create user mode idi card %d", adapter_nr)); @@ -152,6 +116,7 @@ */ static void um_remove_card(DESCRIPTOR * d) { + diva_os_spin_lock_magic_t old_irql; udiva_card *card = NULL; if (!(card = find_card_in_list(d))) { @@ -159,7 +124,9 @@ return; } diva_user_mode_idi_remove_adapter(card->Id); - remove_card_from_list(card); + diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card"); + list_del(&card->list); + diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card"); DBG_LOG(("idi proc entry removed for card %d", card->Id)); diva_os_free(0, card); } @@ -169,20 +136,20 @@ */ static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void) { - udiva_card *card, *last; + udiva_card *card; + struct list_head *tmp; diva_os_spin_lock_magic_t old_irql; +rescan: diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all"); - card = cards; - cards = NULL; + list_for_each(tmp, &cards) { + card = list_entry(tmp, udiva_card, list); diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); - - while (card) { diva_user_mode_idi_remove_adapter(card->Id); - last = card; - card = card->next; - diva_os_free(0, last); + diva_os_free(0, card); + goto rescan; } + diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); } /* diff -Nru a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c --- a/drivers/isdn/hardware/eicon/message.c Sat Apr 3 19:38:44 2004 +++ b/drivers/isdn/hardware/eicon/message.c Sat Apr 3 19:38:44 2004 @@ -14821,7 +14821,7 @@ for(i=0;i #include #include +#include #include #include @@ -332,7 +333,6 @@ */ #define NO_CORNETN #define IMPLEMENT_DTMF 1 -#define IMPLEMENT_LINE_INTERCONNECT2 1 #define IMPLEMENT_ECHO_CANCELLER 1 #define IMPLEMENT_RTP 1 #define IMPLEMENT_T38 1 @@ -346,7 +346,6 @@ #define IMPLEMENT_FAX_NONSTANDARD 1 #define VSWITCH_SUPPORT 1 -#define IMPLEMENT_LINE_INTERCONNECT 0 #define IMPLEMENT_MARKED_OK_AFTER_FC 1 #define DIVA_IDI_RX_DMA 1 diff -Nru a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c --- a/drivers/isdn/hardware/eicon/um_idi.c Sat Apr 3 19:38:45 2004 +++ b/drivers/isdn/hardware/eicon/um_idi.c Sat Apr 3 19:38:45 2004 @@ -1,9 +1,8 @@ -/* $Id: um_idi.c,v 1.12 2004/01/12 18:00:09 armin Exp $ */ +/* $Id: um_idi.c,v 1.14 2004/03/21 17:54:37 armin Exp $ */ #include "platform.h" #include "di_defs.h" #include "pc.h" -#include "dlist.h" #include "dqueue.h" #include "adapter.h" #include "entity.h" @@ -22,7 +21,7 @@ /* -------------------------------------------------------------------------- LOCALS -------------------------------------------------------------------------- */ -static diva_entity_queue_t adapter_q; +static LIST_HEAD(adapter_q); static diva_os_spin_lock_t adapter_lock; static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr); @@ -37,17 +36,11 @@ static int process_idi_ind(divas_um_idi_entity_t * e, byte ind); static int write_return_code(divas_um_idi_entity_t * e, byte rc); -/* - * include queue functions - */ -#include "dlist.c" - /* -------------------------------------------------------------------------- MAIN -------------------------------------------------------------------------- */ int diva_user_mode_idi_init(void) { - diva_q_init(&adapter_q); diva_os_initialize_spin_lock(&adapter_lock, "adapter"); return (0); } @@ -89,18 +82,18 @@ -------------------------------------------------------------------------- */ void diva_user_mode_idi_remove_adapter(int adapter_nr) { - diva_um_idi_adapter_t *a = - (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q); + struct list_head *tmp; + diva_um_idi_adapter_t *a; - while (a) { + list_for_each(tmp, &adapter_q) { + a = list_entry(tmp, diva_um_idi_adapter_t, link); if (a->adapter_nr == adapter_nr) { - diva_q_remove(&adapter_q, &a->link); + list_del(tmp); cleanup_adapter(a); DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr)); diva_os_free(0, a); break; } - a = (diva_um_idi_adapter_t *) diva_q_get_next(&a->link); } } @@ -109,15 +102,15 @@ -------------------------------------------------------------------------- */ void diva_user_mode_idi_finit(void) { - diva_um_idi_adapter_t *a = - (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q); + struct list_head *tmp, *safe; + diva_um_idi_adapter_t *a; - while (a) { - diva_q_remove(&adapter_q, &a->link); + list_for_each_safe(tmp, safe, &adapter_q) { + a = list_entry(tmp, diva_um_idi_adapter_t, link); + list_del(tmp); cleanup_adapter(a); DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr)); diva_os_free(0, a); - a = (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q); } diva_os_destroy_spin_lock(&adapter_lock, "adapter"); } @@ -137,6 +130,7 @@ return (-1); } memset(a, 0x00, sizeof(*a)); + INIT_LIST_HEAD(&a->entity_q); a->d = *d; a->adapter_nr = adapter_nr; @@ -145,46 +139,27 @@ adapter_nr, a->d.type, a->d.features, a->d.channels)); diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_adapter"); - diva_q_add_tail(&adapter_q, &a->link); + list_add_tail(&a->link, &adapter_q); diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_adapter"); return (0); } -static int cmp_adapter_nr(const void *what, const diva_entity_link_t * p) -{ - diva_um_idi_adapter_t *a = (diva_um_idi_adapter_t *) p; - dword nr = (dword) (unsigned long) what; - - DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr)); - - return (nr != a->adapter_nr); -} - /* ------------------------------------------------------------------------ Find adapter by Adapter number ------------------------------------------------------------------------ */ static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr) { - return (diva_um_idi_adapter_t *) diva_q_find(&adapter_q, - (void *) (unsigned - long) nr, - cmp_adapter_nr); -} + diva_um_idi_adapter_t *a = NULL; + struct list_head *tmp; -/* ------------------------------------------------------------------------ - Return number of adapters in system - ------------------------------------------------------------------------ */ -int diva_um_idi_nr_of_adapters(void) -{ - int i = 0; - const diva_entity_queue_t * q = &adapter_q; - const diva_entity_link_t *diva_current = q->head; - - while (diva_current) { - i++; - diva_current = diva_current->next; + list_for_each(tmp, &adapter_q) { + a = list_entry(tmp, diva_um_idi_adapter_t, link); + DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr)); + if (a->adapter_nr == (int)nr) + break; + a = NULL; } - return(i); + return(a); } /* ------------------------------------------------------------------------ @@ -193,17 +168,17 @@ ------------------------------------------------------------------------ */ static void cleanup_adapter(diva_um_idi_adapter_t * a) { - divas_um_idi_entity_t *e = - (divas_um_idi_entity_t *) diva_q_get_head(&a->entity_q); + struct list_head *tmp, *safe; + divas_um_idi_entity_t *e; - while (e) { - diva_q_remove(&a->entity_q, &e->link); + list_for_each_safe(tmp, safe, &a->entity_q) { + e = list_entry(tmp, divas_um_idi_entity_t, link); + list_del(tmp); cleanup_entity(e); if (e->os_context) { diva_os_wakeup_read(e->os_context); diva_os_wakeup_close(e->os_context); } - e = (divas_um_idi_entity_t *) diva_q_get_head(&a->entity_q); } memset(&a->d, 0x00, sizeof(DESCRIPTOR)); } @@ -281,7 +256,7 @@ e->os_ref = file; /* link to os handle */ e->adapter = a; /* link to adapter */ - diva_q_add_tail(&a->entity_q, &e->link); /* link from adapter */ + list_add_tail(&e->link, &a->entity_q); /* link from adapter */ diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity"); @@ -305,7 +280,7 @@ diva_os_enter_spin_lock(&adapter_lock, &old_irql, "delete_entity"); if ((a = e->adapter)) { - diva_q_remove(&a->entity_q, &e->link); + list_del(&e->link); } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "delete_entity"); diff -Nru a/drivers/isdn/hardware/eicon/um_idi.h b/drivers/isdn/hardware/eicon/um_idi.h --- a/drivers/isdn/hardware/eicon/um_idi.h Sat Apr 3 19:38:57 2004 +++ b/drivers/isdn/hardware/eicon/um_idi.h Sat Apr 3 19:38:57 2004 @@ -1,4 +1,4 @@ -/* $Id: um_idi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */ +/* $Id: um_idi.h,v 1.6 2004/03/21 17:26:01 armin Exp $ */ #ifndef __DIVA_USER_MODE_IDI_CORE_H__ #define __DIVA_USER_MODE_IDI_CORE_H__ @@ -9,7 +9,6 @@ */ int diva_user_mode_idi_init(void); void diva_user_mode_idi_finit(void); -int diva_um_idi_nr_of_adapters(void); void *divas_um_idi_create_entity(dword adapter_nr, void *file); int divas_um_idi_delete_entity(int adapter_nr, void *entity); diff -Nru a/drivers/isdn/hardware/eicon/xdi_adapter.h b/drivers/isdn/hardware/eicon/xdi_adapter.h --- a/drivers/isdn/hardware/eicon/xdi_adapter.h Sat Apr 3 19:38:44 2004 +++ b/drivers/isdn/hardware/eicon/xdi_adapter.h Sat Apr 3 19:38:44 2004 @@ -1,4 +1,4 @@ -/* $Id: xdi_adapter.h,v 1.6 2003/12/05 18:45:05 armin Exp $ */ +/* $Id: xdi_adapter.h,v 1.7 2004/03/21 17:26:01 armin Exp $ */ #ifndef __DIVA_OS_XDI_ADAPTER_H__ #define __DIVA_OS_XDI_ADAPTER_H__ @@ -47,7 +47,7 @@ } diva_os_idi_adapter_interface_t; typedef struct _diva_os_xdi_adapter { - diva_entity_link_t link; + struct list_head link; int CardIndex; int CardOrdinal; int controller; /* number of this controller */ diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c --- a/drivers/isdn/hisax/hfc_usb.c Sat Apr 3 19:38:42 2004 +++ b/drivers/isdn/hisax/hfc_usb.c Sat Apr 3 19:38:42 2004 @@ -1349,9 +1349,11 @@ { struct usb_device *dev= interface_to_usbdev(intf); hfcusb_data *context; - struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting; + struct usb_host_interface *iface = intf->cur_altsetting; + struct usb_host_interface *iface_used = NULL; struct usb_host_endpoint *ep; - int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; + int ifnum = iface->desc.bInterfaceNumber; + int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0; // usb_show_device(dev); @@ -1366,7 +1368,7 @@ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", - intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor); + ifnum, iface->desc.bAlternateSetting, intf->minor); #endif if (vend_idx != 0xffff) { @@ -1374,14 +1376,15 @@ printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name); #endif /* if vendor and product ID is OK, start probing a matching alternate setting ... */ - probe_alt_setting = 0; + alt_idx = 0; small_match=0xffff; // default settings iso_packet_size=16; packet_size=64; - while(probe_alt_setting < intf->num_altsetting) { - iface = intf->altsetting + probe_alt_setting; + while (alt_idx < intf->num_altsetting) { + iface = intf->altsetting + alt_idx; + probe_alt_setting = iface->desc.bAlternateSetting; cfg_used=0; #ifdef VERBOSE_USB_DEBUG @@ -1395,7 +1398,7 @@ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n", - probe_alt_setting, intf->act_altsetting,cfg_used); + ifnum, probe_alt_setting, cfg_used); #endif // copy table memcpy(cmptbl,vcf,16*sizeof(int)); @@ -1448,6 +1451,7 @@ if (cfg_used < small_match) { small_match = cfg_used; alt_used = probe_alt_setting; + iface_used = iface; } #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used); @@ -1457,15 +1461,14 @@ cfg_used++; } - probe_alt_setting++; - } /* (probe_alt_setting < intf->num_altsetting) */ + alt_idx++; + } /* (alt_idx < intf->num_altsetting) */ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used); #endif // yiipiee, we found a valid config if (small_match != 0xffff) { - intf->act_altsetting = alt_used; - iface = intf->altsetting + intf->act_altsetting; + iface = iface_used; if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) return(-ENOMEM); /* got no mem */ @@ -1542,8 +1545,8 @@ // now share our luck context->dev = dev; /* save device */ - context->if_used = intf->altsetting->desc.bInterfaceNumber; /* save used interface */ - context->alt_used = intf->act_altsetting; /* and alternate config */ + context->if_used = ifnum; /* save used interface */ + context->alt_used = alt_used; /* and alternate config */ context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ context->cfg_used=vcf[16]; // store used config context->vend_idx=vend_idx; // store found vendor diff -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c --- a/drivers/isdn/hisax/hisax_fcpcipnp.c Sat Apr 3 19:38:54 2004 +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c Sat Apr 3 19:38:54 2004 @@ -762,7 +762,7 @@ adapter->isac.priv = adapter; switch (adapter->type) { case AVM_FRITZ_PCIV2: - adapter->isac.read_isac = &fcpci2_read_isac;; + adapter->isac.read_isac = &fcpci2_read_isac; adapter->isac.write_isac = &fcpci2_write_isac; adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo; @@ -771,7 +771,7 @@ adapter->write_ctrl = &fcpci2_write_ctrl; break; case AVM_FRITZ_PCI: - adapter->isac.read_isac = &fcpci_read_isac;; + adapter->isac.read_isac = &fcpci_read_isac; adapter->isac.write_isac = &fcpci_write_isac; adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; @@ -780,7 +780,7 @@ adapter->write_ctrl = &fcpci_write_ctrl; break; case AVM_FRITZ_PNP: - adapter->isac.read_isac = &fcpci_read_isac;; + adapter->isac.read_isac = &fcpci_read_isac; adapter->isac.write_isac = &fcpci_write_isac; adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c --- a/drivers/isdn/hisax/niccy.c Sat Apr 3 19:38:42 2004 +++ b/drivers/isdn/hisax/niccy.c Sat Apr 3 19:38:42 2004 @@ -271,7 +271,7 @@ } card->para[1] = pnp_port_start(pnp_d, 0); card->para[2] = pnp_port_start(pnp_d, 1); - card->para[0] = pnp_irq(pnp_d, 0);; + card->para[0] = pnp_irq(pnp_d, 0); if (!card->para[0] || !card->para[1] || !card->para[2]) { printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n", card->para[0], card->para[1], card->para[2]); diff -Nru a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c --- a/drivers/isdn/hisax/nj_s.c Sat Apr 3 19:38:42 2004 +++ b/drivers/isdn/hisax/nj_s.c Sat Apr 3 19:38:42 2004 @@ -80,7 +80,7 @@ printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n", cs->hw.njet.last_is0, s0val); spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED;; + return IRQ_HANDLED; } cs->hw.njet.irqstat0 = s0val; if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != diff -Nru a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig --- a/drivers/macintosh/Kconfig Sat Apr 3 19:38:43 2004 +++ b/drivers/macintosh/Kconfig Sat Apr 3 19:38:43 2004 @@ -1,5 +1,6 @@ menu "Macintosh device drivers" + depends on PPC || MAC config ADB bool "Apple Desktop Bus (ADB) support" @@ -174,8 +175,8 @@ This driver provides some thermostat and fan control for the desktop G4 "Windtunnel" -config THERM_ADT7467 - tristate "Support for thermal mgmnt on laptops with ADT 7467 chipset" +config THERM_ADT746X + tristate "Support for thermal mgmnt on laptops with ADT 746x chipset" depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64 help This driver provides some thermostat and fan control for the diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile --- a/drivers/macintosh/Makefile Sat Apr 3 19:38:55 2004 +++ b/drivers/macintosh/Makefile Sat Apr 3 19:38:55 2004 @@ -25,4 +25,4 @@ obj-$(CONFIG_THERM_PM72) += therm_pm72.o obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o -obj-$(CONFIG_THERM_ADT7467) += therm_adt7467.o +obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c --- a/drivers/macintosh/adbhid.c Sat Apr 3 19:38:57 2004 +++ b/drivers/macintosh/adbhid.c Sat Apr 3 19:38:57 2004 @@ -107,7 +107,6 @@ static void adbhid_probe(void); static void adbhid_input_keycode(int, int, int, struct pt_regs *); -static void leds_done(struct adb_request *); static void init_trackpad(int id); static void init_trackball(int id); @@ -446,24 +445,54 @@ static struct adb_request led_request; static int leds_pending[16]; +static int leds_req_pending; static int pending_devs[16]; static int pending_led_start=0; static int pending_led_end=0; +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +static void leds_done(struct adb_request *req) +{ + int leds, device; + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + } else + leds_req_pending = 0; + + spin_unlock_irqrestore(&leds_lock, flags); + if (leds_req_pending) + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); +} static void real_leds(unsigned char leds, int device) { - if (led_request.complete) { - adb_request(&led_request, leds_done, 0, 3, - ADB_WRITEREG(device, KEYB_LEDREG), 0xff, - ~leds); - } else { - if (!(leds_pending[device] & 0x100)) { - pending_devs[pending_led_end] = device; - pending_led_end++; - pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + if (!leds_req_pending) { + leds_req_pending = 1; + spin_unlock_irqrestore(&leds_lock, flags); + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds); + return; + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; } - leds_pending[device] = leds | 0x100; - } + spin_unlock_irqrestore(&leds_lock, flags); } /* @@ -487,21 +516,6 @@ return -1; } -static void leds_done(struct adb_request *req) -{ - int leds,device; - - if (pending_led_start != pending_led_end) { - device = pending_devs[pending_led_start]; - leds = leds_pending[device] & 0xff; - leds_pending[device] = 0; - pending_led_start++; - pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; - real_leds(leds,device); - } - -} - static int adb_message_handler(struct notifier_block *this, unsigned long code, void *x) { @@ -518,7 +532,7 @@ } /* Stop pending led requests */ - while(!led_request.complete) + while(leds_req_pending) adb_poll(); break; diff -Nru a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c --- a/drivers/macintosh/mediabay.c Sat Apr 3 19:38:42 2004 +++ b/drivers/macintosh/mediabay.c Sat Apr 3 19:38:42 2004 @@ -10,8 +10,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -21,7 +19,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/macintosh/therm_adt7467.c b/drivers/macintosh/therm_adt7467.c --- a/drivers/macintosh/therm_adt7467.c Sat Apr 3 19:38:54 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,562 +0,0 @@ -/* - * Device driver for the i2c thermostat found on the iBook G4, Albook G4 - * - * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt - * - * Documentation from - * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf - * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG - -#define CONFIG_REG 0x40 -#define MANUAL_MASK 0xe0 -#define AUTO_MASK 0x20 - -static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, cpu, gpu */ -static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */ -static u8 MANUAL_MODE[2] = {0x5c, 0x5d}; -static u8 REM_CONTROL[2] = {0x00, 0x40}; -static u8 FAN_SPEED[2] = {0x28, 0x2a}; -static u8 FAN_SPD_SET[2] = {0x30, 0x31}; - -static u8 default_limits_local[3] = {70, 50, 70}; /* local, cpu, gpu */ -static u8 default_limits_chip[3] = {80, 65, 80}; /* local, cpu, gpu */ - -static int limit_adjust = 0; -static int fan_speed = -1; - -MODULE_AUTHOR("Colin Leroy "); -MODULE_DESCRIPTION("Driver for ADT7467 thermostat in iBook G4"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(limit_adjust,"i"); -MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C."); -MODULE_PARM(fan_speed,"i"); -MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)"); - -struct thermostat { - struct i2c_client clt; - u8 cached_temp[3]; - u8 initial_limits[3]; - u8 limits[3]; - int last_speed[2]; - int overriding[2]; -}; - -static enum {ADT7460, ADT7467} therm_type; -static int therm_bus, therm_address; -static struct of_device * of_dev; -static struct thermostat* thermostat; -static pid_t monitor_thread_id; -static int monitor_running; -static struct completion monitor_task_compl; - -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno); -static void write_both_fan_speed(struct thermostat *th, int speed); -static void write_fan_speed(struct thermostat *th, int speed, int fan); - -static int -write_reg(struct thermostat* th, int reg, u8 data) -{ - u8 tmp[2]; - int rc; - - tmp[0] = reg; - tmp[1] = data; - rc = i2c_master_send(&th->clt, (const char *)tmp, 2); - if (rc < 0) - return rc; - if (rc != 2) - return -ENODEV; - return 0; -} - -static int -read_reg(struct thermostat* th, int reg) -{ - u8 reg_addr, data; - int rc; - - reg_addr = (u8)reg; - rc = i2c_master_send(&th->clt, ®_addr, 1); - if (rc < 0) - return rc; - if (rc != 1) - return -ENODEV; - rc = i2c_master_recv(&th->clt, (char *)&data, 1); - if (rc < 0) - return rc; - return data; -} - -static int -attach_thermostat(struct i2c_adapter *adapter) -{ - unsigned long bus_no; - - if (strncmp(adapter->name, "uni-n", 5)) - return -ENODEV; - bus_no = simple_strtoul(adapter->name + 6, NULL, 10); - if (bus_no != therm_bus) - return -ENODEV; - return attach_one_thermostat(adapter, therm_address, bus_no); -} - -static int -detach_thermostat(struct i2c_adapter *adapter) -{ - struct thermostat* th; - int i; - - if (thermostat == NULL) - return 0; - - th = thermostat; - - if (monitor_running) { - monitor_running = 0; - wait_for_completion(&monitor_task_compl); - } - - printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d," - " to %d, %d, %d, (°C)\n", - th->limits[0], th->limits[1], th->limits[2], - th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]); - - for (i = 0; i < 3; i++) - write_reg(th, LIMIT_REG[i], th->initial_limits[i]); - - write_both_fan_speed(th, -1); - - i2c_detach_client(&th->clt); - - thermostat = NULL; - - kfree(th); - - return 0; -} - -static struct i2c_driver thermostat_driver = { - .name ="Apple Thermostat ADT7467", - .id =0xDEAD7467, - .flags =I2C_DF_NOTIFY, - .attach_adapter =&attach_thermostat, - .detach_adapter =&detach_thermostat, -}; - -static int read_fan_speed(struct thermostat *th, u8 addr) -{ - u8 tmp[2]; - u16 res; - - /* should start with low byte */ - tmp[1] = read_reg(th, addr); - tmp[0] = read_reg(th, addr + 1); - - res = tmp[1] + (tmp[0] << 8); - return (90000*60)/res; -} - -static void write_both_fan_speed(struct thermostat *th, int speed) -{ - write_fan_speed(th, speed, 0); - if (therm_type == ADT7460) - write_fan_speed(th, speed, 1); -} - -static void write_fan_speed(struct thermostat *th, int speed, int fan) -{ - u8 manual; - - if (speed > 0xff) - speed = 0xff; - else if (speed < -1) - speed = 0; - - if (therm_type == ADT7467 && fan == 1) - return; - - if (th->last_speed[fan] != speed) { - if (speed == -1) - printk(KERN_INFO "adt746x: Setting speed to: automatic for %s fan.\n", - fan?"GPU":"CPU"); - else - printk(KERN_INFO "adt746x: Setting speed to: %d for %s fan.\n", - speed, fan?"GPU":"CPU"); - } else - return; - - if (speed >= 0) { - manual = read_reg(th, MANUAL_MODE[fan]); - write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK); - write_reg(th, FAN_SPD_SET[fan], speed); - } else { - /* back to automatic */ - if(therm_type == ADT7460) { - manual = read_reg(th, MANUAL_MODE[fan]) & (~MANUAL_MASK); - write_reg(th, MANUAL_MODE[fan], manual|REM_CONTROL[fan]); - } else { - manual = read_reg(th, MANUAL_MODE[fan]); - write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK)); - } - } - - th->last_speed[fan] = speed; -} - -static int monitor_task(void *arg) -{ - struct thermostat* th = arg; - u8 temps[3]; - u8 lims[3]; - int i; -#ifdef DEBUG - int mfan_speed; -#endif - - lock_kernel(); - daemonize("kfand"); - unlock_kernel(); - strcpy(current->comm, "thermostat"); - monitor_running = 1; - - while(monitor_running) - { - set_task_state(current, TASK_UNINTERRUPTIBLE); - schedule_timeout(2*HZ); - - /* Check status */ - /* local : chip */ - /* remote 1: CPU ?*/ - /* remote 2: GPU ?*/ -#ifndef DEBUG - if (fan_speed != -1) { -#endif - for (i = 0; i < 3; i++) { - temps[i] = read_reg(th, TEMP_REG[i]); - lims[i] = th->limits[i]; - } -#ifndef DEBUG - } -#endif - if (fan_speed != -1) { - int lastvar = 0; /* for iBook */ - for (i = 1; i < 3; i++) { /* we don't care about local sensor */ - int started = 0; - int fan_number = (therm_type == ADT7460 && i == 2); - int var = temps[i] - lims[i]; - if (var > 8) { - if (th->overriding[fan_number] == 0) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n", - var, fan_number?"GPU":"CPU"); - th->overriding[fan_number] = 1; - write_fan_speed(th, 255, fan_number); - started = 1; - } else if ((!th->overriding[fan_number] || var < 6) && var > 0) { - if (th->overriding[fan_number] == 1) - printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n", - var, fan_number?"GPU":"CPU"); - th->overriding[fan_number] = 0; - write_fan_speed(th, fan_speed, fan_number); - started = 1; - } else if (var < -1) { - /* don't stop iBook fan if GPU is cold and CPU is not - * so cold (lastvar >= -1) */ - if (therm_type == ADT7460 || lastvar < -1 || i == 1) { - if (th->last_speed[fan_number] != 0) - printk(KERN_INFO "adt746x: Stopping %s fan.\n", - fan_number?"GPU":"CPU"); - write_fan_speed(th, 0, fan_number); - } - } - - lastvar = var; - - if (started && therm_type == ADT7467) - break; /* we don't want to re-stop the fan - * if CPU is heating and GPU is not */ - } - } -#ifdef DEBUG - mfan_speed = read_fan_speed(th, FAN_SPEED[0]); - /* only one fan in the iBook G4 */ - - if (temps[0] != th->cached_temp[0] - || temps[1] != th->cached_temp[1] - || temps[2] != th->cached_temp[2]) { - printk(KERN_INFO "adt746x: Temperature infos:" - " thermostats: %d,%d,%d °C;" - " limits: %d,%d,%d °C;" - " fan speed: %d RPM\n", - temps[0], temps[1], temps[2], - lims[0], lims[1], lims[2], - mfan_speed); - } - th->cached_temp[0] = temps[0]; - th->cached_temp[1] = temps[1]; - th->cached_temp[2] = temps[2]; -#endif - } - - complete_and_exit(&monitor_task_compl, 0); - return 0; -} - -static void -set_limit(struct thermostat *th, int i) -{ - /* Set CPU limit higher to avoid powerdowns */ - th->limits[i] = default_limits_chip[i] + limit_adjust; - write_reg(th, LIMIT_REG[i], th->limits[i]); - - /* set our limits to normal */ - th->limits[i] = default_limits_local[i] + limit_adjust; -} - -static int -attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno) -{ - struct thermostat* th; - int rc; - int i; - - if (thermostat) - return 0; - th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL); - if (!th) - return -ENOMEM; - memset(th, 0, sizeof(*th)); - th->clt.addr = addr; - th->clt.adapter = adapter; - th->clt.driver = &thermostat_driver; - th->clt.id = 0xDEAD7467; - strcpy(th->clt.name, "thermostat"); - - rc = read_reg(th, 0); - if (rc < 0) { - printk(KERN_ERR "adt746x: Thermostat failed to read config from bus %d !\n", - busno); - kfree(th); - return -ENODEV; - } - /* force manual control to start the fan quieter */ - - if (fan_speed == -1) - fan_speed=128; - - if(therm_type == ADT7460) { - printk(KERN_INFO "adt746x: ADT7460 initializing\n"); - /* The 7460 needs to be started explicitly */ - write_reg(th, CONFIG_REG, 1); - } else - printk(KERN_INFO "adt746x: ADT7467 initializing\n"); - - for (i = 0; i < 3; i++) { - th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); - set_limit(th, i); - } - - printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" - " to %d, %d, %d (°C)\n", - th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], - th->limits[0], th->limits[1], th->limits[2]); - - thermostat = th; - - if (i2c_attach_client(&th->clt)) { - printk("adt746x: Thermostat failed to attach client !\n"); - thermostat = NULL; - kfree(th); - return -ENODEV; - } - - /* be sure to really write fan speed the first time */ - th->last_speed[0] = -2; - th->last_speed[1] = -2; - - if (fan_speed != -1) { - write_both_fan_speed(th, 0); - } else { - write_both_fan_speed(th, -1); - } - - init_completion(&monitor_task_compl); - - monitor_thread_id = kernel_thread(monitor_task, th, - SIGCHLD | CLONE_KERNEL); - - return 0; -} - -/* - * Now, unfortunately, sysfs doesn't give us a nice void * we could - * pass around to the attribute functions, so we don't really have - * choice but implement a bunch of them... - * - */ -#define BUILD_SHOW_FUNC_DEG(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - return sprintf(buf, "%d°C\n", data); \ -} -#define BUILD_SHOW_FUNC_INT(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - return sprintf(buf, "%d\n", data); \ -} - -#define BUILD_STORE_FUNC_DEG(name, data) \ -static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ -{ \ - int val; \ - int i; \ - val = simple_strtol(buf, NULL, 10); \ - printk(KERN_INFO "Adjusting limits by %d°C\n", val); \ - limit_adjust = val; \ - for (i=0; i < 3; i++) \ - set_limit(thermostat, i); \ - return n; \ -} - -#define BUILD_STORE_FUNC_INT(name, data) \ -static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ -{ \ - u32 val; \ - val = simple_strtoul(buf, NULL, 10); \ - if (val < 0 || val > 255) \ - return -EINVAL; \ - printk(KERN_INFO "Setting fan speed to %d\n", val); \ - data = val; \ - return n; \ -} - -BUILD_SHOW_FUNC_DEG(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) -BUILD_SHOW_FUNC_DEG(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) -BUILD_SHOW_FUNC_DEG(cpu_limit, thermostat->limits[1]) -BUILD_SHOW_FUNC_DEG(gpu_limit, thermostat->limits[2]) - -BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) -BUILD_SHOW_FUNC_INT(cpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[0]))) -BUILD_SHOW_FUNC_INT(gpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[1]))) - -BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) -BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) -BUILD_STORE_FUNC_DEG(limit_adjust, thermostat) - -static DEVICE_ATTR(cpu_temperature, S_IRUGO, - show_cpu_temperature,NULL); -static DEVICE_ATTR(gpu_temperature, S_IRUGO, - show_gpu_temperature,NULL); -static DEVICE_ATTR(cpu_limit, S_IRUGO, - show_cpu_limit, NULL); -static DEVICE_ATTR(gpu_limit, S_IRUGO, - show_gpu_limit, NULL); - -static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, - show_specified_fan_speed,store_specified_fan_speed); - -static DEVICE_ATTR(cpu_fan_speed, S_IRUGO, - show_cpu_fan_speed, NULL); -static DEVICE_ATTR(gpu_fan_speed, S_IRUGO, - show_gpu_fan_speed, NULL); - -static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, - show_limit_adjust, store_limit_adjust); - - -static int __init -thermostat_init(void) -{ - struct device_node* np; - u32 *prop; - - /* Currently, we only deal with the iBook G4, we will support - * all "2003" powerbooks later on - */ - np = of_find_node_by_name(NULL, "fan"); - if (!np) - return -ENODEV; - if (device_is_compatible(np, "adt7460")) - therm_type = ADT7460; - else if (device_is_compatible(np, "adt7467")) - therm_type = ADT7467; - else - return -ENODEV; - - prop = (u32 *)get_property(np, "reg", NULL); - if (!prop) - return -ENODEV; - therm_bus = ((*prop) >> 8) & 0x0f; - therm_address = ((*prop) & 0xff) >> 1; - - printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, limit_adjust: %d, fan_speed: %d\n", - therm_bus, therm_address, limit_adjust, fan_speed); - - of_dev = of_platform_device_create(np, "temperatures"); - - if (of_dev == NULL) { - printk(KERN_ERR "Can't register temperatures device !\n"); - return -ENODEV; - } - - device_create_file(&of_dev->dev, &dev_attr_cpu_temperature); - device_create_file(&of_dev->dev, &dev_attr_gpu_temperature); - device_create_file(&of_dev->dev, &dev_attr_cpu_limit); - device_create_file(&of_dev->dev, &dev_attr_gpu_limit); - device_create_file(&of_dev->dev, &dev_attr_limit_adjust); - device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed); - device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed); - if(therm_type == ADT7460) - device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed); - -#ifndef CONFIG_I2C_KEYWEST - request_module("i2c-keywest"); -#endif - - return i2c_add_driver(&thermostat_driver); -} - -static void __exit -thermostat_exit(void) -{ - if (of_dev) { - device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature); - device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature); - device_remove_file(&of_dev->dev, &dev_attr_cpu_limit); - device_remove_file(&of_dev->dev, &dev_attr_gpu_limit); - device_remove_file(&of_dev->dev, &dev_attr_limit_adjust); - device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed); - device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed); - if(therm_type == ADT7460) - device_remove_file(&of_dev->dev, &dev_attr_gpu_fan_speed); - of_device_unregister(of_dev); - } - i2c_del_driver(&thermostat_driver); -} - -module_init(thermostat_init); -module_exit(thermostat_exit); diff -Nru a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/macintosh/therm_adt746x.c Sat Apr 3 19:38:54 2004 @@ -0,0 +1,559 @@ +/* + * Device driver for the i2c thermostat found on the iBook G4, Albook G4 + * + * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt + * + * Documentation from + * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf + * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#define CONFIG_REG 0x40 +#define MANUAL_MASK 0xe0 +#define AUTO_MASK 0x20 + +static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, cpu, gpu */ +static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */ +static u8 MANUAL_MODE[2] = {0x5c, 0x5d}; +static u8 REM_CONTROL[2] = {0x00, 0x40}; +static u8 FAN_SPEED[2] = {0x28, 0x2a}; +static u8 FAN_SPD_SET[2] = {0x30, 0x31}; + +static u8 default_limits_local[3] = {70, 50, 70}; /* local, cpu, gpu */ +static u8 default_limits_chip[3] = {80, 65, 80}; /* local, cpu, gpu */ + +static int limit_adjust = 0; +static int fan_speed = -1; + +MODULE_AUTHOR("Colin Leroy "); +MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and Powerbook G4 Alu"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(limit_adjust,"i"); +MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C."); +MODULE_PARM(fan_speed,"i"); +MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)"); + +struct thermostat { + struct i2c_client clt; + u8 cached_temp[3]; + u8 initial_limits[3]; + u8 limits[3]; + int last_speed[2]; + int overriding[2]; +}; + +static enum {ADT7460, ADT7467} therm_type; +static int therm_bus, therm_address; +static struct of_device * of_dev; +static struct thermostat* thermostat; +static pid_t monitor_thread_id; +static int monitor_running; +static struct completion monitor_task_compl; + +static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno); +static void write_both_fan_speed(struct thermostat *th, int speed); +static void write_fan_speed(struct thermostat *th, int speed, int fan); + +static int +write_reg(struct thermostat* th, int reg, u8 data) +{ + u8 tmp[2]; + int rc; + + tmp[0] = reg; + tmp[1] = data; + rc = i2c_master_send(&th->clt, (const char *)tmp, 2); + if (rc < 0) + return rc; + if (rc != 2) + return -ENODEV; + return 0; +} + +static int +read_reg(struct thermostat* th, int reg) +{ + u8 reg_addr, data; + int rc; + + reg_addr = (u8)reg; + rc = i2c_master_send(&th->clt, ®_addr, 1); + if (rc < 0) + return rc; + if (rc != 1) + return -ENODEV; + rc = i2c_master_recv(&th->clt, (char *)&data, 1); + if (rc < 0) + return rc; + return data; +} + +static int +attach_thermostat(struct i2c_adapter *adapter) +{ + unsigned long bus_no; + + if (strncmp(adapter->name, "uni-n", 5)) + return -ENODEV; + bus_no = simple_strtoul(adapter->name + 6, NULL, 10); + if (bus_no != therm_bus) + return -ENODEV; + return attach_one_thermostat(adapter, therm_address, bus_no); +} + +static int +detach_thermostat(struct i2c_adapter *adapter) +{ + struct thermostat* th; + int i; + + if (thermostat == NULL) + return 0; + + th = thermostat; + + if (monitor_running) { + monitor_running = 0; + wait_for_completion(&monitor_task_compl); + } + + printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d," + " to %d, %d, %d, (°C)\n", + th->limits[0], th->limits[1], th->limits[2], + th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]); + + for (i = 0; i < 3; i++) + write_reg(th, LIMIT_REG[i], th->initial_limits[i]); + + write_both_fan_speed(th, -1); + + i2c_detach_client(&th->clt); + + thermostat = NULL; + + kfree(th); + + return 0; +} + +static struct i2c_driver thermostat_driver = { + .name ="Apple Thermostat ADT746x", + .id =0xDEAD7467, + .flags =I2C_DF_NOTIFY, + .attach_adapter =&attach_thermostat, + .detach_adapter =&detach_thermostat, +}; + +static int read_fan_speed(struct thermostat *th, u8 addr) +{ + u8 tmp[2]; + u16 res; + + /* should start with low byte */ + tmp[1] = read_reg(th, addr); + tmp[0] = read_reg(th, addr + 1); + + res = tmp[1] + (tmp[0] << 8); + return (90000*60)/res; +} + +static void write_both_fan_speed(struct thermostat *th, int speed) +{ + write_fan_speed(th, speed, 0); + if (therm_type == ADT7460) + write_fan_speed(th, speed, 1); +} + +static void write_fan_speed(struct thermostat *th, int speed, int fan) +{ + u8 manual; + + if (speed > 0xff) + speed = 0xff; + else if (speed < -1) + speed = 0; + + if (therm_type == ADT7467 && fan == 1) + return; + + if (th->last_speed[fan] != speed) { + if (speed == -1) + printk(KERN_INFO "adt746x: Setting speed to: automatic for %s fan.\n", + fan?"GPU":"CPU"); + else + printk(KERN_INFO "adt746x: Setting speed to: %d for %s fan.\n", + speed, fan?"GPU":"CPU"); + } else + return; + + if (speed >= 0) { + manual = read_reg(th, MANUAL_MODE[fan]); + write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK); + write_reg(th, FAN_SPD_SET[fan], speed); + } else { + /* back to automatic */ + if(therm_type == ADT7460) { + manual = read_reg(th, MANUAL_MODE[fan]) & (~MANUAL_MASK); + write_reg(th, MANUAL_MODE[fan], manual|REM_CONTROL[fan]); + } else { + manual = read_reg(th, MANUAL_MODE[fan]); + write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK)); + } + } + + th->last_speed[fan] = speed; +} + +static int monitor_task(void *arg) +{ + struct thermostat* th = arg; + u8 temps[3]; + u8 lims[3]; + int i; +#ifdef DEBUG + int mfan_speed; +#endif + + lock_kernel(); + daemonize("kfand"); + unlock_kernel(); + strcpy(current->comm, "thermostat"); + monitor_running = 1; + + while(monitor_running) + { + set_task_state(current, TASK_UNINTERRUPTIBLE); + schedule_timeout(2*HZ); + + /* Check status */ + /* local : chip */ + /* remote 1: CPU ?*/ + /* remote 2: GPU ?*/ +#ifndef DEBUG + if (fan_speed != -1) { +#endif + for (i = 0; i < 3; i++) { + temps[i] = read_reg(th, TEMP_REG[i]); + lims[i] = th->limits[i]; + } +#ifndef DEBUG + } +#endif + if (fan_speed != -1) { + int lastvar = 0; /* for iBook */ + for (i = 1; i < 3; i++) { /* we don't care about local sensor */ + int started = 0; + int fan_number = (therm_type == ADT7460 && i == 2); + int var = temps[i] - lims[i]; + if (var > 8) { + if (th->overriding[fan_number] == 0) + printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n", + var, fan_number?"GPU":"CPU"); + th->overriding[fan_number] = 1; + write_fan_speed(th, 255, fan_number); + started = 1; + } else if ((!th->overriding[fan_number] || var < 6) && var > 0) { + if (th->overriding[fan_number] == 1) + printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n", + var, fan_number?"GPU":"CPU"); + th->overriding[fan_number] = 0; + write_fan_speed(th, fan_speed, fan_number); + started = 1; + } else if (var < -1) { + /* don't stop iBook fan if GPU is cold and CPU is not + * so cold (lastvar >= -1) */ + if (therm_type == ADT7460 || lastvar < -1 || i == 1) { + if (th->last_speed[fan_number] != 0) + printk(KERN_INFO "adt746x: Stopping %s fan.\n", + fan_number?"GPU":"CPU"); + write_fan_speed(th, 0, fan_number); + } + } + + lastvar = var; + + if (started && therm_type == ADT7467) + break; /* we don't want to re-stop the fan + * if CPU is heating and GPU is not */ + } + } +#ifdef DEBUG + mfan_speed = read_fan_speed(th, FAN_SPEED[0]); + /* only one fan in the iBook G4 */ + + if (temps[0] != th->cached_temp[0] + || temps[1] != th->cached_temp[1] + || temps[2] != th->cached_temp[2]) { + printk(KERN_INFO "adt746x: Temperature infos:" + " thermostats: %d,%d,%d °C;" + " limits: %d,%d,%d °C;" + " fan speed: %d RPM\n", + temps[0], temps[1], temps[2], + lims[0], lims[1], lims[2], + mfan_speed); + } + th->cached_temp[0] = temps[0]; + th->cached_temp[1] = temps[1]; + th->cached_temp[2] = temps[2]; +#endif + } + + complete_and_exit(&monitor_task_compl, 0); + return 0; +} + +static void +set_limit(struct thermostat *th, int i) +{ + /* Set CPU limit higher to avoid powerdowns */ + th->limits[i] = default_limits_chip[i] + limit_adjust; + write_reg(th, LIMIT_REG[i], th->limits[i]); + + /* set our limits to normal */ + th->limits[i] = default_limits_local[i] + limit_adjust; +} + +static int +attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno) +{ + struct thermostat* th; + int rc; + int i; + + if (thermostat) + return 0; + th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL); + if (!th) + return -ENOMEM; + memset(th, 0, sizeof(*th)); + th->clt.addr = addr; + th->clt.adapter = adapter; + th->clt.driver = &thermostat_driver; + th->clt.id = 0xDEAD7467; + strcpy(th->clt.name, "thermostat"); + + rc = read_reg(th, 0); + if (rc < 0) { + printk(KERN_ERR "adt746x: Thermostat failed to read config from bus %d !\n", + busno); + kfree(th); + return -ENODEV; + } + /* force manual control to start the fan quieter */ + + if (fan_speed == -1) + fan_speed=128; + + if(therm_type == ADT7460) { + printk(KERN_INFO "adt746x: ADT7460 initializing\n"); + /* The 7460 needs to be started explicitly */ + write_reg(th, CONFIG_REG, 1); + } else + printk(KERN_INFO "adt746x: ADT7467 initializing\n"); + + for (i = 0; i < 3; i++) { + th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); + set_limit(th, i); + } + + printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" + " to %d, %d, %d (°C)\n", + th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], + th->limits[0], th->limits[1], th->limits[2]); + + thermostat = th; + + if (i2c_attach_client(&th->clt)) { + printk("adt746x: Thermostat failed to attach client !\n"); + thermostat = NULL; + kfree(th); + return -ENODEV; + } + + /* be sure to really write fan speed the first time */ + th->last_speed[0] = -2; + th->last_speed[1] = -2; + + if (fan_speed != -1) { + write_both_fan_speed(th, 0); + } else { + write_both_fan_speed(th, -1); + } + + init_completion(&monitor_task_compl); + + monitor_thread_id = kernel_thread(monitor_task, th, + SIGCHLD | CLONE_KERNEL); + + return 0; +} + +/* + * Now, unfortunately, sysfs doesn't give us a nice void * we could + * pass around to the attribute functions, so we don't really have + * choice but implement a bunch of them... + * + */ +#define BUILD_SHOW_FUNC_DEG(name, data) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%d°C\n", data); \ +} +#define BUILD_SHOW_FUNC_INT(name, data) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%d\n", data); \ +} + +#define BUILD_STORE_FUNC_DEG(name, data) \ +static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ +{ \ + int val; \ + int i; \ + val = simple_strtol(buf, NULL, 10); \ + printk(KERN_INFO "Adjusting limits by %d°C\n", val); \ + limit_adjust = val; \ + for (i=0; i < 3; i++) \ + set_limit(thermostat, i); \ + return n; \ +} + +#define BUILD_STORE_FUNC_INT(name, data) \ +static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ +{ \ + u32 val; \ + val = simple_strtoul(buf, NULL, 10); \ + if (val < 0 || val > 255) \ + return -EINVAL; \ + printk(KERN_INFO "Setting fan speed to %d\n", val); \ + data = val; \ + return n; \ +} + +BUILD_SHOW_FUNC_DEG(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) +BUILD_SHOW_FUNC_DEG(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) +BUILD_SHOW_FUNC_DEG(cpu_limit, thermostat->limits[1]) +BUILD_SHOW_FUNC_DEG(gpu_limit, thermostat->limits[2]) + +BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) +BUILD_SHOW_FUNC_INT(cpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[0]))) +BUILD_SHOW_FUNC_INT(gpu_fan_speed, (read_fan_speed(thermostat, FAN_SPEED[1]))) + +BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) +BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) +BUILD_STORE_FUNC_DEG(limit_adjust, thermostat) + +static DEVICE_ATTR(cpu_temperature, S_IRUGO, + show_cpu_temperature,NULL); +static DEVICE_ATTR(gpu_temperature, S_IRUGO, + show_gpu_temperature,NULL); +static DEVICE_ATTR(cpu_limit, S_IRUGO, + show_cpu_limit, NULL); +static DEVICE_ATTR(gpu_limit, S_IRUGO, + show_gpu_limit, NULL); + +static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + show_specified_fan_speed,store_specified_fan_speed); + +static DEVICE_ATTR(cpu_fan_speed, S_IRUGO, + show_cpu_fan_speed, NULL); +static DEVICE_ATTR(gpu_fan_speed, S_IRUGO, + show_gpu_fan_speed, NULL); + +static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + show_limit_adjust, store_limit_adjust); + + +static int __init +thermostat_init(void) +{ + struct device_node* np; + u32 *prop; + + np = of_find_node_by_name(NULL, "fan"); + if (!np) + return -ENODEV; + if (device_is_compatible(np, "adt7460")) + therm_type = ADT7460; + else if (device_is_compatible(np, "adt7467")) + therm_type = ADT7467; + else + return -ENODEV; + + prop = (u32 *)get_property(np, "reg", NULL); + if (!prop) + return -ENODEV; + therm_bus = ((*prop) >> 8) & 0x0f; + therm_address = ((*prop) & 0xff) >> 1; + + printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, limit_adjust: %d, fan_speed: %d\n", + therm_bus, therm_address, limit_adjust, fan_speed); + + of_dev = of_platform_device_create(np, "temperatures"); + + if (of_dev == NULL) { + printk(KERN_ERR "Can't register temperatures device !\n"); + return -ENODEV; + } + + device_create_file(&of_dev->dev, &dev_attr_cpu_temperature); + device_create_file(&of_dev->dev, &dev_attr_gpu_temperature); + device_create_file(&of_dev->dev, &dev_attr_cpu_limit); + device_create_file(&of_dev->dev, &dev_attr_gpu_limit); + device_create_file(&of_dev->dev, &dev_attr_limit_adjust); + device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed); + device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed); + if(therm_type == ADT7460) + device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed); + +#ifndef CONFIG_I2C_KEYWEST + request_module("i2c-keywest"); +#endif + + return i2c_add_driver(&thermostat_driver); +} + +static void __exit +thermostat_exit(void) +{ + if (of_dev) { + device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature); + device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature); + device_remove_file(&of_dev->dev, &dev_attr_cpu_limit); + device_remove_file(&of_dev->dev, &dev_attr_gpu_limit); + device_remove_file(&of_dev->dev, &dev_attr_limit_adjust); + device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed); + device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed); + if(therm_type == ADT7460) + device_remove_file(&of_dev->dev, &dev_attr_gpu_fan_speed); + of_device_unregister(of_dev); + } + i2c_del_driver(&thermostat_driver); +} + +module_init(thermostat_init); +module_exit(thermostat_exit); diff -Nru a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c --- a/drivers/macintosh/therm_pm72.c Sat Apr 3 19:38:54 2004 +++ b/drivers/macintosh/therm_pm72.c Sat Apr 3 19:38:54 2004 @@ -2,7 +2,7 @@ * Device driver for the thermostats & fan controller of the * Apple G5 "PowerMac7,2" desktop machines. * - * (c) Copyright IBM Corp. 2003 + * (c) Copyright IBM Corp. 2003-2004 * * Maintained by: Benjamin Herrenschmidt * @@ -45,7 +45,7 @@ * - Add things like /sbin/overtemp for non-critical * overtemp conditions so userland can take some policy * decisions, like slewing down CPUs - * - Deal with fan failures + * - Deal with fan and i2c failures in a better way * * History: * @@ -63,9 +63,16 @@ * - Move back statics definitions to .c file * - Avoid calling schedule_timeout with a negative number * - * Dev. 18, 2003 : 0.8 + * Dec. 18, 2003 : 0.8 * - Fix typo when reading back fan speed on 2 CPU machines * + * Mar. 11, 2004 : 0.9 + * - Rework code accessing the ADC chips, make it more robust and + * closer to the chip spec. Also make sure it is configured properly, + * I've seen yet unexplained cases where on startup, I would have stale + * values in the configuration register + * - Switch back to use of target fan speed for PID, thus lowering + * pressure on i2c */ #include @@ -94,14 +101,14 @@ #include "therm_pm72.h" -#define VERSION "0.8" +#define VERSION "0.9" #undef DEBUG #ifdef DEBUG #define DBG(args...) printk(args) #else -#define DBG(args...) +#define DBG(args...) do { } while(0) #endif @@ -194,14 +201,76 @@ /* * Here are the i2c chip access wrappers */ -static int read_smon_adc(struct i2c_client *chip, int chan) + +static void initialize_adc(struct cpu_pid_state *state) +{ + int rc; + u8 buf[2]; + + /* Read ADC the configuration register and cache it. We + * also make sure Config2 contains proper values, I've seen + * cases where we got stale grabage in there, thus preventing + * proper reading of conv. values + */ + + /* Clear Config2 */ + buf[0] = 5; + buf[1] = 0; + i2c_master_send(state->monitor, buf, 2); + + /* Read & cache Config1 */ + buf[0] = 1; + rc = i2c_master_send(state->monitor, buf, 1); + if (rc > 0) { + rc = i2c_master_recv(state->monitor, buf, 1); + if (rc > 0) { + state->adc_config = buf[0]; + DBG("ADC config reg: %02x\n", state->adc_config); + /* Disable shutdown mode */ + state->adc_config &= 0xfe; + buf[0] = 1; + buf[1] = state->adc_config; + rc = i2c_master_send(state->monitor, buf, 2); + } + } + if (rc <= 0) + printk(KERN_ERR "therm_pm72: Error reading ADC config" + " register !\n"); +} + +static int read_smon_adc(struct cpu_pid_state *state, int chan) { - int ctrl; + int rc, data, tries = 0; + u8 buf[2]; - ctrl = i2c_smbus_read_byte_data(chip, 1); - i2c_smbus_write_byte_data(chip, 1, (ctrl & 0x1f) | (chan << 5)); - wait_ms(1); - return le16_to_cpu(i2c_smbus_read_word_data(chip, 4)) >> 6; + for (;;) { + /* Set channel */ + buf[0] = 1; + buf[1] = (state->adc_config & 0x1f) | (chan << 5); + rc = i2c_master_send(state->monitor, buf, 2); + if (rc <= 0) + goto error; + /* Wait for convertion */ + wait_ms(1); + /* Switch to data register */ + buf[0] = 4; + rc = i2c_master_send(state->monitor, buf, 1); + if (rc <= 0) + goto error; + /* Read result */ + rc = i2c_master_recv(state->monitor, buf, 2); + if (rc < 0) + goto error; + data = ((u16)buf[0]) << 8 | (u16)buf[1]; + return data >> 6; + error: + DBG("Error reading ADC, retrying...\n"); + if (++tries > 10) { + printk(KERN_ERR "therm_pm72: Error reading ADC !\n"); + return -1; + } + wait_ms(10); + } } static int fan_read_reg(int reg, unsigned char *buf, int nb) @@ -460,9 +529,13 @@ DBG(" current rpm: %d\n", state->rpm); /* Get some sensor readings and scale it */ - temp = read_smon_adc(state->monitor, 1); - voltage = read_smon_adc(state->monitor, 3); - current_a = read_smon_adc(state->monitor, 4); + temp = read_smon_adc(state, 1); + if (temp == -1) { + state->overtemp++; + return; + } + voltage = read_smon_adc(state, 3); + current_a = read_smon_adc(state, 4); /* Fixup temperature according to diode calibration */ @@ -476,7 +549,8 @@ * full blown immediately and try to trigger a shutdown */ if (temp >= ((state->mpu.tmax + 8) << 16)) { - printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum (%d) !\n", + printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum" + " (%d) !\n", state->index, temp >> 16); state->overtemp = CPU_MAX_OVERTEMP; } else if (temp > (state->mpu.tmax << 16)) @@ -613,6 +687,7 @@ state->first = 1; state->rpm = 1000; state->overtemp = 0; + state->adc_config = 0x00; if (index == 0) state->monitor = attach_i2c_chip(SUPPLY_MONITOR_ID, "CPU0_monitor"); @@ -941,8 +1016,17 @@ DBG("main_control_loop started\n"); + down(&driver_lock); + /* Set the PCI fan once for now */ set_pwm_fan(SLOTS_FAN_PWM_ID, SLOTS_FAN_DEFAULT_PWM); + + /* Initialize ADCs */ + initialize_adc(&cpu_state[0]); + if (cpu_state[1].monitor != NULL) + initialize_adc(&cpu_state[1]); + + up(&driver_lock); while (state == state_attached) { unsigned long elapsed, start; diff -Nru a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h --- a/drivers/macintosh/therm_pm72.h Sat Apr 3 19:38:43 2004 +++ b/drivers/macintosh/therm_pm72.h Sat Apr 3 19:38:43 2004 @@ -85,7 +85,7 @@ * I'm not sure which of these Apple's algorithm is supposed * to use */ -#define RPM_PID_USE_ACTUAL_SPEED 1 +#define RPM_PID_USE_ACTUAL_SPEED 0 /* * i2c IDs. Currently, we hard code those and assume that @@ -220,6 +220,7 @@ s32 current_a; s32 last_temp; int first; + u8 adc_config; }; /* diff -Nru a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c --- a/drivers/macintosh/therm_windtunnel.c Sat Apr 3 19:38:54 2004 +++ b/drivers/macintosh/therm_windtunnel.c Sat Apr 3 19:38:54 2004 @@ -1,24 +1,23 @@ /* * Creation Date: <2003/03/14 20:54:13 samuel> - * Time-stamp: <2003/03/15 18:55:53 samuel> + * Time-stamp: <2004/03/20 14:20:59 samuel> * * * - * The G4 "windtunnel" has a single fan controlled by a - * DS1775 fan controller and an ADM1030 thermostat. + * The G4 "windtunnel" has a single fan controlled by an + * ADM1030 fan controller and a DS1775 thermostat. * * The fan controller is equipped with a temperature sensor - * which measures the case temperature. The ADM censor + * which measures the case temperature. The DS1775 sensor * measures the CPU temperature. This driver tunes the * behavior of the fan. It is based upon empirical observations - * of the 'AppleFan' driver under OSX. + * of the 'AppleFan' driver under Mac OS X. * * WARNING: This driver has only been testen on Apple's - * 1.25 MHz Dual G4 (March 03). Other machines might have - * a different thermal design. It is tuned for a CPU + * 1.25 MHz Dual G4 (March 03). It is tuned for a CPU * temperatur around 57 C. * - * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) * * Loosely based upon 'thermostat.c' written by Benjamin Herrenschmidt * @@ -38,50 +37,37 @@ #include #include #include -#include #include #include #include #include #include - -MODULE_AUTHOR("Samuel Rydh "); -MODULE_DESCRIPTION("Apple G4 (windtunnel) fan driver"); -MODULE_LICENSE("GPL"); +#include #define LOG_TEMP 0 /* continously log temperature */ -/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END }; -static struct work_struct poll_work; - -I2C_CLIENT_INSMOD; - #define I2C_DRIVERID_G4FAN 0x9001 /* fixme */ - #define THERMOSTAT_CLIENT_ID 1 #define FAN_CLIENT_ID 2 -struct temp_range { - u8 high; /* start the fan */ - u8 low; /* stop the fan */ -}; -struct apple_thermal_info { - u8 id; /* implementation ID */ - u8 fan_count; /* number of fans */ - u8 thermostat_count; /* number of thermostats */ - u8 unused[5]; - struct temp_range ranges[4]; /* temperature ranges (may be [])*/ -}; +static int do_probe( struct i2c_adapter *adapter, int addr, int kind); -static int do_detect( struct i2c_adapter *adapter, int addr, int kind); +/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ +static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; static struct { + volatile int running; + struct completion completion; + pid_t poll_task; + + struct semaphore lock; + struct of_device *of_dev; + struct i2c_client *thermostat; struct i2c_client *fan; - int error; - struct timer_list timer; int overheat_temp; /* 100% fan at this temp */ int overheat_hyst; @@ -95,37 +81,54 @@ int r0, r1, r20, r23, r25; /* saved register */ } x; +#define T(x,y) (((x)<<8) | (y)*0x100/10 ) + static struct { + int fan_down_setting; int temp; - int fan_setting; -} fan_up_table[] = { - { 0x0000, 11 }, /* min fan */ - { 0x3900, 8 }, /* 57.0 C */ - { 0x3a4a, 7 }, /* 58.3 C */ - { 0x3ad3, 6 }, /* 58.8 C */ - { 0x3b3c, 5 }, /* 59.2 C */ - { 0x3b94, 4 }, /* 59.6 C */ - { 0x3be3, 3 }, /* 58.9 C */ - { 0x3c29, 2 }, /* 59.2 C */ - { 0xffff, 1 } /* on fire */ -}; -static struct { - int temp; - int fan_setting; -} fan_down_table[] = { - { 0x3700, 11 }, /* 55.0 C */ - { 0x374a, 6 }, - { 0x3800, 7 }, /* 56.0 C */ - { 0x3900, 8 }, /* 57.0 C */ - { 0x3a4a, 7 }, /* 58.3 C */ - { 0x3ad3, 6 }, /* 58.8 C */ - { 0x3b3c, 5 }, /* 59.2 C */ - { 0x3b94, 4 }, /* 58.9 C */ - { 0x3be3, 3 }, /* 58.9 C */ - { 0x3c29, 2 }, /* 59.2 C */ - { 0xffff, 1 } + int fan_up_setting; +} fan_table[] = { + { 11, T(0,0), 11 }, /* min fan */ + { 11, T(55,0), 11 }, + { 6, T(55,3), 11 }, + { 7, T(56,0), 11 }, + { 8, T(57,0), 8 }, + { 7, T(58,3), 7 }, + { 6, T(58,8), 6 }, + { 5, T(59,2), 5 }, + { 4, T(59,6), 4 }, + { 3, T(59,9), 3 }, + { 2, T(60,1), 2 }, + { 1, 0xfffff, 1 } /* on fire */ }; +static void +print_temp( const char *s, int temp ) +{ + printk("%s%d.%d C", s ? s : "", temp>>8, (temp & 255)*10/256 ); +} + +static ssize_t +show_cpu_temperature( struct device *dev, char *buf ) +{ + return sprintf(buf, "%d.%d\n", x.temp>>8, (x.temp & 255)*10/256 ); +} + +static ssize_t +show_case_temperature( struct device *dev, char *buf ) +{ + return sprintf(buf, "%d.%d\n", x.casetemp>>8, (x.casetemp & 255)*10/256 ); +} + +static DEVICE_ATTR(cpu_temperature, S_IRUGO, show_cpu_temperature, NULL ); +static DEVICE_ATTR(case_temperature, S_IRUGO, show_case_temperature, NULL ); + + + +/************************************************************************/ +/* controller thread */ +/************************************************************************/ + static int write_reg( struct i2c_client *cl, int reg, int data, int len ) { @@ -159,37 +162,32 @@ return (len == 2)? ((unsigned int)buf[0] << 8) | buf[1] : buf[0]; } - -static void -print_temp( const char *s, int temp ) -{ - printk("%s%d.%d C", s ? s : "", temp>>8, (temp & 255)*10/256 ); -} - static void tune_fan( int fan_setting ) { int val = (fan_setting << 3) | 7; - x.fan_level = fan_setting; - - //write_reg( x.fan, 0x24, val, 1 ); + + /* write_reg( x.fan, 0x24, val, 1 ); */ write_reg( x.fan, 0x25, val, 1 ); write_reg( x.fan, 0x20, 0, 1 ); print_temp("CPU-temp: ", x.temp ); if( x.casetemp ) print_temp(", Case: ", x.casetemp ); - printk(" Tuning fan: %d (%02x)\n", fan_setting, val ); + printk(", Fan: %d (tuned %+d)\n", 11-fan_setting, x.fan_level-fan_setting ); + + x.fan_level = fan_setting; } static void -poll_temp( void *param ) +poll_temp( void ) { - int temp = read_reg( x.thermostat, 0, 2 ); - int i, level, casetemp; + int temp, i, level, casetemp; + + temp = read_reg( x.thermostat, 0, 2 ); /* this actually occurs when the computer is loaded */ if( temp < 0 ) - goto out; + return; casetemp = read_reg(x.fan, 0x0b, 1) << 8; casetemp |= (read_reg(x.fan, 0x06, 1) & 0x7) << 5; @@ -197,37 +195,117 @@ if( LOG_TEMP && x.temp != temp ) { print_temp("CPU-temp: ", temp ); print_temp(", Case: ", casetemp ); - printk(", Fan: %d\n", x.fan_level ); + printk(", Fan: %d\n", 11-x.fan_level ); } x.temp = temp; x.casetemp = casetemp; level = -1; - for( i=0; (temp & 0xffff) > fan_down_table[i].temp ; i++ ) + for( i=0; (temp & 0xffff) > fan_table[i].temp ; i++ ) ; if( i < x.downind ) - level = fan_down_table[i].fan_setting; + level = fan_table[i].fan_down_setting; x.downind = i; - for( i=0; (temp & 0xfffe) >= fan_up_table[i+1].temp ; i++ ) + for( i=0; (temp & 0xffff) >= fan_table[i+1].temp ; i++ ) ; if( x.upind < i ) - level = fan_up_table[i].fan_setting; + level = fan_table[i].fan_up_setting; x.upind = i; if( level >= 0 ) tune_fan( level ); - out: - x.timer.expires = jiffies + 8*HZ; - add_timer( &x.timer ); +} + + +static void +setup_hardware( void ) +{ + int val; + + /* save registers (if we unload the module) */ + x.r0 = read_reg( x.fan, 0x00, 1 ); + x.r1 = read_reg( x.fan, 0x01, 1 ); + x.r20 = read_reg( x.fan, 0x20, 1 ); + x.r23 = read_reg( x.fan, 0x23, 1 ); + x.r25 = read_reg( x.fan, 0x25, 1 ); + + /* improve measurement resolution (convergence time 1.5s) */ + if( (val=read_reg(x.thermostat, 1, 1)) >= 0 ) { + val |= 0x60; + if( write_reg( x.thermostat, 1, val, 1 ) ) + printk("Failed writing config register\n"); + } + /* disable interrupts and TAC input */ + write_reg( x.fan, 0x01, 0x01, 1 ); + /* enable filter */ + write_reg( x.fan, 0x23, 0x91, 1 ); + /* remote temp. controls fan */ + write_reg( x.fan, 0x00, 0x95, 1 ); + + /* The thermostat (which besides measureing temperature controls + * has a THERM output which puts the fan on 100%) is usually + * set to kick in at 80 C (chip default). We reduce this a bit + * to be on the safe side (OSX doesn't)... + */ + if( x.overheat_temp == (80 << 8) ) { + x.overheat_temp = 65 << 8; + x.overheat_hyst = 60 << 8; + write_reg( x.thermostat, 2, x.overheat_hyst, 2 ); + write_reg( x.thermostat, 3, x.overheat_temp, 2 ); + + print_temp("Reducing overheating limit to ", x.overheat_temp ); + print_temp(" (Hyst: ", x.overheat_hyst ); + printk(")\n"); + } + + /* set an initial fan setting */ + x.downind = 0xffff; + x.upind = -1; + /* tune_fan( fan_up_table[x.upind].fan_setting ); */ + + device_create_file( &x.of_dev->dev, &dev_attr_cpu_temperature ); + device_create_file( &x.of_dev->dev, &dev_attr_case_temperature ); } static void -schedule_poll( unsigned long t ) +restore_regs( void ) { - schedule_work(&poll_work); + device_remove_file( &x.of_dev->dev, &dev_attr_cpu_temperature ); + device_remove_file( &x.of_dev->dev, &dev_attr_case_temperature ); + + write_reg( x.fan, 0x01, x.r1, 1 ); + write_reg( x.fan, 0x20, x.r20, 1 ); + write_reg( x.fan, 0x23, x.r23, 1 ); + write_reg( x.fan, 0x25, x.r25, 1 ); + write_reg( x.fan, 0x00, x.r0, 1 ); } +static int +control_loop( void *dummy ) +{ + daemonize("g4fand"); + + down( &x.lock ); + setup_hardware(); + + while( x.running ) { + up( &x.lock ); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout( 8*HZ ); + + down( &x.lock ); + poll_temp(); + } + + restore_regs(); + up( &x.lock ); + + complete_and_exit( &x.completion, 0 ); +} + + /************************************************************************/ /* i2c probing and setup */ /************************************************************************/ @@ -235,7 +313,20 @@ static int do_attach( struct i2c_adapter *adapter ) { - return i2c_probe( adapter, &addr_data, &do_detect ); + int ret = 0; + + if( strncmp(adapter->name, "uni-n", 5) ) + return 0; + + if( !x.running ) { + ret = i2c_probe( adapter, &addr_data, &do_probe ); + if( x.thermostat && x.fan ) { + x.running = 1; + init_completion( &x.completion ); + x.poll_task = kernel_thread( control_loop, NULL, SIGCHLD | CLONE_KERNEL ); + } + } + return ret; } static int @@ -243,13 +334,23 @@ { int err; - printk("do_detach: id %d\n", client->id ); - if( (err=i2c_detach_client(client)) ) { - printk("failed to detach thermostat client\n"); - return err; + if( (err=i2c_detach_client(client)) ) + printk(KERN_ERR "failed to detach thermostat client\n"); + else { + if( x.running ) { + x.running = 0; + wait_for_completion( &x.completion ); + } + if( client == x.thermostat ) + x.thermostat = NULL; + else if( client == x.fan ) + x.fan = NULL; + else { + printk(KERN_ERR "g4fan: bad client\n"); + } + kfree( client ); } - kfree( client ); - return 0; + return err; } static struct i2c_driver g4fan_driver = { @@ -262,24 +363,21 @@ }; static int -detect_fan( struct i2c_client *cl ) +attach_fan( struct i2c_client *cl ) { + if( x.fan ) + goto out; + /* check that this is an ADM1030 */ if( read_reg(cl, 0x3d, 1) != 0x30 || read_reg(cl, 0x3e, 1) != 0x41 ) goto out; - printk("ADM1030 fan controller detected at %02x\n", cl->addr ); + printk("ADM1030 fan controller [@%02x]\n", cl->addr ); - if( x.fan ) { - x.error |= 2; - goto out; - } - x.fan = cl; cl->id = FAN_CLIENT_ID; - strncpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); + strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); - if( i2c_attach_client( cl ) ) - goto out; - return 0; + if( !i2c_attach_client(cl) ) + x.fan = cl; out: if( cl != x.fan ) kfree( cl ); @@ -287,10 +385,13 @@ } static int -detect_thermostat( struct i2c_client *cl ) +attach_thermostat( struct i2c_client *cl ) { int hyst_temp, os_temp, temp; + if( x.thermostat ) + goto out; + if( (temp=read_reg(cl, 0, 2)) < 0 ) goto out; @@ -302,44 +403,37 @@ if( hyst_temp < 0 || os_temp < 0 ) goto out; - printk("DS1775 digital thermometer detected at %02x\n", cl->addr ); + printk("DS1775 digital thermometer [@%02x]\n", cl->addr ); print_temp("Temp: ", temp ); print_temp(" Hyst: ", hyst_temp ); print_temp(" OS: ", os_temp ); printk("\n"); - if( x.thermostat ) { - x.error |= 1; - goto out; - } x.temp = temp; - x.thermostat = cl; x.overheat_temp = os_temp; x.overheat_hyst = hyst_temp; cl->id = THERMOSTAT_CLIENT_ID; - strncpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); + strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); - if( i2c_attach_client( cl ) ) - goto out; - return 0; + if( !i2c_attach_client(cl) ) + x.thermostat = cl; out: - kfree( cl ); + if( cl != x.thermostat ) + kfree( cl ); return 0; } static int -do_detect( struct i2c_adapter *adapter, int addr, int kind ) +do_probe( struct i2c_adapter *adapter, int addr, int kind ) { struct i2c_client *cl; - if( strncmp(adapter->name, "uni-n", 5) ) - return 0; if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE) ) return 0; - if( !(cl=kmalloc( sizeof(struct i2c_client), GFP_KERNEL )) ) + if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) ) return -ENOMEM; memset( cl, 0, sizeof(struct i2c_client) ); @@ -349,108 +443,94 @@ cl->flags = 0; if( addr < 0x48 ) - return detect_fan( cl ); - return detect_thermostat( cl ); + return attach_fan( cl ); + return attach_thermostat( cl ); +} + + +/************************************************************************/ +/* initialization / cleanup */ +/************************************************************************/ + +static int +therm_of_probe( struct of_device *dev, const struct of_match *match ) +{ + return i2c_add_driver( &g4fan_driver ); } -#define PRINT_REG( r ) printk("reg %02x = %02x\n", r, read_reg(x.fan, r, 1) ) +static int +therm_of_remove( struct of_device *dev ) +{ + return i2c_del_driver( &g4fan_driver ); +} + +static struct of_match therm_of_match[] = {{ + .name = "fan", + .type = OF_ANY_MATCH, + .compatible = "adm1030" + }, {} +}; + +static struct of_platform_driver therm_of_driver = { + .name = "temperature", + .match_table = therm_of_match, + .probe = therm_of_probe, + .remove = therm_of_remove, +}; + +struct apple_thermal_info { + u8 id; /* implementation ID */ + u8 fan_count; /* number of fans */ + u8 thermostat_count; /* number of thermostats */ + u8 unused; +}; static int __init g4fan_init( void ) { struct apple_thermal_info *info; struct device_node *np; - int ret, val; - - np = of_find_node_by_name(NULL, "power-mgt"); - if (np == NULL) + + init_MUTEX( &x.lock ); + + if( !(np=of_find_node_by_name(NULL, "power-mgt")) ) return -ENODEV; info = (struct apple_thermal_info*)get_property(np, "thermal-info", NULL); of_node_put(np); - if (info == NULL) - return -ENODEV; - - /* check for G4 "Windtunnel" SMP */ - if( machine_is_compatible("PowerMac3,6") ) { - if( info->id != 3 ) { - printk(KERN_ERR "g4fan: design id %d unknown\n", info->id); - return -ENODEV; - } - } else { - printk(KERN_ERR "g4fan: unsupported machine type\n"); - return -ENODEV; - } - if( (ret=i2c_add_driver(&g4fan_driver)) ) - return ret; - if( !x.thermostat || !x.fan ) { - i2c_del_driver(&g4fan_driver ); + if( !info || !machine_is_compatible("PowerMac3,6") ) return -ENODEV; - } - - /* save registers (if we unload the module) */ - x.r0 = read_reg( x.fan, 0x00, 1 ); - x.r1 = read_reg( x.fan, 0x01, 1 ); - x.r20 = read_reg( x.fan, 0x20, 1 ); - x.r23 = read_reg( x.fan, 0x23, 1 ); - x.r25 = read_reg( x.fan, 0x25, 1 ); - /* improve measurement resolution (convergence time 1.5s) */ - if( (val=read_reg( x.thermostat, 1, 1 )) >= 0 ) { - val |= 0x60; - if( write_reg( x.thermostat, 1, val, 1 ) ) - printk("Failed writing config register\n"); + if( info->id != 3 ) { + printk(KERN_ERR "therm_windtunnel: unsupported thermal design %d\n", info->id ); + return -ENODEV; } - /* disable interrupts and TAC input */ - write_reg( x.fan, 0x01, 0x01, 1 ); - /* enable filter */ - write_reg( x.fan, 0x23, 0x91, 1 ); - /* remote temp. controls fan */ - write_reg( x.fan, 0x00, 0x95, 1 ); - - /* The thermostat (which besides measureing temperature controls - * has a THERM output which puts the fan on 100%) is usually - * set to kick in at 80 C (chip default). We reduce this a bit - * to be on the safe side (OSX doesn't)... - */ - if( x.overheat_temp == (80 << 8) ) { - x.overheat_temp = 65 << 8; - x.overheat_hyst = 60 << 8; - write_reg( x.thermostat, 2, x.overheat_hyst, 2 ); - write_reg( x.thermostat, 3, x.overheat_temp, 2 ); + if( !(np=of_find_node_by_name(NULL, "fan")) ) + return -ENODEV; + x.of_dev = of_platform_device_create( np, "temperature" ); + of_node_put( np ); - print_temp("Reducing overheating limit to ", x.overheat_temp ); - print_temp(" (Hyst: ", x.overheat_hyst ); - printk(")\n"); + if( !x.of_dev ) { + printk(KERN_ERR "Can't register fan controller!\n"); + return -ENODEV; } - /* set an initial fan setting */ - x.upind = x.downind = 1; - tune_fan( fan_up_table[x.upind].fan_setting ); - - INIT_WORK(&poll_work, poll_temp, NULL); - - init_timer( &x.timer ); - x.timer.expires = jiffies + 8*HZ; - x.timer.function = schedule_poll; - add_timer( &x.timer ); + of_register_driver( &therm_of_driver ); return 0; } static void __exit g4fan_exit( void ) { - del_timer( &x.timer ); + of_unregister_driver( &therm_of_driver ); - write_reg( x.fan, 0x01, x.r1, 1 ); - write_reg( x.fan, 0x20, x.r20, 1 ); - write_reg( x.fan, 0x23, x.r23, 1 ); - write_reg( x.fan, 0x25, x.r25, 1 ); - write_reg( x.fan, 0x00, x.r0, 1 ); - - i2c_del_driver( &g4fan_driver ); + if( x.of_dev ) + of_device_unregister( x.of_dev ); } module_init(g4fan_init); module_exit(g4fan_exit); +MODULE_AUTHOR("Samuel Rydh "); +MODULE_DESCRIPTION("Apple G4 (windtunnel) fan controller"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c --- a/drivers/macintosh/via-pmu.c Sat Apr 3 19:38:55 2004 +++ b/drivers/macintosh/via-pmu.c Sat Apr 3 19:38:55 2004 @@ -137,7 +137,8 @@ static int data_len; static volatile int adb_int_pending; static volatile int disable_poll; -static struct adb_request bright_req_1, bright_req_2, bright_req_3; +static struct adb_request bright_req_1, bright_req_2; +static unsigned long async_req_locks; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; @@ -404,7 +405,6 @@ bright_req_1.complete = 1; bright_req_2.complete = 1; - bright_req_3.complete = 1; #ifdef CONFIG_PMAC_PBOOK batt_req.complete = 1; if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) @@ -710,6 +710,8 @@ pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time; + + clear_bit(0, &async_req_locks); } static void __pmac @@ -785,12 +787,14 @@ pmu_batteries[pmu_cur_battery].time_remaining = 0; pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; + + clear_bit(0, &async_req_locks); } static void __pmac query_battery_state(void) { - if (!batt_req.complete) + if (test_and_set_bit(0, &async_req_locks)) return; if (pmu_kind == PMU_OHARE_BASED) pmu_request(&batt_req, done_battery_state_ohare, @@ -1690,20 +1694,30 @@ return 0; } +static void __openfirmware +pmu_bright_complete(struct adb_request *req) +{ + if (req == &bright_req_1) + clear_bit(1, &async_req_locks); + if (req == &bright_req_2) + clear_bit(2, &async_req_locks); +} + static int __openfirmware pmu_set_backlight_level(int level, void* data) { if (vias == NULL) return -ENODEV; - if (!bright_req_1.complete) + if (test_and_set_bit(1, &async_req_locks)) return -EAGAIN; - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT, backlight_to_bright[level]); - if (!bright_req_2.complete) + if (test_and_set_bit(2, &async_req_locks)) return -EAGAIN; - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT - | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); + pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ? + PMU_POW_ON : PMU_POW_OFF)); return 0; } @@ -2330,6 +2344,8 @@ return -EBUSY; } + preempt_disable(); + /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); /* Make sure any pending DEC interrupt occurring while we did @@ -2352,6 +2368,7 @@ if (ret) { wakeup_decrementer(); local_irq_enable(); + preempt_enable(); device_resume(); broadcast_wake(); printk(KERN_ERR "Driver powerdown failed\n"); @@ -2360,7 +2377,8 @@ /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete || !batt_req.complete) + + !batt_req.complete) pmu_poll(); /* Giveup the lazy FPU & vec so we don't have to back them @@ -2398,6 +2416,8 @@ pmu_blink(1); + preempt_enable(); + /* Resume devices */ device_resume(); @@ -2673,9 +2693,9 @@ mb(); pmac_wakeup_devices(); - pbook_free_pci_save(); iounmap(mem_ctrl); + return 0; } diff -Nru a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c --- a/drivers/mca/mca-bus.c Sat Apr 3 19:38:41 2004 +++ b/drivers/mca/mca-bus.c Sat Apr 3 19:38:41 2004 @@ -106,6 +106,7 @@ sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot); mca_dev->dma_mask = mca_bus->default_dma_mask; mca_dev->dev.dma_mask = &mca_dev->dma_mask; + mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask; if (device_register(&mca_dev->dev)) return 0; diff -Nru a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c --- a/drivers/md/dm-crypt.c Sat Apr 3 19:38:40 2004 +++ b/drivers/md/dm-crypt.c Sat Apr 3 19:38:40 2004 @@ -621,7 +621,8 @@ return clone; } -static int crypt_map(struct dm_target *ti, struct bio *bio) +static int crypt_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct crypt_config *cc = (struct crypt_config *) ti->private; struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO); @@ -739,6 +740,7 @@ static struct target_type crypt_target = { .name = "crypt", + .version= {1, 0, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c --- a/drivers/md/dm-ioctl.c Sat Apr 3 19:38:42 2004 +++ b/drivers/md/dm-ioctl.c Sat Apr 3 19:38:42 2004 @@ -33,6 +33,14 @@ struct dm_table *new_map; }; +struct vers_iter { + size_t param_size; + struct dm_target_versions *vers, *old_vers; + char *end; + uint32_t flags; +}; + + #define NUM_BUCKETS 64 #define MASK_BUCKETS (NUM_BUCKETS - 1) static struct list_head _name_buckets[NUM_BUCKETS]; @@ -88,30 +96,24 @@ *---------------------------------------------------------------*/ static struct hash_cell *__get_name_cell(const char *str) { - struct list_head *tmp; struct hash_cell *hc; unsigned int h = hash_str(str); - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); + list_for_each_entry (hc, _name_buckets + h, name_list) if (!strcmp(hc->name, str)) return hc; - } return NULL; } static struct hash_cell *__get_uuid_cell(const char *str) { - struct list_head *tmp; struct hash_cell *hc; unsigned int h = hash_str(str); - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); + list_for_each_entry (hc, _uuid_buckets + h, uuid_list) if (!strcmp(hc->uuid, str)) return hc; - } return NULL; } @@ -415,6 +417,80 @@ return 0; } +static void list_version_get_needed(struct target_type *tt, void *param) +{ + int *needed = param; + + *needed += strlen(tt->name); + *needed += sizeof(tt->version); + *needed += ALIGN_MASK; +} + +static void list_version_get_info(struct target_type *tt, void *param) +{ + struct vers_iter *info = param; + + /* Check space - it might have changed since the first iteration */ + if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > + info->end) { + + info->flags = DM_BUFFER_FULL_FLAG; + return; + } + + if (info->old_vers) + info->old_vers->next = (uint32_t) ((void *)info->vers - + (void *)info->old_vers); + info->vers->version[0] = tt->version[0]; + info->vers->version[1] = tt->version[1]; + info->vers->version[2] = tt->version[2]; + info->vers->next = 0; + strcpy(info->vers->name, tt->name); + + info->old_vers = info->vers; + info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1); +} + +static int list_versions(struct dm_ioctl *param, size_t param_size) +{ + size_t len, needed = 0; + struct dm_target_versions *vers; + struct vers_iter iter_info; + + /* + * Loop through all the devices working out how much + * space we need. + */ + dm_target_iterate(list_version_get_needed, &needed); + + /* + * Grab our output buffer. + */ + vers = get_result_buffer(param, param_size, &len); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + goto out; + } + param->data_size = param->data_start + needed; + + iter_info.param_size = param_size; + iter_info.old_vers = NULL; + iter_info.vers = vers; + iter_info.flags = 0; + iter_info.end = (char *)vers+len; + + /* + * Now loop through filling out the names & versions. + */ + dm_target_iterate(list_version_get_info, &iter_info); + param->flags |= iter_info.flags; + + out: + return 0; +} + + + static int check_name(const char *name) { if (strchr(name, '/')) { @@ -935,6 +1011,7 @@ unsigned int count = 0; struct list_head *tmp; size_t len, needed; + struct dm_dev *dd; struct dm_target_deps *deps; deps = get_result_buffer(param, param_size, &len); @@ -942,7 +1019,7 @@ /* * Count the devices. */ - list_for_each(tmp, dm_table_get_devices(table)) + list_for_each (tmp, dm_table_get_devices(table)) count++; /* @@ -959,10 +1036,8 @@ */ deps->count = count; count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + list_for_each_entry (dd, dm_table_get_devices(table), list) deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev); - } param->data_size = param->data_start + needed; } @@ -1045,7 +1120,9 @@ {DM_TABLE_LOAD_CMD, table_load}, {DM_TABLE_CLEAR_CMD, table_clear}, {DM_TABLE_DEPS_CMD, table_deps}, - {DM_TABLE_STATUS_CMD, table_status} + {DM_TABLE_STATUS_CMD, table_status}, + + {DM_LIST_VERSIONS_CMD, list_versions} }; return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; @@ -1119,7 +1196,9 @@ param->flags &= ~DM_BUFFER_FULL_FLAG; /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) + if (cmd == DM_REMOVE_ALL_CMD || + cmd == DM_LIST_DEVICES_CMD || + cmd == DM_LIST_VERSIONS_CMD) return 0; /* Unless creating, either name or uuid but not both */ diff -Nru a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c --- a/drivers/md/dm-linear.c Sat Apr 3 19:38:43 2004 +++ b/drivers/md/dm-linear.c Sat Apr 3 19:38:43 2004 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ @@ -65,7 +65,8 @@ kfree(lc); } -static int linear_map(struct dm_target *ti, struct bio *bio) +static int linear_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct linear_c *lc = (struct linear_c *) ti->private; @@ -96,6 +97,7 @@ static struct target_type linear_target = { .name = "linear", + .version= {1, 0, 1}, .module = THIS_MODULE, .ctr = linear_ctr, .dtr = linear_dtr, diff -Nru a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c --- a/drivers/md/dm-stripe.c Sat Apr 3 19:38:43 2004 +++ b/drivers/md/dm-stripe.c Sat Apr 3 19:38:43 2004 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ @@ -97,7 +97,8 @@ /* * chunk_size is a power of two */ - if (!chunk_size || (chunk_size & (chunk_size - 1))) { + if (!chunk_size || (chunk_size & (chunk_size - 1)) || + (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { ti->error = "dm-stripe: Invalid chunk size"; return -EINVAL; } @@ -166,7 +167,8 @@ kfree(sc); } -static int stripe_map(struct dm_target *ti, struct bio *bio) +static int stripe_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct stripe_c *sc = (struct stripe_c *) ti->private; @@ -211,6 +213,7 @@ static struct target_type stripe_target = { .name = "striped", + .version= {1, 0, 1}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c --- a/drivers/md/dm-table.c Sat Apr 3 19:38:56 2004 +++ b/drivers/md/dm-table.c Sat Apr 3 19:38:56 2004 @@ -329,13 +329,11 @@ */ static struct dm_dev *find_device(struct list_head *l, dev_t dev) { - struct list_head *tmp; + struct dm_dev *dd; - list_for_each(tmp, l) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + list_for_each_entry (dd, l, list) if (dd->bdev->bd_dev == dev) return dd; - } return NULL; } @@ -631,14 +629,20 @@ return 0; } -static void set_default_limits(struct io_restrictions *rs) +static void check_for_valid_limits(struct io_restrictions *rs) { - rs->max_sectors = MAX_SECTORS; - rs->max_phys_segments = MAX_PHYS_SEGMENTS; - rs->max_hw_segments = MAX_HW_SEGMENTS; - rs->hardsect_size = 1 << SECTOR_SHIFT; - rs->max_segment_size = MAX_SEGMENT_SIZE; - rs->seg_boundary_mask = -1; + if (!rs->max_sectors) + rs->max_sectors = MAX_SECTORS; + if (!rs->max_phys_segments) + rs->max_phys_segments = MAX_PHYS_SEGMENTS; + if (!rs->max_hw_segments) + rs->max_hw_segments = MAX_HW_SEGMENTS; + if (!rs->hardsect_size) + rs->hardsect_size = 1 << SECTOR_SHIFT; + if (!rs->max_segment_size) + rs->max_segment_size = MAX_SEGMENT_SIZE; + if (!rs->seg_boundary_mask) + rs->seg_boundary_mask = -1; } int dm_table_add_target(struct dm_table *t, const char *type, @@ -653,7 +657,6 @@ tgt = t->targets + t->num_targets; memset(tgt, 0, sizeof(*tgt)); - set_default_limits(&tgt->limits); if (!len) { tgt->error = "zero-length target"; @@ -737,6 +740,8 @@ { int r = 0; unsigned int leaf_nodes; + + check_for_valid_limits(&t->limits); /* how many indexes will the btree have ? */ leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); diff -Nru a/drivers/md/dm-target.c b/drivers/md/dm-target.c --- a/drivers/md/dm-target.c Sat Apr 3 19:38:56 2004 +++ b/drivers/md/dm-target.c Sat Apr 3 19:38:56 2004 @@ -25,15 +25,11 @@ static inline struct tt_internal *__find_target_type(const char *name) { - struct list_head *tih; struct tt_internal *ti; - list_for_each(tih, &_targets) { - ti = list_entry(tih, struct tt_internal, list); - + list_for_each_entry (ti, &_targets, list) if (!strcmp(name, ti->tt.name)) return ti; - } return NULL; } @@ -100,6 +96,20 @@ return ti; } + +int dm_target_iterate(void (*iter_func)(struct target_type *tt, + void *param), void *param) +{ + struct tt_internal *ti; + + down_read(&_lock); + list_for_each_entry (ti, &_targets, list) + iter_func(&ti->tt, param); + up_read(&_lock); + + return 0; +} + int dm_register_target(struct target_type *t) { int rv = 0; @@ -157,13 +167,15 @@ /* empty */ } -static int io_err_map(struct dm_target *ti, struct bio *bio) +static int io_err_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { return -EIO; } static struct target_type error_target = { .name = "error", + .version = {1, 0, 1}, .ctr = io_err_ctr, .dtr = io_err_dtr, .map = io_err_map, diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c Sat Apr 3 19:38:54 2004 +++ b/drivers/md/dm.c Sat Apr 3 19:38:54 2004 @@ -21,6 +21,9 @@ static unsigned int major = 0; static unsigned int _major = 0; +/* + * One of these is allocated per bio. + */ struct dm_io { struct mapped_device *md; int error; @@ -29,6 +32,16 @@ }; /* + * One of these is allocated per target within a bio. Hopefully + * this will be simplified out one day. + */ +struct target_io { + struct dm_io *io; + struct dm_target *ti; + union map_info info; +}; + +/* * Bits for the md->flags field. */ #define DMF_BLOCK_IO 0 @@ -59,6 +72,7 @@ * io objects are allocated from here. */ mempool_t *io_pool; + mempool_t *tio_pool; /* * Event handling. @@ -69,6 +83,7 @@ #define MIN_IOS 256 static kmem_cache_t *_io_cache; +static kmem_cache_t *_tio_cache; static __init int local_init(void) { @@ -80,9 +95,18 @@ if (!_io_cache) return -ENOMEM; + /* allocate a slab for the target ios */ + _tio_cache = kmem_cache_create("dm_tio", sizeof(struct target_io), + 0, 0, NULL, NULL); + if (!_tio_cache) { + kmem_cache_destroy(_io_cache); + return -ENOMEM; + } + _major = major; r = register_blkdev(_major, _name); if (r < 0) { + kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); return r; } @@ -95,6 +119,7 @@ static void local_exit(void) { + kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); if (unregister_blkdev(_major, _name) < 0) @@ -184,6 +209,16 @@ mempool_free(io, md->io_pool); } +static inline struct target_io *alloc_tio(struct mapped_device *md) +{ + return mempool_alloc(md->tio_pool, GFP_NOIO); +} + +static inline void free_tio(struct mapped_device *md, struct target_io *tio) +{ + mempool_free(tio, md->tio_pool); +} + /* * Add the bio to the list of deferred io. */ @@ -232,17 +267,30 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) { - struct dm_io *io = bio->bi_private; + int r = 0; + struct target_io *tio = bio->bi_private; + struct dm_io *io = tio->io; + dm_endio_fn endio = tio->ti->type->end_io; if (bio->bi_size) return 1; + if (endio) { + r = endio(tio->ti, bio, error, &tio->info); + if (r < 0) + error = r; + + else if (r > 0) + /* the target wants another shot at the io */ + return 1; + } + + free_tio(io->md, tio); dec_pending(io, error); bio_put(bio); - return 0; + return r; } - static sector_t max_io_len(struct mapped_device *md, sector_t sector, struct dm_target *ti) { @@ -263,7 +311,8 @@ return len; } -static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io) +static void __map_bio(struct dm_target *ti, struct bio *clone, + struct target_io *tio) { int r; @@ -273,22 +322,25 @@ BUG_ON(!clone->bi_size); clone->bi_end_io = clone_endio; - clone->bi_private = io; + clone->bi_private = tio; /* * Map the clone. If r == 0 we don't need to do * anything, the target has assumed ownership of * this io. */ - atomic_inc(&io->io_count); - r = ti->type->map(ti, clone); + atomic_inc(&tio->io->io_count); + r = ti->type->map(ti, clone, &tio->info); if (r > 0) /* the bio has been remapped so dispatch it */ generic_make_request(clone); - else if (r < 0) + else if (r < 0) { /* error the io and bail out */ + struct dm_io *io = tio->io; + free_tio(tio->io->md, tio); dec_pending(io, -EIO); + } } struct clone_info { @@ -348,6 +400,15 @@ struct bio *clone, *bio = ci->bio; struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector); sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti); + struct target_io *tio; + + /* + * Allocate a target io object. + */ + tio = alloc_tio(ci->md); + tio->io = ci->io; + tio->ti = ti; + memset(&tio->info, 0, sizeof(tio->info)); if (ci->sector_count <= max) { /* @@ -356,7 +417,7 @@ */ clone = clone_bio(bio, ci->sector, ci->idx, bio->bi_vcnt - ci->idx, ci->sector_count); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector_count = 0; } else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) { @@ -379,7 +440,7 @@ } clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector += len; ci->sector_count -= len; @@ -394,7 +455,7 @@ clone = split_bvec(bio, ci->sector, ci->idx, bv->bv_offset, max); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector += max; ci->sector_count -= max; @@ -403,7 +464,11 @@ len = to_sector(bv->bv_len) - max; clone = split_bvec(bio, ci->sector, ci->idx, bv->bv_offset + to_bytes(max), len); - __map_bio(ti, clone, ci->io); + tio = alloc_tio(ci->md); + tio->io = ci->io; + tio->ti = ti; + memset(&tio->info, 0, sizeof(tio->info)); + __map_bio(ti, clone, tio); ci->sector += len; ci->sector_count -= len; @@ -441,6 +506,16 @@ *---------------------------------------------------------------*/ +static inline void __dm_request(struct mapped_device *md, struct bio *bio) +{ + if (!md->map) { + bio_io_error(bio, bio->bi_size); + return; + } + + __split_bio(md, bio); +} + /* * The request function that just remaps the bio built up by * dm_merge_bvec. @@ -479,12 +554,7 @@ down_read(&md->lock); } - if (!md->map) { - bio_io_error(bio, bio->bi_size); - return 0; - } - - __split_bio(md, bio); + __dm_request(md, bio); up_read(&md->lock); return 0; } @@ -574,9 +644,14 @@ if (!md->io_pool) goto bad2; + md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab, + mempool_free_slab, _tio_cache); + if (!md->tio_pool) + goto bad3; + md->disk = alloc_disk(1); if (!md->disk) - goto bad3; + goto bad4; md->disk->major = _major; md->disk->first_minor = minor; @@ -592,7 +667,8 @@ return md; - + bad4: + mempool_destroy(md->tio_pool); bad3: mempool_destroy(md->io_pool); bad2: @@ -606,6 +682,7 @@ static void free_dev(struct mapped_device *md) { free_minor(md->disk->first_minor); + mempool_destroy(md->tio_pool); mempool_destroy(md->io_pool); del_gendisk(md->disk); put_disk(md->disk); @@ -644,13 +721,13 @@ { request_queue_t *q = md->queue; sector_t size; - md->map = t; size = dm_table_get_size(t); __set_size(md->disk, size); if (size == 0) return 0; + md->map = t; dm_table_event_callback(md->map, event_callback, md); dm_table_get(t); @@ -710,16 +787,16 @@ } /* - * Requeue the deferred bios by calling generic_make_request. + * Process the deferred bios */ -static void flush_deferred_io(struct bio *c) +static void __flush_deferred_io(struct mapped_device *md, struct bio *c) { struct bio *n; while (c) { n = c->bi_next; c->bi_next = NULL; - generic_make_request(c); + __dm_request(md, c); c = n; } } @@ -814,10 +891,11 @@ dm_table_resume_targets(md->map); clear_bit(DMF_SUSPENDED, &md->flags); clear_bit(DMF_BLOCK_IO, &md->flags); + def = bio_list_get(&md->deferred); + __flush_deferred_io(md, def); up_write(&md->lock); - flush_deferred_io(def); blk_run_queues(); return 0; diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h --- a/drivers/md/dm.h Sat Apr 3 19:38:43 2004 +++ b/drivers/md/dm.h Sat Apr 3 19:38:43 2004 @@ -123,6 +123,8 @@ void dm_target_exit(void); struct target_type *dm_get_target_type(const char *name); void dm_put_target_type(struct target_type *t); +int dm_target_iterate(void (*iter_func)(struct target_type *tt, + void *param), void *param); /*----------------------------------------------------------------- diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Sat Apr 3 19:38:42 2004 +++ b/drivers/md/md.c Sat Apr 3 19:38:42 2004 @@ -57,7 +57,7 @@ #ifndef MODULE -static void autostart_arrays (void); +static void autostart_arrays (int part); #endif static mdk_personality_t *pers[MAX_PERSONALITY]; @@ -1447,7 +1447,7 @@ return 1; } -static int mdp_major = 0; +int mdp_major = 0; static struct kobject *md_probe(dev_t dev, int *part, void *data) { @@ -1792,7 +1792,7 @@ * * If "unit" is allocated, then bump its reference count */ -static void autorun_devices(void) +static void autorun_devices(int part) { struct list_head candidates; struct list_head *tmp; @@ -1825,7 +1825,12 @@ bdevname(rdev0->bdev, b), rdev0->preferred_minor); break; } - dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); + if (part) + dev = MKDEV(mdp_major, + rdev0->preferred_minor << MdpMinorShift); + else + dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); + md_probe(dev, NULL, NULL); mddev = mddev_find(dev); if (!mddev) { @@ -1922,7 +1927,7 @@ /* * possibly return codes */ - autorun_devices(); + autorun_devices(0); return 0; } @@ -2407,7 +2412,7 @@ #ifndef MODULE case RAID_AUTORUN: err = 0; - autostart_arrays(); + autostart_arrays(arg); goto done; #endif default:; @@ -3173,13 +3178,14 @@ static void md_do_sync(mddev_t *mddev) { mddev_t *mddev2; - unsigned int max_sectors, currspeed = 0, - j, window; + unsigned int currspeed = 0, + window; + sector_t max_sectors,j; unsigned long mark[SYNC_MARKS]; - unsigned long mark_cnt[SYNC_MARKS]; + sector_t mark_cnt[SYNC_MARKS]; int last_mark,m; struct list_head *tmp; - unsigned long last_check; + sector_t last_check; /* just incase thread restarts... */ if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) @@ -3248,8 +3254,8 @@ * Tune reconstruction: */ window = 32*(PAGE_SIZE/512); - printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n", - window/2,max_sectors/2); + printk(KERN_INFO "md: using %dk window, over a total of %Lu blocks.\n", + window/2,(unsigned long long) max_sectors/2); atomic_set(&mddev->recovery_active, 0); init_waitqueue_head(&mddev->recovery_wait); @@ -3317,7 +3323,7 @@ */ cond_resched(); - currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; + currspeed = ((unsigned long)(j-mddev->resync_mark_cnt))/2/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { if ((currspeed > sysctl_speed_limit_max) || @@ -3577,7 +3583,7 @@ } -static void autostart_arrays(void) +static void autostart_arrays(int part) { char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; @@ -3602,7 +3608,7 @@ } dev_cnt = 0; - autorun_devices(); + autorun_devices(part); } #endif diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Sat Apr 3 19:38:43 2004 +++ b/drivers/md/raid0.c Sat Apr 3 19:38:43 2004 @@ -313,8 +313,8 @@ /* calculate the max read-ahead size. * For read-ahead of large files to be effective, we need to - * readahead at least a whole stripe. i.e. number of devices - * multiplied by chunk size. + * readahead at least twice a whole stripe. i.e. number of devices + * multiplied by chunk size times 2. * If an individual device has an ra_pages greater than the * chunk size, then we will not drive that device as hard as it * wants. We consider this a configuration error: a larger @@ -322,8 +322,8 @@ */ { int stripe = mddev->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) + mddev->queue->backing_dev_info.ra_pages = 2* stripe; } diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Sat Apr 3 19:38:41 2004 +++ b/drivers/md/raid5.c Sat Apr 3 19:38:41 2004 @@ -181,7 +181,7 @@ static void raid5_build_block (struct stripe_head *sh, int i); -static inline void init_stripe(struct stripe_head *sh, unsigned long sector, int pd_idx) +static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) { raid5_conf_t *conf = sh->raid_conf; int disks = conf->raid_disks, i; @@ -218,25 +218,25 @@ insert_hash(conf, sh); } -static struct stripe_head *__find_stripe(raid5_conf_t *conf, unsigned long sector) +static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector) { struct stripe_head *sh; CHECK_DEVLOCK(); - PRINTK("__find_stripe, sector %lu\n", sector); + PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next) if (sh->sector == sector) return sh; - PRINTK("__stripe %lu not in cache\n", sector); + PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); return NULL; } -static struct stripe_head *get_active_stripe(raid5_conf_t *conf, unsigned long sector, +static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int pd_idx, int noblock) { struct stripe_head *sh; - PRINTK("get_stripe, sector %lu\n", sector); + PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector); spin_lock_irq(&conf->device_lock); @@ -495,7 +495,7 @@ * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */ -static unsigned long raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, +static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, unsigned int data_disks, unsigned int * dd_idx, unsigned int * pd_idx, raid5_conf_t *conf) { @@ -556,7 +556,7 @@ /* * Finally, compute the new sector number */ - new_sector = stripe * sectors_per_chunk + chunk_offset; + new_sector = (sector_t)stripe * sectors_per_chunk + chunk_offset; return new_sector; } @@ -567,7 +567,7 @@ int raid_disks = conf->raid_disks, data_disks = raid_disks - 1; sector_t new_sector = sh->sector, check; int sectors_per_chunk = conf->chunk_size >> 9; - long stripe; + sector_t stripe; int chunk_offset; int chunk_number, dummy1, dummy2, dd_idx = i; sector_t r_sector; @@ -1388,7 +1388,7 @@ unsigned long stripe; int chunk_offset; int dd_idx, pd_idx; - unsigned long first_sector; + sector_t first_sector; int raid_disks = conf->raid_disks; int data_disks = raid_disks-1; @@ -1401,7 +1401,7 @@ stripe = x; BUG_ON(x != stripe); - first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk + first_sector = raid5_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); sh = get_active_stripe(conf, sector_nr, pd_idx, 1); if (sh == NULL) { @@ -1409,7 +1409,8 @@ /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - yield(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); @@ -1602,14 +1603,14 @@ print_raid5_conf(conf); - /* read-ahead size must cover a whole stripe, which is - * (n-1) * chunksize where 'n' is the number of raid devices + /* read-ahead size must cover two whole stripes, which is + * 2 * (n-1) * chunksize where 'n' is the number of raid devices */ { int stripe = (mddev->raid_disks-1) * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) + mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } /* Ok, everything is just fine now */ diff -Nru a/drivers/md/raid6main.c b/drivers/md/raid6main.c --- a/drivers/md/raid6main.c Sat Apr 3 19:38:40 2004 +++ b/drivers/md/raid6main.c Sat Apr 3 19:38:40 2004 @@ -200,7 +200,7 @@ static void raid6_build_block (struct stripe_head *sh, int i); -static inline void init_stripe(struct stripe_head *sh, unsigned long sector, int pd_idx) +static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) { raid6_conf_t *conf = sh->raid_conf; int disks = conf->raid_disks, i; @@ -237,25 +237,25 @@ insert_hash(conf, sh); } -static struct stripe_head *__find_stripe(raid6_conf_t *conf, unsigned long sector) +static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector) { struct stripe_head *sh; CHECK_DEVLOCK(); - PRINTK("__find_stripe, sector %lu\n", sector); + PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next) if (sh->sector == sector) return sh; - PRINTK("__stripe %lu not in cache\n", sector); + PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); return NULL; } -static struct stripe_head *get_active_stripe(raid6_conf_t *conf, unsigned long sector, +static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector, int pd_idx, int noblock) { struct stripe_head *sh; - PRINTK("get_stripe, sector %lu\n", sector); + PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector); spin_lock_irq(&conf->device_lock); @@ -516,7 +516,7 @@ * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */ -static unsigned long raid6_compute_sector(sector_t r_sector, unsigned int raid_disks, +static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks, unsigned int data_disks, unsigned int * dd_idx, unsigned int * pd_idx, raid6_conf_t *conf) { @@ -588,7 +588,7 @@ /* * Finally, compute the new sector number */ - new_sector = stripe * sectors_per_chunk + chunk_offset; + new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset; return new_sector; } @@ -599,7 +599,7 @@ int raid_disks = conf->raid_disks, data_disks = raid_disks - 2; sector_t new_sector = sh->sector, check; int sectors_per_chunk = conf->chunk_size >> 9; - long stripe; + sector_t stripe; int chunk_offset; int chunk_number, dummy1, dummy2, dd_idx = i; sector_t r_sector; @@ -1550,7 +1550,7 @@ unsigned long stripe; int chunk_offset; int dd_idx, pd_idx; - unsigned long first_sector; + sector_t first_sector; int raid_disks = conf->raid_disks; int data_disks = raid_disks - 2; @@ -1563,7 +1563,7 @@ stripe = x; BUG_ON(x != stripe); - first_sector = raid6_compute_sector(stripe*data_disks*sectors_per_chunk + first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); sh = get_active_stripe(conf, sector_nr, pd_idx, 1); if (sh == NULL) { @@ -1571,7 +1571,8 @@ /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - yield(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); @@ -1771,14 +1772,14 @@ print_raid6_conf(conf); - /* read-ahead size must cover a whole stripe, which is - * (n-2) * chunksize where 'n' is the number of raid devices + /* read-ahead size must cover two whole stripes, which is + * 2 * (n-2) * chunksize where 'n' is the number of raid devices */ { int stripe = (mddev->raid_disks-2) * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) + mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } /* Ok, everything is just fine now */ diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c --- a/drivers/media/dvb/frontends/alps_tdlb7.c Sat Apr 3 19:38:42 2004 +++ b/drivers/media/dvb/frontends/alps_tdlb7.c Sat Apr 3 19:38:42 2004 @@ -29,8 +29,6 @@ */ - -#define __KERNEL_SYSCALLS__ #include #include #include @@ -58,8 +56,6 @@ #define SP8870_FIRMWARE_OFFSET 0x0A -static int errno; - static struct dvb_frontend_info tdlb7_info = { .name = "Alps TDLB7", .type = FE_OFDM, @@ -174,13 +170,13 @@ loff_t filesize; char *dp; - fd = open(fn, 0, 0); + fd = sys_open(fn, 0, 0); if (fd == -1) { printk("%s: unable to open '%s'.\n", __FUNCTION__, fn); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) { printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn); sys_close(fd); @@ -194,8 +190,8 @@ return -EIO; } - lseek(fd, SP8870_FIRMWARE_OFFSET, 0); - if (read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) { + sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0); + if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) { printk("%s: failed to read '%s'.\n",__FUNCTION__, fn); vfree(dp); sys_close(fd); diff -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c --- a/drivers/media/dvb/frontends/sp887x.c Sat Apr 3 19:38:54 2004 +++ b/drivers/media/dvb/frontends/sp887x.c Sat Apr 3 19:38:54 2004 @@ -12,7 +12,6 @@ next 0x4000 loaded. This may change in future versions. */ -#define __KERNEL_SYSCALLS__ #include #include #include @@ -68,8 +67,6 @@ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_RECOVER }; -static int errno; - static int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len) { @@ -216,13 +213,13 @@ // Load the firmware set_fs(get_ds()); - fd = open(sp887x_firmware, 0, 0); + fd = sys_open(sp887x_firmware, 0, 0); if (fd < 0) { printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__, sp887x_firmware); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0) { printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__, sp887x_firmware); @@ -244,8 +241,8 @@ // read it! // read the first 16384 bytes from the file // ignore the first 10 bytes - lseek(fd, 10, 0); - if (read(fd, firmware, fw_size) != fw_size) { + sys_lseek(fd, 10, 0); + if (sys_read(fd, firmware, fw_size) != fw_size) { printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__); vfree(firmware); sys_close(fd); diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c --- a/drivers/media/dvb/frontends/tda1004x.c Sat Apr 3 19:38:40 2004 +++ b/drivers/media/dvb/frontends/tda1004x.c Sat Apr 3 19:38:40 2004 @@ -32,7 +32,6 @@ */ -#define __KERNEL_SYSCALLS__ #include #include #include @@ -41,7 +40,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" @@ -399,13 +397,13 @@ // Load the firmware set_fs(get_ds()); - fd = open(tda1004x_firmware, 0, 0); + fd = sys_open(tda1004x_firmware, 0, 0); if (fd < 0) { printk("%s: Unable to open firmware %s\n", __FUNCTION__, tda1004x_firmware); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0) { printk("%s: Firmware %s is empty\n", __FUNCTION__, tda1004x_firmware); @@ -436,8 +434,8 @@ } // read it! - lseek(fd, fw_offset, 0); - if (read(fd, firmware, fw_size) != fw_size) { + sys_lseek(fd, fw_offset, 0); + if (sys_read(fd, firmware, fw_size) != fw_size) { printk("%s: Failed to read firmware\n", __FUNCTION__); vfree(firmware); sys_close(fd); diff -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c --- a/drivers/media/video/meye.c Sat Apr 3 19:38:44 2004 +++ b/drivers/media/video/meye.c Sat Apr 3 19:38:44 2004 @@ -160,13 +160,15 @@ } } -/* return a page table pointing to N pages of locked memory +/* + * return a page table pointing to N pages of locked memory * * NOTE: The meye device expects dma_addr_t size to be 32 bits * (the toc must be exactly 1024 entries each of them being 4 bytes * in size, the whole result being 4096 bytes). We're using here - * dma_addr_t for corectness but the compilation of this driver is - * disabled for HIGHMEM64G=y, where sizeof(dma_addr_t) != 4 */ + * dma_addr_t for correctness but the compilation of this driver is + * disabled for HIGHMEM64G=y, where sizeof(dma_addr_t) != 4 + */ static int ptable_alloc(void) { dma_addr_t *pt; int i; diff -Nru a/drivers/media/video/meye.h b/drivers/media/video/meye.h --- a/drivers/media/video/meye.h Sat Apr 3 19:38:43 2004 +++ b/drivers/media/video/meye.h Sat Apr 3 19:38:43 2004 @@ -31,7 +31,7 @@ #define _MEYE_PRIV_H_ #define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 8 +#define MEYE_DRIVER_MINORVERSION 9 #include #include diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c --- a/drivers/media/video/video-buf.c Sat Apr 3 19:38:43 2004 +++ b/drivers/media/video/video-buf.c Sat Apr 3 19:38:43 2004 @@ -215,7 +215,7 @@ BUG(); if (!dma->bus_addr) - pci_dma_sync_sg(dev,dma->sglist,dma->nr_pages,dma->direction); + pci_dma_sync_sg_for_cpu(dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } diff -Nru a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c --- a/drivers/media/video/zoran_driver.c Sat Apr 3 19:38:54 2004 +++ b/drivers/media/video/zoran_driver.c Sat Apr 3 19:38:54 2004 @@ -2815,7 +2815,7 @@ fh->jpg_settings.TmpDcm); fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh-> - jpg_settings);; + jpg_settings); fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; if (fh->jpg_settings.TmpDcm == 1) diff -Nru a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig --- a/drivers/message/fusion/Kconfig Sat Apr 3 19:38:57 2004 +++ b/drivers/message/fusion/Kconfig Sat Apr 3 19:38:57 2004 @@ -3,7 +3,7 @@ config FUSION tristate "Fusion MPT (base + ScsiHost) drivers" - depends on BLK_DEV_SD && PCI + depends on PCI ---help--- LSI Logic Fusion(TM) Message Passing Technology (MPT) device support provides high performance SCSI host initiator, and LAN [1] interface @@ -14,41 +14,6 @@ [1] LAN is not supported on parallel SCSI medium. - These drivers require a Fusion MPT compatible PCI adapter installed - in the host system. MPT adapters contain specialized I/O processors - to handle I/O workload, and more importantly to offload this work - from the host CPU(s). - - If you have Fusion MPT hardware and want to use it, you can say - Y or M here to add MPT (base + ScsiHost) drivers. - = build lib (fusion), and link [static] into the kernel [2] - proper - = compiled as [dynamic] modules [3] named: (mptbase, - mptscsih) - - [2] In order enable capability to boot the linux kernel - natively from a Fusion MPT target device, you MUST - answer Y here! (currently requires CONFIG_BLK_DEV_SD) - [3] To compile this support as modules, choose M here. - - If unsure, say N. - - If you say Y or M here you will get a choice of these - additional protocol and support module options: Module Name: - Enhanced SCSI error reporting (isense) - Fusion MPT misc device (ioctl) driver (mptctl) - Fusion MPT LAN driver (mptlan) - - --- - Fusion MPT is trademark of LSI Logic Corporation, and its - architecture is based on LSI Logic's Message Passing Interface (MPI) - specification. - -config FUSION_BOOT - bool - depends on FUSION=y - default y - config FUSION_MAX_SGE int "Maximum number of scatter gather entries" depends on FUSION @@ -62,7 +27,6 @@ necessary (or recommended) unless the user will be running large I/O's via the raw interface. -# How can we force these options to module or nothing? config FUSION_ISENSE tristate "Enhanced SCSI error reporting" depends on MODULES && FUSION && m @@ -132,17 +96,4 @@ If unsure whether you really want or need this, say N. - NOTES: This feature is NOT available nor supported for linux-2.2.x - kernels. You must be building a linux-2.3.x or linux-2.4.x kernel - in order to configure this option. - Support for building this feature into the linux kernel is not - yet available. - -# if [ "$CONFIG_FUSION_LAN" != "n" ]; then -# define_bool CONFIG_NET_FC y -# fi -# These be define_tristate, but we leave them define_bool -# for backward compatibility with pre-linux-2.2.15 kernels. -# (Bugzilla:fibrebugs, #384) endmenu - diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile --- a/drivers/message/fusion/Makefile Sat Apr 3 19:38:45 2004 +++ b/drivers/message/fusion/Makefile Sat Apr 3 19:38:45 2004 @@ -17,10 +17,16 @@ # Fusion MPT drivers; recognized debug defines... # MPT general: -#EXTRA_CFLAGS += -DDEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG_SCSI #EXTRA_CFLAGS += -DMPT_DEBUG #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME #EXTRA_CFLAGS += -DMPT_DEBUG_SG + +# This is a temporary fix for the reply/request fifo +# for some 64bit archs. Uncommenting this line +# will place the fifo's in 32bit space +#EXTRA_CFLAGS += -DMPTBASE_MEM_ALLOC_FIFO_FIX + # # driver/module specifics... # diff -Nru a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c --- a/drivers/message/fusion/isense.c Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/isense.c Sat Apr 3 19:38:43 2004 @@ -5,7 +5,7 @@ * Error Report logging output. This module implements SCSI-3 * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. * - * Copyright (c) 1991-2003 Steven J. Ralston + * Copyright (c) 1991-2004 Steven J. Ralston * Written By: Steven J. Ralston * (yes I wrote some of the orig. code back in 1991!) * (mailto:sjralston1@netscape.net) @@ -66,7 +66,7 @@ #endif #define MODULEAUTHOR "Steven J. Ralston" -#define COPYRIGHT "Copyright (c) 2001-2003 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR #include "mptbase.h" #include "isense.h" diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h --- a/drivers/message/fusion/linux_compat.h Sat Apr 3 19:38:42 2004 +++ b/drivers/message/fusion/linux_compat.h Sat Apr 3 19:38:42 2004 @@ -15,25 +15,7 @@ #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#define SET_NICE(current,x) do {(current)->nice = (x);} while (0) -#else -#define SET_NICE(current,x) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -#define pci_enable_device(pdev) (0) -#define SCSI_DATA_UNKNOWN 0 -#define SCSI_DATA_WRITE 1 -#define SCSI_DATA_READ 2 -#define SCSI_DATA_NONE 3 -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) -#define pci_set_dma_mask(pdev, mask) (0) -#define scsi_set_pci_device(sh, pdev) (0) -#endif +#define SET_NICE(current,x) do {(current)->nice = (x);} while (0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) # if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) @@ -147,31 +129,9 @@ /* PCI/driver subsystem { */ -#if 0 /* FIXME Don't know what to use to check for the proper kernel version */ -#define DEVICE_COUNT_RESOURCE 6 -#define PCI_BASEADDR_FLAGS(idx) base_address[idx] -#define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL -/* - * We have to keep track of the original value using - * a temporary, and not by just sticking pdev->base_address[x] - * back. pdev->base_address[x] is an opaque cookie that can - * be used by the PCI implementation on a given Linux port - * for any purpose. -DaveM - */ -#define PCI_BASEADDR_SIZE(__pdev, __idx) \ -({ unsigned int size, tmp; \ - pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \ - pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \ - pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \ - pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \ - (4 - size); \ -}) -#else #define PCI_BASEADDR_FLAGS(idx) resource[idx].flags #define PCI_BASEADDR_START(idx) resource[idx].start #define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 -#endif /* } ifndef 0 */ - /* Compatability for the 2.3.x PCI DMA API. */ #ifndef PCI_DMA_BIDIRECTIONAL @@ -227,54 +187,10 @@ /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* PCI_DMA_BIDIRECTIONAL */ -/* - * With the new command queuing code in the SCSI mid-layer we no longer have - * to hold the io_request_lock spin lock when calling the scsi_done routine. - * For now we only do this with the 2.5.1 kernel or newer. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) - #define MPT_HOST_LOCK(flags) - #define MPT_HOST_UNLOCK(flags) -#else - #define MPT_HOST_LOCK(flags) \ - spin_lock_irqsave(&io_request_lock, flags) - #define MPT_HOST_UNLOCK(flags) \ - spin_unlock_irqrestore(&io_request_lock, flags) -#endif - -/* - * We use our new error handling code if the kernel version is 2.4.18 or newer. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) - #define MPT_SCSI_USE_NEW_EH -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) #define mpt_work_struct work_struct #define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data) -#else -#define mpt_work_struct tq_struct -#define MPT_INIT_WORK(_task, _func, _data) \ -({ (_task)->sync = 0; \ - (_task)->routine = (_func); \ - (_task)->data = (void *) (_data); \ -}) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_sync_irq(_irq) synchronize_irq(_irq) -#else -#define mptscsih_sync_irq(_irq) synchronize_irq() -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58) -#define mpt_inc_use_count() -#define mpt_dec_use_count() -#else -#define mpt_inc_use_count() MOD_INC_USE_COUNT -#define mpt_dec_use_count() MOD_DEC_USE_COUNT -#endif - +#define mpt_sync_irq(_irq) synchronize_irq(_irq) /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ diff -Nru a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h --- a/drivers/message/fusion/lsi/mpi.h Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/lsi/mpi.h Sat Apr 3 19:38:41 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI.H + * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI.H Version: 01.02.07 + * mpi.h Version: 01.05.xx * * Version History * --------------- @@ -48,6 +48,10 @@ * 05-31-02 01.02.05 Bumped MPI_HEADER_VERSION_UNIT. * 07-12-02 01.02.06 Added define for MPI_FUNCTION_MAILBOX. * 09-16-02 01.02.07 Bumped value for MPI_HEADER_VERSION_UNIT. + * 11-15-02 01.02.08 Added define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX and + * obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX. + * 04-01-03 01.02.09 New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED + * 06-26-03 01.02.10 Bumped MPI_HEADER_VERSION_UNIT value. * -------------------------------------------------------------------------- */ @@ -62,7 +66,7 @@ *****************************************************************************/ #define MPI_VERSION_MAJOR (0x01) -#define MPI_VERSION_MINOR (0x02) +#define MPI_VERSION_MINOR (0x05) #define MPI_VERSION_MAJOR_MASK (0xFF00) #define MPI_VERSION_MAJOR_SHIFT (8) #define MPI_VERSION_MINOR_MASK (0x00FF) @@ -73,10 +77,12 @@ #define MPI_VERSION_01_00 (0x0100) #define MPI_VERSION_01_01 (0x0101) #define MPI_VERSION_01_02 (0x0102) +#define MPI_VERSION_01_03 (0x0103) +#define MPI_VERSION_01_05 (0x0105) /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x09) +#define MPI_HEADER_VERSION_UNIT (0x00) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) @@ -171,6 +177,8 @@ #define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) #define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) +#define MPI_HI_PRI_REQUEST_QUEUE_OFFSET (0x00000048) + /***************************************************************************** @@ -230,10 +238,6 @@ #define MPI_FUNCTION_TARGET_ASSIST (0x0B) #define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) #define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) -#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ #define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) #define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) #define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) @@ -251,16 +255,46 @@ #define MPI_FUNCTION_MAILBOX (0x19) +#define MPI_FUNCTION_SMP_PASSTHROUGH (0x1A) +#define MPI_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) + +#define MPI_DIAG_BUFFER_POST (0x1D) +#define MPI_DIAG_RELEASE (0x1E) + +#define MPI_FUNCTION_SCSI_IO_32 (0x1F) + #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) #define MPI_FUNCTION_LAN_RESET (0x22) +#define MPI_FUNCTION_INBAND_BUFFER_POST (0x28) +#define MPI_FUNCTION_INBAND_SEND (0x29) +#define MPI_FUNCTION_INBAND_RSP (0x2A) +#define MPI_FUNCTION_INBAND_ABORT (0x2B) + #define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) #define MPI_FUNCTION_IO_UNIT_RESET (0x41) #define MPI_FUNCTION_HANDSHAKE (0x42) #define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) +/* standard version format */ +typedef struct _MPI_VERSION_STRUCT +{ + U8 Dev; /* 00h */ + U8 Unit; /* 01h */ + U8 Minor; /* 02h */ + U8 Major; /* 03h */ +} MPI_VERSION_STRUCT, MPI_POINTER PTR_MPI_VERSION_STRUCT, + MpiVersionStruct_t, MPI_POINTER pMpiVersionStruct; + +typedef union _MPI_VERSION_FORMAT +{ + MPI_VERSION_STRUCT Struct; + U32 Word; +} MPI_VERSION_FORMAT, MPI_POINTER PTR_MPI_VERSION_FORMAT, + MpiVersionFormat_t, MPI_POINTER pMpiVersionFormat_t; + /***************************************************************************** * @@ -573,44 +607,54 @@ /* Common IOCStatus values for all replies */ /****************************************************************************/ -#define MPI_IOCSTATUS_SUCCESS (0x0000) -#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) -#define MPI_IOCSTATUS_BUSY (0x0002) -#define MPI_IOCSTATUS_INVALID_SGL (0x0003) -#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) -#define MPI_IOCSTATUS_RESERVED (0x0005) -#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) -#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_SUCCESS (0x0000) +#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI_IOCSTATUS_BUSY (0x0002) +#define MPI_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI_IOCSTATUS_RESERVED (0x0005) +#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) /****************************************************************************/ /* Config IOCStatus values */ /****************************************************************************/ -#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) +#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) /****************************************************************************/ /* SCSIIO Reply (SPI & FCP) initiator values */ /****************************************************************************/ -#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) -#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) -#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) +#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) +#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) +#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/****************************************************************************/ +/* For use by SCSI Initiator and SCSI Target end-to-end data protection */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_EEDP_CRC_ERROR (0x004D) +#define MPI_IOCSTATUS_EEDP_LBA_TAG_ERROR (0x004E) +#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + /****************************************************************************/ /* SCSI (SPI & FCP) target values */ @@ -618,7 +662,8 @@ #define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060) #define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061) -#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) +#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) #define MPI_IOCSTATUS_TARGET_ABORTED (0x0063) #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) #define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) @@ -626,7 +671,7 @@ #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) /****************************************************************************/ -/* Additional FCP target values */ +/* Additional FCP target values (obsolete) */ /****************************************************************************/ #define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ @@ -642,6 +687,7 @@ #define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067) #define MPI_IOCSTATUS_FC_DID_INVALID (0x0068) #define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069) +#define MPI_IOCSTATUS_FC_EXCHANGE_CANCELED (0x006C) /****************************************************************************/ /* LAN values */ @@ -656,6 +702,25 @@ #define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) #define MPI_IOCSTATUS_LAN_CANCELED (0x0087) +/****************************************************************************/ +/* Serial Attached SCSI values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) + +/****************************************************************************/ +/* Inband values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_INBAND_ABORTED (0x0098) +#define MPI_IOCSTATUS_INBAND_NO_CONNECTION (0x0099) + +/****************************************************************************/ +/* Diagnostic Tools values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + /****************************************************************************/ /* IOCStatus flag to indicate that log info is available */ @@ -669,9 +734,12 @@ /****************************************************************************/ #define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI_IOCLOGINFO_TYPE_SHIFT (28) #define MPI_IOCLOGINFO_TYPE_NONE (0x0) #define MPI_IOCLOGINFO_TYPE_SCSI (0x1) #define MPI_IOCLOGINFO_TYPE_FC (0x2) +#define MPI_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI_IOCLOGINFO_TYPE_ISCSI (0x4) #define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) diff -Nru a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h --- a/drivers/message/fusion/lsi/mpi_cnfg.h Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/lsi/mpi_cnfg.h Sat Apr 3 19:38:43 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_CNFG.H + * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI_CNFG.H Version: 01.02.09 + * mpi_cnfg.h Version: 01.05.xx * * Version History * --------------- @@ -127,7 +127,24 @@ * MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE. * Added new config page: CONFIG_PAGE_SCSI_DEVICE_3. * Modified MPI_FCPORTPAGE5_FLAGS_ defines. - * 09-16-02 01.02.09 Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define. + * 09-16-02 01.02.09 Added MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define. + * 11-15-02 01.02.10 Added ConnectedID defines for CONFIG_PAGE_SCSI_PORT_0. + * Added more Flags defines for CONFIG_PAGE_FC_PORT_1. + * Added more Flags defines for CONFIG_PAGE_FC_DEVICE_0. + * 04-01-03 01.02.11 Added RR_TOV field and additional Flags defines for + * CONFIG_PAGE_FC_PORT_1. + * Added define MPI_FCPORTPAGE5_FLAGS_DISABLE to disable + * an alias. + * Added more device id defines. + * 06-26-03 01.02.12 Added MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID define. + * Added TargetConfig and IDConfig fields to + * CONFIG_PAGE_SCSI_PORT_1. + * Added more PortFlags defines for CONFIG_PAGE_SCSI_PORT_2 + * to control DV. + * Added more Flags defines for CONFIG_PAGE_FC_PORT_1. + * In CONFIG_PAGE_FC_DEVICE_0, replaced Reserved1 field + * with ADISCHardALPA. + * Added MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY define. * -------------------------------------------------------------------------- */ @@ -159,6 +176,19 @@ } ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; +typedef struct _CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 00h */ + U8 Reserved1; /* 01h */ + U8 PageNumber; /* 02h */ + U8 PageType; /* 03h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ + U8 Reserved2; /* 07h */ +} fCONFIG_EXTENDED_PAGE_HEADER, MPI_POINTER PTR_CONFIG_EXTENDED_PAGE_HEADER, + ConfigExtendedPageHeader_t, MPI_POINTER pConfigExtendedPageHeader_t; + + /**************************************************************************** * PageType field values @@ -180,12 +210,23 @@ #define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) #define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) #define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI_CONFIG_PAGETYPE_INBAND (0x0B) +#define MPI_CONFIG_PAGETYPE_EXTENDED (0x0F) #define MPI_CONFIG_PAGETYPE_MASK (0x0F) #define MPI_CONFIG_TYPENUM_MASK (0x0FFF) /**************************************************************************** +* ExtPageType field values +****************************************************************************/ +#define MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) + + +/**************************************************************************** * PageAddress field values ****************************************************************************/ #define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) @@ -219,6 +260,24 @@ #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_DEVICE_PGAD_FORM_SHIFT (28) +#define MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID (0x00000001) +#define MPI_SAS_DEVICE_PGAD_FORM_HANDLE (0x00000002) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_SAS_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT (0) + +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x00FF0000) +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT (16) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_MASK (0x0000FFFF) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_SHIFT (0) /**************************************************************************** @@ -230,7 +289,8 @@ U8 Reserved; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[8]; /* 0Ch */ @@ -260,7 +320,8 @@ U8 Reserved; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[2]; /* 0Ch */ @@ -281,23 +342,22 @@ /**************************************************************************** * Manufacturing Config pages ****************************************************************************/ +#define MPI_MANUFACTPAGE_VENDORID_LSILOGIC (0x1000) +/* Fibre Channel */ #define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) #define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) #define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) #define MPI_MANUFACTPAGE_DEVICEID_FC919X (0x0628) #define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) - +/* SCSI */ #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) #define MPI_MANUFACTPAGE_DEVID_1030_53C1035 (0x0032) #define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035 (0x0033) #define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0040) #define MPI_MANUFACTPAGE_DEVID_53C1035ZC (0x0041) - -#define MPI_MANUFACTPAGE_DEVID_SA2010 (0x0804) -#define MPI_MANUFACTPAGE_DEVID_SA2010ZC (0x0805) -#define MPI_MANUFACTPAGE_DEVID_SA2020 (0x0806) -#define MPI_MANUFACTPAGE_DEVID_SA2020ZC (0x0807) +/* SAS */ +#define MPI_MANUFACTPAGE_DEVID_SAS1064 (0x0050) typedef struct _CONFIG_PAGE_MANUFACTURING_0 @@ -381,8 +441,8 @@ U8 InfoOffset1; /* 0Ah */ U8 InfoSize1; /* 0Bh */ U8 InquirySize; /* 0Ch */ - U8 Reserved2; /* 0Dh */ - U16 Reserved3; /* 0Eh */ + U8 Flags; /* 0Dh */ + U16 Reserved2; /* 0Eh */ U8 InquiryData[56]; /* 10h */ U32 ISVolumeSettings; /* 48h */ U32 IMEVolumeSettings; /* 4Ch */ @@ -390,7 +450,30 @@ } fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x00) +#define MPI_MANUFACTURING4_PAGEVERSION (0x01) + +/* defines for the Flags field */ +#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_5 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U64 BaseWWID; /* 04h */ +} fCONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, + ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; + +#define MPI_MANUFACTURING5_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_6 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} fCONFIG_PAGE_MANUFACTURING_6, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_6, + ManufacturingPage6_t, MPI_POINTER pManufacturingPage6_t; + +#define MPI_MANUFACTURING6_PAGEVERSION (0x00) /**************************************************************************** @@ -414,16 +497,18 @@ } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; -#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE1_PAGEVERSION (0x01) /* IO Unit Page 1 Flags defines */ - #define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) #define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) #define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) #define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) +#define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI_IOUNITPAGE1_DISABLE_QUEUE_FULL_HANDLING (0x00000020) #define MPI_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) +#define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) typedef struct _MPI_ADAPTER_INFO @@ -453,6 +538,11 @@ #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) +#define MPI_IOUNITPAGE2_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI_IOUNITPAGE2_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to @@ -515,6 +605,12 @@ #define MPI_IOCPAGE1_PAGEVERSION (0x01) +/* defines for the Flags field */ +#define MPI_IOCPAGE1_EEDP_HOST_SUPPORTS_DIF (0x08000000) +#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000) +#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000) +#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000) +#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000) #define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) #define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) @@ -655,7 +751,7 @@ typedef struct _CONFIG_PAGE_IOC_5 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved1; /* 04h */ U8 NumHotSpares; /* 08h */ U8 Reserved2; /* 09h */ @@ -667,6 +763,57 @@ #define MPI_IOCPAGE5_PAGEVERSION (0x00) +/**************************************************************************** +* BIOS Port Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_BIOS_1 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 BiosOptions; /* 04h */ + U32 IOCSettings; /* 08h */ + U32 Reserved1; /* 0Ch */ + U32 DeviceSettings; /* 10h */ + U16 NumberOfDevices; /* 14h */ + U16 Reserved2; /* 16h */ + U16 IOTimeoutBlockDevicesNonRM; /* 18h */ + U16 IOTimeoutSequential; /* 1Ah */ + U16 IOTimeoutOther; /* 1Ch */ + U16 IOTimeoutBlockDevicesRM; /* 1Eh */ +} fCONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1, + BIOSPage1_t, MPI_POINTER pBIOSPage1_t; + +#define MPI_BIOSPAGE1_PAGEVERSION (0x00) + +/* values for the BiosOptions field */ +#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) +#define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE (0x00000200) +#define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE (0x00000100) +#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for the IOCSettings field */ +#define MPI_BIOSPAGE1_IOCSET_MASK_SPINUP_DELAY (0x00000F00) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_SPINUP_DELAY (8) + +#define MPI_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for the DeviceSettings field */ +#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + /**************************************************************************** * SCSI Port Config Pages @@ -686,7 +833,27 @@ #define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) #define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_SYNC_ASYNC (0x00) +#define MPI_SCSIPORTPAGE0_SYNC_5 (0x32) +#define MPI_SCSIPORTPAGE0_SYNC_10 (0x19) +#define MPI_SCSIPORTPAGE0_SYNC_20 (0x0C) +#define MPI_SCSIPORTPAGE0_SYNC_33_33 (0x0B) +#define MPI_SCSIPORTPAGE0_SYNC_40 (0x0A) +#define MPI_SCSIPORTPAGE0_SYNC_80 (0x09) +#define MPI_SCSIPORTPAGE0_SYNC_160 (0x08) +#define MPI_SCSIPORTPAGE0_SYNC_UNKNOWN (0xFF) + +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD (8) +#define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD \ + ) #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET (16) +#define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET \ + ) #define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) #define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) @@ -694,6 +861,10 @@ #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD (0x01) #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE (0x02) #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD (0x03) +#define MPI_SCSIPORTPAGE0_PHY_MASK_CONNECTED_ID (0xFF000000) +#define MPI_SCSIPORTPAGE0_PHY_SHIFT_CONNECTED_ID (24) +#define MPI_SCSIPORTPAGE0_PHY_BUS_FREE_CONNECTED_ID (0xFE) +#define MPI_SCSIPORTPAGE0_PHY_UNKNOWN_CONNECTED_ID (0xFF) typedef struct _CONFIG_PAGE_SCSI_PORT_1 @@ -701,13 +872,22 @@ fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Configuration; /* 04h */ U32 OnBusTimerValue; /* 08h */ + U8 TargetConfig; /* 0Ch */ + U8 Reserved1; /* 0Dh */ + U16 IDConfig; /* 0Eh */ } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; -#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x02) +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x03) +/* Configuration values */ #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) +#define MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID (16) + +/* TargetConfig values */ +#define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY (0x01) +#define MPI_SCSIPORTPAGE1_TARGCONFIG_INIT_TARG (0x02) typedef struct _MPI_DEVICE_INFO @@ -727,13 +907,21 @@ } fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2, SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t; -#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01) +#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x02) +/* PortFlags values */ #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK (0x00000060) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_FULL_DV (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY (0x00000020) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV (0x00000060) + + +/* PortSettings values */ #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA (0x00000000) @@ -741,7 +929,11 @@ #define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_RM_NONE (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_RM_BOOT_ONLY (0x00000040) +#define MPI_SCSIPORTPAGE2_PORT_RM_WITH_MEDIA (0x00000080) #define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_SHIFT_SPINUP_DELAY (8) #define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) #define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) #define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00001000) @@ -778,7 +970,9 @@ #define MPI_SCSIDEVPAGE0_NP_RTI (0x00000040) #define MPI_SCSIDEVPAGE0_NP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) @@ -808,7 +1002,9 @@ #define MPI_SCSIDEVPAGE1_RP_RTI (0x00000040) #define MPI_SCSIDEVPAGE1_RP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) @@ -915,7 +1111,7 @@ #define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED (0x00000010) #define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED (0x00000020) -#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000030) +#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000040) #define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK (0x00000F00) #define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT (0x00000000) @@ -954,13 +1150,19 @@ #define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) #define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) -#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN (0x00000000) /* (SNIA)HBA_PORTSPEED_UNKNOWN 0 Unknown - transceiver incapable of reporting */ +#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED (0x00000008) /* (SNIA)HBA_PORTSPEED_4GBIT 8 4 GBit/sec */ +#define MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN #define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_NOT_NEGOTIATED (0x00008000) /* (SNIA)HBA_PORTSPEED_NOT_NEGOTIATED (1<<15) Speed not established */ + typedef struct _CONFIG_PAGE_FC_PORT_1 @@ -974,15 +1176,25 @@ U8 TopologyConfig; /* 1Ah */ U8 AltConnector; /* 1Bh */ U8 NumRequestedAliases; /* 1Ch */ - U8 Reserved1; /* 1Dh */ - U16 Reserved2; /* 1Eh */ + U8 RR_TOV; /* 1Dh */ + U8 InitiatorDeviceTimeout; /* 1Eh */ + U8 InitiatorIoPendTimeout; /* 1Fh */ } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, FCPortPage1_t, MPI_POINTER pFCPortPage1_t; -#define MPI_FCPORTPAGE1_PAGEVERSION (0x04) +#define MPI_FCPORTPAGE1_PAGEVERSION (0x06) #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN (0x08000000) #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY (0x04000000) +#define MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS (0x02000000) +#define MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS (0x01000000) +#define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID (0x00800000) +#define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE (0x00400000) +#define MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK (0x00200000) +#define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS (0x00000070) +#define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG (0x00000008) +#define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO (0x00000004) +#define MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS (0x00000002) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000) @@ -993,6 +1205,11 @@ #define MPI_FCPORTPAGE1_FLAGS_PROT_LAN ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) #define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_NONE_RR_TOV_UNITS (0x00000000) +#define MPI_FCPORTPAGE1_FLAGS_THOUSANDTH_RR_TOV_UNITS (0x00000010) +#define MPI_FCPORTPAGE1_FLAGS_TENTH_RR_TOV_UNITS (0x00000030) +#define MPI_FCPORTPAGE1_FLAGS_TEN_RR_TOV_UNITS (0x00000050) + #define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED (0xFF) #define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK (0x0F) @@ -1009,6 +1226,8 @@ #define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN (0x00) +#define MPI_FCPORTPAGE1_INITIATOR_DEV_TIMEOUT_MASK (0x7F) + typedef struct _CONFIG_PAGE_FC_PORT_2 { @@ -1108,12 +1327,13 @@ } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5, FCPortPage5_t, MPI_POINTER pFCPortPage5_t; -#define MPI_FCPORTPAGE5_PAGEVERSION (0x01) +#define MPI_FCPORTPAGE5_PAGEVERSION (0x02) #define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED (0x01) #define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA (0x02) #define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN (0x04) #define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN (0x08) +#define MPI_FCPORTPAGE5_FLAGS_DISABLE (0x10) typedef struct _CONFIG_PAGE_FC_PORT_6 { @@ -1322,7 +1542,7 @@ U8 Flags; /* 19h */ U16 BBCredit; /* 1Ah */ U16 MaxRxFrameSize; /* 1Ch */ - U8 Reserved1; /* 1Eh */ + U8 ADISCHardALPA; /* 1Eh */ U8 PortNumber; /* 1Fh */ U8 FcPhLowestVersion; /* 20h */ U8 FcPhHighestVersion; /* 21h */ @@ -1331,13 +1551,16 @@ } fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0, FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t; -#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x02) +#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x03) #define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID (0x01) +#define MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID (0x02) +#define MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID (0x04) #define MPI_FC_DEVICE_PAGE0_PROT_IP (0x01) #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02) #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY (0x08) #define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) #define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) @@ -1348,6 +1571,7 @@ #define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) #define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) +#define MPI_FC_DEVICE_PAGE0_HARD_ALPA_UNKNOWN (0xFF) /**************************************************************************** * RAID Volume Config Pages @@ -1564,6 +1788,318 @@ #define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) #define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + + +/**************************************************************************** +* Inband Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_INBAND_0 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + MPI_VERSION_FORMAT InbandVersion; /* 04h */ + U16 MaximumBuffers; /* 08h */ + U16 Reserved1; /* 0Ah */ +} fCONFIG_PAGE_INBAND_0, MPI_POINTER PTR_CONFIG_PAGE_INBAND_0, + InbandPage0_t, MPI_POINTER pInbandPage0_t; + +#define MPI_INBAND_PAGEVERSION (0x00) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 NegotiatedLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U16 AttachedDeviceHandle; /* 08h */ + U16 ControllerDevHandle; /* 0Ah */ + U32 Reserved2; /* 0Ch */ +} MPI_SAS_IO_UNIT0_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT0_PHY_DATA, + SasIOUnit0PhyData, MPI_POINTER pSasIOUnit0PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT0_PHY_MAX +#define MPI_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT0_PHY_DATA PhyData[MPI_SAS_IOUNIT0_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, + SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; + +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT0_PHY_FLAGS_PHY_DISABLED (0x04) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 NegotiatedLinkRate */ +#define MPI_SAS_IOUNIT0_RATE_UNKNOWN (0x00) +#define MPI_SAS_IOUNIT0_RATE_PHY_DISABLED (0x01) +#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION (0x02) +#define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI_SAS_IOUNIT0_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT0_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + + +typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U32 Reserved1; /* 08h */ +} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, + SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT1_PHY_MAX +#define MPI_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, + SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; + +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE (0x04) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +#define MPI_SAS_IOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI_SAS_IOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI_SAS_IOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI_SAS_IOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI_SAS_IOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT1_MIN_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U16 MaxPersistentIDs; /* 0Ch */ + U16 NumPersistentIDsUsed; /* 0Eh */ + U8 Status; /* 10h */ + U8 Flags; /* 11h */ + U16 Reserved2; /* 12h */ +} fCONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, + SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; + +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) +#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) + +/* values for SAS IO Unit Page 2 Flags field */ +#define MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 MaxInvalidDwordCount; /* 0Ch */ + U32 InvalidDwordCountTime; /* 10h */ + U32 MaxRunningDisparityErrorCount; /* 14h */ + U32 RunningDisparityErrorTime; /* 18h */ + U32 MaxLossDwordSynchCount; /* 1Ch */ + U32 LossDwordSynchCountTime; /* 20h */ + U32 MaxPhyResetProblemCount; /* 24h */ + U32 PhyResetProblemTime; /* 28h */ +} fCONFIG_PAGE_SAS_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_3, + SasIOUnitPage3_t, MPI_POINTER pSasIOUnitPage3_t; + +#define MPI_SASIOUNITPAGE3_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_EXPANDER_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U16 ParentDevHandle; /* 1Ah */ + U16 ExpanderChangeCount; /* 1Ch */ + U16 ExpanderRouteIndexes; /* 1Eh */ + U8 NumPhys; /* 20h */ + U8 SASLevel; /* 21h */ + U8 Flags; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0, + SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t; + +#define MPI_SASEXPANDER0_PAGEVERSION (0x00) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U32 DeviceInfo; /* 1Ch */ + U16 Flags; /* 20h */ + U8 PhysicalPort; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, + SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; + +#define MPI_SASDEVICE0_PAGEVERSION (0x00) + +/* values for SAS Device Page 0 Flags field */ +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x04) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x02) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x01) + +/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U8 InitialRegDeviceFIS[20];/* 1Ch */ +} fCONFIG_PAGE_SAS_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_1, + SasDevicePage1_t, MPI_POINTER pSasDevicePage1_t; + +#define MPI_SASDEVICE1_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_PHY_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U16 AttachedDevHandle; /* 14h */ + U8 AttachedPhyIdentifier; /* 16h */ + U8 Reserved2; /* 17h */ + U32 AttachedDeviceInfo; /* 18h */ + U8 ProgrammedLinkRate; /* 20h */ + U8 HwLinkRate; /* 21h */ + U8 ChangeCount; /* 22h */ + U8 Reserved3; /* 23h */ + U32 PhyInfo; /* 24h */ +} fCONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, + SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; + +#define MPI_SASPHY0_PAGEVERSION (0x00) + +/* values for SAS PHY Page 0 ProgrammedLinkRate field */ +#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 HwLinkRate field */ +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 PhyInfo field */ +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) +#define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI_SAS_PHY0_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI_SAS_PHY0_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING (0x00000020) + +#define MPI_SAS_PHY0_PHYINFO_MASK_LINK_RATE (0x0000000F) +#define MPI_SAS_PHY0_PHYINFO_UNKNOWN_LINK_RATE (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_PHY_DISABLED (0x00000001) +#define MPI_SAS_PHY0_PHYINFO_NEGOTIATION_FAILED (0x00000002) +#define MPI_SAS_PHY0_PHYINFO_SATA_OOB_COMPLETE (0x00000003) +#define MPI_SAS_PHY0_PHYINFO_RATE_1_5 (0x00000008) +#define MPI_SAS_PHY0_PHYINFO_RATE_3_0 (0x00000009) + + +typedef struct _CONFIG_PAGE_SAS_PHY_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 InvalidDwordCount; /* 0Ch */ + U32 RunningDisparityErrorCount; /* 10h */ + U32 LossDwordSynchCount; /* 14h */ + U32 PhyResetProblemCount; /* 18h */ +} fCONFIG_PAGE_SAS_PHY_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_1, + SasPhyPage1_t, MPI_POINTER pSasPhyPage1_t; + +#define MPI_SASPHY1_PAGEVERSION (0x00) + #endif diff -Nru a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h --- a/drivers/message/fusion/lsi/mpi_fc.h Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/lsi/mpi_fc.h Sat Apr 3 19:38:41 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_FC.H + * Name: mpi_fc.h * Title: MPI Fibre Channel messages and structures * Creation Date: June 12, 2000 * - * MPI_FC.H Version: 01.02.03 + * mpi_fc.h Version: 01.05.xx * * Version History * --------------- @@ -45,7 +45,7 @@ /***************************************************************************** * -* F C T a r g e t M o d e M e s s a g e s +* F C D i r e c t A c c e s s M e s s a g e s * *****************************************************************************/ @@ -334,6 +334,7 @@ FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t; #define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01) +#define MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK (0x02) #define MPI_FC_PRIM_SEND_FLAGS_RESET_LINK (0x04) #define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08) #define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10) diff -Nru a/drivers/message/fusion/lsi/mpi_inb.h b/drivers/message/fusion/lsi/mpi_inb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_inb.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_inb.h + * Title: MPI Inband structures and definitions + * Creation Date: September 30, 2003 + * + * mpi_inb.h Version: 01.03.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * ??-??-?? 01.03.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_INB_H +#define MPI_INB_H + +/****************************************************************************** +* +* I n b a n d M e s s a g e s +* +*******************************************************************************/ + + +/****************************************************************************/ +/* Inband Buffer Post Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_BUFFER_POST_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferCount; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + SGE_TRANS_SIMPLE_UNION SGL; /* 10h */ +} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST, + MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t; + + +typedef struct _WWN_FC_FORMAT +{ + U64 NodeName; /* 00h */ + U64 PortName; /* 08h */ +} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT, + WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t; + +typedef struct _WWN_SAS_FORMAT +{ + U64 WorldWideID; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ +} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT, + WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t; + +typedef union _WWN_INBAND_FORMAT +{ + WWN_FC_FORMAT Fc; + WWN_SAS_FORMAT Sas; +} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT, + WwnInbandFormat, MPI_POINTER pWwnInbandFormat; + + +/* Inband Buffer Post reply message */ + +typedef struct _MSG_INBAND_BUFFER_POST_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ + U32 TransactionContext; /* 18h */ + WWN_INBAND_FORMAT Wwn; /* 1Ch */ + U32 IOCIdentifier[4]; /* 2Ch */ +} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY, + MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t; + + +/****************************************************************************/ +/* Inband Send Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_SEND_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 Reserved5; /* 20h */ + SGE_IO_UNION SGL; /* 24h */ +} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST, + MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t; + + +/* Inband Send reply message */ + +typedef struct _MSG_INBAND_SEND_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY, + MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t; + + +/****************************************************************************/ +/* Inband Response Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_RSP_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 IOCIdentifier[4]; /* 20h */ + U32 ResponseLength; /* 30h */ + SGE_IO_UNION SGL; /* 34h */ +} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST, + MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t; + + +/* Inband Response reply message */ + +typedef struct _MSG_INBAND_RSP_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY, + MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t; + + +/****************************************************************************/ +/* Inband Abort Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_ABORT_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + U32 ContextToAbort; /* 10h */ +} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST, + MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t; + +#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS (0x00) +#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER (0x01) +#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST (0x02) +#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST (0x03) + + +/* Inband Abort reply message */ + +typedef struct _MSG_INBAND_ABORT_REPLY +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY, + MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t; + + +#endif + diff -Nru a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h --- a/drivers/message/fusion/lsi/mpi_init.h Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/lsi/mpi_init.h Sat Apr 3 19:38:41 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_INIT.H + * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * MPI_INIT.H Version: 01.02.05 + * mpi_init.h Version: 01.05.xx * * Version History * --------------- @@ -31,6 +31,8 @@ * 10-04-01 01.02.04 Added defines for SEP request Action field. * 05-31-02 01.02.05 Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define * for SCSI IO requests. + * 11-15-02 01.02.06 Added special extended SCSI Status defines for FCP. + * 06-26-03 01.02.07 Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define. * -------------------------------------------------------------------------- */ @@ -45,7 +47,7 @@ *****************************************************************************/ /****************************************************************************/ -/* SCSI IO messages and assocaited structures */ +/* SCSI IO messages and associated structures */ /****************************************************************************/ typedef struct _MSG_SCSI_IO_REQUEST @@ -78,6 +80,16 @@ #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) #define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) +#define MPI_SCSIIO_MSGFLGS_EEDP_TYPE_MASK (0xE0) +#define MPI_SCSIIO_MSGFLGS_EEDP_NONE (0x00) +#define MPI_SCSIIO_MSGFLGS_EEDP_RDPROTECT_T10 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_VRPROTECT_T10 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_WRPROTECT_T10 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_READ_MODE1 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_WRITE_MODE1 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_READ_MODE1 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_WRITE_MODE1 (0x80) + /* SCSI IO LUN fields */ @@ -153,6 +165,10 @@ #define MPI_SCSI_STATUS_TASK_SET_FULL (0x28) #define MPI_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT (0x80) +#define MPI_SCSI_STATUS_FCPEXT_NO_LINK (0x81) +#define MPI_SCSI_STATUS_FCPEXT_UNASSIGNED (0x82) + /* SCSI IO Reply SCSIState values */ @@ -176,6 +192,33 @@ /****************************************************************************/ +/* SCSI IO 32 Request message structure */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO32_REQUEST +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Reserved; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + U8 CDB[32]; /* 18h */ + U32 DataLength; /* 38h */ + U32 SenseBufferLowAddr; /* 3Ch */ + SGE_IO_UNION SGL; /* 40h */ +} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST, + SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t; + +/* SCSI IO 32 uses the same defines as above for SCSI IO */ + + +/****************************************************************************/ /* SCSI Task Management messages */ /****************************************************************************/ @@ -203,6 +246,7 @@ #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x04) #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff -Nru a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h --- a/drivers/message/fusion/lsi/mpi_ioc.h Sat Apr 3 19:38:42 2004 +++ b/drivers/message/fusion/lsi/mpi_ioc.h Sat Apr 3 19:38:42 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_IOC.H + * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * MPI_IOC.H Version: 01.02.06 + * mpi_ioc.h Version: 01.05.xx * * Version History * --------------- @@ -55,6 +55,8 @@ * 05-31-02 01.02.06 Added define for * MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID. * Added AliasIndex to EVENT_DATA_LOGOUT structure. + * 04-01-03 01.02.07 Added defines for MPI_FW_HEADER_SIGNATURE_. + * 06-26-03 01.02.08 Added new values to the product family defines. * -------------------------------------------------------------------------- */ @@ -87,19 +89,21 @@ U8 Reserved1[2]; /* 0Eh */ U32 HostMfaHighAddr; /* 10h */ U32 SenseBufferHighAddr; /* 14h */ + U32 ReplyFifoHostSignalingAddr; /* 18h */ } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, IOCInit_t, MPI_POINTER pIOCInit_t; /* WhoInit values */ -#define MPI_WHOINIT_NO_ONE (0x00) -#define MPI_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI_WHOINIT_ROM_BIOS (0x02) -#define MPI_WHOINIT_PCI_PEER (0x03) -#define MPI_WHOINIT_HOST_DRIVER (0x04) -#define MPI_WHOINIT_MANUFACTURER (0x05) +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) /* Flags values */ -#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) typedef struct _MSG_IOC_INIT_REPLY { @@ -179,8 +183,10 @@ U8 MaxDevices; /* 2Eh */ U8 MaxBuses; /* 2Fh */ U32 FWImageSize; /* 30h */ - U32 Reserved4; /* 34h */ + U32 IOCCapabilities; /* 34h */ MPI_FW_VERSION FWVersion; /* 38h */ + U16 HighPriorityQueueDepth; /* 3Ch */ + U16 Reserved2; /* 3Eh */ } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; @@ -192,12 +198,22 @@ #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) #define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) #define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) +#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q (0x00000001) +#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL (0x00000002) +#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004) +#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040) + /***************************************************************************** @@ -253,6 +269,8 @@ #define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) #define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) #define MPI_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI_PORTFACTS_PORTTYPE_SAS (0x30) /* ProtocolFlags values */ @@ -386,6 +404,10 @@ #define MPI_EVENT_INTEGRATED_RAID (0x0000000B) #define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) #define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) /* AckRequired field values */ @@ -433,6 +455,39 @@ #define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING (0x04) #define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA (0x05) +/* SAS Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 Reserved; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 DevHandle; /* 06h */ + U32 DeviceInfo; /* 08h */ +} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MpiEventDataSasDeviceStatusChange_t, + MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; + +/* MPI SAS Device Status Change Event data ReasonCode values */ +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) + +/* SCSI Event data for Queue Full event */ + +typedef struct _EVENT_DATA_QUEUE_FULL +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 CurrentDepth; /* 02h */ +} EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL, + EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t; + /* MPI Link Status Change Event data */ typedef struct _EVENT_DATA_LINK_STATUS @@ -538,6 +593,7 @@ #define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWDownloadTCSGE @@ -590,6 +646,7 @@ #define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) #define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWUploadTCSGE { @@ -653,6 +710,11 @@ #define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) #define MPI_FW_HEADER_PID_TYPE_FC (0x1000) +#define MPI_FW_HEADER_PID_TYPE_SAS (0x2000) + +#define MPI_FW_HEADER_SIGNATURE_0 (0x5AEAA55A) +#define MPI_FW_HEADER_SIGNATURE_1 (0xA55AEAA5) +#define MPI_FW_HEADER_SIGNATURE_2 (0x5AA55AEA) #define MPI_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI (0x0100) @@ -663,6 +725,7 @@ #define MPI_FW_HEADER_PID_PROD_CTX_SCSI (0x0600) #define MPI_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SCSI */ #define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI (0x0001) #define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI (0x0002) #define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI (0x0003) @@ -673,9 +736,17 @@ #define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI (0x0008) #define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI (0x0009) #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI (0x000A) +#define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI (0x000B) +#define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI (0x000C) +/* Fibre Channel */ #define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) #define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) #define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_919XL_FC (0x0003) +#define MPI_FW_HEADER_PID_FAMILY_949_FC (0x0004) +#define MPI_FW_HEADER_PID_FAMILY_959_FC (0x0005) +/* SAS */ +#define MPI_FW_HEADER_PID_FAMILY_1064_SAS (0x0001) typedef struct _MPI_EXT_IMAGE_HEADER { @@ -694,5 +765,6 @@ #define MPI_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) #endif diff -Nru a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h --- a/drivers/message/fusion/lsi/mpi_lan.h Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/lsi/mpi_lan.h Sat Apr 3 19:38:43 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_LAN.H + * Name: mpi_lan.h * Title: MPI LAN messages and structures * Creation Date: June 30, 2000 * - * MPI_LAN.H Version: 01.02.01 + * mpi_lan.h Version: 01.05.xx * * Version History * --------------- diff -Nru a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h --- a/drivers/message/fusion/lsi/mpi_raid.h Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/lsi/mpi_raid.h Sat Apr 3 19:38:43 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001-2002 LSI Logic Corporation. + * Copyright (c) 2001-2003 LSI Logic Corporation. * * - * Name: MPI_RAID.H + * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * MPI_RAID.H Version: 01.02.07 + * mpi_raid.h Version: 01.05.xx * * Version History * --------------- @@ -25,6 +25,9 @@ * MPI_RAID_ACTION_INACTIVATE_VOLUME, and * MPI_RAID_ACTION_ADATA_INACTIVATE_ALL. * 07-12-02 01.02.07 Added structures for Mailbox request and reply. + * 11-15-02 01.02.08 Added missing MsgContext field to MSG_MAILBOX_REQUEST. + * 04-01-03 01.02.09 New action data option flag for + * MPI_RAID_ACTION_DELETE_VOLUME. * -------------------------------------------------------------------------- */ @@ -40,7 +43,7 @@ /****************************************************************************/ -/* RAID Volume Request */ +/* RAID Action Request */ /****************************************************************************/ typedef struct _MSG_RAID_ACTION @@ -90,6 +93,9 @@ #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS (0x00000000) #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS (0x00000001) +#define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) +#define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002) + /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) @@ -184,7 +190,7 @@ /****************************************************************************/ -/* Mailbox request structure */ +/* Mailbox reqeust structure */ /****************************************************************************/ typedef struct _MSG_MAILBOX_REQUEST @@ -195,6 +201,7 @@ U16 Reserved2; U8 Reserved3; U8 MsgFlags; + U32 MsgContext; U8 Command[10]; U16 Reserved4; SGE_IO_UNION SGL; diff -Nru a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_sas.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: April 23, 2003 + * + * mpi_sas.h Version: 01.05.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * xx-yy-zz 01.05.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_SAS_H +#define MPI_SAS_H + +/***************************************************************************** +* +* S e r i a l A t t a c h e d S C S I M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Serial Management Protocol Passthrough Request */ +/****************************************************************************/ + +typedef struct _MSG_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 RequestDataLength; /* 04h */ + U8 ConnectionRate; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved1; /* 0Ch */ + U64 SASAddress; /* 10h */ + U32 Reserved2; /* 18h */ + U32 Reserved3; /* 1Ch */ + SGE_SIMPLE_UNION SGL; /* 20h */ +} MSG_SMP_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REQUEST, + SmpPassthroughRequest_t, MPI_POINTER pSmpPassthroughRequest_t; + +#define MPI_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +#define MPI_SMP_PT_REQ_CONNECT_RATE_NEGOTIATED (0x00) +#define MPI_SMP_PT_REQ_CONNECT_RATE_1_5 (0x08) +#define MPI_SMP_PT_REQ_CONNECT_RATE_3_0 (0x09) + + +/* Serial Management Protocol Passthrough Reply */ +typedef struct _MSG_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 ResponseDataLength; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Reserved2; /* 0Ch */ + U8 SASStatus; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 Reserved3; /* 14h */ + U8 ResponseData[4]; /* 18h */ +} MSG_SMP_PASSTHROUGH_REPLY, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REPLY, + SmpPassthroughReply_t, MPI_POINTER pSmpPassthroughReply_t; + +#define MPI_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for the SASStatus field */ +#define MPI_SASSTATUS_SUCCESS (0x00) +#define MPI_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI_SASSTATUS_INVALID_FRAME (0x02) +#define MPI_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS IO Unit Configuration pages. + */ +#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/****************************************************************************/ +/* SAS IO Unit Control Request */ +/****************************************************************************/ + +typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 TargetID; /* 0Ch */ + U8 Bus; /* 0Dh */ + U8 PhyNum; /* 0Eh */ + U8 Reserved4; /* 0Fh */ + U32 Reserved5; /* 10h */ + U64 SASAddress; /* 14h */ + U32 Reserved6; /* 1Ch */ +} MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, + SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; + +/* values for the ... field */ +#define MPI_SAS_OP_CLEAR_NOT_PRESENT (0x01) +#define MPI_SAS_OP_CLEAR_ALL (0x02) +#define MPI_SAS_OP_MAP (0x03) +#define MPI_SAS_OP_MOVE (0x04) +#define MPI_SAS_OP_CLEAR (0x05) +#define MPI_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) + + +/* SAS IO Unit Control Reply */ +typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_SAS_IOUNIT_CONTROL_REPLY, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REPLY, + SasIoUnitControlReply_t, MPI_POINTER pSasIoUnitControlReply_t; + +#endif + + diff -Nru a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h --- a/drivers/message/fusion/lsi/mpi_targ.h Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/lsi/mpi_targ.h Sat Apr 3 19:38:41 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TARG.H + * Name: mpi_targ.h * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI_TARG.H Version: 01.02.07 + * mpi_targ.h Version: 01.05.xx * * Version History * --------------- @@ -41,6 +41,8 @@ * Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER. * 09-16-02 01.02.07 Added flags for confirmed completion. * Added PRIORITY_REASON_TARGET_BUSY. + * 11-15-02 01.02.08 Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER. + * 04-01-03 01.02.09 Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER. * -------------------------------------------------------------------------- */ @@ -171,7 +173,7 @@ U32 FcpDl; /* 1Ch */ U8 AliasIndex; /* 20h */ U8 Reserved1; /* 21h */ - U16 Reserved2; /* 22h */ + U16 OptionalOxid; /* 22h */ } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER, MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer; @@ -190,6 +192,10 @@ U8 TaskManagementFlags; /* 12h */ U8 AdditionalCDBLength; /* 13h */ U8 CDB[16]; /* 14h */ + /* Alias ID */ + U8 AliasID; /* 24h */ + U8 Reserved1; /* 25h */ + U16 Reserved2; /* 26h */ } MPI_TARGET_SCSI_SPI_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER, MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer; diff -Nru a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_tool.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2001-2003 LSI Logic Corporation. + * + * + * Name: mpi_tool.h + * Title: MPI Toolbox structures and definitions + * Creation Date: July 30, 2001 + * + * mpi_tool.h Version: 01.05.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 08-08-01 01.02.01 Original release. + * 08-29-01 01.02.02 Added DIAG_DATA_UPLOAD_HEADER and related defines. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TOOL_H +#define MPI_TOOL_H + +#define MPI_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) +#define MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) +#define MPI_TOOLBOX_FC_MANAGEMENT_TOOL (0x04) + + +/****************************************************************************/ +/* Toolbox reply */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_REPLY +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY, + ToolboxReply_t, MPI_POINTER pToolboxReply_t; + + +/****************************************************************************/ +/* Toolbox Clean Tool request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ +} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST, + ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t; + +#define MPI_TOOLBOX_CLEAN_NVSRAM (0x00000001) +#define MPI_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI_TOOLBOX_CLEAN_BOOTLOADER (0x04000000) +#define MPI_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) + + +/****************************************************************************/ +/* Toolbox Memory Move request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + SGE_SIMPLE_UNION SGL; /* 0Ch */ +} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST, + ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t; + + +/****************************************************************************/ +/* Toolbox Diagnostic Data Upload request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ + U32 Reserved3; /* 10h */ + SGE_SIMPLE_UNION SGL; /* 14h */ +} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t; + +typedef struct _DIAG_DATA_UPLOAD_HEADER +{ + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved; /* 05h */ + U16 Reserved1; /* 06h */ +} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER, + DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t; + +#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1 (0x01) +#define MPI_TB_DIAG_FORMAT_SCSI_2 (0x02) +#define MPI_TB_DIAG_FORMAT_SCSI_3 (0x03) +#define MPI_TB_DIAG_FORMAT_FC_TRACE_1 (0x04) + + +/****************************************************************************/ +/* Toolbox ISTWI Read Write request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Flags; /* 0Ch */ + U8 BusNum; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + U8 NumAddressBytes; /* 10h */ + U8 Reserved4; /* 11h */ + U16 DataLength; /* 12h */ + U8 DeviceAddr; /* 14h */ + U8 Addr1; /* 15h */ + U8 Addr2; /* 16h */ + U8 Addr3; /* 17h */ + U32 Reserved5; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 1Ch */ +} MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + ToolboxIstwiReadWriteRequest_t, MPI_POINTER pToolboxIstwiReadWriteRequest_t; + +#define MPI_TB_ISTWI_FLAGS_WRITE (0x00) +#define MPI_TB_ISTWI_FLAGS_READ (0x01) + + +/****************************************************************************/ +/* Toolbox FC Management request */ +/****************************************************************************/ + +/* ActionInfo for Bus and TargetId */ +typedef struct _MPI_TB_FC_MANAGE_BUS_TID_AI +{ + U16 Reserved; /* 00h */ + U8 Bus; /* 02h */ + U8 TargetId; /* 03h */ +} MPI_TB_FC_MANAGE_BUS_TID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_BUS_TID_AI, + MpiTbFcManageBusTidAi_t, MPI_POINTER pMpiTbFcManageBusTidAi_t; + +/* ActionInfo for port identifier */ +typedef struct _MPI_TB_FC_MANAGE_PID_AI +{ + U32 PortIdentifier; /* 00h */ +} MPI_TB_FC_MANAGE_PID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_PID_AI, + MpiTbFcManagePidAi_t, MPI_POINTER pMpiTbFcManagePidAi_t; + +/* union of ActionInfo */ +typedef union _MPI_TB_FC_MANAGE_AI_UNION +{ + MPI_TB_FC_MANAGE_BUS_TID_AI BusTid; + MPI_TB_FC_MANAGE_PID_AI Port; +} MPI_TB_FC_MANAGE_AI_UNION, MPI_POINTER PTR_MPI_TB_FC_MANAGE_AI_UNION, + MpiTbFcManageAiUnion_t, MPI_POINTER pMpiTbFcManageAiUnion_t; + +typedef struct _MSG_TOOLBOX_FC_MANAGE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Action; /* 0Ch */ + U8 Reserved3; /* 0Dh */ + U16 Reserved4; /* 0Eh */ + MPI_TB_FC_MANAGE_AI_UNION ActionInfo; /* 10h */ +} MSG_TOOLBOX_FC_MANAGE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_FC_MANAGE_REQUEST, + ToolboxFcManageRequest_t, MPI_POINTER pToolboxFcManageRequest_t; + +/* defines for the Action field */ +#define MPI_TB_FC_MANAGE_ACTION_DISC_ALL (0x00) +#define MPI_TB_FC_MANAGE_ACTION_DISC_PID (0x01) +#define MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID (0x02) + + +/****************************************************************************/ +/* Diagnostic Buffer Post request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_BUFFER_POST_REQUEST +{ + U8 TraceLevel; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 ExtendedType; /* 0Ch */ + U32 BufferLength; /* 10h */ + U32 ProductSpecific[4]; /* 14h */ + U32 Reserved3; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 28h */ +} MSG_DIAG_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REQUEST, + DiagBufferPostRequest_t, MPI_POINTER pDiagBufferPostRequest_t; + +#define MPI_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI_DIAG_BUF_TYPE_EXTENDED (0x02) + +#define MPI_DIAG_EXTENDED_QTAG (0x00000001) + + +/* Diagnostic Buffer Post reply */ +typedef struct _MSG_DIAG_BUFFER_POST_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ +} MSG_DIAG_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REPLY, + DiagBufferPostReply_t, MPI_POINTER pDiagBufferPostReply_t; + + +/****************************************************************************/ +/* Diagnostic Release request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ +} MSG_DIAG_RELEASE_REQUEST, MPI_POINTER PTR_MSG_DIAG_RELEASE_REQUEST, + DiagReleaseRequest_t, MPI_POINTER pDiagReleaseRequest_t; + + +/* Diagnostic Release reply */ +typedef struct _MSG_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_DIAG_RELEASE_REPLY, MPI_POINTER PTR_MSG_DIAG_RELEASE_REPLY, + DiagReleaseReply_t, MPI_POINTER pDiagReleaseReply_t; + + +#endif + + diff -Nru a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h --- a/drivers/message/fusion/lsi/mpi_type.h Sat Apr 3 19:38:44 2004 +++ b/drivers/message/fusion/lsi/mpi_type.h Sat Apr 3 19:38:44 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TYPE.H + * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * MPI Version: 01.02.01 + * mpi_type.h Version: 01.05.xx * * Version History * --------------- diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c Sat Apr 3 19:38:42 2004 +++ b/drivers/message/fusion/mptbase.c Sat Apr 3 19:38:42 2004 @@ -44,7 +44,7 @@ * for gobs of hard work fixing and optimizing LAN code. * THANK YOU! * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -209,8 +209,8 @@ static int GetIoUnitPage2(MPT_ADAPTER *ioc); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); -static int mpt_findImVolumes(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); +static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); static void mpt_timer_expired(unsigned long data); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); @@ -347,14 +347,14 @@ MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; u32 pa; - int req_idx = -1; + int req_idx; int cb_idx; int type; int freeme; - int count = 0; ioc = bus_id; +#ifdef MPT_DEBUG_IRQ /* * Verify ioc pointer is ok */ @@ -369,6 +369,7 @@ return IRQ_NONE; } } +#endif /* * Drain the reply FIFO! @@ -521,17 +522,7 @@ spin_unlock_irqrestore(&ioc->FreeQlock, flags); } - count++; - dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count)); mb(); - - if (count >= MPT_MAX_REPLIES_PER_ISR) { - dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.", - ioc->name, count)); - dirqprintk((" Giving this ISR a break!\n")); - return IRQ_HANDLED; - } - } /* drain reply FIFO */ return IRQ_HANDLED; @@ -605,7 +596,8 @@ } else if (func == MPI_FUNCTION_EVENT_ACK) { dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { + } else if (func == MPI_FUNCTION_CONFIG || + func == MPI_FUNCTION_TOOLBOX) { CONFIGPARMS *pCfg; unsigned long flags; @@ -714,11 +706,7 @@ MptCallbacks[i] = cbfunc; MptDriverClass[i] = dclass; MptEvHandlers[i] = NULL; - MptDeviceDriverHandlers[i] = NULL; last_drv_idx = i; - if (cbfunc != mpt_base_reply) { - mpt_inc_use_count(); - } break; } } @@ -745,10 +733,6 @@ last_drv_idx++; if (isense_idx != -1 && isense_idx <= cb_idx) isense_idx++; - - if (cb_idx != mpt_base_index) { - mpt_dec_use_count(); - } } } @@ -890,7 +874,7 @@ MPT_FRAME_HDR* mpt_get_msg_frame(int handle, int iocid) { - MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *mf; MPT_ADAPTER *iocp; unsigned long flags; @@ -922,6 +906,8 @@ iocp->mfcnt++; #endif } + else + mf = NULL; spin_unlock_irqrestore(&iocp->FreeQlock, flags); #ifdef MFCNT @@ -986,7 +972,11 @@ mf_dma_addr = iocp->req_frames_low_dma + req_offset; CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + } else { + printk (KERN_ERR + "mpt_put_msg_frame: Invalid iocid=%d\n", iocid); } + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1135,7 +1125,7 @@ ((reqBytes/4)<chip->IntStatus, 0); - if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { return -2; } @@ -1162,7 +1152,7 @@ (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { r = -3; break; } @@ -1190,10 +1180,12 @@ MPT_ADAPTER * mpt_adapter_find_first(void) { - MPT_ADAPTER *this = NULL; + MPT_ADAPTER *this; if (! Q_IS_EMPTY(&MptAdapters)) this = MptAdapters.head; + else + this = NULL; return this; } @@ -1208,10 +1200,12 @@ MPT_ADAPTER * mpt_adapter_find_next(MPT_ADAPTER *prev) { - MPT_ADAPTER *next = NULL; + MPT_ADAPTER *next; if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head)) next = prev->forw; + else + next = NULL; return next; } @@ -1272,10 +1266,12 @@ int ii; int r = -ENODEV; u64 mask = 0xffffffffffffffffULL; + u8 revision; + u8 pcixcmd; if (pci_enable_device(pdev)) return r; - + if (!pci_set_dma_mask(pdev, mask)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); @@ -1284,24 +1280,47 @@ return r; } +#if 0 + /* broken because some code assumes that multiple calls + to pci_alloc_consistent return data in the same 4GB segment. + This cannot work on machines with enough memory. */ if (!pci_set_consistent_dma_mask(pdev, mask)) dprintk((KERN_INFO MYNAM ": Using 64 bit consistent mask\n")); else dprintk((KERN_INFO MYNAM ": Not using 64 bit consistent mask\n")); +#endif ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } - memset(ioc, 0, sizeof(*ioc)); + memset(ioc, 0, sizeof(MPT_ADAPTER)); ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ - ioc->reply_sz = ioc->req_sz; + ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->pcidev = pdev; + +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + memcpy(&ioc->pcidev32,ioc->pcidev,sizeof(struct pci_dev)); + if (pci_set_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) { + dprintk((KERN_INFO MYNAM + ": error setting 32bit mask\n")); + kfree(ioc); + return -ENODEV; + } + + if (pci_set_consistent_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) { + dprintk((KERN_INFO MYNAM + ": error setting 32bit mask\n")); + kfree(ioc); + return -ENODEV; + } +#endif + ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); @@ -1412,48 +1431,45 @@ } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { ioc->chip_type = FC929X; - ioc->prod_name = "LSIFC929X"; - { + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < XL_929) { + ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level - * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. - */ - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF9F; - pcixcmd |= 0x0010; - pci_write_config_word(pdev, 0x6a, pcixcmd); + * for PCIX. Set MOST bits to zero. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); + } else { + ioc->prod_name = "LSIFC929XL"; + /* 929XL Chip Fix. Set MMRBC to 0x08. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd |= 0x08; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; - { - /* 919X Chip Fix. Set Split transactions level - * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. - */ - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF9F; - pcixcmd |= 0x0010; - pci_write_config_word(pdev, 0x6a, pcixcmd); - } + /* 919X Chip Fix. Set Split transactions level + * for PCIX. Set MOST bits to zero. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; - { - u8 revision; - - /* 1030 Chip Fix. Disable Split transactions - * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8) - */ - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - if (revision < 0x08) { - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF8F; - pci_write_config_word(pdev, 0x6a, pcixcmd); - } + /* 1030 Chip Fix. Disable Split transactions + * for PCIX. Set MOST bits to zero if Rev < C0( = 8). + */ + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < C0_1030) { + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { @@ -1515,17 +1531,18 @@ || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) mpt_detect_bound_ports(ioc, pdev); - if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { - printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", - ioc->name, r); - } + if ((r = mpt_do_ioc_recovery(ioc, + MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { + printk(KERN_WARNING MYNAM + ": WARNING - %s did not initialize properly! (%d)\n", + ioc->name, r); - if(r != 0 ) { Q_DEL_ITEM(ioc); mpt_adapters[ioc->id] = NULL; free_irq(ioc->pci_irq, ioc); iounmap(mem); kfree(ioc); + pci_set_drvdata(pdev, NULL); return r; } @@ -1565,6 +1582,7 @@ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; + mpt_sync_irq(pdev->irq); /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -1574,7 +1592,6 @@ Q_DEL_ITEM(ioc); mpt_adapter_dispose(ioc); - mptscsih_sync_irq(pdev->irq); pci_set_drvdata(pdev, NULL); } @@ -1755,20 +1772,23 @@ int r; int ii; int handlers; + int ret = 0; + int reset_alt_ioc_active = 0; printk(KERN_INFO MYNAM ": Initiating %s %s\n", ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); - /* Disable reply interrupts */ + /* Disable reply interrupts (also blocks FreeQ) */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; - /* NOTE: Access to IOC's request FreeQ is now blocked! */ if (ioc->alt_ioc) { - /* Disable alt-IOC's reply interrupts for a bit ... */ + if (ioc->alt_ioc->active) + reset_alt_ioc_active = 1; + + /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); ioc->alt_ioc->active = 0; - /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */ } hard = 1; @@ -1776,15 +1796,29 @@ hard = 0; if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { - printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", - ioc->name); + if (hard_reset_done == -4) { + printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n", + ioc->name); + + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ + dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", + ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->alt_ioc->active = 1; + } + + } else { + printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", + ioc->name); + } return -1; } /* hard_reset_done = 0 if a soft reset was performed * and 1 if a hard reset was performed. */ - if (hard_reset_done && ioc->alt_ioc) { + if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else @@ -1793,42 +1827,55 @@ ioc->alt_ioc->name, r); } - /* Get IOC facts! */ + /* Get IOC facts! Allow 1 retry */ if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) - return -2; - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + r = GetIocFacts(ioc, sleepFlag, reason); + + if (r) { + ret = -2; + } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } if (alt_ioc_ready) { - if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) - return -2; - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + /* Retry - alt IOC was initialized once + */ + r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); + } + if (r) { + alt_ioc_ready = 0; + reset_alt_ioc_active = 0; + } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc->alt_ioc); } } - /* - * Prime reply & request queues! + /* Prime reply & request queues! * (mucho alloc's) Must be done prior to * init as upper addresses are needed for init. + * If fails, continue with alt-ioc processing */ - if ((r = PrimeIocFifos(ioc)) != 0) - return -3; + if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0)) + ret = -3; - // May need to check/upload firmware & data here! - if ((r = SendIocInit(ioc, sleepFlag)) != 0) - return -4; + /* May need to check/upload firmware & data here! + * If fails, continue with alt-ioc processing + */ + if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0)) + ret = -4; // NEW! if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, r); alt_ioc_ready = 0; + reset_alt_ioc_active = 0; } if (alt_ioc_ready) { if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; + reset_alt_ioc_active = 0; printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", ioc->alt_ioc->name, r); @@ -1840,9 +1887,14 @@ ddlprintk((MYIOC_s_INFO_FMT "firmware upload required!\n", ioc->name)); - r = mpt_do_upload(ioc, sleepFlag); - if (r != 0) - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + /* Controller is not operational, cannot do upload + */ + if (ret == 0) { + r = mpt_do_upload(ioc, sleepFlag); + if (r != 0) + printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + } + /* Handle the alt IOC too */ if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ ddlprintk((MYIOC_s_INFO_FMT @@ -1855,12 +1907,13 @@ } } + if (ret == 0) { + /* Enable! (reply interrupt) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->active = 1; + } - /* Enable! (reply interrupt) */ - CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); - ioc->active = 1; - - if (ioc->alt_ioc) { + if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); @@ -1872,7 +1925,7 @@ * Enable MPT base driver management of EventNotification * and EventAck handling. */ - if (!ioc->facts.EventState) + if ((ret == 0) && (!ioc->facts.EventState)) (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) @@ -1886,7 +1939,7 @@ * routine calls HardResetHandler, which calls into here again, * and we try GetLanConfigPages again... */ - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { if ((int)ioc->chip_type <= (int)FC929) { /* * Pre-fetch FC port WWN and stuff... @@ -1928,6 +1981,8 @@ /* Check, and possibly reset, the coalescing value */ mpt_read_ioc_pg_1(ioc); + + mpt_read_ioc_pg_4(ioc); } GetIoUnitPage2(ioc); @@ -1942,24 +1997,24 @@ if (hard_reset_done) { r = handlers = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { + if ((ret == 0) && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", ioc->name, ii)); r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); handlers++; + } - if (alt_ioc_ready) { - dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } + if (alt_ioc_ready && MptResetHandlers[ii]) { + dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + handlers++; } } /* FIXME? Examine results here? */ } - return 0; + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2114,6 +2169,15 @@ kfree(this->spi_data.pIocPg3); this->spi_data.pIocPg3 = NULL; } + + if (freeup && this->spi_data.pIocPg4 != NULL) { + sz = this->spi_data.IocPg4Sz; + pci_free_consistent(this->pcidev, sz, + this->spi_data.pIocPg4, + this->spi_data.IocPg4_dma); + this->spi_data.pIocPg4 = NULL; + this->alloc_total -= sz; + } } } @@ -2429,7 +2493,7 @@ * 1 byte in size, so we can just fire it off as is. */ r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, - reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); if (r != 0) return r; @@ -2510,7 +2574,7 @@ */ ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits); - ioc->reply_sz = ioc->req_sz; + ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", @@ -2578,7 +2642,7 @@ * 1 byte in size, so we can just fire it off as is. */ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, - reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); if (ii != 0) return ii; @@ -2651,6 +2715,8 @@ /* ioc_init.MsgFlags = 0; */ /* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ + + ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize; if (sizeof(dma_addr_t) == sizeof(u64)) { /* Save the upper 32-bits of the request @@ -2663,6 +2729,9 @@ ioc_init.HostMfaHighAddr = cpu_to_le32(0); ioc_init.SenseBufferHighAddr = cpu_to_le32(0); } + + ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; + ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); @@ -2773,8 +2842,8 @@ void * mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) { - fw_image_t **cached_fw = NULL; - u8 *mem = NULL; + fw_image_t **cached_fw; + u8 *mem; dma_addr_t fw_dma; int alloc_total = 0; int bytes_left, bytes, num_frags; @@ -2922,7 +2991,7 @@ u8 reply[sizeof(FWUploadReply_t)]; FWUpload_t *prequest; FWUploadReply_t *preply; - FWUploadTCSGE_t *ptcsge = NULL; + FWUploadTCSGE_t *ptcsge; int sgeoffset; int ii, sz, reply_sz; int cmdStatus, freeMem = 0; @@ -3054,16 +3123,16 @@ static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) { - MpiFwHeader_t *FwHdr = NULL; + MpiFwHeader_t *FwHdr; MpiExtImageHeader_t *ExtHdr; - fw_image_t **pCached = NULL; + fw_image_t **pCached=NULL; int fw_sz; u32 diag0val; #ifdef MPT_DEBUG u32 diag1val = 0; #endif int count = 0; - u32 *ptru32 = NULL; + u32 *ptru32; u32 diagRwData; u32 nextImage; u32 ext_offset; @@ -3097,11 +3166,11 @@ pCached = (fw_image_t **)ioc->cached_fw; else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL)) pCached = (fw_image_t **)ioc->alt_ioc->cached_fw; + else + return -2; ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n", ioc->name, pCached)); - if (!pCached) - return -2; /* Write magic sequence to WriteSequence register * until enter diagnostic mode @@ -3351,6 +3420,7 @@ SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } else { mdelay (1000); @@ -3551,11 +3621,11 @@ } else { /* Wait for FW to reload and for board * to go to the READY state. - * Maximum wait is 30 seconds. + * Maximum wait is 60 seconds. * If fail, no error will check again * with calling program. */ - for (count = 0; count < 30; count ++) { + for (count = 0; count < 60; count ++) { doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; @@ -3673,7 +3743,7 @@ dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<reply_frames == NULL) { sz = (ioc->reply_sz * ioc->reply_depth) + 128; +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->reply_alloc_dma); +#else mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma); +#endif if (mem == NULL) goto out_fail; @@ -3778,7 +3852,11 @@ */ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->req_alloc_dma); +#else mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma); +#endif if (mem == NULL) goto out_fail; @@ -3894,8 +3972,8 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_handshake_req_reply_wait - Send MPT request to and receive reply from - * IOC via doorbell handshake method. + * mpt_handshake_req_reply_wait - Send MPT request to and receive reply + * from IOC via doorbell handshake method. * @ioc: Pointer to MPT_ADAPTER structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame @@ -3955,7 +4033,7 @@ * our handshake request. */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; if (!failcnt) { @@ -3973,7 +4051,7 @@ (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&ioc->chip->Doorbell, word); - if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; } @@ -4137,7 +4215,7 @@ } else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); @@ -4154,7 +4232,7 @@ * reply 16 bits at a time. */ for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); /* don't overflow our IOC hs_reply[] buffer! */ @@ -4163,7 +4241,7 @@ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); } - if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -4466,7 +4544,7 @@ static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) { - u8 *pbuf = NULL; + u8 *pbuf; dma_addr_t buf_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4528,6 +4606,9 @@ pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; + ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { @@ -4552,7 +4633,6 @@ } if (pbuf) { pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; } } } @@ -4589,6 +4669,8 @@ /* Save the Port Page 2 data * (reformat into a 32bit quantity) */ + data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; + ioc->spi_data.PortFlags = data; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { pdevice = &pPP2->DeviceSettings[ii]; data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | @@ -4598,7 +4680,6 @@ } pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; } } @@ -4671,11 +4752,12 @@ * -EFAULT if read of config page header fails or data pointer not NULL * -ENOMEM if pci_alloc failed */ -static int +int mpt_findImVolumes(MPT_ADAPTER *ioc) { - IOCPage2_t *pIoc2 = NULL; - ConfigPageIoc2RaidVol_t *pIocRv = NULL; + IOCPage2_t *pIoc2; + u8 *mem; + ConfigPageIoc2RaidVol_t *pIocRv; dma_addr_t ioc2_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4685,9 +4767,6 @@ u8 nVols, nPhys; u8 vid, vbus, vioc; - if (ioc->spi_data.pIocPg3) - return -EFAULT; - /* Read IOCP2 header then the page. */ header.PageVersion = 0; @@ -4716,11 +4795,22 @@ if (mpt_config(ioc, &cfg) != 0) goto done_and_free; + if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) { + mem = kmalloc(iocpage2sz, GFP_ATOMIC); + if (mem) { + ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem; + } else { + goto done_and_free; + } + } + memcpy(mem, (u8 *)pIoc2, iocpage2sz); + /* Identify RAID Volume Id's */ nVols = pIoc2->NumActiveVolumes; if ( nVols == 0) { - /* No RAID Volumes. Done. + /* No RAID Volume. */ + goto done_and_free; } else { /* At least 1 RAID Volume */ @@ -4745,17 +4835,14 @@ /* Identify Hidden Physical Disk Id's */ nPhys = pIoc2->NumActivePhysDisks; if (nPhys == 0) { - /* No physical disks. Done. + /* No physical disks. */ } else { mpt_read_ioc_pg_3(ioc); } done_and_free: - if (pIoc2) { - pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); - pIoc2 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); return rc; } @@ -4763,7 +4850,7 @@ int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) { - IOCPage3_t *pIoc3 = NULL; + IOCPage3_t *pIoc3; u8 *mem; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4816,18 +4903,66 @@ } } - if (pIoc3) { - pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); - pIoc3 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); return 0; } static void +mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) +{ + IOCPage4_t *pIoc4; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + dma_addr_t ioc4_dma; + int iocpage4sz; + + /* Read and save IOC Page 4 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 4; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return; + + if (header.PageLength == 0) + return; + + if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) { + iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */ + pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma); + if (!pIoc4) + return; + } else { + ioc4_dma = ioc->spi_data.IocPg4_dma; + iocpage4sz = ioc->spi_data.IocPg4Sz; + } + + /* Read the Page into dma memory. + */ + cfg.physAddr = ioc4_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4; + ioc->spi_data.IocPg4_dma = ioc4_dma; + ioc->spi_data.IocPg4Sz = iocpage4sz; + } else { + pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma); + ioc->spi_data.pIocPg4 = NULL; + } +} + +static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) { - IOCPage1_t *pIoc1 = NULL; + IOCPage1_t *pIoc1; CONFIGPARMS cfg; ConfigPageHeader_t header; dma_addr_t ioc1_dma; @@ -4903,10 +5038,7 @@ } } - if (pIoc1) { - pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); - pIoc1 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); return; } @@ -5022,9 +5154,8 @@ pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; - pReq->Reserved1[0] = 0; - pReq->Reserved1[1] = 0; - pReq->Reserved1[2] = 0; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; pReq->MsgFlags = 0; for (ii=0; ii < 8; ii++) pReq->Reserved2[ii] = 0; @@ -5083,6 +5214,112 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_toolbox - Generic function to issue toolbox message + * @ioc - Pointer to an adapter structure + * @cfg - Pointer to a toolbox structure. Struct contains + * action, page address, direction, physical address + * and pointer to a configuration page header + * Page header is updated. + * + * Returns 0 for success + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +int +mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) +{ + ToolboxIstwiReadWriteRequest_t *pReq; + MPT_FRAME_HDR *mf; + unsigned long flags; + int rc; + int flagsLength; + int in_isr; + + /* (Bugzilla:fibrebugs, #513) + * Bug fix (part 1)! 20010905 -sralston + * Prevent calling wait_event() (below), if caller happens + * to be in ISR context, because that is fatal! + */ + in_isr = in_interrupt(); + if (in_isr) { + dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n", + ioc->name)); + return -EPERM; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + pReq = (ToolboxIstwiReadWriteRequest_t *)mf; + pReq->Tool = pCfg->action; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_TOOLBOX; + pReq->Reserved1 = 0; + pReq->Reserved2 = 0; + pReq->MsgFlags = 0; + pReq->Flags = pCfg->dir; + pReq->BusNum = 0; + pReq->Reserved3 = 0; + pReq->NumAddressBytes = 0x01; + pReq->Reserved4 = 0; + pReq->DataLength = 0x04; + pReq->DeviceAddr = 0xB0; + pReq->Addr1 = 0; + pReq->Addr2 = 0; + pReq->Addr3 = 0; + pReq->Reserved5 = 0; + + /* Add a SGE to the config request. + */ + + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4; + + mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr); + + dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n", + ioc->name, pReq->Tool)); + + /* Append pCfg pointer to end of mf + */ + *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; + + /* Initalize the timer + */ + init_timer(&pCfg->timer); + pCfg->timer.data = (unsigned long) ioc; + pCfg->timer.function = mpt_timer_expired; + pCfg->wait_done = 0; + + /* Set the timer; ensure 10 second minimum */ + if (pCfg->timeout < 10) + pCfg->timer.expires = jiffies + HZ*10; + else + pCfg->timer.expires = jiffies + HZ*pCfg->timeout; + + /* Add to end of Q, set timer and then issue this command */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + add_timer(&pCfg->timer); + mpt_put_msg_frame(mpt_base_index, ioc->id, mf); + wait_event(mpt_waitq, pCfg->wait_done); + + /* mf has been freed - do not access */ + + rc = pCfg->status; + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_timer_expired - Call back for timer process. * Used only internal config functionality. @@ -5124,9 +5361,12 @@ dprintk((KERN_WARNING MYNAM ": IOC %s_reset routed to MPT base driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - if (reset_phase == MPT_IOC_PRE_RESET) { + if (reset_phase == MPT_IOC_SETUP_RESET) { + ; + } else if (reset_phase == MPT_IOC_PRE_RESET) { /* If the internal config Q is not empty - * delete timer. MF resources will be freed when * the FIFO's are primed. @@ -5590,7 +5830,7 @@ int rc; unsigned long flags; - dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); + dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); printk("MF count 0x%x !\n", ioc->mfcnt); @@ -5611,6 +5851,29 @@ /* FIXME: If do_ioc_recovery fails, repeat.... */ + /* The SCSI driver needs to adjust timeouts on all current + * commands prior to the diagnostic reset being issued. + * Prevents timeouts occuring during a diagnostic reset...very bad. + * For all other protocol drivers, this is a no-op. + */ + { + int ii; + int r = 0; + + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + if (MptResetHandlers[ii]) { + dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n", + ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) { + dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET); + } + } + } + } + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); @@ -5625,7 +5888,7 @@ ioc->alt_ioc->diagPending = 0; spin_unlock_irqrestore(&ioc->diagLock, flags); - dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); return rc; } @@ -5634,7 +5897,7 @@ static char * EventDescriptionStr(u8 event, u32 evData0) { - char *ds = NULL; + char *ds; switch(event) { case MPI_EVENT_NONE: @@ -5839,109 +6102,11 @@ "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; - char *desc = "unknown"; u8 subcl = (log_info >> 24) & 0x7; - u32 SubCl = log_info & 0x27000000; - - switch(log_info) { -/* FCP Initiator */ - case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: - desc = "Received an out of order frame - unsupported"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: - desc = "Bad start of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME: - desc = "Bad end of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN: - desc = "Receiver hardware detected overrun"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER: - desc = "Other errors caught by IOC which require retries"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD: - desc = "Main processor could not initialize sub-processor"; - break; -/* FC Target */ - case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC: - desc = "Not sent because we are waiting for a PDISC from the initiator"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN: - desc = "Not sent because we are not logged in to the remote node"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP: - desc = "Data Out, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP: - desc = "Data In, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA: - desc = "Data In, Auto Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP: - desc = "Data Out, No Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP: - desc = "Auto-response after a write not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP: - desc = "Data In, No Response, not completed due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA: - desc = "Data In, No Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP: - desc = "Manual Response not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3: - desc = "Not sent because remote node does not support Class 3"; - break; - case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID: - desc = "Not sent because login to remote node not validated"; - break; - case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: - desc = "Cleared from the outbound queue after a logout"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: - desc = "Cleared waiting for data after a logout"; - break; -/* LAN */ - case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING: - desc = "Transaction Context Sgl Missing"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE: - desc = "Transaction Context found before an EOB"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET: - desc = "Transaction Context value has reserved bits set"; - break; - case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG: - desc = "Invalid SGL Flags"; - break; -/* FC Link */ - case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT: - desc = "Loop initialization timed out"; - break; - case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED: - desc = "Another system controller already initialized the loop"; - break; - case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED: - desc = "Not synchronized to signal or still negotiating (possible cable problem)"; - break; - case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR: - desc = "CRC check detected error on received frame"; - break; - } +// u32 SubCl = log_info & 0x27000000; printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", ioc->name, log_info, subcl_str[subcl]); - if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) - printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); - else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE) - printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */ - else - printk("\n" KERN_INFO " %s\n", desc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6021,7 +6186,6 @@ isense_idx = last_drv_idx; r = 1; } - mpt_inc_use_count(); return r; } @@ -6040,7 +6204,6 @@ mpt_ScsiOpcodesPtr = NULL; printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); isense_idx = -1; - mpt_dec_use_count(); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6072,6 +6235,8 @@ EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); +EXPORT_SYMBOL(mpt_toolbox); +EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/mptbase.h Sat Apr 3 19:38:41 2004 @@ -8,7 +8,7 @@ * Credits: * (see mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -68,6 +68,7 @@ #include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ #include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ +#include "lsi/mpi_tool.h" /* Tools support */ #include "lsi/fc_log.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -77,11 +78,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2003 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.00.03" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.00.03" +#define MPT_LINUX_VERSION_COMMON "3.01.01" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.01" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -93,10 +94,10 @@ */ #define MPT_MAX_ADAPTERS 18 #define MPT_MAX_PROTOCOL_DRIVERS 16 -#define MPT_MAX_BUS 1 +#define MPT_MAX_BUS 1 /* Do not change */ #define MPT_MAX_FC_DEVICES 255 #define MPT_MAX_SCSI_DEVICES 16 -#define MPT_LAST_LUN 31 +#define MPT_LAST_LUN 255 #define MPT_SENSE_BUFFER_ALLOC 64 /* allow for 256 max sense alloc, but only 255 max request */ #if MPT_SENSE_BUFFER_ALLOC >= 256 @@ -127,6 +128,8 @@ #define MPT_MAX_FRAME_SIZE 128 #define MPT_DEFAULT_FRAME_SIZE 128 +#define MPT_REPLY_FRAME_SIZE 0x40 /* Must be a multiple of 8 */ + #define MPT_SG_REQ_128_SCALE 1 #define MPT_SG_REQ_96_SCALE 2 #define MPT_SG_REQ_64_SCALE 4 @@ -150,6 +153,9 @@ #define MPT_NARROW 0 #define MPT_WIDE 1 +#define C0_1030 0x08 +#define XL_929 0x01 + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -185,8 +191,8 @@ void (*remove) (struct pci_dev *dev); void (*shutdown) (struct device * dev); #ifdef CONFIG_PM - int (*suspend) (struct pci_dev *dev, u32 state); int (*resume) (struct pci_dev *dev); + int (*suspend) (struct pci_dev *dev, u32 state); #endif }; @@ -201,9 +207,6 @@ u32 arg1; u32 pad; void *argp1; -#ifndef MPT_SCSI_USE_NEW_EH - void *argp2; -#endif } linkage; /* * NOTE: When request frames are free, on the linkage structure @@ -255,6 +258,7 @@ MPIHeader_t hdr; SCSIIORequest_t scsireq; SCSIIOReply_t sreply; + ConfigReply_t configreply; MPIDefaultReply_t reply; MPT_FRAME_TRACKER frame; } u; @@ -408,12 +412,9 @@ ScsiCmndTracker SentQ; ScsiCmndTracker DoneQ; u32 num_luns; -//--- LUN split here? - u32 luns; /* Max LUNs is 32 */ - u8 inq_data[SCSI_STD_INQUIRY_BYTES]; /* 36 */ - u8 pad0[4]; - u8 inq00_data[20]; - u8 pad1[4]; + u32 luns[8]; /* Max LUNs is 256 */ + u8 pad[4]; + u8 inq_data[8]; /* IEEE Registered Extended Identifier obtained via INQUIRY VPD page 0x83 */ /* NOTE: Do not separate uniq_prepad and uniq_data @@ -421,26 +422,17 @@ u8 uniq_prepad[8]; u8 uniq_data[20]; u8 pad2[4]; - u8 inqC3_data[12]; - u8 pad3[4]; - u8 inqC9_data[12]; - u8 pad4[4]; - u8 dev_vol_name[64]; } VirtDevice; /* * Fibre Channel (SCSI) target device and associated defines... */ -#define MPT_TARGET_DEFAULT_DV_STATUS 0 -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,55) -#define MPT_TARGET_FLAGS_CONFIGURED 0x02 -#define MPT_TARGET_FLAGS_Q_YES 0x08 -#else +#define MPT_TARGET_DEFAULT_DV_STATUS 0x00 #define MPT_TARGET_FLAGS_VALID_NEGO 0x01 #define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02 #define MPT_TARGET_FLAGS_Q_YES 0x08 #define MPT_TARGET_FLAGS_VALID_56 0x10 -#endif +#define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20 #define MPT_TARGET_NO_NEGO_WIDE 0x01 #define MPT_TARGET_NO_NEGO_SYNC 0x02 @@ -539,8 +531,13 @@ /* #define MPT_SCSICFG_BLK_NEGO 0x10 WriteSDP1 with WDTR and SDTR disabled */ typedef struct _ScsiCfgData { + u32 PortFlags; int *nvram; /* table of device NVRAM values */ + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ + IOCPage4_t *pIocPg4; /* SEP devices addressing */ + dma_addr_t IocPg4_dma; /* Phys Addr of IOCPage4 data */ + int IocPg4Sz; /* IOCPage4 size */ u8 dvStatus[MPT_MAX_SCSI_DEVICES]; int isRaid; /* bit field, 1 if RAID */ u8 minSyncFactor; /* 0xFF if async */ @@ -554,7 +551,8 @@ u8 dvScheduled; /* 1 if scheduled */ u8 forceDv; /* 1 to force DV scheduling */ u8 noQas; /* Disable QAS for this adapter */ - u8 rsvd[2]; + u8 Saf_Te; /* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */ + u8 rsvd[1]; } ScsiCfgData; typedef struct _fw_image { @@ -610,6 +608,9 @@ u32 sense_buf_low_dma; int mtrr_reg; struct pci_dev *pcidev; /* struct pci_dev pointer */ +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + struct pci_dev pcidev32; /* struct pci_dev pointer */ +#endif u8 *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ ScsiCfgData spi_data; /* Scsi config. data */ @@ -622,6 +623,12 @@ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ int eventLogSize; /* Max number of cached events */ +#ifdef MPTSCSIH_DBG_TIMEOUT + int timeout_hard; + int timeout_delta; + int timeout_cnt; + int timeout_maxcnt; +#endif struct _mpt_ioctl_events *events; /* pointer to event log */ fw_image_t **cached_fw; /* Pointer to FW SG List */ Q_TRACKER configQ; /* linked list of config. requests */ @@ -665,6 +672,7 @@ /* reset_phase defs */ #define MPT_IOC_PRE_RESET 0 #define MPT_IOC_POST_RESET 1 +#define MPT_IOC_SETUP_RESET 2 /* * Invent MPT host event (super-set of MPI Events) @@ -880,14 +888,12 @@ #define MPT_NVRAM_WIDE_DISABLE (0x00100000) #define MPT_NVRAM_BOOT_CHOICE (0x00200000) -#ifdef MPT_SCSI_USE_NEW_EH /* The TM_STATE variable is used to provide strict single threading of TM * requests as well as communicate TM error conditions. */ #define TM_STATE_NONE (0) #define TM_STATE_IN_PROGRESS (1) #define TM_STATE_ERROR (2) -#endif typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; @@ -928,12 +934,8 @@ u8 is_spi; /* Parallel SCSI i/f */ u8 negoNvram; /* DV disabled, nego NVRAM */ u8 is_multipath; /* Multi-path compatible */ -#ifdef MPT_SCSI_USE_NEW_EH u8 tmState; u8 rsvd[1]; -#else - u8 rsvd[2]; -#endif MPT_FRAME_HDR *tmPtr; /* Ptr to TM request*/ MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ struct scsi_cmnd *abortSCpnt; @@ -1033,8 +1035,10 @@ extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); +extern int mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); extern void *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img); +extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); /* diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c Sat Apr 3 19:38:41 2004 +++ b/drivers/message/fusion/mptctl.c Sat Apr 3 19:38:41 2004 @@ -29,7 +29,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston, Noah Romer * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -91,7 +92,7 @@ #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" -#define COPYRIGHT "Copyright (c) 1999-2003 LSI Logic Corporation" +#define COPYRIGHT "Copyright (c) 1999-2004 LSI Logic Corporation" #define MODULEAUTHOR "Steven J. Ralston, Noah Romer, Pamela Delaney" #include "mptbase.h" #include "mptctl.h" @@ -260,6 +261,7 @@ iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK; if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) { if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) { + ioc->ioctl->reset &= ~MPTCTL_RESET_OK; del_timer (&ioc->ioctl->timer); ioc->ioctl->timer.expires = jiffies + HZ; add_timer(&ioc->ioctl->timer); @@ -456,7 +458,7 @@ unsigned long flags; spin_lock_irqsave(&hd->ioc->FreeQlock, flags); -#ifdef MPT_SCSI_USE_NEW_EH + if (hd->tmState == TM_STATE_NONE) { hd->tmState = TM_STATE_IN_PROGRESS; hd->tmPending = 1; @@ -465,15 +467,7 @@ spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); return -EBUSY; } -#else - if (hd->tmPending) { - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - return -EBUSY; - } else { - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - } -#endif + return 0; } @@ -488,14 +482,10 @@ return; spin_lock_irqsave(&ioc->FreeQlock, flags); -#ifdef MPT_SCSI_USE_NEW_EH + hd->tmState = TM_STATE_ERROR; hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); -#else - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); -#endif return; } @@ -513,9 +503,12 @@ { MPT_IOCTL *ioctl = ioc->ioctl; dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - if (reset_phase == MPT_IOC_PRE_RESET){ + if (reset_phase == MPT_IOC_SETUP_RESET){ + ; + } else if (reset_phase == MPT_IOC_PRE_RESET){ /* Someone has called the reset handler to * do a hard reset. No more replies from the FW. @@ -532,13 +525,15 @@ } } else { + ioctl->tmPtr = NULL; + /* Set the status and continue IOCTL * processing. All memory will be free'd * by originating thread after wake_up is * called. */ if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){ - ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET; + ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; /* Wake up the calling process */ @@ -620,7 +615,11 @@ return -ENODEV; } - + if (!iocp->active) { + printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n", + __FILE__, __LINE__); + return -EFAULT; + } /* Handle those commands that are just returning * information stored in the driver. @@ -691,7 +690,7 @@ return -ENODEV; /* (-6) No such device or address */ } - if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) { + if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) { printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", __FILE__, __LINE__); return -1; @@ -1254,10 +1253,10 @@ /* Fill in the data and return the structure to the calling * program */ - if (ioc->chip_type == C1030) - karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; - else + if ((int)ioc->chip_type <= (int) FC929) karg.adapterType = MPT_IOCTL_INTERFACE_FC; + else + karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; port = karg.hdr.port; @@ -1307,7 +1306,8 @@ /* Set the Version Strings. */ - strlcpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); + strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); + karg.driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; karg.busChangeEvent = 0; karg.hostId = ioc->pfacts[port].PortSCSIID; @@ -1343,15 +1343,18 @@ MPT_ADAPTER *ioc; struct Scsi_Host *sh; MPT_SCSI_HOST *hd; + VirtDevice *vdev; char *pmem; int *pdata; + IOCPage2_t *pIoc2; int iocnum; int numDevices = 0; unsigned int max_id; - int ii, jj, lun; + int id, jj, indexed_lun, lun_index; + u32 lun; int maxWordsLeft; int numBytes; - u8 port; + u8 port, devType, bus_id; dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { @@ -1418,27 +1421,59 @@ * sh->max_id = maximum target ID + 1 */ if (hd && hd->Targets) { - ii = 0; - while (ii <= max_id) { - if (hd->Targets[ii]) { - for (jj = 0; jj <= MPT_LAST_LUN; jj++) { - lun = (1 << jj); - if (hd->Targets[ii]->luns & lun) { - numDevices++; - *pdata = (jj << 16) | ii; - --maxWordsLeft; - - pdata++; - - if (maxWordsLeft <= 0) - break; + mpt_findImVolumes(ioc); + pIoc2 = ioc->spi_data.pIocPg2; + for ( id = 0; id <= max_id; id++ ) { + if ( pIoc2 && pIoc2->NumActiveVolumes && + ( id == pIoc2->RaidVolume[0].VolumeID ) ) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR "mptctl_gettargetinfo - " + "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices); + goto data_space_full; + } + if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 ) + devType = 0x80; + else + devType = 0xC0; + bus_id = pIoc2->RaidVolume[0].VolumeBus; + numDevices++; + *pdata = ( (devType << 24) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR "mptctl_gettargetinfo - " + "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); + pdata++; + --maxWordsLeft; + } else { + vdev = hd->Targets[id]; + if (vdev) { + for (jj = 0; jj <= MPT_LAST_LUN; jj++) { + lun_index = (jj >> 5); + indexed_lun = (jj % 32); + lun = (1 << indexed_lun); + if (vdev->luns[lun_index] & lun) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR + "mptctl_gettargetinfo - " + "buffer is full but more targets are available on ioc %d numDevices=%d\n", + iocnum, numDevices); + goto data_space_full; + } + bus_id = vdev->bus_id; + numDevices++; + *pdata = ( (jj << 16) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR + "mptctl_gettargetinfo - " + "target ioc=%d target=%x numDevices=%d pdata=%p\n", + iocnum, *pdata, numDevices, pdata)); + pdata++; + --maxWordsLeft; + } } } } - ii++; } } } +data_space_full: karg.numDevices = numDevices; /* Copy part of the data from kernel memory to user memory @@ -1507,8 +1542,10 @@ #else karg.chip_type = ioc->chip_type; #endif - strlcpy (karg.name, ioc->name, MPT_MAX_NAME); - strlcpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); + strncpy (karg.name, ioc->name, MPT_MAX_NAME); + karg.name[MPT_MAX_NAME-1]='\0'; + strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); + karg.product[MPT_PRODUCT_LENGTH-1]='\0'; /* Copy the data from kernel memory to user memory */ @@ -1806,22 +1843,20 @@ MPT_FRAME_HDR *mf = NULL; MPIHeader_t *hdr; char *psge; - MptSge_t *this_sge = NULL; - MptSge_t *sglbuf = NULL; struct buflist bufIn; /* data In buffer */ struct buflist bufOut; /* data Out buffer */ - dma_addr_t sglbuf_dma; - dma_addr_t dma_addr; + dma_addr_t dma_addr_in; + dma_addr_t dma_addr_out; int dir; /* PCI data direction */ int sgSize = 0; /* Num SG elements */ - int this_alloc; - int iocnum, flagsLength; - int sz, rc = 0; - int msgContext; + int iocnum, flagsLength; + int sz, rc = 0; + int msgContext; int tm_flags_set = 0; u16 req_idx; dctlprintk(("mptctl_do_mpt_command called.\n")); + bufIn.kptr = bufOut.kptr = NULL; if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { @@ -1848,7 +1883,7 @@ if (karg.dataOutSize > 0) sz += sizeof(dma_addr_t) + sizeof(u32); - if ( sz > ioc->req_sz) { + if (sz > ioc->req_sz) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Request frame too large (%d) maximum (%d)\n", __FILE__, __LINE__, sz, ioc->req_sz); @@ -1891,6 +1926,9 @@ switch (hdr->Function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: + karg.dataOutSize = karg.dataInSize = 0; + break; + case MPI_FUNCTION_CONFIG: case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: @@ -1928,12 +1966,14 @@ */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + else + pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (req_idx * MPT_SENSE_BUFFER_ALLOC)); - if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { + if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { if (hd->Targets) pTarget = hd->Targets[target]; } @@ -1944,11 +1984,10 @@ /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ - if (karg.dataOutSize > 0 ) { + if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; - } - else { + } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } @@ -1990,6 +2029,8 @@ */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + else + pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma @@ -2001,11 +2042,10 @@ /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ - if (karg.dataOutSize > 0 ) { + if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; - } - else { + } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } @@ -2033,7 +2073,7 @@ __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; - } else if (mptctl_set_tm_flags(hd) != 0) { + } else if (mptctl_set_tm_flags(hd) != 0) { rc = -EPERM; goto done_free_mem; } @@ -2107,7 +2147,7 @@ * preceede the data in (read) SGE. psgList is used to free the * allocated memory. */ - psge = (char *) ( ((int *) mf) + karg.dataSgeOffset); + psge = (char *) (((int *) mf) + karg.dataSgeOffset); flagsLength = 0; /* bufIn and bufOut are used for user to kernel space transfers @@ -2115,30 +2155,18 @@ bufIn.kptr = bufOut.kptr = NULL; bufIn.len = bufOut.len = 0; - if (karg.dataOutSize > 0 ) + if (karg.dataOutSize > 0) sgSize ++; - if (karg.dataInSize > 0 ) + if (karg.dataInSize > 0) sgSize ++; if (sgSize > 0) { - /* Allocate memory for the SGL. - * Used to free kernel memory once - * the MF is freed. - */ - sglbuf = pci_alloc_consistent (ioc->pcidev, - sgSize*sizeof(MptSge_t), &sglbuf_dma); - if (sglbuf == NULL) { - rc = -ENOMEM; - goto done_free_mem; - } - this_sge = sglbuf; - /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { dir = PCI_DMA_TODEVICE; - if (karg.dataInSize > 0 ) { + if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) @@ -2147,22 +2175,25 @@ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; } flagsLength |= karg.dataOutSize; - - this_alloc = karg.dataOutSize; - bufOut.len = this_alloc; + bufOut.len = karg.dataOutSize; bufOut.kptr = pci_alloc_consistent( - ioc->pcidev, this_alloc, &dma_addr); + ioc->pcidev, bufOut.len, &dma_addr_out); if (bufOut.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; } else { + /* Set up this SGE. + * Copy to MF and to sglbuf + */ + mpt_add_sge(psge, flagsLength, dma_addr_out); + psge += (sizeof(u32) + sizeof(dma_addr_t)); + /* Copy user data to kernel space. */ if (copy_from_user(bufOut.kptr, karg.dataOutBufPtr, bufOut.len)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - Unable " "to read user data " @@ -2171,16 +2202,6 @@ rc = -EFAULT; goto done_free_mem; } - - /* Set up this SGE. - * Copy to MF and to sglbuf - */ - mpt_add_sge(psge, flagsLength, dma_addr); - psge += (sizeof(u32) + sizeof(dma_addr_t)); - - this_sge->FlagsLength = flagsLength; - this_sge->Address = dma_addr; - this_sge++; } } @@ -2189,10 +2210,10 @@ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; - this_alloc = karg.dataInSize; - bufIn.len = this_alloc; + bufIn.len = karg.dataInSize; bufIn.kptr = pci_alloc_consistent(ioc->pcidev, - this_alloc, &dma_addr); + bufIn.len, &dma_addr_in); + if (bufIn.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; @@ -2200,11 +2221,7 @@ /* Set up this SGE * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr); - - this_sge->FlagsLength = flagsLength; - this_sge->Address = dma_addr; - this_sge++; + mpt_add_sge(psge, flagsLength, dma_addr_in); } } } else { @@ -2228,7 +2245,7 @@ if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { rc = mpt_send_handshake_request(mptctl_id, ioc->id, - sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP); + sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc == 0) { wait_event(mptctl_wait, ioc->ioctl->wait_done); } else { @@ -2236,45 +2253,41 @@ tm_flags_set= 0; del_timer(&ioc->ioctl->timer); ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; - ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED; + ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED; + mpt_free_msg_frame(mptctl_id, ioc->id, mf); } } else { mpt_put_msg_frame(mptctl_id, ioc->id, mf); wait_event(mptctl_wait, ioc->ioctl->wait_done); } - /* The command is complete. * Return data to the user. + mf = NULL; + + /* MF Cleanup: + * If command failed and failure triggered a diagnostic reset + * OR a diagnostic reset happens during command processing, + * no data, messaging queues are reset (mf cannot be accessed), + * and status is DID_IOCRESET * - * If command completed, mf has been freed so cannot - * use this memory. + * If a user-requested bus reset fails to be handshaked, then + * mf is returned to free queue and status is TM_FAILED. * - * If timeout, a recovery mechanism has been called. - * Need to free the mf. + * Otherise, the command completed and the mf was freed + # by ISR (mf cannot be touched). */ if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { - - /* A timeout - there is no data to return to the - * the user other than an error. - * The timer callback deleted the + /* The timer callback deleted the * timer and reset the adapter queues. */ printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - " "Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__); tm_flags_set= 0; rc = -ETIME; - - /* Free memory and return to the calling function - */ - goto done_free_mem; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) { - /* User TM request failed! + /* User TM request failed! mf has not been freed. */ rc = -ENODATA; } else { - /* Callback freed request frame. - */ - mf = NULL; - /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ @@ -2332,42 +2345,31 @@ } done_free_mem: - /* Clear status bits. - */ - ioc->ioctl->status = 0; + /* Clear all status bits except TMTIMER_ACTIVE, this bit is cleared + * upon completion of the TM command. + * ioc->ioctl->status = 0; + */ + ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_TIMER_ACTIVE | MPT_IOCTL_STATUS_TM_FAILED | + MPT_IOCTL_STATUS_COMMAND_GOOD | MPT_IOCTL_STATUS_SENSE_VALID | + MPT_IOCTL_STATUS_RF_VALID | MPT_IOCTL_STATUS_DID_IOCRESET); if (tm_flags_set) mptctl_free_tm_flags(ioc); - if (sglbuf) { - this_sge = sglbuf; - - /* Free the allocated memory. - */ - if (bufOut.kptr != NULL ) { - dma_addr = this_sge->Address; - this_sge++; /* go to next structure */ - this_alloc = bufOut.len; - pci_free_consistent(ioc->pcidev, - this_alloc, (void *) bufOut.kptr, dma_addr); - } - - if (bufIn.kptr != NULL ) { - dma_addr = this_sge->Address; - this_alloc = bufIn.len; - - pci_free_consistent(ioc->pcidev, - this_alloc, (void *) bufIn.kptr, dma_addr); - } - - this_alloc = sgSize * sizeof(MptSge_t); + /* Free the allocated memory. + */ + if (bufOut.kptr != NULL) { pci_free_consistent(ioc->pcidev, - this_alloc, (void *) sglbuf, sglbuf_dma); + bufOut.len, (void *) bufOut.kptr, dma_addr_out); + } + if (bufIn.kptr != NULL) { + pci_free_consistent(ioc->pcidev, + bufIn.len, (void *) bufIn.kptr, dma_addr_in); } - /* mf will be null if allocation failed OR - * if command completed OK (callback freed) + /* mf is null if command issued successfully + * otherwise, failure occured after mf acquired. */ if (mf) mpt_free_msg_frame(mptctl_id, ioc->id, mf); @@ -2405,7 +2407,7 @@ */ if (data_size == sizeof(hp_host_info_t)) cim_rev = 1; - else if (data_size == (sizeof(hp_host_info_t) + 12)) + else if (data_size == sizeof(hp_host_info_rev0_t)) cim_rev = 0; /* obsolete */ else return -EFAULT; @@ -2478,7 +2480,7 @@ cfg.dir = 0; /* read */ cfg.timeout = 10; - strlcpy(karg.serial_number, " ", sizeof(karg.serial_number)); + strncpy(karg.serial_number, " ", 24); if (mpt_config(ioc, &cfg) == 0) { if (cfg.hdr->PageLength > 0) { /* Issue the second config page request */ @@ -2489,9 +2491,10 @@ cfg.physAddr = buf_dma; if (mpt_config(ioc, &cfg) == 0) { ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; - if (strlen(pdata->BoardTracerNumber) > 1) - strlcpy(karg.serial_number, pdata->BoardTracerNumber, - sizeof(karg.serial_number)); + if (strlen(pdata->BoardTracerNumber) > 1) { + strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); + karg.serial_number[24-1]='\0'; + } } pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); pbuf = NULL; @@ -2535,6 +2538,20 @@ } } + cfg.pageAddr = 0; + cfg.action = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; + cfg.dir = MPI_TB_ISTWI_FLAGS_READ; + cfg.timeout = 10; + pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); + if (pbuf) { + cfg.physAddr = buf_dma; + if ((mpt_toolbox(ioc, &cfg)) == 0) { + karg.rsvd = *(u32 *)pbuf; + } + pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); + pbuf = NULL; + } + /* Copy the data from kernel memory to user memory */ if (copy_to_user((char *)arg, &karg, @@ -2736,6 +2753,19 @@ * to ensure the structure contents is properly processed by mptctl. */ static int +compat_mptctl_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + int ret; + + lock_kernel(); + dctlprintk((KERN_INFO MYNAM "::compat_mptctl_ioctl() called\n")); + ret = mptctl_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + return ret; +} + +static int compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp) { @@ -2875,30 +2905,30 @@ } #ifdef CONFIG_COMPAT - err = register_ioctl32_conversion(MPTIOCINFO, NULL); + err = register_ioctl32_conversion(MPTIOCINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTIOCINFO1, NULL); + err = register_ioctl32_conversion(MPTIOCINFO1, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTTARGETINFO, NULL); + err = register_ioctl32_conversion(MPTTARGETINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTTEST, NULL); + err = register_ioctl32_conversion(MPTTEST, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTQUERY, NULL); + err = register_ioctl32_conversion(MPTEVENTQUERY, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTENABLE, NULL); + err = register_ioctl32_conversion(MPTEVENTENABLE, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTREPORT, NULL); + err = register_ioctl32_conversion(MPTEVENTREPORT, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTHARDRESET, NULL); + err = register_ioctl32_conversion(MPTHARDRESET, compat_mptctl_ioctl); if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTCOMMAND32, compat_mpt_command); if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTFWDOWNLOAD32, compat_mptfwxfer_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL); + err = register_ioctl32_conversion(HP_GETHOSTINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL); + err = register_ioctl32_conversion(HP_GETTARGETINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; #endif diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h --- a/drivers/message/fusion/mptctl.h Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/mptctl.h Sat Apr 3 19:38:43 2004 @@ -15,7 +15,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -342,6 +342,7 @@ #define CPQFCTS_IOC_MAGIC 'Z' #define HP_IOC_MAGIC 'Z' #define HP_GETHOSTINFO _IOR(HP_IOC_MAGIC, 20, hp_host_info_t) +#define HP_GETHOSTINFO1 _IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t) #define HP_GETTARGETINFO _IOR(HP_IOC_MAGIC, 21, hp_target_info_t) /* All HP IOCTLs must include this header @@ -357,7 +358,7 @@ /* * Header: * iocnum required (input) - * host ignored + * host ignored * channe ignored * id ignored * lun ignored @@ -371,9 +372,9 @@ u8 devfn; u8 bus; ushort host_no; /* SCSI Host number, if scsi driver not loaded*/ - u8 fw_version[16]; /* string */ + u8 fw_version[16]; /* string */ u8 serial_number[24]; /* string */ - u32 ioc_status; + u32 ioc_status; u32 bus_phys_width; u32 base_io_addr; u32 rsvd; @@ -382,10 +383,33 @@ unsigned int timeouts; /* num timeouts */ } hp_host_info_t; +/* replace ulongs with uints, need to preserve backwards + * compatibility. + */ +typedef struct _hp_host_info_rev0 { + hp_header_t hdr; + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_id; + u8 devfn; + u8 bus; + ushort host_no; /* SCSI Host number, if scsi driver not loaded*/ + u8 fw_version[16]; /* string */ + u8 serial_number[24]; /* string */ + u32 ioc_status; + u32 bus_phys_width; + u32 base_io_addr; + u32 rsvd; + unsigned long hard_resets; /* driver initiated resets */ + unsigned long soft_resets; /* ioc, external resets */ + unsigned long timeouts; /* num timeouts */ +} hp_host_info_rev0_t; + /* * Header: * iocnum required (input) - * host required + * host required * channel required (bus number) * id required * lun ignored diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/mptlan.c Sat Apr 3 19:38:43 2004 @@ -23,7 +23,7 @@ * * (see also mptbase.c) * - * Copyright (c) 2000-2003 LSI Logic Corporation + * Copyright (c) 2000-2004 LSI Logic Corporation * Originally By: Noah Romer * (mailto:mpt_linux_developer@lsil.com) * @@ -337,15 +337,18 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { struct net_device *dev = mpt_landev[ioc->id]; - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); if (priv->mpt_rxfidx == NULL) return (1); - if (reset_phase == MPT_IOC_PRE_RESET) { + if (reset_phase == MPT_IOC_SETUP_RESET) { + ; + } else if (reset_phase == MPT_IOC_PRE_RESET) { int i; unsigned long flags; @@ -406,7 +409,7 @@ static int mpt_lan_open(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); int i; if (mpt_lan_reset(dev) != 0) { @@ -497,7 +500,7 @@ { MPT_FRAME_HDR *mf; LANResetRequest_t *pResetReq; - struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id); @@ -526,7 +529,7 @@ static int mpt_lan_close(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; unsigned int timeout; int i; @@ -587,7 +590,7 @@ static struct net_device_stats * mpt_lan_get_stats(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); return (struct net_device_stats *) &priv->stats; } @@ -607,7 +610,7 @@ static void mpt_lan_tx_timeout(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; if (mpt_dev->active) { @@ -621,7 +624,7 @@ static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *sent; unsigned long flags; @@ -654,7 +657,7 @@ static int mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *sent; unsigned long flags; @@ -727,7 +730,7 @@ static int mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; MPT_FRAME_HDR *mf; LANSendRequest_t *pSendReq; @@ -955,11 +958,13 @@ return -ENOMEM; } - pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, len), old_skb->data, len); + pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); goto out; } @@ -1113,12 +1118,17 @@ // IOC_AND_NETDEV_NAMES_s_s(dev), // i, l)); - pci_dma_sync_single(mpt_dev->pcidev, - priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, l), old_skb->data, l); + pci_dma_sync_single_for_device(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; szrem -= l; } @@ -1136,11 +1146,18 @@ return -ENOMEM; } - pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, len), old_skb->data, len); + pci_dma_sync_single_for_device(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&priv->rxfidx_lock, flags); priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); @@ -1369,7 +1386,7 @@ dev->mtu = MPT_LAN_MTU; - priv = (struct mpt_lan_priv *) dev->priv; + priv = netdev_priv(dev); priv->mpt_dev = mpt_dev; priv->pnum = pnum; diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Sat Apr 3 19:38:57 2004 +++ b/drivers/message/fusion/mptscsih.c Sat Apr 3 19:38:57 2004 @@ -21,7 +21,7 @@ * * (see mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Original author: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -165,17 +165,19 @@ static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx); static void post_pendingQ_commands(MPT_SCSI_HOST *hd); -static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); +static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); +static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); -static void mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev); +static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags); +static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus); static int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_timer_expired(unsigned long data); static void mptscsih_taskmgmt_timeout(unsigned long data); @@ -190,7 +192,7 @@ static void mptscsih_domainValidation(void *hd); static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id); -static int mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target); +static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target); static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif @@ -200,8 +202,8 @@ static int __init mptscsih_init (void); static void __exit mptscsih_exit (void); -static int __devinit mptscsih_probe (struct pci_dev *, const struct pci_device_id *); -static void __devexit mptscsih_remove(struct pci_dev *); +static int mptscsih_probe (struct pci_dev *, const struct pci_device_id *); +static void mptscsih_remove(struct pci_dev *); static void mptscsih_shutdown(struct device *); #ifdef CONFIG_PM static int mptscsih_suspend(struct pci_dev *pdev, u32 state); @@ -214,7 +216,6 @@ */ static int mpt_scsi_hosts = 0; -static atomic_t queue_depth; static int ScsiDoneCtx = -1; static int ScsiTaskCtx = -1; @@ -243,6 +244,10 @@ static struct mptscsih_driver_setup driver_setup = MPTSCSIH_DRIVER_SETUP; +#ifdef MPTSCSIH_DBG_TIMEOUT +static Scsi_Cmnd *foo_to[8]; +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* see mptscsih.h */ @@ -438,10 +443,10 @@ static inline int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) { - MPT_FRAME_HDR *chainBuf = NULL; + MPT_FRAME_HDR *chainBuf; unsigned long flags; - int rc = FAILED; - int chain_idx = MPT_HOST_NO_CHAIN; + int rc; + int chain_idx; spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if (!Q_IS_EMPTY(&hd->FreeChainQ)) { @@ -454,6 +459,10 @@ chain_idx = offset / hd->ioc->req_sz; rc = SUCCESS; } + else { + rc = FAILED; + chain_idx = MPT_HOST_NO_CHAIN; + } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); @@ -506,13 +515,12 @@ /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ - sges_left = SCpnt->use_sg; - if (SCpnt->use_sg) { + if ( (sges_left = SCpnt->use_sg) ) { sges_left = pci_map_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - if (sges_left == 0) + if (sges_left == 0) return FAILED; } else if (SCpnt->request_bufflen) { dma_addr_t buf_dma_addr; @@ -729,50 +737,67 @@ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n", - ioc->name, mf?"BAD":"NULL", (void *) mf); - return 0; - } - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); sc = hd->ScsiLookup[req_idx]; if (sc == NULL) { + MPIHeader_t *hdr = (MPIHeader_t *)mf; + /* Remark: writeSDP1 will use the ScsiDoneCtx * If a SCSI I/O cmd, device disabled by OS and * completion done. Cannot touch sc struct. Just free mem. */ - atomic_dec(&queue_depth); + if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) + printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", + ioc->name); mptscsih_freeChainBuffers(hd, req_idx); return 1; } - dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", - ioc->name, mf, mr, sc, req_idx)); - - atomic_dec(&queue_depth); + dmfprintk((MYIOC_s_INFO_FMT + "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", + ioc->name, mf, mr, sc, req_idx)); sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; +#ifdef MPTSCSIH_DBG_TIMEOUT + if (ioc->timeout_cnt > 0) { + int ii, left = 0; + + for (ii=0; ii < 8; ii++) { + if (sc == foo_to[ii]) { + printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n", + ioc->name, sc, jiffies); + foo_to[ii] = NULL; + } + if (foo_to[ii] != NULL) + left++; + } + + if (left == 0) { + ioc->timeout_maxcnt = 0; + ioc->timeout_cnt = 0; + } + } +#endif + if (pScsiReply == NULL) { /* special context reply handling */ ; } else { u32 xfer_cnt; u16 status; - u8 scsi_state; + u8 scsi_state, scsi_status; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; - dsprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", + dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], mf, mr, sc)); - dsprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" + dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", status, scsi_state, pScsiReply->SCSIStatus, le32_to_cpu(pScsiReply->IOCLogInfo))); @@ -780,14 +805,6 @@ if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); - /* - * Look for + dump FCP ResponseInfo[]! - */ - if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { - dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n", - le32_to_cpu(pScsiReply->ResponseInfo))); - } - switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ /* CHECKME! @@ -827,52 +844,45 @@ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ /* - * YIKES! I just discovered that SCSI IO which - * returns check condition, SenseKey=05 (ILLEGAL REQUEST) - * and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific), - * comes down this path! * Do upfront check for valid SenseData and give it * precedence! */ - sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; - if (scsi_state == 0) { - ; - } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { + scsi_status = pScsiReply->SCSIStatus; + sc->result = (DID_OK << 16) | scsi_status; + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ ; - } else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { - /* What to do? - */ - sc->result = DID_SOFT_ERROR << 16; - } - else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { - /* Not real sure here either... */ - sc->result = DID_RESET << 16; + } else { + if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) { + sc->result = DID_SOFT_ERROR << 16; + } + if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_RESET << 16; + } } /* Give report and update residual count. */ - xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); sc->resid = sc->request_bufflen - xfer_cnt; dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); - - if(sc->underflow > xfer_cnt) { - printk(MYIOC_s_INFO_FMT - "SCSI data underrun: underflow=%02x, xfercnt=%02x\n", - ioc->name, sc->underflow, xfer_cnt); - sc->result = DID_SOFT_ERROR << 16; - } - + /* Report Queue Full */ - if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) + if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); - + break; case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ @@ -965,9 +975,7 @@ hd->ScsiLookup[req_idx] = NULL; - MPT_HOST_LOCK(flags); sc->scsi_done(sc); /* Issue the command callback */ - MPT_HOST_UNLOCK(flags); /* Free Chain buffers */ mptscsih_freeChainBuffers(hd, req_idx); @@ -988,7 +996,7 @@ /* Flush the doneQ. */ - dprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); + dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); while (1) { spin_lock_irqsave(&hd->freedoneQlock, flags); if (Q_IS_EMPTY(&hd->doneQ)) { @@ -1013,9 +1021,7 @@ /* Do the OS callback. */ - MPT_HOST_LOCK(flags); SCpnt->scsi_done(SCpnt); - MPT_HOST_UNLOCK(flags); } return; @@ -1055,6 +1061,26 @@ return; } +static void +mptscsih_reset_timeouts (MPT_SCSI_HOST *hd) +{ + Scsi_Cmnd *SCpnt; + int ii; + int max = hd->ioc->req_depth; + + + for (ii= 0; ii < max; ii++) { + if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { + /* calling mod_timer() panics in 2.6 kernel... + * need to investigate + */ +// mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); + dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); + } + } +} + /* * mptscsih_flush_running_cmds - For each command found, search * Scsi_Host instance taskQ and reply to OS. @@ -1068,23 +1094,24 @@ static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { - Scsi_Cmnd *SCpnt = NULL; - MPT_FRAME_HDR *mf = NULL; + Scsi_Cmnd *SCpnt; + MPT_FRAME_HDR *mf; + MPT_DONE_Q *buffer; int ii; int max = hd->ioc->req_depth; + unsigned long flags; dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); for (ii= 0; ii < max; ii++) { if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { /* Command found. - * - * Search pendingQ, if found, - * delete from Q. If found, do not decrement - * queue_depth, command never posted. */ - if (mptscsih_search_pendingQ(hd, ii) == NULL) - atomic_dec(&queue_depth); + + /* Search pendingQ, if found, + * delete from Q. + */ + mptscsih_search_pendingQ(hd, ii); /* Null ScsiLookup index */ @@ -1111,15 +1138,39 @@ } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; - MPT_HOST_LOCK(flags); - SCpnt->scsi_done(SCpnt); /* Issue the command callback */ - MPT_HOST_UNLOCK(flags); /* Free Chain buffers */ mptscsih_freeChainBuffers(hd, ii); /* Free Message frames */ mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + +#if 1 + /* Post to doneQ, do not reply until POST phase + * of reset handler....prevents new commands from + * being queued. + */ + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->freeQ)) { + buffer = hd->freeQ.head; + Q_DEL_ITEM(buffer); + + /* Set the Scsi_Cmnd pointer + */ + buffer->argp = (void *)SCpnt; + + /* Add to the doneQ + */ + Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + } else { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + SCpnt->scsi_done(SCpnt); + } +#else + SCpnt->scsi_done(SCpnt); /* Issue the command callback */ +#endif + } } @@ -1147,8 +1198,8 @@ int ii; int max = hd->ioc->req_depth; - dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d numIos %d\n", - target, lun, max, atomic_read(&queue_depth))); + dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", + target, lun, max)); for (ii=0; ii < max; ii++) { if (hd->ScsiLookup[ii] != NULL) { @@ -1161,11 +1212,6 @@ if ((mf->TargetID != ((u8)target)) || (mf->LUN[1] != ((u8) lun))) continue; - /* If cmd pended, do not decrement queue_depth, command never posted. - */ - if (mptscsih_search_pendingQ(hd, ii) == NULL) - atomic_dec(&queue_depth); - /* Cleanup */ hd->ScsiLookup[ii] = NULL; @@ -1177,73 +1223,6 @@ return; } -#ifdef DROP_TEST -/* mptscsih_flush_drop_test - Free resources and do callback if - * DROP_TEST enabled. - * - * @hd: Pointer to a SCSI HOST structure - * - * Returns: None. - * - * Must be called while new I/Os are being queued. - */ -static void -mptscsih_flush_drop_test (MPT_SCSI_HOST *hd) -{ - Scsi_Cmnd *sc; - unsigned long flags; - u16 req_idx; - - /* Free resources for the drop test MF - * and chain buffers. - */ - if (dropMfPtr) { - req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx); - sc = hd->ScsiLookup[req_idx]; - if (sc == NULL) { - printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n", - ioc->name); - } else { - /* unmap OS resources, set status, do callback - * free driver resources - */ - if (sc->use_sg) { - pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, - sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction)); - } else if (sc->request_bufflen) { - scPrivate *my_priv; - - my_priv = (scPrivate *) &sc->SCp; - pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, - sc->request_bufflen, - scsi_to_pci_dma_dir(sc->sc_data_direction)); - } - - sc->host_scribble = NULL; - sc->result = DID_RESET << 16; - hd->ScsiLookup[req_idx] = NULL; - atomic_dec(&queue_depth); - MPT_HOST_LOCK(flags); - sc->scsi_done(sc); /* Issue callback */ - MPT_HOST_UNLOCK(flags); - } - - mptscsih_freeChainBuffers(hd, req_idx); - mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr); - printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n", - hd->ioc->name, sc); - printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n", - hd->ioc->name, dropMfPtr, req_idx); - printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n", - hd->ioc->name, dropTestNum, - dropTestOK, dropTestBad); - } - dropMfPtr = NULL; - - return; -} -#endif - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_initChainBuffers - Allocate memory for and initialize @@ -1263,18 +1242,15 @@ /* ReqToChain size must equal the req_depth * index = req_idx */ - sz = hd->ioc->req_depth * sizeof(int); if (hd->ReqToChain == NULL) { + sz = hd->ioc->req_depth * sizeof(int); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; hd->ReqToChain = (int *) mem; - } else { - mem = (u8 *) hd->ReqToChain; } -/* memset(mem, 0xFF, sz); */ - for(ii=0;iiioc->req_depth;ii++) + for (ii = 0; ii < hd->ioc->req_depth; ii++) hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN; /* ChainToChain size must equal the total number @@ -1322,7 +1298,11 @@ if (hd->ChainBuffer == NULL) { /* Allocate free chain buffer pool */ +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&hd->ioc->pcidev32, sz, &hd->ChainBufferDMA); +#else mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA); +#endif if (mem == NULL) return -1; @@ -1405,310 +1385,333 @@ * */ -static int __devinit +static int mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct Scsi_Host *sh = NULL; - MPT_SCSI_HOST *hd = NULL; + struct Scsi_Host *sh; + MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - int portnum; MPT_DONE_Q *freedoneQ; unsigned long flags; int sz, ii; int numSGE = 0; int scale; + int ioc_cap; u8 *mem; int error=0; - for (portnum=0; portnum < ioc->facts.NumberOfPorts; portnum++) { - /* 20010215 -sralston - * Added sanity check on SCSI Initiator-mode enabled - * for this MPT adapter. - */ - if (!(ioc->pfacts[portnum].ProtocolFlags & - MPI_PORTFACTS_PROTOCOL_INITIATOR)) { - printk(MYIOC_s_WARN_FMT - "Skipping because SCSI Initiator mode is NOT enabled!\n", - ioc->name); - continue; - } - - /* 20010202 -sralston - * Added sanity check on readiness of the MPT adapter. - */ - if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "Skipping because it's not operational!\n", - ioc->name); - continue; - } - - sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST)); - if (sh != NULL) { - spin_lock_irqsave(&ioc->FreeQlock, flags); - - /* Attach the SCSI Host to the IOC structure - */ - ioc->sh = sh; - - sh->io_port = 0; - sh->n_io_port = 0; - sh->irq = 0; - - /* set 16 byte cdb's */ - sh->max_cmd_len = 16; - - /* Yikes! This is important! - * Otherwise, by default, linux - * only scans target IDs 0-7! - * pfactsN->MaxDevices unreliable - * (not supported in early - * versions of the FW). - * max_id = 1 + actual max id, - * max_lun = 1 + actual last lun, - * see hosts.h :o( - */ - if ((int)ioc->chip_type > (int)FC929) { - sh->max_id = MPT_MAX_SCSI_DEVICES; - } else { - /* For FC, increase the queue depth - * from MPT_SCSI_CAN_QUEUE (31) - * to MPT_FC_CAN_QUEUE (63). - */ - sh->can_queue = MPT_FC_CAN_QUEUE; - sh->max_id = - MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; - } - - sh->max_lun = MPT_LAST_LUN + 1; - sh->max_sectors = MPT_SCSI_MAX_SECTORS; - sh->this_id = ioc->pfacts[portnum].PortSCSIID; - - /* Required entry. - */ - sh->unique_id = ioc->id; - - /* Verify that we won't exceed the maximum - * number of chain buffers - * We can optimize: ZZ = req_sz/sizeof(SGE) - * For 32bit SGE's: - * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ - * + (req_sz - 64)/sizeof(SGE) - * A slightly different algorithm is required for - * 64bit SGEs. - */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { - numSGE = (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); - } else { - numSGE = 1 + (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); - } - - if (numSGE < sh->sg_tablesize) { - /* Reset this value */ - dprintk((MYIOC_s_INFO_FMT - "Resetting sg_tablesize to %d from %d\n", - ioc->name, numSGE, sh->sg_tablesize)); - sh->sg_tablesize = numSGE; - } - - /* Set the pci device pointer in Scsi_Host structure. - */ - scsi_set_device(sh, &ioc->pcidev->dev); - - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - hd = (MPT_SCSI_HOST *) sh->hostdata; - hd->ioc = ioc; - hd->max_sge = sh->sg_tablesize; - - if ((int)ioc->chip_type > (int)FC929) - hd->is_spi = 1; + /* 20010202 -sralston + * Added sanity check on readiness of the MPT adapter. + */ + if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "Skipping because it's not operational!\n", + ioc->name); + return -ENODEV; + } - if (DmpService && (ioc->chip_type == FC919 || - ioc->chip_type == FC929)) { - hd->is_multipath = 1; - } - hd->port = 0; /* FIXME! */ + if (!ioc->active) { + printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", + ioc->name); + return -ENODEV; + } - /* SCSI needs Scsi_Cmnd lookup table! - * (with size equal to req_depth*PtrSz!) - */ - sz = hd->ioc->req_depth * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + /* Sanity check - ensure at least 1 port is INITIATOR capable + */ + ioc_cap = 0; + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { + if (ioc->pfacts[ii].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_INITIATOR) + ioc_cap ++; + } - memset(mem, 0, sz); - hd->ScsiLookup = (struct scsi_cmnd **) mem; + if (!ioc_cap) { + printk(MYIOC_s_WARN_FMT + "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", + ioc->name, ioc); + return -ENODEV; + } - dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", - ioc->name, hd->ScsiLookup, sz)); + sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST)); + + if (!sh) { + printk(MYIOC_s_WARN_FMT + "Unable to register controller with SCSI subsystem\n", + ioc->name); + return -1; + } + + spin_lock_irqsave(&ioc->FreeQlock, flags); - if (mptscsih_initChainBuffers(hd, 1) < 0) { - error = -EINVAL; - goto mptscsih_probe_failed; - } + /* Attach the SCSI Host to the IOC structure + */ + ioc->sh = sh; - /* Allocate memory for free and doneQ's - */ - sz = sh->can_queue * sizeof(MPT_DONE_Q); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* set 16 byte cdb's */ + sh->max_cmd_len = 16; + + /* Yikes! This is important! + * Otherwise, by default, linux + * only scans target IDs 0-7! + * pfactsN->MaxDevices unreliable + * (not supported in early + * versions of the FW). + * max_id = 1 + actual max id, + * max_lun = 1 + actual last lun, + * see hosts.h :o( + */ + if ((int)ioc->chip_type > (int)FC929) { + sh->max_id = MPT_MAX_SCSI_DEVICES; + } else { + /* For FC, increase the queue depth + * from MPT_SCSI_CAN_QUEUE (31) + * to MPT_FC_CAN_QUEUE (63). + */ + sh->can_queue = MPT_FC_CAN_QUEUE; + sh->max_id = + MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; + } + + sh->max_lun = MPT_LAST_LUN + 1; + sh->max_sectors = MPT_SCSI_MAX_SECTORS; + sh->max_channel = 0; + sh->this_id = ioc->pfacts[0].PortSCSIID; + + /* Required entry. + */ + sh->unique_id = ioc->id; + + /* Verify that we won't exceed the maximum + * number of chain buffers + * We can optimize: ZZ = req_sz/sizeof(SGE) + * For 32bit SGE's: + * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ + * + (req_sz - 64)/sizeof(SGE) + * A slightly different algorithm is required for + * 64bit SGEs. + */ + scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + + sizeof(u32)); + } + + if (numSGE < sh->sg_tablesize) { + /* Reset this value */ + dprintk((MYIOC_s_INFO_FMT + "Resetting sg_tablesize to %d from %d\n", + ioc->name, numSGE, sh->sg_tablesize)); + sh->sg_tablesize = numSGE; + } - memset(mem, 0xFF, sz); - hd->memQ = mem; + /* Set the pci device pointer in Scsi_Host structure. + */ + scsi_set_device(sh, &ioc->pcidev->dev); - /* Initialize the free, done and pending Qs. - */ - Q_INIT(&hd->freeQ, MPT_DONE_Q); - Q_INIT(&hd->doneQ, MPT_DONE_Q); - Q_INIT(&hd->pendingQ, MPT_DONE_Q); - spin_lock_init(&hd->freedoneQlock); - - mem = hd->memQ; - for (ii=0; ii < sh->can_queue; ii++) { - freedoneQ = (MPT_DONE_Q *) mem; - Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); - mem += sizeof(MPT_DONE_Q); - } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); - /* Initialize this Scsi_Host - * internal task Q. - */ - Q_INIT(&hd->taskQ, MPT_FRAME_HDR); - hd->taskQcnt = 0; + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = ioc; + hd->max_sge = sh->sg_tablesize; + + if ((int)ioc->chip_type > (int)FC929) + hd->is_spi = 1; + + if (DmpService && (ioc->chip_type == FC919 || + ioc->chip_type == FC929)) { + hd->is_multipath = 1; + } + + /* SCSI needs Scsi_Cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = hd->ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - /* Allocate memory for the device structures. - * A non-Null pointer at an offset - * indicates a device exists. - * max_id = 1 + maximum id (hosts.h) - */ - sz = sh->max_id * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; - memset(mem, 0, sz); - hd->Targets = (VirtDevice **) mem; + dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", + ioc->name, hd->ScsiLookup, sz)); + + if (mptscsih_initChainBuffers(hd, 1) < 0) { + error = -EINVAL; + goto mptscsih_probe_failed; + } + + /* Allocate memory for free and doneQ's + */ + sz = sh->can_queue * sizeof(MPT_DONE_Q); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - dprintk((KERN_INFO - " Targets @ %p, sz=%d\n", hd->Targets, sz)); + memset(mem, 0xFF, sz); + hd->memQ = mem; + /* Initialize the free, done and pending Qs. + */ + Q_INIT(&hd->freeQ, MPT_DONE_Q); + Q_INIT(&hd->doneQ, MPT_DONE_Q); + Q_INIT(&hd->pendingQ, MPT_DONE_Q); + spin_lock_init(&hd->freedoneQlock); + + mem = hd->memQ; + for (ii=0; ii < sh->can_queue; ii++) { + freedoneQ = (MPT_DONE_Q *) mem; + Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); + mem += sizeof(MPT_DONE_Q); + } + + /* Initialize this Scsi_Host + * internal task Q. + */ + Q_INIT(&hd->taskQ, MPT_FRAME_HDR); + hd->taskQcnt = 0; + + /* Allocate memory for the device structures. + * A non-Null pointer at an offset + * indicates a device exists. + * max_id = 1 + maximum id (hosts.h) + */ + sz = sh->max_id * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - hd->tmPtr = NULL; - hd->numTMrequests = 0; + memset(mem, 0, sz); + hd->Targets = (VirtDevice **) mem; - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; + dprintk((KERN_INFO + " Targets @ %p, sz=%d\n", hd->Targets, sz)); - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - - init_timer(&hd->TMtimer); - hd->TMtimer.data = (unsigned long) hd; - hd->TMtimer.function = mptscsih_taskmgmt_timeout; - hd->qtag_tick = jiffies; + /* Clear the TM flags + */ + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + hd->resetPending = 0; + hd->abortSCpnt = NULL; + hd->tmPtr = NULL; + hd->numTMrequests = 0; + + /* Clear the pointer used to store + * single-threaded commands, i.e., those + * issued during a bus scan, dv and + * configuration pages. + */ + hd->cmdPtr = NULL; - /* Moved Earlier Pam D */ - /* ioc->sh = sh; */ + /* Initialize this SCSI Hosts' timers + * To use, set the timer expires field + * and add_timer + */ + init_timer(&hd->timer); + hd->timer.data = (unsigned long) hd; + hd->timer.function = mptscsih_timer_expired; + + init_timer(&hd->TMtimer); + hd->TMtimer.data = (unsigned long) hd; + hd->TMtimer.function = mptscsih_taskmgmt_timeout; + hd->qtag_tick = jiffies; + + /* Moved Earlier Pam D */ + /* ioc->sh = sh; */ + +#ifdef MPTSCSIH_DBG_TIMEOUT + hd->ioc->timeout_hard = 0; + hd->ioc->timeout_delta = 30 * HZ; + hd->ioc->timeout_maxcnt = 0; + hd->ioc->timeout_cnt = 0; + for (ii=0; ii < 8; ii++) + foo_to[ii] = NULL; +#endif + if (hd->is_spi) { + /* Update with the driver setup + * values. + */ + if (hd->ioc->spi_data.maxBusWidth > + driver_setup.max_width) { + hd->ioc->spi_data.maxBusWidth = + driver_setup.max_width; + } - if (hd->is_spi) { - /* Update with the driver setup - * values. - */ - if (hd->ioc->spi_data.maxBusWidth > - driver_setup.max_width) { - hd->ioc->spi_data.maxBusWidth = - driver_setup.max_width; - } + if (hd->ioc->spi_data.minSyncFactor < + driver_setup.min_sync_fac) { + hd->ioc->spi_data.minSyncFactor = + driver_setup.min_sync_fac; + } - if (hd->ioc->spi_data.minSyncFactor < - driver_setup.min_sync_fac) { - hd->ioc->spi_data.minSyncFactor = - driver_setup.min_sync_fac; - } + if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { + hd->ioc->spi_data.maxSyncOffset = 0; + } - if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { - hd->ioc->spi_data.maxSyncOffset = 0; - } + hd->ioc->spi_data.Saf_Te = driver_setup.saf_te; - hd->negoNvram = 0; + hd->negoNvram = 0; #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; #endif - if (driver_setup.dv == 0) { - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - } - - hd->ioc->spi_data.forceDv = 0; - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - hd->ioc->spi_data.dvStatus[ii] = - MPT_SCSICFG_NEGOTIATE; - } - - if (hd->negoNvram == 0) { - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) - hd->ioc->spi_data.dvStatus[ii] |= - MPT_SCSICFG_DV_NOT_DONE; - } + if (driver_setup.dv == 0) { + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; + } - ddvprintk((MYIOC_s_INFO_FMT - "dv %x width %x factor %x \n", - hd->ioc->name, driver_setup.dv, - driver_setup.max_width, - driver_setup.min_sync_fac)); + hd->ioc->spi_data.forceDv = 0; + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + hd->ioc->spi_data.dvStatus[ii] = + MPT_SCSICFG_NEGOTIATE; + } - } + if (hd->negoNvram == 0) { + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + hd->ioc->spi_data.dvStatus[ii] |= + MPT_SCSICFG_DV_NOT_DONE; + } - mpt_scsi_hosts++; + ddvprintk((MYIOC_s_INFO_FMT + "dv %x width %x factor %x saf_te %x\n", + hd->ioc->name, driver_setup.dv, + driver_setup.max_width, + driver_setup.min_sync_fac, + driver_setup.saf_te)); + } - error = scsi_add_host (sh, &ioc->pcidev->dev); - if(error) { - dprintk((KERN_ERR MYNAM, - "scsi_add_host failed\n")); - goto mptscsih_probe_failed; - } + mpt_scsi_hosts++; - scsi_scan_host(sh); - return 0; - } /* scsi_host_alloc */ + error = scsi_add_host (sh, &ioc->pcidev->dev); + if(error) { + dprintk((KERN_ERR MYNAM + "scsi_add_host failed\n")); + goto mptscsih_probe_failed; + } - } /* for each adapter port */ + scsi_scan_host(sh); + return 0; mptscsih_probe_failed: mptscsih_remove(pdev); return error; + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1718,7 +1721,7 @@ * * */ -static void __devexit +static void mptscsih_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); @@ -1920,7 +1923,7 @@ static struct mpt_pci_driver mptscsih_driver = { .probe = mptscsih_probe, - .remove = __devexit_p(mptscsih_remove), + .remove = mptscsih_remove, .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, @@ -2023,7 +2026,7 @@ const char * mptscsih_info(struct Scsi_Host *SChost) { - MPT_SCSI_HOST *h = NULL; + MPT_SCSI_HOST *h; int size = 0; if (info_kbuf == NULL) @@ -2099,101 +2102,20 @@ return ((info.pos > info.offset) ? info.pos - info.offset : 0); } -struct mptscsih_usrcmd { - ulong target; - ulong lun; - ulong data; - ulong cmd; -}; - -#define UC_GET_SPEED 0x10 - -static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc) +#ifndef MPTSCSIH_DBG_TIMEOUT +static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len) { - CONFIGPARMS cfg; - dma_addr_t cfg_dma_addr = -1; - ConfigPageHeader_t header; - - dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n", - ioc, uc->cmd, uc->target)); - - switch (uc->cmd) { - case UC_GET_SPEED: - { - SCSIDevicePage0_t *pData = NULL; - - if (ioc->spi_data.sdp0length == 0) - return; - - pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev, - ioc->spi_data.sdp0length * 4, &cfg_dma_addr); - - if (pData == NULL) - return; - - header.PageVersion = ioc->spi_data.sdp0version; - header.PageLength = ioc->spi_data.sdp0length; - header.PageNumber = 0; - header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - - cfg.hdr = &header; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - cfg.dir = 0; - cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */ - cfg.physAddr = cfg_dma_addr; - - if (mpt_config(ioc, &cfg) == 0) { - u32 np = le32_to_cpu(pData->NegotiatedParameters); - u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE; - - printk("Target %d: %s;", - (u32) uc->target, - tmp ? "Wide" : "Narrow"); - - tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK; - if (tmp) { - u32 speed = 0; - printk(" Synchronous"); - tmp = (tmp >> 16); - printk(" (Offset=0x%x", tmp); - tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK; - tmp = (tmp >> 8); - printk(" Factor=0x%x)", tmp); - if (tmp <= MPT_ULTRA320) - speed=160; - else if (tmp <= MPT_ULTRA160) - speed=80; - else if (tmp <= MPT_ULTRA2) - speed=40; - else if (tmp <= MPT_ULTRA) - speed=20; - else if (tmp <= MPT_FAST) - speed=10; - else if (tmp <= MPT_SCSI) - speed=5; - - if (np & MPI_SCSIDEVPAGE0_NP_WIDE) - speed*=2; - - printk(" %dMB/sec\n", speed); - - } else - printk(" Asynchronous.\n"); - } else { - printk("failed\n" ); - } - - pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4, - pData, cfg_dma_addr); - } - break; - } + /* Not yet implemented */ + return len; } - +#else #define is_digit(c) ((c) >= '0' && (c) <= '9') #define digit_to_bin(c) ((c) - '0') #define is_space(c) ((c) == ' ' || (c) == '\t') +#define UC_DBG_TIMEOUT 0x01 +#define UC_DBG_HARDRESET 0x02 + static int skip_spaces(char *ptr, int len) { int cnt, c; @@ -2242,50 +2164,66 @@ static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length) { - char *ptr = buffer; - struct mptscsih_usrcmd cmd, *uc = &cmd; - ulong target; - int arg_len; - int len = length; + char *ptr = buffer; + char btmp[24]; /* REMOVE */ + int arg_len; + int len = length; + int cmd; + ulong number = 1; + ulong delta = 10; - uc->target = uc->cmd = uc->lun = uc->data = 0; - if ((len > 0) && (ptr[len -1] == '\n')) --len; - if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0) - uc->cmd = UC_GET_SPEED; - else - arg_len = 0; - - dprintk(("user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd)); + if (len < 22) { + strncpy(btmp, buffer, len); + btmp[len+1]='\0'; + } else { + strncpy(btmp, buffer, 22); + btmp[23]='\0'; + } + printk("user_command: ioc %d, buffer %s, length %d\n", + ioc->id, btmp, length); - if (!arg_len) + if ((arg_len = is_keyword(ptr, len, "timeout")) != 0) + cmd = UC_DBG_TIMEOUT; + else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0) + cmd = UC_DBG_HARDRESET; + else return -EINVAL; ptr += arg_len; len -= arg_len; - switch(uc->cmd) { - case UC_GET_SPEED: + switch(cmd) { + case UC_DBG_TIMEOUT: SKIP_SPACES(1); - GET_INT_ARG(target); - uc->target = target; + GET_INT_ARG(number); + SKIP_SPACES(1); + GET_INT_ARG(delta); break; } - dprintk(("user_command: target=%ld len=%d\n", uc->target, len)); + printk("user_command: cnt=%ld delta=%ld\n", number, delta); if (len) return -EINVAL; else { - /* process this command ... - */ - mptscsih_exec_user_cmd(ioc, uc); + if (cmd == UC_DBG_HARDRESET) { + ioc->timeout_hard = 1; + } else if (cmd == UC_DBG_TIMEOUT) { + /* process this command ... + */ + ioc->timeout_maxcnt = 0; + ioc->timeout_delta = delta < 2 ? 2 : delta; + ioc->timeout_cnt = 0; + ioc->timeout_maxcnt = number < 8 ? number: 8; + } } /* Not yet implemented */ return length; } +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -2303,7 +2241,7 @@ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { - MPT_ADAPTER *ioc = NULL; + MPT_ADAPTER *ioc; MPT_SCSI_HOST *hd = NULL; int size = 0; @@ -2334,49 +2272,8 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static int max_qd = 1; #define ADD_INDEX_LOG(req_ent) do { } while(0) -#ifdef DROP_TEST -#define DROP_IOC 1 /* IOC to force failures */ -#define DROP_TARGET 3 /* Target ID to force failures */ -#define DROP_THIS_CMD 10000 /* iteration to drop command */ -static int dropCounter = 0; -static int dropTestOK = 0; /* num did good */ -static int dropTestBad = 0; /* num did bad */ -static int dropTestNum = 0; /* total = good + bad + incomplete */ -static int numTotCmds = 0; -static MPT_FRAME_HDR *dropMfPtr = NULL; -static int numTMrequested = 0; -#endif - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_put_msgframe - Wrapper routine to post message frame to F/W. - * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) - * @id: IOC id number - * @mf: Pointer to message frame - * - * Handles the call to mptbase for posting request and queue depth - * tracking. - * - * Returns none. - */ -static inline void -mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf) -{ - /* Main banana... */ - atomic_inc(&queue_depth); - if (atomic_read(&queue_depth) > max_qd) { - max_qd = atomic_read(&queue_depth); - dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); - } - - mpt_put_msg_frame(context, id, mf); - - return; -} - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. @@ -2396,7 +2293,7 @@ MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; - MPT_DONE_Q *buffer = NULL; + MPT_DONE_Q *buffer; unsigned long flags; int target; int lun; @@ -2424,9 +2321,14 @@ if (hd->resetPending) { /* Prevent new commands from being issued - * while reloading the FW. + * while reloading the FW. Reset timer to 60 seconds, + * as the FW can take some time to come ready. + * For New EH, cmds on doneQ posted to FW. */ did_errcode = 1; + mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); + dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); goto did_error; } @@ -2481,8 +2383,8 @@ /* Use the above information to set up the message frame */ - pScsiReq->TargetID = target; - pScsiReq->Bus = hd->port; + pScsiReq->TargetID = (u8) target; + pScsiReq->Bus = (u8) SCpnt->device->channel; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; @@ -2501,12 +2403,14 @@ /* * Write SCSI CDB into the message - * Should write from cmd_len up to 16, but skip for performance reasons. */ cmd_len = SCpnt->cmd_len; for (ii=0; ii < cmd_len; ii++) pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; + for (ii=cmd_len; ii < 16; ii++) + pScsiReq->CDB[ii] = 0; + /* DataLength */ pScsiReq->DataLength = cpu_to_le32(datalen); @@ -2532,39 +2436,6 @@ hd->ScsiLookup[my_idx] = SCpnt; SCpnt->host_scribble = NULL; -#ifdef DROP_TEST - numTotCmds++; - /* If the IOC number and target match, increment - * counter. If counter matches DROP_THIS, do not - * issue command to FW to force a reset. - * Save the MF pointer so we can free resources - * when task mgmt completes. - */ - if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) { - dropCounter++; - - if (dropCounter == DROP_THIS_CMD) { - dropCounter = 0; - - /* If global is set, then we are already - * doing something - so keep issuing commands. - */ - if (dropMfPtr == NULL) { - dropTestNum++; - dropMfPtr = mf; - atomic_inc(&queue_depth); - printk(MYIOC_s_INFO_FMT - "Dropped SCSI cmd (%p)\n", - hd->ioc->name, SCpnt); - printk("mf (%p) req (%4x) tot cmds (%d)\n", - mf, my_idx, numTotCmds); - - return 0; - } - } - } -#endif - /* SCSI specific processing */ issueCmd = 1; if (hd->is_spi) { @@ -2617,8 +2488,20 @@ } } +#ifdef MPTSCSIH_DBG_TIMEOUT + if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) { + foo_to[hd->ioc->timeout_cnt] = SCpnt; + hd->ioc->timeout_cnt++; + //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta); + issueCmd = 0; + printk(MYIOC_s_WARN_FMT + "to pendingQ: (sc=%p, mf=%p, time=%ld)\n", + hd->ioc->name, SCpnt, mf, jiffies); + } +#endif + if (issueCmd) { - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); } else { @@ -2660,6 +2543,8 @@ SCpnt->result = (DID_BUS_BUSY << 16); spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->freeQ)) { + dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); buffer = hd->freeQ.head; Q_DEL_ITEM(buffer); @@ -2692,7 +2577,7 @@ static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) { - MPT_FRAME_HDR *chain = NULL; + MPT_FRAME_HDR *chain; unsigned long flags; int chain_idx; int next; @@ -2755,9 +2640,9 @@ * Returns 0 for SUCCESS or -1 if FAILED. */ static int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) +mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) { - MPT_ADAPTER *ioc = NULL; + MPT_ADAPTER *ioc; int rc = -1; int doTask = 1; u32 ioc_raw_state; @@ -2770,19 +2655,18 @@ return 0; ioc = hd->ioc; - dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); - if (ioc == NULL) { printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n"); - return 0; + return FAILED; } + dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); // SJR - CHECKME - Can we avoid this here? // (mpt_HardResetHandler has this check...) spin_lock_irqsave(&ioc->diagLock, flags); if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { spin_unlock_irqrestore(&ioc->diagLock, flags); - return 0; + return FAILED; } spin_unlock_irqrestore(&ioc->diagLock, flags); @@ -2792,6 +2676,37 @@ if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM) doTask = 0; + /* Wait a fixed amount of time for the TM pending flag to be cleared. + * If we time out and not bus reset, then we return a FAILED status to the caller. + * The call to mptscsih_tm_pending_wait() will set the pending flag if we are + * successful. Otherwise, reload the FW. + */ + if (mptscsih_tm_pending_wait(hd) == FAILED) { + if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + return FAILED; + } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + return FAILED; + } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)) + return FAILED; + + doTask = 0; + } + } else { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending |= (1 << type); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + } + /* Is operational? */ ioc_raw_state = mpt_GetIocState(hd->ioc, 0); @@ -2799,7 +2714,7 @@ #ifdef MPT_DEBUG_RESET if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT - "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", + "TM Handler: IOC Not operational(0x%x)!\n", hd->ioc->name, ioc_raw_state); } #endif @@ -2811,23 +2726,24 @@ */ if (hd->hard_resets < -1) hd->hard_resets++; - rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, timeout, sleepFlag); + rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout, sleepFlag); if (rc) { printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); } else { dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name)); } } -#ifdef DROP_TEST - numTMrequested++; - if (numTMrequested > 5) { - rc = 0; /* set to 1 to force a hard reset */ - numTMrequested = 0; - } + +#ifdef MPTSCSIH_DBG_TIMEOUT + if (hd->ioc->timeout_hard) + rc = 1; #endif - if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) { - dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n", + /* Only fall through to the HRH if this is a bus reset + */ + if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc || + ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) { + dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", hd->ioc->name)); rc = mpt_HardResetHandler(hd->ioc, sleepFlag); } @@ -2857,7 +2773,7 @@ * else other non-zero value returned. */ static int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; @@ -2879,7 +2795,7 @@ */ pScsiTm = (SCSITaskMgmt_t *) mf; pScsiTm->TargetID = target; - pScsiTm->Bus = hd->port; + pScsiTm->Bus = channel; pScsiTm->ChainOffset = 0; pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; @@ -2953,8 +2869,11 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + if (hd->resetPending) + return FAILED; + + printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n", + hd->ioc->name, SCpnt); if (hd->timeouts < -1) hd->timeouts++; @@ -2968,38 +2887,21 @@ search_doneQ_for_cmd(hd, SCpnt); SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done(SCpnt); dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", hd->ioc->name, SCpnt)); return SUCCESS; } - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ - spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED){ - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - spin_lock_irq(host_lock); - /* If this command is pended, then timeout/hang occurred * during DV. Post command and flush pending Q * and then following up with the reset request. */ if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); post_pendingQ_commands(hd); dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Found command in pending queue! (sc=%p)\n", + "Posting pended cmd! (sc=%p)\n", hd->ioc->name, SCpnt)); } @@ -3017,7 +2919,7 @@ spin_unlock_irq(host_lock); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - SCpnt->device->id, SCpnt->device->lun, + SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, ctx2abort, (HZ*2) /* 2 second timeout */,CAN_SLEEP) < 0) { @@ -3064,31 +2966,21 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + if (hd->resetPending) + return FAILED; - /* Unsupported for SCSI. Suppored for FCP + printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n", + hd->ioc->name, SCpnt); + + /* Unsupported for SCSI. Supported for FCP */ if (hd->is_spi) return FAILED; - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED) { - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - SCpnt->device->id, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) + SCpnt->device->channel, SCpnt->device->id, + 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. @@ -3129,30 +3021,19 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n", + hd->ioc->name, SCpnt); if (hd->timeouts < -1) hd->timeouts++; - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ - spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED) { - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - /* We are now ready to execute the task management request. */ + spin_unlock_irq(host_lock); +// printk("testing start : mptscsih_schedule_reset\n"); +// mptscsih_schedule_reset(hd); +// printk("testing end: mptscsih_schedule_reset\n"); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) + SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! @@ -3197,8 +3078,6 @@ printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n", hd->ioc->name, SCpnt); - printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n", - hd->ioc->name, atomic_read(&queue_depth)); /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. @@ -3274,7 +3153,7 @@ { SCSITaskMgmtReply_t *pScsiTmReply; SCSITaskMgmt_t *pScsiTmReq; - MPT_SCSI_HOST *hd = NULL; + MPT_SCSI_HOST *hd; unsigned long flags; u8 tmType = 0; @@ -3325,10 +3204,7 @@ */ if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) hd->abortSCpnt = NULL; -#ifdef DROP_TEST - if (dropMfPtr) - dropTestBad++; -#endif + /* If an internal command is present * or the TM failed - reload the FW. * FC FW may respond FAILED to an ABORT @@ -3349,17 +3225,9 @@ hd->abortSCpnt = NULL; flush_doneQ(hd); -#ifdef DROP_TEST - if (dropMfPtr) - dropTestOK++; -#endif } } -#ifdef DROP_TEST - mptscsih_flush_drop_test(hd); -#endif - hd->tmPtr = NULL; spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending = 0; @@ -3438,15 +3306,14 @@ hd = (MPT_SCSI_HOST *)host->hostdata; - if (hd == NULL) - return ENODEV; + return -ENODEV; if ((vdev = hd->Targets[device->id]) == NULL) { if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%d) FAILED!\n", - hd->ioc->name, (int)sizeof(VirtDevice)); - return ENOMEM; + hd->ioc->name, (int)sizeof(VirtDevice)); + return -ENOMEM; } else { memset(vdev, 0, sizeof(VirtDevice)); rwlock_init(&vdev->VdevLock); @@ -3476,9 +3343,10 @@ struct Scsi_Host *host = device->host; MPT_SCSI_HOST *hd; VirtDevice *vdev; + int raid_volume=0; hd = (MPT_SCSI_HOST *)host->hostdata; - + if (hd == NULL) return; @@ -3489,8 +3357,8 @@ if ((vdev = hd->Targets[device->id]) != NULL) { vdev->num_luns--; - if (vdev->luns & (1 << device->lun)) - vdev->luns &= ~(1 << device->lun); + if (vdev->luns[0] & (1 << device->lun)) + vdev->luns[0] &= ~(1 << device->lun); /* Free device structure only if number of luns is 0. */ @@ -3498,21 +3366,33 @@ kfree(hd->Targets[device->id]); hd->Targets[device->id] = NULL; - if (hd->is_spi) { - hd->ioc->spi_data.dvStatus[device->id] = MPT_SCSICFG_NEGOTIATE; + if (!hd->is_spi) + return; - if (hd->negoNvram == 0) - hd->ioc->spi_data.dvStatus[device->id] |= MPT_SCSICFG_DV_NOT_DONE; + if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) { + int i; + for(i=0;iioc->spi_data.pIocPg3->NumPhysDisks && + raid_volume==0;i++) + + if(device->id == + hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskNum) { + raid_volume=1; + hd->ioc->spi_data.forceDv |= + MPT_SCSICFG_RELOAD_IOC_PG3; + } + } - /* Don't alter isRaid, not allowed to move - * volumes on a running system. - */ - if (hd->ioc->spi_data.isRaid & (1 << (device->id))) - hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; + if(!raid_volume){ + hd->ioc->spi_data.dvStatus[device->id] = + MPT_SCSICFG_NEGOTIATE; + + if (hd->negoNvram == 0) + hd->ioc->spi_data.dvStatus[device->id] + |= MPT_SCSICFG_DV_NOT_DONE; } } } - + return; } @@ -3525,205 +3405,76 @@ int mptscsih_slave_configure(Scsi_Device *device) { - struct Scsi_Host *host = device->host; - VirtDevice *vdev; - MPT_SCSI_HOST *hd; - - hd = (MPT_SCSI_HOST *)host->hostdata; - - dsprintk((KERN_INFO "slave_configure: device @ %p, id=%d, LUN=%d, channel=%d\n", - device, device->id, device->lun, device->channel)); - dsprintk((KERN_INFO "sdtr %d wdtr %d ppr %d inq length=%d\n", - device->sdtr, device->wdtr, device->ppr, device->inquiry_len)); - dsprintk(("tagged %d simple %d ordered %d\n", - device->tagged_supported, device->simple_tags, device->ordered_tags)); - - /* set target parameters, queue depths, set dv flags ? */ - if (hd && (hd->Targets != NULL)) { - vdev = hd->Targets[device->id]; - - if (vdev && !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { - /* Configure only the first discovered LUN - */ - vdev->raidVolume = 0; - if (hd->is_spi && (hd->ioc->spi_data.isRaid & (1 << (device->id)))) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", device->id)); - } - - mptscsih_target_settings(hd, vdev, device); + struct Scsi_Host *sh = device->host; + VirtDevice *pTarget; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; - vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED; - } + if ((hd == NULL) || (hd->Targets == NULL)) { + return 0; + } - if (vdev) { - /* set the queue depth for all devices - */ - if (!device->tagged_supported || - !(vdev->tflags & MPT_TARGET_FLAGS_Q_YES)) { + dsprintk((MYIOC_s_INFO_FMT + "device @ %p, id=%d, LUN=%d, channel=%d\n", + hd->ioc->name, device, device->id, device->lun, device->channel)); + dsprintk((MYIOC_s_INFO_FMT + "sdtr %d wdtr %d ppr %d inq length=%d\n", + hd->ioc->name, device->sdtr, device->wdtr, + device->ppr, device->inquiry_len)); + + if (device->id > sh->max_id) { + /* error case, should never happen */ + scsi_adjust_queue_depth(device, 0, 1); + goto slave_configure_exit; + } + + pTarget = hd->Targets[device->id]; + + if (pTarget == NULL) { + /* error case - don't know about this device */ + scsi_adjust_queue_depth(device, 0, 1); + goto slave_configure_exit; + } + + mptscsih_initTarget(hd, device->channel, device->id, device->lun, + device->inquiry, device->inquiry_len ); + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_HIGH); + if ( hd->is_spi ) { + if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) scsi_adjust_queue_depth(device, 0, 1); - } else if (vdev->type == 0x00 - && (vdev->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) { + else if (((pTarget->inq_data[0] & 0x1f) == 0x00) + && (pTarget->minSyncFactor <= MPT_ULTRA160 )) scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - MPT_SCSI_CMD_PER_DEV_HIGH); - } else { + MPT_SCSI_CMD_PER_DEV_HIGH); + else scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - MPT_SCSI_CMD_PER_DEV_LOW); - } - - vdev->luns |= (1 << device->lun); - vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED; - } - } - return 0; -} -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Update the target negotiation parameters based on the - * the Inquiry data, adapter capabilities, and NVRAM settings. - * - */ -static void -mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev) -{ - ScsiCfgData *pspi_data = &hd->ioc->spi_data; - int id = (int) target->target_id; - int nvram; - u8 width = MPT_NARROW; - u8 factor = MPT_ASYNC; - u8 offset = 0; - u8 nfactor; - u8 noQas = 1; - - ddvtprintk((KERN_INFO "set Target: (id %d) \n", id)); - - if (!hd->is_spi) { - /* FC - only care about QTag support - */ - if (sdev->tagged_supported) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - return; - } - - /* SCSI - Set flags based on Inquiry data - */ - if (sdev->scsi_level < 2) { - width = 0; - factor = MPT_ULTRA2; - offset = pspi_data->maxSyncOffset; - } else { - width = sdev->wdtr; - if (sdev->sdtr) { - if (sdev->ppr) { - /* U320 requires IU capability */ - if ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x01)) - factor = MPT_ULTRA320; - else - factor = MPT_ULTRA160; - } else - factor = MPT_ULTRA2; - - /* If RAID, never disable QAS - * else if non RAID, do not disable - * QAS if bit 1 is set - * bit 1 QAS support, non-raid only - * bit 0 IU support - */ - if ((target->raidVolume == 1) || - ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x02))) - noQas = 0; - - offset = pspi_data->maxSyncOffset; - + MPT_SCSI_CMD_PER_DEV_LOW); } else { - factor = MPT_ASYNC; - offset = 0; + /* error case - No Inq. Data */ + scsi_adjust_queue_depth(device, 0, 1); } } - /* Update tflags based on NVRAM settings. (SCSI only) - */ - if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = pspi_data->nvram[id]; - nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - - if (offset > 0) { - /* Ensure factor is set to the - * maximum of: adapter, nvram, inquiry - */ - if (nfactor) { - if (nfactor < pspi_data->minSyncFactor ) - nfactor = pspi_data->minSyncFactor; - - factor = MAX (factor, nfactor); - if (factor == MPT_ASYNC) - offset = 0; - } else { - offset = 0; - factor = MPT_ASYNC; - } - } else - factor = MPT_ASYNC; - } - - /* Make sure data is consistent - */ - if ((!width) && (factor < MPT_ULTRA2)) - factor = MPT_ULTRA2; - - /* Save the data to the target structure. - */ - target->minSyncFactor = factor; - target->maxOffset = offset; - target->maxWidth = width; - if (sdev->tagged_supported) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - - /* Disable unused features. - */ - target->negoFlags = pspi_data->noQas; - if (!width) - target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - - if (!offset) - target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + dsprintk((MYIOC_s_INFO_FMT + "Queue depth=%d, tflags=%x\n", + hd->ioc->name, device->queue_depth, pTarget->tflags)); - if (noQas) - target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + dsprintk((MYIOC_s_INFO_FMT + "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", + hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor)); - /* GEM, processor WORKAROUND - */ - target->type = sdev->inquiry[0] & 0x1F; - if ((target->type == 0x03) || (target->type > 0x08)){ - target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; - } +slave_configure_exit: - /* Disable QAS if mixed configuration case - */ - if ((noQas) && (!pspi_data->noQas) && (target->type == 0x00)){ - VirtDevice *vdev; - int ii; + dsprintk((MYIOC_s_INFO_FMT + "tagged %d, simple %d, ordered %d\n", + hd->ioc->name,device->tagged_supported, device->simple_tags, + device->ordered_tags)); - ddvtprintk((KERN_INFO "Disabling QAS!\n")); - pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS; - for (ii = 0; ii < id; ii++) { - vdev = hd->Targets[id]; - if (vdev != NULL) - vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - } - } - - ddvtprintk((KERN_INFO "Final settings id %d: dvstatus 0x%x\n", sdev->id, pspi_data->dvStatus[id])); - ddvtprintk(("wide %d, factor 0x%x offset 0x%x neg flags 0x%x flags 0x%x\n", - width, factor, offset, target->negoFlags, target->tflags)); - - return; + return 0; } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Private routines... @@ -3789,11 +3540,10 @@ thisIo.SCSIStatus = pScsiReply->SCSIStatus; thisIo.DoDisplay = 1; if (hd->is_multipath) - sprintf(devFoo, "%d:%d:%d \"%s\"", + sprintf(devFoo, "%d:%d:%d", hd->ioc->id, pReq->TargetID, - pReq->LUN[1], - target->dev_vol_name); + pReq->LUN[1]); else sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->device->id, sc->device->lun); thisIo.DevIDStr = devFoo; @@ -3842,7 +3592,7 @@ unsigned long flags; MPT_DONE_Q *buffer; MPT_FRAME_HDR *mf = NULL; - MPT_FRAME_HDR *cmdMfPtr = NULL; + MPT_FRAME_HDR *cmdMfPtr; ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name)); cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); @@ -3911,7 +3661,7 @@ continue; } - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); #if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) { @@ -3930,12 +3680,13 @@ static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_SCSI_HOST *hd = NULL; + MPT_SCSI_HOST *hd; unsigned long flags; dtmprintk((KERN_WARNING MYNAM ": IOC %s_reset routed to SCSI host driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); /* If a FW reload request arrives after base installed but * before all scsi hosts have been attached, then an alt_ioc @@ -3946,9 +3697,8 @@ else hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (reset_phase == MPT_IOC_PRE_RESET) { - dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n", - ioc->name)); + if (reset_phase == MPT_IOC_SETUP_RESET) { + dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name)); /* Clean Up: * 1. Set Hard Reset Pending Flag @@ -3956,6 +3706,11 @@ */ hd->resetPending = 1; + mptscsih_reset_timeouts (hd); + + } else if (reset_phase == MPT_IOC_PRE_RESET) { + dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); + /* 2. Flush running commands * Clean drop test code - if compiled * Clean ScsiLookup (and associated memory) @@ -3964,9 +3719,6 @@ /* 2a. Drop Test Command. */ -#ifdef DROP_TEST - mptscsih_flush_drop_test(hd); -#endif /* 2b. Reply to OS all known outstanding I/O commands. */ @@ -3979,7 +3731,6 @@ if (hd->cmdPtr) { del_timer(&hd->timer); mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr); - atomic_dec(&queue_depth); } /* 2d. If a task management has not completed, @@ -3990,12 +3741,14 @@ mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr); } - dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n", - ioc->name)); +#ifdef MPTSCSIH_DBG_TIMEOUT + ioc->timeout_hard = 0; +#endif + + dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name)); } else { - dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n", - ioc->name)); + dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name)); /* Once a FW reload begins, all new OS commands are * redirected to the doneQ w/ a reset status. @@ -4052,10 +3805,6 @@ */ flush_doneQ(hd); - dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n", - ioc->name)); - - /* 8. Set flag to force DV and re-read IOC Page 3 */ if (hd->is_spi) { @@ -4063,6 +3812,8 @@ ddvtprintk(("Set reload IOC Pg3 Flag\n")); } + dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); + } return 1; /* currently means nothing really */ @@ -4571,6 +4322,268 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_initTarget - Target, LUN alloc/free functionality. + * @hd: Pointer to MPT_SCSI_HOST structure + * @bus_id: Bus number (?) + * @target_id: SCSI target id + * @lun: SCSI LUN id + * @data: Pointer to data + * @dlen: Number of INQUIRY bytes + * + * NOTE: It's only SAFE to call this routine if data points to + * sane & valid STANDARD INQUIRY data! + * + * Allocate and initialize memory for this target. + * Save inquiry data. + * + */ +static void +mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen) +{ + int indexed_lun, lun_index; + VirtDevice *vdev; + char data_56; + + dprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", + hd->ioc->name, bus_id, target_id, lun, hd)); + + /* Is LUN supported? If so, upper 3 bits will be 0 + * in first byte of inquiry data. + */ + if (data[0] & 0xe0) + return; + + vdev = hd->Targets[target_id]; + + lun_index = (lun >> 5); /* 32 luns per lun_index */ + indexed_lun = (lun % 32); + vdev->luns[lun_index] |= (1 << indexed_lun); + + vdev->raidVolume = 0; + if (hd->is_spi) { + if (hd->ioc->spi_data.isRaid & (1 << target_id)) { + vdev->raidVolume = 1; + ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id)); + } + } + + if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { + if ( dlen > 8 ) { + memcpy (vdev->inq_data, data, 8); + } else { + memcpy (vdev->inq_data, data, dlen); + } + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + + /* If LUN 0, tape and have not done DV, set the DV flag. + */ + if (hd->is_spi && (lun == 0) && (data[0] == SCSI_TYPE_TAPE)) { + ScsiCfgData *pSpi = &hd->ioc->spi_data; + if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) + pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + } + + if ( (data[0] == SCSI_TYPE_PROC) && + !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { + if ( dlen > 49 ) { + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + if ( data[44] == 'S' && + data[45] == 'A' && + data[46] == 'F' && + data[47] == '-' && + data[48] == 'T' && + data[49] == 'E' ) { + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + } + } else { + /* Treat all Processors as SAF-TE if + * command line option is set */ + if ( hd->ioc->spi_data.Saf_Te ) { + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + } + } + } + + data_56 = 0; + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + } + } + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } + + dprintk((KERN_INFO " target = %p\n", vdev)); + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Update the target negotiation parameters based on the + * the Inquiry data, adapter capabilities, and NVRAM settings. + * + */ +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) +{ + ScsiCfgData *pspi_data = &hd->ioc->spi_data; + int id = (int) target->target_id; + int nvram; + char canQ = 0; + VirtDevice *vdev; + int ii; + u8 width = MPT_NARROW; + u8 factor = MPT_ASYNC; + u8 offset = 0; + u8 version, nfactor; + u8 noQas = 1; + + if (!hd->is_spi) { + if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + if (target->inq_data[7] & 0x02) + target->tflags |= MPT_TARGET_FLAGS_Q_YES; + } + return; + } + + target->negoFlags = pspi_data->noQas; + + /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine + * support. If available, default QAS to off and allow enabling. + * If not available, default QAS to on, turn off for non-disks. + */ + + /* Set flags based on Inquiry data + */ + if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + version = target->inq_data[2] & 0x07; + if (version < 2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + } else { + if (target->inq_data[7] & 0x20) { + width = 1; + } + + if (target->inq_data[7] & 0x10) { + /* bits 2 & 3 show DT support + */ + if ((byte56 & 0x04) == 0) + factor = MPT_ULTRA2; + else if ((byte56 & 0x03) == 0) + factor = MPT_ULTRA160; + else + factor = MPT_ULTRA320; + offset = pspi_data->maxSyncOffset; + + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support + */ + if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0)) + noQas = 0; + } else { + factor = MPT_ASYNC; + offset = 0; + } + } + + if (target->inq_data[7] & 0x02) { + canQ = 1; + } + + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = MAX (factor, nfactor); + if (factor == MPT_ASYNC) + offset = 0; + } else { + offset = 0; + factor = MPT_ASYNC; + } + } else { + factor = MPT_ASYNC; + } + } + + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) { + factor = MPT_ULTRA2; + } + + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; + if (canQ) { + target->tflags |= MPT_TARGET_FLAGS_Q_YES; + } + + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + + /* Disable unused features. + */ + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + + /* GEM, processor WORKAROUND + */ + if (((target->inq_data[0] & 0x1F) == 0x03) + || ((target->inq_data[0] & 0x1F) > 0x08)) { + target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); + pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; + } else { + if (noQas && (pspi_data->noQas == 0)) { + pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; + target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + + /* Disable QAS in a mixed configuration case + */ + +// ddvtprintk((KERN_INFO "Disabling QAS!\n")); + for (ii = 0; ii < id; ii++) { + if ( (vdev = hd->Targets[ii]) ) { + vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + } + } + } + } + } + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. * Else set the NEED_DV flag after Read Capacity Issued (disks) * or Mode Sense (cdroms). @@ -4581,7 +4594,7 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { u8 cmd; - + if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; @@ -4609,16 +4622,14 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * If no Target (old) or Target unconfigured (new) and bus reset on 1st I/O, - * set the flag to prevent any future negotiations to this device. + * If no Target, bus reset on 1st I/O. Set the flag to + * prevent any future negotiations to this device. */ static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id) { - if (hd->Targets) { - VirtDevice *vdev = hd->Targets[target_id]; - if ((vdev == NULL) || !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED)) - hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO; - } + + if ((hd->Targets) && (hd->Targets[target_id] == NULL)) + hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO; return; } @@ -4691,9 +4702,9 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) { MPT_ADAPTER *ioc = hd->ioc; - Config_t *pReq = NULL; - SCSIDevicePage1_t *pData = NULL; - VirtDevice *pTarget = NULL; + Config_t *pReq; + SCSIDevicePage1_t *pData; + VirtDevice *pTarget; MPT_FRAME_HDR *mf; dma_addr_t dataDma; u16 req_idx; @@ -4784,13 +4795,11 @@ /* If id is not a raid volume, get the updated * transmission settings from the target structure. */ - if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume - && (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { + if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { width = pTarget->maxWidth; factor = pTarget->minSyncFactor; offset = pTarget->maxOffset; negoFlags = pTarget->negoFlags; - pTarget = NULL; } if (flags & MPT_SCSICFG_BLK_NEGO) @@ -4832,9 +4841,8 @@ pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; - pReq->Reserved1[0] = 0; - pReq->Reserved1[1] = 0; - pReq->Reserved1[2] = 0; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; pReq->MsgFlags = 0; for (ii=0; ii < 8; ii++) { pReq->Reserved2[ii] = 0; @@ -4861,14 +4869,93 @@ pData->Reserved = 0; pData->Configuration = cpu_to_le32(configuration); - dsprintk((MYIOC_s_INFO_FMT + dprintk((MYIOC_s_INFO_FMT "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n", ioc->name, id, (id | (bus<<8)), requested, configuration)); - mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_writeIOCPage4 - write IOC Page 4 + * @hd: Pointer to a SCSI Host Structure + * @target_id: write IOC Page4 for this ID & Bus + * + * Return: -EAGAIN if unable to obtain a Message Frame + * or 0 if success. + * + * Remark: We do not wait for a return, write pages sequentially. + */ +static int +mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) +{ + MPT_ADAPTER *ioc = hd->ioc; + Config_t *pReq; + IOCPage4_t *IOCPage4Ptr; + MPT_FRAME_HDR *mf; + dma_addr_t dataDma; + u16 req_idx; + u32 frameOffset; + u32 flagsLength; + int ii; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) { + dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + + ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n", + ioc->name, mf, target_id)); + + /* Set the request and the data pointers. + * Place data at end of MF. + */ + pReq = (Config_t *)mf; + + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + frameOffset = ioc->req_sz - sizeof(IOCPage4_t); + + /* Complete the request frame (same for all requests). + */ + pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_CONFIG; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; + pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) { + pReq->Reserved2[ii] = 0; } + IOCPage4Ptr = ioc->spi_data.pIocPg4; + dataDma = ioc->spi_data.IocPg4_dma; + ii = IOCPage4Ptr->ActiveSEP++; + IOCPage4Ptr->SEP[ii].SEPTargetID = target_id; + IOCPage4Ptr->SEP[ii].SEPBus = bus; + pReq->Header = IOCPage4Ptr->Header; + pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 )); + + /* Add a SGE to the config request. + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | + (IOCPage4Ptr->Header.PageLength + ii) * 4; + + mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + + dsprintk((MYIOC_s_INFO_FMT + "writeIOCPage4: pgaddr 0x%x\n", + ioc->name, (target_id | (bus<<8)))); + + mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf); + return 0; } @@ -4982,8 +5069,6 @@ ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", hd->ioc->name, mf, mr, req_idx)); - atomic_dec(&queue_depth); - hd->pLocal = &hd->localReply; hd->pLocal->scsiStatus = 0; @@ -5042,7 +5127,7 @@ u8 *sense_data; int sz; - /* save sense data in global & target structure + /* save sense data in global structure */ completionCode = MPT_SCANDV_SENSE; hd->pLocal->scsiStatus = pReply->SCSIStatus; @@ -5215,7 +5300,7 @@ hd->cmdPtr = mf; add_timer(&hd->timer); - mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf); wait_event(scandv_waitq, scandv_wait_done); if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD)) @@ -5452,7 +5537,7 @@ hd->cmdPtr = mf; add_timer(&hd->timer); - mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf); wait_event(scandv_waitq, scandv_wait_done); if (hd->pLocal) { @@ -5490,7 +5575,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) { MPT_ADAPTER *ioc= hd->ioc; - VirtDevice *pTarget = NULL; + VirtDevice *pTarget; SCSIDevicePage1_t *pcfg1Data = NULL; INTERNAL_CMD iocmd; CONFIGPARMS cfg; @@ -5498,7 +5583,8 @@ ConfigPageHeader_t header1; int bus = 0; int id = 0; - int lun = 0; + int lun; + int indexed_lun, lun_index; int hostId = ioc->pfacts[portnum].PortSCSIID; int max_id; int requested, configuration, data; @@ -5593,7 +5679,9 @@ for (lun=0; lun <= MPT_LAST_LUN; lun++) { /* If LUN present, issue the command */ - if (pTarget->luns & (1<> 5); /* 32 luns per lun_index */ + indexed_lun = (lun % 32); + if (pTarget->luns[lun_index] & (1<Targets == NULL) @@ -5843,15 +5931,15 @@ * Return: None. */ static int -mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) +mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) { MPT_ADAPTER *ioc = hd->ioc; - VirtDevice *pTarget = NULL; - SCSIDevicePage1_t *pcfg1Data = NULL; - SCSIDevicePage0_t *pcfg0Data = NULL; - u8 *pbuf1 = NULL; - u8 *pbuf2 = NULL; - u8 *pDvBuf = NULL; + VirtDevice *pTarget; + SCSIDevicePage1_t *pcfg1Data; + SCSIDevicePage0_t *pcfg0Data; + u8 *pbuf1; + u8 *pbuf2; + u8 *pDvBuf; dma_addr_t dvbuf_dma = -1; dma_addr_t buf1_dma = -1; dma_addr_t buf2_dma = -1; @@ -5871,6 +5959,7 @@ int patt; int repeat; int retcode = 0; + int nfactor = MPT_ULTRA320; char firstPass = 1; char doFallback = 0; char readPage0; @@ -5883,14 +5972,17 @@ if (ioc->spi_data.sdp0length == 0) return 0; - if (id == ioc->pfacts[portnum].PortSCSIID) + /* If multiple buses are used, require that the initiator + * id be the same on all buses. + */ + if (id == ioc->pfacts[0].PortSCSIID) return 0; lun = 0; - bus = 0; + bus = (u8) bus_number; ddvtprintk((MYIOC_s_NOTE_FMT - "DV started: numIOs %d bus=%d, id %d dv @ %p\n", - ioc->name, atomic_read(&queue_depth), bus, id, &dv)); + "DV started: bus=%d, id %d dv @ %p\n", + ioc->name, bus, id, &dv)); /* Prep DV structure */ @@ -5916,11 +6008,11 @@ iocmd.rsvd = iocmd.rsvd2 = 0; pTarget = hd->Targets[id]; - if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ - if ((pTarget->type == 0x03) || (pTarget->type > 0x08)) { + if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) { pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); return 0; } @@ -5992,24 +6084,34 @@ /* Skip this ID? Set cfg.hdr to force config page write */ - if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) && - (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { + { + ScsiCfgData *pspi_data = &hd->ioc->spi_data; + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + /* Set the factor from nvram */ + nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8; + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; - ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", - ioc->name, bus, id, lun)); + if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) || + (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) { - dv.cmd = MPT_SET_MAX; - mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); - cfg.hdr = &header1; - /* Double writes to SDP1 can cause problems, - * skip save of the final negotiated settings to - * SCSI device page 1. - */ - cfg.physAddr = cfg1_dma_addr; - cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; - cfg.dir = 1; - mpt_config(hd->ioc, &cfg); - goto target_done; + ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", + ioc->name, bus, id, lun)); + + dv.cmd = MPT_SET_MAX; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + cfg.hdr = &header1; + + /* Save the final negotiated settings to + * SCSI device page 1. + */ + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + mpt_config(hd->ioc, &cfg); + goto target_done; + } + } } /* Finish iocmd inititialization - hidden or visible disk? */ @@ -6059,7 +6161,7 @@ sz = SCSI_STD_INQUIRY_BYTES; rc = MPT_SCANDV_GOOD; while (1) { - ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name)); + ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id)); retcode = 0; dv.cmd = MPT_SET_MIN; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); @@ -6131,6 +6233,14 @@ } } + /* Reset the size for disks + */ + inq0 = (*pbuf1) & 0x1F; + if ((inq0 == 0) && pTarget && !pTarget->raidVolume) { + sz = 0x40; + iocmd.size = sz; + } + /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ @@ -6140,6 +6250,28 @@ if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; + if (sz == 0x40) { + if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A) + && (pTarget->minSyncFactor > 0x09)) { + if ((pbuf1[56] & 0x04) == 0) + ; + else if ((pbuf1[56] & 0x01) == 1) { + pTarget->minSyncFactor = + nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320; + } else { + pTarget->minSyncFactor = + nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160; + } + + dv.max.factor = pTarget->minSyncFactor; + + if ((pbuf1[56] & 0x02) == 0) { + pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + } + } + } + if (doFallback) dv.cmd = MPT_FALLBACK; else @@ -6223,7 +6355,7 @@ firstPass = 0; } } - ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name)); + ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id)); inq0 = (*pbuf1) & 0x1F; /* Continue only for disks @@ -6231,6 +6363,9 @@ if (inq0 != 0) goto target_done; + if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY ) + goto target_done; + /* Start the Enhanced Test. * 0) issue TUR to clear out check conditions * 1) read capacity of echo (regular) buffer @@ -6671,8 +6806,8 @@ if (pDvBuf) pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma); - ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n", - ioc->name, atomic_read(&queue_depth))); + ddvtprintk((MYIOC_s_INFO_FMT "DV Done.\n", + ioc->name)); return retcode; } @@ -6687,9 +6822,9 @@ static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) { - VirtDevice *pTarget = NULL; - SCSIDevicePage0_t *pPage0 = NULL; - SCSIDevicePage1_t *pPage1 = NULL; + VirtDevice *pTarget; + SCSIDevicePage0_t *pPage0; + SCSIDevicePage1_t *pPage1; int val = 0, data, configuration; u8 width = 0; u8 offset = 0; @@ -6841,7 +6976,6 @@ factor = MPT_ULTRA; width = MPT_WIDE; } else if ((factor == MPT_ULTRA) && width) { - factor = MPT_ULTRA; width = MPT_NARROW; } else if (factor < MPT_FAST) { factor = MPT_FAST; @@ -7072,9 +7206,9 @@ /* Commandline Parsing routines and defines. * * insmod format: - * insmod mptscsih mptscsih="width:1 dv:n factor:0x09" + * insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1" * boot format: - * mptscsih=width:1,dv:n,factor:0x8 + * mptscsih=width:1,dv:n,factor:0x8,saf-te:1 * */ #ifdef MODULE @@ -7087,11 +7221,13 @@ "dv:" "width:" "factor:" - ; /* DONNOT REMOVE THIS ';' */ + "saf-te:" + ; /* DO NOT REMOVE THIS ';' */ #define OPT_DV 1 #define OPT_MAX_WIDTH 2 #define OPT_MIN_SYNC_FACTOR 3 +#define OPT_SAF_TE 4 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int @@ -7146,6 +7282,10 @@ case OPT_MIN_SYNC_FACTOR: driver_setup.min_sync_fac = val; + break; + + case OPT_SAF_TE: + driver_setup.saf_te = val; break; default: diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h --- a/drivers/message/fusion/mptscsih.h Sat Apr 3 19:38:56 2004 +++ b/drivers/message/fusion/mptscsih.h Sat Apr 3 19:38:56 2004 @@ -15,7 +15,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -70,11 +70,7 @@ * Try to keep these at 2^N-1 */ #define MPT_FC_CAN_QUEUE 127 -#if defined MPT_SCSI_USE_NEW_EH - #define MPT_SCSI_CAN_QUEUE 127 -#else - #define MPT_SCSI_CAN_QUEUE 63 -#endif +#define MPT_SCSI_CAN_QUEUE 127 #define MPT_SCSI_CMD_PER_DEV_HIGH 31 #define MPT_SCSI_CMD_PER_DEV_LOW 7 @@ -98,7 +94,7 @@ #define MPT_SCSI_SG_DEPTH 40 #endif -/* To disable domain validation, comment the +/* To disable domain validation, uncomment the * following line. No effect for FC devices. * For SCSI devices, driver will negotiate to * NVRAM settings (if available) or to maximum adapter @@ -114,12 +110,14 @@ #define MPTSCSIH_DOMAIN_VALIDATION 1 #define MPTSCSIH_MAX_WIDTH 1 #define MPTSCSIH_MIN_SYNC 0x08 +#define MPTSCSIH_SAF_TE 0 struct mptscsih_driver_setup { u8 dv; u8 max_width; u8 min_sync_fac; + u8 saf_te; }; @@ -128,6 +126,7 @@ MPTSCSIH_DOMAIN_VALIDATION, \ MPTSCSIH_MAX_WIDTH, \ MPTSCSIH_MIN_SYNC, \ + MPTSCSIH_SAF_TE, \ } diff -Nru a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h --- a/drivers/message/fusion/scsi3.h Sat Apr 3 19:38:43 2004 +++ b/drivers/message/fusion/scsi3.h Sat Apr 3 19:38:43 2004 @@ -4,7 +4,7 @@ * (Ultimately) SCSI-3 definitions; for now, inheriting * SCSI-2 definitions. * - * Copyright (c) 1996-2003 Steven J. Ralston + * Copyright (c) 1996-2004 Steven J. Ralston * Written By: Steven J. Ralston (19960517) * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c --- a/drivers/message/i2o/i2o_core.c Sat Apr 3 19:38:44 2004 +++ b/drivers/message/i2o/i2o_core.c Sat Apr 3 19:38:44 2004 @@ -1179,7 +1179,7 @@ * the processor */ - pci_dma_sync_single(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE); /* * Despatch it diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c --- a/drivers/mtd/cmdlinepart.c Sat Apr 3 19:38:54 2004 +++ b/drivers/mtd/cmdlinepart.c Sat Apr 3 19:38:54 2004 @@ -28,7 +28,6 @@ #include #include -#include #include /* error message prefix */ diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c --- a/drivers/mtd/devices/blkmtd.c Sat Apr 3 19:38:41 2004 +++ b/drivers/mtd/devices/blkmtd.c Sat Apr 3 19:38:41 2004 @@ -664,12 +664,12 @@ } memset(dev, 0, sizeof(struct blkmtd_dev)); + dev->blkdev = bdev; atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0); if(!readonly) { init_MUTEX(&dev->wrbuf_mutex); } - dev->blkdev = bdev; dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; /* Setup the MTD structure */ diff -Nru a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c --- a/drivers/mtd/nand/nand.c Sat Apr 3 19:38:57 2004 +++ b/drivers/mtd/nand/nand.c Sat Apr 3 19:38:57 2004 @@ -1060,7 +1060,7 @@ goto out; /* Update written bytes count */ - written += mtd->oobblock;; + written += mtd->oobblock; /* Increment page address */ page++; @@ -1192,7 +1192,7 @@ nand_deselect (); spin_unlock_bh (&this->chip_lock); - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;; + ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; /* Do call back function */ if (!ret && instr->callback) instr->callback (instr); diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c --- a/drivers/net/3c501.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/3c501.c Sat Apr 3 19:38:40 2004 @@ -306,7 +306,7 @@ printk(KERN_DEBUG "%s", version); memset(dev->priv, 0, sizeof(struct net_local)); - lp=dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); /* @@ -341,7 +341,7 @@ { int retval; int ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; if (el_debug > 2) @@ -371,7 +371,7 @@ static void el_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el_debug) @@ -411,7 +411,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -524,7 +524,7 @@ int axsr; /* Aux. status reg. */ ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -698,7 +698,7 @@ static void el_receive(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int pkt_len; struct sk_buff *skb; @@ -764,7 +764,7 @@ static void el_reset(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el_debug> 2) @@ -828,7 +828,7 @@ static struct net_device_stats *el1_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c --- a/drivers/net/3c503.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/3c503.c Sat Apr 3 19:38:54 2004 @@ -337,6 +337,9 @@ dev->open = &el2_open; dev->stop = &el2_close; dev->ethtool_ops = &netdev_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c --- a/drivers/net/3c507.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/3c507.c Sat Apr 3 19:38:54 2004 @@ -441,7 +441,7 @@ if (net_debug) printk(version); - lp = dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); @@ -471,7 +471,7 @@ static void el16_tx_timeout (struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; @@ -501,7 +501,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; @@ -546,7 +546,7 @@ } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); shmem = dev->mem_start; spin_lock(&lp->lock); @@ -660,7 +660,7 @@ closed. */ static struct net_device_stats *el16_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); /* ToDo: decide if there are any useful statistics from the SCB. */ @@ -670,7 +670,7 @@ /* Initialize the Rx-block list. */ static void init_rx_bufs(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long write_ptr; unsigned short SCB_base = SCB_BASE; @@ -713,7 +713,7 @@ static void init_82586_mem(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; @@ -771,7 +771,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; ushort tx_block = lp->tx_head; unsigned long write_ptr = dev->mem_start + tx_block; @@ -820,7 +820,7 @@ static void el16_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long shmem = dev->mem_start; ushort rx_head = lp->rx_head; ushort rx_tail = lp->rx_tail; diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/3c509.c Sat Apr 3 19:38:41 2004 @@ -304,7 +304,7 @@ static int __init el3_common_init(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); short i; int err; @@ -355,21 +355,21 @@ static void el3_common_remove (struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); - (void) lp; /* Keep gcc quiet... */ + (void) lp; /* Keep gcc quiet... */ #ifdef CONFIG_PM - if (lp->pmdev) - pm_unregister(lp->pmdev); + if (lp->pmdev) + pm_unregister(lp->pmdev); #endif #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) - if (lp->type == EL3_PNP) - pnp_device_detach(to_pnp_dev(lp->dev)); + if (lp->type == EL3_PNP) + pnp_device_detach(to_pnp_dev(lp->dev)); #endif - unregister_netdev (dev); - release_region(dev->base_addr, EL3_IO_EXTENT); - free_netdev (dev); + unregister_netdev (dev); + release_region(dev->base_addr, EL3_IO_EXTENT); + free_netdev (dev); } static int __init el3_probe(int card_idx) @@ -397,9 +397,9 @@ if (pnp_device_attach(idev) < 0) continue; if (pnp_activate_dev(idev) < 0) { - __again: - pnp_device_detach(idev); - continue; +__again: + pnp_device_detach(idev); + continue; } if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) goto __again; @@ -575,7 +575,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->if_port = if_port; - lp = dev->priv; + lp = netdev_priv(dev); #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) lp->dev = &idev->dev; #endif @@ -612,79 +612,80 @@ } #ifdef CONFIG_MCA -static int __init el3_mca_probe(struct device *device) { - /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, - * heavily modified by Chris Beauregard - * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA - * probing. - * - * redone for multi-card detection by ZP Gu (zpg@castle.net) - * now works as a module */ - - struct el3_private *lp; - short i; - int ioaddr, irq, if_port; - u16 phys_addr[3]; - struct net_device *dev = NULL; - u_char pos4, pos5; - struct mca_device *mdev = to_mca_device(device); - int slot = mdev->slot; - int err; - - pos4 = mca_device_read_stored_pos(mdev, 4); - pos5 = mca_device_read_stored_pos(mdev, 5); - - ioaddr = ((short)((pos4&0xfc)|0x02)) << 8; - irq = pos5 & 0x0f; - - - printk("3c529: found %s at slot %d\n", - el3_mca_adapter_names[mdev->index], slot + 1); - - /* claim the slot */ - strncpy(mdev->name, el3_mca_adapter_names[mdev->index], - sizeof(mdev->name)); - mca_device_set_claim(mdev, 1); - - if_port = pos4 & 0x03; - - irq = mca_device_transform_irq(mdev, irq); - ioaddr = mca_device_transform_ioport(mdev, ioaddr); - if (el3_debug > 2) { - printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); - } - EL3WINDOW(0); - for (i = 0; i < 3; i++) { - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - } +static int __init el3_mca_probe(struct device *device) +{ + /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, + * heavily modified by Chris Beauregard + * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA + * probing. + * + * redone for multi-card detection by ZP Gu (zpg@castle.net) + * now works as a module */ - dev = alloc_etherdev(sizeof (struct el3_private)); - if (dev == NULL) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; - } + struct el3_private *lp; + short i; + int ioaddr, irq, if_port; + u16 phys_addr[3]; + struct net_device *dev = NULL; + u_char pos4, pos5; + struct mca_device *mdev = to_mca_device(device); + int slot = mdev->slot; + int err; + + pos4 = mca_device_read_stored_pos(mdev, 4); + pos5 = mca_device_read_stored_pos(mdev, 5); - SET_MODULE_OWNER(dev); - netdev_boot_setup_check(dev); + ioaddr = ((short)((pos4&0xfc)|0x02)) << 8; + irq = pos5 & 0x0f; - memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); - dev->base_addr = ioaddr; - dev->irq = irq; - dev->if_port = if_port; - lp = dev->priv; - lp->dev = device; - lp->type = EL3_MCA; - device->driver_data = dev; - err = el3_common_init(dev); - - if (err) { - device->driver_data = NULL; - free_netdev(dev); + + printk("3c529: found %s at slot %d\n", + el3_mca_adapter_names[mdev->index], slot + 1); + + /* claim the slot */ + strncpy(mdev->name, el3_mca_adapter_names[mdev->index], + sizeof(mdev->name)); + mca_device_set_claim(mdev, 1); + + if_port = pos4 & 0x03; + + irq = mca_device_transform_irq(mdev, irq); + ioaddr = mca_device_transform_ioport(mdev, ioaddr); + if (el3_debug > 2) { + printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); + } + EL3WINDOW(0); + for (i = 0; i < 3; i++) { + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + } + + dev = alloc_etherdev(sizeof (struct el3_private)); + if (dev == NULL) { + release_region(ioaddr, EL3_IO_EXTENT); return -ENOMEM; - } + } - el3_cards++; - return 0; + SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); + + memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); + dev->base_addr = ioaddr; + dev->irq = irq; + dev->if_port = if_port; + lp = netdev_priv(dev); + lp->dev = device; + lp->type = EL3_MCA; + device->driver_data = dev; + err = el3_common_init(dev); + + if (err) { + device->driver_data = NULL; + free_netdev(dev); + return -ENOMEM; + } + + el3_cards++; + return 0; } #endif /* CONFIG_MCA */ @@ -713,15 +714,15 @@ irq = inw(ioaddr + WN0_IRQ) >> 12; if_port = inw(ioaddr + 6)>>14; for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); + phys_addr[i] = htons(read_eeprom(ioaddr, i)); /* Restore the "Product ID" to the EEPROM read register. */ read_eeprom(ioaddr, 3); dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; + release_region(ioaddr, EL3_IO_EXTENT); + return -ENOMEM; } SET_MODULE_OWNER(dev); @@ -732,7 +733,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->if_port = if_port; - lp = dev->priv; + lp = netdev_priv(dev); lp->dev = device; lp->type = EL3_EISA; eisa_set_drvdata (edev, dev); @@ -755,12 +756,12 @@ * The net dev must be stored in the driver_data field */ static int __devexit el3_device_remove (struct device *device) { - struct net_device *dev; + struct net_device *dev; - dev = device->driver_data; + dev = device->driver_data; - el3_common_remove (dev); - return 0; + el3_common_remove (dev); + return 0; } #endif @@ -810,7 +811,8 @@ outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev); - if (i) return i; + if (i) + return i; EL3WINDOW(0); if (el3_debug > 3) @@ -829,7 +831,7 @@ static void el3_tx_timeout (struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -849,7 +851,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -891,8 +893,8 @@ * time sensitive devices. */ - spin_lock_irqsave(&lp->lock, flags); - + spin_lock_irqsave(&lp->lock, flags); + /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); outw(0x00, ioaddr + TX_FIFO); @@ -943,7 +945,7 @@ return IRQ_NONE; } - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); ioaddr = dev->base_addr; @@ -975,7 +977,7 @@ outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & TxComplete) { /* Really Tx error. */ - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); short tx_status; int i = 4; @@ -1022,7 +1024,7 @@ static struct net_device_stats * el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; /* @@ -1043,7 +1045,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el3_debug > 5) @@ -1073,7 +1075,7 @@ static int el3_rx(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short rx_status; @@ -1145,7 +1147,7 @@ set_multicast_list(struct net_device *dev) { unsigned long flags; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el3_debug > 1) { @@ -1164,7 +1166,7 @@ outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); } else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); spin_unlock_irqrestore(&lp->lock, flags); } @@ -1172,7 +1174,7 @@ el3_close(struct net_device *dev) { int ioaddr = dev->base_addr; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); if (el3_debug > 2) printk("%s: Shutting down ethercard.\n", dev->name); @@ -1183,10 +1185,10 @@ /* Switching back to window 0 disables the IRQ. */ EL3WINDOW(0); if (lp->type != EL3_EISA) { - /* But we explicitly zero the IRQ line select anyway. Don't do - * it on EISA cards, it prevents the module from getting an - * IRQ after unload+reload... */ - outw(0x0f00, ioaddr + WN0_IRQ); + /* But we explicitly zero the IRQ line select anyway. Don't do + * it on EISA cards, it prevents the module from getting an + * IRQ after unload+reload... */ + outw(0x0f00, ioaddr + WN0_IRQ); } return 0; @@ -1317,7 +1319,7 @@ netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) { u32 ethcmd; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ @@ -1558,7 +1560,7 @@ return -EINVAL; dev = (struct net_device *)pdev->data; - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock_irqsave(&lp->lock, flags); @@ -1585,7 +1587,7 @@ return -EINVAL; dev = (struct net_device *)pdev->data; - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock_irqsave(&lp->lock, flags); @@ -1654,13 +1656,13 @@ #ifdef CONFIG_EISA if (eisa_driver_register (&el3_eisa_driver) < 0) { - eisa_driver_unregister (&el3_eisa_driver); + eisa_driver_unregister (&el3_eisa_driver); } #endif #ifdef CONFIG_MCA mca_register_driver(&el3_mca_driver); #endif - return el3_cards ? 0 : -ENODEV; + return 0; } static void __exit el3_cleanup_module(void) @@ -1668,7 +1670,7 @@ struct net_device *next_dev; while (el3_root_dev) { - struct el3_private *lp = (struct el3_private *)el3_root_dev->priv; + struct el3_private *lp = netdev_priv(el3_root_dev); next_dev = lp->next_dev; el3_common_remove (el3_root_dev); @@ -1686,11 +1688,3 @@ module_init (el3_init_module); module_exit (el3_cleanup_module); -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c --- a/drivers/net/3c527.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/3c527.c Sat Apr 3 19:38:44 2004 @@ -226,7 +226,7 @@ static void cleanup_card(struct net_device *dev) { - struct mc32_local *lp=dev->priv; + struct mc32_local *lp = netdev_priv(dev); unsigned slot = lp->slot; mca_mark_as_unused(slot); mca_set_adapter_name(slot, NULL); @@ -307,7 +307,7 @@ int i, err; u8 POS; u32 base; - struct mc32_local *lp = dev->priv; + struct mc32_local *lp = netdev_priv(dev); static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, @@ -573,7 +573,7 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = -1; @@ -619,7 +619,7 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = 0; @@ -671,7 +671,7 @@ static void mc32_start_transceiver(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Ignore RX overflow on device closure */ @@ -706,7 +706,7 @@ static void mc32_halt_transceiver(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; mc32_ready_poll(dev); @@ -743,7 +743,7 @@ static int mc32_load_rx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; u16 rx_base; volatile struct skb_header *p; @@ -792,7 +792,7 @@ static void mc32_flush_rx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; for(i=0; i < RX_RING_LEN; i++) @@ -824,7 +824,7 @@ static void mc32_load_tx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; int i; u16 tx_base; @@ -861,7 +861,7 @@ static void mc32_flush_tx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; for (i=0; i < TX_RING_LEN; i++) @@ -899,7 +899,7 @@ static int mc32_open(struct net_device *dev) { int ioaddr = dev->base_addr; - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u8 one=1; u8 regs; u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; @@ -1022,7 +1022,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u32 head = atomic_read(&lp->tx_ring_head); volatile struct skb_header *p, *np; @@ -1092,7 +1092,7 @@ static void mc32_update_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct mc32_stats *st = lp->stats; u32 rx_errors=0; @@ -1143,7 +1143,7 @@ static void mc32_rx_ring(struct net_device *dev) { - struct mc32_local *lp=dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; u16 rx_ring_tail; u16 rx_old_tail; @@ -1236,7 +1236,7 @@ static void mc32_tx_ring(struct net_device *dev) { - struct mc32_local *lp=(struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *np; /* @@ -1333,7 +1333,7 @@ } ioaddr = dev->base_addr; - lp = (struct mc32_local *)dev->priv; + lp = netdev_priv(dev); /* See whats cooking */ @@ -1450,7 +1450,7 @@ static int mc32_close(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; u8 regs; @@ -1499,7 +1499,7 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); mc32_update_stats(dev); return &lp->net_stats; @@ -1531,7 +1531,7 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/3c59x.c Sat Apr 3 19:38:40 2004 @@ -927,6 +927,18 @@ static int vortex_cards_found; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_vortex(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_PM static int vortex_suspend (struct pci_dev *pdev, u32 state) @@ -1013,7 +1025,7 @@ BUG(); } - vp = dev->priv; + vp = netdev_priv(dev); ioaddr = dev->base_addr; unregister_netdev (dev); @@ -1115,7 +1127,7 @@ } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); - vp = dev->priv; + vp = netdev_priv(dev); option = global_options; @@ -1463,6 +1475,9 @@ dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = poll_vortex; +#endif if (pdev && vp->enable_wol) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp), vp->power_state); @@ -1516,7 +1531,7 @@ vortex_up(struct net_device *dev) { long ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); unsigned int config; int i; @@ -1714,7 +1729,7 @@ static int vortex_open(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int i; int retval; @@ -1772,7 +1787,7 @@ vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; int ok = 0; @@ -1898,7 +1913,7 @@ static void vortex_tx_timeout(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", @@ -1968,7 +1983,7 @@ static void vortex_error(struct net_device *dev, int status) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int do_tx_reset = 0, reset_mask = 0; unsigned char tx_status = 0; @@ -2070,7 +2085,7 @@ static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Put out the doubleword header... */ @@ -2125,7 +2140,7 @@ static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; @@ -2225,7 +2240,7 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr; int status; int work_done = max_interrupt_work; @@ -2330,7 +2345,7 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr; int status; int work_done = max_interrupt_work; @@ -2455,7 +2470,7 @@ static int vortex_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; short rx_status; @@ -2525,7 +2540,7 @@ static int boomerang_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int entry = vp->cur_rx % RX_RING_SIZE; long ioaddr = dev->base_addr; int rx_status; @@ -2562,11 +2577,12 @@ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pci_dma_sync_single(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), vp->rx_skbuff[entry]->tail, pkt_len); + pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); vp->rx_copy++; } else { /* Pass up the skbuff already on the Rx ring. */ @@ -2627,7 +2643,7 @@ rx_oom_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); spin_lock_irq(&vp->lock); if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ @@ -2642,7 +2658,7 @@ static void vortex_down(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; netif_stop_queue (dev); @@ -2678,7 +2694,7 @@ static int vortex_close(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; @@ -2740,7 +2756,7 @@ dump_tx_ring(struct net_device *dev) { if (vortex_debug > 0) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; if (vp->full_bus_master_tx) { @@ -2773,7 +2789,7 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); unsigned long flags; if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ @@ -2793,7 +2809,7 @@ */ static void update_stats(long ioaddr, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int old_window = inw(ioaddr + EL3_CMD); if (old_window == 0xffff) /* Chip suspended or ejected. */ @@ -2834,7 +2850,7 @@ static void vortex_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct vortex_private *vp = dev->priv; + struct vortex_private *vp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -2855,7 +2871,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; @@ -2942,7 +2958,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int i; long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; @@ -2976,7 +2992,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; @@ -3010,7 +3026,7 @@ /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ static void acpi_set_WOL(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ @@ -3036,7 +3052,7 @@ BUG(); } - vp = dev->priv; + vp = netdev_priv(dev); /* AKPM: FIXME: we should have * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); diff -Nru a/drivers/net/7990.c b/drivers/net/7990.c --- a/drivers/net/7990.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/7990.c Sat Apr 3 19:38:54 2004 @@ -99,7 +99,7 @@ /* Set up the Lance Rx and Tx rings and the init block */ static void lance_init_ring (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ int leptr; @@ -216,7 +216,7 @@ static int lance_reset (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int status; DECLARE_LL; @@ -236,7 +236,7 @@ static int lance_rx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; @@ -316,7 +316,7 @@ static int lance_tx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_tx_desc *td; int i, j; @@ -401,7 +401,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; DECLARE_LL; @@ -457,7 +457,7 @@ int lance_open (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int res; DECLARE_LL; @@ -474,7 +474,7 @@ int lance_close (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); DECLARE_LL; netif_stop_queue (dev); @@ -499,7 +499,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; static int outs; @@ -556,7 +556,7 @@ struct net_device_stats *lance_get_stats (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -564,7 +564,7 @@ /* taken from the depca driver via a2065.c */ static void lance_load_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -601,7 +601,7 @@ void lance_set_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int stopped; DECLARE_LL; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/8139too.c Sat Apr 3 19:38:40 2004 @@ -113,6 +113,7 @@ #include #include #include +#include #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " @@ -968,12 +969,11 @@ if (i < 0) return i; + assert (dev != NULL); tp = dev->priv; + assert (tp != NULL); ioaddr = tp->mmio_addr; - assert (ioaddr != NULL); - assert (dev != NULL); - assert (tp != NULL); addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) diff -Nru a/drivers/net/82596.c b/drivers/net/82596.c --- a/drivers/net/82596.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/82596.c Sat Apr 3 19:38:54 2004 @@ -458,7 +458,7 @@ static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -528,7 +528,7 @@ static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -579,7 +579,7 @@ static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; struct i596_rbd *rbd; int i; @@ -593,7 +593,7 @@ static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -612,7 +612,7 @@ static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) short ioaddr = dev->base_addr; #endif @@ -765,7 +765,7 @@ static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -960,7 +960,7 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int ioaddr = dev->base_addr; unsigned long flags; @@ -1030,7 +1030,7 @@ static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -1059,7 +1059,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1245,7 +1245,7 @@ dev->priv = (void *)(dev->mem_start); - lp = (struct i596_private *) dev->priv; + lp = dev->priv; DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); @@ -1305,7 +1305,7 @@ } ioaddr = dev->base_addr; - lp = (struct i596_private *) dev->priv; + lp = dev->priv; spin_lock (&lp->lock); @@ -1448,7 +1448,7 @@ static int i596_close(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; unsigned long flags; netif_stop_queue(dev); @@ -1495,7 +1495,7 @@ static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; return &lp->stats; } @@ -1506,7 +1506,7 @@ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c --- a/drivers/net/8390.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/8390.c Sat Apr 3 19:38:41 2004 @@ -516,6 +516,15 @@ return IRQ_RETVAL(nr_serviced > 0); } +#ifdef CONFIG_NET_POLL_CONTROLLER +void ei_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /** * ei_tx_err - handle transmitter error * @dev: network device which threw the exception @@ -1124,6 +1133,9 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); +#ifdef CONFIG_NET_POLL_CONTROLLER +EXPORT_SYMBOL(ei_poll); +#endif EXPORT_SYMBOL(ei_tx_timeout); EXPORT_SYMBOL(NS8390_init); EXPORT_SYMBOL(__alloc_ei_netdev); diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h --- a/drivers/net/8390.h Sat Apr 3 19:38:54 2004 +++ b/drivers/net/8390.h Sat Apr 3 19:38:54 2004 @@ -39,6 +39,10 @@ #define ei_debug 1 #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +extern void ei_poll(struct net_device *dev); +#endif + extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Sat Apr 3 19:38:55 2004 +++ b/drivers/net/Kconfig Sat Apr 3 19:38:55 2004 @@ -2048,8 +2048,8 @@ If you want to compile this driver 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. This is recommended. - The module will be called sk98lin. This is recommended. + say M here and read Documentation/kbuild/modules.txt. The module will + be called sk98lin. This is recommended. config TIGON3 tristate "Broadcom Tigon3 support" @@ -2494,6 +2494,13 @@ To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. + +config NETCONSOLE + tristate "Network console logging support (EXPERIMENTAL)" + depends on NETDEVICES && EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. source "drivers/net/wan/Kconfig" diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Sat Apr 3 19:38:42 2004 +++ b/drivers/net/Makefile Sat Apr 3 19:38:42 2004 @@ -188,3 +188,4 @@ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +obj-$(CONFIG_NETCONSOLE) += netconsole.o diff -Nru a/drivers/net/a2065.c b/drivers/net/a2065.c --- a/drivers/net/a2065.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/a2065.c Sat Apr 3 19:38:44 2004 @@ -164,7 +164,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ int leptr; @@ -265,7 +265,7 @@ static int lance_rx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; volatile struct lance_rx_desc *rd; @@ -342,7 +342,7 @@ static int lance_tx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; volatile struct lance_tx_desc *td; @@ -433,7 +433,7 @@ dev = (struct net_device *) dev_id; - lp = (struct lance_private *) dev->priv; + lp = netdev_priv(dev); ll = lp->ll; ll->rap = LE_CSR0; /* LANCE Controller Status */ @@ -481,7 +481,7 @@ static int lance_open (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int ret; @@ -506,7 +506,7 @@ static int lance_close (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; netif_stop_queue(dev); @@ -522,7 +522,7 @@ static inline int lance_reset (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status; @@ -545,7 +545,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", @@ -556,7 +556,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; @@ -624,7 +624,7 @@ static struct net_device_stats *lance_get_stats (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -632,7 +632,7 @@ /* taken from the depca driver */ static void lance_load_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -668,7 +668,7 @@ static void lance_set_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; @@ -748,7 +748,7 @@ } SET_MODULE_OWNER(dev); - priv = dev->priv; + priv = netdev_priv(dev); r1->name = dev->name; r2->name = dev->name; diff -Nru a/drivers/net/ac3200.c b/drivers/net/ac3200.c --- a/drivers/net/ac3200.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/ac3200.c Sat Apr 3 19:38:45 2004 @@ -276,6 +276,9 @@ dev->open = &ac_open; dev->stop = &ac_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h --- a/drivers/net/acenic.h Sat Apr 3 19:38:43 2004 +++ b/drivers/net/acenic.h Sat Apr 3 19:38:43 2004 @@ -696,7 +696,7 @@ char name[48]; #ifdef INDEX_DEBUG spinlock_t debug_lock - __attribute__ ((aligned (SMP_CACHE_BYTES)));; + __attribute__ ((aligned (SMP_CACHE_BYTES))); u32 last_tx, last_std_rx, last_mini_rx; #endif struct net_device_stats stats; diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/amd8111e.c Sat Apr 3 19:38:44 2004 @@ -174,7 +174,7 @@ */ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); unsigned int reg_val; amd8111e_read_phy(lp,phy_id,reg_num,®_val); @@ -187,7 +187,7 @@ */ static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); amd8111e_write_phy(lp, phy_id, reg_num, val); } @@ -197,7 +197,7 @@ */ static void amd8111e_set_ext_phy(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); u32 bmcr,advert,tmp; /* Determine mii register values to set the speed */ @@ -239,7 +239,7 @@ */ static int amd8111e_free_skbs(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct sk_buff* rx_skbuff; int i; @@ -272,7 +272,7 @@ */ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); unsigned int mtu = dev->mtu; if (mtu > ETH_DATA_LEN){ @@ -290,7 +290,7 @@ */ static int amd8111e_init_ring(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int i; lp->rx_idx = lp->tx_idx = 0; @@ -371,7 +371,7 @@ unsigned int timeout; unsigned int event_count; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void* mmio = lp->mmio; struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; @@ -429,7 +429,7 @@ */ static int amd8111e_restart(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv* )dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; int i,reg_val; @@ -663,7 +663,7 @@ */ static int amd8111e_tx(struct net_device *dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; int status; /* Complete all the transmit packet */ @@ -705,7 +705,7 @@ */ static int amd8111e_rx(struct net_device *dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct sk_buff *skb,*new_skb; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; int min_pkt_len, status; @@ -809,7 +809,7 @@ */ static int amd8111e_link_change(struct net_device* dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int status0,speed; /* read the link change */ @@ -871,7 +871,7 @@ */ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; unsigned long flags; /* struct net_device_stats *prev_stats = &lp->prev_stats; */ @@ -966,7 +966,7 @@ */ static int amd8111e_calc_coalesce(struct net_device *dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; int tx_pkt_rate; int rx_pkt_rate; @@ -1102,7 +1102,7 @@ { struct net_device * dev = (struct net_device *) dev_id; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; unsigned int intr0; unsigned int handled = 1; @@ -1153,12 +1153,23 @@ return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void amd8111e_poll(struct net_device *dev) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + amd8111e_interrupt(0, dev, NULL); + local_irq_restore(flags); +} +#endif + /* This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ static int amd8111e_close(struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); spin_lock_irq(&lp->lock); @@ -1185,7 +1196,7 @@ */ static int amd8111e_open(struct net_device * dev ) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, SA_SHIRQ, dev->name, dev)) @@ -1231,7 +1242,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int tx_index; unsigned long flags; @@ -1338,7 +1349,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) { struct dev_mc_list* mc_ptr; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); u32 mc_filter[2] ; int i,bit_num; if(dev->flags & IFF_PROMISC){ @@ -1388,7 +1399,7 @@ static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct pci_dev *pci_dev = lp->pci_dev; u32 ethcmd; @@ -1510,7 +1521,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int err; u32 mii_regval; @@ -1554,7 +1565,7 @@ */ int amd8111e_change_mtu(struct net_device *dev, int new_mtu) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int err; if ((new_mtu < AMD8111E_MIN_MTU) || (new_mtu > AMD8111E_MAX_MTU)) @@ -1584,7 +1595,7 @@ #if AMD8111E_VLAN_TAG_USED static void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); lp->vlgrp = grp; spin_unlock_irq(&lp->lock); @@ -1592,7 +1603,7 @@ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); if (lp->vlgrp) lp->vlgrp->vlan_devices[vid] = NULL; @@ -1623,7 +1634,7 @@ static void amd8111e_tx_timeout(struct net_device *dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); int err; printk(KERN_ERR "%s: transmit timed out, resetting\n", @@ -1637,7 +1648,7 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; @@ -1680,7 +1691,7 @@ static int amd8111e_resume(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; @@ -1719,7 +1730,7 @@ } static void amd8111e_config_ipg(struct net_device* dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct ipg_info* ipg_data = &lp->ipg_data; void * mmio = lp->mmio; unsigned int prev_col_cnt = ipg_data->col_cnt; @@ -1841,7 +1852,7 @@ dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid; #endif - lp = dev->priv; + lp = netdev_priv(dev); lp->pci_dev = pdev; lp->amd8111e_net_dev = dev; lp->pm_cap = pm_cap; @@ -1884,6 +1895,9 @@ dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = amd8111e_poll; +#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; diff -Nru a/drivers/net/apne.c b/drivers/net/apne.c --- a/drivers/net/apne.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/apne.c Sat Apr 3 19:38:56 2004 @@ -333,6 +333,9 @@ ei_status.get_8390_hdr = &apne_get_8390_hdr; dev->open = &apne_open; dev->stop = &apne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ diff -Nru a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c --- a/drivers/net/appletalk/cops.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/appletalk/cops.c Sat Apr 3 19:38:43 2004 @@ -333,7 +333,7 @@ dev->base_addr = ioaddr; - lp = (struct cops_local *)dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(struct cops_local)); spin_lock_init(&lp->lock); @@ -422,7 +422,7 @@ */ static int cops_open(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); if(dev->irq==0) { @@ -456,7 +456,7 @@ */ static int cops_jumpstart(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); /* * Once the card has the firmware loaded and has acquired @@ -490,7 +490,7 @@ */ static void cops_reset(struct net_device *dev, int sleep) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; if(lp->board==TANGENT) @@ -525,7 +525,7 @@ { struct ifreq ifr; struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data; - struct cops_local *lp=(struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; int length, i = 0; @@ -618,7 +618,7 @@ */ static int cops_nodeid (struct net_device *dev, int nodeid) { - struct cops_local *lp = (struct cops_local *) dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if(lp->board == DAYNA) @@ -730,7 +730,7 @@ int boguscount = 0; ioaddr = dev->base_addr; - lp = (struct cops_local *)dev->priv; + lp = netdev_priv(dev); if(lp->board==DAYNA) { @@ -765,7 +765,7 @@ int pkt_len = 0; int rsp_type = 0; struct sk_buff *skb = NULL; - struct cops_local *lp = dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 0; unsigned long flags; @@ -869,7 +869,7 @@ static void cops_timeout(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->stats.tx_errors++; @@ -891,7 +891,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -966,7 +966,7 @@ static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr; struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr; @@ -1002,7 +1002,7 @@ static int cops_close(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); /* If we were running polled, yank the timer. */ @@ -1019,7 +1019,7 @@ */ static struct net_device_stats *cops_get_stats(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c --- a/drivers/net/ariadne.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/ariadne.c Sat Apr 3 19:38:45 2004 @@ -184,7 +184,7 @@ } SET_MODULE_OWNER(dev); - priv = dev->priv; + priv = netdev_priv(dev); r1->name = dev->name; r2->name = dev->name; @@ -333,7 +333,7 @@ static void ariadne_init_ring(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; int i; @@ -379,7 +379,7 @@ static int ariadne_close(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; netif_stop_queue(dev); @@ -434,7 +434,7 @@ if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ return IRQ_NONE; /* generated by the board. */ - priv = (struct ariadne_private *)dev->priv; + priv = netdev_priv(dev); boguscnt = 10; while ((csr0 = lance->RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { @@ -589,7 +589,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; int entry; unsigned long flags; @@ -697,7 +697,7 @@ static int ariadne_rx(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); int entry = priv->cur_rx % RX_RING_SIZE; int i; @@ -787,7 +787,7 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; short saved_addr; unsigned long flags; diff -Nru a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c --- a/drivers/net/arm/am79c961a.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/arm/am79c961a.c Sat Apr 3 19:38:54 2004 @@ -196,7 +196,7 @@ static void am79c961_init_for_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned char *p; u_int hdr_addr, first_free_addr; @@ -271,7 +271,7 @@ static void am79c961_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned int lnkstat, carrier; lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; @@ -291,7 +291,7 @@ static int am79c961_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int ret; memset (&priv->stats, 0, sizeof (priv->stats)); @@ -318,7 +318,7 @@ static int am79c961_close(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; del_timer_sync(&priv->timer); @@ -341,7 +341,7 @@ */ static struct net_device_stats *am79c961_getstats (struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -365,7 +365,7 @@ */ static void am79c961_setmulticastlist (struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned short multi_hash[4], mode; int i, stopped; @@ -444,7 +444,7 @@ static int am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned int hdraddr, bufaddr; unsigned int head; unsigned long flags; @@ -593,7 +593,7 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); u_int status, n = 100; int handled = 0; @@ -630,7 +630,7 @@ static int am79c961_hw_init(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); spin_lock_irq(&priv->chip_lock); write_rreg (dev->base_addr, CSR0, CSR0_STOP); @@ -662,7 +662,7 @@ if (!dev) goto out; - priv = dev->priv; + priv = netdev_priv(dev); /* * Fixed address and IRQ lines here. diff -Nru a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c --- a/drivers/net/arm/ether1.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/arm/ether1.c Sat Apr 3 19:38:44 2004 @@ -447,7 +447,7 @@ static int ether1_init_for_open (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int i, status, addr, next, next2; int failures = 0; unsigned long timeout; @@ -616,7 +616,7 @@ static int ether1_txalloc (struct net_device *dev, int size) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int start, tail; size = (size + 1) & ~1; @@ -642,7 +642,7 @@ static int ether1_open (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_WARNING "%s: invalid ethernet MAC address\n", @@ -668,7 +668,7 @@ static void ether1_timeout(struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n", dev->name); @@ -686,7 +686,7 @@ static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; unsigned long flags; tx_t tx; @@ -762,7 +762,7 @@ static void ether1_xmit_done (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); nop_t nop; int caddr, tst; @@ -863,7 +863,7 @@ static void ether1_recv_done (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int status; int nexttail, rbdaddr; rbd_t rbd; @@ -919,7 +919,7 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int status; status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); @@ -978,7 +978,7 @@ static struct net_device_stats * ether1_getstats (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -1030,7 +1030,7 @@ request_region(dev->base_addr, 16, dev->name); request_region(dev->base_addr + 0x800, 4096, dev->name); - priv = (struct ether1_priv *)dev->priv; + priv = netdev_priv(dev); if ((priv->bus_type = ether1_reset(dev)) == 0) { ret = -ENODEV; goto release; diff -Nru a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c --- a/drivers/net/arm/ether3.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/arm/ether3.c Sat Apr 3 19:38:56 2004 @@ -121,7 +121,7 @@ static int ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int timeout = 1000; ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); @@ -180,7 +180,7 @@ ether3_ledoff(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); } @@ -280,7 +280,7 @@ static int __init ether3_init_2(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int i; priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; @@ -330,7 +330,7 @@ static void ether3_init_for_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int i; memset(&priv->stats, 0, sizeof(struct net_device_stats)); @@ -434,7 +434,7 @@ static int ether3_close(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); netif_stop_queue(dev); @@ -457,7 +457,7 @@ */ static struct net_device_stats *ether3_getstats(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -469,7 +469,7 @@ */ static void ether3_setmulticastlist(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); priv->regs.config1 &= ~CFG1_RECVPROMISC; @@ -487,7 +487,7 @@ static void ether3_timeout(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; del_timer(&priv->timer); @@ -518,7 +518,7 @@ static int ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; @@ -594,7 +594,7 @@ printk("eth3irq: %d ", irq); #endif - priv = (struct dev_priv *)dev->priv; + priv = netdev_priv(dev); status = ether3_inw(REG_STATUS); @@ -844,7 +844,7 @@ goto free; } - priv = (struct dev_priv *) dev->priv; + priv = netdev_priv(dev); init_timer(&priv->timer); /* Reset card... diff -Nru a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c --- a/drivers/net/arm/etherh.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/arm/etherh.c Sat Apr 3 19:38:55 2004 @@ -144,7 +144,7 @@ static void etherh_setif(struct net_device *dev) { - struct etherh_priv *eh = (struct etherh_priv *)dev->priv; + struct etherh_priv *eh = netdev_priv(dev); struct ei_device *ei_local = &eh->eidev; unsigned long addr, flags; @@ -188,7 +188,7 @@ static int etherh_getifstat(struct net_device *dev) { - struct etherh_priv *eh = (struct etherh_priv *)dev->priv; + struct etherh_priv *eh = netdev_priv(dev); struct ei_device *ei_local = &eh->eidev; int stat = 0; @@ -256,7 +256,7 @@ static void etherh_reset(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr); @@ -283,7 +283,7 @@ static void etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; unsigned long dma_start; @@ -349,7 +349,7 @@ static void etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; unsigned char *buf; @@ -390,7 +390,7 @@ static void etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; if (ei_local->dmaing) { @@ -432,7 +432,7 @@ static int etherh_open(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_WARNING "%s: invalid ethernet MAC address\n", @@ -557,7 +557,7 @@ goto out; } - eh = dev->priv; + eh = netdev_priv(dev); spin_lock_init(&eh->eidev.page_lock); @@ -653,7 +653,7 @@ break; } - ei_local = (struct ei_device *) dev->priv; + ei_local = netdev_priv(dev); if (ec->cid.product == PROD_ANT_ETHERM) { ei_local->tx_start_page = ETHERM_TX_START_PAGE; ei_local->stop_page = ETHERM_STOP_PAGE; diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c --- a/drivers/net/at1700.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/at1700.c Sat Apr 3 19:38:43 2004 @@ -241,7 +241,7 @@ static void cleanup_card(struct net_device *dev) { #ifdef CONFIG_MCA - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->mca_slot) mca_mark_as_unused(lp->mca_slot); #endif @@ -319,8 +319,8 @@ char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; - struct net_local *lp = dev->priv; - + struct net_local *lp = netdev_priv(dev); + #ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) return -EBUSY; @@ -618,7 +618,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit @@ -649,7 +649,7 @@ static void net_tx_timeout (struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; printk ("%s: transmit timed out with status %04x, %s?\n", dev->name, @@ -683,7 +683,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; short len = skb->len; @@ -748,7 +748,7 @@ } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock (&lp->lock); @@ -808,7 +808,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 5; @@ -891,7 +891,7 @@ /* The inverse routine to net_open(). */ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -919,7 +919,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -931,7 +931,7 @@ set_rx_mode(struct net_device *dev) { int ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned char mc_filter[8]; /* Multicast hash filter */ unsigned long flags; int i; diff -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c --- a/drivers/net/atari_bionet.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/atari_bionet.c Sat Apr 3 19:38:44 2004 @@ -408,7 +408,7 @@ */ static int bionet_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (bionet_debug > 0) printk("bionet_open\n"); @@ -433,7 +433,7 @@ static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; /* Block a timer-based transmit from overlapping. This could better be @@ -499,7 +499,7 @@ */ static void bionet_poll_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount = 10; int pkt_len, status; unsigned long flags; @@ -601,7 +601,7 @@ static void bionet_tick(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 ) printk("bionet_tick: %ld\n", lp->open_time); @@ -616,7 +616,7 @@ */ static int bionet_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (bionet_debug > 0) printk("bionet_close, open_time=%ld\n", lp->open_time); @@ -638,7 +638,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c --- a/drivers/net/atari_pamsnet.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/atari_pamsnet.c Sat Apr 3 19:38:42 2004 @@ -667,7 +667,7 @@ */ static int pamsnet_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (pamsnet_debug > 0) printk("pamsnet_open\n"); @@ -696,7 +696,7 @@ static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; /* Block a timer-based transmit from overlapping. This could better be @@ -742,7 +742,7 @@ */ static void pamsnet_poll_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount; int pkt_len; struct sk_buff *skb; @@ -817,7 +817,7 @@ static void pamsnet_tick(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 ) printk("pamsnet_tick: %ld\n", lp->open_time); @@ -832,7 +832,7 @@ */ static int pamsnet_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (pamsnet_debug > 0) printk("pamsnet_close, open_time=%ld\n", lp->open_time); @@ -859,7 +859,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/atp.c b/drivers/net/atp.c --- a/drivers/net/atp.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/atp.c Sat Apr 3 19:38:56 2004 @@ -335,7 +335,7 @@ /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); lp->chip_type = RTL8002; lp->addr_mode = CMR2h_Normal; spin_lock_init(&lp->lock); @@ -432,7 +432,7 @@ */ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ret; /* The interrupt line is turned off (tri-stated) when the device isn't in @@ -458,7 +458,7 @@ the hardware may have been temporarily detached. */ static void hardware_init(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; @@ -541,7 +541,7 @@ static void tx_timeout(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name, @@ -557,7 +557,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; int length; unsigned long flags; @@ -611,7 +611,7 @@ return IRQ_NONE; } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -726,7 +726,7 @@ { struct net_device *dev = (struct net_device *)data; long ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int tickssofar = jiffies - lp->last_rx_time; int i; @@ -740,7 +740,7 @@ for (i = 0; i < 6; i++) if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i]) { - struct net_local *lp = (struct net_local *)atp_timed_dev->priv; + struct net_local *lp = netdev_priv(atp_timed_dev); write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); if (i == 2) lp->stats.tx_errors++; @@ -762,7 +762,7 @@ /* 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 net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; struct rx_header rx_head; @@ -838,7 +838,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -863,7 +863,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -873,7 +873,7 @@ static void set_rx_mode_8002(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) { @@ -890,7 +890,7 @@ static void set_rx_mode_8012(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */ int i; diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c --- a/drivers/net/b44.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/b44.c Sat Apr 3 19:38:43 2004 @@ -667,6 +667,10 @@ dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; src_map->skb = NULL; + + pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, + RX_PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); } static int b44_rx(struct b44 *bp, int budget) @@ -686,9 +690,9 @@ struct rx_header *rh; u16 len; - pci_dma_sync_single(bp->pdev, map, - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(bp->pdev, map, + RX_PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); rh = (struct rx_header *) skb->data; len = cpu_to_le16(rh->len); if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || @@ -1887,6 +1891,8 @@ if (!netif_running(dev)) return 0; + + pci_restore_state(pdev, bp->pci_cfg_state); spin_lock_irq(&bp->lock); diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c --- a/drivers/net/bagetlance.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/bagetlance.c Sat Apr 3 19:38:40 2004 @@ -594,7 +594,7 @@ return( 0 ); probe_ok: - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ @@ -736,7 +736,7 @@ static int lance_open( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int i; @@ -778,7 +778,7 @@ static void lance_init_ring( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); int i; unsigned offset; @@ -834,7 +834,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int entry, len; struct lance_tx_head *head; @@ -988,7 +988,7 @@ return IRQ_NONE; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); IO = lp->iobase; AREG = CSR0; @@ -1101,7 +1101,7 @@ static int lance_rx( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1225,7 +1225,7 @@ static int lance_close( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; dev->start = 0; @@ -1247,7 +1247,7 @@ static struct net_device_stats *lance_get_stats( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1261,7 +1261,7 @@ static void set_multicast_list( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; if (!dev->start) @@ -1303,7 +1303,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct sockaddr *saddr = addr; int i; diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c --- a/drivers/net/bmac.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/bmac.c Sat Apr 3 19:38:41 2004 @@ -226,7 +226,7 @@ static void bmac_enable_and_reset_chip(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; @@ -310,7 +310,7 @@ static void bmac_init_registers(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile unsigned short regValue; unsigned short *pWord16; int i; @@ -405,7 +405,7 @@ static void bmac_start_chip(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; unsigned short oldConfig; @@ -425,7 +425,7 @@ bmac_init_phy(struct net_device *dev) { unsigned int addr; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); printk(KERN_DEBUG "phy registers:"); for (addr = 0; addr < 32; ++addr) { @@ -458,7 +458,7 @@ static int bmac_suspend(struct macio_dev *mdev, u32 state) { struct net_device* dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; unsigned short config; int i; @@ -508,7 +508,7 @@ static int bmac_resume(struct macio_dev *mdev) { struct net_device* dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); /* see if this is enough */ if (bp->opened) @@ -525,7 +525,7 @@ static int bmac_set_address(struct net_device *dev, void *addr) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned char *p = addr; unsigned short *pWord16; unsigned long flags; @@ -550,7 +550,7 @@ static inline void bmac_set_timeout(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&bp->lock, flags); @@ -656,7 +656,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *td = bp->tx_dma; int i; @@ -692,7 +692,7 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; int i, nb, stat; @@ -769,7 +769,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_cmd *cp; int stat; unsigned long flags; @@ -822,7 +822,7 @@ static struct net_device_stats *bmac_stats(struct net_device *dev) { - struct bmac_data *p = (struct bmac_data *) dev->priv; + struct bmac_data *p = netdev_priv(dev); return &p->stats; } @@ -995,7 +995,7 @@ static void bmac_set_multicast(struct net_device *dev) { struct dev_mc_list *dmi; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); int num_addrs = dev->mc_count; unsigned short rx_cfg; int i; @@ -1086,7 +1086,7 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *)dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned int status = bmread(dev, STATUS); if (miscintcount++ < 10) { XXDEBUG(("bmac_misc_intr\n")); @@ -1232,7 +1232,7 @@ static void bmac_reset_and_enable(struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; struct sk_buff *skb; unsigned char *data; @@ -1288,7 +1288,7 @@ return -ENOMEM; } - bp = (struct bmac_data *) dev->priv; + bp = netdev_priv(dev); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); @@ -1312,10 +1312,8 @@ bmwrite(dev, INTDISABLE, DisableAll); rev = addr[0] == 0 && addr[1] == 0xA0; - for (j = 0; j < 6; ++j) { + for (j = 0; j < 6; ++j) dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; - printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); - } /* Enable chip without interrupts for now */ bmac_enable_and_reset_chip(dev); @@ -1380,6 +1378,8 @@ } printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); + for (j = 0; j < 6; ++j) + printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); @@ -1408,7 +1408,7 @@ static int bmac_open(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ bp->opened = 1; @@ -1420,7 +1420,7 @@ static int bmac_close(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; unsigned short config; @@ -1469,7 +1469,7 @@ static void bmac_start(struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); int i; struct sk_buff *skb; unsigned long flags; @@ -1495,7 +1495,7 @@ static int bmac_output(struct sk_buff *skb, struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); skb_queue_tail(bp->queue, skb); bmac_start(dev); return 0; @@ -1504,7 +1504,7 @@ static void bmac_tx_timeout(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *td = bp->tx_dma; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; @@ -1630,7 +1630,7 @@ static int __devexit bmac_remove(struct macio_dev *mdev) { struct net_device *dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unregister_netdev(dev); diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c --- a/drivers/net/cs89x0.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/cs89x0.c Sat Apr 3 19:38:55 2004 @@ -399,7 +399,7 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); static unsigned version_printed; int i; unsigned rev_type = 0; @@ -735,7 +735,7 @@ static void get_dma_channel(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->dma) { dev->dma = lp->dma; @@ -757,7 +757,7 @@ static void write_dma(struct net_device *dev, int chip_type, int dma) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if ((lp->isa_config & ANY_ISA_DMA) == 0) return; if (chip_type == CS8900) { @@ -770,7 +770,7 @@ static void set_dma_cfg(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) { if ((lp->isa_config & ANY_ISA_DMA) == 0) { @@ -793,7 +793,7 @@ static int dma_bufcfg(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0; else @@ -804,7 +804,7 @@ dma_busctl(struct net_device *dev) { int retval = 0; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) { if (lp->isa_config & ANY_ISA_DMA) retval |= RESET_RX_DMA; /* Reset the DMA pointer */ @@ -820,7 +820,7 @@ static void dma_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; unsigned char *bp = lp->rx_dma_ptr; @@ -882,7 +882,7 @@ void __init reset_chip(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int reset_start_time; @@ -912,7 +912,7 @@ static void control_dc_dc(struct net_device *dev, int on_not_off) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned int selfcontrol; int timenow = jiffies; /* control the DC to DC convertor in the SelfControl register. @@ -940,7 +940,7 @@ static int detect_tp(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int timenow = jiffies; int fdx; @@ -1055,7 +1055,7 @@ static int detect_aui(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name); control_dc_dc(dev, 0); @@ -1071,7 +1071,7 @@ static int detect_bnc(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name); control_dc_dc(dev, 1); @@ -1117,7 +1117,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int result = 0; int i; int ret; @@ -1358,7 +1358,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 3) { printk("%s: sent %d byte packet of type %x\n", @@ -1419,7 +1419,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* 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 @@ -1517,7 +1517,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; @@ -1573,7 +1573,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -1600,7 +1600,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1614,7 +1614,7 @@ static void set_multicast_list(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1758,7 +1758,7 @@ dev->irq = irq; dev->base_addr = io; - lp = dev->priv; + lp = netdev_priv(dev); #if ALLOW_DMA if (use_dma) { diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c --- a/drivers/net/declance.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/declance.c Sat Apr 3 19:38:44 2004 @@ -433,7 +433,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; int leptr; int i; @@ -530,7 +530,7 @@ static int lance_rx(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_rx_desc *rd = 0; unsigned char bits; @@ -617,7 +617,7 @@ static void lance_tx(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_regs *ll = lp->ll; volatile struct lance_tx_desc *td; @@ -709,7 +709,7 @@ lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int csr0; @@ -757,7 +757,7 @@ static int lance_open(struct net_device *dev) { volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status = 0; @@ -822,7 +822,7 @@ static int lance_close(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; netif_stop_queue(dev); @@ -856,7 +856,7 @@ static inline int lance_reset(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status; @@ -873,7 +873,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", @@ -884,7 +884,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); int entry, skblen, len; @@ -936,7 +936,7 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -982,7 +982,7 @@ static void lance_set_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_regs *ll = lp->ll; @@ -1048,7 +1048,7 @@ * alloc_etherdev ensures the data structures used by the LANCE * are aligned. */ - lp = (struct lance_private *) dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); lp->type = type; @@ -1287,7 +1287,7 @@ { while (root_lance_dev) { struct net_device *dev = root_lance_dev; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); unregister_netdev(dev); #ifdef CONFIG_TC if (lp->slot >= 0) diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c --- a/drivers/net/dl2k.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/dl2k.c Sat Apr 3 19:38:43 2004 @@ -874,8 +874,6 @@ frame_status = le64_to_cpu (desc->status); if (--cnt < 0) break; - pci_dma_sync_single (np->pdev, desc->fraginfo, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); /* Update rx error statistics, drop packet. */ if (frame_status & RFS_Errors) { np->stats.rx_errors++; @@ -898,6 +896,10 @@ skb_put (skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { + pci_dma_sync_single_for_cpu(np->pdev, + desc->fraginfo, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb->dev = dev; /* 16 byte align the IP header */ skb_reserve (skb, 2); @@ -905,6 +907,10 @@ np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put (skb, pkt_len); + pci_dma_sync_single_for_device(np->pdev, + desc->fraginfo, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans (skb, dev); #if 0 diff -Nru a/drivers/net/e100.c b/drivers/net/e100.c --- a/drivers/net/e100.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/e100.c Sat Apr 3 19:38:56 2004 @@ -158,7 +158,7 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.16" +#define DRV_VERSION "3.0.17" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -1285,6 +1285,7 @@ le16_to_cpu(cb->u.tcb.tbd.size), PCI_DMA_TODEVICE); dev_kfree_skb_any(cb->skb); + cb->skb = NULL; tx_cleaned = 1; } cb->status = 0; @@ -1347,6 +1348,7 @@ cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); cb->link = cpu_to_le32(nic->cbs_dma_addr + ((i+1) % count) * sizeof(struct cb)); + cb->skb = NULL; } nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; @@ -1387,8 +1389,8 @@ (u32 *)&prev_rfd->link); wmb(); prev_rfd->command &= ~cpu_to_le16(cb_el); - pci_dma_sync_single(nic->pdev, rx->prev->dma_addr, - sizeof(struct rfd), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); } return 0; @@ -1405,8 +1407,8 @@ return -EAGAIN; /* Need to sync before taking a peek at cb_complete bit */ - pci_dma_sync_single(nic->pdev, rx->dma_addr, - sizeof(struct rfd), PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); rfd_status = le16_to_cpu(rfd->status); DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); @@ -1421,11 +1423,8 @@ actual_size = RFD_BUF_LEN - sizeof(struct rfd); /* Get data */ - pci_dma_sync_single(nic->pdev, rx->dma_addr, - sizeof(struct rfd) + actual_size, - PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, rx->dma_addr, - RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/e1000/e1000_ethtool.c Sat Apr 3 19:38:43 2004 @@ -1191,16 +1191,16 @@ for(i = 0; i < 64; i++) { e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, - txdr->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); } E1000_WRITE_REG(&adapter->hw, TDT, i); msec_delay(200); - pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, - rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[0].dma, + rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); } diff -Nru a/drivers/net/e2100.c b/drivers/net/e2100.c --- a/drivers/net/e2100.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/e2100.c Sat Apr 3 19:38:55 2004 @@ -269,6 +269,9 @@ ei_status.get_8390_hdr = &e21_get_8390_hdr; dev->open = &e21_open; dev->stop = &e21_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c --- a/drivers/net/eepro.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/eepro.c Sat Apr 3 19:38:54 2004 @@ -662,7 +662,7 @@ { struct eepro_local * lp; - lp = dev->priv; + lp = netdev_priv(dev); lp->xmt_ram = RAM_SIZE - lp->rcv_ram; if (lp->eepro == LAN595FX_10ISA) { @@ -680,9 +680,9 @@ } /* prints boot-time info */ -static void eepro_print_info (struct net_device *dev) +static void __init eepro_print_info (struct net_device *dev) { - struct eepro_local * lp = dev->priv; + struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; @@ -769,7 +769,7 @@ if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40)) goto exit; - lp = (struct eepro_local *)dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(struct eepro_local)); lp->xmt_bar = XMT_BAR_PRO; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; @@ -932,7 +932,7 @@ unsigned short temp_reg, old8, old9; int irqMask; int i, ioaddr = dev->base_addr; - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name); @@ -1106,7 +1106,7 @@ static void eepro_tx_timeout (struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *) dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* if (net_debug > 1) */ @@ -1122,7 +1122,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); unsigned long flags; int ioaddr = dev->base_addr; short length = skb->len; @@ -1187,7 +1187,7 @@ return IRQ_NONE; } - lp = (struct eepro_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -1235,7 +1235,7 @@ static int eepro_close(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short temp_reg; @@ -1280,7 +1280,7 @@ static struct net_device_stats * eepro_get_stats(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); return &lp->stats; } @@ -1290,7 +1290,7 @@ static void set_multicast_list(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; @@ -1424,7 +1424,7 @@ { int i; unsigned short retval = 0; - struct eepro_local *lp = dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ee_addr = ioaddr + lp->eeprom_reg; int read_cmd = location | EE_READ_CMD; short ctrl_val = EECS ; @@ -1468,7 +1468,7 @@ static int hardware_send_packet(struct net_device *dev, void *buf, short length) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned status, tx_available, last, end; @@ -1553,7 +1553,7 @@ static void eepro_rx(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 20; short rcv_car = lp->rx_start; @@ -1651,7 +1651,7 @@ static void eepro_transmit_interrupt(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 25; short xmt_status; diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/eepro100.c Sat Apr 3 19:38:45 2004 @@ -113,6 +113,7 @@ #include #include #include +#include #include #include @@ -654,6 +655,23 @@ return -ENODEV; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_speedo (struct net_device *dev) +{ + /* disable_irq is not very nice, but with the funny lockless design + we have no other choice. */ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit speedo_found1(struct pci_dev *pdev, long ioaddr, int card_idx, int acpi_idle_state) { @@ -839,7 +857,7 @@ dev->irq = pdev->irq; - sp = dev->priv; + sp = netdev_priv(dev); sp->pdev = pdev; sp->msg_enable = DEBUG; sp->acpi_pwr = acpi_idle_state; @@ -885,6 +903,9 @@ dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_speedo; +#endif if (register_netdevice(dev)) goto err_free_unlock; @@ -995,7 +1016,7 @@ static int speedo_open(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int retval; @@ -1082,7 +1103,7 @@ /* Start the chip hardware after a full reset. */ static void speedo_resume(struct net_device *dev) { - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ @@ -1162,7 +1183,7 @@ static void speedo_rx_soft_reset(struct net_device *dev) { - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rfd; long ioaddr; @@ -1194,7 +1215,7 @@ static void speedo_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int phy_num = sp->phy[0] & 0x1f; @@ -1239,7 +1260,7 @@ static void speedo_show_state(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int i; if (netif_msg_pktdata(sp)) { @@ -1282,7 +1303,7 @@ static void speedo_init_rx_ring(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rxf, *last_rxf = NULL; dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */; int i; @@ -1306,8 +1327,8 @@ skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); - pci_dma_sync_single(sp->pdev, last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma, + sizeof(struct RxFD), PCI_DMA_TODEVICE); } last_rxf = rxf; last_rxf_dma = sp->rx_ring_dma[i]; @@ -1316,21 +1337,21 @@ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i], + sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], + sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; sp->last_rxf_dma = last_rxf_dma; } static void speedo_purge_tx(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry; while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { @@ -1362,7 +1383,7 @@ static void reset_mii(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { @@ -1385,7 +1406,7 @@ static void speedo_tx_timeout(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int status = inw(ioaddr + SCBStatus); unsigned long flags; @@ -1447,7 +1468,7 @@ static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int entry; @@ -1518,7 +1539,7 @@ static void speedo_tx_buffer_gc(struct net_device *dev) { unsigned int dirty_tx; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); dirty_tx = sp->dirty_tx; while ((int)(sp->cur_tx - dirty_tx) > 0) { @@ -1585,7 +1606,7 @@ unsigned int handled = 0; ioaddr = dev->base_addr; - sp = (struct speedo_private *)dev->priv; + sp = netdev_priv(dev); #ifndef final_version /* A lock to prevent simultaneous entry on SMP machines. */ @@ -1677,7 +1698,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rxf; struct sk_buff *skb; /* Get a fresh skbuff to replace the consumed one. */ @@ -1696,29 +1717,29 @@ skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } static inline void speedo_rx_link(struct net_device *dev, int entry, struct RxFD *rxf, dma_addr_t rxf_dma) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ rxf->link = 0; /* None yet. */ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); - pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma, + sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry; struct RxFD *rxf; @@ -1760,7 +1781,7 @@ static void speedo_refill_rx_buffers(struct net_device *dev, int force) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); /* Refill the RX ring. */ while ((int)(sp->cur_rx - sp->dirty_rx) > 0 && @@ -1770,7 +1791,7 @@ static int speedo_rx(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry = sp->cur_rx % RX_RING_SIZE; int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; int alloc_ok = 1; @@ -1783,8 +1804,8 @@ int status; int pkt_len; - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); status = le32_to_cpu(sp->rx_ringp[entry]->status); pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; @@ -1830,8 +1851,9 @@ skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD) + pkt_len, + PCI_DMA_FROMDEVICE); #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ @@ -1841,6 +1863,9 @@ memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD) + pkt_len, + PCI_DMA_FROMDEVICE); npkts++; } else { /* Pass up the already-filled skbuff. */ @@ -1855,7 +1880,8 @@ npkts++; sp->rx_ringp[entry] = NULL; pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + PKT_BUF_SZ + sizeof(struct RxFD), + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1884,7 +1910,7 @@ speedo_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int i; netdevice_stop(dev); @@ -1962,7 +1988,7 @@ static struct net_device_stats * speedo_get_stats(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Update only if the previous dump finished. */ @@ -1995,7 +2021,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { u32 ethcmd; - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; @@ -2070,7 +2096,7 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; int saved_acpi; @@ -2121,7 +2147,7 @@ */ static void set_rx_mode(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; struct descriptor *last_cmd; char new_rx_mode; @@ -2287,8 +2313,8 @@ mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, - mc_blk->len, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma, + mc_blk->len, PCI_DMA_TODEVICE); wait_for_cmd_done(dev); clear_suspend(last_cmd); @@ -2313,7 +2339,7 @@ static int eepro100_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; pci_save_state(pdev, sp->pm_state); @@ -2333,7 +2359,7 @@ static int eepro100_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; pci_restore_state(pdev, sp->pm_state); @@ -2363,7 +2389,7 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); unregister_netdev(dev); diff -Nru a/drivers/net/eexpress.c b/drivers/net/eexpress.c --- a/drivers/net/eexpress.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/eexpress.c Sat Apr 3 19:38:40 2004 @@ -452,7 +452,7 @@ { int ret; unsigned short ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_open()\n", dev->name); @@ -515,7 +515,7 @@ static int eexp_close(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); int irq = dev->irq; @@ -541,7 +541,7 @@ static struct net_device_stats *eexp_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -553,7 +553,7 @@ static void unstick_cu(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if (lp->started) @@ -627,7 +627,7 @@ static void eexp_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_SMP unsigned long flags; #endif @@ -667,7 +667,7 @@ */ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short length = buf->len; #ifdef CONFIG_SMP unsigned long flags; @@ -728,7 +728,7 @@ unsigned short status) { unsigned short ack_cmd = SCB_ack(status); - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) { short diag_status, tdr_status; @@ -806,7 +806,7 @@ return IRQ_NONE; } - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock(&lp->lock); @@ -925,7 +925,7 @@ static void eexp_hw_rx_pio(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short rx_block = lp->rx_ptr; unsigned short boguscount = lp->num_rx_bufs; unsigned short ioaddr = dev->base_addr; @@ -1022,7 +1022,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, unsigned short len) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if (LOCKUP16 || lp->width) { @@ -1090,7 +1090,7 @@ unsigned int memory_size; int i; unsigned short xsum = 0; - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); @@ -1262,7 +1262,7 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short tx_block = lp->tx_reap; unsigned short status; @@ -1332,7 +1332,7 @@ static void eexp_hw_txrestart(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; lp->last_tx_restart = lp->tx_link; @@ -1377,7 +1377,7 @@ static void eexp_hw_txinit(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short tx_block = TX_BUF_START; unsigned short curtbuf; unsigned short ioaddr = dev->base_addr; @@ -1419,7 +1419,7 @@ static void eexp_hw_rxinit(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short rx_block = lp->rx_buf_start; unsigned short ioaddr = dev->base_addr; @@ -1478,7 +1478,7 @@ static void eexp_hw_init586(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; int i; @@ -1639,7 +1639,7 @@ eexp_set_multicast(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int kick = 0, i; if ((dev->flags & IFF_PROMISC) != lp->was_promisc) { outw(CONF_PROMISC & ~31, ioaddr+SM_PTR); diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/epic100.c Sat Apr 3 19:38:43 2004 @@ -1199,8 +1199,6 @@ short pkt_len = (status >> 16) - 4; struct sk_buff *skb; - pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pkt_len > PKT_BUF_SZ - 4) { printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " "%d bytes.\n", @@ -1213,6 +1211,10 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(ep->pci_dev, + ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, + PCI_DMA_FROMDEVICE); #if 1 /* HAS_IP_COPYSUM */ eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); @@ -1220,6 +1222,10 @@ memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(ep->pci_dev, + ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, diff -Nru a/drivers/net/es3210.c b/drivers/net/es3210.c --- a/drivers/net/es3210.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/es3210.c Sat Apr 3 19:38:55 2004 @@ -298,6 +298,9 @@ dev->open = &es_open; dev->stop = &es_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: diff -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c --- a/drivers/net/eth16i.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/eth16i.c Sat Apr 3 19:38:55 2004 @@ -486,7 +486,7 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { - struct eth16i_local *lp = dev->priv; + struct eth16i_local *lp = netdev_priv(dev); static unsigned version_printed; int retval; @@ -950,7 +950,7 @@ static int eth16i_open(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Powerup the chip */ @@ -986,7 +986,7 @@ static int eth16i_close(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; eth16i_reset(dev); @@ -1012,7 +1012,7 @@ static void eth16i_timeout(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* If we get here, some higher level has decided that @@ -1053,7 +1053,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int status = 0; ushort length = skb->len; @@ -1130,7 +1130,7 @@ static void eth16i_rx(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = MAX_RX_LOOP; @@ -1232,7 +1232,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct eth16i_local *)dev->priv; + lp = netdev_priv(dev); /* Turn off all interrupts from adapter */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); @@ -1340,7 +1340,7 @@ static void eth16i_reset(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if(eth16i_debug > 1) @@ -1372,7 +1372,7 @@ static struct net_device_stats *eth16i_get_stats(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c --- a/drivers/net/ethertap.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/ethertap.c Sat Apr 3 19:38:42 2004 @@ -121,7 +121,7 @@ static int ethertap_open(struct net_device *dev) { - struct net_local *lp = (struct net_local*)dev->priv; + struct net_local *lp = netdev_priv(dev); if (ethertap_debug > 2) printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name); @@ -150,7 +150,7 @@ static void set_multicast_list(struct net_device *dev) { unsigned groups = ~0; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) { struct dev_mc_list *dmi; @@ -176,7 +176,7 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_ETHERTAP_MC struct ethhdr *eth = (struct ethhdr*)skb->data; #endif @@ -234,7 +234,7 @@ static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_ETHERTAP_MC struct ethhdr *eth = (struct ethhdr*)(skb->data + 2); #endif @@ -320,7 +320,7 @@ static int ethertap_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sock *sk = lp->nl; if (ethertap_debug > 2) @@ -338,7 +338,7 @@ static struct net_device_stats *ethertap_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/fc/iph5526.c Sat Apr 3 19:38:42 2004 @@ -238,7 +238,7 @@ static int __init iph5526_probe_pci(struct net_device *dev) { - struct fc_info *fi = (struct fc_info *)dev->priv; + struct fc_info *fi = dev->priv; fi->dev = dev; dev->base_addr = fi->base_addr; dev->irq = fi->irq; @@ -2908,7 +2908,7 @@ static void iph5526_timeout(struct net_device *dev) { - struct fc_info *fi = (struct fc_info*)dev->priv; + struct fc_info *fi = dev->priv; printk(KERN_WARNING "%s: timed out on send.\n", dev->name); fi->fc_stats.rx_dropped++; dev->trans_start = jiffies; @@ -2917,7 +2917,7 @@ static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct fc_info *fi = (struct fc_info*)dev->priv; + struct fc_info *fi = dev->priv; int status = 0; short type = 0; u_long flags; @@ -3688,7 +3688,7 @@ static struct net_device_stats * iph5526_get_stats(struct net_device *dev) { -struct fc_info *fi = (struct fc_info*)dev->priv; +struct fc_info *fi = dev->priv; return (struct net_device_stats *) &fi->fc_stats; } diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/fealnx.c Sat Apr 3 19:38:54 2004 @@ -1303,14 +1303,15 @@ /* for the last tx descriptor */ np->tx_ring[i - 1].next_desc = np->tx_ring_dma; np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0]; - - return; } static int start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&np->lock, flags); np->cur_tx_copy->skbuff = skb; @@ -1377,6 +1378,7 @@ writel(0, dev->base_addr + TXPDR); dev->trans_start = jiffies; + spin_unlock_irqrestore(&np->lock, flags); return 0; } @@ -1423,6 +1425,8 @@ unsigned int num_tx = 0; int handled = 0; + spin_lock(&np->lock); + writel(0, dev->base_addr + IMR); ioaddr = dev->base_addr; @@ -1565,6 +1569,8 @@ writel(np->imrvalue, ioaddr + IMR); + spin_unlock(&np->lock); + return IRQ_RETVAL(handled); } @@ -1647,10 +1653,6 @@ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" " status %x.\n", pkt_len, rx_status); #endif - pci_dma_sync_single(np->pci_dev, np->cur_rx->buffer, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - pci_unmap_single(np->pci_dev, np->cur_rx->buffer, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1658,6 +1660,10 @@ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if ! defined(__alpha__) @@ -1668,7 +1674,15 @@ memcpy(skb_put(skb, pkt_len), np->cur_rx->skbuff->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { + pci_unmap_single(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_put(skb = np->cur_rx->skbuff, pkt_len); np->cur_rx->skbuff = NULL; if (np->really_rx_count == RX_RING_SIZE) @@ -1689,8 +1703,10 @@ if (skb != NULL) { skb->dev = dev; /* Mark as being used by this device. */ - np->cur_rx->buffer = pci_map_single(np->pci_dev, skb->tail, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); + np->cur_rx->buffer = pci_map_single(np->pci_dev, + skb->tail, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); np->cur_rx->skbuff = skb; ++np->really_rx_count; } diff -Nru a/drivers/net/fec.c b/drivers/net/fec.c --- a/drivers/net/fec.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/fec.c Sat Apr 3 19:38:41 2004 @@ -269,7 +269,7 @@ volatile fec_t *fecp; volatile cbd_t *bdp; - fep = dev->priv; + fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; if (!fep->link) { @@ -349,7 +349,7 @@ static void fec_timeout(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); printk("%s: transmit timed out.\n", dev->name); fep->stats.tx_errors++; @@ -445,7 +445,7 @@ volatile cbd_t *bdp; struct sk_buff *skb; - fep = dev->priv; + fep = netdev_priv(dev); spin_lock(&fep->lock); bdp = fep->dirty_tx; @@ -524,7 +524,7 @@ ushort pkt_len; __u8 *data; - fep = dev->priv; + fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; /* First, grab all of the stats for the incoming packet. @@ -645,7 +645,7 @@ mii_list_t *mip; uint mii_reg; - fep = (struct fec_enet_private *)dev->priv; + fep = netdev_priv(dev); ep = fec_hwp; mii_reg = ep->fec_mii_data; @@ -675,7 +675,7 @@ /* Add PHY address to register command. */ - fep = dev->priv; + fep = netdev_priv(dev); regval |= fep->phy_addr << 23; retval = 0; @@ -720,7 +720,7 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); @@ -735,7 +735,7 @@ static void mii_parse_cr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); @@ -748,7 +748,7 @@ static void mii_parse_anar(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_CONF_SPMASK); @@ -774,7 +774,7 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK); @@ -841,7 +841,7 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); @@ -919,7 +919,7 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK); @@ -983,7 +983,7 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); @@ -1280,7 +1280,7 @@ static void mii_display_status(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); if (!fep->link && !fep->old_link) { @@ -1316,7 +1316,7 @@ static void mii_display_config(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); printk("%s: config: auto-negotiation ", dev->name); @@ -1347,7 +1347,7 @@ static void mii_relink(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); int duplex; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; @@ -1372,7 +1372,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); INIT_WORK(&fep->phy_task, (void*)mii_relink, dev); schedule_work(&fep->phy_task); @@ -1380,7 +1380,7 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev); schedule_work(&fep->phy_task); @@ -1403,7 +1403,7 @@ struct fec_enet_private *fep; int i; - fep = dev->priv; + fep = netdev_priv(dev); fep->phy_id |= (mii_reg & 0xffff); printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); @@ -1431,7 +1431,7 @@ volatile fec_t *fecp; uint phytype; - fep = dev->priv; + fep = netdev_priv(dev); fecp = fec_hwp; if (fep->phy_addr < 32) { @@ -1466,7 +1466,7 @@ #endif { struct net_device *dev = dev_id; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); fec_phy_ack_intr(); @@ -1482,7 +1482,7 @@ static int fec_enet_open(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. @@ -1531,7 +1531,7 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) { - struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); return &fep->stats; } @@ -1557,7 +1557,7 @@ unsigned int i, j, bit, data, crc; unsigned char hash; - fep = (struct fec_enet_private *)dev->priv; + fep = netdev_priv(dev); ep = fec_hwp; if (dev->flags&IFF_PROMISC) { @@ -1643,7 +1643,7 @@ */ int __init fec_enet_init(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); unsigned long mem_addr; volatile cbd_t *bdp; cbd_t *cbd_base; @@ -1807,7 +1807,7 @@ fecp = fec_hwp; - fep = dev->priv; + fep = netdev_priv(dev); /* Whack a reset. We should wait for this. */ @@ -1924,7 +1924,7 @@ struct fec_enet_private *fep; fecp = fec_hwp; - fep = dev->priv; + fep = netdev_priv(dev); fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ diff -Nru a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c --- a/drivers/net/forcedeth.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/forcedeth.c Sat Apr 3 19:38:41 2004 @@ -11,6 +11,7 @@ * countries. * * Copyright (C) 2003 Manfred Spraul + * Copyright (C) 2004 Andrew de Quincey (wol support) * * 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 @@ -28,7 +29,7 @@ * * Changelog: * 0.01: 05 Oct 2003: First release that compiles without warnings. - * 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs. + * 0.02: 05 Oct 2003: Fix bug for nv_drain_tx: do not try to free NULL skbs. * Check all PCI BARs for the register window. * udelay added to mii_rw. * 0.03: 06 Oct 2003: Initialize dev->irq. @@ -37,7 +38,7 @@ * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, * irq mask updated * 0.07: 14 Oct 2003: Further irq mask updates. - * 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill + * 0.08: 20 Oct 2003: rx_desc.Length initialization added, nv_alloc_rx refill * added into irq handler, NULL check for drain_ring. * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the * requested interrupt sources. @@ -47,7 +48,7 @@ * 0.12: 23 Oct 2003: Cleanups for release. * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. * Set link speed correctly. start rx before starting - * tx (start_rx sets the link speed). + * tx (nv_start_rx sets the link speed). * 0.14: 25 Oct 2003: Nic dependant irq mask. * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during * open. @@ -58,7 +59,7 @@ * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac * addresses, really stop rx if already running - * in start_rx, clean up a bit. + * in nv_start_rx, clean up a bit. * (C) Carl-Daniel Hailfinger * 0.20: 07 Dec 2003: alloc fixes * 0.21: 12 Jan 2004: additional alloc fix, nic polling fix. @@ -66,6 +67,8 @@ * on close. * (C) Carl-Daniel Hailfinger, Manfred Spraul * 0.23: 26 Jan 2004: various small cleanups + * 0.24: 27 Feb 2004: make driver even less anonymous in backtraces + * 0.25: 09 Mar 2004: wol support * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -77,7 +80,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.23" +#define FORCEDETH_VERSION "0.25" #include #include @@ -232,6 +235,7 @@ #define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 #define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 +#define NVREG_WAKEUPFLAGS_ENABLE 0x1111 NvRegPatternCRC = 0x204, NvRegPatternMask = 0x208, @@ -340,6 +344,7 @@ u32 linkspeed; int duplex; int phyaddr; + int wolenabled; /* General data: RO fields */ dma_addr_t ring_addr; @@ -468,12 +473,12 @@ return retval; } -static void start_rx(struct net_device *dev) +static void nv_start_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: start_rx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); /* Already running? Stop it. */ if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { writel(0, base + NvRegReceiverControl); @@ -485,48 +490,48 @@ pci_push(base); } -static void stop_rx(struct net_device *dev) +static void nv_stop_rx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); writel(0, base + NvRegReceiverControl); reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, - KERN_INFO "stop_rx: ReceiverStatus remained busy"); + KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); udelay(NV_RXSTOP_DELAY2); writel(0, base + NvRegLinkSpeed); } -static void start_tx(struct net_device *dev) +static void nv_start_tx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: start_tx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name); writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); pci_push(base); } -static void stop_tx(struct net_device *dev) +static void nv_stop_tx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); writel(0, base + NvRegTransmitterControl); reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, - KERN_INFO "stop_tx: TransmitterStatus remained busy"); + KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); udelay(NV_TXSTOP_DELAY2); writel(0, base + NvRegUnknownTransmitterReg); } -static void txrx_reset(struct net_device *dev) +static void nv_txrx_reset(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); @@ -551,9 +556,10 @@ return &np->stats; } -static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr) +static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) @@ -580,6 +586,39 @@ return -EFAULT; return 0; } + case ETHTOOL_GWOL: + { + struct ethtool_wolinfo wolinfo; + memset(&wolinfo, 0, sizeof(wolinfo)); + wolinfo.supported = WAKE_MAGIC; + + spin_lock_irq(&np->lock); + if (np->wolenabled) + wolinfo.wolopts = WAKE_MAGIC; + spin_unlock_irq(&np->lock); + + if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: + { + struct ethtool_wolinfo wolinfo; + if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo))) + return -EFAULT; + + spin_lock_irq(&np->lock); + if (wolinfo.wolopts == 0) { + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; + } + if (wolinfo.wolopts & WAKE_MAGIC) { + writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags); + np->wolenabled = 1; + } + spin_unlock_irq(&np->lock); + return 0; + } default: break; @@ -603,11 +642,11 @@ } /* - * alloc_rx: fill rx ring entries. + * nv_alloc_rx: fill rx ring entries. * Return 1 if the allocations for the skbs failed and the * rx engine is without Available descriptors */ -static int alloc_rx(struct net_device *dev) +static int nv_alloc_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); unsigned int refill_rx = np->refill_rx; @@ -633,7 +672,7 @@ np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); wmb(); np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); - dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n", + dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; } @@ -643,13 +682,13 @@ return 0; } -static void do_rx_refill(unsigned long data) +static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); disable_irq(dev->irq); - if (alloc_rx(dev)) { + if (nv_alloc_rx(dev)) { spin_lock(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -658,7 +697,7 @@ enable_irq(dev->irq); } -static int init_ring(struct net_device *dev) +static int nv_init_ring(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -673,10 +712,10 @@ for (i = 0; i < RX_RING; i++) { np->rx_ring[i].Flags = 0; } - return alloc_rx(dev); + return nv_alloc_rx(dev); } -static void drain_tx(struct net_device *dev) +static void nv_drain_tx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -693,7 +732,7 @@ } } -static void drain_rx(struct net_device *dev) +static void nv_drain_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -712,8 +751,8 @@ static void drain_ring(struct net_device *dev) { - drain_tx(dev); - drain_rx(dev); + nv_drain_tx(dev); + nv_drain_rx(dev); } /* @@ -759,11 +798,11 @@ } /* - * tx_done: check for completed packets, release the skbs. + * nv_tx_done: check for completed packets, release the skbs. * * Caller must own np->lock. */ -static void tx_done(struct net_device *dev) +static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -773,7 +812,7 @@ prd = &np->tx_ring[i]; - dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n", + dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", dev->name, np->nic_tx, prd->Flags); if (prd->Flags & cpu_to_le16(NV_TX_VALID)) break; @@ -814,26 +853,26 @@ spin_lock_irq(&np->lock); /* 1) stop tx engine */ - stop_tx(dev); + nv_stop_tx(dev); /* 2) check that the packets were not sent already: */ - tx_done(dev); + nv_tx_done(dev); /* 3) if there are dead entries: clear everything */ if (np->next_tx != np->nic_tx) { printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); - drain_tx(dev); + nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); netif_wake_queue(dev); } /* 4) restart tx engine */ - start_tx(dev); + nv_start_tx(dev); spin_unlock_irq(&np->lock); } -static void rx_process(struct net_device *dev) +static void nv_rx_process(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -847,7 +886,7 @@ i = np->cur_rx % RX_RING; prd = &np->rx_ring[i]; - dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n", + dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", dev->name, np->cur_rx, prd->Flags); if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) @@ -915,7 +954,7 @@ skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); - dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n", + dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", dev->name, np->cur_rx, len, skb->protocol); netif_rx(skb); dev->last_rx = jiffies; @@ -990,24 +1029,24 @@ addr[0] |= NVREG_MCASTADDRA_FORCE; pff |= NVREG_PFF_ALWAYS; spin_lock_irq(&np->lock); - stop_rx(dev); + nv_stop_rx(dev); writel(addr[0], base + NvRegMulticastAddrA); writel(addr[1], base + NvRegMulticastAddrB); writel(mask[0], base + NvRegMulticastMaskA); writel(mask[1], base + NvRegMulticastMaskB); writel(pff, base + NvRegPacketFilterFlags); - start_rx(dev); + nv_start_rx(dev); spin_unlock_irq(&np->lock); } -static int update_linkspeed(struct net_device *dev) +static int nv_update_linkspeed(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int adv, lpa, newls, newdup; adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); - dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); /* FIXME: handle parallel detection properly, handle gigabit ethernet */ @@ -1037,7 +1076,7 @@ return 0; } -static void link_irq(struct net_device *dev) +static void nv_link_irq(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); @@ -1050,29 +1089,29 @@ miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); if (miival & BMSR_ANEGCOMPLETE) { - update_linkspeed(dev); + nv_update_linkspeed(dev); if (netif_carrier_ok(dev)) { - stop_rx(dev); + nv_stop_rx(dev); } else { netif_carrier_on(dev); printk(KERN_INFO "%s: link up.\n", dev->name); } writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1); - start_rx(dev); + nv_start_rx(dev); } else { if (netif_carrier_ok(dev)) { netif_carrier_off(dev); printk(KERN_INFO "%s: link down.\n", dev->name); - stop_rx(dev); + nv_stop_rx(dev); } writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); } } -static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); @@ -1080,7 +1119,7 @@ u32 events; int i; - dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); for (i=0; ; i++) { events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; @@ -1092,13 +1131,13 @@ if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { spin_lock(&np->lock); - tx_done(dev); + nv_tx_done(dev); spin_unlock(&np->lock); } if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { - rx_process(dev); - if (alloc_rx(dev)) { + nv_rx_process(dev); + if (nv_alloc_rx(dev)) { spin_lock(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1108,7 +1147,7 @@ if (events & NVREG_IRQ_LINK) { spin_lock(&np->lock); - link_irq(dev); + nv_link_irq(dev); spin_unlock(&np->lock); } if (events & (NVREG_IRQ_TX_ERR)) { @@ -1127,31 +1166,32 @@ if (!np->in_shutdown) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i); + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); spin_unlock(&np->lock); break; } } - dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); return IRQ_RETVAL(i); } -static void do_nic_poll(unsigned long data) +static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); disable_irq(dev->irq); + /* FIXME: Do we need synchronize_irq(dev->irq) here? */ /* * reenable interrupts on the nic, we have to do this before calling - * nic_irq because that may decide to do otherwise + * nv_nic_irq because that may decide to do otherwise */ writel(np->irqmask, base + NvRegIrqMask); pci_push(base); - nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); enable_irq(dev->irq); } @@ -1173,12 +1213,12 @@ writel(0, base + NvRegAdapterControl); writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegUnknownTransmitterReg); - txrx_reset(dev); + nv_txrx_reset(dev); writel(0, base + NvRegUnknownSetupReg6); /* 2) initialize descriptor rings */ np->in_shutdown = 0; - oom = init_ring(dev); + oom = nv_init_ring(dev); /* 3) set mac address */ { @@ -1224,7 +1264,7 @@ np->phyaddr = i; spin_lock_irq(&np->lock); - update_linkspeed(dev); + nv_update_linkspeed(dev); spin_unlock_irq(&np->lock); break; @@ -1279,7 +1319,7 @@ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); - ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev); + ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev); if (ret) goto out_drain; @@ -1291,8 +1331,8 @@ writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); - start_rx(dev); - start_tx(dev); + nv_start_rx(dev); + nv_start_tx(dev); netif_start_queue(dev); if (oom) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1326,8 +1366,8 @@ netif_stop_queue(dev); spin_lock_irq(&np->lock); - stop_tx(dev); - stop_rx(dev); + nv_stop_tx(dev); + nv_stop_rx(dev); base = get_hwbase(dev); /* disable interrupts on the nic or we will lock up */ @@ -1341,6 +1381,9 @@ drain_ring(dev); + if (np->wolenabled) + nv_start_rx(dev); + /* FIXME: power down nic */ return 0; @@ -1367,10 +1410,10 @@ init_timer(&np->oom_kick); np->oom_kick.data = (unsigned long) dev; - np->oom_kick.function = &do_rx_refill; /* timer handler */ + np->oom_kick.function = &nv_do_rx_refill; /* timer handler */ init_timer(&np->nic_poll); np->nic_poll.data = (unsigned long) dev; - np->nic_poll.function = &do_nic_poll; /* timer handler */ + np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ err = pci_enable_device(pci_dev); if (err) { @@ -1458,6 +1501,10 @@ dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + /* disable WOL */ + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); if (id->driver_data & DEV_NEED_LASTPACKET1) diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c --- a/drivers/net/gt96100eth.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/gt96100eth.c Sat Apr 3 19:38:54 2004 @@ -277,7 +277,7 @@ static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); gt96100_td_t *td = &gp->tx_ring[i]; dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td)); @@ -292,7 +292,7 @@ static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); gt96100_rd_t *rd = &gp->rx_ring[i]; dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd)); @@ -332,7 +332,7 @@ static void dump_tx_ring(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__, @@ -345,7 +345,7 @@ static void dump_rx_ring(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out); @@ -359,7 +359,7 @@ dump_MII(int dbg_lvl, struct net_device *dev) { int i, val; - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); if (dbg_lvl <= GT96100_DEBUG) { for (i=0; i<7; i++) { @@ -419,7 +419,7 @@ static int gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); //u16 hashResult, stmp; //unsigned char ctmp, hash_ea[6]; u32 tblEntry1, tblEntry0, *tblEntryAddr; @@ -544,7 +544,7 @@ static void abort(struct net_device *dev, u32 abort_bits) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int timedout = 100; // wait up to 100 msec for hard stop to complete dbg(3, "%s\n", __FUNCTION__); @@ -582,7 +582,7 @@ static void hard_stop(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); dbg(3, "%s\n", __FUNCTION__); @@ -598,7 +598,7 @@ static void enable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 intMask; /* * route ethernet interrupt to GT_SERINT0 for port 0, @@ -631,7 +631,7 @@ static void disable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 intMask; int intr_mask_reg = (gp->port_num == 0) ? GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; @@ -745,7 +745,7 @@ goto out1; } - gp = dev->priv; + gp = netdev_priv(dev); memset(gp, 0, sizeof(*gp)); // clear it @@ -839,7 +839,7 @@ static void reset_tx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; abort(dev, sdcmrAT); @@ -877,7 +877,7 @@ static void reset_rx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; abort(dev, sdcmrAR); @@ -934,7 +934,7 @@ static int gt96100_init(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 tmp; u16 mii_reg; @@ -1115,7 +1115,7 @@ static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; int nextIn; @@ -1187,7 +1187,7 @@ static int gt96100_rx(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); struct sk_buff *skb; int pkt_len, nextOut, cdp; gt96100_rd_t *rd; @@ -1296,7 +1296,7 @@ static void gt96100_tx_complete(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int nextOut, cdp; gt96100_td_t *td; u32 cmdstat; @@ -1385,7 +1385,7 @@ gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 status; int handled = 0; @@ -1486,7 +1486,7 @@ static void gt96100_tx_timeout(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -1511,7 +1511,7 @@ static void gt96100_set_rx_mode(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; //struct dev_mc_list *mcptr; @@ -1555,7 +1555,7 @@ static struct net_device_stats * gt96100_get_stats(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; dbg(3, "%s: dev=%p\n", __FUNCTION__, dev); diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c --- a/drivers/net/hamachi.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/hamachi.c Sat Apr 3 19:38:56 2004 @@ -1498,8 +1498,10 @@ if (desc_status & DescOwn) break; - pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(hmp->pci_dev, + desc->addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); buf_addr = desc_to_virt(desc->addr); frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); if (hamachi_debug > 4) @@ -1563,6 +1565,10 @@ #endif skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(hmp->pci_dev, + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if 1 || USE_IP_COPYSUM eth_copy_and_sum(skb, @@ -1572,10 +1578,14 @@ memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma + entry*sizeof(*desc), pkt_len); #endif + pci_dma_sync_single_for_device(hmp->pci_dev, + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(hmp->pci_dev, - hmp->rx_ring[entry].addr, - hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb = hmp->rx_skbuff[entry], pkt_len); hmp->rx_skbuff[entry] = NULL; } diff -Nru a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c --- a/drivers/net/hamradio/6pack.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/hamradio/6pack.c Sat Apr 3 19:38:41 2004 @@ -3,15 +3,13 @@ * devices like TTY. It interfaces between a raw TTY and the * kernel's AX.25 protocol layers. * - * Version: @(#)6pack.c 0.3.0 04/07/98 - * * Authors: Andreas Könsgen + * Ralf Baechle DO1GRB * - * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by + * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by * * Laurence Culhane, * Fred N. van Kempen, - * */ #include @@ -31,20 +29,23 @@ #include #include #include +#include #include #include #include #include +#include +#include #define SIXPACK_VERSION "Revision: 0.3.0" /* sixpack priority commands */ -#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ -#define SIXP_TX_URUN 0x48 /* transmit overrun */ -#define SIXP_RX_ORUN 0x50 /* receive overrun */ -#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ +#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ +#define SIXP_TX_URUN 0x48 /* transmit overrun */ +#define SIXP_RX_ORUN 0x50 /* receive overrun */ +#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ -#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ +#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ /* masks to get certain bits out of the status bytes sent by the TNC */ @@ -78,23 +79,20 @@ #define SIXP_MTU 256 /* Default MTU */ enum sixpack_flags { - SIXPF_INUSE, /* Channel in use */ SIXPF_ERROR, /* Parity, etc. error */ }; struct sixpack { - int magic; - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* easy for intr handling */ /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ unsigned char raw_buf[4]; unsigned char cooked_buf[400]; @@ -105,11 +103,11 @@ /* 6pack interface statistics. */ struct net_device_stats stats; - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ - unsigned long flags; /* Flag values/ mode etc */ - unsigned char mode; /* 6pack mode */ + unsigned long flags; /* Flag values/ mode etc */ + unsigned char mode; /* 6pack mode */ /* 6pack stuff */ unsigned char tx_delay; @@ -125,112 +123,293 @@ struct timer_list tx_t; struct timer_list resync_t; + + atomic_t refcnt; + struct semaphore dead_sem; + spinlock_t lock; }; #define AX25_6PACK_HEADER_LEN 0 -#define SIXPACK_MAGIC 0x5304 - -typedef struct sixpack_ctrl { - struct sixpack ctrl; /* 6pack things */ - struct net_device dev; /* the device */ -} sixpack_ctrl_t; -static sixpack_ctrl_t **sixpack_ctrls; - -int sixpack_maxdev = SIXP_NRUNIT; /* Can be overridden with insmod! */ -MODULE_PARM(sixpack_maxdev, "i"); -MODULE_PARM_DESC(sixpack_maxdev, "number of 6PACK devices"); static void sp_start_tx_timer(struct sixpack *); -static void sp_xmit_on_air(unsigned long); -static void resync_tnc(unsigned long); static void sixpack_decode(struct sixpack *, unsigned char[], int); static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); static int sixpack_init(struct net_device *dev); -static void decode_prio_command(unsigned char, struct sixpack *); -static void decode_std_command(unsigned char, struct sixpack *); -static void decode_data(unsigned char, struct sixpack *); +/* + * perform the persistence/slottime algorithm for CSMA access. If the + * persistence check was successful, write the data to the serial driver. + * Note that in case of DAMA operation, the data is not sent here. + */ + +static void sp_xmit_on_air(unsigned long channel) +{ + struct sixpack *sp = (struct sixpack *) channel; + int actual; + static unsigned char random; -static int tnc_init(struct sixpack *); + random = random * 17 + 41; -/* Find a free 6pack channel, and link in this `tty' line. */ -static inline struct sixpack *sp_alloc(void) + if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { + sp->led_state = 0x70; + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + sp->tx_enable = 1; + actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2); + sp->xleft -= actual; + sp->xhead += actual; + sp->led_state = 0x60; + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + sp->status2 = 0; + } else + sp_start_tx_timer(sp); +} + +/* ----> 6pack timer interrupt handler and friends. <---- */ +static void sp_start_tx_timer(struct sixpack *sp) { - sixpack_ctrl_t *spp = NULL; - int i; + int when = sp->slottime; - for (i = 0; i < sixpack_maxdev; i++) { - spp = sixpack_ctrls[i]; + del_timer(&sp->tx_t); + sp->tx_t.data = (unsigned long) sp; + sp->tx_t.function = sp_xmit_on_air; + sp->tx_t.expires = jiffies + ((when + 1) * HZ) / 100; + add_timer(&sp->tx_t); +} - if (spp == NULL) - break; +/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ +static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) +{ + unsigned char *msg, *p = icp; + int actual, count; - if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags)) - break; + if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ + msg = "oversized transmit packet!"; + goto out_drop; } - /* Too many devices... */ - if (i >= sixpack_maxdev) - return NULL; + if (p[0] > 5) { + msg = "invalid KISS command"; + goto out_drop; + } - /* If no channels are available, allocate one */ - if (!spp && - (sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t), - GFP_KERNEL)) != NULL) { - spp = sixpack_ctrls[i]; + if ((p[0] != 0) && (len > 2)) { + msg = "KISS control packet too long"; + goto out_drop; } - memset(spp, 0, sizeof(sixpack_ctrl_t)); - /* Initialize channel control data */ - set_bit(SIXPF_INUSE, &spp->ctrl.flags); - spp->ctrl.tty = NULL; - sprintf(spp->dev.name, "sp%d", i); - spp->dev.base_addr = i; - spp->dev.priv = (void *) &spp->ctrl; - spp->dev.next = NULL; - spp->dev.init = sixpack_init; - - if (spp != NULL) { - /* register device so that it can be ifconfig'ed */ - /* sixpack_init() will be called as a side-effect */ - /* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */ - - if (register_netdev(&spp->dev) == 0) { - set_bit(SIXPF_INUSE, &spp->ctrl.flags); - spp->ctrl.dev = &spp->dev; - spp->dev.priv = (void *) &spp->ctrl; - SET_MODULE_OWNER(&spp->dev); - return &spp->ctrl; - } else { - clear_bit(SIXPF_INUSE, &spp->ctrl.flags); - printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n"); - } + if ((p[0] == 0) && (len < 15)) { + msg = "bad AX.25 packet to transmit"; + goto out_drop; } - return NULL; + count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay); + set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); + + switch (p[0]) { + case 1: sp->tx_delay = p[1]; + return; + case 2: sp->persistence = p[1]; + return; + case 3: sp->slottime = p[1]; + return; + case 4: /* ignored */ + return; + case 5: sp->duplex = p[1]; + return; + } + + if (p[0] != 0) + return; + + /* + * In case of fullduplex or DAMA operation, we don't take care about the + * state of the DCD or of any timers, as the determination of the + * correct time to send is the job of the AX.25 layer. We send + * immediately after data has arrived. + */ + if (sp->duplex == 1) { + sp->led_state = 0x70; + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + sp->tx_enable = 1; + actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, count); + sp->xleft = count - actual; + sp->xhead = sp->xbuff + actual; + sp->led_state = 0x60; + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + } else { + sp->xleft = count; + sp->xhead = sp->xbuff; + sp->status2 = count; + if (sp->duplex == 0) + sp_start_tx_timer(sp); + } + + return; + +out_drop: + sp->stats.tx_dropped++; + netif_start_queue(sp->dev); + printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg); + return; } +/* Encapsulate an IP datagram and kick it into a TTY queue. */ + +static int sp_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sixpack *sp = netdev_priv(dev); + + spin_lock_bh(&sp->lock); + /* We were not busy, so we are now... :-) */ + netif_stop_queue(dev); + sp->stats.tx_bytes += skb->len; + sp_encaps(sp, skb->data, skb->len); + spin_unlock_bh(&sp->lock); + + dev_kfree_skb(skb); + + return 0; +} + +static int sp_open_dev(struct net_device *dev) +{ + struct sixpack *sp = netdev_priv(dev); + + if (sp->tty == NULL) + return -ENODEV; + return 0; +} + +/* Close the low-level part of the 6pack channel. */ +static int sp_close(struct net_device *dev) +{ + struct sixpack *sp = netdev_priv(dev); + + spin_lock_bh(&sp->lock); + if (sp->tty) { + /* TTY discipline is running. */ + clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); + } + netif_stop_queue(dev); + spin_unlock_bh(&sp->lock); + + return 0; +} + +/* Return the frame type ID */ +static int sp_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ +#ifdef CONFIG_INET + if (type != htons(ETH_P_AX25)) + return ax25_encapsulate(skb, dev, type, daddr, saddr, len); +#endif + return 0; +} + +static struct net_device_stats *sp_get_stats(struct net_device *dev) +{ + struct sixpack *sp = netdev_priv(dev); + return &sp->stats; +} + +static int sp_set_dev_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + return 0; +} + +static int sp_rebuild_header(struct sk_buff *skb) +{ +#ifdef CONFIG_INET + return ax25_rebuild_header(skb); +#else + return 0; +#endif +} + +static void sp_setup(struct net_device *dev) +{ + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + /* Finish setting up the DEVICE info. */ + dev->init = sixpack_init; + dev->mtu = SIXP_MTU; + dev->hard_start_xmit = sp_xmit; + dev->open = sp_open_dev; + dev->destructor = free_netdev; + dev->stop = sp_close; + dev->hard_header = sp_header; + dev->get_stats = sp_get_stats; + dev->set_mac_address = sp_set_dev_mac_address; + dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->addr_len = AX25_ADDR_LEN; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + dev->rebuild_header = sp_rebuild_header; + dev->tx_timeout = NULL; + + /* Only activated in AX.25 mode */ + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + + SET_MODULE_OWNER(dev); + + /* New-style flags. */ + dev->flags = 0; +} + +/* Find a free 6pack channel, and link in this `tty' line. */ +static inline struct sixpack *sp_alloc(void) +{ + struct sixpack *sp = NULL; + struct net_device *dev = NULL; + + dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); + if (!dev) + return NULL; + + sp = netdev_priv(dev); + sp->dev = dev; + + spin_lock_init(&sp->lock); + + if (register_netdev(dev)) + goto out_free; + + return sp; + +out_free: + printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n"); + + free_netdev(dev); + + return NULL; +} /* Free a 6pack channel. */ static inline void sp_free(struct sixpack *sp) { - /* Free all 6pack frame buffers. */ - if (sp->rbuff) - kfree(sp->rbuff); - sp->rbuff = NULL; - if (sp->xbuff) - kfree(sp->xbuff); - sp->xbuff = NULL; + void * tmp; - if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags)) - printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name); + /* Free all 6pack frame buffers. */ + if ((tmp = xchg(&sp->rbuff, NULL)) != NULL) + kfree(tmp); + if ((tmp = xchg(&sp->xbuff, NULL)) != NULL) + kfree(tmp); } /* Send one completely decapsulated IP datagram to the IP layer. */ -/* This is the routine that sends the received data to the kernel AX.25. - 'cmd' is the KISS command. For AX.25 data, it is zero. */ +/* + * This is the routine that sends the received data to the kernel AX.25. + * 'cmd' is the KISS command. For AX.25 data, it is zero. + */ static void sp_bump(struct sixpack *sp, char cmd) { @@ -238,98 +417,60 @@ int count; unsigned char *ptr; - count = sp->rcount+1; + count = sp->rcount + 1; sp->stats.rx_bytes += count; - if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name); - sp->stats.rx_dropped++; - return; - } + if ((skb = dev_alloc_skb(count)) == NULL) + goto out_mem; skb->dev = sp->dev; ptr = skb_put(skb, count); *ptr++ = cmd; /* KISS command */ - memcpy(ptr, (sp->cooked_buf)+1, count); + memcpy(ptr, sp->cooked_buf + 1, count); skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_AX25); netif_rx(skb); sp->dev->last_rx = jiffies; sp->stats.rx_packets++; + + return; + +out_mem: + sp->stats.rx_dropped++; } /* ----------------------------------------------------------------------- */ -/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ -static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) +/* + * We have a potential race on dereferencing tty->disc_data, because the tty + * layer provides no locking at all - thus one cpu could be running + * sixpack_receive_buf while another calls sixpack_close, which zeroes + * tty->disc_data and frees the memory that sixpack_receive_buf is using. The + * best way to fix this is to use a rwlock in the tty struct, but for now we + * use a single global rwlock for all ttys in ppp line discipline. + */ +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct sixpack *sp_get(struct tty_struct *tty) { - unsigned char *p; - int actual, count; - - if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ - printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name); - sp->stats.tx_dropped++; - netif_start_queue(sp->dev); - return; - } - - p = icp; - - if (p[0] > 5) { - printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name); - netif_start_queue(sp->dev); - return; - } - - if ((p[0] != 0) && (len > 2)) { - printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name); - netif_start_queue(sp->dev); - return; - } - - if ((p[0] == 0) && (len < 15)) { - printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name); - netif_start_queue(sp->dev); - sp->stats.tx_dropped++; - return; - } + struct sixpack *sp; - count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay); - sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + read_lock(&disc_data_lock); + sp = tty->disc_data; + if (sp) + atomic_inc(&sp->refcnt); + read_unlock(&disc_data_lock); - switch (p[0]) { - case 1: sp->tx_delay = p[1]; return; - case 2: sp->persistence = p[1]; return; - case 3: sp->slottime = p[1]; return; - case 4: /* ignored */ return; - case 5: sp->duplex = p[1]; return; - } + return sp; +} - if (p[0] == 0) { - /* in case of fullduplex or DAMA operation, we don't take care - about the state of the DCD or of any timers, as the determination - of the correct time to send is the job of the AX.25 layer. We send - immediately after data has arrived. */ - if (sp->duplex == 1) { - sp->led_state = 0x70; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - sp->tx_enable = 1; - actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, count); - sp->xleft = count - actual; - sp->xhead = sp->xbuff + actual; - sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - } else { - sp->xleft = count; - sp->xhead = sp->xbuff; - sp->status2 = count; - if (sp->duplex == 0) - sp_start_tx_timer(sp); - } - } +static void sp_put(struct sixpack *sp) +{ + if (atomic_dec_and_test(&sp->refcnt)) + up(&sp->dead_sem); } /* @@ -338,22 +479,17 @@ */ static void sixpack_write_wakeup(struct tty_struct *tty) { + struct sixpack *sp = sp_get(tty); int actual; - struct sixpack *sp = (struct sixpack *) tty->disc_data; - - /* First make sure we're connected. */ - if (!sp || sp->magic != SIXPACK_MAGIC || - !netif_running(sp->dev)) - return; if (sp->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ sp->stats.tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); sp->tx_enable = 0; netif_wake_queue(sp->dev); - return; + goto out; } if (sp->tx_enable == 1) { @@ -361,79 +497,34 @@ sp->xleft -= actual; sp->xhead += actual; } -} - -/* ----------------------------------------------------------------------- */ - -/* Encapsulate an IP datagram and kick it into a TTY queue. */ - -static int sp_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct sixpack *sp = (struct sixpack *) dev->priv; - - /* We were not busy, so we are now... :-) */ - netif_stop_queue(dev); - sp->stats.tx_bytes += skb->len; - sp_encaps(sp, skb->data, skb->len); - dev_kfree_skb(skb); - return 0; -} - - -/* perform the persistence/slottime algorithm for CSMA access. If the persistence - check was successful, write the data to the serial driver. Note that in case - of DAMA operation, the data is not sent here. */ -static void sp_xmit_on_air(unsigned long channel) -{ - struct sixpack *sp = (struct sixpack *) channel; - int actual; - static unsigned char random; - - random = random * 17 + 41; - - if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { - sp->led_state = 0x70; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - sp->tx_enable = 1; - actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2); - sp->xleft -= actual; - sp->xhead += actual; - sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - sp->status2 = 0; - } else - sp_start_tx_timer(sp); +out: + sp_put(sp); } +/* ----------------------------------------------------------------------- */ -/* Return the frame type ID */ -static int sp_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +/* Open the low-level part of the 6pack channel. */ +static int sp_open(struct net_device *dev) { -#ifdef CONFIG_INET - if (type != htons(ETH_P_AX25)) - return ax25_encapsulate(skb, dev, type, daddr, saddr, len); -#endif - return 0; -} + struct sixpack *sp = netdev_priv(dev); + char *rbuff, *xbuff = NULL; + int err = -ENOBUFS; + unsigned long len; + /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */ -static int sp_rebuild_header(struct sk_buff *skb) -{ -#ifdef CONFIG_INET - return ax25_rebuild_header(skb); -#else - return 0; -#endif -} + len = dev->mtu * 2; + rbuff = kmalloc(len + 4, GFP_KERNEL); + if (rbuff == NULL) + goto err_exit; + + xbuff = kmalloc(len + 4, GFP_KERNEL); + if (xbuff == NULL) + goto err_exit; -/* Open the low-level part of the 6pack channel. */ -static int sp_open(struct net_device *dev) -{ - struct sixpack *sp = (struct sixpack *) dev->priv; - unsigned long len; + spin_lock_bh(&sp->lock); if (sp->tty == NULL) return -ENODEV; @@ -445,18 +536,8 @@ * xbuff Transmit buffer. */ - /* !!! length of the buffers. MTU is IP MTU, not PACLEN! - */ - - len = dev->mtu * 2; - - if ((sp->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if ((sp->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) { - kfree(sp->rbuff); - return -ENOMEM; - } + rbuff = xchg(&sp->rbuff, rbuff); + xbuff = xchg(&sp->xbuff, xbuff); sp->mtu = AX25_MTU + 73; sp->buffsize = len; @@ -465,7 +546,7 @@ sp->rx_count_cooked = 0; sp->xleft = 0; - sp->flags &= (1 << SIXPF_INUSE); /* Clear ESCAPE & ERROR flags */ + sp->flags = 0; /* Clear ESCAPE & ERROR flags */ sp->duplex = 0; sp->tx_delay = SIXP_TXDELAY; @@ -482,49 +563,47 @@ init_timer(&sp->tx_t); init_timer(&sp->resync_t); - return 0; -} + spin_unlock_bh(&sp->lock); -/* Close the low-level part of the 6pack channel. */ -static int sp_close(struct net_device *dev) -{ - struct sixpack *sp = (struct sixpack *) dev->priv; - - if (sp->tty == NULL) - return -EBUSY; + err = 0; - sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); +err_exit: + if (xbuff) + kfree(xbuff); + if (rbuff) + kfree(rbuff); - netif_stop_queue(dev); - return 0; + return err; } + static int sixpack_receive_room(struct tty_struct *tty) { return 65536; /* We can handle an infinite amount of data. :-) */ } -/* !!! receive state machine */ - /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of 6pack data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ -static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) { + struct sixpack *sp; unsigned char buf[512]; int count1; - struct sixpack *sp = (struct sixpack *) tty->disc_data; + if (!count) + return; - if (!sp || sp->magic != SIXPACK_MAGIC || - !netif_running(sp->dev) || !count) + sp = sp_get(tty); + if (!sp) return; - memcpy(buf, cp, countflags) + && tty->driver->unthrottle) + tty->driver->unthrottle(tty); +} + +/* + * Try to resync the TNC. Called by the resync timer defined in + * decode_prio_command + */ + +static void resync_tnc(unsigned long channel) +{ + struct sixpack *sp = (struct sixpack *) channel; + struct net_device *dev = sp->dev; + static char resync_cmd = 0xe8; + + printk(KERN_INFO "%s: resyncing TNC\n", dev->name); + + /* clear any data that might have been received */ + + sp->rx_count = 0; + sp->rx_count_cooked = 0; + + /* reset state machine */ + + sp->status = 1; + sp->status1 = 1; + sp->status2 = 0; + sp->tnc_ok = 0; + + /* resync the TNC */ + + sp->led_state = 0x60; + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1); + + + /* Start resync timer again -- the TNC might be still absent */ + + del_timer(&sp->resync_t); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&sp->resync_t); +} + +static inline int tnc_init(struct sixpack *sp) +{ + unsigned char inbyte = 0xe8; + + sp->tty->driver->write(sp->tty, 0, &inbyte, 1); + + del_timer(&sp->resync_t); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&sp->resync_t); + + return 0; } /* @@ -549,37 +689,33 @@ */ static int sixpack_open(struct tty_struct *tty) { - struct sixpack *sp = (struct sixpack *) tty->disc_data; - int err; + struct sixpack *sp; + int err = 0; - /* First make sure we're not already connected. */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; - if (sp && sp->magic == SIXPACK_MAGIC) - return -EEXIST; + sp = sp_alloc(); + if (!sp) { + err = -ENOMEM; + goto out; + } - /* OK. Find a free 6pack channel to use. */ - if ((sp = sp_alloc()) == NULL) - return -ENFILE; sp->tty = tty; - tty->disc_data = sp; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - /* Restore default settings */ - sp->dev->type = ARPHRD_AX25; + atomic_set(&sp->refcnt, 1); + init_MUTEX_LOCKED(&sp->dead_sem); /* Perform the low-level 6pack initialization. */ if ((err = sp_open(sp->dev))) - return err; + goto out; /* Done. We have linked the TTY line to a channel. */ + tty->disc_data = sp; tnc_init(sp); - return sp->dev->base_addr; +out: + return err; } @@ -593,102 +729,93 @@ { struct sixpack *sp = (struct sixpack *) tty->disc_data; - /* First make sure we're connected. */ - if (!sp || sp->magic != SIXPACK_MAGIC) + write_lock(&disc_data_lock); + sp = tty->disc_data; + tty->disc_data = 0; + write_unlock(&disc_data_lock); + if (sp == 0) return; - rtnl_lock(); - dev_close(sp->dev); + /* + * We have now ensured that nobody can start using ap from now on, but + * we have to wait for all existing users to finish. + */ + if (!atomic_dec_and_test(&sp->refcnt)) + down(&sp->dead_sem); del_timer(&sp->tx_t); del_timer(&sp->resync_t); - tty->disc_data = 0; - sp->tty = NULL; - sp_free(sp); - unregister_netdevice(sp->dev); - rtnl_unlock(); + unregister_netdev(sp->dev); } - -static struct net_device_stats *sp_get_stats(struct net_device *dev) -{ - struct sixpack *sp = (struct sixpack *) dev->priv; - return &sp->stats; -} - - static int sp_set_mac_address(struct net_device *dev, void *addr) { return copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN) ? -EFAULT : 0; } -static int sp_set_dev_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = addr; - memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); - return 0; -} - - /* Perform I/O control on an active 6pack channel. */ -static int sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +static int sixpack_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - struct sixpack *sp = (struct sixpack *) tty->disc_data; - unsigned int tmp; + struct sixpack *sp = sp_get(tty); + unsigned int tmp, err; - /* First make sure we're connected. */ - if (!sp || sp->magic != SIXPACK_MAGIC) - return -EINVAL; + if (!sp) + return -ENXIO; switch(cmd) { case SIOCGIFNAME: - return copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1) ? -EFAULT : 0; + err = copy_to_user((void *) arg, sp->dev->name, + strlen(sp->dev->name) + 1) ? -EFAULT : 0; + break; case SIOCGIFENCAP: - return put_user(0, (int *)arg); + err = put_user(0, (int *)arg); + break; case SIOCSIFENCAP: - if (get_user(tmp, (int *) arg)) - return -EFAULT; + if (get_user(tmp, (int *) arg)) { + err = -EFAULT; + break; + } sp->mode = tmp; sp->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; sp->dev->type = ARPHRD_AX25; - return 0; + err = 0; + break; case SIOCSIFHWADDR: - return sp_set_mac_address(sp->dev, arg); + err = sp_set_mac_address(sp->dev, (void *) arg); + break; /* Allow stty to read, but not set, the serial port */ case TCGETS: case TCGETA: - return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); + err = n_tty_ioctl(tty, (struct file *) file, cmd, arg); + break; default: return -ENOIOCTLCMD; } -} -static int sp_open_dev(struct net_device *dev) -{ - struct sixpack *sp = (struct sixpack *) dev->priv; - if (sp->tty == NULL) - return -ENODEV; - return 0; + sp_put(sp); + + return err; } /* Fill in our line protocol discipline */ static struct tty_ldisc sp_ldisc = { - .magic = TTY_LDISC_MAGIC, + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, .name = "6pack", .open = sixpack_open, - .close = sixpack_close, - .ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long)) sixpack_ioctl, + .close = sixpack_close, + .ioctl = sixpack_ioctl, .receive_buf = sixpack_receive_buf, .receive_room = sixpack_receive_room, .write_wakeup = sixpack_write_wakeup, @@ -696,34 +823,18 @@ /* Initialize 6pack control device -- register 6pack line discipline */ -static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n"; -static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n"; +static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION "\n"; static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n"; static int __init sixpack_init_driver(void) { int status; - /* Do sanity checks on maximum device parameter. */ - if (sixpack_maxdev < 4) - sixpack_maxdev = 4; - - printk(msg_banner, sixpack_maxdev); - - sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL); - if (sixpack_ctrls == NULL) { - printk(msg_nomem); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */ + printk(msg_banner); /* Register the provided line protocol discipline */ - if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) { + if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) printk(msg_regfail, status); - kfree(sixpack_ctrls); - } return status; } @@ -732,36 +843,16 @@ static void __exit sixpack_exit_driver(void) { - int i; - - if ((i = tty_register_ldisc(N_6PACK, NULL))) - printk(msg_unregfail, i); + int ret; - for (i = 0; i < sixpack_maxdev; i++) { - if (sixpack_ctrls[i]) { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (netif_running(&sixpack_ctrls[i]->dev)) - unregister_netdev(&sixpack_ctrls[i]->dev); - - kfree(sixpack_ctrls[i]); - } - } - kfree(sixpack_ctrls); + if ((ret = tty_register_ldisc(N_6PACK, NULL))) + printk(msg_unregfail, ret); } - /* Initialize the 6pack driver. Called by DDI. */ static int sixpack_init(struct net_device *dev) { - struct sixpack *sp = (struct sixpack *) dev->priv; - - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + struct sixpack *sp = netdev_priv(dev); if (sp == NULL) /* Allocation failed ?? */ return -ENODEV; @@ -769,52 +860,15 @@ /* Set up the "6pack Control Block". (And clear statistics) */ memset(sp, 0, sizeof (struct sixpack)); - sp->magic = SIXPACK_MAGIC; sp->dev = dev; - /* Finish setting up the DEVICE info. */ - dev->mtu = SIXP_MTU; - dev->hard_start_xmit = sp_xmit; - dev->open = sp_open_dev; - dev->stop = sp_close; - dev->hard_header = sp_header; - dev->get_stats = sp_get_stats; - dev->set_mac_address = sp_set_dev_mac_address; - dev->hard_header_len = AX25_MAX_HEADER_LEN; - dev->addr_len = AX25_ADDR_LEN; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - dev->rebuild_header = sp_rebuild_header; - dev->tx_timeout = NULL; - - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */ - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */ - - /* New-style flags. */ - dev->flags = 0; - return 0; } - - - -/* ----> 6pack timer interrupt handler and friends. <---- */ -static void sp_start_tx_timer(struct sixpack *sp) -{ - int when = sp->slottime; - - del_timer(&sp->tx_t); - sp->tx_t.data = (unsigned long) sp; - sp->tx_t.function = sp_xmit_on_air; - sp->tx_t.expires = jiffies + ((when+1)*HZ)/100; - add_timer(&sp->tx_t); -} - - /* encode an AX.25 packet into 6pack */ -static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay) +static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, + int length, unsigned char tx_delay) { int count = 0; unsigned char checksum = 0, buf[400]; @@ -849,47 +903,28 @@ return raw_count; } +/* decode 4 sixpack-encoded bytes into 3 data bytes */ -/* decode a 6pack packet */ - -static void -sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count) -{ - unsigned char inbyte; - int count1; - - for (count1 = 0; count1 < count; count1++) { - inbyte = pre_rbuff[count1]; - if (inbyte == SIXP_FOUND_TNC) { - printk(KERN_INFO "6pack: TNC found.\n"); - sp->tnc_ok = 1; - del_timer(&sp->resync_t); - } - if ((inbyte & SIXP_PRIO_CMD_MASK) != 0) - decode_prio_command(inbyte, sp); - else if ((inbyte & SIXP_STD_CMD_MASK) != 0) - decode_std_command(inbyte, sp); - else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) - decode_data(inbyte, sp); - } -} - -static int tnc_init(struct sixpack *sp) +static void decode_data(unsigned char inbyte, struct sixpack *sp) { - unsigned char inbyte = 0xe8; + unsigned char *buf; - sp->tty->driver->write(sp->tty, 0, &inbyte, 1); + if (sp->rx_count != 3) { + sp->raw_buf[sp->rx_count++] = inbyte; - del_timer(&sp->resync_t); - sp->resync_t.data = (unsigned long) sp; - sp->resync_t.function = resync_tnc; - sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; - add_timer(&sp->resync_t); + return; + } - return 0; + buf = sp->raw_buf; + sp->cooked_buf[sp->rx_count_cooked++] = + buf[0] | ((buf[1] << 2) & 0xc0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[2] & 0x03) | (inbyte << 2); + sp->rx_count = 0; } - /* identify and execute a 6pack priority command byte */ static void decode_prio_command(unsigned char cmd, struct sixpack *sp) @@ -916,8 +951,7 @@ cmd &= !SIXP_RX_DCD_MASK; } sp->status = cmd & SIXP_PRIO_DATA_MASK; - } - else { /* output watchdog char if idle */ + } else { /* output watchdog char if idle */ if ((sp->status2 != 0) && (sp->duplex == 1)) { sp->led_state = 0x70; sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); @@ -948,46 +982,6 @@ sp->status1 = cmd & SIXP_PRIO_DATA_MASK; } -/* try to resync the TNC. Called by the resync timer defined in - decode_prio_command */ - -static void resync_tnc(unsigned long channel) -{ - static char resync_cmd = 0xe8; - struct sixpack *sp = (struct sixpack *) channel; - - printk(KERN_INFO "6pack: resyncing TNC\n"); - - /* clear any data that might have been received */ - - sp->rx_count = 0; - sp->rx_count_cooked = 0; - - /* reset state machine */ - - sp->status = 1; - sp->status1 = 1; - sp->status2 = 0; - sp->tnc_ok = 0; - - /* resync the TNC */ - - sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1); - - - /* Start resync timer again -- the TNC might be still absent */ - - del_timer(&sp->resync_t); - sp->resync_t.data = (unsigned long) sp; - sp->resync_t.function = resync_tnc; - sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; - add_timer(&sp->resync_t); -} - - - /* identify and execute a standard 6pack command byte */ static void decode_std_command(unsigned char cmd, struct sixpack *sp) @@ -997,67 +991,70 @@ channel = cmd & SIXP_CHN_MASK; switch (cmd & SIXP_CMD_MASK) { /* normal command */ - case SIXP_SEOF: - if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { - if ((sp->status & SIXP_RX_DCD_MASK) == - SIXP_RX_DCD_MASK) { - sp->led_state = 0x68; - sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - } - } else { - sp->led_state = 0x60; - /* fill trailing bytes with zeroes */ + case SIXP_SEOF: + if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { + if ((sp->status & SIXP_RX_DCD_MASK) == + SIXP_RX_DCD_MASK) { + sp->led_state = 0x68; sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); - rest = sp->rx_count; - if (rest != 0) - for (i = rest; i <= 3; i++) - decode_data(0, sp); - if (rest == 2) - sp->rx_count_cooked -= 2; - else if (rest == 3) - sp->rx_count_cooked -= 1; - for (i = 0; i < sp->rx_count_cooked; i++) - checksum += sp->cooked_buf[i]; - if (checksum != SIXP_CHKSUM) { - printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); - } else { - sp->rcount = sp->rx_count_cooked-2; - sp_bump(sp, 0); - } - sp->rx_count_cooked = 0; } - break; - case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); - break; - case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); - break; - case SIXP_RX_BUF_OVL: - printk(KERN_DEBUG "6pack: RX buffer overflow\n"); + } else { + sp->led_state = 0x60; + /* fill trailing bytes with zeroes */ + sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1); + rest = sp->rx_count; + if (rest != 0) + for (i = rest; i <= 3; i++) + decode_data(0, sp); + if (rest == 2) + sp->rx_count_cooked -= 2; + else if (rest == 3) + sp->rx_count_cooked -= 1; + for (i = 0; i < sp->rx_count_cooked; i++) + checksum += sp->cooked_buf[i]; + if (checksum != SIXP_CHKSUM) { + printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); + } else { + sp->rcount = sp->rx_count_cooked-2; + sp_bump(sp, 0); + } + sp->rx_count_cooked = 0; + } + break; + case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); + break; + case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); + break; + case SIXP_RX_BUF_OVL: + printk(KERN_DEBUG "6pack: RX buffer overflow\n"); } } -/* decode 4 sixpack-encoded bytes into 3 data bytes */ +/* decode a 6pack packet */ -static void decode_data(unsigned char inbyte, struct sixpack *sp) +static void +sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count) { - unsigned char *buf; + unsigned char inbyte; + int count1; - if (sp->rx_count != 3) - sp->raw_buf[sp->rx_count++] = inbyte; - else { - buf = sp->raw_buf; - sp->cooked_buf[sp->rx_count_cooked++] = - buf[0] | ((buf[1] << 2) & 0xc0); - sp->cooked_buf[sp->rx_count_cooked++] = - (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); - sp->cooked_buf[sp->rx_count_cooked++] = - (buf[2] & 0x03) | (inbyte << 2); - sp->rx_count = 0; + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; + if (inbyte == SIXP_FOUND_TNC) { + printk(KERN_INFO "6pack: TNC found.\n"); + sp->tnc_ok = 1; + del_timer(&sp->resync_t); + } + if ((inbyte & SIXP_PRIO_CMD_MASK) != 0) + decode_prio_command(inbyte, sp); + else if ((inbyte & SIXP_STD_CMD_MASK) != 0) + decode_std_command(inbyte, sp); + else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) + decode_data(inbyte, sp); } } - -MODULE_AUTHOR("Andreas Könsgen "); +MODULE_AUTHOR("Ralf Baechle DO1GRB "); MODULE_DESCRIPTION("6pack driver for AX.25"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_6PACK); diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c --- a/drivers/net/hamradio/baycom_epp.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/hamradio/baycom_epp.c Sat Apr 3 19:38:56 2004 @@ -646,7 +646,7 @@ static void do_rxpacket(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct sk_buff *skb; unsigned char *cp; unsigned pktlen; @@ -705,7 +705,7 @@ static int receive(struct net_device *dev, int cnt) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp = bc->pdev->port; unsigned int bitbuf, notbitstream, bitstream, numbits, state; unsigned char tmp[128]; @@ -790,7 +790,7 @@ int cnt, cnt2; baycom_paranoia_check_void(dev, "epp_bh"); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (!bc->work_running) return; baycom_int_freq(bc); @@ -908,7 +908,7 @@ struct baycom_state *bc; baycom_paranoia_check(dev, "baycom_send_packet", 0); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); @@ -944,7 +944,7 @@ struct baycom_state *bc; baycom_paranoia_check(dev, "baycom_get_stats", NULL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); /* * Get the current statistics. This may be called with the * card open or closed. @@ -960,7 +960,7 @@ struct baycom_state *bc; baycom_paranoia_check_void(dev, "epp_wakeup"); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); if (!parport_claim(bc->pdev)) printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); @@ -987,7 +987,7 @@ unsigned long tstart; baycom_paranoia_check(dev, "epp_open", -ENXIO); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); pp = parport_find_base(dev->base_addr); if (!pp) { printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); @@ -1102,7 +1102,7 @@ unsigned char tmp[1]; baycom_paranoia_check(dev, "epp_close", -EINVAL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); pp = bc->pdev->port; bc->work_running = 0; flush_scheduled_work(); @@ -1163,7 +1163,7 @@ struct hdlcdrv_ioctl hi; baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; if (get_user(cmd, (int *)ifr->ifr_data)) @@ -1290,7 +1290,7 @@ /* * not a real probe! only initialize data structures */ - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); /* * initialize the baycom_state struct */ @@ -1351,7 +1351,7 @@ static void __init baycom_epp_dev_setup(struct net_device *dev) { - struct baycom_state *bc = dev->priv; + struct baycom_state *bc = netdev_priv(dev); /* * initialize part of the baycom_state struct @@ -1415,7 +1415,7 @@ struct net_device *dev = baycom_device[i]; if (dev) { - struct baycom_state *bc = dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (bc->magic == BAYCOM_MAGIC) { unregister_netdev(dev); free_netdev(dev); diff -Nru a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c --- a/drivers/net/hamradio/baycom_par.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/hamradio/baycom_par.c Sat Apr 3 19:38:56 2004 @@ -272,7 +272,7 @@ static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) return; @@ -302,7 +302,7 @@ static void par96_wakeup(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name); if (!parport_claim(bc->pdev)) @@ -313,7 +313,7 @@ static int par96_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp; if (!dev || !bc) @@ -362,7 +362,7 @@ static int par96_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp; if (!dev || !bc) @@ -424,7 +424,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -524,7 +524,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; found++; diff -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c --- a/drivers/net/hamradio/baycom_ser_fdx.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/hamradio/baycom_ser_fdx.c Sat Apr 3 19:38:44 2004 @@ -281,7 +281,7 @@ static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct timeval tv; unsigned char iir, msr; unsigned int txcount = 0; @@ -407,7 +407,7 @@ static int ser12_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); enum uart u; if (!dev || !bc) @@ -466,7 +466,7 @@ static int ser12_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc) return -EINVAL; @@ -536,7 +536,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -644,7 +644,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; bc->baud = baud[i]; diff -Nru a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c --- a/drivers/net/hamradio/baycom_ser_hdx.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/hamradio/baycom_ser_hdx.c Sat Apr 3 19:38:41 2004 @@ -375,7 +375,7 @@ static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); unsigned char iir; if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) @@ -468,7 +468,7 @@ static int ser12_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); enum uart u; if (!dev || !bc) @@ -511,7 +511,7 @@ static int ser12_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc) return -EINVAL; @@ -576,7 +576,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -681,7 +681,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; found++; diff -Nru a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c --- a/drivers/net/hamradio/hdlcdrv.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/hamradio/hdlcdrv.c Sat Apr 3 19:38:54 2004 @@ -737,7 +737,7 @@ static const struct hdlcdrv_channel_params dflt_ch_params = { 20, 2, 10, 40, 0 }; - struct hdlcdrv_state *s = dev->priv;; + struct hdlcdrv_state *s = dev->priv; /* * initialize the hdlcdrv_state struct diff -Nru a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c --- a/drivers/net/hp-plus.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/hp-plus.c Sat Apr 3 19:38:41 2004 @@ -236,6 +236,9 @@ dev->open = &hpp_open; dev->stop = &hpp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ diff -Nru a/drivers/net/hp.c b/drivers/net/hp.c --- a/drivers/net/hp.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/hp.c Sat Apr 3 19:38:42 2004 @@ -207,6 +207,9 @@ dev->base_addr = ioaddr + NIC_OFFSET; dev->open = &hp_open; dev->stop = &hp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = wordmode; diff -Nru a/drivers/net/hplance.c b/drivers/net/hplance.c --- a/drivers/net/hplance.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/hplance.c Sat Apr 3 19:38:43 2004 @@ -63,7 +63,7 @@ static void cleanup_card(struct net_device *dev) { - struct hplance_private *lp = dev->priv; + struct hplance_private *lp = netdev_priv(dev); dio_unconfig_board(lp->scode); } @@ -97,7 +97,7 @@ dio_config_board(scode); hplance_init(dev, scode); if (!register_netdev(dev)) { - struct hplance_private *lp = dev->priv; + struct hplance_private *lp = netdev_priv(dev); lp->next_module = root_hplance_dev; root_hplance_dev = lp; return dev; @@ -141,7 +141,7 @@ printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]); } - lp = (struct hplance_private *)dev->priv; + lp = netdev_priv(dev); lp->lance.name = (char*)name; /* discards const, shut up gcc */ lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF); lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */ @@ -195,7 +195,7 @@ static int hplance_open(struct net_device *dev) { int status; - struct hplance_private *lp = (struct hplance_private *)dev->priv; + struct hplance_private *lp = netdev_priv(dev); struct hplance_reg *hpregs = (struct hplance_reg *)lp->base; status = lance_open(dev); /* call generic lance open code */ @@ -209,7 +209,7 @@ static int hplance_close(struct net_device *dev) { - struct hplance_private *lp = (struct hplance_private *)dev->priv; + struct hplance_private *lp = netdev_priv(dev); struct hplance_reg *hpregs = (struct hplance_reg *)lp->base; out_8(&(hpregs->status), 8); /* disable interrupts at boardlevel */ lance_close(dev); diff -Nru a/drivers/net/hydra.c b/drivers/net/hydra.c --- a/drivers/net/hydra.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/hydra.c Sat Apr 3 19:38:43 2004 @@ -142,6 +142,10 @@ ei_status.reg_offset = hydra_offsets; dev->open = &hydra_open; dev->stop = &hydra_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); err = register_netdev(dev); diff -Nru a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c --- a/drivers/net/ibmveth.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/ibmveth.c Sat Apr 3 19:38:40 2004 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -404,27 +405,27 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) { if(adapter->buffer_list_addr != NULL) { - if(adapter->buffer_list_dma != NO_TCE) { + if(!vio_dma_mapping_error(adapter->buffer_list_dma)) { vio_unmap_single(adapter->vdev, adapter->buffer_list_dma, 4096, PCI_DMA_BIDIRECTIONAL); - adapter->buffer_list_dma = NO_TCE; + adapter->buffer_list_dma = DMA_ERROR_CODE; } free_page((unsigned long)adapter->buffer_list_addr); adapter->buffer_list_addr = NULL; } if(adapter->filter_list_addr != NULL) { - if(adapter->filter_list_dma != NO_TCE) { + if(!vio_dma_mapping_error(adapter->filter_list_dma)) { vio_unmap_single(adapter->vdev, adapter->filter_list_dma, 4096, PCI_DMA_BIDIRECTIONAL); - adapter->filter_list_dma = NO_TCE; + adapter->filter_list_dma = DMA_ERROR_CODE; } free_page((unsigned long)adapter->filter_list_addr); adapter->filter_list_addr = NULL; } if(adapter->rx_queue.queue_addr != NULL) { - if(adapter->rx_queue.queue_dma != NO_TCE) { + if(!vio_dma_mapping_error(adapter->rx_queue.queue_dma)) { vio_unmap_single(adapter->vdev, adapter->rx_queue.queue_dma, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL); - adapter->rx_queue.queue_dma = NO_TCE; + adapter->rx_queue.queue_dma = DMA_ERROR_CODE; } kfree(adapter->rx_queue.queue_addr); adapter->rx_queue.queue_addr = NULL; @@ -473,9 +474,9 @@ adapter->filter_list_dma = vio_map_single(adapter->vdev, adapter->filter_list_addr, 4096, PCI_DMA_BIDIRECTIONAL); adapter->rx_queue.queue_dma = vio_map_single(adapter->vdev, adapter->rx_queue.queue_addr, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL); - if((adapter->buffer_list_dma == NO_TCE) || - (adapter->filter_list_dma == NO_TCE) || - (adapter->rx_queue.queue_dma == NO_TCE)) { + if((vio_dma_mapping_error(adapter->buffer_list_dma) ) || + (vio_dma_mapping_error(adapter->filter_list_dma)) || + (vio_dma_mapping_error(adapter->rx_queue.queue_dma))) { ibmveth_error_printk("unable to map filter or buffer list pages\n"); ibmveth_cleanup(adapter); return -ENOMEM; @@ -527,7 +528,10 @@ ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); - h_free_logical_lan(adapter->vdev->unit_address); + do { + rc = h_free_logical_lan(adapter->vdev->unit_address); + } while H_isLongBusy(rc); + ibmveth_cleanup(adapter); return rc; } @@ -556,7 +560,9 @@ cancel_delayed_work(&adapter->replenish_task); flush_scheduled_work(); - lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); + do { + lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); + } while H_isLongBusy(lpar_rc); if(lpar_rc != H_Success) { @@ -617,6 +623,8 @@ union ibmveth_buf_desc desc[IbmVethMaxSendFrags]; unsigned long lpar_rc; int nfrags = 0, curfrag; + unsigned long correlator; + unsigned int retry_count; if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { adapter->stats.tx_dropped++; @@ -637,7 +645,7 @@ desc[0].fields.address = vio_map_single(adapter->vdev, skb->data, desc[0].fields.length, PCI_DMA_TODEVICE); desc[0].fields.valid = 1; - if(desc[0].fields.address == NO_TCE) { + if(vio_dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); adapter->tx_map_failed++; adapter->stats.tx_dropped++; @@ -656,7 +664,7 @@ desc[curfrag+1].fields.length = frag->size; desc[curfrag+1].fields.valid = 1; - if(desc[curfrag+1].fields.address == NO_TCE) { + if(vio_dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); adapter->tx_map_failed++; adapter->stats.tx_dropped++; @@ -674,8 +682,8 @@ } /* send the frame. Arbitrarily set retrycount to 1024 */ - unsigned long correlator = 0; - unsigned int retry_count = 1024; + correlator = 0; + retry_count = 1024; do { lpar_rc = h_send_logical_lan(adapter->vdev->unit_address, desc[0].desc, @@ -937,9 +945,9 @@ INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); - adapter->buffer_list_dma = NO_TCE; - adapter->filter_list_dma = NO_TCE; - adapter->rx_queue.queue_dma = NO_TCE; + adapter->buffer_list_dma = DMA_ERROR_CODE; + adapter->filter_list_dma = DMA_ERROR_CODE; + adapter->rx_queue.queue_dma = DMA_ERROR_CODE; atomic_set(&adapter->not_replenishing, 1); diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c --- a/drivers/net/irda/vlsi_ir.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/irda/vlsi_ir.c Sat Apr 3 19:38:41 2004 @@ -173,7 +173,7 @@ PCIDEV_NAME(pdev), (int)pdev->vendor, (int)pdev->device); out += sprintf(out, "pci-power-state: %u\n", (unsigned) pdev->current_state); out += sprintf(out, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", - pdev->irq, (unsigned)pci_resource_start(pdev, 0), (u64)pdev->dma_mask); + pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask); out += sprintf(out, "hw registers: "); for (i = 0; i < 0x20; i++) out += sprintf(out, "%02x", (unsigned)inb((iobase+i))); @@ -566,7 +566,6 @@ return NULL; } rd_set_addr_status(rd, busaddr, 0); - pci_dma_sync_single(pdev, busaddr, len, dir); /* initially, the dma buffer is owned by the CPU */ rd->skb = NULL; } @@ -660,7 +659,7 @@ struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev); vlsi_irda_dev_t *idev = ndev->priv; - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ status = rd_get_status(rd); if (status & RD_RX_ERROR) { @@ -746,7 +745,7 @@ break; /* probably not worth logging? */ } /* give dma buffer back to busmaster */ - pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); rd_activate(rd); } } @@ -816,7 +815,7 @@ ret = -VLSI_RX_DROP; } rd_set_count(rd, 0); - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); if (rd->skb) { dev_kfree_skb_any(rd->skb); rd->skb = NULL; @@ -854,7 +853,7 @@ int len; int ret; - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ status = rd_get_status(rd); if (status & RD_TX_UNDRN) @@ -1077,8 +1076,8 @@ } } - /* tx buffer already owned by CPU due to pci_dma_sync_single() either - * after initial pci_map_single or after subsequent tx-completion + /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() + * after subsequent tx-completion */ if (idev->mode == IFF_SIR) { @@ -1120,7 +1119,7 @@ * CPU-driven changes visible from the pci bus). */ - pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); /* Switching to TX mode here races with the controller * which may stop TX at any time when fetching an inactive descriptor @@ -1248,7 +1247,7 @@ if (rd_is_active(rd)) { rd_set_status(rd, 0); rd_set_count(rd, 0); - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); if (rd->skb) { dev_kfree_skb_any(rd->skb); rd->skb = NULL; diff -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c --- a/drivers/net/isa-skeleton.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/isa-skeleton.c Sat Apr 3 19:38:56 2004 @@ -303,7 +303,7 @@ } #endif /* jumpered DMA */ - np = (struct net_local *)dev->priv; + np = netdev_priv(dev); spin_lock_init(&np->lock); dev->open = net_open; @@ -326,7 +326,7 @@ static void net_tx_timeout(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); @@ -361,7 +361,7 @@ static int net_open(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int ioaddr = dev->base_addr; /* * This is used if the interrupt line can turned off (shared). @@ -399,7 +399,7 @@ */ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; @@ -465,7 +465,7 @@ */ void net_tx(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int entry; /* This protects us from concurrent execution of @@ -508,7 +508,7 @@ ioaddr = dev->base_addr; - np = (struct net_local *)dev->priv; + np = netdev_priv(dev); status = inw(ioaddr + 0); if (status == 0) @@ -539,7 +539,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 10; @@ -591,7 +591,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->open_time = 0; @@ -620,7 +620,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; /* Update the statistics from the device registers. */ diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/lasi_82596.c Sat Apr 3 19:38:41 2004 @@ -426,7 +426,7 @@ static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; u32 v = (u32) (c) | (u32) (x); u16 a, b; @@ -481,7 +481,7 @@ static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -541,7 +541,7 @@ static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -595,7 +595,7 @@ static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; struct i596_rbd *rbd; int i; @@ -612,7 +612,7 @@ static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -633,7 +633,7 @@ static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; unsigned long flags; disable_irq(dev->irq); /* disable IRQs from LAN */ @@ -727,7 +727,7 @@ static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = dev->priv; struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -802,9 +802,10 @@ skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ - dma_sync_single(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); skb_reserve(skb, 2); memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); + dma_sync_single_for_device(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); } skb->len = pkt_len; skb->protocol=eth_type_trans(skb,dev); @@ -939,7 +940,7 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; unsigned long flags; DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head)); @@ -987,7 +988,7 @@ device list */ static int i596_test(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; volatile int *tint; u32 data; @@ -1041,7 +1042,7 @@ static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; /* Transmitter timeout, serious problems. */ DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n", @@ -1070,7 +1071,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1219,7 +1220,7 @@ dev->priv = (void *)(dev->mem_start); - lp = (struct i596_private *) dev->priv; + lp = dev->priv; DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); @@ -1249,7 +1250,7 @@ return IRQ_NONE; } - lp = (struct i596_private *) dev->priv; + lp = dev->priv; spin_lock (&lp->lock); @@ -1395,7 +1396,7 @@ static int i596_close(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; unsigned long flags; netif_stop_queue(dev); @@ -1429,7 +1430,7 @@ static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; return &lp->stats; } @@ -1440,7 +1441,7 @@ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = dev->priv; int config = 0, cnt; DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); @@ -1594,7 +1595,7 @@ unregister_netdev(netdevice); - lp = (struct i596_private *) netdevice->priv; + lp = netdevice->priv; dma_free_noncoherent(lp->dev, sizeof(struct i596_private), (void *)netdevice->mem_start, lp->dma_addr); free_netdev(netdevice); diff -Nru a/drivers/net/lne390.c b/drivers/net/lne390.c --- a/drivers/net/lne390.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/lne390.c Sat Apr 3 19:38:55 2004 @@ -299,6 +299,9 @@ dev->open = &lne390_open; dev->stop = &lne390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; cleanup: diff -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c --- a/drivers/net/loopback.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/loopback.c Sat Apr 3 19:38:41 2004 @@ -123,7 +123,7 @@ */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + struct net_device_stats *stats = dev->priv; skb_orphan(skb); diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c --- a/drivers/net/mac8390.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/mac8390.c Sat Apr 3 19:38:43 2004 @@ -442,6 +442,9 @@ /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff -Nru a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c --- a/drivers/net/mac89x0.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/mac89x0.c Sat Apr 3 19:38:43 2004 @@ -225,7 +225,7 @@ goto out; /* Initialize the net_device structure. */ - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; @@ -328,7 +328,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int i; /* Disable the interrupt for now */ @@ -392,7 +392,7 @@ 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; + struct net_local *lp = netdev_priv(dev); unsigned long flags; if (net_debug > 3) @@ -446,7 +446,7 @@ dev->interrupt = 1; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* 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 @@ -505,7 +505,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; @@ -571,7 +571,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -585,7 +585,7 @@ static void set_multicast_list(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if(dev->flags&IFF_PROMISC) { diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/mace.c Sat Apr 3 19:38:42 2004 @@ -202,7 +202,7 @@ rc = -ENOMEM; goto err_unmap_tx_dma; } - mp->rx_dma_intr = macio_irq(mdev, 2);; + mp->rx_dma_intr = macio_irq(mdev, 2); mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c --- a/drivers/net/myri_sbus.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/myri_sbus.c Sat Apr 3 19:38:41 2004 @@ -435,9 +435,9 @@ /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - sbus_dma_sync_single(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + sbus_dma_sync_single_for_cpu(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); mp->enet_stats.rx_errors++; @@ -454,6 +454,10 @@ drops++; DRX(("DROP ")); mp->enet_stats.rx_dropped++; + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -508,6 +512,10 @@ /* Reuse original ring buffer. */ DRX(("reuse ")); + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c --- a/drivers/net/natsemi.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/natsemi.c Sat Apr 3 19:38:41 2004 @@ -175,6 +175,8 @@ #define DRV_VERSION "1.07+LK1.0.17" #define DRV_RELDATE "Sep 27, 2002" +#define RX_OFFSET 2 + /* Updated to recommendations in pci-skeleton v2.03. */ /* The user-configurable values. @@ -1467,13 +1469,14 @@ struct sk_buff *skb; int entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; + skb = dev_alloc_skb(buflen); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); + skb->tail, buflen, PCI_DMA_FROMDEVICE); np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); } np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz); @@ -1543,6 +1546,7 @@ static void drain_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; int i; /* Free all the skbuffs in the Rx queue. */ @@ -1551,7 +1555,7 @@ np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, - np->rx_dma[i], np->rx_skbuff[i]->len, + np->rx_dma[i], buflen, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } @@ -1747,6 +1751,7 @@ int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ @@ -1785,13 +1790,13 @@ /* Check if the packet is long enough to accept * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { skb->dev = dev; /* 16 byte align the IP header */ - skb_reserve(skb, 2); - pci_dma_sync_single(np->pci_dev, + skb_reserve(skb, RX_OFFSET); + pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_dma[entry], - np->rx_skbuff[entry]->len, + buflen, PCI_DMA_FROMDEVICE); #if HAS_IP_COPYSUM eth_copy_and_sum(skb, @@ -1801,10 +1806,13 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev, + np->rx_dma[entry], + buflen, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(np->pci_dev, np->rx_dma[entry], - np->rx_skbuff[entry]->len, - PCI_DMA_FROMDEVICE); + buflen, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } diff -Nru a/drivers/net/ne.c b/drivers/net/ne.c --- a/drivers/net/ne.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/ne.c Sat Apr 3 19:38:43 2004 @@ -498,6 +498,9 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/ne2.c b/drivers/net/ne2.c --- a/drivers/net/ne2.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/ne2.c Sat Apr 3 19:38:56 2004 @@ -509,6 +509,9 @@ dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out: diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/ne2k-pci.c Sat Apr 3 19:38:42 2004 @@ -359,6 +359,9 @@ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; dev->ethtool_ops = &ne2k_pci_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); i = register_netdev(dev); diff -Nru a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c --- a/drivers/net/ne2k_cbus.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/ne2k_cbus.c Sat Apr 3 19:38:42 2004 @@ -534,6 +534,9 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c --- a/drivers/net/ne3210.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/ne3210.c Sat Apr 3 19:38:43 2004 @@ -205,6 +205,9 @@ dev->open = &ne3210_open; dev->stop = &ne3210_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif dev->if_port = ifmap_val[port_index]; if ((retval = register_netdev (dev))) diff -Nru a/drivers/net/netconsole.c b/drivers/net/netconsole.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/netconsole.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,127 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + */ + +/**************************************************************** + * 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, 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. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; +static int configured = 0; + +#define MAX_PRINT_CHUNK 1000 + +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + int frag, left; + unsigned long flags; + + if (!np.dev) + return; + + local_irq_save(flags); + + for(left = len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + + local_irq_restore(flags); +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static int option_setup(char *opt) +{ + configured = !netpoll_parse_options(&np, opt); + return 0; +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config)) + option_setup(config); + + if(!configured) { + printk("netconsole: not configured, aborting\n"); + return -EINVAL; + } + + if(netpoll_setup(&np)) + return -EINVAL; + + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); diff -Nru a/drivers/net/ni5010.c b/drivers/net/ni5010.c --- a/drivers/net/ni5010.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/ni5010.c Sat Apr 3 19:38:43 2004 @@ -309,7 +309,7 @@ PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); /* DMA is not supported (yet?), so no use detecting it */ - lp = (struct ni5010_local*)dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); @@ -484,7 +484,7 @@ PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name)); ioaddr = dev->base_addr; - lp = (struct ni5010_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); status = inb(IE_ISTAT); @@ -527,7 +527,7 @@ /* We have a good packet, get it out of the buffer. */ static void ni5010_rx(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; @@ -592,7 +592,7 @@ static int process_xmt_interrupt(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int xmit_stat; @@ -651,7 +651,7 @@ closed. */ static struct net_device_stats *ni5010_get_stats(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); @@ -693,7 +693,7 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; unsigned int buf_offs; diff -Nru a/drivers/net/oaknet.c b/drivers/net/oaknet.c --- a/drivers/net/oaknet.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/oaknet.c Sat Apr 3 19:38:54 2004 @@ -192,6 +192,9 @@ dev->open = oaknet_open; dev->stop = oaknet_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, FALSE); ret = register_netdev(dev); diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/pcmcia/3c574_cs.c Sat Apr 3 19:38:42 2004 @@ -283,7 +283,7 @@ dev = alloc_etherdev(sizeof(struct el3_private)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -388,7 +388,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; unsigned short buf[32]; @@ -733,7 +733,7 @@ /* Reset and restore all of the 3c574 registers. */ static void tc574_reset(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int i, ioaddr = dev->base_addr; unsigned long flags; @@ -814,7 +814,7 @@ static int el3_open(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; if (!DEV_OK(link)) @@ -837,7 +837,7 @@ static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); @@ -852,7 +852,7 @@ static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -877,7 +877,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " @@ -909,7 +909,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; int handled = 0; @@ -1002,7 +1002,7 @@ static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *) arg; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; unsigned long flags; unsigned short /* cable, */ media, partner; @@ -1074,7 +1074,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); if (netif_device_present(dev)) { unsigned long flags; @@ -1091,7 +1091,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u8 rx, tx, up; @@ -1128,7 +1128,7 @@ static int el3_rx(struct net_device *dev, int worklimit) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; short rx_status; @@ -1190,7 +1190,7 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = lp->phys & 0x1f; @@ -1259,7 +1259,7 @@ static int el3_close(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c --- a/drivers/net/pcmcia/3c589_cs.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/pcmcia/3c589_cs.c Sat Apr 3 19:38:56 2004 @@ -196,7 +196,7 @@ dev = alloc_etherdev(sizeof(struct el3_private)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -304,7 +304,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u16 buf[32], *phys_addr; @@ -526,7 +526,7 @@ */ static void tc589_set_xcvr(struct net_device *dev, int if_port) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; EL3WINDOW(0); @@ -648,7 +648,7 @@ static int el3_open(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; if (!DEV_OK(link)) @@ -672,7 +672,7 @@ static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name); @@ -687,7 +687,7 @@ static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -741,7 +741,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr, status; int i = 0, handled = 1; @@ -826,7 +826,7 @@ static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u16 media, errs; unsigned long flags; @@ -906,7 +906,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; dev_link_t *link = &lp->link; @@ -928,7 +928,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -955,7 +955,7 @@ static int el3_rx(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int worklimit = 32; short rx_status; @@ -1009,7 +1009,7 @@ static void set_multicast_list(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; u16 opts = SetRxFilter | RxStation | RxBroadcast; @@ -1024,7 +1024,7 @@ static int el3_close(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; diff -Nru a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c --- a/drivers/net/pcmcia/com20020_cs.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/pcmcia/com20020_cs.c Sat Apr 3 19:38:43 2004 @@ -492,7 +492,7 @@ pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { int ioaddr = dev->base_addr; - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct arcnet_local *lp = dev->priv; ARCRESET; } } diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Sat Apr 3 19:38:45 2004 @@ -256,7 +256,7 @@ dev = alloc_etherdev(sizeof(local_info_t)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -394,7 +394,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - local_info_t *lp = dev->priv; + local_info_t *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -803,7 +803,7 @@ static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - local_info_t *lp = dev->priv; + local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr; unsigned short tx_stat, rx_stat; @@ -862,7 +862,7 @@ static void fjn_tx_timeout(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n", @@ -892,7 +892,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; short length = skb->len; @@ -966,7 +966,7 @@ static void fjn_reset(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -1052,7 +1052,7 @@ static void fjn_rx(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int boguscount = 10; /* 5 -> 10: by agy 19940922 */ @@ -1181,7 +1181,7 @@ static int fjn_open(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(4, "fjn_open('%s').\n", dev->name); @@ -1206,7 +1206,7 @@ static int fjn_close(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; @@ -1239,7 +1239,7 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev) { - local_info_t *lp = (local_info_t *)dev->priv; + local_info_t *lp = netdev_priv(dev); return &lp->stats; } /* fjn_get_stats */ @@ -1252,7 +1252,7 @@ static void set_rx_mode(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); u_char mc_filter[8]; /* Multicast hash filter */ u_long flags; int i; diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/pcmcia/ibmtr_cs.c Sat Apr 3 19:38:43 2004 @@ -178,7 +178,7 @@ link = &info->link; link->priv = info; - info->ti = dev->priv; + info->ti = netdev_priv(dev); link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 4; @@ -256,7 +256,7 @@ unregister_netdev(dev); { - struct tok_info *ti = (struct tok_info *)dev->priv; + struct tok_info *ti = netdev_priv(dev); del_timer_sync(&(ti->tr_timer)); } if (link->state & DEV_CONFIG) @@ -287,7 +287,7 @@ client_handle_t handle = link->handle; ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); tuple_t tuple; cisparse_t parse; win_req_t req; @@ -412,7 +412,7 @@ pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); if (link->win) { - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); iounmap((void *)ti->mmio); pcmcia_release_window(link->win); pcmcia_release_window(info->sram_win_handle); diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/pcmcia/pcnet_cs.c Sat Apr 3 19:38:55 2004 @@ -722,6 +722,10 @@ link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + if (register_netdev(dev) != 0) { printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n"); link->dev = NULL; diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c --- a/drivers/net/pcmcia/smc91c92_cs.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/pcmcia/smc91c92_cs.c Sat Apr 3 19:38:45 2004 @@ -327,7 +327,7 @@ dev = alloc_etherdev(sizeof(struct smc_private)); if (!dev) return NULL; - smc = dev->priv; + smc = netdev_priv(dev); link = &smc->link; link->priv = dev; @@ -483,7 +483,7 @@ static int mhz_3288_power(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); u_char tmp; /* Read the ISR twice... */ @@ -505,7 +505,7 @@ static int mhz_mfc_config(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_char buf[255]; @@ -618,7 +618,7 @@ static void mot_config(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; ioaddr_t iouart = link->io.BasePort2; @@ -894,7 +894,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -1069,7 +1069,7 @@ pcmcia_release_irq(link->handle, &link->irq); if (link->win) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); iounmap(smc->base); pcmcia_release_window(link->win); } @@ -1091,7 +1091,7 @@ { dev_link_t *link = args->client_data; struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); int i; DEBUG(1, "smc91c92_event(0x%06x)\n", event); @@ -1240,7 +1240,7 @@ static int smc_open(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link; #ifdef PCMCIA_DEBUG @@ -1277,7 +1277,7 @@ static int smc_close(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link; ioaddr_t ioaddr = dev->base_addr; @@ -1314,7 +1314,7 @@ static void smc_hardware_send_packet(struct net_device * dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); struct sk_buff *skb = smc->saved_skb; ioaddr_t ioaddr = dev->base_addr; u_char packet_no; @@ -1379,7 +1379,7 @@ static void smc_tx_timeout(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, " @@ -1394,7 +1394,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short num_pages; short time_out, ir; @@ -1460,7 +1460,7 @@ static void smc_tx_err(struct net_device * dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; @@ -1504,7 +1504,7 @@ static void smc_eph_irq(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short card_stats, ephs; @@ -1539,7 +1539,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr; u_short saved_bank, saved_pointer, mask, status; unsigned int handled = 1; @@ -1657,7 +1657,7 @@ static void smc_rx(struct net_device *dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int rx_status; int packet_length; /* Caution: not frame length, rather words @@ -1725,7 +1725,7 @@ static struct net_device_stats *smc_get_stats(struct net_device *dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); /* Nothing to update - the 91c92 is a pretty primative chip. */ return &smc->stats; } @@ -1765,7 +1765,7 @@ static void set_rx_mode(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); u_int multicast_table[ 2 ] = { 0, }; unsigned long flags; u_short rx_cfg_setting; @@ -1804,7 +1804,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (smc->cfg & CFG_MII_SELECT) return -EOPNOTSUPP; @@ -1830,7 +1830,7 @@ */ static void smc_set_xcvr(struct net_device *dev, int if_port) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short saved_bank; @@ -1855,7 +1855,7 @@ static void smc_reset(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); int i; DEBUG(0, "%s: smc91c92 reset called.\n", dev->name); @@ -1930,7 +1930,7 @@ static void media_check(u_long arg) { struct net_device *dev = (struct net_device *) arg; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; u_short link; @@ -2044,7 +2044,7 @@ static int smc_link_ok(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if (smc->cfg & CFG_MII_SELECT) { return mii_link_ok(&smc->mii_if); @@ -2109,7 +2109,7 @@ static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr) { u32 ethcmd; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; @@ -2202,7 +2202,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); struct mii_ioctl_data *mii; int rc = 0; u_short saved_bank; diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Sat Apr 3 19:38:43 2004 @@ -1666,6 +1666,7 @@ struct ethtool_drvinfo *info) { strcpy(info->driver, "xirc2ps_cs"); + sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr); } static struct ethtool_ops netdev_ethtool_ops = { diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/pcnet32.c Sat Apr 3 19:38:42 2004 @@ -51,6 +51,7 @@ #include #include #include +#include /* * PCI device identifiers for "new style" Linux PCI Device Drivers @@ -225,10 +226,12 @@ * v1.27b Sep 30 2002 Kent Yoder * Added timer for cable connection state changes. * v1.28 20 Feb 2004 Don Fry - * Jon Lewis , Chinmay Albal + * Jon Mason , Chinmay Albal * Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl. * Fixes bogus 'Bus master arbitration failure', pci_[un]map_single * length errors, and transmit hangs. Cleans up after errors in open. + * Jim Lewis added ethernet loopback test. + * Thomas Munck Steenholdt non-mii ioctl corrections. */ @@ -479,6 +482,14 @@ .reset = pcnet32_dwio_reset }; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pcnet32_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); +} +#endif static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1106,6 +1117,10 @@ dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pcnet32_poll_controller; +#endif + /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) goto err_free_consistent; @@ -1733,13 +1748,17 @@ if (!rx_in_place) { skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ - pci_dma_sync_single(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, (unsigned char *)(lp->rx_skbuff[entry]->tail), pkt_len,0); + pci_dma_sync_single_for_device(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); } lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c --- a/drivers/net/plip.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/plip.c Sat Apr 3 19:38:56 2004 @@ -280,7 +280,7 @@ static void plip_init_netdev(struct net_device *dev) { - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); /* Then, override parts of it */ dev->hard_start_xmit = plip_tx_packet; @@ -323,7 +323,7 @@ static void plip_kick_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (nl->is_deferred) schedule_work(&nl->immediate); @@ -366,7 +366,7 @@ static void plip_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; plip_func f; @@ -384,7 +384,7 @@ static void plip_timer_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (!(atomic_read (&nl->kill_timer))) { plip_interrupt (-1, dev, NULL); @@ -917,7 +917,7 @@ return; } - nl = (struct net_local *)dev->priv; + nl = netdev_priv(dev); rcv = &nl->rcv_data; spin_lock_irq (&nl->lock); @@ -961,7 +961,7 @@ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; if (netif_queue_stopped(dev)) @@ -1021,7 +1021,7 @@ unsigned short type, void *daddr, void *saddr, unsigned len) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); int ret; if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0) @@ -1033,7 +1033,7 @@ int plip_hard_header_cache(struct neighbour *neigh, struct hh_cache *hh) { - struct net_local *nl = (struct net_local *)neigh->dev->priv; + struct net_local *nl = neigh->dev->priv; int ret; if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) @@ -1057,7 +1057,7 @@ static int plip_open(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct in_device *in_dev; /* Grab the port */ @@ -1116,7 +1116,7 @@ static int plip_close(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; @@ -1163,7 +1163,7 @@ plip_preempt(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); /* Stand our ground if a datagram is on the wire */ if (nl->connection != PLIP_CN_NONE) { @@ -1179,7 +1179,7 @@ plip_wakeup(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (nl->port_owner) { /* Why are we being woken up? */ @@ -1207,7 +1207,7 @@ static struct net_device_stats * plip_get_stats(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct net_device_stats *r = &nl->enet_stats; return r; @@ -1216,7 +1216,7 @@ static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct plipconf *pc = (struct plipconf *) &rq->ifr_data; switch(pc->pcmd) { @@ -1288,7 +1288,7 @@ "which is fairly inefficient!\n", port->name); } - nl = dev->priv; + nl = netdev_priv(dev); nl->pardev = parport_register_device(port, name, plip_preempt, plip_wakeup, plip_interrupt, 0, dev); @@ -1348,7 +1348,7 @@ for (i=0; i < PLIP_MAX; i++) { if ((dev = dev_plip[i])) { - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); unregister_netdev(dev); if (nl->port_owner) parport_release(nl->pardev); diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/ppp_generic.c Sat Apr 3 19:38:55 2004 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -271,6 +272,8 @@ static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); +static struct class_simple *ppp_class; + /* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex(int proto) { @@ -804,15 +807,29 @@ printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (!err) { + ppp_class = class_simple_create(THIS_MODULE, "ppp"); + if (IS_ERR(ppp_class)) { + err = PTR_ERR(ppp_class); + goto out_chrdev; + } + class_simple_device_add(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); if (err) - unregister_chrdev(PPP_MAJOR, "ppp"); + goto out_class; } +out: if (err) printk(KERN_ERR "failed to register PPP device (%d)\n", err); return err; + +out_class: + class_simple_device_remove(MKDEV(PPP_MAJOR,0)); + class_simple_destroy(ppp_class); +out_chrdev: + unregister_chrdev(PPP_MAJOR, "ppp"); + goto out; } /* @@ -2545,6 +2562,8 @@ if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); devfs_remove("ppp"); + class_simple_device_remove(MKDEV(PPP_MAJOR, 0)); + class_simple_destroy(ppp_class); } /* diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c --- a/drivers/net/rrunner.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/rrunner.c Sat Apr 3 19:38:42 2004 @@ -108,7 +108,7 @@ goto out2; } - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -236,7 +236,7 @@ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct rr_private *rr = dev->priv; + struct rr_private *rr = netdev_priv(dev); if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ printk(KERN_ERR "%s: trying to unload running NIC\n", @@ -308,7 +308,7 @@ u32 start_pc; int i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; rr_load_firmware(dev); @@ -524,7 +524,7 @@ u32 sram_size, rev; int i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; rev = readl(®s->FwRev); @@ -595,7 +595,7 @@ int ecode = 0; short i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; spin_lock_irqsave(&rrpriv->lock, flags); @@ -761,7 +761,7 @@ struct rr_regs *regs; u32 tmp; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; while (prodidx != eidx){ @@ -960,7 +960,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; do { @@ -983,18 +983,26 @@ rx_skb = rrpriv->rx_skbuff[index]; - pci_dma_sync_single(rrpriv->pci_dev, desc->addr.addrlo, - pkt_len, PCI_DMA_FROMDEVICE); - if (pkt_len < PKT_COPY_THRESHOLD) { skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL){ printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); rrpriv->stats.rx_dropped++; goto defer; - }else + } else { + pci_dma_sync_single_for_cpu(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, pkt_len), rx_skb->data, pkt_len); + + pci_dma_sync_single_for_device(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + } }else{ struct sk_buff *newskb; @@ -1052,7 +1060,7 @@ struct net_device *dev = (struct net_device *)dev_id; u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; if (!(readl(®s->HostCtrl) & RR_INT)) @@ -1133,7 +1141,7 @@ static void rr_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; unsigned long flags; @@ -1160,7 +1168,7 @@ static int rr_open(struct net_device *dev) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct pci_dev *pdev = rrpriv->pci_dev; struct rr_regs *regs; int ecode = 0; @@ -1296,7 +1304,7 @@ short i; int len; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; printk("%s: dumping NIC TX rings\n", dev->name); @@ -1361,7 +1369,7 @@ netif_stop_queue(dev); - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; /* @@ -1418,7 +1426,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; struct ring_ctrl *txctrl; unsigned long flags; @@ -1488,7 +1496,7 @@ { struct rr_private *rrpriv; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); return(&rrpriv->stats); } @@ -1511,7 +1519,7 @@ u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; if (dev->flags & IFF_UP) @@ -1614,7 +1622,7 @@ unsigned int i; int error = -EOPNOTSUPP; - rrpriv = dev->priv; + rrpriv = netdev_priv(dev); switch(cmd){ case SIOCRRGFW: diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c --- a/drivers/net/sb1000.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/sb1000.c Sat Apr 3 19:38:41 2004 @@ -746,7 +746,7 @@ int ioaddr, ns; unsigned int skbsize; struct sk_buff *skb; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); struct net_device_stats *stats = &lp->stats; /* SB1000 frame constants */ @@ -905,7 +905,7 @@ char *name; unsigned char st[5]; int ioaddr[2]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00}; const int ErrorDpcCounterInitialize = 200; @@ -932,7 +932,7 @@ { char *name; int ioaddr[2], status; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned short FirmwareVersion[] = {0x01, 0x01}; ioaddr[0] = dev->base_addr; @@ -998,7 +998,7 @@ short PID[4]; int ioaddr[2], status, frequency; unsigned int stats[5]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); if (!(dev && dev->flags & IFF_UP)) return -ENODEV; @@ -1092,7 +1092,7 @@ unsigned char st; int ioaddr[2]; struct net_device *dev = (struct net_device *) dev_id; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; @@ -1148,7 +1148,7 @@ static struct net_device_stats *sb1000_stats(struct net_device *dev) { - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1156,7 +1156,7 @@ { int i; int ioaddr[2]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); if (sb1000_debug > 2) printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name); diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c --- a/drivers/net/sb1250-mac.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/sb1250-mac.c Sat Apr 3 19:38:55 2004 @@ -2080,7 +2080,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv); + struct sbmac_softc *sc = netdev_priv(dev); uint64_t isr; int handled = 0; @@ -2150,7 +2150,7 @@ ********************************************************************* */ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); /* lock eth irq */ spin_lock_irq (&sc->sbm_lock); @@ -2374,7 +2374,7 @@ int i; int err; - sc = (struct sbmac_softc *)dev->priv; + sc = netdev_priv(dev); /* Determine controller base address */ @@ -2454,7 +2454,7 @@ static int sbmac_open(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); if (debug > 1) { printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); @@ -2609,7 +2609,7 @@ static void sbmac_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); int next_tick = HZ; int mii_status; @@ -2655,7 +2655,7 @@ static void sbmac_tx_timeout (struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); spin_lock_irq (&sc->sbm_lock); @@ -2673,7 +2673,7 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&sc->sbm_lock, flags); @@ -2691,7 +2691,7 @@ { unsigned long flags; int msg_flag = 0; - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); spin_lock_irqsave(&sc->sbm_lock, flags); if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) { @@ -2726,7 +2726,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); u16 *data = (u16 *)&rq->ifr_data; unsigned long flags; int retval; @@ -2762,7 +2762,7 @@ static int sbmac_close(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; int irq; @@ -2911,7 +2911,7 @@ for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; if (!dev) { - struct sbmac_softc *sc = dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unregister_netdev(dev); sbmac_uninitctx(sc); free_netdev(dev); diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/seeq8005.c Sat Apr 3 19:38:54 2004 @@ -357,7 +357,7 @@ */ static int seeq8005_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); { int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev); @@ -390,7 +390,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short length = skb->len; unsigned char *buf; @@ -424,7 +424,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); status = inw(SEEQ_STATUS); do { @@ -462,7 +462,7 @@ /* We have a good packet(s), get it/them out of the buffers. */ static void seeq8005_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount = 10; int pkt_hdr; int ioaddr = dev->base_addr; @@ -561,7 +561,7 @@ /* The inverse routine to net_open(). */ static int seeq8005_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->open_time = 0; @@ -583,7 +583,7 @@ closed. */ static struct net_device_stats *seeq8005_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -618,7 +618,7 @@ void seeq8005_init(struct net_device *dev, int startp) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int i; diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c --- a/drivers/net/sgiseeq.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/sgiseeq.c Sat Apr 3 19:38:55 2004 @@ -151,7 +151,7 @@ static int seeq_init_ring(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; volatile struct sgiseeq_init_block *ib = &sp->srings; int i; @@ -423,7 +423,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; struct hpc3_ethregs *hregs = sp->hregs; struct sgiseeq_regs *sregs = sp->sregs; @@ -445,7 +445,7 @@ static int sgiseeq_open(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv; + struct sgiseeq_private *sp = dev->priv; struct sgiseeq_regs *sregs = sp->sregs; int err = init_seeq(dev, sp, sregs); @@ -459,7 +459,7 @@ static int sgiseeq_close(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; struct sgiseeq_regs *sregs = sp->sregs; netif_stop_queue(dev); @@ -472,7 +472,7 @@ static inline int sgiseeq_reset(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; struct sgiseeq_regs *sregs = sp->sregs; int err; @@ -494,7 +494,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; struct hpc3_ethregs *hregs = sp->hregs; unsigned long flags; struct sgiseeq_tx_desc *td; @@ -560,7 +560,7 @@ static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = dev->priv; return &sp->stats; } @@ -710,7 +710,7 @@ struct net_device *next, *dev = root_sgiseeq_dev; while (dev) { - sp = (struct sgiseeq_private *) dev->priv; + sp = dev->priv; next = sp->next_module; unregister_netdev(dev); free_irq(dev->irq, dev); diff -Nru a/drivers/net/sis190.c b/drivers/net/sis190.c --- a/drivers/net/sis190.c Sat Apr 3 19:38:57 2004 +++ b/drivers/net/sis190.c Sat Apr 3 19:38:57 2004 @@ -1016,14 +1016,20 @@ int pkt_size; pkt_size = (int) (desc->PSize & 0x0000FFFF) - 4; - pci_dma_sync_single(tp->pci_dev, desc->buf_addr, - RX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb = dev_alloc_skb(pkt_size + 2); if (skb != NULL) { skb->dev = dev; skb_reserve(skb, 2); // 16 byte align the IP fields. // + pci_dma_sync_single_for_cpu(tp->pci_dev, + desc->buf_addr, + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], pkt_size, 0); + pci_dma_sync_single_for_device(tp->pci_dev, + desc->buf_addr, + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/sis900.c Sat Apr 3 19:38:43 2004 @@ -1650,9 +1650,6 @@ break; } - pci_dma_sync_single(sis_priv->pci_dev, - sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); pci_unmap_single(sis_priv->pci_dev, sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/sk98lin/skge.c Sat Apr 3 19:38:41 2004 @@ -2533,12 +2533,6 @@ "Control: %x\nRxStat: %x\n", Control, FrameStat)); - PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; - PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_dma_sync_single(pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); @@ -2559,12 +2553,16 @@ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_dma_sync_single(pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); + pci_dma_sync_single_for_device(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); diff -Nru a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c --- a/drivers/net/sk98lin/skgepnmi.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/sk98lin/skgepnmi.c Sat Apr 3 19:38:54 2004 @@ -7684,7 +7684,7 @@ to the low-power state. A miniport driver must always return NDIS_STATUS_SUCCESS to a query of OID_PNP_QUERY_POWER. */ - *pLen = sizeof(SK_DEVICE_POWER_STATE);; + *pLen = sizeof(SK_DEVICE_POWER_STATE); RetCode = SK_PNMI_ERR_OK; break; diff -Nru a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c --- a/drivers/net/sk_g16.c Sat Apr 3 19:38:57 2004 +++ b/drivers/net/sk_g16.c Sat Apr 3 19:38:57 2004 @@ -650,7 +650,7 @@ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ - struct priv *p = dev->priv; /* SK_G16 private structure */ + struct priv *p = netdev_priv(dev); /* SK_G16 private structure */ if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH) return -ENODEV; @@ -869,7 +869,7 @@ int irqtab[] = SK_IRQS; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -1023,7 +1023,7 @@ { int i; unsigned long flags; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct tmd *tmdp; struct rmd *rmdp; @@ -1196,7 +1196,7 @@ static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct tmd *tmdp; static char pad[64]; @@ -1285,7 +1285,7 @@ { int csr0; struct net_device *dev = dev_id; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", @@ -1355,7 +1355,7 @@ { int tmdstat; struct tmd *tmdp; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_txintr() status: %#06x\n", @@ -1469,7 +1469,7 @@ struct rmd *rmdp; int rmdstat; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -1653,7 +1653,7 @@ static struct net_device_stats *SK_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -2030,7 +2030,7 @@ { int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); printk("## %s: RAM Details.\n" "## RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n", diff -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c --- a/drivers/net/smc-mca.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/smc-mca.c Sat Apr 3 19:38:41 2004 @@ -324,6 +324,9 @@ dev->open = &ultramca_open; dev->stop = &ultramca_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); diff -Nru a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c --- a/drivers/net/smc-ultra.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/smc-ultra.c Sat Apr 3 19:38:41 2004 @@ -121,6 +121,14 @@ #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ultra_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. @@ -134,6 +142,9 @@ SET_MODULE_OWNER(dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &ultra_poll; +#endif if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -301,6 +312,9 @@ ei_status.reset_8390 = &ultra_reset_8390; dev->open = &ultra_open; dev->stop = &ultra_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c --- a/drivers/net/smc-ultra32.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/smc-ultra32.c Sat Apr 3 19:38:55 2004 @@ -268,6 +268,9 @@ ei_status.reset_8390 = &ultra32_reset_8390; dev->open = &ultra32_open; dev->stop = &ultra32_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c --- a/drivers/net/smc9194.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/smc9194.c Sat Apr 3 19:38:54 2004 @@ -465,7 +465,7 @@ */ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; word length; unsigned short numPages; @@ -576,7 +576,7 @@ */ static void smc_hardware_send_packet( struct net_device * dev ) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; @@ -1150,7 +1150,7 @@ { struct net_device *dev = dev_id; int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte status; word card_stats; @@ -1274,7 +1274,7 @@ */ static void smc_rcv(struct net_device *dev) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int packet_number; word status; @@ -1401,7 +1401,7 @@ static void smc_tx( struct net_device * dev ) { int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte saved_packet; byte packet_no; word tx_status; @@ -1474,7 +1474,7 @@ . This may be called with the card open or closed. .-------------------------------------------------------------*/ static struct net_device_stats* smc_query_statistics(struct net_device *dev) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c --- a/drivers/net/starfire.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/starfire.c Sat Apr 3 19:38:42 2004 @@ -1637,10 +1637,13 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pci_dev, - np->rx_info[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(np->pci_dev, + np->rx_info[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); + pci_dma_sync_single_for_device(np->pci_dev, + np->rx_info[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); } else { pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); diff -Nru a/drivers/net/stnic.c b/drivers/net/stnic.c --- a/drivers/net/stnic.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/stnic.c Sat Apr 3 19:38:45 2004 @@ -20,7 +20,7 @@ #include #include -#include +#include #include #ifdef CONFIG_SH_STANDARD_BIOS #include @@ -124,6 +124,9 @@ dev->irq = IRQ_STNIC; dev->open = &stnic_open; dev->stop = &stnic_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c --- a/drivers/net/sun3lance.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/sun3lance.c Sat Apr 3 19:38:55 2004 @@ -332,7 +332,7 @@ return 0; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); /* XXX - leak? */ MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); @@ -402,7 +402,7 @@ static int lance_open( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int i; DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); @@ -439,7 +439,7 @@ static void lance_init_ring( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int i; lp->lock = 0; @@ -499,7 +499,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int entry, len; struct lance_tx_head *head; unsigned long flags; @@ -646,7 +646,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) { struct net_device *dev = dev_id; - struct lance_private *lp = dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; static int in_interrupt; @@ -772,7 +772,7 @@ /* get packet, toss into skbuff */ static int lance_rx( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int entry = lp->new_rx; /* If we own the next entry, it's a new packet. Send it up. */ @@ -870,7 +870,7 @@ static int lance_close( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -888,7 +888,7 @@ static struct net_device_stats *lance_get_stats( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -904,7 +904,7 @@ /* completely untested on a sun3 */ static void set_multicast_list( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); if(netif_queue_stopped(dev)) /* Only possible if board is already started */ diff -Nru a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c --- a/drivers/net/sunbmac.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/sunbmac.c Sat Apr 3 19:38:43 2004 @@ -849,9 +849,13 @@ copy_skb->dev = bp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - sbus_dma_sync_single(bp->bigmac_sdev, - this->rx_addr, len, SBUS_DMA_FROMDEVICE); + sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); + sbus_dma_sync_single_for_device(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); /* Reuse original ring buffer. */ this->rx_flags = diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/sundance.c Sat Apr 3 19:38:44 2004 @@ -1331,9 +1331,6 @@ if (netif_msg_rx_status(np)) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", frame_status); - pci_dma_sync_single(np->pci_dev, desc->frag[0].addr, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - if (frame_status & 0x001f4000) { /* There was a error. */ if (netif_msg_rx_err(np)) @@ -1363,7 +1360,16 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(np->pci_dev, + desc->frag[0].addr, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + pci_dma_sync_single_for_device(np->pci_dev, + desc->frag[0].addr, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); } else { pci_unmap_single(np->pci_dev, diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/sungem.c Sat Apr 3 19:38:56 2004 @@ -763,8 +763,9 @@ copy_skb->dev = gp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - pci_dma_sync_single(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + pci_dma_sync_single_for_device(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c --- a/drivers/net/sunhme.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/sunhme.c Sat Apr 3 19:38:42 2004 @@ -273,8 +273,10 @@ ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir))) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -297,8 +299,10 @@ sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -320,8 +324,10 @@ pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #endif #endif @@ -2069,8 +2075,9 @@ copy_skb->dev = dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE); + hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); /* Reuse original ring buffer. */ hme_write_rxd(hp, this, @@ -2838,7 +2845,10 @@ hp->write_rxd = sbus_hme_write_rxd; hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_device; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -3182,7 +3192,10 @@ hp->write_rxd = pci_hme_write_rxd; hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_device; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif diff -Nru a/drivers/net/sunhme.h b/drivers/net/sunhme.h --- a/drivers/net/sunhme.h Sat Apr 3 19:38:43 2004 +++ b/drivers/net/sunhme.h Sat Apr 3 19:38:43 2004 @@ -406,7 +406,8 @@ void (*write_rxd)(struct happy_meal_rxd *, u32, u32); u32 (*dma_map)(void *, void *, long, int); void (*dma_unmap)(void *, u32, long, int); - void (*dma_sync)(void *, u32, long, int); + void (*dma_sync_for_cpu)(void *, u32, long, int); + void (*dma_sync_for_device)(void *, u32, long, int); #endif /* This is either a sbus_dev or a pci_dev. */ diff -Nru a/drivers/net/sunlance.c b/drivers/net/sunlance.c --- a/drivers/net/sunlance.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/sunlance.c Sat Apr 3 19:38:42 2004 @@ -313,7 +313,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; dma_addr_t aib = lp->init_block_dvma; __u32 leptr; @@ -370,7 +370,7 @@ static void lance_init_ring_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; u32 leptr; int i; @@ -500,7 +500,7 @@ static void lance_rx_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; u8 bits; @@ -563,7 +563,7 @@ static void lance_tx_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int i, j; @@ -673,7 +673,7 @@ static void lance_rx_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; @@ -735,7 +735,7 @@ static void lance_tx_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int i, j; @@ -816,7 +816,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; sbus_writew(LE_CSR0, lp->lregs + RAP); @@ -915,7 +915,7 @@ static int lance_open(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int status = 0; @@ -968,7 +968,7 @@ static int lance_close(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); netif_stop_queue(dev); del_timer_sync(&lp->multicast_timer); @@ -981,7 +981,7 @@ static int lance_reset(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); int status; STOP_LANCE(lp); @@ -1102,7 +1102,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", dev->name, sbus_readw(lp->lregs + RDP)); @@ -1112,7 +1112,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; @@ -1165,7 +1165,7 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1173,7 +1173,7 @@ /* taken from the depca driver */ static void lance_load_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *) &ib->filter; struct dev_mc_list *dmi = dev->mc_list; @@ -1223,7 +1223,7 @@ static void lance_set_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; u16 mode; @@ -1291,7 +1291,7 @@ /* Ethtool support... */ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = netdev_priv(dev); strcpy(info->driver, "sunlance"); strcpy(info->version, "2.02"); @@ -1325,7 +1325,7 @@ if (!dev) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); if (sparc_lance_debug && version_printed++ == 0) printk (KERN_INFO "%s", version); diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/tg3.c Sat Apr 3 19:38:44 2004 @@ -2280,8 +2280,9 @@ copy_skb->dev = tp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; @@ -2466,6 +2467,13 @@ static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tg3_poll_controller(struct net_device *dev) +{ + tg3_interrupt(dev->irq, dev, NULL); +} +#endif + static void tg3_reset_task(void *_data) { struct tg3 *tp = _data; @@ -7614,6 +7622,9 @@ dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tg3_poll_controller; +#endif err = tg3_get_invariants(tp); if (err) { diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/tlan.c Sat Apr 3 19:38:41 2004 @@ -814,6 +814,14 @@ } /* TLan_EisaProbe */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void TLan_Poll(struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif @@ -893,6 +901,9 @@ dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_Poll; +#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c --- a/drivers/net/tokenring/3c359.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/tokenring/3c359.c Sat Apr 3 19:38:56 2004 @@ -937,15 +937,17 @@ while (xl_priv->rx_ring_tail != temp_ring_loc) { copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; frame_length -= copy_len ; - pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; + pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; } /* Now we have found the last fragment */ - pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; /* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ + pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; skb->protocol = tr_type_trans(skb,dev) ; netif_rx(skb) ; diff -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c --- a/drivers/net/tokenring/abyss.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/tokenring/abyss.c Sat Apr 3 19:38:42 2004 @@ -154,7 +154,7 @@ printk(":%2.2x", dev->dev_addr[i]); printk("\n"); - tp = dev->priv; + tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; tp->sifreadb = abyss_sifreadb; tp->sifreadw = abyss_sifreadw; @@ -188,7 +188,7 @@ static unsigned short abyss_setnselout_pins(struct net_device *dev) { unsigned short val = 0; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->DataRate == SPEED_4) val |= 0x01; /* Set 4Mbps */ @@ -398,7 +398,7 @@ unsigned short val; int i; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); ioaddr = dev->base_addr; /* Must enable glue chip first */ diff -Nru a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c --- a/drivers/net/tokenring/madgemc.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tokenring/madgemc.c Sat Apr 3 19:38:55 2004 @@ -365,7 +365,7 @@ return 0; return -1; } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); /* * The MC16 is physically a 32bit card. However, Madge @@ -504,7 +504,7 @@ unsigned short madgemc_setnselout_pins(struct net_device *dev) { unsigned char reg1; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); reg1 = inb(dev->base_addr + MC_CONTROL_REG1); @@ -731,7 +731,7 @@ } len += sprintf(buf+len, "-------\n"); if (curcard) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int i; len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c Sat Apr 3 19:38:54 2004 +++ b/drivers/net/tokenring/olympic.c Sat Apr 3 19:38:54 2004 @@ -842,10 +842,13 @@ olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; netif_rx(skb2) ; } else { - pci_dma_sync_single(olympic_priv->pdev, + pci_dma_sync_single_for_cpu(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; + pci_dma_sync_single_for_device(olympic_priv->pdev, + le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), + olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; skb->protocol = tr_type_trans(skb,dev) ; netif_rx(skb) ; } @@ -854,12 +857,15 @@ olympic_priv->rx_ring_last_received++ ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); rx_ring_last_received = olympic_priv->rx_ring_last_received ; - pci_dma_sync_single(olympic_priv->pdev, + pci_dma_sync_single_for_cpu(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ; + pci_dma_sync_single_for_device(olympic_priv->pdev, + le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), + olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; } while (--i) ; skb_trim(skb,skb->len-4) ; skb->protocol = tr_type_trans(skb,dev); diff -Nru a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c --- a/drivers/net/tokenring/proteon.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/tokenring/proteon.c Sat Apr 3 19:38:56 2004 @@ -158,7 +158,7 @@ printk(":%2.2x", dev->dev_addr[j]); printk("\n"); - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; tp->sifreadb = proteon_sifreadb; @@ -316,7 +316,7 @@ static int proteon_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short val = 0; int i; diff -Nru a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c --- a/drivers/net/tokenring/skisa.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/tokenring/skisa.c Sat Apr 3 19:38:41 2004 @@ -175,7 +175,7 @@ printk(":%2.2x", dev->dev_addr[j]); printk("\n"); - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; tp->sifreadb = sk_isa_sifreadb; @@ -332,7 +332,7 @@ static int sk_isa_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short val = 0; unsigned short oldval; int i; diff -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c --- a/drivers/net/tokenring/smctr.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/tokenring/smctr.c Sat Apr 3 19:38:43 2004 @@ -327,7 +327,7 @@ */ static int smctr_alloc_shared_memory(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_alloc_shared_memory\n", dev->name); @@ -454,7 +454,7 @@ static int smctr_checksum_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 i, checksum = 0; if(smctr_debug > 10) @@ -477,10 +477,10 @@ return (0); } -static int smctr_chk_mca(struct net_device *dev) +static int __init smctr_chk_mca(struct net_device *dev) { #ifdef CONFIG_MCA - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int current_slot; __u8 r1, r2, r3, r4, r5; @@ -631,7 +631,7 @@ static int smctr_chg_rx_mask(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -694,7 +694,7 @@ static int smctr_clear_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); outb((tp->trc_mask | CSR_CLRTINT), dev->base_addr + CSR); @@ -716,7 +716,7 @@ */ static int smctr_close(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sk_buff *skb; int err; @@ -752,7 +752,7 @@ static int smctr_decode_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); short bit = 0x80, shift = 12; DECODE_TREE_NODE *tree; short branch, tsize; @@ -823,7 +823,7 @@ */ static int smctr_disable_adapter_ctrl_store(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(smctr_debug > 10) @@ -837,7 +837,7 @@ static int smctr_disable_bic_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; tp->trc_mask = CSR_MSK_ALL | CSR_MSKCBUSY @@ -849,7 +849,7 @@ static int smctr_enable_16bit(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u8 r; if(tp->adapter_bus == BUS_ISA16_TYPE) @@ -869,7 +869,7 @@ */ static int smctr_enable_adapter_ctrl_store(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(smctr_debug > 10) @@ -900,7 +900,7 @@ static int smctr_enable_bic_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r; @@ -926,7 +926,7 @@ static int __init smctr_chk_isa(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r1, r2, b, chksum = 0; __u16 r; @@ -1155,7 +1155,7 @@ static int __init smctr_get_boardid(struct net_device *dev, int mca) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r, r1, IdByte; __u16 BoardIdMask; @@ -1273,7 +1273,7 @@ */ static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int mem_used = 0; /* Allocate System Control Blocks. */ @@ -1358,7 +1358,7 @@ static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); BDBlock *bdb; bdb = (BDBlock *)((__u32)tp->ram_access @@ -1382,7 +1382,7 @@ */ static struct net_device_stats *smctr_get_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); return ((struct net_device_stats *)&tp->MacStat); } @@ -1390,7 +1390,7 @@ static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue, __u16 bytes_count) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *pFCB; BDBlock *pbdb; unsigned short alloc_size; @@ -1513,7 +1513,7 @@ static int smctr_init_acbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; ACBlock *acb; @@ -1557,7 +1557,7 @@ static int smctr_init_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(smctr_debug > 10) @@ -1640,7 +1640,7 @@ static int smctr_init_card_real(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -1716,7 +1716,7 @@ static int smctr_init_rx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; BDBlock *bdb; __u16 *buf; @@ -1768,7 +1768,7 @@ static int smctr_init_rx_fcbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; @@ -1818,7 +1818,7 @@ static int smctr_init_shared_memory(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; __u32 *iscpb; @@ -1876,7 +1876,7 @@ static int smctr_init_tx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; BDBlock *bdb; @@ -1906,7 +1906,7 @@ static int smctr_init_tx_fcbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; @@ -1945,7 +1945,7 @@ static int smctr_internal_self_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_issue_test_internal_rom_cmd(dev))) @@ -1998,7 +1998,7 @@ } ioaddr = dev->base_addr; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); if(tp->status == NOT_INITIALIZED) @@ -2471,7 +2471,7 @@ static int smctr_issue_enable_int_cmd(struct net_device *dev, __u16 interrupt_enable_mask) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2487,7 +2487,7 @@ static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ibits) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_wait_while_cbusy(dev)) return (-1); @@ -2503,7 +2503,7 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; int err; __u16 *pTimer_Struc = (__u16 *)tp->misc_command_data; @@ -2660,7 +2660,7 @@ static int smctr_issue_init_txrx_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; int err; void **txrx_ptrs = (void *)tp->misc_command_data; @@ -2748,7 +2748,7 @@ static int smctr_issue_remove_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2764,7 +2764,7 @@ static int smctr_issue_resume_acb_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2782,7 +2782,7 @@ static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2802,7 +2802,7 @@ static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_issue_resume_rx_fcb_cmd\n", dev->name); @@ -2824,7 +2824,7 @@ static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_issue_resume_tx_fcb_cmd\n", dev->name); @@ -2893,7 +2893,7 @@ static int smctr_issue_write_byte_cmd(struct net_device *dev, short aword_cnt, void *byte) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int iword, ibyte; int err; @@ -2917,7 +2917,7 @@ static int smctr_issue_write_word_cmd(struct net_device *dev, short aword_cnt, void *word) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, err; if((err = smctr_wait_while_cbusy(dev))) @@ -2947,7 +2947,7 @@ static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; BDBlock *bdb; @@ -2971,7 +2971,7 @@ static int smctr_load_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 i, checksum = 0; int err = 0; @@ -3071,7 +3071,7 @@ */ static int smctr_lobe_media_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, perror = 0; unsigned short saved_rcv_mask; @@ -3146,7 +3146,7 @@ static int smctr_lobe_media_test_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(smctr_debug > 10) @@ -3230,7 +3230,7 @@ static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = AUTHORIZED_ACCESS_PRIORITY; tsv->svl = S_AUTHORIZED_ACCESS_PRIORITY; @@ -3255,7 +3255,7 @@ static int smctr_make_auth_funct_class(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = AUTHORIZED_FUNCTION_CLASS; tsv->svl = S_AUTHORIZED_FUNCTION_CLASS; @@ -3280,7 +3280,7 @@ static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_functional_address(dev); @@ -3298,7 +3298,7 @@ static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_group_address(dev); @@ -3324,7 +3324,7 @@ static int smctr_make_phy_drop_num(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_physical_drop_number(dev); @@ -3355,7 +3355,7 @@ static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_station_id(dev); @@ -3393,7 +3393,7 @@ static int smctr_make_ring_station_version(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = RING_STATION_VERSION_NUMBER; tsv->svl = S_RING_STATION_VERSION_NUMBER; @@ -3433,7 +3433,7 @@ static int smctr_make_upstream_neighbor_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_upstream_neighbor_addr(dev); @@ -3485,7 +3485,7 @@ /* Interrupt driven open of Token card. */ static int smctr_open_tr(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned long flags; int err; @@ -3618,7 +3618,7 @@ return dev; out1: #ifdef CONFIG_MCA - { struct net_local *tp = (struct net_local *)dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } @@ -3634,7 +3634,7 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); int err; __u32 *ram; @@ -3654,7 +3654,7 @@ } } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); dev->mem_start = tp->ram_base; dev->mem_end = dev->mem_start + 0x10000; ram = (__u32 *)phys_to_virt(dev->mem_start); @@ -3696,7 +3696,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, struct net_device *dev, __u16 rx_status) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sk_buff *skb; __u16 rcode, correlator; int err = 0; @@ -3917,7 +3917,7 @@ /* Adapter RAM test. Incremental word ODD boundary data test. */ static int smctr_ram_memory_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 page, pages_of_ram, start_pattern = 0, word_pattern = 0, word_read = 0, err_word = 0, err_pattern = 0; unsigned int err_offset; @@ -4310,7 +4310,7 @@ */ static int smctr_reset_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Reseting the NIC will put it in a halted and un-initialized state. */ smctr_set_trc_reset(ioaddr); @@ -4329,7 +4329,7 @@ static int smctr_restart_tx_chain(struct net_device *dev, short queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -4347,7 +4347,7 @@ static int smctr_ring_status_chg(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_ring_status_chg\n", dev->name); @@ -4449,7 +4449,7 @@ static int smctr_rx_frame(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 queue, status, rx_size, err = 0; __u8 *pbuff; @@ -4516,7 +4516,7 @@ static int smctr_send_dat(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, err; MAC_HEADER *tmf; FCBlock *fcb; @@ -4596,7 +4596,7 @@ */ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_send_packet\n", dev->name); @@ -4621,7 +4621,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); MAC_SUB_VECTOR *tsv; MAC_HEADER *tmf; FCBlock *fcb; @@ -4917,7 +4917,7 @@ static int smctr_send_rq_init(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); MAC_HEADER *tmf; MAC_SUB_VECTOR *tsv; FCBlock *fcb; @@ -5001,7 +5001,7 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf, __u16 *tx_fstatus) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *fcb; unsigned int i; int err; @@ -5065,7 +5065,7 @@ static int smctr_set_auth_access_pri(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_AUTHORIZED_ACCESS_PRIORITY) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5078,7 +5078,7 @@ static int smctr_set_auth_funct_class(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_AUTHORIZED_FUNCTION_CLASS) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5139,7 +5139,7 @@ static int smctr_set_local_ring_num(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_LOCAL_RING_NUMBER) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5153,7 +5153,7 @@ static unsigned short smctr_set_ctrl_attention(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(tp->bic_type == BIC_585_CHIP) @@ -5177,7 +5177,7 @@ static int smctr_set_page(struct net_device *dev, __u8 *buf) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u8 amask; __u32 tptr; @@ -5207,7 +5207,7 @@ */ static int smctr_set_ring_speed(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(tp->media_type == MEDIA_UTP_16) @@ -5235,7 +5235,7 @@ static int smctr_set_rx_look_ahead(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 sword, rword; if(smctr_debug > 10) @@ -5278,7 +5278,7 @@ static int smctr_setup_single_cmd(struct net_device *dev, __u16 command, __u16 subcommand) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int err; if(smctr_debug > 10) @@ -5305,7 +5305,7 @@ static int smctr_setup_single_cmd_w_data(struct net_device *dev, __u16 command, __u16 subcommand) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->acb_head->cmd_done_status = ACB_COMMAND_NOT_DONE; tp->acb_head->cmd = command; @@ -5318,7 +5318,7 @@ static char *smctr_malloc(struct net_device *dev, __u16 size) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); char *m; m = (char *)(tp->ram_access + tp->sh_mem_used); @@ -5329,7 +5329,7 @@ static int smctr_status_chg(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_status_chg\n", dev->name); @@ -5365,7 +5365,7 @@ static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -5386,7 +5386,7 @@ static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 status, err = 0; int cstatus; @@ -5441,7 +5441,7 @@ static unsigned short smctr_tx_move_frame(struct net_device *dev, struct sk_buff *skb, __u8 *pbuff, unsigned int bytes) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int ram_usable; __u32 flen, len, offset = 0; __u8 *frag, *page; @@ -5482,7 +5482,7 @@ /* Update the error statistic counters for this adapter. */ static int smctr_update_err_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct tr_statistics *tstat = &tp->MacStat; if(tstat->internal_errors) @@ -5524,7 +5524,7 @@ static int smctr_update_rx_chain(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *fcb; BDBlock *bdb; __u16 size, len; @@ -5562,7 +5562,7 @@ static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 20) printk(KERN_DEBUG "smctr_update_tx_chain\n"); @@ -5598,7 +5598,7 @@ static int smctr_wait_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int loop_count = 0x20000; if(smctr_debug > 10) @@ -5623,7 +5623,7 @@ static int smctr_wait_while_cbusy(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int timeout = 0x20000; int ioaddr = dev->base_addr; __u8 r; @@ -5686,7 +5686,7 @@ return dev; out1: #ifdef CONFIG_MCA - { struct net_local *tp = (struct net_local *)dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } @@ -5726,7 +5726,7 @@ unregister_netdev(dev); #ifdef CONFIG_MCA - { struct net_local *tp = dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } diff -Nru a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c --- a/drivers/net/tokenring/tms380tr.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/tokenring/tms380tr.c Sat Apr 3 19:38:44 2004 @@ -243,7 +243,7 @@ */ int tms380tr_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; /* init the spinlock */ @@ -313,7 +313,7 @@ static void tms380tr_timer_end_wait(unsigned long data) { struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->Sleeping) { @@ -329,7 +329,7 @@ */ static int tms380tr_chipset_init(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; tms380tr_init_ipb(tp); @@ -364,7 +364,7 @@ */ static void tms380tr_init_net_local(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int i; dma_addr_t dmabuf; @@ -492,7 +492,7 @@ unsigned short BufferSize = BUFFER_SIZE; int i; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->ocpl.OPENOptions = 0; tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; @@ -531,7 +531,7 @@ */ static void tms380tr_open_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->OpenCommandIssued) return; @@ -569,7 +569,7 @@ */ static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->CMDqueue |= Command; tms380tr_chk_outstanding_cmds(dev); @@ -596,7 +596,7 @@ */ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; err = tms380tr_hardware_send_packet(skb, dev); @@ -616,7 +616,7 @@ unsigned long flags; int i; dma_addr_t dmabuf, newbuf; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); /* Try to get a free TPL from the chain. * @@ -715,7 +715,7 @@ static void tms380tr_timer_chk(unsigned long data) { struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local*)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->HaltInProgress) return; @@ -755,7 +755,7 @@ return IRQ_NONE; } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); irq_type = SIFREADW(SIFSTS); @@ -843,7 +843,7 @@ */ static void tms380tr_reset_interrupt(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); SSB *ssb = &tp->ssb; /* @@ -929,7 +929,7 @@ */ static void tms380tr_cmd_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short ssb_cmd, ssb_parm_0; unsigned short ssb_parm_1; char *open_err = "Open error -"; @@ -1126,7 +1126,7 @@ */ int tms380tr_close(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); netif_stop_queue(dev); del_timer(&tp->timer); @@ -1172,7 +1172,7 @@ */ static struct net_device_stats *tms380tr_get_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); return ((struct net_device_stats *)&tp->MacStat); } @@ -1182,7 +1182,7 @@ */ static void tms380tr_set_multicast_list(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int OpenOptions; OpenOptions = tp->ocpl.OPENOptions & @@ -1275,7 +1275,7 @@ */ static int tms380tr_reset_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short *fw_ptr; unsigned short count, c, count2; const struct firmware *fw_entry = NULL; @@ -1428,7 +1428,7 @@ */ static int tms380tr_init_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, @@ -1541,7 +1541,7 @@ */ static void tms380tr_chk_outstanding_cmds(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned long Addr = 0; if(tp->CMDqueue == 0) @@ -1713,7 +1713,7 @@ */ static void tms380tr_ring_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]); @@ -1785,7 +1785,7 @@ { int i; unsigned short AdapterCheckBlock[4]; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->AdapterOpenFlag = 0; /* Adapter closed now */ @@ -1941,7 +1941,7 @@ */ static int tms380tr_read_ptr(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short adapterram; tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, @@ -2031,7 +2031,7 @@ */ static void tms380tr_tx_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned char HighByte, HighAc, LowAc; TPL *tpl; @@ -2102,7 +2102,7 @@ */ static void tms380tr_rcv_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned char *ReceiveDataPtr; struct sk_buff *skb; unsigned int Length, Length2; @@ -2293,7 +2293,7 @@ static int tms380tr_set_mac_address(struct net_device *dev, void *addr) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sockaddr *saddr = addr; if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { @@ -2327,7 +2327,7 @@ { struct net_local *tp; - tp = (struct net_local *) dev->priv; + tp = netdev_priv(dev); pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL); } @@ -2338,7 +2338,7 @@ struct net_local *tms_local; memset(dev->priv, 0, sizeof(struct net_local)); - tms_local = (struct net_local *)dev->priv; + tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); tms_local->dmalimit = dmalimit; tms_local->pdev = pdev; diff -Nru a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c --- a/drivers/net/tulip/21142.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/tulip/21142.c Sat Apr 3 19:38:42 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -29,7 +29,7 @@ void t21142_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr12 = inl(ioaddr + CSR12); int next_tick = 60*HZ; @@ -103,7 +103,7 @@ void t21142_start_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14 = ((tp->sym_advertise & 0x0780) << 9) | ((tp->sym_advertise & 0x0020) << 1) | 0xffbf; @@ -131,7 +131,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr12 = inl(ioaddr + CSR12); diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tulip/de2104x.c Sat Apr 3 19:38:55 2004 @@ -28,8 +28,8 @@ */ #define DRV_NAME "de2104x" -#define DRV_VERSION "0.6" -#define DRV_RELDATE "Sep 1, 2003" +#define DRV_VERSION "0.7" +#define DRV_RELDATE "Mar 17, 2004" #include #include @@ -303,7 +303,6 @@ struct net_device_stats net_stats; struct pci_dev *pdev; - u32 macmode; u16 setup_frame[DE_SETUP_FRAME_WORDS]; @@ -457,10 +456,12 @@ buflen, PCI_DMA_FROMDEVICE); de->rx_skb[rx_tail].skb = copy_skb; } else { - pci_dma_sync_single(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); memcpy(skb_put(copy_skb, len), skb->tail, len); + pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); + /* We'll reuse the original ring buffer. */ skb = copy_skb; } @@ -730,7 +731,7 @@ struct de_desc *txd; struct de_desc *dummy_txd = NULL; - macmode = de->macmode & ~(AcceptAllMulticast | AcceptAllPhys); + macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ macmode |= AcceptAllMulticast | AcceptAllPhys; @@ -803,10 +804,8 @@ dw32(TxPoll, NormalTxPoll); out: - if (macmode != de->macmode) { - dw32 (MacMode, macmode); - de->macmode = macmode; - } + if (macmode != dr32(MacMode)) + dw32(MacMode, macmode); } static void de_set_rx_mode (struct net_device *dev) @@ -921,6 +920,7 @@ static void de_set_media (struct de_private *de) { unsigned media = de->media_type; + u32 macmode = dr32(MacMode); if (de_is_running(de)) BUG(); @@ -938,9 +938,9 @@ mdelay(10); if (media == DE_MEDIA_TP_FD) - de->macmode |= FullDuplex; + macmode |= FullDuplex; else - de->macmode &= ~FullDuplex; + macmode &= ~FullDuplex; if (netif_msg_link(de)) { printk(KERN_INFO "%s: set link %s\n" @@ -949,9 +949,11 @@ de->dev->name, media_name[media], de->dev->name, dr32(MacMode), dr32(SIAStatus), dr32(CSR13), dr32(CSR14), dr32(CSR15), - de->dev->name, de->macmode, de->media[media].csr13, + de->dev->name, macmode, de->media[media].csr13, de->media[media].csr14, de->media[media].csr15); } + if (macmode != dr32(MacMode)) + dw32(MacMode, macmode); } static void de_next_media (struct de_private *de, u32 *media, @@ -1171,18 +1173,18 @@ u32 status, tmp; /* - * Reset MAC. Copied from de4x5.c. + * Reset MAC. de4x5.c and tulip.c examined for "advice" + * in this area. */ - tmp = dr32 (BusMode); - if (tmp == 0xffffffff) - return -ENODEV; - mdelay (1); + if (dr32(BusMode) == 0xffffffff) + return -EBUSY; - dw32 (BusMode, tmp | CmdReset); + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + dw32 (BusMode, CmdReset); mdelay (1); - dw32 (BusMode, tmp); + dw32 (BusMode, de_bus_mode); mdelay (1); for (tmp = 0; tmp < 5; tmp++) { @@ -1233,11 +1235,12 @@ static int de_init_hw (struct de_private *de) { struct net_device *dev = de->dev; + u32 macmode; int rc; de_adapter_wake(de); - de->macmode = dr32(MacMode) & ~MacModeClear; + macmode = dr32(MacMode) & ~MacModeClear; rc = de_reset_mac(de); if (rc) @@ -1248,7 +1251,7 @@ dw32(RxRingAddr, de->ring_dma); dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE)); - dw32(MacMode, RxTx | de->macmode); + dw32(MacMode, RxTx | macmode); dr32(RxMissed); /* self-clearing */ @@ -1499,7 +1502,7 @@ break; } - if (de->macmode & FullDuplex) + if (dr32(MacMode) & FullDuplex) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/tulip/de4x5.c Sat Apr 3 19:38:40 2004 @@ -1086,7 +1086,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) { char name[DE4X5_NAME_LENGTH + 1]; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; @@ -1294,7 +1294,7 @@ static int de4x5_open(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, status = 0; s32 omr; @@ -1384,7 +1384,7 @@ static int de4x5_sw_reset(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, j, status = 0; s32 bmr, omr; @@ -1462,7 +1462,7 @@ static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int status = 0; u_long flags = 0; @@ -1551,7 +1551,7 @@ printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq); return IRQ_NONE; } - lp = (struct de4x5_private *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); iobase = dev->base_addr; @@ -1610,7 +1610,7 @@ static int de4x5_rx(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int entry; s32 status; @@ -1701,7 +1701,7 @@ static int de4x5_tx(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int entry; s32 status; @@ -1753,7 +1753,7 @@ static int de4x5_ast(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; disable_ast(dev); @@ -1776,7 +1776,7 @@ static int de4x5_txur(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int omr; @@ -1799,7 +1799,7 @@ static int de4x5_rx_ovfc(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int omr; @@ -1820,7 +1820,7 @@ static int de4x5_close(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 imr, omr; @@ -1856,7 +1856,7 @@ static struct net_device_stats * de4x5_get_stats(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR)); @@ -1867,7 +1867,7 @@ static void de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=1; ipriv; + struct de4x5_private *lp = netdev_priv(dev); int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1); dma_addr_t buf_dma = dma_map_single(lp->gendev, buf, flags & TD_TBS1, DMA_TO_DEVICE); @@ -1927,7 +1927,7 @@ static void set_multicast_list(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; /* First, double check that the adapter is open */ @@ -1957,7 +1957,7 @@ static void SetMulticastFilter(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct dev_mc_list *dmi=dev->mc_list; u_long iobase = dev->base_addr; int i, j, bit, byte; @@ -2036,7 +2036,7 @@ status = -ENOMEM; goto release_reg_2; } - lp = dev->priv; + lp = netdev_priv(dev); cfid = (u32) inl(PCI_CFID); lp->cfrv = (u_short) inl(PCI_CFRV); @@ -2142,7 +2142,7 @@ u_int irq = 0, device; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j, cfrv; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct list_head *walk = &pdev->bus_list; for (walk = walk->next; walk != &pdev->bus_list; walk = walk->next) { @@ -2245,7 +2245,7 @@ if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); lp->bus = PCI; lp->bus_num = 0; @@ -2374,7 +2374,7 @@ static int autoconf_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; @@ -2415,7 +2415,7 @@ static int dc21040_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; s32 imr; @@ -2488,7 +2488,7 @@ int next_state, int suspect_state, int (*fn)(struct net_device *, int)) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; int linkBad; @@ -2527,7 +2527,7 @@ int (*fn)(struct net_device *, int), int (*asfn)(struct net_device *)) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; int linkBad; @@ -2569,7 +2569,7 @@ static int dc21041_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, irqs, irq_mask, imr, omr; int next_tick = DE4X5_AUTOSENSE_MS; @@ -2771,7 +2771,7 @@ static int dc21140m_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int ana, anlpa, cap, cr, slnk, sr; int next_tick = DE4X5_AUTOSENSE_MS; u_long imr, omr, iobase = dev->base_addr; @@ -2955,7 +2955,7 @@ static int dc2114x_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts; int next_tick = DE4X5_AUTOSENSE_MS; @@ -3206,7 +3206,7 @@ static int srom_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); return lp->infoleaf_fn(dev); } @@ -3219,7 +3219,7 @@ static int srom_map_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); lp->fdx = 0; if (lp->infoblock_media == lp->media) @@ -3284,7 +3284,7 @@ static void de4x5_init_connection(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; u_long flags = 0; @@ -3313,7 +3313,7 @@ static int de4x5_reset_phy(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = 0; @@ -3347,7 +3347,7 @@ static int test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, csr12; @@ -3385,7 +3385,7 @@ static int test_tp(struct net_device *dev, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int sisr; @@ -3414,7 +3414,7 @@ static int test_for_100Mb(struct net_device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK); if (lp->timeout < 0) { @@ -3445,7 +3445,7 @@ static int wait_for_link(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->timeout < 0) { lp->timeout = 1; @@ -3467,7 +3467,7 @@ static int test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int test; u_long iobase = dev->base_addr; @@ -3491,7 +3491,7 @@ static int is_spd_100(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int spd; @@ -3515,7 +3515,7 @@ static int is_100_up(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->useMII) { @@ -3536,7 +3536,7 @@ static int is_10_up(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->useMII) { @@ -3559,7 +3559,7 @@ static int is_anc_capable(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { @@ -3578,7 +3578,7 @@ static int ping_media(struct net_device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int sisr; @@ -3619,7 +3619,7 @@ static struct sk_buff * de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; #if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) @@ -3667,7 +3667,7 @@ static void de4x5_free_rx_buffs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=0; irxRingSize; i++) { @@ -3684,7 +3684,7 @@ static void de4x5_free_tx_buffs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=0; itxRingSize; i++) { @@ -3711,7 +3711,7 @@ static void de4x5_save_skbs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 omr; @@ -3732,7 +3732,7 @@ static void de4x5_rst_desc_ring(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i; s32 omr; @@ -3765,7 +3765,7 @@ static void de4x5_cache_state(struct net_device *dev, int flag) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; switch(flag) { @@ -3795,7 +3795,7 @@ static void de4x5_put_cache(struct net_device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; if (lp->cache.skb) { @@ -3812,7 +3812,7 @@ static void de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p = lp->cache.skb; lp->cache.skb = skb; @@ -3824,7 +3824,7 @@ static struct sk_buff * de4x5_get_cache(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p = lp->cache.skb; if (p) { @@ -3842,7 +3842,7 @@ static int test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, ans; @@ -3870,7 +3870,7 @@ static void de4x5_setup_intr(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 imr, sts; @@ -3891,7 +3891,7 @@ static void reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; RESET_SIA; @@ -4014,7 +4014,7 @@ DevicePresent(struct net_device *dev, u_long aprom_addr) { int i, j=0; - struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->chipset == DC21040) { if (lp->bus == EISA) { @@ -4095,7 +4095,7 @@ u_long iobase = dev->base_addr; int broken, i, k, tmp, status = 0; u_short j,chksum; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); broken = de4x5_bad_srom(lp); @@ -4210,7 +4210,7 @@ static void srom_repair(struct net_device *dev, int card) { - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); switch(card) { case SMC: @@ -4231,7 +4231,7 @@ static int test_bad_enet(struct net_device *dev, int status) { - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i, tmp; for (tmp=0,i=0; idev_addr[i]; @@ -4384,7 +4384,7 @@ static int srom_infoleaf_info(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i, count; u_char *p; @@ -4432,7 +4432,7 @@ static void srom_init(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; u_char count; @@ -4477,7 +4477,7 @@ static void srom_exec(struct net_device *dev, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; u_char count = (p ? *p++ : 0); u_short *w = (u_short *)p; @@ -4514,7 +4514,7 @@ static int dc21140_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4552,7 +4552,7 @@ static int dc21142_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4587,7 +4587,7 @@ static int dc21143_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4625,7 +4625,7 @@ static int compact_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6; /* Recursively figure out the info blocks */ @@ -4665,7 +4665,7 @@ static int type0_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6, len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4705,7 +4705,7 @@ static int type1_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4744,7 +4744,7 @@ static int type2_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4785,7 +4785,7 @@ static int type3_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4827,7 +4827,7 @@ static int type4_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6, len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4872,7 +4872,7 @@ static int type5_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -5072,7 +5072,7 @@ static int mii_get_phy(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table); int id; @@ -5136,7 +5136,7 @@ static char * build_setup_frame(struct net_device *dev, int mode) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; char *pa = lp->setup_frame; @@ -5176,7 +5176,7 @@ static void disable_ast(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); del_timer(&lp->timer); @@ -5186,7 +5186,7 @@ static long de4x5_switch_mac_port(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 omr; @@ -5222,7 +5222,7 @@ static void gep_wr(s32 data, struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->chipset == DC21140) { @@ -5237,7 +5237,7 @@ static int gep_rd(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->chipset == DC21140) { @@ -5252,7 +5252,7 @@ static void timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int dt; /* First, cancel any pending timer events */ @@ -5275,7 +5275,7 @@ static void yawn(struct net_device *dev, int state) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return; @@ -5321,7 +5321,7 @@ static void de4x5_parse_params(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); char *p, *q, t; lp->params.fdx = 0; @@ -5364,7 +5364,7 @@ static void de4x5_dbg_open(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; if (de4x5_debug & DEBUG_OPEN) { @@ -5415,7 +5415,7 @@ static void de4x5_dbg_mii(struct net_device *dev, int k) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (de4x5_debug & DEBUG_MII) { @@ -5443,7 +5443,7 @@ static void de4x5_dbg_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->media != lp->c_media) { if (de4x5_debug & DEBUG_MEDIA) { @@ -5534,7 +5534,7 @@ static int de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; u_long iobase = dev->base_addr; int i, j, status = 0; diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tulip/dmfe.c Sat Apr 3 19:38:55 2004 @@ -392,7 +392,7 @@ } /* Init system & device */ - db = dev->priv; + db = netdev_priv(dev); /* Allocate Tx/Rx descriptor memory */ db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); @@ -466,7 +466,7 @@ static void __devexit dmfe_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_remove_one()", 0); @@ -494,7 +494,7 @@ static int dmfe_open(struct DEVICE *dev) { int ret; - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_open", 0); @@ -552,7 +552,7 @@ static void dmfe_init_dm910x(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = db->ioaddr; DMFE_DBUG(0, "dmfe_init_dm910x()", 0); @@ -618,7 +618,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); struct tx_desc *txptr; unsigned long flags; @@ -687,7 +687,7 @@ static int dmfe_stop(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); @@ -730,7 +730,7 @@ static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct DEVICE *dev = dev_id; - struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -957,7 +957,7 @@ static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev) { - struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_get_stats", 0); return &db->stats; @@ -970,7 +970,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; DMFE_DBUG(0, "dmfe_set_filter_mode()", 0); @@ -1003,7 +1003,7 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct dmfe_board_info *np = dev->priv; + struct dmfe_board_info *np = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -1028,7 +1028,7 @@ u32 tmp_cr8; unsigned char tmp_cr12; struct DEVICE *dev = (struct DEVICE *) data; - struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; DMFE_DBUG(0, "dmfe_timer()", 0); @@ -1160,7 +1160,7 @@ static void dmfe_dynamic_reset(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_dynamic_reset()", 0); @@ -1358,7 +1358,7 @@ static void send_filter_frame(struct DEVICE *dev, int mc_cnt) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); struct dev_mc_list *mcptr; struct tx_desc *txptr; u16 * addrptr; diff -Nru a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c --- a/drivers/net/tulip/eeprom.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tulip/eeprom.c Sat Apr 3 19:38:55 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -136,7 +136,7 @@ static struct mediatable *last_mediatable; static unsigned char *last_ee_data; static int controller_index; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned char *ee_data = tp->eeprom; int i; diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c --- a/drivers/net/tulip/interrupt.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/tulip/interrupt.c Sat Apr 3 19:38:42 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -63,7 +63,7 @@ int tulip_refill_rx(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry; int refilled = 0; @@ -109,7 +109,7 @@ int tulip_poll(struct net_device *dev, int *budget) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = *budget; int received = 0; @@ -191,9 +191,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(tp->pdev, - tp->rx_buffers[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, pkt_len, 0); @@ -203,6 +203,9 @@ tp->rx_buffers[entry].skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); } else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len); @@ -354,7 +357,7 @@ static int tulip_rx(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; int received = 0; @@ -412,9 +415,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(tp->pdev, - tp->rx_buffers[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, pkt_len, 0); @@ -424,6 +427,9 @@ tp->rx_buffers[entry].skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); } else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len); @@ -465,7 +471,7 @@ { #ifdef __hppa__ int csr12 = inl(dev->base_addr + CSR12) & 0xff; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); if (csr12 != tp->csr12_shadow) { /* ack interrupt */ @@ -490,7 +496,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr5; int missed; diff -Nru a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c --- a/drivers/net/tulip/media.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/tulip/media.c Sat Apr 3 19:38:42 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -48,7 +48,7 @@ int tulip_mdio_read(struct net_device *dev, int phy_id, int location) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location; int retval = 0; @@ -111,7 +111,7 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff); long ioaddr = dev->base_addr; @@ -171,7 +171,7 @@ void tulip_select_media(struct net_device *dev, int startup) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); struct mediatable *mtable = tp->mtable; u32 new_csr6; int i; @@ -374,7 +374,7 @@ */ int tulip_check_duplex(struct net_device *dev) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned int bmsr, lpa, negotiated, new_csr6; bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); @@ -420,7 +420,7 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); int phyn, phy_idx = 0; int mii_reg0; int mii_advert; diff -Nru a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c --- a/drivers/net/tulip/pnic.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/tulip/pnic.c Sat Apr 3 19:38:45 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -20,7 +20,7 @@ void pnic_do_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; u32 phy_reg = inl(ioaddr + 0xB8); u32 new_csr6 = tp->csr6 & ~0x40C40200; @@ -53,7 +53,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int phy_reg = inl(ioaddr + 0xB8); @@ -89,7 +89,7 @@ void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; diff -Nru a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c --- a/drivers/net/tulip/pnic2.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/tulip/pnic2.c Sat Apr 3 19:38:41 2004 @@ -9,7 +9,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -84,7 +84,7 @@ void pnic2_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; @@ -100,7 +100,7 @@ void pnic2_start_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14; int csr12; @@ -175,7 +175,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14; diff -Nru a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c --- a/drivers/net/tulip/timer.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/tulip/timer.c Sat Apr 3 19:38:40 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -20,7 +20,7 @@ void tulip_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; u32 csr12 = inl(ioaddr + CSR12); int next_tick = 2*HZ; @@ -135,7 +135,7 @@ void mxic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; @@ -152,7 +152,7 @@ void comet_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; diff -Nru a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h --- a/drivers/net/tulip/tulip.h Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tulip/tulip.h Sat Apr 3 19:38:55 2004 @@ -7,7 +7,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/tulip/tulip_core.c Sat Apr 3 19:38:44 2004 @@ -8,7 +8,7 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver, or visit the project Web page at http://sourceforge.net/projects/tulip/ @@ -253,8 +253,9 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); - - +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_tulip(struct net_device *dev); +#endif static void tulip_set_power_state (struct tulip_private *tp, int sleep, int snooze) @@ -276,7 +277,7 @@ static void tulip_up(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 3*HZ; int i; @@ -499,7 +500,7 @@ static void tulip_tx_timeout(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned long flags; @@ -587,7 +588,7 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void tulip_init_ring(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; tp->susp_rx = 0; @@ -638,7 +639,7 @@ static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry; u32 flag; dma_addr_t mapping; @@ -724,7 +725,7 @@ static void tulip_down (struct net_device *dev) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned long flags; del_timer_sync (&tp->timer); @@ -764,7 +765,7 @@ static int tulip_close (struct net_device *dev) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; netif_stop_queue (dev); @@ -811,7 +812,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -830,7 +831,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { - struct tulip_private *np = dev->priv; + struct tulip_private *np = netdev_priv(dev); u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) @@ -855,7 +856,7 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; const unsigned int phy_idx = 0; @@ -964,7 +965,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); u16 hash_table[32]; struct dev_mc_list *mclist; int i; @@ -995,7 +996,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); struct dev_mc_list *mclist; int i; u16 *eaddrs; @@ -1023,7 +1024,7 @@ static void set_rx_mode(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr6; @@ -1150,7 +1151,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, struct net_device *dev) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); u8 cache; u16 pci_command; u32 csr0; @@ -1373,7 +1374,7 @@ * initialize private data structure 'tp' * it is zeroed and aligned in alloc_etherdev */ - tp = dev->priv; + tp = netdev_priv(dev); tp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct tulip_rx_desc) * RX_RING_SIZE + @@ -1618,6 +1619,9 @@ dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_tulip; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1756,7 +1760,7 @@ if (!dev) return; - tp = dev->priv; + tp = netdev_priv(dev); pci_free_consistent (pdev, sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, @@ -1774,6 +1778,22 @@ /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { .name = DRV_NAME, diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/tulip/winbond-840.c Sat Apr 3 19:38:41 2004 @@ -1289,9 +1289,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pci_dev,np->rx_addr[entry], - np->rx_skbuff[entry]->len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], + np->rx_skbuff[entry]->len, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if HAS_IP_COPYSUM eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1300,6 +1300,9 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry], + np->rx_skbuff[entry]->len, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, diff -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c --- a/drivers/net/tulip/xircom_cb.c Sat Apr 3 19:38:55 2004 +++ b/drivers/net/tulip/xircom_cb.c Sat Apr 3 19:38:55 2004 @@ -178,7 +178,7 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct xircom_private *private = dev->priv; + struct xircom_private *private = netdev_priv(dev); strcpy(info->driver, "xircom_cb"); strcpy(info->bus_info, pci_name(private->pdev)); @@ -235,7 +235,7 @@ printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); goto device_fail; } - private = dev->priv; + private = netdev_priv(dev); /* Allocate the send/receive buffers */ private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); @@ -312,7 +312,7 @@ static void __devexit xircom_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct xircom_private *card = dev->priv; + struct xircom_private *card = netdev_priv(dev); enter("xircom_remove"); pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); @@ -328,7 +328,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct xircom_private *card = (struct xircom_private *) dev->priv; + struct xircom_private *card = netdev_priv(dev); unsigned int status; int i; @@ -385,7 +385,7 @@ int desc; enter("xircom_start_xmit"); - card = (struct xircom_private*)dev->priv; + card = netdev_priv(dev); spin_lock_irqsave(&card->lock,flags); /* First see if we can free some descriptors */ @@ -444,7 +444,7 @@ static int xircom_open(struct net_device *dev) { - struct xircom_private *xp = (struct xircom_private *) dev->priv; + struct xircom_private *xp = netdev_priv(dev); int retval; enter("xircom_open"); printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); @@ -466,7 +466,7 @@ unsigned long flags; enter("xircom_close"); - card = dev->priv; + card = netdev_priv(dev); netif_stop_queue(dev); /* we don't want new packets */ @@ -495,7 +495,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev) { - struct xircom_private *card = (struct xircom_private *)dev->priv; + struct xircom_private *card = netdev_priv(dev); return &card->stats; } diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/tun.c Sat Apr 3 19:38:43 2004 @@ -70,7 +70,7 @@ /* Net device start xmit */ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len); @@ -113,14 +113,14 @@ static struct net_device_stats *tun_net_stats(struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); return &tun->stats; } /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: @@ -153,7 +153,7 @@ /* Poll */ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; unsigned int mask = POLLOUT | POLLWRNORM; if (!tun) @@ -169,7 +169,7 @@ return mask; } -/* Get packet from user space buffer(already verified) */ +/* Get packet from user space buffer */ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count) { struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; @@ -180,7 +180,8 @@ if ((len -= sizeof(pi)) > len) return -EINVAL; - memcpy_fromiovec((void *)&pi, iv, sizeof(pi)); + if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi))) + return -EFAULT; } if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { @@ -189,7 +190,8 @@ } skb_reserve(skb, 2); - memcpy_fromiovec(skb_put(skb, len), iv, len); + if (memcpy_fromiovec(skb_put(skb, len), iv, len)) + return -EFAULT; skb->dev = tun->dev; switch (tun->flags & TUN_TYPE_MASK) { @@ -213,26 +215,29 @@ return count; } +static inline size_t iov_total(const struct iovec *iv, unsigned long count) +{ + unsigned long i; + size_t len; + + for (i = 0, len = 0; i < count; i++) + len += iv[i].iov_len; + + return len; +} + /* Writev */ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, unsigned long count, loff_t *pos) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; - unsigned long i; - size_t len; + struct tun_struct *tun = file->private_data; if (!tun) return -EBADFD; DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); - for (i = 0, len = 0; i < count; i++) { - if (verify_area(VERIFY_READ, iv[i].iov_base, iv[i].iov_len)) - return -EFAULT; - len += iv[i].iov_len; - } - - return tun_get_user(tun, (struct iovec *) iv, len); + return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count)); } /* Write */ @@ -243,7 +248,7 @@ return tun_chr_writev(file, &iv, 1, pos); } -/* Put packet to the user space buffer (already verified) */ +/* Put packet to the user space buffer */ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, struct sk_buff *skb, struct iovec *iv, int len) @@ -260,7 +265,8 @@ pi.flags |= TUN_PKT_STRIP; } - memcpy_toiovec(iv, (void *) &pi, sizeof(pi)); + if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) + return -EFAULT; total += sizeof(pi); } @@ -279,22 +285,17 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, unsigned long count, loff_t *pos) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; - unsigned long i; if (!tun) return -EBADFD; DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); - for (i = 0, len = 0; i < count; i++) { - if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len)) - return -EFAULT; - len += iv[i].iov_len; - } + len = iov_total(iv, count); if (len < 0) return -EINVAL; @@ -341,7 +342,7 @@ static void tun_setup(struct net_device *dev) { - struct tun_struct *tun = dev->priv; + struct tun_struct *tun = netdev_priv(dev); skb_queue_head_init(&tun->readq); init_waitqueue_head(&tun->read_wait); @@ -413,7 +414,7 @@ if (!dev) return -ENOMEM; - tun = dev->priv; + tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; @@ -455,7 +456,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; if (cmd == TUNSETIFF && !tun) { struct ifreq ifr; @@ -527,7 +528,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; int ret; if (!tun) @@ -558,7 +559,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; if (!tun) return 0; @@ -602,21 +603,22 @@ static struct miscdevice tun_miscdev = { .minor = TUN_MINOR, - .name = "net/tun", - .fops = &tun_fops + .name = "tun", + .fops = &tun_fops, + .devfs_name = "net/tun", }; int __init tun_init(void) { + int ret = 0; + printk(KERN_INFO "Universal TUN/TAP device driver %s " "(C)1999-2002 Maxim Krasnyansky\n", TUN_VER); - if (misc_register(&tun_miscdev)) { + ret = misc_register(&tun_miscdev); + if (ret) printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR); - return -EIO; - } - - return 0; + return ret; } void tun_cleanup(void) diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c --- a/drivers/net/typhoon.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/typhoon.c Sat Apr 3 19:38:45 2004 @@ -1318,7 +1318,7 @@ tp->rxHiRing.ringBase = (u8 *) tp->shared->rxHi; tp->rxBuffRing.ringBase = (u8 *) tp->shared->rxBuff; tp->cmdRing.ringBase = (u8 *) tp->shared->cmd; - tp->respRing.ringBase = (u8 *) tp->shared->resp;; + tp->respRing.ringBase = (u8 *) tp->shared->resp; tp->txLoRing.writeRegister = TYPHOON_REG_TX_LO_READY; tp->txHiRing.writeRegister = TYPHOON_REG_TX_HI_READY; @@ -1701,9 +1701,13 @@ (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) { new_skb->dev = tp->dev; skb_reserve(new_skb, 2); - pci_dma_sync_single(tp->pdev, dma_addr, PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, + PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0); + pci_dma_sync_single_for_device(tp->pdev, dma_addr, + PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); skb_put(new_skb, pkt_len); typhoon_recycle_rx_skb(tp, idx); } else { diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/via-rhine.c Sat Apr 3 19:38:56 2004 @@ -615,6 +615,15 @@ break; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, (void *)dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -784,6 +793,9 @@ dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1524,7 +1536,7 @@ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry], + pci_dma_sync_single_for_cpu(np->pdev, np->rx_skbuff_dma[entry], np->rx_buf_sz, PCI_DMA_FROMDEVICE); /* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum @@ -1537,6 +1549,8 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pdev, np->rx_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); } else { skb = np->rx_skbuff[entry]; if (skb == NULL) { diff -Nru a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c --- a/drivers/net/wan/comx-hw-locomx.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/wan/comx-hw-locomx.c Sat Apr 3 19:38:45 2004 @@ -77,7 +77,7 @@ static int LOCOMX_txe(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; return (!hw->board.chanA.tx_next_skb); @@ -86,8 +86,8 @@ static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb) { - struct net_device *dev=c->netdevice; - struct comx_channel *ch=dev->priv; + struct net_device *dev = c->netdevice; + struct comx_channel *ch = netdev_priv(dev); if (ch->debug_flags & DEBUG_HW_RX) { comx_debug_skb(dev, skb, "locomx_rx receiving"); @@ -97,7 +97,7 @@ static int LOCOMX_send_packet(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; if (ch->debug_flags & DEBUG_HW_TX) { @@ -126,9 +126,9 @@ static void locomx_status_timerfun(unsigned long d) { - struct net_device *dev=(struct net_device *)d; - struct comx_channel *ch=dev->priv; - struct locomx_data *hw=ch->HW_privdata; + struct net_device *dev = (struct net_device *)d; + struct comx_channel *ch = netdev_priv(dev); + struct locomx_data *hw = ch->HW_privdata; if(!(ch->line_status & LINE_UP) && (hw->board.chanA.status & CTS)) { @@ -144,7 +144,7 @@ static int LOCOMX_open(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; unsigned long flags; @@ -256,7 +256,7 @@ static int LOCOMX_close(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; @@ -376,7 +376,7 @@ static int LOCOMX_init(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw; struct proc_dir_entry *new_file; @@ -449,7 +449,7 @@ static int LOCOMX_exit(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); ch->HW_access_board = NULL; ch->HW_release_board = NULL; diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c --- a/drivers/net/wan/comx-hw-munich.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/wan/comx-hw-munich.c Sat Apr 3 19:38:42 2004 @@ -373,7 +373,7 @@ void rework_idle_channels(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board = slicecom_boards + hw->boardnum; munich_ccb_t *ccb = board->ccb; @@ -731,7 +731,7 @@ { munich_board_t *board = (munich_board_t *) b; struct net_device *dev = board->twins[0]; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); unsigned long regs; regs = readl((void *)(&board->bar1[GPDATA])); @@ -765,7 +765,7 @@ static int MUNICH_txe(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; return (hw->busy < TX_DESC_MAX - 1); @@ -905,7 +905,7 @@ #if 0 static int slicecom_reset(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); printk("slicecom_reset: resetting the hardware\n"); @@ -933,7 +933,7 @@ static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; /* Send it to the debug facility too if needed: */ @@ -1085,7 +1085,7 @@ goto go_for_next_interrupt; } - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; // printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n", @@ -1125,7 +1125,7 @@ if (dev != NULL) { - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; rx_status = hw->rx_desc[hw->rx_desc_ptr].status; @@ -1261,7 +1261,7 @@ goto go_for_next_tx_interrupt; } - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; // printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr ); @@ -1295,7 +1295,7 @@ { int newbusy; - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; /* We don't trust the "Tx available" info from the TIQ, but check */ @@ -1398,7 +1398,7 @@ static int MUNICH_open(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; munich_board_t *board; @@ -1891,7 +1891,7 @@ static int MUNICH_close(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; munich_board_t *board; @@ -2028,7 +2028,7 @@ static int MUNICH_minden(struct net_device *dev, char *page) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; struct net_device *devp; @@ -2290,7 +2290,7 @@ { struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; @@ -2388,7 +2388,7 @@ { struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; @@ -2656,7 +2656,7 @@ static int BOARD_init(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw; struct proc_dir_entry *new_file; @@ -2772,7 +2772,7 @@ */ static int BOARD_exit(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); /* Free private data area */ // board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); diff -Nru a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c --- a/drivers/net/wan/comx.c Sat Apr 3 19:38:43 2004 +++ b/drivers/net/wan/comx.c Sat Apr 3 19:38:43 2004 @@ -379,7 +379,7 @@ static struct net_device_stats *comx_stats(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = dev->priv; return ch->current_stats; } @@ -535,7 +535,7 @@ { struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; - struct comx_channel *ch=(struct comx_channel *)dev->priv; + struct comx_channel *ch = dev->priv; int len = 0; if (strcmp(file->name, FILENAME_STATUS) == 0) { @@ -599,7 +599,7 @@ { struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch=(struct comx_channel *)dev->priv; + struct comx_channel *ch = dev->priv; char *page; struct comx_hardware *hw = comx_channels; struct comx_protocol *line = comx_lines; @@ -821,7 +821,7 @@ if (register_netdevice(dev)) { goto cleanup_filename_debug; } - ch=dev->priv; + ch = dev->priv; if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), GFP_KERNEL)) == NULL) { goto cleanup_register; diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c --- a/drivers/net/wan/cosa.c Sat Apr 3 19:38:40 2004 +++ b/drivers/net/wan/cosa.c Sat Apr 3 19:38:40 2004 @@ -807,7 +807,7 @@ { DECLARE_WAITQUEUE(wait, current); unsigned long flags; - struct channel_data *chan = (struct channel_data *)file->private_data; + struct channel_data *chan = file->private_data; struct cosa_data *cosa = chan->cosa; char *kbuf; @@ -881,7 +881,7 @@ const char *buf, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); - struct channel_data *chan = (struct channel_data *)file->private_data; + struct channel_data *chan = file->private_data; struct cosa_data *cosa = chan->cosa; unsigned long flags; char *kbuf; @@ -990,7 +990,7 @@ static int cosa_release(struct inode *inode, struct file *file) { - struct channel_data *channel = (struct channel_data *)file->private_data; + struct channel_data *channel = file->private_data; struct cosa_data *cosa; unsigned long flags; @@ -1205,7 +1205,7 @@ int cmd) { int rv; - struct channel_data *chan = (struct channel_data *)dev->priv; + struct channel_data *chan = dev->priv; rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data); if (rv == -ENOIOCTLCMD) { return sppp_do_ioctl(dev, ifr, cmd); @@ -1216,7 +1216,7 @@ static int cosa_chardev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct channel_data *channel = (struct channel_data *)file->private_data; + struct channel_data *channel = file->private_data; struct cosa_data *cosa = channel->cosa; return cosa_ioctl_common(cosa, channel, cmd, arg); } diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c --- a/drivers/net/wan/dscc4.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/wan/dscc4.c Sat Apr 3 19:38:42 2004 @@ -652,7 +652,6 @@ goto refill; } pkt_len = TO_SIZE(rx_fd->state2); - pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); if ((skb->data[--pkt_len] & FrameOk) == FrameOk) { stats->rx_packets++; diff -Nru a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c --- a/drivers/net/wan/lapbether.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/wan/lapbether.c Sat Apr 3 19:38:42 2004 @@ -198,7 +198,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb) { - struct lapbethdev *lapbeth = ndev->priv; + struct lapbethdev *lapbeth = netdev_priv(ndev); unsigned char *ptr; struct net_device *dev; int size = skb->len; @@ -269,7 +269,7 @@ */ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) { - struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv; + struct lapbethdev *lapbeth = netdev_priv(dev); return &lapbeth->stats; } @@ -278,7 +278,7 @@ */ static int lapbeth_set_mac_address(struct net_device *dev, void *addr) { - struct sockaddr *sa = (struct sockaddr *)addr; + struct sockaddr *sa = addr; memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); return 0; } @@ -355,7 +355,7 @@ if (!ndev) goto out; - lapbeth = ndev->priv; + lapbeth = netdev_priv(ndev); lapbeth->axdev = ndev; dev_hold(dev); @@ -397,7 +397,7 @@ unsigned long event, void *ptr) { struct lapbethdev *lapbeth; - struct net_device *dev = (struct net_device *)ptr; + struct net_device *dev = ptr; if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c --- a/drivers/net/wan/pc300_drv.c Sat Apr 3 19:38:56 2004 +++ b/drivers/net/wan/pc300_drv.c Sat Apr 3 19:38:56 2004 @@ -3661,7 +3661,7 @@ release_mem_region(card->hw.falcphys, card->hw.falcsize); } for (i = 0; i < card->hw.nchan; i++) - if (card->chan[i].d.dev); + if (card->chan[i].d.dev) free_netdev(card->chan[i].d.dev); if (card->hw.irq) free_irq(card->hw.irq, card); diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c --- a/drivers/net/wd.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/wd.c Sat Apr 3 19:38:41 2004 @@ -333,6 +333,9 @@ ei_status.get_8390_hdr = &wd_get_8390_hdr; dev->open = &wd_open; dev->stop = &wd_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); #if 1 diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig --- a/drivers/net/wireless/Kconfig Sat Apr 3 19:38:42 2004 +++ b/drivers/net/wireless/Kconfig Sat Apr 3 19:38:42 2004 @@ -307,6 +307,54 @@ It has basic support for Linux wireless extensions and initial micro support for ethtool. +comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support" + depends on NET_RADIO && PCI +config PRISM54 + tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' + depends on PCI && NET_RADIO && EXPERIMENTAL && HOTPLUG + select FW_LOADER + ---help--- + Enable PCI and Cardbus support for the following chipset based cards: + + ISL3880 - Prism GT 802.11 b/g + ISL3877 - Prism Indigo 802.11 a + ISL3890 - Prism Duette 802.11 a/b/g + + For a complete list of supported cards visit . + Here is the latest confirmed list of supported cards: + + 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 + Allnet ALL0271 PCI Card + Compex WL54G Cardbus Card + Corega CG-WLCB54GT Cardbus Card + D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 + I-O Data WN-G54/CB Cardbus Card + Kobishi XG-300 aka Z-Com Cardbus Card + Netgear WG511 Cardbus Card + Ovislink WL-5400PCI PCI Card + Peabird WLG-PCI PCI Card + Sitecom WL-100i Cardbus Card + Sitecom WL-110i PCI Card + SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card + SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card + SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card + Z-Com XG-900 PCI Card + Zyxel G-100 Cardbus Card + + If you enable this you will need a firmware file as well. + You will need to copy this to /usr/lib/hotplug/firmware/isl3890. + You can get this non-GPL'd firmware file from the Prism54 project page: + + You will also need the /etc/hotplug/firmware.agent script from + a current hotplug package. + + Note: You need a motherboard with DMA support to use any of these cards + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called prism54.ko. + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Sat Apr 3 19:38:57 2004 +++ b/drivers/net/wireless/Makefile Sat Apr 3 19:38:57 2004 @@ -26,6 +26,8 @@ obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o +obj-$(CONFIG_PRISM54) += prism54/ + # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Sat Apr 3 19:38:41 2004 +++ b/drivers/net/wireless/airo.c Sat Apr 3 19:38:41 2004 @@ -1505,7 +1505,7 @@ seq = micSeq - (context->window - 33); //Too old of a SEQ number to check. - if ((u32)seq < 0) + if ((s32)seq < 0) return ERROR; if ( seq > 64 ) { diff -Nru a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c --- a/drivers/net/wireless/arlan-main.c Sat Apr 3 19:38:45 2004 +++ b/drivers/net/wireless/arlan-main.c Sat Apr 3 19:38:45 2004 @@ -1281,7 +1281,7 @@ priv->retransmissions = 0; if (priv->Conf->tx_delay_ms) { - priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;; + priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1; } else { diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- a/drivers/net/wireless/atmel.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/wireless/atmel.c Sat Apr 3 19:38:42 2004 @@ -537,7 +537,7 @@ int channel; int reg_domain; int tx_rate; - int auto_tx_rate;; + int auto_tx_rate; int rts_threshold; int frag_threshold; int long_retry, short_retry; @@ -796,7 +796,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); struct ieee802_11_hdr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; @@ -1167,7 +1167,7 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); u8 isr; if (priv->card && priv->present_callback && @@ -1234,13 +1234,13 @@ static struct net_device_stats *atmel_get_stats (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); return &priv->stats; } static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* update the link quality here in case we are seeing no beacons at all to drive the process */ @@ -1287,7 +1287,7 @@ static int atmel_open (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); priv->station_state = STATION_STATE_INITIALIZING; if (!reset_atmel_card(dev)) { priv->station_state = STATION_STATE_DOWN; @@ -1298,7 +1298,7 @@ static int atmel_close (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); netif_carrier_off(dev); if (netif_running(dev)) @@ -1378,7 +1378,7 @@ static int atmel_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct atmel_private *priv = (struct atmel_private *)data; + struct atmel_private *priv = data; int len = atmel_proc_output (page, priv); if (len <= off+count) *eof = 1; *start = page + off; @@ -1406,7 +1406,7 @@ goto err_out_free; } - priv = dev->priv; + priv = netdev_priv(dev); priv->dev = dev; priv->sys_dev = sys_dev; priv->present_callback = card_present; @@ -1525,7 +1525,7 @@ void stop_atmel_card(struct net_device *dev, int freeres) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* put a brick on it... */ if (priv->bus_type == BUS_TYPE_PCCARD) @@ -1582,7 +1582,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Check if we asked for `any' */ if(dwrq->flags == 0) { @@ -1610,7 +1610,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Get the current SSID */ if (priv->SSID_size == 0) { @@ -1633,7 +1633,7 @@ struct sockaddr *awrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); memcpy(awrq->sa_data, priv->CurrentBSSID, 6); awrq->sa_family = ARPHRD_ETHER; @@ -1645,7 +1645,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Basic checking: do we have a key to set ? * Note : with the new API, it's impossible to get a NULL pointer. @@ -1736,7 +1736,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; if (!priv->wep_is_on) @@ -1776,7 +1776,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (vwrq->fixed == 0) { priv->tx_rate = 3; @@ -1808,7 +1808,7 @@ __u32 *uwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) return -EINVAL; @@ -1822,7 +1822,7 @@ __u32 *uwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); *uwrq = priv->operating_mode; return 0; @@ -1833,7 +1833,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (priv->auto_tx_rate) { vwrq->fixed = 0; @@ -1855,7 +1855,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); priv->power_mode = vwrq->disabled ? 0 : 1; return -EINPROGRESS; } @@ -1865,7 +1865,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->disabled = priv->power_mode ? 0 : 1; vwrq->flags = IW_POWER_ON; return 0; @@ -1876,7 +1876,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { if(vwrq->flags & IW_RETRY_MAX) @@ -1899,7 +1899,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->disabled = 0; /* Can't be disabled */ @@ -1922,7 +1922,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int rthr = vwrq->value; if(vwrq->disabled) @@ -1940,7 +1940,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->value = priv->rts_threshold; vwrq->disabled = (vwrq->value >= 2347); @@ -1954,7 +1954,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int fthr = vwrq->value; if(vwrq->disabled) @@ -1973,7 +1973,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->value = priv->frag_threshold; vwrq->disabled = (vwrq->value >= 2346); @@ -1990,7 +1990,7 @@ struct iw_freq *fwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int rc = -EINPROGRESS; /* Call commit handler */ /* If setting by frequency, convert to a channel */ @@ -2024,7 +2024,7 @@ struct iw_freq *fwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); fwrq->m = priv->channel; fwrq->e = 0; @@ -2036,7 +2036,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Note : you may have realised that, as this is a SET operation, * this is privileged and therefore a normal user can't @@ -2074,7 +2074,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int i; char *current_ev = extra; struct iw_event iwe; @@ -2126,7 +2126,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); struct iw_range *range = (struct iw_range *) extra; int k,i,j; @@ -2193,7 +2193,7 @@ struct sockaddr *awrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int i; static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; @@ -2318,7 +2318,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); atmel_priv_ioctl com; struct iwreq *wrq = (struct iwreq *) rq; unsigned char *new_firmware; @@ -3053,7 +3053,7 @@ static void atmel_management_timer(u_long a) { struct net_device *dev = (struct net_device *) a; - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); unsigned long flags; /* Check if the card has been yanked. */ @@ -3297,7 +3297,7 @@ static int probe_atmel_card(struct net_device *dev) { int rc = 0; - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* reset pccard */ if (priv->bus_type == BUS_TYPE_PCCARD) @@ -3486,7 +3486,7 @@ which is the route into the rest of the firmare datastructures. */ int channel; - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); u8 configuration; /* data to add to the firmware names, in priority order diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h --- a/drivers/net/wireless/hermes.h Sat Apr 3 19:38:41 2004 +++ b/drivers/net/wireless/hermes.h Sat Apr 3 19:38:41 2004 @@ -364,7 +364,7 @@ /* Note that for the next two, the count is in 16-bit words, not bytes */ static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) { - off = off << hw->reg_spacing;; + off = off << hw->reg_spacing; if (hw->io_space) { insw(hw->iobase + off, buf, count); diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c Sat Apr 3 19:38:57 2004 +++ b/drivers/net/wireless/orinoco.c Sat Apr 3 19:38:57 2004 @@ -599,7 +599,7 @@ int __orinoco_up(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -626,7 +626,7 @@ int __orinoco_down(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -657,7 +657,7 @@ int orinoco_reinit_firmware(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -685,7 +685,7 @@ static int orinoco_open(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -705,7 +705,7 @@ int orinoco_stop(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; /* We mustn't use orinoco_lock() here, because we need to be @@ -724,7 +724,7 @@ static int __orinoco_program_rids(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -912,7 +912,7 @@ /* xyzzy */ static int orinoco_reconfigure(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; @@ -965,7 +965,7 @@ * schedule_work() */ static void orinoco_reset(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -1070,7 +1070,7 @@ static void orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { @@ -1433,7 +1433,7 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; @@ -1561,7 +1561,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); u16 infofid; struct { u16 len; @@ -1662,7 +1662,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -1814,7 +1814,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; @@ -1840,7 +1840,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -1850,7 +1850,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); u16 fid = hermes_read_regn(hw, ALLOCFID); @@ -1886,7 +1886,7 @@ static void determine_firmware(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct sta_id sta_id; @@ -2024,7 +2024,7 @@ static int orinoco_init(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; struct hermes_idstring nickbuf; @@ -2204,7 +2204,7 @@ struct net_device_stats * orinoco_get_stats(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); return &priv->stats; } @@ -2212,7 +2212,7 @@ struct iw_statistics * orinoco_get_wireless_stats(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err = 0; @@ -2271,7 +2271,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int i; /* Gather wireless spy statistics: for each packet, compare the @@ -2290,7 +2290,7 @@ struct sk_buff *skb, struct hermes_rx_descriptor *desc) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -2311,7 +2311,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -2449,7 +2449,7 @@ static void orinoco_tx_timeout(struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; struct hermes *hw = &priv->hw; @@ -2466,7 +2466,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; @@ -2484,7 +2484,7 @@ static void __orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; int promisc, mc_count; @@ -2554,7 +2554,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; int mode; struct iw_range range; @@ -2699,7 +2699,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int enable = priv->wep_on; @@ -2794,7 +2794,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; char keybuf[ORINOCO_MAX_KEY_SIZE]; @@ -2841,7 +2841,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char essidbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2874,7 +2874,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char essidbuf[IW_ESSID_MAX_SIZE+1]; int active; int err = 0; @@ -2907,7 +2907,7 @@ static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char nickbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2935,7 +2935,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char nickbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2957,7 +2957,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int chan = -1; int err; unsigned long flags; @@ -2999,7 +2999,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; u16 val; int err; @@ -3025,7 +3025,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = srq->value; int err; unsigned long flags; @@ -3047,7 +3047,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = rrq->value; int err; unsigned long flags; @@ -3070,7 +3070,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; @@ -3105,7 +3105,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 val; @@ -3143,7 +3143,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; int ratemode = -1; int bitrate; /* 100s of kilobits */ @@ -3186,7 +3186,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; int ratemode; @@ -3253,7 +3253,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; @@ -3306,7 +3306,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; @@ -3356,7 +3356,7 @@ #if WIRELESS_EXT > 10 static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; @@ -3409,7 +3409,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = *( (int *) wrq->u.name ); int err; unsigned long flags; @@ -3429,7 +3429,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int *val = (int *)wrq->u.name; int err; unsigned long flags; @@ -3446,7 +3446,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = *( (int *) wrq->u.name ); int err = 0; unsigned long flags; @@ -3488,7 +3488,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int *val = (int *)wrq->u.name; int err; unsigned long flags; @@ -3507,7 +3507,7 @@ * Jean II */ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -3554,7 +3554,7 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; int number; @@ -3601,7 +3601,7 @@ static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct iwreq *wrq = (struct iwreq *)rq; int err = 0; int tmp; @@ -4057,7 +4057,7 @@ static int orinoco_debug_dump_recs(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; u8 *val8; u16 *val16; @@ -4131,7 +4131,7 @@ dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); if (!dev) return NULL; - priv = (struct orinoco_private *)dev->priv; + priv = netdev_priv(dev); priv->ndev = dev; if (sizeof_card) priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private)); diff -Nru a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/Makefile Sat Apr 3 19:38:57 2004 @@ -0,0 +1,10 @@ +# $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $ + +prism54-objs := islpci_eth.o islpci_mgt.o \ + isl_38xx.o isl_ioctl.o islpci_dev.o \ + islpci_hotplug.o oid_mgt.o + +obj-$(CONFIG_PRISM54) += prism54.o + +EXTRA_CFLAGS = -I$(PWD) #-DCONFIG_PRISM54_WDS + diff -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_38xx.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,397 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.c,v 1.22 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003-2004 Luis R. Rodriguez _ + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include + +#include "isl_38xx.h" +#include + +#include +#include + +#include +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error No Firmware Loading configured in the kernel ! +#endif + +#include "islpci_dev.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Device Interface & Control functions +******************************************************************************/ + +/** + * isl38xx_disable_interrupts - disable all interrupts + * @device: pci memory base address + * + * Instructs the device to disable all interrupt reporting by asserting + * the IRQ line. New events may still show up in the interrupt identification + * register located at offset %ISL38XX_INT_IDENT_REG. + */ +void +isl38xx_disable_interrupts(void *device) +{ + isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_sleep_request(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device requests to go into sleep mode + * check whether the transmit queues for data and management are empty */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) + /* data tx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + /* management tx queue not empty */ + return; + + /* check also whether received frames are pending */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) + /* data rx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) + /* management rx queue not empty */ + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); +#endif + + /* all queues are empty, allow the device to go into sleep mode */ + *powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* assert the Sleep interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_wakeup(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device is in active state, update the powerstate flag */ + *powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* now check whether there are frames pending for the card */ + if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) + && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); +#endif + + /* either data or management transmit queue has a frame pending + * trigger the device by setting the Update bit in the Device Int reg */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_trigger_device(int asleep, void *device_base) +{ + struct timeval current_time; + u32 reg, counter = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); +#endif + + /* check whether the device is in power save mode */ + if (asleep) { + /* device is in powersave, trigger the device for wakeup */ +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", + current_time.tv_sec, current_time.tv_usec); +#endif + + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + + if (reg = readl(device_base + ISL38XX_INT_IDENT_REG), + reg == 0xabadface) { +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device register abadface\n", + current_time.tv_sec, current_time.tv_usec); +#endif + /* read the Device Status Register until Sleepmode bit is set */ + while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), + (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { + udelay(ISL38XX_WRITEIO_DELAY); + counter++; + } + + DEBUG(SHOW_TRACING, + "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device asleep counter %i\n", + current_time.tv_sec, current_time.tv_usec, + counter); +#endif + } + /* assert the Wakeup interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* perform another read on the Device Status Register */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, reg); +#endif + } else { + /* device is (still) awake */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device is in active state\n"); +#endif + /* trigger the device by setting the Update bit in the Device Int reg */ + + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + } +} + +void +isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +{ + u32 reg; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); +#endif + + /* load the address of the control block in the device */ + isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* enable the interrupt for detecting initialization */ + + /* Note: Do not enable other interrupts here. We want the + * device to have come up first 100% before allowing any other + * interrupts. */ + reg = ISL38XX_INT_IDENT_INIT; + + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ +} + +void +isl38xx_enable_common_interrupts(void *device_base) { + u32 reg; + reg = ( ISL38XX_INT_IDENT_UPDATE | + ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +int +isl38xx_upload_firmware(char *fw_id, _REQ_FW_DEV_T dev, void *device_base, + dma_addr_t host_address) +{ + u32 reg, rc; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ERROR_MESSAGES, "isl38xx_upload_firmware(0x%lx, 0x%lx)\n", + (long) device_base, (long) host_address); +#endif + + /* clear the RAMBoot and the Reset bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the Reset bit without reading the register ! */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reboot */ + mdelay(50); + + { + const struct firmware *fw_entry = 0; + long fw_len; + const u32 *fw_ptr; + + rc = request_firmware(&fw_entry, fw_id, dev); + if (rc) { + printk(KERN_ERR + "%s: request_firmware() failed for '%s'\n", + "prism54", fw_id); + return rc; + } + /* prepare the Direct Memory Base register */ + reg = ISL38XX_DEV_FIRMWARE_ADDRES; + + fw_ptr = (u32 *) fw_entry->data; + fw_len = fw_entry->size; + + if (fw_len % 4) { + printk(KERN_ERR + "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", + "prism54", fw_id); + release_firmware(fw_entry); + return EILSEQ; /* Illegal byte sequence */; + } + + while (fw_len > 0) { + long _fw_len = + (fw_len > + ISL38XX_MEMORY_WINDOW_SIZE) ? + ISL38XX_MEMORY_WINDOW_SIZE : fw_len; + u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + + /* set the cards base address for writting the data */ + isl38xx_w32_flush(device_base, reg, + ISL38XX_DIR_MEM_BASE_REG); + wmb(); /* be paranoid */ + + /* increment the write address for next iteration */ + reg += _fw_len; + fw_len -= _fw_len; + + /* write the data to the Direct Memory Window 32bit-wise */ + /* memcpy_toio() doesn't guarantee 32bit writes :-| */ + while (_fw_len > 0) { + /* use non-swapping writel() */ + __raw_writel(*fw_ptr, dev_fw_ptr); + fw_ptr++, dev_fw_ptr++; + _fw_len -= 4; + } + + /* flush PCI posting */ + (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); + wmb(); /* be paranoid again */ + + BUG_ON(_fw_len != 0); + } + + BUG_ON(fw_len != 0); + + release_firmware(fw_entry); + } + + /* now reset the device + * clear the Reset & ClkRun bit, set the RAMBoot bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_CLKRUN; + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg |= ISL38XX_CTRL_STAT_RAMBOOT; + isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit latches the host override and RAMBoot bits + * into the device for operation when the reset bit is reset */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the reset bit should start the whole circus */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + return 0; +} + +int +isl38xx_in_queue(isl38xx_control_block *cb, int queue) +{ + const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - + le32_to_cpu(cb->device_curr_frag[queue])); + + /* determine the amount of fragments in the queue depending on the type + * of the queue, either transmit or receive */ + + BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ + + switch (queue) { + /* send queues */ + case ISL38XX_CB_TX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + case ISL38XX_CB_TX_DATA_LQ: + case ISL38XX_CB_TX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_TX_QSIZE); + return delta; + break; + + /* receive queues */ + case ISL38XX_CB_RX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + return ISL38XX_CB_MGMT_QSIZE - delta; + break; + + case ISL38XX_CB_RX_DATA_LQ: + case ISL38XX_CB_RX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_RX_QSIZE); + return ISL38XX_CB_RX_QSIZE - delta; + break; + } + BUG(); + return 0; +} diff -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_38xx.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,179 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.h,v 1.22 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISL_38XX_H +#define _ISL_38XX_H + +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75)) +#include +# define _REQ_FW_DEV_T struct device * +#else +# define _REQ_FW_DEV_T char * +#endif + +#include + +#define ISL38XX_CB_RX_QSIZE 8 +#define ISL38XX_CB_TX_QSIZE 32 + +/* ISL38XX Access Point Specific definitions */ +#define ISL38XX_MAX_WDS_LINKS 8 + +/* ISL38xx Client Specific definitions */ +#define ISL38XX_PSM_ACTIVE_STATE 0 +#define ISL38XX_PSM_POWERSAVE_STATE 1 + +/* ISL38XX Host Interface Definitions */ +#define ISL38XX_PCI_MEM_SIZE 0x02000 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */ +#define ISL38XX_RESET_DELAY 50 /* in ms */ +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ +#define ISL38XX_MAX_WAIT_CYCLES 10 + +/* PCI Memory Area */ +#define ISL38XX_HARDWARE_REG 0x0000 +#define ISL38XX_CARDBUS_CIS 0x0800 +#define ISL38XX_DIRECT_MEM_WIN 0x1000 + +/* Hardware registers */ +#define ISL38XX_DEV_INT_REG 0x0000 +#define ISL38XX_INT_IDENT_REG 0x0010 +#define ISL38XX_INT_ACK_REG 0x0014 +#define ISL38XX_INT_EN_REG 0x0018 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030 +#define ISL38XX_CTRL_STAT_REG 0x0078 + +/* High end mobos queue up pci writes, the following + * is used to "read" from after a write to force flush */ +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG + +/** + * isl38xx_w32_flush - PCI iomem write helper + * @base: (host) memory base address of the device + * @val: 32bit value (host order) to write + * @offset: byte offset into @base to write value to + * + * This helper takes care of writing a 32bit datum to the + * specified offset into the device's pci memory space, and making sure + * the pci memory buffers get flushed by performing one harmless read + * from the %ISL38XX_PCI_POSTING_FLUSH offset. + */ +static inline void +isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +{ + writel(val, base + offset); + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); +} + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_SOURCES 0x001E + +/* Control/Status register bits */ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +/* Control Block definitions */ +#define ISL38XX_CB_RX_DATA_LQ 0 +#define ISL38XX_CB_TX_DATA_LQ 1 +#define ISL38XX_CB_RX_DATA_HQ 2 +#define ISL38XX_CB_TX_DATA_HQ 3 +#define ISL38XX_CB_RX_MGMTQ 4 +#define ISL38XX_CB_TX_MGMTQ 5 +#define ISL38XX_CB_QCOUNT 6 +#define ISL38XX_CB_MGMT_QSIZE 4 +#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ + +/* Memory Manager definitions */ +#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ +#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ +#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ +#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) +#define CONTROL_BLOCK_SIZE 1024 /* should be enough */ +#define PSM_FRAME_SIZE 1536 +#define PSM_MINIMAL_STATION_COUNT 64 +#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT +#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT +#define MAX_TRAP_RX_QUEUE 4 +#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE + +/* Fragment package definitions */ +#define FRAGMENT_FLAG_MF 0x0001 +#define MAX_FRAGMENT_SIZE 1536 + +/* In monitor mode frames have a header. I don't know exactly how big those + * frame can be but I've never seen any frame bigger than 1584... : + */ +#define MAX_FRAGMENT_SIZE_RX 1600 + +typedef struct { + u32 address; /* physical address on host */ + u16 size; /* packet size */ + u16 flags; /* set of bit-wise flags */ +} isl38xx_fragment; + +struct isl38xx_cb { + u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; + u32 device_curr_frag[ISL38XX_CB_QCOUNT]; + isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; + isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; +}; + +typedef struct isl38xx_cb isl38xx_control_block; + +/* determine number of entries currently in queue */ +int isl38xx_in_queue(isl38xx_control_block *cb, int queue); + +void isl38xx_disable_interrupts(void *); +void isl38xx_enable_common_interrupts(void *); + +void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, + void *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); +void isl38xx_trigger_device(int, void *); +void isl38xx_interface_reset(void *, dma_addr_t); + +int isl38xx_upload_firmware(char *, _REQ_FW_DEV_T, void *, dma_addr_t); + +#endif /* _ISL_38XX_H */ diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_ioctl.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,2211 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.c,v 1.140 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Herbert Valerio Riedel + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "isl_ioctl.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "oid_mgt.h" + +#include /* New driver API */ + +static int init_mode = CARD_DEFAULT_IW_MODE; +static int init_channel = CARD_DEFAULT_CHANNEL; +static int init_wep = CARD_DEFAULT_WEP; +static int init_filter = CARD_DEFAULT_FILTER; +static int init_authen = CARD_DEFAULT_AUTHEN; +static int init_dot1x = CARD_DEFAULT_DOT1X; +static int init_conformance = CARD_DEFAULT_CONFORMANCE; +static int init_mlme = CARD_DEFAULT_MLME_MODE; + +module_param(init_mode, int, 0); +MODULE_PARM_DESC(init_mode, + "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor"); + +module_param(init_channel, int, 0); +MODULE_PARM_DESC(init_channel, + "Check `iwpriv ethx channel` for available channels"); + +module_param(init_wep, int, 0); +module_param(init_filter, int, 0); + +module_param(init_authen, int, 0); +MODULE_PARM_DESC(init_authen, + "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH"); + +module_param(init_dot1x, int, 0); +MODULE_PARM_DESC(init_dot1x, + "\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED"); + +module_param(init_mlme, int, 0); +MODULE_PARM_DESC(init_mlme, + "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED"); + +/** + * prism54_mib_mode_helper - MIB change mode helper function + * @mib: the &struct islpci_mib object to modify + * @iw_mode: new mode (%IW_MODE_*) + * + * This is a helper function, hence it does not lock. Make sure + * caller deals with locking *if* necessary. This function sets the + * mode-dependent mib values and does the mapping of the Linux + * Wireless API modes to Device firmware modes. It also checks for + * correct valid Linux wireless modes. + */ +int +prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) +{ + u32 config = INL_CONFIG_MANUALRUN; + u32 mode, bsstype; + + /* For now, just catch early the Repeater and Secondary modes here */ + if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { + printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode " + "are not yet supported by this driver.\n", + __FUNCTION__); + return -EINVAL; + } + + priv->iw_mode = iw_mode; + + switch (iw_mode) { + case IW_MODE_AUTO: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_ANY; + break; + case IW_MODE_ADHOC: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_IBSS; + break; + case IW_MODE_INFRA: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MASTER: + mode = INL_MODE_AP; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MONITOR: + mode = INL_MODE_PROMISCUOUS; + bsstype = DOT11_BSSTYPE_ANY; + config |= INL_CONFIG_RXANNEX; + break; + default: + return -EINVAL; + } + + if (init_wds) + config |= INL_CONFIG_WDS; + mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); + mgt_set(priv, OID_INL_CONFIG, &config); + mgt_set(priv, OID_INL_MODE, &mode); + + return 0; +} + +/** + * prism54_mib_init - fill MIB cache with defaults + * + * this function initializes the struct given as @mib with defaults, + * of which many are retrieved from the global module parameter + * variables. + */ + +void +prism54_mib_init(islpci_private *priv) +{ + u32 t; + struct obj_buffer psm_buffer = { + .size = cpu_to_le32(PSM_BUFFER_SIZE), + .addr = cpu_to_le32(priv->device_psm_buffer) + }; + + mgt_set(priv, DOT11_OID_CHANNEL, &init_channel); + mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen); + mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep); + + mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter); + mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x); + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme); + mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance); + + t = 127; + mgt_set(priv, OID_INL_OUTPUTPOWER, &t); + + /* Important: we are setting a default wireless mode and we are + * forcing a valid one, so prism54_mib_mode_helper should just set + * mib values depending on what the wireless mode given is. No need + * for it save old values */ + if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) { + printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. " + "Using default mode\n", __FUNCTION__); + init_mode = CARD_DEFAULT_IW_MODE; + } + /* This sets all of the mode-dependent values */ + prism54_mib_mode_helper(priv, init_mode); +} + +void +prism54_mib_init_work(islpci_private *priv) +{ + down_write(&priv->mib_sem); + mgt_commit(priv); + up_write(&priv->mib_sem); +} + +/* this will be executed outside of atomic context thanks to + * schedule_work(), thus we can as well use sleeping semaphore + * locking */ +void +prism54_update_stats(islpci_private *priv) +{ + char *data; + int j; + struct obj_bss bss, *bss2; + union oid_res_t r; + + if (down_interruptible(&priv->stats_sem)) + return; + +/* missing stats are : + * iwstatistics.qual.updated + * iwstatistics.discard.nwid + * iwstatistics.discard.fragment + * iwstatistics.discard.misc + * iwstatistics.miss.beacon */ + +/* Noise floor. + * I'm not sure if the unit is dBm. + * Note : If we are not connected, this value seems to be irrevelant. */ + + mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + priv->local_iwstatistics.qual.noise = r.u; + +/* Get the rssi of the link. To do this we need to retrieve a bss. */ + + /* First get the MAC address of the AP we are associated with. */ + mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + data = r.ptr; + + /* copy this MAC to the bss */ + for (j = 0; j < 6; j++) + bss.address[j] = data[j]; + kfree(data); + + /* now ask for the corresponding bss */ + j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); + bss2 = r.ptr; + /* report the rssi and use it to calculate + * link quality through a signal-noise + * ratio */ + priv->local_iwstatistics.qual.level = bss2->rssi; + priv->local_iwstatistics.qual.qual = + bss2->rssi - priv->iwstatistics.qual.noise; + + kfree(bss2); + + /* report that the stats are new */ + priv->local_iwstatistics.qual.updated = 0x7; + +/* Rx : unable to decrypt the MPDU */ + mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.code = r.u; + +/* Tx : Max MAC retries num reached */ + mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.retries = r.u; + + up(&priv->stats_sem); + + return; +} + +struct iw_statistics * +prism54_get_wireless_stats(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + /* If the stats are being updated return old data */ + if (down_trylock(&priv->stats_sem) == 0) { + memcpy(&priv->iwstatistics, &priv->local_iwstatistics, + sizeof (struct iw_statistics)); + /* They won't be marked updated for the next time */ + priv->local_iwstatistics.qual.updated = 0; + up(&priv->stats_sem); + } else + priv->iwstatistics.qual.updated = 0; + + /* Update our wireless stats, but do not schedule to often + * (max 1 HZ) */ + if ((priv->stats_timestamp == 0) || + time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { + schedule_work(&priv->stats_work); + priv->stats_timestamp = jiffies; + } + + return &priv->iwstatistics; +} + +static int +prism54_commit(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + /* simply re-set the last set SSID, this should commit most stuff */ + + /* Commit in Monitor mode is not necessary, also setting essid + * in Monitor mode does not make sense and isn't allowed for this + * device's firmware */ + if(priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); + return 0; +} + +static int +prism54_get_name(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char *capabilities; + union oid_res_t r; + int rvalue; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + strncpy(cwrq, "NOT READY!", IFNAMSIZ); + return 0; + } + rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); + + switch (r.u) { + case INL_PHYCAP_5000MHZ: + capabilities = "IEEE 802.11a/b/g"; + break; + case INL_PHYCAP_FAA: + capabilities = "IEEE 802.11b/g - FAA Support"; + break; + case INL_PHYCAP_2400MHZ: + default: + capabilities = "IEEE 802.11b/g"; /* Default */ + break; + } + strncpy(cwrq, capabilities, IFNAMSIZ); + return rvalue; +} + +static int +prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + u32 c = 0; + + /* prepare the structure for the set object */ + if (fwrq->m < 1000) + /* structure value contains a channel indication */ + c = fwrq->m; + else { + /* structure contains a frequency indication and fwrq->e = 1 */ + int f = fwrq->m / 100000; + + if (fwrq->e != 1) + return -EINVAL; + if ((f >= 2412) && (f <= 2484)) { + while ((c < 14) && (f != frequency_list_bg[c])) + c++; + if (c >= 14) + return -EINVAL; + } else if ((f >= (int) 5170) && (f <= (int) 5320)) { + while ((c < 12) && (f != frequency_list_a[c])) + c++; + if (c >= 12) + return -EINVAL; + } else + return -EINVAL; + c++; + } + + rvalue = mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c); + + /* Call commit handler */ + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); + + fwrq->m = r.u; + fwrq->e = 0; + + return rvalue; +} + +static int +prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; + + /* Let's see if the user passed a valid Linux Wireless mode */ + if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { + printk(KERN_DEBUG + "%s: %s() You passed a non-valid init_mode.\n", + priv->ndev->name, __FUNCTION__); + return -EINVAL; + } + + down_write(&priv->mib_sem); + + if (prism54_mib_mode_helper(priv, *uwrq)) { + up_write(&priv->mib_sem); + return -EOPNOTSUPP; + } + + /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an + * extended one. + */ + if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + + mgt_commit(priv); + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) + ? ARPHRD_IEEE80211 : ARPHRD_ETHER; + up_write(&priv->mib_sem); + + return 0; +} + +/* Use mib cache */ +static int +prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > + IW_MODE_MONITOR)); + *uwrq = priv->iw_mode; + + return 0; +} + +/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to + * emit data if (sensitivity > rssi - noise) (in dBm). + * prism54_set_sens does not seem to work. + */ + +static int +prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 sens; + + /* by default the card sets this to 20. */ + sens = vwrq->disabled ? 20 : vwrq->value; + + /* set the ed threshold. */ + return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); +} + +static int +prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); + + vwrq->value = r.u; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + + return rvalue; +} + +static int +prism54_get_range(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + islpci_private *priv = netdev_priv(ndev); + char *data; + int i, m, rvalue; + struct obj_frequencies *freq; + union oid_res_t r; + + memset(range, 0, sizeof (struct iw_range)); + dwrq->length = sizeof (struct iw_range); + + /* set the wireless extension version number */ + range->we_version_source = SUPPORTED_WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + + /* Now the encoding capabilities */ + range->num_encoding_sizes = 3; + /* 64(40) bits WEP */ + range->encoding_size[0] = 5; + /* 128(104) bits WEP */ + range->encoding_size[1] = 13; + /* 256 bits for WPA-PSK */ + range->encoding_size[2] = 32; + /* 4 keys are allowed */ + range->max_encoding_tokens = 4; + + /* we don't know the quality range... */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.qual = 0; + /* these value describe an average quality. Needs more tweaking... */ + range->avg_qual.level = -80; /* -80 dBm */ + range->avg_qual.noise = 0; /* don't know what to put here */ + range->avg_qual.qual = 0; + + range->sensitivity = 200; + + /* retry limit capabilities */ + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + + /* I don't know the range. Put stupid things here */ + range->min_retry = 1; + range->max_retry = 65535; + range->min_r_time = 1024; + range->max_r_time = 65535 * 1024; + + /* txpower is supported in dBm's */ + range->txpower_capa = IW_TXPOW_DBM; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* Request the device for the supported frequencies + * not really revelant since some devices will report the 5 GHz band + * frequencies even if they don't support them. + */ + rvalue = + mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); + freq = r.ptr; + + range->num_channels = le16_to_cpu(freq->nr); + range->num_frequency = le16_to_cpu(freq->nr); + + /* Frequencies are not listed in the right order. The reordering is probably + * firmware dependant and thus should work for everyone. + */ + m = min(IW_MAX_FREQUENCIES, (int) le16_to_cpu(freq->nr)); + for (i = 0; i < m - 12; i++) { + range->freq[i].m = le16_to_cpu(freq->mhz[12 + i]); + range->freq[i].e = 6; + range->freq[i].i = i + 1; + } + for (i = m - 12; i < m; i++) { + range->freq[i].m = le16_to_cpu(freq->mhz[i - m + 12]); + range->freq[i].e = 6; + range->freq[i].i = i + 23; + } + + kfree(freq); + + rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); + data = r.ptr; + + /* We got an array of char. It is NULL terminated. */ + i = 0; + while ((i < IW_MAX_BITRATES) && (*data != 0)) { + /* the result must be in bps. The card gives us 500Kbps */ + range->bitrate[i] = (__s32) (*data >> 1); + range->bitrate[i] *= 1000000; + i++; + data++; + } + + range->num_bitrates = i; + + kfree(r.ptr); + + return rvalue; +} + +/* Set AP address*/ + +static int +prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char bssid[6]; + int rvalue; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* prepare the structure for the set object */ + memcpy(&bssid[0], awrq->sa_data, 6); + + /* set the bssid -- does this make sense when in AP mode? */ + rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); + + return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ +} + +/* get AP address*/ + +static int +prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + + memcpy(awrq->sa_data, r.ptr, 6); + awrq->sa_family = ARPHRD_ETHER; + kfree(r.ptr); + + return rvalue; +} + +static int +prism54_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + /* hehe the device does this automagicaly */ + return 0; +} + +/* a little helper that will translate our data into a card independent + * format that the Wireless Tools will understand. This was inspired by + * the "Aironet driver for 4500 and 4800 series cards" (GPL) + */ + +inline char * +prism54_translate_bss(struct net_device *ndev, char *current_ev, + char *end_buf, struct obj_bss *bss, char noise) +{ + struct iw_event iwe; /* Temporary buffer */ + short cap; + islpci_private *priv = netdev_priv(ndev); + + /* The first entry must be the MAC address */ + memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.cmd = SIOCGIWAP; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* The following entries will be displayed in the same order we give them */ + + /* The ESSID. */ + iwe.u.data.length = bss->ssid.length; + iwe.u.data.flags = 1; + iwe.cmd = SIOCGIWESSID; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, bss->ssid.octets); + + /* Capabilities */ +#define CAP_ESS 0x01 +#define CAP_IBSS 0x02 +#define CAP_CRYPT 0x10 + + /* Mode */ + cap = le16_to_cpu(bss->capinfo); + iwe.u.mode = 0; + if (cap & CAP_ESS) + iwe.u.mode = IW_MODE_MASTER; + else if (cap & CAP_IBSS) + iwe.u.mode = IW_MODE_ADHOC; + iwe.cmd = SIOCGIWMODE; + if (iwe.u.mode) + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + + /* Encryption capability */ + if (cap & CAP_CRYPT) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.cmd = SIOCGIWENCODE; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); + + /* Add frequency. (short) bss->channel is the frequency in MHz */ + iwe.u.freq.m = bss->channel; + iwe.u.freq.e = 6; + iwe.cmd = SIOCGIWFREQ; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.u.qual.level = bss->rssi; + iwe.u.qual.noise = noise; + /* do a simple SNR for quality */ + iwe.u.qual.qual = bss->rssi - noise; + iwe.cmd = IWEVQUAL; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + if (priv->wpa) { + u8 wpa_ie[MAX_WPA_IE_LEN]; + char *buf, *p; + size_t wpa_ie_len; + int i; + + wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); + if (wpa_ie_len > 0 && + (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { + p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < wpa_ie_len; i++) { + p += sprintf(p, "%02x", wpa_ie[i]); + } + memset(&iwe, 0, sizeof (iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + + return current_ev; +} + +int +prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *current_ev = extra; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + dwrq->length = 0; + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. We can report at most + * IW_MAX_AP=64 to the range struct. But the device won't repport anything + * if you change the value of MAXBSS=24. Anyway 24 AP It is probably enough. + */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < min(IW_MAX_AP, (int) le32_to_cpu(bsslist->nr)); i++) + current_ev = prism54_translate_bss(ndev, current_ev, + extra + IW_SCAN_MAX_DATA, + &(bsslist->bsslist[i]), + noise); + kfree(bsslist); + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return rvalue; +} + +static int +prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid essid; + + memset(essid.octets, 0, 33); + + /* Check if we were asked for `any' */ + if (dwrq->flags && dwrq->length) { + if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) + return -E2BIG; + essid.length = dwrq->length - 1; + memcpy(essid.octets, extra, dwrq->length); + } else + essid.length = 0; + + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); + + /* If in monitor mode, just save to mib */ + mgt_set(priv, DOT11_OID_SSID, &essid); + return 0; + +} + +static int +prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid *essid; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); + essid = r.ptr; + + if (essid->length) { + dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ + /* if it is to big, trunk it */ + dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); + } else { + dwrq->flags = 0; + dwrq->length = 0; + } + essid->octets[essid->length] = '\0'; + memcpy(extra, essid->octets, dwrq->length); + kfree(essid); + + return rvalue; +} + +/* Provides no functionality, just completes the ioctl. In essence this is a + * just a cosmetic ioctl. + */ +static int +prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + if (dwrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + down_write(&priv->mib_sem); + memset(priv->nickname, 0, sizeof (priv->nickname)); + memcpy(priv->nickname, extra, dwrq->length); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + dwrq->length = 0; + + down_read(&priv->mib_sem); + dwrq->length = strlen(priv->nickname) + 1; + memcpy(extra, priv->nickname, dwrq->length); + up_read(&priv->mib_sem); + + return 0; +} + +/* Set the allowed Bitrates */ + +static int +prism54_set_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + + islpci_private *priv = netdev_priv(ndev); + u32 rate, profile; + char *data; + int ret, i; + union oid_res_t r; + + if (vwrq->value == -1) { + /* auto mode. No limit. */ + profile = 1; + return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + } + + if((ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r))) + return ret; + + rate = (u32) (vwrq->value / 500000); + data = r.ptr; + i = 0; + + while(data[i]) { + if(rate && (data[i] == rate)) { + break; + } + if(vwrq->value == i) { + break; + } + data[i] |= 0x80; + i++; + } + + if(!data[i]) { + return -EINVAL; + } + + data[i] |= 0x80; + data[i + 1] = 0; + + /* Now, check if we want a fixed or auto value */ + if (vwrq->fixed) { + data[0] = data[i]; + data[1] = 0; + } + +/* + i = 0; + printk("prism54 rate: "); + while(data[i]) { + printk("%u ", data[i]); + i++; + } + printk("0\n"); +*/ + profile = -1; + ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); + ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); + + kfree(r.ptr); + + return ret; +} + +/* Get the current bit rate */ +static int +prism54_get_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + char *data; + union oid_res_t r; + + /* Get the current bit rate */ + if((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) + return rvalue; + vwrq->value = r.u * 500000; + + /* request the device for the enabled rates */ + if((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r))) + return rvalue; + data = r.ptr; + vwrq->fixed = (data[0] != 0) && (data[1] == 0); + kfree(r.ptr); + + return 0; +} + +static int +prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + /* get the rts threshold */ + rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +static int +prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +/* Here we have (min,max) = max retries for (small frames, big frames). Where + * big frame <=> bigger than the rts threshold + * small frame <=> smaller than the rts threshold + * This is not really the behavior expected by the wireless tool but it seems + * to be a common behavior in other drivers. + * + * It seems that playing with this tends to hang the card -> DISABLED + */ + +static int +prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 slimit = 0, llimit = 0; /* short and long limit */ + u32 lifetime = 0; + int rvalue = 0; + + if (vwrq->disabled) + /* we cannot disable this feature */ + return -EINVAL; + + if (vwrq->flags & IW_RETRY_LIMIT) { + if (vwrq->flags & IW_RETRY_MIN) + slimit = vwrq->value; + else if (vwrq->flags & IW_RETRY_MAX) + llimit = vwrq->value; + else { + /* we are asked to set both */ + slimit = vwrq->value; + llimit = vwrq->value; + } + } + if (vwrq->flags & IW_RETRY_LIFETIME) + /* Wireless tools use us unit while the device uses 1024 us unit */ + lifetime = vwrq->value / 1024; + + /* now set what is requested */ + + if (slimit != 0) + rvalue = + mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); + if (llimit != 0) + rvalue |= + mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); + if (lifetime != 0) + rvalue |= + mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, + &lifetime); + + return rvalue; +} + +static int +prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue = 0; + vwrq->disabled = 0; /* It cannot be disabled */ + + if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + /* we are asked for the life time */ + rvalue = + mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); + vwrq->value = r.u * 1024; + vwrq->flags = IW_RETRY_LIFETIME; + } else if ((vwrq->flags & IW_RETRY_MAX)) { + /* we are asked for the long retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else { + /* default. get the short retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } + + return rvalue; +} + +static int +prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (dwrq->length > 0) { + /* we have a key to set */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index; + struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { + key.length = dwrq->length > sizeof (key.key) ? + sizeof (key.key) : dwrq->length; + memcpy(key.key, extra, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!dwrq->flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + + /* now read the flags */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (dwrq->flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((dwrq->flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_key *key; + u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + u32 authen = 0, invoke = 0, exunencrypt = 0; + int rvalue; + union oid_res_t r; + + /* first get the flags */ + rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + invoke = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + + if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) + dwrq->flags = IW_ENCODE_RESTRICTED; + else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { + if (invoke) + dwrq->flags = IW_ENCODE_OPEN; + else + dwrq->flags = IW_ENCODE_DISABLED; + } else + /* The card should not work in this state */ + dwrq->flags = 0; + + /* get the current device key index */ + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + devindex = r.u; + /* Now get the key, return it */ + if ((index < 0) || (index > 3)) + /* no index provided, use the current one */ + index = devindex; + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); + key = r.ptr; + dwrq->length = key->length; + memcpy(extra, key->key, dwrq->length); + kfree(key); + /* return the used key index */ + dwrq->flags |= devindex + 1; + + return rvalue; +} + +static int +prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); + /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ + vwrq->value = (s32)r.u / 4; + vwrq->fixed = 1; + /* radio is not turned of + * btw: how is possible to turn off only the radio + */ + vwrq->disabled = 0; + + return rvalue; +} + +static int +prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + s32 u = vwrq->value; + + /* intersil firmware operates in 0.25 dBm (1/4) */ + u *= 4; + if (vwrq->disabled) { + /* don't know how to disable radio */ + printk(KERN_DEBUG + "%s: %s() disabling radio is not yet supported.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } else if (vwrq->fixed) + /* currently only fixed value is supported */ + return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); + else { + printk(KERN_DEBUG + "%s: %s() auto power will be implemented later.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } +} + +static int +prism54_reset(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_reset(netdev_priv(ndev), 0); + + return 0; +} + +static int +prism54_set_beacon(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + int rvalue = mgt_set_request((islpci_private *) netdev_priv(ndev), + DOT11_OID_BEACONPERIOD, 0, uwrq); + + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_beacon(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + union oid_res_t r; + int rvalue; + + rvalue = + mgt_get_request((islpci_private *) netdev_priv(ndev), + DOT11_OID_BEACONPERIOD, 0, NULL, &r); + *uwrq = r.u; + + return rvalue; +} + +void +prism54_acl_init(struct islpci_acl *acl) +{ + sema_init(&acl->sem, 1); + INIT_LIST_HEAD(&acl->mac_list); + acl->size = 0; + acl->policy = MAC_POLICY_OPEN; +} + +static void +prism54_clear_mac(struct islpci_acl *acl) +{ + struct list_head *ptr, *next; + struct mac_entry *entry; + + if (down_interruptible(&acl->sem)) + return; + + if (acl->size == 0) { + up(&acl->sem); + return; + } + + for (ptr = acl->mac_list.next, next = ptr->next; + ptr != &acl->mac_list; ptr = next, next = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + list_del(ptr); + kfree(entry); + } + acl->size = 0; + up(&acl->sem); +} + +void +prism54_acl_clean(struct islpci_acl *acl) +{ + prism54_clear_mac(acl); +} + +static int +prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); + if (entry == NULL) + return -ENOMEM; + + memcpy(entry->addr, addr->sa_data, ETH_ALEN); + + if (down_interruptible(&acl->sem)) { + kfree(entry); + return -ERESTARTSYS; + } + list_add_tail(&entry->_list, &acl->mac_list); + acl->size++; + up(&acl->sem); + + return 0; +} + +static int +prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { + list_del(ptr); + acl->size--; + kfree(entry); + up(&acl->sem); + return 0; + } + } + up(&acl->sem); + return -EINVAL; +} + +static int +prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *dst = (struct sockaddr *) extra; + + dwrq->length = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + memcpy(dst->sa_data, entry->addr, ETH_ALEN); + dst->sa_family = ARPHRD_ETHER; + dwrq->length++; + dst++; + } + up(&acl->sem); + return 0; +} + +/* Setting policy also clears the MAC acl, even if we don't change the defaut + * policy + */ + +static int +prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + u32 mlmeautolevel; + + prism54_clear_mac(acl); + + if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) + return -EINVAL; + + down_write(&priv->mib_sem); + + acl->policy = *uwrq; + + /* the ACL code needs an intermediate mlmeautolevel */ + if ((priv->iw_mode == IW_MODE_MASTER) && + (acl->policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + else + mlmeautolevel = CARD_DEFAULT_MLME_MODE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + /* restart the card with our new policy */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + + *uwrq = acl->policy; + + return 0; +} + +/* Return 1 only if client should be accepted. */ + +static int +prism54_mac_accept(struct islpci_acl *acl, char *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + int res = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + if (acl->policy == MAC_POLICY_OPEN) { + up(&acl->sem); + return 1; + } + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + res = 1; + break; + } + } + res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; + up(&acl->sem); + + return res; +} + +static int +prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct obj_mlme *mlme; + int rvalue; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to kick every client */ + mlme->id = cpu_to_le16(0); + rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + kfree(mlme); + + return rvalue; +} + +static int +prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + struct obj_mlme *mlme; + struct sockaddr *addr = (struct sockaddr *) extra; + int rvalue; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to only kick the corresponding bastard */ + memcpy(mlme->address, addr->sa_data, ETH_ALEN); + mlme->id = cpu_to_le16(-1); + rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + + kfree(mlme); + + return rvalue; +} + +/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ + +static inline void +format_event(islpci_private *priv, char *dest, const char *str, + const struct obj_mlme *mlme, u16 *length, int error) +{ + const u8 *a = mlme->address; + int n = snprintf(dest, IW_CUSTOM_MAX, + "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s", + str, + ((priv->iw_mode == IW_MODE_MASTER) ? "to" : "from"), + a[0], a[1], a[2], a[3], a[4], a[5], + (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") + : "")); + BUG_ON(n > IW_CUSTOM_MAX); + *length = n; +} + +static void +send_formatted_event(islpci_private *priv, const char *str, + const struct obj_mlme *mlme, int error) +{ + union iwreq_data wrqu; + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + wrqu.data.length = 0; + format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length, + error); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +send_simple_event(islpci_private *priv, const char *str) +{ + union iwreq_data wrqu; + int n = strlen(str); + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + BUG_ON(n > IW_CUSTOM_MAX); + wrqu.data.length = n; + strcpy(wrqu.data.pointer, str); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +link_changed(struct net_device *ndev, u32 bitrate) +{ + islpci_private *priv = netdev_priv(ndev); + + if (le32_to_cpu(bitrate)) { + if (priv->iw_mode == IW_MODE_INFRA) { + union iwreq_data uwrq; + prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, + NULL); + wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); + } else + send_simple_event(netdev_priv(ndev), "Link established"); + } else + send_simple_event(netdev_priv(ndev), "Link lost"); +} + +/* Beacon/ProbeResp payload header */ +struct ieee80211_beacon_phdr { + u8 timestamp[8]; + u16 beacon_int; + u16 capab_info; +} __attribute__ ((packed)); + +#define WLAN_EID_GENERIC 0xdd +static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void +prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + + if (wpa_ie_len > MAX_WPA_IE_LEN) + wpa_ie_len = MAX_WPA_IE_LEN; + + if (down_interruptible(&priv->wpa_sem)) + return; + + /* try to use existing entry */ + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + list_move(&bss->list, &priv->bss_wpa_list); + break; + } + bss = NULL; + } + + if (bss == NULL) { + /* add a new BSS entry; if max number of entries is already + * reached, replace the least recently updated */ + if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + list_del(&bss->list); + } else { + bss = kmalloc(sizeof (*bss), GFP_ATOMIC); + if (bss != NULL) { + priv->num_bss_wpa++; + memset(bss, 0, sizeof (*bss)); + } + } + if (bss != NULL) { + memcpy(bss->bssid, bssid, ETH_ALEN); + list_add(&bss->list, &priv->bss_wpa_list); + } + } + + if (bss != NULL) { + memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); + bss->wpa_ie_len = wpa_ie_len; + bss->last_update = jiffies; + } else { + printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR + "\n", MAC2STR(bssid)); + } + + /* expire old entries from WPA list */ + while (priv->num_bss_wpa > 0) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + if (!time_after(jiffies, bss->last_update + 60 * HZ)) + break; + + list_del(&bss->list); + priv->num_bss_wpa--; + kfree(bss); + } + + up(&priv->wpa_sem); +} + +size_t +prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + size_t len = 0; + + if (down_interruptible(&priv->wpa_sem)) + return 0; + + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + break; + bss = NULL; + } + if (bss) { + len = bss->wpa_ie_len; + memcpy(wpa_ie, bss->wpa_ie, len); + } + up(&priv->wpa_sem); + + return len; +} + +void +prism54_wpa_ie_init(islpci_private *priv) +{ + INIT_LIST_HEAD(&priv->bss_wpa_list); + sema_init(&priv->wpa_sem, 1); +} + +void +prism54_wpa_ie_clean(islpci_private *priv) +{ + struct list_head *ptr, *n; + + list_for_each_safe(ptr, n, &priv->bss_wpa_list) { + struct islpci_bss_wpa_ie *bss; + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + kfree(bss); + } +} + +static void +prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, + u8 *payload, size_t len) +{ + struct ieee80211_beacon_phdr *hdr; + u8 *pos, *end; + + if (!priv->wpa) + return; + + hdr = (struct ieee80211_beacon_phdr *) payload; + pos = (u8 *) (hdr + 1); + end = payload + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " + "for " MACSTR "\n", MAC2STR(addr)); + return; + } + if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && + memcmp(pos + 2, wpa_oid, 4) == 0) { + prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); + return; + } + pos += 2 + pos[1]; + } +} + +static void +handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) +{ + if (((le16_to_cpu(mlme->state) == DOT11_STATE_AUTHING) || + (le16_to_cpu(mlme->state) == DOT11_STATE_ASSOCING)) + && mgt_mlme_answer(priv)) { + /* Someone is requesting auth and we must respond. Just send back + * the trap with error code set accordingly. + */ + mlme->code = cpu_to_le16(prism54_mac_accept(&priv->acl, + mlme-> + address) ? 0 : 1); + mgt_set_request(priv, oid, 0, mlme); + } +} + +int +prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, + char *data) +{ + struct obj_mlme *mlme = (struct obj_mlme *) data; + size_t len; + u8 *payload, *pos = (u8 *) (mlme + 1); + + len = pos[0] | (pos[1] << 8); /* little endian data length */ + payload = pos + 2; + + /* I think all trapable objects are listed here. + * Some oids have a EX version. The difference is that they are emitted + * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) + * with more info. + * The few events already defined by the wireless tools are not really + * suited. We use the more flexible custom event facility. + */ + + switch (oid) { + + case GEN_OID_LINKSTATE: + link_changed(priv->ndev, (u32) *data); + break; + + case DOT11_OID_MICFAILURE: + send_simple_event(priv, "Mic failure"); + break; + + case DOT11_OID_DEAUTHENTICATE: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATE: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "ReAssociate request", mlme, 1); + break; + + case DOT11_OID_BEACON: + prism54_process_bss_data(priv, oid, mlme->address, + payload, len); + send_formatted_event(priv, + "Received a beacon from an unkown AP", + mlme, 0); + break; + + case DOT11_OID_PROBE: + /* we received a probe from a client. */ + prism54_process_bss_data(priv, oid, mlme->address, + payload, len); + send_formatted_event(priv, "Received a probe from client", mlme, + 0); + break; + + /* Note : the following should never happen since we don't run the card in + * extended mode. + * Note : "mlme" is actually a "struct obj_mlmeex *" here, but this + * is backward compatible layout-wise with "struct obj_mlme". + */ + + case DOT11_OID_DEAUTHENTICATEEX: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATEEX: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Reassociate request", mlme, 1); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Process a device trap. This is called via schedule_work(), outside of + * interrupt context, no locks held. + */ +void +prism54_process_trap(void *data) +{ + struct islpci_mgmtframe *frame = data; + struct net_device *ndev = frame->ndev; + enum oid_num_t n = mgt_oidtonum(frame->header->oid); + + prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); + islpci_mgt_release(frame); +} + +int +prism54_set_mac_address(struct net_device *ndev, void *addr) +{ + islpci_private *priv = netdev_priv(ndev); + int ret; + + if (ndev->addr_len != 6) + return -EINVAL; + ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, + &((struct sockaddr *) addr)->sa_data); + if (!ret) + memcpy(priv->ndev->dev_addr, + &((struct sockaddr *) addr)->sa_data, 6); + + return ret; +} + +int +prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + /* should we really support this old stuff ? */ + return -EOPNOTSUPP; +} + +int +prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + down_write(&priv->mib_sem); + + priv->wpa = *uwrq; + if (priv->wpa) { + u32 l = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l); + } + /* restart the card with new level. Needed ? */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +int +prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + *uwrq = priv->wpa; + return 0; +} + +int +prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 max_burst; + + max_burst = (*uwrq) ? *uwrq : CARD_DEFAULT_MAXFRAMEBURST; + mgt_set_request(priv, DOT11_OID_MAXFRAMEBURST, 0, &max_burst); + + return -EINPROGRESS; /* Call commit handler */ +} + +int +prism54_get_maxframeburst(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_MAXFRAMEBURST, 0, NULL, &r); + *uwrq = r.u; + + return rvalue; +} + +int +prism54_set_profile(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 profile; + + profile = (*uwrq) ? *uwrq : CARD_DEFAULT_PROFILE; + mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + + return -EINPROGRESS; /* Call commit handler */ +} + +int +prism54_get_profile(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_PROFILES, 0, NULL, &r); + *uwrq = r.u; + + return rvalue; +} + +int +prism54_oid(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + priv->priv_oid = *uwrq; + printk("%s: oid 0x%08X\n", ndev->name, *uwrq); + + return 0; +} + +int +prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response = NULL; + int ret = -EIO, response_op = PIMFOR_OP_ERROR; + + printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); + data->length = 0; + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, priv->priv_oid, extra, 256, &response); + response_op = response->header->operation; + printk("%s: ret: %i\n", ndev->name, ret); + printk("%s: response_op: %i\n", ndev->name, response_op); + if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) { + if (response) { + islpci_mgt_release(response); + } + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + if (!ret) { + data->length = response->header->length; + memcpy(extra, response->data, data->length); + islpci_mgt_release(response); + printk("%s: len: %i\n", ndev->name, data->length); + } + } + + return ret; +} + +int +prism54_set_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response = NULL; + int ret = 0, response_op = PIMFOR_OP_ERROR; + + printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, data->length); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, priv->priv_oid, extra, data->length, &response); + printk("%s: ret: %i\n", ndev->name, ret); + if (!ret) { + response_op = response->header->operation; + printk("%s: response_op: %i\n", ndev->name, response_op); + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) { + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + } + + return ret; +} + +static const iw_handler prism54_handler[] = { + (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ + (iw_handler) prism54_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ + (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ + (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ + (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ + (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ + (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) prism54_set_wap, /* SIOCSIWAP */ + (iw_handler) prism54_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */ + (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ + (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ + (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ + (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ + (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ + (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ + (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ + (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ + (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ + (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ + (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ + (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ + (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ + (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ + (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ + (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ + (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +}; + +/* The low order bit identify a SET (0) or a GET (1) ioctl. */ + +#define PRISM54_RESET SIOCIWFIRSTPRIV +#define PRISM54_GET_BEACON SIOCIWFIRSTPRIV+1 +#define PRISM54_SET_BEACON SIOCIWFIRSTPRIV+2 +#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+3 +#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+4 +#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+5 +#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+6 + +#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+8 + +#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+10 + +#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+12 + +#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+13 +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+14 + +#define PRISM54_OID SIOCIWFIRSTPRIV+16 +#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 +#define PRISM54_SET_OID SIOCIWFIRSTPRIV+18 + +static const struct iw_priv_args prism54_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + {PRISM54_RESET, 0, 0, "reset"}, + {PRISM54_GET_BEACON, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getBeaconPeriod"}, + {PRISM54_SET_BEACON, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setBeaconPeriod"}, + {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getPolicy"}, + {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setPolicy"}, + {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, + {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "addMac"}, + {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "delMac"}, + {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "kickMac"}, + {PRISM54_KICK_ALL, 0, 0, "kickAll"}, + {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_wpa"}, + {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_wpa"}, + {PRISM54_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oid"}, + {PRISM54_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "get_oid"}, + {PRISM54_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "set_oid"}, +}; + +static const iw_handler prism54_private_handler[] = { + (iw_handler) prism54_reset, + (iw_handler) prism54_get_beacon, + (iw_handler) prism54_set_beacon, + (iw_handler) prism54_get_policy, + (iw_handler) prism54_set_policy, + (iw_handler) prism54_get_mac, + (iw_handler) prism54_add_mac, + (iw_handler) NULL, + (iw_handler) prism54_del_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_all, + (iw_handler) prism54_get_wpa, + (iw_handler) prism54_set_wpa, + (iw_handler) NULL, + (iw_handler) prism54_oid, + (iw_handler) prism54_get_oid, + (iw_handler) prism54_set_oid, +}; + +const struct iw_handler_def prism54_handler_def = { + .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), + .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), + .num_private_args = + sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .standard = (iw_handler *) prism54_handler, + .private = (iw_handler *) prism54_private_handler, + .private_args = (struct iw_priv_args *) prism54_private_args, +}; + diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_ioctl.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,55 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.h,v 1.30 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISL_IOCTL_H +#define _ISL_IOCTL_H + +#include "islpci_mgt.h" +#include "islpci_dev.h" + +#include /* New driver API */ + +#define SUPPORTED_WIRELESS_EXT 16 + +void prism54_mib_init(islpci_private *); +void prism54_mib_init_work(islpci_private *); + +struct iw_statistics *prism54_get_wireless_stats(struct net_device *); +void prism54_update_stats(islpci_private *); + +void prism54_acl_init(struct islpci_acl *); +void prism54_acl_clean(struct islpci_acl *); + +void prism54_process_trap(void *); + +void prism54_wpa_ie_init(islpci_private *priv); +void prism54_wpa_ie_clean(islpci_private *priv); +void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len); +size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); + +int prism54_set_mac_address(struct net_device *, void *); + +int prism54_ioctl(struct net_device *, struct ifreq *, int); + +extern const struct iw_handler_def prism54_handler_def; + +#endif /* _ISL_IOCTL_H */ diff -Nru a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_oid.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,483 @@ +/* + * $Id: isl_oid.h,v 1.3 2004/03/09 09:05:27 mcgrof Exp $ + * + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2004 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_ISL_OID_H) +#define _ISL_OID_H + +/* + * MIB related constant and structure definitions for communicating + * with the device firmware + */ + +struct obj_ssid { + u8 length; + char octets[33]; +} __attribute__ ((packed)); + +struct obj_key { + u8 type; /* dot11_priv_t */ + u8 length; + char key[32]; +} __attribute__ ((packed)); + +struct obj_mlme { + u8 address[6]; + u16 id; + u16 state; + u16 code; +} __attribute__ ((packed)); + +struct obj_mlmeex { + u8 address[6]; + u16 id; + u16 state; + u16 code; + u16 size; + u8 data[0]; +} __attribute__ ((packed)); + +struct obj_buffer { + u32 size; + u32 addr; /* 32bit bus address */ +} __attribute__ ((packed)); + +struct obj_bss { + u8 address[6]; + int:16; /* padding */ + + char state; + char reserved; + short age; + + char quality; + char rssi; + + struct obj_ssid ssid; + short channel; + char beacon_period; + char dtim_period; + short capinfo; + short rates; + short basic_rates; + int:16; /* padding */ +} __attribute__ ((packed)); + +struct obj_bsslist { + u32 nr; + struct obj_bss bsslist[0]; +} __attribute__ ((packed)); + +struct obj_frequencies { + u16 nr; + u16 mhz[0]; +} __attribute__ ((packed)); + +/* + * in case everything's ok, the inlined function below will be + * optimized away by the compiler... + */ +static inline void +__bug_on_wrong_struct_sizes(void) +{ + BUG_ON(sizeof (struct obj_ssid) != 34); + BUG_ON(sizeof (struct obj_key) != 34); + BUG_ON(sizeof (struct obj_mlme) != 12); + BUG_ON(sizeof (struct obj_mlmeex) != 14); + BUG_ON(sizeof (struct obj_buffer) != 8); + BUG_ON(sizeof (struct obj_bss) != 60); + BUG_ON(sizeof (struct obj_bsslist) != 4); + BUG_ON(sizeof (struct obj_frequencies) != 2); +} + +enum dot11_state_t { + DOT11_STATE_NONE = 0, + DOT11_STATE_AUTHING = 1, + DOT11_STATE_AUTH = 2, + DOT11_STATE_ASSOCING = 3, + + DOT11_STATE_ASSOC = 5, + DOT11_STATE_IBSS = 6, + DOT11_STATE_WDS = 7 +}; + +enum dot11_bsstype_t { + DOT11_BSSTYPE_NONE = 0, + DOT11_BSSTYPE_INFRA = 1, + DOT11_BSSTYPE_IBSS = 2, + DOT11_BSSTYPE_ANY = 3 +}; + +enum dot11_auth_t { + DOT11_AUTH_NONE = 0, + DOT11_AUTH_OS = 1, + DOT11_AUTH_SK = 2, + DOT11_AUTH_BOTH = 3 +}; + +enum dot11_mlme_t { + DOT11_MLME_AUTO = 0, + DOT11_MLME_INTERMEDIATE = 1, + DOT11_MLME_EXTENDED = 2 +}; + +enum dot11_priv_t { + DOT11_PRIV_WEP = 0, + DOT11_PRIV_TKIP = 1 +}; + +/* Prism "Nitro" / Frameburst / "Packet Frame Grouping" + * Value is in microseconds. Represents the # microseconds + * the firmware will take to group frames before sending out then out + * together with a CSMA contention. Without this all frames are + * sent with a CSMA contention. + * Bibliography: + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html + */ +enum dot11_maxframeburst_t { + /* Values for DOT11_OID_MAXFRAMEBURST */ + DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */ + DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */ + DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */ + DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max, + * Note: firmware allows for greater values. This is a + * recommended max. I'll update this as I find + * out what the real MAX is. Also note that you don't necessarily + * get better results with a greater value here. + */ +}; + +/* Support for 802.11 long and short frame preambles. + * Long preamble uses 128-bit sync field, 8-bit CRC + * Short preamble uses 56-bit sync field, 16-bit CRC + * + * 802.11a -- not sure, both optionally ? + * 802.11b supports long and optionally short + * 802.11g supports both */ +enum dot11_preamblesettings_t { + DOT11_PREAMBLESETTING_LONG = 0, + /* Allows *only* long 802.11 preambles */ + DOT11_PREAMBLESETTING_SHORT = 1, + /* Allows *only* short 802.11 preambles */ + DOT11_PREAMBLESETTING_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* Support for 802.11 slot timing (time between packets). + * + * Long uses 802.11a slot timing (9 usec ?) + * Short uses 802.11b slot timing (20 use ?) */ +enum dot11_slotsettings_t { + DOT11_SLOTSETTINGS_LONG = 0, + /* Allows *only* long 802.11b slot timing */ + DOT11_SLOTSETTINGS_SHORT = 1, + /* Allows *only* long 802.11a slot timing */ + DOT11_SLOTSETTINGS_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* All you need to know, ERP is "Extended Rate PHY". + * An Extended Rate PHY (ERP) STA or AP shall support three different + * preamble and header formats: + * Long preamble (refer to above) + * Short preamble (refer to above) + * OFDM preamble ( ? ) + * + * I'm assuming here Protection tells the AP + * to be careful, a STA which cannot handle the long pre-amble + * has joined. + */ +enum do11_nonerpstatus_t { + DOT11_ERPSTAT_NONEPRESENT = 0, + DOT11_ERPSTAT_USEPROTECTION = 1 +}; + +/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-* + * The key here is DOT11 NON ERP NEVER protects against + * NON ERP STA's. You *don't* want this unless + * you know what you are doing. It means you will only + * get Extended Rate capabilities */ +enum dot11_nonerpprotection_t { + DOT11_NONERP_NEVER = 0, + DOT11_NONERP_ALWAYS = 1, + DOT11_NONERP_DYNAMIC = 2 +}; + +/* Preset OID configuration for 802.11 modes + * Note: DOT11_OID_CW[MIN|MAX] hold the values of the + * DCS MIN|MAX backoff used */ +enum dot11_profile_t { /* And set/allowed values */ + /* Allowed values for DOT11_OID_PROFILES */ + DOT11_PROFILE_B_ONLY = 0, + /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 31 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG + */ + DOT11_PROFILE_MIXED_G_WIFI = 1, + /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 15 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC + */ + DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */ + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_G_ONLY = 3, + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_TEST = 4, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT + */ + DOT11_PROFILE_B_WIFI = 5, + /* Same as Profile B_ONLY */ + DOT11_PROFILE_A_ONLY = 6, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs + */ + DOT11_PROFILE_MIXED_SHORT = 7 + /* Same as MIXED_G_WIFI */ +}; + + +/* The dot11d conformance level configures the 802.11d conformance levels. + * The following conformance levels exist:*/ +enum oid_inl_conformance_t { + OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ + OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ + OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to + * determine channel AND/OR just make assumption that active + * channels are valid channels */ +}; + +enum oid_inl_mode_t { + INL_MODE_NONE = -1, + INL_MODE_PROMISCUOUS = 0, + INL_MODE_CLIENT = 1, + INL_MODE_AP = 2, + INL_MODE_SNIFFER = 3 +}; + +enum oid_inl_config_t { + INL_CONFIG_NOTHING = 0x00, + INL_CONFIG_MANUALRUN = 0x01, + INL_CONFIG_FRAMETRAP = 0x02, + INL_CONFIG_RXANNEX = 0x04, + INL_CONFIG_TXANNEX = 0x08, + INL_CONFIG_WDS = 0x10 +}; + +enum oid_inl_phycap_t { + INL_PHYCAP_2400MHZ = 1, + INL_PHYCAP_5000MHZ = 2, + INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ +}; + + +enum oid_num_t { + GEN_OID_MACADDRESS = 0, + GEN_OID_LINKSTATE, + GEN_OID_WATCHDOG, + GEN_OID_MIBOP, + GEN_OID_OPTIONS, + GEN_OID_LEDCONFIG, + + /* 802.11 */ + DOT11_OID_BSSTYPE, + DOT11_OID_BSSID, + DOT11_OID_SSID, + DOT11_OID_STATE, + DOT11_OID_AID, + DOT11_OID_COUNTRYSTRING, + DOT11_OID_SSIDOVERRIDE, + + DOT11_OID_MEDIUMLIMIT, + DOT11_OID_BEACONPERIOD, + DOT11_OID_DTIMPERIOD, + DOT11_OID_ATIMWINDOW, + DOT11_OID_LISTENINTERVAL, + DOT11_OID_CFPPERIOD, + DOT11_OID_CFPDURATION, + + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYID, + DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + DOT11_OID_STAKEY, + DOT11_OID_REKEYTHRESHOLD, + DOT11_OID_STASC, + + DOT11_OID_PRIVTXREJECTED, + DOT11_OID_PRIVRXPLAIN, + DOT11_OID_PRIVRXFAILED, + DOT11_OID_PRIVRXNOKEY, + + DOT11_OID_RTSTHRESH, + DOT11_OID_FRAGTHRESH, + DOT11_OID_SHORTRETRIES, + DOT11_OID_LONGRETRIES, + DOT11_OID_MAXTXLIFETIME, + DOT11_OID_MAXRXLIFETIME, + DOT11_OID_AUTHRESPTIMEOUT, + DOT11_OID_ASSOCRESPTIMEOUT, + + DOT11_OID_ALOFT_TABLE, + DOT11_OID_ALOFT_CTRL_TABLE, + DOT11_OID_ALOFT_RETREAT, + DOT11_OID_ALOFT_PROGRESS, + DOT11_OID_ALOFT_FIXEDRATE, + DOT11_OID_ALOFT_RSSIGRAPH, + DOT11_OID_ALOFT_CONFIG, + + DOT11_OID_VDCFX, + DOT11_OID_MAXFRAMEBURST, + + DOT11_OID_PSM, + DOT11_OID_CAMTIMEOUT, + DOT11_OID_RECEIVEDTIMS, + DOT11_OID_ROAMPREFERENCE, + + DOT11_OID_BRIDGELOCAL, + DOT11_OID_CLIENTS, + DOT11_OID_CLIENTSASSOCIATED, + DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + DOT11_OID_CLIENTFIND, + DOT11_OID_WDSLINKADD, + DOT11_OID_WDSLINKREMOVE, + DOT11_OID_EAPAUTHSTA, + DOT11_OID_EAPUNAUTHSTA, + DOT11_OID_DOT1XENABLE, + DOT11_OID_MICFAILURE, + DOT11_OID_REKEYINDICATE, + + DOT11_OID_MPDUTXSUCCESSFUL, + DOT11_OID_MPDUTXONERETRY, + DOT11_OID_MPDUTXMULTIPLERETRIES, + DOT11_OID_MPDUTXFAILED, + DOT11_OID_MPDURXSUCCESSFUL, + DOT11_OID_MPDURXDUPS, + DOT11_OID_RTSSUCCESSFUL, + DOT11_OID_RTSFAILED, + DOT11_OID_ACKFAILED, + DOT11_OID_FRAMERECEIVES, + DOT11_OID_FRAMEERRORS, + DOT11_OID_FRAMEABORTS, + DOT11_OID_FRAMEABORTSPHY, + + DOT11_OID_SLOTTIME, + DOT11_OID_CWMIN, /* MIN DCS backoff */ + DOT11_OID_CWMAX, /* MAX DCS backoff */ + DOT11_OID_ACKWINDOW, + DOT11_OID_ANTENNARX, + DOT11_OID_ANTENNATX, + DOT11_OID_ANTENNADIVERSITY, + DOT11_OID_CHANNEL, + DOT11_OID_EDTHRESHOLD, + DOT11_OID_PREAMBLESETTINGS, + DOT11_OID_RATES, + DOT11_OID_CCAMODESUPPORTED, + DOT11_OID_CCAMODE, + DOT11_OID_RSSIVECTOR, + DOT11_OID_OUTPUTPOWERTABLE, + DOT11_OID_OUTPUTPOWER, + DOT11_OID_SUPPORTEDRATES, + DOT11_OID_FREQUENCY, + DOT11_OID_SUPPORTEDFREQUENCIES, + DOT11_OID_NOISEFLOOR, + DOT11_OID_FREQUENCYACTIVITY, + DOT11_OID_IQCALIBRATIONTABLE, + DOT11_OID_NONERPPROTECTION, + DOT11_OID_SLOTSETTINGS, + DOT11_OID_NONERPTIMEOUT, + DOT11_OID_PROFILES, + DOT11_OID_EXTENDEDRATES, + + DOT11_OID_DEAUTHENTICATE, + DOT11_OID_AUTHENTICATE, + DOT11_OID_DISASSOCIATE, + DOT11_OID_ASSOCIATE, + DOT11_OID_SCAN, + DOT11_OID_BEACON, + DOT11_OID_PROBE, + DOT11_OID_DEAUTHENTICATEEX, + DOT11_OID_AUTHENTICATEEX, + DOT11_OID_DISASSOCIATEEX, + DOT11_OID_ASSOCIATEEX, + DOT11_OID_REASSOCIATE, + DOT11_OID_REASSOCIATEEX, + + DOT11_OID_NONERPSTATUS, + + DOT11_OID_STATIMEOUT, + DOT11_OID_MLMEAUTOLEVEL, + DOT11_OID_BSSTIMEOUT, + DOT11_OID_ATTACHMENT, + DOT11_OID_PSMBUFFER, + + DOT11_OID_BSSS, + DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + DOT11_OID_BSSFIND, + DOT11_OID_BSSLIST, + + OID_INL_TUNNEL, + OID_INL_MEMADDR, + OID_INL_MEMORY, + OID_INL_MODE, + OID_INL_COMPONENT_NR, + OID_INL_VERSION, + OID_INL_INTERFACE_ID, + OID_INL_COMPONENT_ID, + OID_INL_CONFIG, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_PHYCAPABILITIES, + OID_INL_OUTPUTPOWER, + + OID_NUM_LAST +}; + +/* We could add more flags. eg: in which mode are they allowed, ro, rw, ...*/ +#define OID_FLAG_CACHED 0x01 +#define OID_FLAG_U32 0x02 +#define OID_FLAG_MLMEEX 0x04 /* this type is special because of a variable + size field when sending. Not yet implemented (not used in driver). */ + +struct oid_t { + enum oid_num_t oid; + short range; /* to define a range of oid */ + short size; /* size of the associated data */ + char flags; +}; + +union oid_res_t { + void *ptr; + u32 u; +}; + +#define IWMAX_BITRATES 20 +#define IWMAX_BSS 24 +#define IWMAX_FREQ 30 + +#endif /* !defined(_ISL_OID_H) */ +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_dev.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,827 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.c,v 1.68 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "isl_38xx.h" +#include "isl_ioctl.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "islpci_eth.h" +#include "oid_mgt.h" + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) +#define prism54_synchronize_irq(irq) synchronize_irq() +#else +#define prism54_synchronize_irq(irq) synchronize_irq(irq) +#endif + +#define ISL3877_IMAGE_FILE "isl3877" +#define ISL3890_IMAGE_FILE "isl3890" + +/* Temporary dummy MAC address to use until firmware is loaded. + * The idea there is that some tools (such as nameif) may query + * the MAC address before the netdev is 'open'. By using a valid + * OUI prefix, they can process the netdev properly. + * Of course, this is not the final/real MAC address. It doesn't + * matter, as you are suppose to be able to change it anytime via + * ndev->set_mac_address. Jean II */ +const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; + +/****************************************************************************** + Device Interrupt Handler +******************************************************************************/ + +irqreturn_t +islpci_interrupt(int irq, void *config, struct pt_regs *regs) +{ + u32 reg; + islpci_private *priv = config; + struct net_device *ndev = priv->ndev; + void *device = priv->device_base; + int powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* received an interrupt request on a shared IRQ line + * first check whether the device is in sleep mode */ + reg = readl(device + ISL38XX_CTRL_STAT_REG); + if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) + /* device is in sleep mode, IRQ was generated by someone else */ + { + printk(KERN_DEBUG "Assuming someone else called the IRQ\n"); + return IRQ_NONE; + } + + if (islpci_get_state(priv) != PRV_STATE_SLEEP) + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* lock the interrupt handler */ + spin_lock(&priv->slock); + + /* check whether there is any source of interrupt on the device */ + reg = readl(device + ISL38XX_INT_IDENT_REG); + + /* also check the contents of the Interrupt Enable Register, because this + * will filter out interrupt sources from other devices on the same irq ! */ + reg &= readl(device + ISL38XX_INT_EN_REG); + reg &= ISL38XX_INT_SOURCES; + + if (reg != 0) { + /* reset the request bits in the Identification register */ + isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, + "IRQ: Identification register 0x%p 0x%x \n", device, reg); +#endif + + /* check for each bit in the register separately */ + if (reg & ISL38XX_INT_IDENT_UPDATE) { +#if VERBOSE > SHOW_ERROR_MESSAGES + /* Queue has been updated */ + DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + driver_curr_frag[0]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[1]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[2]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[3]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[4]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[5]) + ); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + device_curr_frag[0]), + le32_to_cpu(priv->control_block-> + device_curr_frag[1]), + le32_to_cpu(priv->control_block-> + device_curr_frag[2]), + le32_to_cpu(priv->control_block-> + device_curr_frag[3]), + le32_to_cpu(priv->control_block-> + device_curr_frag[4]), + le32_to_cpu(priv->control_block-> + device_curr_frag[5]) + ); +#endif + + /* cleanup the data low transmit queue */ + islpci_eth_cleanup_transmit(priv, priv->control_block); + + /* device is in active state, update the + * powerstate flag if necessary */ + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* check all three queues in priority order + * call the PIMFOR receive function until the + * queue is empty */ + if (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_MGMTQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Management Queue\n"); +#endif + islpci_mgt_receive(ndev); + + islpci_mgt_cleanup_transmit(ndev); + + /* Refill slots in receive queue */ + islpci_mgmt_rx_fill(ndev); + + /* no need to trigger the device, next + islpci_mgt_transaction does it */ + } + + while (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_DATA_LQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Data Low Queue \n"); +#endif + islpci_eth_receive(priv); + } + + /* check whether the data transmit queues were full */ + if (priv->data_low_tx_full) { + /* check whether the transmit is not full anymore */ + if (ISL38XX_CB_TX_QSIZE - + isl38xx_in_queue(priv->control_block, + ISL38XX_CB_TX_DATA_LQ) >= + ISL38XX_MIN_QTHRESHOLD) { + /* nope, the driver is ready for more network frames */ + netif_wake_queue(priv->ndev); + + /* reset the full flag */ + priv->data_low_tx_full = 0; + } + } + } + + if (reg & ISL38XX_INT_IDENT_INIT) { + /* Device has been initialized */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "IRQ: Init flag, device initialized \n"); +#endif + wake_up(&priv->reset_done); + } + + if (reg & ISL38XX_INT_IDENT_SLEEP) { + /* Device intends to move to powersave state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); +#endif + isl38xx_handle_sleep_request(priv->control_block, + &powerstate, + priv->device_base); + } + + if (reg & ISL38XX_INT_IDENT_WAKEUP) { + /* Device has been woken up to active state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); +#endif + + isl38xx_handle_wakeup(priv->control_block, + &powerstate, priv->device_base); + } + } + + /* sleep -> ready */ + if (islpci_get_state(priv) == PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_ACTIVE_STATE) + islpci_set_state(priv, PRV_STATE_READY); + + /* !sleep -> sleep */ + if (islpci_get_state(priv) != PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_POWERSAVE_STATE) + islpci_set_state(priv, PRV_STATE_SLEEP); + + /* unlock the interrupt handler */ + spin_unlock(&priv->slock); + + return IRQ_HANDLED; +} + +/****************************************************************************** + Network Interface Control & Statistical functions +******************************************************************************/ +static int +islpci_open(struct net_device *ndev) +{ + u32 rc; + islpci_private *priv = netdev_priv(ndev); + + printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name); + + /* reset data structures, upload firmware and reset device */ + rc = islpci_reset(priv,1); + if (rc) { + prism54_bring_down(priv); + return rc; /* Returns informative message */ + } + + netif_start_queue(ndev); +/* netif_mark_up( ndev ); */ + + return 0; +} + +static int +islpci_close(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); + + netif_stop_queue(ndev); + + return prism54_bring_down(priv); +} + +int +prism54_bring_down(islpci_private *priv) +{ + void *device_base = priv->device_base; + u32 reg; + /* we are going to shutdown the device */ + islpci_set_state(priv, PRV_STATE_PREBOOT); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* For safety reasons, we may want to ensure that no DMA transfer is + * currently in progress by emptying the TX and RX queues. */ + + /* wait until interrupts have finished executing on other CPUs */ + prism54_synchronize_irq(priv->pdev->irq); + + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(50*HZ/1000); + + return 0; +} + +static int +islpci_upload_fw(islpci_private *priv) +{ + islpci_state_t old_state; + u32 rc; + + old_state = islpci_set_state(priv, PRV_STATE_BOOT); + + printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); + + rc = isl38xx_upload_firmware(priv->firmware, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75)) + &priv->pdev->dev, +#else + pci_name(priv->pdev), +#endif + priv->device_base, + priv->device_host_address); + if (rc) { + /* error uploading the firmware */ + printk(KERN_ERR "%s: could not upload firmware ('%s')\n", + priv->ndev->name, priv->firmware); + + islpci_set_state(priv, old_state); + return rc; + } + + printk(KERN_DEBUG + "%s: firmware uploaded done, now triggering reset...\n", + priv->ndev->name); + + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + return 0; +} + +static int +islpci_reset_if(islpci_private *priv) +{ + long remaining; + int result = -ETIME; + int count; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + /* This is 2.6 specific, nicer, shorter, but not in 2.4 yet */ + DEFINE_WAIT(wait); + prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); +#else + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&priv->reset_done, &wait); +#endif + + /* now the last step is to reset the interface */ + isl38xx_interface_reset(priv->device_base, priv->device_host_address); + islpci_set_state(priv, PRV_STATE_PREINIT); + + for(count = 0; count < 2 && result; count++) { + /* The software reset acknowledge needs about 220 msec here. + * Be conservative and wait for up to one second. */ + + remaining = schedule_timeout(HZ); + + if(remaining > 0) { + result = 0; + break; + } + + /* If we're here it's because our IRQ hasn't yet gone through. + * Retry a bit more... + */ + printk(KERN_ERR "%s: device soft reset timed out\n", + priv->ndev->name); + + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + /* 2.6 specific too */ + finish_wait(&priv->reset_done, &wait); +#else + remove_wait_queue(&priv->reset_done, &wait); + set_current_state(TASK_RUNNING); +#endif + + if(result) + return result; + + islpci_set_state(priv, PRV_STATE_INIT); + + /* Now that the device is 100% up, let's allow + * for the other interrupts -- + * NOTE: this is not *yet* true since we've only allowed the + * INIT interrupt on the IRQ line. We can perhaps poll + * the IRQ line until we know for sure the reset went through */ + isl38xx_enable_common_interrupts(priv->device_base); + + prism54_mib_init_work(priv); + + islpci_set_state(priv, PRV_STATE_READY); + + return 0; +} + +int +islpci_reset(islpci_private *priv, int reload_firmware) +{ + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + unsigned counter; + int rc; + + if (reload_firmware) + islpci_set_state(priv, PRV_STATE_PREBOOT); + else + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* flush all management queues */ + priv->index_mgmt_tx = 0; + priv->index_mgmt_rx = 0; + + /* clear the indexes in the frame pointer */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + cb->driver_curr_frag[counter] = cpu_to_le32(0); + cb->device_curr_frag[counter] = cpu_to_le32(0); + } + + /* reset the mgmt receive queue */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; + frag->size = MGMT_FRAME_SIZE; + frag->flags = 0; + frag->address = priv->mgmt_rx[counter].pci_addr; + } + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + cb->rx_data_low[counter].address = + cpu_to_le32((u32) priv->pci_map_rx_address[counter]); + } + + /* since the receive queues are filled with empty fragments, now we can + * set the corresponding indexes in the Control Block */ + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = + cpu_to_le32(ISL38XX_CB_RX_QSIZE); + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); + + /* reset the remaining real index registers and full flags */ + priv->free_data_rx = 0; + priv->free_data_tx = 0; + priv->data_low_tx_full = 0; + + if (reload_firmware) { /* Should we load the firmware ? */ + /* now that the data structures are cleaned up, upload + * firmware and reset interface */ + rc = islpci_upload_fw(priv); + if (rc) + return rc; + } + + /* finally reset interface */ + rc = islpci_reset_if(priv); + if (!rc) /* If successful */ + return rc; + + printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); + return rc; + +} + +struct net_device_stats * +islpci_statistics(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n"); +#endif + + return &priv->statistics; +} + +/****************************************************************************** + Network device configuration functions +******************************************************************************/ +int +islpci_alloc_memory(islpci_private *priv) +{ + int counter; + +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG "islpci_alloc_memory\n"); +#endif + + /* remap the PCI device base address to accessable */ + if (!(priv->device_base = + ioremap(pci_resource_start(priv->pdev, 0), + ISL38XX_PCI_MEM_SIZE))) { + /* error in remapping the PCI device memory address range */ + printk(KERN_ERR "PCI memory remapping failed \n"); + return -1; + } + + /* memory layout for consistent DMA region: + * + * Area 1: Control Block for the device interface + * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that + * the number of supported stations in the AP determines the minimal + * size of the buffer ! + */ + + /* perform the allocation */ + priv->driver_mem_address = pci_alloc_consistent(priv->pdev, + HOST_MEM_BLOCK, + &priv-> + device_host_address); + + if (!priv->driver_mem_address) { + /* error allocating the block of PCI memory */ + printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", + "prism54"); + return -1; + } + + /* assign the Control Block to the first address of the allocated area */ + priv->control_block = + (isl38xx_control_block *) priv->driver_mem_address; + + /* set the Power Save Buffer pointer directly behind the CB */ + priv->device_psm_buffer = + priv->device_host_address + CONTROL_BLOCK_SIZE; + + /* make sure all buffer pointers are initialized */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); + priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); + } + + priv->index_mgmt_rx = 0; + memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); + memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); + + /* allocate rx queue for management frames */ + if (islpci_mgmt_rx_fill(priv->ndev) < 0) + goto out_free; + + /* now get the data rx skb's */ + memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); + memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + struct sk_buff *skb; + + /* allocate an sk_buff for received data frames storage + * each frame on receive size consists of 1 fragment + * include any required allignment operations */ + if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { + /* error allocating an sk_buff structure elements */ + printk(KERN_ERR "Error allocating skb.\n"); + skb = NULL; + goto out_free; + } + /* add the new allocated sk_buff to the buffer array */ + priv->data_low_rx[counter] = skb; + + /* map the allocated skb data area to pci */ + priv->pci_map_rx_address[counter] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (!priv->pci_map_rx_address[counter]) { + /* error mapping the buffer to device + accessable memory address */ + printk(KERN_ERR "failed to map skb DMA'able\n"); + goto out_free; + } + } + + prism54_acl_init(&priv->acl); + prism54_wpa_ie_init(priv); + if (mgt_init(priv)) + goto out_free; + + return 0; + out_free: + islpci_free_memory(priv); + return -1; +} + +int +islpci_free_memory(islpci_private *priv) +{ + int counter; + + if (priv->device_base) + iounmap(priv->device_base); + priv->device_base = 0; + + /* free consistent DMA area... */ + if (priv->driver_mem_address) + pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); + + /* clear some dangling pointers */ + priv->driver_mem_address = 0; + priv->device_host_address = 0; + priv->device_psm_buffer = 0; + priv->control_block = 0; + + /* clean up mgmt rx buffers */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + struct islpci_membuf *buf = &priv->mgmt_rx[counter]; + if (buf->pci_addr) + pci_unmap_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + buf->pci_addr = 0; + if (buf->mem) + kfree(buf->mem); + buf->size = 0; + buf->mem = NULL; + } + + /* clean up data rx buffers */ + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + if (priv->pci_map_rx_address[counter]) + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[counter], + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + priv->pci_map_rx_address[counter] = 0; + + if (priv->data_low_rx[counter]) + dev_kfree_skb(priv->data_low_rx[counter]); + priv->data_low_rx[counter] = 0; + } + + /* Free the acces control list and the WPA list */ + prism54_acl_clean(&priv->acl); + prism54_wpa_ie_clean(priv); + mgt_clean(priv); + + return 0; +} + +#if 0 +static void +islpci_set_multicast_list(struct net_device *dev) +{ + /* put device into promisc mode and let network layer handle it */ +} +#endif + +struct net_device * +islpci_setup(struct pci_dev *pdev) +{ + islpci_private *priv; + struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); + + if (!ndev) + return ndev; + + SET_MODULE_OWNER(ndev); + pci_set_drvdata(pdev, ndev); +#if defined(SET_NETDEV_DEV) + SET_NETDEV_DEV(ndev, &pdev->dev); +#endif + + /* setup the structure members */ + ndev->base_addr = pci_resource_start(pdev, 0); + ndev->irq = pdev->irq; + + /* initialize the function pointers */ + ndev->open = &islpci_open; + ndev->stop = &islpci_close; + ndev->get_stats = &islpci_statistics; + ndev->get_wireless_stats = &prism54_get_wireless_stats; + ndev->do_ioctl = &prism54_ioctl; + ndev->wireless_handlers = + (struct iw_handler_def *) &prism54_handler_def; + + ndev->hard_start_xmit = &islpci_eth_transmit; + /* ndev->set_multicast_list = &islpci_set_multicast_list; */ + ndev->addr_len = ETH_ALEN; + ndev->set_mac_address = &prism54_set_mac_address; + /* Get a non-zero dummy MAC address for nameif. Jean II */ + memcpy(ndev->dev_addr, dummy_mac, 6); + +#ifdef HAVE_TX_TIMEOUT + ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; + ndev->tx_timeout = &islpci_eth_tx_timeout; +#endif + + /* allocate a private device structure to the network device */ + priv = netdev_priv(ndev); + priv->ndev = ndev; + priv->pdev = pdev; + + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? + ARPHRD_IEEE80211: ARPHRD_ETHER; + + /* save the start and end address of the PCI memory area */ + ndev->mem_start = (unsigned long) priv->device_base; + ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); +#endif + + init_waitqueue_head(&priv->reset_done); + + /* init the queue read locks, process wait counter */ + sema_init(&priv->mgmt_sem, 1); + priv->mgmt_received = NULL; + init_waitqueue_head(&priv->mgmt_wqueue); + sema_init(&priv->stats_sem, 1); + spin_lock_init(&priv->slock); + + /* init state machine with off#1 state */ + priv->state = PRV_STATE_OFF; + priv->state_off = 1; + + /* initialize workqueue's */ + INIT_WORK(&priv->stats_work, + (void (*)(void *)) prism54_update_stats, priv); + + priv->stats_timestamp = 0; + + /* allocate various memory areas */ + if (islpci_alloc_memory(priv)) + goto do_free_netdev; + + /* select the firmware file depending on the device id */ + switch (pdev->device) { + case PCIDEVICE_ISL3890: + case PCIDEVICE_3COM6001: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + case PCIDEVICE_ISL3877: + strcpy(priv->firmware, ISL3877_IMAGE_FILE); + break; + + default: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + } + + if (register_netdev(ndev)) { + DEBUG(SHOW_ERROR_MESSAGES, + "ERROR: register_netdev() failed \n"); + goto do_islpci_free_memory; + } + + return ndev; + + do_islpci_free_memory: + islpci_free_memory(priv); + do_free_netdev: + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + return NULL; +} + +islpci_state_t +islpci_set_state(islpci_private *priv, islpci_state_t new_state) +{ + islpci_state_t old_state; + + /* lock */ + old_state = priv->state; + + /* this means either a race condition or some serious error in + * the driver code */ + switch (new_state) { + case PRV_STATE_OFF: + priv->state_off++; + default: + priv->state = new_state; + break; + + case PRV_STATE_PREBOOT: + /* there are actually many off-states, enumerated by + * state_off */ + if (old_state == PRV_STATE_OFF) + priv->state_off--; + + /* only if hw_unavailable is zero now it means we either + * were in off#1 state, or came here from + * somewhere else */ + if (!priv->state_off) + priv->state = new_state; + break; + }; +#if 0 + printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", + priv->ndev->name, old_state, new_state, priv->state_off); +#endif + + /* invariants */ + BUG_ON(priv->state_off < 0); + BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); + BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); + + /* unlock */ + return old_state; +} diff -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_dev.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,228 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.h,v 1.53 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_DEV_H +#define _ISLPCI_DEV_H + +#include +#include +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +# include +#else +# include +# define work_struct tq_struct +# define INIT_WORK INIT_TQUEUE +# define schedule_work schedule_task +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +#define free_netdev(x) kfree(x) +#define pci_name(x) x->slot_name +#endif + +#include "isl_38xx.h" +#include "isl_oid.h" +#include "islpci_mgt.h" + +/* some states might not be superflous and may be removed when + design is finalized (hvr) */ +typedef enum { + PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ + PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ + PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ + PRV_STATE_POSTBOOT, /* after boot state, need reset now */ + PRV_STATE_PREINIT, /* pre-init state */ + PRV_STATE_INIT, /* init state (restore MIB backup to device) */ + PRV_STATE_READY, /* driver&device are in operational state */ + PRV_STATE_SLEEP /* device in sleep mode */ +} islpci_state_t; + +/* ACL using MAC address */ +struct mac_entry { + struct list_head _list; + char addr[ETH_ALEN]; +}; + +struct islpci_acl { + enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; + struct list_head mac_list; /* a list of mac_entry */ + int size; /* size of queue */ + struct semaphore sem; /* accessed in ioctls and trap_work */ +}; + +struct islpci_membuf { + int size; /* size of memory */ + void *mem; /* address of memory as seen by CPU */ + dma_addr_t pci_addr; /* address of memory as seen by device */ +}; + +#define MAX_BSS_WPA_IE_COUNT 64 +#define MAX_WPA_IE_LEN 64 +struct islpci_bss_wpa_ie { + struct list_head list; + unsigned long last_update; + u8 bssid[ETH_ALEN]; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + +}; + +typedef struct { + spinlock_t slock; /* generic spinlock; */ + + u32 priv_oid; + + /* our mib cache */ + u32 iw_mode; + struct rw_semaphore mib_sem; + void **mib; + char nickname[IW_ESSID_MAX_SIZE+1]; + + /* Take care of the wireless stats */ + struct work_struct stats_work; + struct semaphore stats_sem; + /* remember when we last updated the stats */ + unsigned long stats_timestamp; + /* The first is accessed under semaphore locking. + * The second is the clean one we return to iwconfig. + */ + struct iw_statistics local_iwstatistics; + struct iw_statistics iwstatistics; + + struct islpci_acl acl; + + /* PCI bus allocation & configuration members */ + struct pci_dev *pdev; /* PCI structure information */ + u32 pci_state[16]; /* used for suspend/resume */ + char firmware[33]; + + void *device_base; /* ioremapped device base address */ + + /* consistent DMA region */ + void *driver_mem_address; /* base DMA address */ + dma_addr_t device_host_address; /* base DMA address (bus address) */ + dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ + + /* our network_device structure */ + struct net_device *ndev; + + /* device queue interface members */ + struct isl38xx_cb *control_block; /* device control block + (== driver_mem_address!) */ + + /* Each queue has three indexes: + * free/index_mgmt/data_rx/tx (called index, see below), + * driver_curr_frag, and device_curr_frag (in the control block) + * All indexes are ever-increasing, but interpreted modulo the + * device queue size when used. + * index <= device_curr_frag <= driver_curr_frag at all times + * For rx queues, [index, device_curr_frag) contains fragments + * that the interrupt processing needs to handle (owned by driver). + * [device_curr_frag, driver_curr_frag) is the free space in the + * rx queue, waiting for data (owned by device). The driver + * increments driver_curr_frag to indicate to the device that more + * buffers are available. + * If device_curr_frag == driver_curr_frag, no more rx buffers are + * available, and the rx DMA engine of the device is halted. + * For tx queues, [index, device_curr_frag) contains fragments + * where tx is done; they need to be freed (owned by driver). + * [device_curr_frag, driver_curr_frag) contains the frames + * that are being transferred (owned by device). The driver + * increments driver_curr_frag to indicate that more tx work + * needs to be done. + */ + u32 index_mgmt_rx; /* real index mgmt rx queue */ + u32 index_mgmt_tx; /* read index mgmt tx queue */ + u32 free_data_rx; /* free pointer data rx queue */ + u32 free_data_tx; /* free pointer data tx queue */ + u32 data_low_tx_full; /* full detected flag */ + + /* frame memory buffers for the device queues */ + struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; + struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; + struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; + struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; + dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; + dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; + + /* driver network interface members */ + struct net_device_stats statistics; + + /* wait for a reset interrupt */ + wait_queue_head_t reset_done; + + /* used by islpci_mgt_transaction */ + struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ + struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ + wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ + + /* state machine */ + islpci_state_t state; + int state_off; /* enumeration of off-state, if 0 then + * we're not in any off-state */ + + /* WPA stuff */ + int wpa; /* WPA mode enabled */ + struct list_head bss_wpa_list; + int num_bss_wpa; + struct semaphore wpa_sem; +} islpci_private; + +static inline islpci_state_t +islpci_get_state(islpci_private *priv) +{ + /* lock */ + return priv->state; + /* unlock */ +} + +islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); + +#define ISLPCI_TX_TIMEOUT (2*HZ) + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,75)) +# define irqreturn_t void +# define IRQ_HANDLED +# define IRQ_NONE +#endif + +irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); + +int prism54_post_setup(islpci_private *, int); +int islpci_reset(islpci_private *, int); + +static inline void +islpci_trigger(islpci_private *priv) +{ + isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, + priv->device_base); +} + +struct net_device_stats *islpci_statistics(struct net_device *); + +int prism54_bring_down(islpci_private *); +int islpci_alloc_memory(islpci_private *); +int islpci_free_memory(islpci_private *); +struct net_device *islpci_setup(struct pci_dev *); +#endif /* _ISLPCI_DEV_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_eth.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,434 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.27 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include + +#include "isl_38xx.h" +#include "islpci_eth.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Network Interface functions +******************************************************************************/ +void +islpci_eth_cleanup_transmit(islpci_private *priv, + isl38xx_control_block *control_block) +{ + struct sk_buff *skb; + u32 index; + + /* compare the control block read pointer with the free pointer */ + while (priv->free_data_tx != + le32_to_cpu(control_block-> + device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { + /* read the index of the first fragment to be freed */ + index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; + + /* check for holes in the arrays caused by multi fragment frames + * searching for the last fragment of a frame */ + if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + /* entry is the last fragment of a frame + * free the skb structure and unmap pci memory */ + skb = priv->data_low_tx[index]; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", + skb, skb->data, skb->len, skb->truesize); +#endif + + pci_unmap_single(priv->pdev, + priv->pci_map_tx_address[index], + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + skb = NULL; + } + /* increment the free data low queue pointer */ + priv->free_data_tx++; + } +} + +int +islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = priv->control_block; + u32 index; + dma_addr_t pci_map_address; + int frame_size; + isl38xx_fragment *fragment; + int offset; + struct sk_buff *newskb; + int newskb_offset; + unsigned long flags; + unsigned char wds_mac[6]; + u32 curr_frag; + int err = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); +#endif + + /* lock the driver code */ + spin_lock_irqsave(&priv->slock, flags); + + /* determine the amount of fragments needed to store the frame */ + + frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + if (init_wds) + frame_size += 6; + + /* check whether the destination queue has enough fragments for the frame */ + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); + if (curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE) { + printk(KERN_ERR "%s: transmit device queue full when awake\n", + ndev->name); + netif_stop_queue(ndev); + + /* trigger the device */ + isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + err = -EBUSY; + goto drop_free; + } + /* Check alignment and WDS frame formatting. The start of the packet should + * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes + * and add WDS address information */ + if (((long) skb->data & 0x03) | init_wds) { + /* get the number of bytes to add and re-allign */ + offset = (4 - (long) skb->data) & 0x03; + offset += init_wds ? 6 : 0; + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, + init_wds); +#endif + + /* align the buffer on 4-byte boundary */ + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + if (init_wds) { + /* wds requires an additional address field of 6 bytes */ + skb_put(skb, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + memmove(skb->data + 6, src, skb->len); + memcpy(skb->data, wds_mac, 6); + } else { + memmove(skb->data, src, skb->len); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, + src, skb->len); +#endif + } else { + newskb = + dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); + newskb_offset = (4 - (long) newskb->data) & 0x03; + + /* Check if newskb->data is aligned */ + if (newskb_offset) + skb_reserve(newskb, newskb_offset); + + skb_put(newskb, init_wds ? skb->len + 6 : skb->len); + if (init_wds) { + memcpy(newskb->data + 6, skb->data, skb->len); + memcpy(newskb->data, wds_mac, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + } else + memcpy(newskb->data, skb->data, skb->len); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", + newskb->data, skb->data, skb->len, init_wds); +#endif + + newskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = newskb; + } + } + /* display the buffer contents for debugging */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* map the skb buffer to pci memory for DMA operation */ + pci_map_address = pci_map_single(priv->pdev, + (void *) skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_map_address == 0) { + printk(KERN_WARNING "%s: cannot map buffer to PCI\n", + ndev->name); + + err = -EIO; + goto drop_free; + } + /* Place the fragment in the control block structure. */ + index = curr_frag % ISL38XX_CB_TX_QSIZE; + fragment = &cb->tx_data_low[index]; + + priv->pci_map_tx_address[index] = pci_map_address; + /* store the skb address for future freeing */ + priv->data_low_tx[index] = skb; + /* set the proper fragment start address and size information */ + fragment->size = cpu_to_le16(frame_size); + fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ + fragment->address = cpu_to_le32(pci_map_address); + curr_frag++; + + /* The fragment address in the control block must have been + * written before announcing the frame buffer to device. */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); + + if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD + > ISL38XX_CB_TX_QSIZE) { + /* stop sends from upper layers */ + netif_stop_queue(ndev); + + /* set the full flag for the transmission queue */ + priv->data_low_tx_full = 1; + } + + /* trigger the device */ + islpci_trigger(priv); + + /* unlock the driver code */ + spin_unlock_irqrestore(&priv->slock, flags); + + /* set the transmission time */ + ndev->trans_start = jiffies; + priv->statistics.tx_packets++; + priv->statistics.tx_bytes += skb->len; + + return 0; + + drop_free: + /* free the skbuf structure before aborting */ + dev_kfree_skb(skb); + skb = NULL; + + priv->statistics.tx_dropped++; + spin_unlock_irqrestore(&priv->slock, flags); + return err; +} + +int +islpci_eth_receive(islpci_private *priv) +{ + struct net_device *ndev = priv->ndev; + isl38xx_control_block *control_block = priv->control_block; + struct sk_buff *skb; + u16 size; + u32 index, offset; + unsigned char *src; + int discard = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n"); +#endif + + /* the device has written an Ethernet frame in the data area + * of the sk_buff without updating the structure, do it now */ + index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; + size = le16_to_cpu(control_block->rx_data_low[index].size); + skb = priv->data_low_rx[index]; + offset = ((unsigned long) le32_to_cpu(control_block->rx_data_low[index].address) - + (unsigned long) skb->data) & 3; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", + control_block->rx_data_low[priv->free_data_rx].address, skb->data, + skb->len, offset, skb->truesize); +#endif + + /* delete the streaming DMA mapping before processing the skb */ + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + + /* update the skb structure and allign the buffer */ + skb_put(skb, size); + if (offset) { + /* shift the buffer allocation offset bytes to get the right frame */ + skb_pull(skb, 2); + skb_put(skb, 2); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* check whether WDS is enabled and whether the data frame is a WDS frame */ + + if (init_wds) { + /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ + src = skb->data + 6; + memmove(skb->data, src, skb->len - 6); + skb_trim(skb, skb->len - 6); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); + DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); + + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* do some additional sk_buff and network layer parameters */ + skb->dev = ndev; + + /* take care of monitor mode */ + if (priv->iw_mode == IW_MODE_MONITOR) { + /* The card reports full 802.11 packets but with a 20 bytes + * header and without the FCS. But there a is a bit that + * indicates if the packet is corrupted :-) */ + /* int i; */ + if (skb->data[8] & 0x01){ + /* This one is bad. Drop it !*/ + discard = 1; + /* printk("BAD\n");*/ + } + /* + for(i=0;i<50;i++) + printk("%2.2X:",skb->data[i]); + printk("\n"); + */ + skb_pull(skb, 20); + skb->protocol = htons(ETH_P_802_2); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + } else + skb->protocol = eth_type_trans(skb, ndev); + + skb->ip_summed = CHECKSUM_NONE; + priv->statistics.rx_packets++; + priv->statistics.rx_bytes += size; + + /* deliver the skb to the network layer */ +#ifdef ISLPCI_ETH_DEBUG + printk + ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5]); +#endif + if (discard) { + dev_kfree_skb(skb); + skb = NULL; + } + else + netif_rx(skb); + + /* increment the read index for the rx data low queue */ + priv->free_data_rx++; + + /* add one or more sk_buff structures */ + while (index = + le32_to_cpu(control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), + index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { + /* allocate an sk_buff for received data frames storage + * include any required allignment operations */ + if (skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2), skb == NULL) { + /* error allocating an sk_buff structure elements */ + DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n"); + break; + } + /* store the new skb structure pointer */ + index = index % ISL38XX_CB_RX_QSIZE; + priv->data_low_rx[index] = skb; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", + skb, skb->data, skb->len, index, skb->truesize); +#endif + + /* set the streaming DMA mapping for proper PCI bus operation */ + priv->pci_map_rx_address[index] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (priv->pci_map_rx_address[index] == (dma_addr_t) NULL) { + /* error mapping the buffer to device accessable memory address */ + DEBUG(SHOW_ERROR_MESSAGES, + "Error mapping DMA address\n"); + + /* free the skbuf structure before aborting */ + dev_kfree_skb((struct sk_buff *) skb); + skb = NULL; + break; + } + /* update the fragment address */ + control_block->rx_data_low[index].address = cpu_to_le32((u32) + priv-> + pci_map_rx_address + [index]); + wmb(); + + /* increment the driver read pointer */ + add_le32p((u32 *) & control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); + } + + /* trigger the device */ + islpci_trigger(priv); + + return 0; +} + +void +islpci_eth_tx_timeout(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + struct net_device_stats *statistics = &priv->statistics; + + /* increment the transmit error counter */ + statistics->tx_errors++; + +#if 0 + /* don't do this here! we are not allowed to sleep since we are in interrupt context */ + if (islpci_reset(priv)) + printk(KERN_ERR "%s: error on TX timeout card reset!\n", + ndev->name); +#endif + + /* netif_wake_queue(ndev); */ + return; +} diff -Nru a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_eth.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,31 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.h,v 1.5 2004/01/12 22:16:32 jmaurer Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_ETH_H +#define _ISLPCI_ETH_H + +#include "isl_38xx.h" +#include "islpci_dev.h" + +void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); +int islpci_eth_transmit(struct sk_buff *, struct net_device *); +int islpci_eth_receive(islpci_private *); +void islpci_eth_tx_timeout(struct net_device *); + +#endif /* _ISL_GEN_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_hotplug.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,436 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_hotplug.c,v 1.56 2004/02/26 23:33:02 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include /* For __init, __exit */ + +#include "islpci_dev.h" +#include "islpci_mgt.h" /* for pc_debug */ +#include "isl_oid.h" + +#define DRV_NAME "prism54" +#define DRV_VERSION "1.1" + +MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team "); +MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); +MODULE_LICENSE("GPL"); + +/* In this order: vendor, device, subvendor, subdevice, class, class_mask, + * driver_data + * Note: for driver_data we put the device's name + * If you have an update for this please contact prism54-devel@prism54.org + * The latest list can be found at http://prism54.org/supported_cards.php */ +static const struct pci_device_id prism54_id_tbl[] = { + { + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + 0, 0, + (unsigned long) "3COM 3CRWE154G72 Wireless LAN adapter"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_DLINK, 0x3202UL, + 0, 0, + (unsigned long) "D-Link Air Plus Xtreme G A1 - DWL-g650 A1"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_IODATA, 0xd019UL, + 0, 0, + (unsigned long) "I-O Data WN-G54/CB - WN-G54/CB"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_NETGEAR, 0x4800UL, + 0, 0, + (unsigned long) "Netgear WG511"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0020UL, + 0, 0, + (unsigned long) "PLANEX GW-DS54G"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2802UL, + 0, 0, + (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2802W"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2835UL, + 0, 0, + (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Adapter - SMC2835W"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_INTERSIL, 0x0000UL, /* This was probably a bogus reading... */ + 0, 0, + (unsigned long) "SparkLAN WL-850F"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0014UL, + 0, 0, + (unsigned long) "I4 Z-Com XG-600"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0020UL, + 0, 0, + (unsigned long) "I4 Z-Com XG-900/PLANEX GW-DS54G"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_ACCTON, 0xee03UL, + 0, 0, + (unsigned long) "SMC 2802Wv2"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0xa835UL, + 0, 0, + (unsigned long) "SMC 2835Wv2"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (unsigned long) "Intersil PRISM Indigo Wireless LAN adapter"}, + { /* Default */ + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (unsigned long) "Intersil PRISM Duette/Prism GT Wireless LAN adapter"}, + {0,} +}; + +/* register the device with the Hotplug facilities of the kernel */ +MODULE_DEVICE_TABLE(pci, prism54_id_tbl); + +static int prism54_probe(struct pci_dev *, const struct pci_device_id *); +static void prism54_remove(struct pci_dev *); +static int prism54_suspend(struct pci_dev *, u32 state); +static int prism54_resume(struct pci_dev *); + +static struct pci_driver prism54_driver = { + .name = DRV_NAME, + .id_table = prism54_id_tbl, + .probe = prism54_probe, + .remove = prism54_remove, + .suspend = prism54_suspend, + .resume = prism54_resume, + /* .enable_wake ; we don't support this yet */ +}; + +static void +prism54_get_card_model(struct net_device *ndev) +{ + islpci_private *priv; + char *modelp; + + priv = netdev_priv(ndev); + switch (priv->pdev->subsystem_device) { + case PCIDEVICE_ISL3877: + modelp = "PRISM Indigo"; + break; + case PCIDEVICE_3COM6001: + modelp = "3COM 3CRWE154G72"; + break; + case 0x3202UL: + modelp = "D-Link DWL-g650 A1"; + break; + case 0xd019UL: + modelp = "WN-G54/CB"; + break; + case 0x4800UL: + modelp = "Netgear WG511"; + break; + case 0x2802UL: + modelp = "SMC2802W"; + break; + case 0xee03UL: + modelp = "SMC2802W V2"; + break; + case 0x2835UL: + modelp = "SMC2835W"; + break; + case 0xa835UL: + modelp = "SMC2835W V2"; + break; + /* Let's leave this one out for now since it seems bogus/wrong + * Even if the manufacturer did use 0x0000UL it may not be correct + * by their part, therefore deserving no name ;) */ + /* case 0x0000UL: + * modelp = "SparkLAN WL-850F"; + * break;*/ + + /* We have two reported for the one below :( */ + case 0x0014UL: + modelp = "XG-600"; + break; + case 0x0020UL: + modelp = "XG-900/GW-DS54G"; + break; +/* Default it */ +/* + case PCIDEVICE_ISL3890: + modelp = "PRISM Duette/GT"; + break; +*/ + default: + modelp = "PRISM Duette/GT"; + } + printk(KERN_DEBUG "%s: %s driver detected card model: %s\n", + ndev->name, DRV_NAME, modelp); + return; +} + +/****************************************************************************** + Module initialization functions +******************************************************************************/ + +int +prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *ndev; + u8 latency_tmr; + u32 mem_addr; + islpci_private *priv; + int rvalue; + + /* TRACE(DRV_NAME); */ + + + /* Enable the pci device */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); + return -ENODEV; + } + + /* check whether the latency timer is set correctly */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); +#endif + if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { + /* set the latency timer */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + PCIDEVICE_LATENCY_TIMER_VAL); + } + + /* enable PCI DMA */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); + goto do_pci_disable_device; + } + + /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) + * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) + * The RETRY_TIMEOUT is used to set the number of retries that the core, as a + * Master, will perform before abandoning a cycle. The default value for + * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new + * devices. A write of zero to the RETRY_TIMEOUT register disables this + * function to allow use with any non-compliant legacy devices that may + * execute more retries. + * + * Writing zero to both these two registers will disable both timeouts and + * *can* solve problems caused by devices that are slow to respond. + */ + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x41, 0); + + /* request the pci device I/O regions */ + rvalue = pci_request_regions(pdev, DRV_NAME); + if (rvalue) { + printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", + DRV_NAME, rvalue); + goto do_pci_disable_device; + } + + /* check if the memory window is indeed set */ + rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); + if (rvalue || !mem_addr) { + printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", + DRV_NAME); + goto do_pci_disable_device; + } + + /* enable PCI bus-mastering */ + DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); + pci_set_master(pdev); + + /* setup the network device interface and its structure */ + if (!(ndev = islpci_setup(pdev))) { + /* error configuring the driver as a network device */ + printk(KERN_ERR "%s: could not configure network device\n", + DRV_NAME); + goto do_pci_release_regions; + } + + priv = netdev_priv(ndev); + islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ + + /* card is in unknown state yet, might have some interrupts pending */ + isl38xx_disable_interrupts(priv->device_base); + + /* request for the interrupt before uploading the firmware */ + rvalue = request_irq(pdev->irq, &islpci_interrupt, + SA_SHIRQ, ndev->name, priv); + + if (rvalue) { + /* error, could not hook the handler to the irq */ + printk(KERN_ERR "%s: could not install IRQ handler\n", + ndev->name); + goto do_unregister_netdev; + } + + /* firmware upload is triggered in islpci_open */ + + /* Pretty card model discovery output */ + prism54_get_card_model(ndev); + + return 0; + + do_unregister_netdev: + unregister_netdev(ndev); + islpci_free_memory(priv); + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + do_pci_release_regions: + pci_release_regions(pdev); + do_pci_disable_device: + pci_disable_device(pdev); + return -EIO; +} + +/* set by cleanup_module */ +static volatile int __in_cleanup_module = 0; + +/* this one removes one(!!) instance only */ +void +prism54_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + if (!__in_cleanup_module) { + printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); + islpci_set_state(priv, PRV_STATE_OFF); + } + + printk(KERN_DEBUG "%s: removing device\n", ndev->name); + + unregister_netdev(ndev); + + /* free the interrupt request */ + + if (islpci_get_state(priv) != PRV_STATE_OFF) { + isl38xx_disable_interrupts(priv->device_base); + islpci_set_state(priv, PRV_STATE_OFF); + /* This bellow causes a lockup at rmmod time. It might be + * because some interrupts still linger after rmmod time, + * see bug #17 */ + /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ + } + + free_irq(pdev->irq, priv); + + /* free the PCI memory and unmap the remapped page */ + islpci_free_memory(priv); + + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + + pci_release_regions(pdev); + + pci_disable_device(pdev); +} + +int +prism54_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got suspend request (state %d)\n", + ndev->name, state); + + pci_save_state(pdev, priv->pci_state); + + /* tell the device not to trigger interrupts for now... */ + isl38xx_disable_interrupts(priv->device_base); + + /* from now on assume the hardware was already powered down + and don't touch it anymore */ + islpci_set_state(priv, PRV_STATE_OFF); + + netif_stop_queue(ndev); + netif_device_detach(ndev); + + return 0; +} + +int +prism54_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got resume request\n", ndev->name); + + pci_restore_state(pdev, priv->pci_state); + + /* alright let's go into the PREBOOT state */ + islpci_reset(priv, 1); + + netif_device_attach(ndev); + netif_start_queue(ndev); + + return 0; +} + +static int __init +prism54_module_init(void) +{ + printk(KERN_INFO "Loaded %s driver, version %s\n", + DRV_NAME, DRV_VERSION); + + __bug_on_wrong_struct_sizes (); + + return pci_module_init(&prism54_driver); +} + +/* by the time prism54_module_exit() terminates, as a postcondition + * all instances will have been destroyed by calls to + * prism54_remove() */ +static void __exit +prism54_module_exit(void) +{ + __in_cleanup_module = 1; + + pci_unregister_driver(&prism54_driver); + + printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); + + __in_cleanup_module = 0; +} + +/* register entry points */ +module_init(prism54_module_init); +module_exit(prism54_module_exit); +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_mgt.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,511 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.c,v 1.40 2004/02/01 10:57:23 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright 2004 Jens Maurer + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "isl_38xx.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "isl_ioctl.h" + +#include + +/****************************************************************************** + Global variable definition section +******************************************************************************/ +int pc_debug = VERBOSE; +module_param(pc_debug, int, 0); + +/****************************************************************************** + Driver general functions +******************************************************************************/ +void +display_buffer(char *buffer, int length) +{ + if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) + return; + + while (length > 0) { + printk("[%02x]", *buffer & 255); + length--; + buffer++; + } + + printk("\n"); +} + +/***************************************************************************** + Queue handling for management frames +******************************************************************************/ + + +/* + * Helper function to create a PIMFOR management frame header. + */ +static void +pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) +{ + h->version = PIMFOR_VERSION; + h->operation = operation; + h->device_id = PIMFOR_DEV_ID_MHLI_MIB; + h->flags = 0; + h->oid = cpu_to_be32(oid); + h->length = cpu_to_be32(length); +} + +/* + * Helper function to analyze a PIMFOR management frame header. + */ +static pimfor_header_t * +pimfor_decode_header(void *data, int len) +{ + pimfor_header_t *h = data; + + while ((void *) h < data + len) { + if(h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { + le32_to_cpus(&h->oid); + le32_to_cpus(&h->length); + } else { + be32_to_cpus(&h->oid); + be32_to_cpus(&h->length); + } + if (h->oid != OID_INL_TUNNEL) + return h; + h++; + } + return NULL; +} + +/* + * Fill the receive queue for management frames with fresh buffers. + */ +int +islpci_mgmt_rx_fill(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n"); +#endif + + while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { + u32 index = curr % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; + + if (buf->mem == NULL) { + buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); + if (!buf->mem) { + printk(KERN_WARNING "Error allocating management frame.\n"); + return -ENOMEM; + } + buf->size = MGMT_FRAME_SIZE; + } + if (buf->pci_addr == 0) { + buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + MGMT_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + if(!buf->pci_addr) { + printk(KERN_WARNING "Failed to make memory DMA'able\n."); + return -ENOMEM; + } + } + + /* be safe: always reset control block information */ + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(buf->pci_addr); + curr++; + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(curr); + } + return 0; +} + +/* + * Create and transmit a management frame using "operation" and "oid", + * with arguments data/length. + * We either return an error and free the frame, or we return 0 and + * islpci_mgt_cleanup_transmit() frees the frame in the tx-done + * interrupt. + */ +static int +islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, + void *data, int length) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + void *p; + int err = -EINVAL; + unsigned long flags; + isl38xx_fragment *frag; + struct islpci_membuf buf; + u32 curr_frag; + int index; + int frag_len = length + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); +#endif + + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_DEBUG "%s: mgmt frame too large %d\n", + ndev->name, frag_len); + goto error; + } + + err = -ENOMEM; + p = buf.mem = kmalloc(frag_len, GFP_KERNEL); + if (!buf.mem) { + printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n", + ndev->name); + goto error; + } + buf.size = frag_len; + + /* create the header directly in the fragment data area */ + pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); + p += PIMFOR_HEADER_SIZE; + + if (data) + memcpy(p, data, length); + else + memset(p, 0, length); + +#if VERBOSE > SHOW_ERROR_MESSAGES + { + pimfor_header_t *h = buf.mem; + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n", + h->operation, oid, h->device_id, h->flags, length); + + /* display the buffer contents for debugging */ + display_buffer((char *) h, sizeof (pimfor_header_t)); + display_buffer(p, length); + } +#endif + + err = -ENOMEM; + buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, + PCI_DMA_TODEVICE); + if (!buf.pci_addr) { + printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", + ndev->name); + goto error_free; + } + + /* Protect the control block modifications against interrupts. */ + spin_lock_irqsave(&priv->slock, flags); + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); + if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { + printk(KERN_WARNING "%s: mgmt tx queue is still full\n", + ndev->name); + goto error_unlock; + } + + /* commit the frame to the tx device queue */ + index = curr_frag % ISL38XX_CB_MGMT_QSIZE; + priv->mgmt_tx[index] = buf; + frag = &cb->tx_data_mgmt[index]; + frag->size = cpu_to_le16(frag_len); + frag->flags = 0; /* for any other than the last fragment, set to 1 */ + frag->address = cpu_to_le32(buf.pci_addr); + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag+1); + spin_unlock_irqrestore(&priv->slock, flags); + + /* trigger the device */ + islpci_trigger(priv); + return 0; + + error_unlock: + spin_unlock_irqrestore(&priv->slock, flags); + error_free: + kfree(buf.mem); + error: + return err; +} + +/* + * Receive a management frame from the device. + * This can be an arbitrary number of traps, and at most one response + * frame for a previous request sent via islpci_mgt_transmit(). + */ +int +islpci_mgt_receive(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n"); +#endif + + + /* Only once per interrupt, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * frames come in faster than we can process them. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); + barrier(); + + for ( ; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { + pimfor_header_t *header; + u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + u16 frag_len; + int size; + struct islpci_mgmtframe *frame; + + /* I have no idea (and no documentation) if flags != 0 + * is possible. Drop the frame, reuse the buffer. */ + if(le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { + printk(KERN_WARNING "%s: unknown flags 0x%04x\n", + ndev->name, + le16_to_cpu(cb->rx_data_mgmt[index].flags)); + continue; + } + + /* The device only returns the size of the header(s) here. */ + frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); + + /* + * We appear to have no way to tell the device the + * size of a receive buffer. Thus, if this check + * triggers, we likely have kernel heap corruption. */ + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\ +n", + ndev->name, frag_len, frag_len); + frag_len = MGMT_FRAME_SIZE; + } + + /* Ensure the results of device DMA are visible to the CPU. */ + pci_dma_sync_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + + /* Perform endianess conversion for PIMFOR header in-place. */ + header = pimfor_decode_header(buf->mem, frag_len); + if (!header) { + printk(KERN_WARNING "%s: no PIMFOR header found\n", + ndev->name); + continue; + } + + /* The device ID from the PIMFOR packet received from + * the MVC is always 0. We forward a sensible device_id. + * Not that anyone upstream would care... */ + header->device_id = priv->ndev->ifindex; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n", + header->operation, header->oid, header->device_id, + header->flags, header->length); + + /* display the buffer contents for debugging */ + display_buffer((char *) header, PIMFOR_HEADER_SIZE); + display_buffer((char *) header + PIMFOR_HEADER_SIZE, header->length); +#endif + + /* nobody sends these */ + if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { + printk(KERN_DEBUG "%s: errant PIMFOR application frame\n", + ndev->name); + continue; + } + + /* Determine frame size, skipping OID_INL_TUNNEL headers. */ + size = PIMFOR_HEADER_SIZE + header->length; + frame = kmalloc(sizeof(struct islpci_mgmtframe) + size, + GFP_ATOMIC); + if (!frame) { + printk(KERN_WARNING "%s: Out of memory, cannot handle oid 0x%08x\n", + + ndev->name, header->oid); + continue; + } + frame->ndev = ndev; + memcpy(&frame->buf, header, size); + frame->header = (pimfor_header_t *) frame->buf; + frame->data = frame->buf + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "frame: header: %p, data: %p, size: %d\n", + frame->header, frame->data, size); +#endif + + if (header->operation == PIMFOR_OP_TRAP) { +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG + "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", + header->oid, header->device_id, header->flags, + header->length); +#endif + + /* Create work to handle trap out of interrupt + * context. */ + INIT_WORK(&frame->ws, prism54_process_trap, frame); + schedule_work(&frame->ws); + + } else { + /* Signal the one waiting process that a response + * has been received. */ + if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { + printk(KERN_WARNING "%s: mgmt response not collected\n", + ndev->name); + kfree(frame); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Wake up Mgmt Queue\n"); +#endif + wake_up(&priv->mgmt_wqueue); + } + + } + + return 0; +} + +/* + * Cleanup the transmit queue by freeing all frames handled by the device. + */ +void +islpci_mgt_cleanup_transmit(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); +#endif + + /* Only once per cleanup, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * the device became confused, incrementing device_curr_frag + * rapidly. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); + barrier(); + + for ( ; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { + int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_tx[index]; + pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, + PCI_DMA_TODEVICE); + buf->pci_addr = 0; + kfree(buf->mem); + buf->mem = NULL; + buf->size = 0; + } +} + +/* + * Perform one request-response transaction to the device. + */ +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe) +{ + islpci_private *priv = netdev_priv(ndev); + const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; + int err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + DEFINE_WAIT(wait); +#else + DECLARE_WAITQUEUE(wait, current); +#endif + + if (down_interruptible(&priv->mgmt_sem)) + return -ERESTARTSYS; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); +#else + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&priv->mgmt_wqueue, &wait); +#endif + err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); + if(err) + goto out; + + err = -ETIMEDOUT; + while (timeout_left > 0) { + int timeleft; + struct islpci_mgmtframe *frame; + + timeleft = schedule_timeout(wait_cycle_jiffies); + frame = xchg(&priv->mgmt_received, NULL); + if (frame) { + *recvframe = frame; + err = 0; + goto out; + } + if(timeleft == 0) { + printk(KERN_DEBUG "%s: timeout waiting for mgmt response %lu, trigging device\n", + ndev->name, timeout_left); + islpci_trigger(priv); + } + timeout_left += timeleft - wait_cycle_jiffies; + } + printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", + ndev->name); + + /* TODO: we should reset the device here */ + out: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + finish_wait(&priv->mgmt_wqueue, &wait); +#else + remove_wait_queue(&priv->mgmt_wqueue, &wait); + set_current_state(TASK_RUNNING); +#endif + up(&priv->mgmt_sem); + return err; +} + diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_mgt.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,168 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.h,v 1.22 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_MGT_H +#define _ISLPCI_MGT_H + +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +# include +#else +# include +# define work_struct tq_struct +# define INIT_WORK INIT_TQUEUE +# define schedule_work schedule_task +#endif + +/* + * Function definitions + */ + +#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) +#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) + +#define TRACE(devname) K_DEBUG(SHOW_TRACING, VERBOSE, "%s: -> " __FUNCTION__ "()\n", devname) + +extern int pc_debug; +static const int init_wds = 0; /* help compiler optimize away dead code */ + + +/* General driver definitions */ +#define PCIVENDOR_INTERSIL 0x1260UL +#define PCIVENDOR_3COM 0x10b7UL +#define PCIVENDOR_DLINK 0x1186UL +#define PCIVENDOR_I4 0x17cfUL +#define PCIVENDOR_IODATA 0x10fcUL +#define PCIVENDOR_NETGEAR 0x1385UL +#define PCIVENDOR_SMC 0x10b8UL +#define PCIVENDOR_ACCTON 0x1113UL + +#define PCIDEVICE_ISL3877 0x3877UL +#define PCIDEVICE_ISL3890 0x3890UL +#define PCIDEVICE_3COM6001 0x6001UL +#define PCIDEVICE_LATENCY_TIMER_MIN 0x40 +#define PCIDEVICE_LATENCY_TIMER_VAL 0x50 + +/* Debugging verbose definitions */ +#define SHOW_NOTHING 0x00 /* overrules everything */ +#define SHOW_ANYTHING 0xFF +#define SHOW_ERROR_MESSAGES 0x01 +#define SHOW_TRAPS 0x02 +#define SHOW_FUNCTION_CALLS 0x04 +#define SHOW_TRACING 0x08 +#define SHOW_QUEUE_INDEXES 0x10 +#define SHOW_PIMFOR_FRAMES 0x20 +#define SHOW_BUFFER_CONTENTS 0x40 +#define VERBOSE 0x01 + +/* Default card definitions */ +#define CARD_DEFAULT_CHANNEL 6 +#define CARD_DEFAULT_MODE INL_MODE_CLIENT +#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA +#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA +#define CARD_DEFAULT_CLIENT_SSID "" +#define CARD_DEFAULT_AP_SSID "default" +#define CARD_DEFAULT_KEY1 "default_key_1" +#define CARD_DEFAULT_KEY2 "default_key_2" +#define CARD_DEFAULT_KEY3 "default_key_3" +#define CARD_DEFAULT_KEY4 "default_key_4" +#define CARD_DEFAULT_WEP 0 +#define CARD_DEFAULT_FILTER 0 +#define CARD_DEFAULT_WDS 0 +#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS +#define CARD_DEFAULT_DOT1X 0 +#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO +#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE +#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI +#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE + +/* PIMFOR package definitions */ +#define PIMFOR_ETHERTYPE 0x8828 +#define PIMFOR_HEADER_SIZE 12 +#define PIMFOR_VERSION 1 +#define PIMFOR_OP_GET 0 +#define PIMFOR_OP_SET 1 +#define PIMFOR_OP_RESPONSE 2 +#define PIMFOR_OP_ERROR 3 +#define PIMFOR_OP_TRAP 4 +#define PIMFOR_OP_RESERVED 5 /* till 255 */ +#define PIMFOR_DEV_ID_MHLI_MIB 0 +#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 +#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 + +static inline void +add_le32p(u32 * le_number, u32 add) +{ + *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); +} + +void display_buffer(char *, int); + +/* + * Type definition section + * + * the structure defines only the header allowing copyless + * frame handling + */ +typedef struct { + u8 version; + u8 operation; + u32 oid; + u8 device_id; + u8 flags; + u32 length; +} __attribute__ ((packed)) +pimfor_header_t; + +/* A received and interrupt-processed management frame, either for + * schedule_work(prism54_process_trap) or for priv->mgmt_received, + * processed by islpci_mgt_transaction(). */ +struct islpci_mgmtframe { + struct net_device *ndev; /* pointer to network device */ + pimfor_header_t *header; /* payload header, points into buf */ + void *data; /* payload ex header, points into buf */ + struct work_struct ws; /* argument for schedule_work() */ + char buf[0]; /* fragment buffer */ +}; + +int +islpci_mgt_receive(struct net_device *ndev); + +int +islpci_mgmt_rx_fill(struct net_device *ndev); + +void +islpci_mgt_cleanup_transmit(struct net_device *ndev); + +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe); + +static inline void +islpci_mgt_release(struct islpci_mgmtframe *frame) +{ + kfree(frame); +} + +#endif /* _ISLPCI_MGT_H */ diff -Nru a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/oid_mgt.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "isl_oid.h" +#include "oid_mgt.h" +#include "isl_ioctl.h" + +/* to convert between channel and freq */ +const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230, + 5240, 5260, 5280, 5300, 5320 +}; + +#define OID_U32(x) {x, 0, sizeof(u32), OID_FLAG_U32} +#define OID_U32_C(x) {x, 0, sizeof(u32), OID_FLAG_U32 | OID_FLAG_CACHED} +#define OID_STRUCT(x,s) {x, 0, sizeof(s), 0} +#define OID_STRUCT_C(x,s) {x, 0, sizeof(s), OID_FLAG_CACHED} +#define OID_STRUCT_MLME(x){x, 0, sizeof(struct obj_mlme), 0} +#define OID_STRUCT_MLMEEX(x){x, 0, sizeof(struct obj_mlmeex), OID_FLAG_MLMEEX} + +#define OID_UNKNOWN(x) {x, 0, 0, 0} + +struct oid_t isl_oid[] = { + [GEN_OID_MACADDRESS] = OID_STRUCT(0x00000000, u8[6]), + [GEN_OID_LINKSTATE] = OID_U32(0x00000001), + [GEN_OID_WATCHDOG] = OID_UNKNOWN(0x00000002), + [GEN_OID_MIBOP] = OID_UNKNOWN(0x00000003), + [GEN_OID_OPTIONS] = OID_UNKNOWN(0x00000004), + [GEN_OID_LEDCONFIG] = OID_UNKNOWN(0x00000005), + + /* 802.11 */ + [DOT11_OID_BSSTYPE] = OID_U32_C(0x10000000), + [DOT11_OID_BSSID] = OID_STRUCT_C(0x10000001, u8[6]), + [DOT11_OID_SSID] = OID_STRUCT_C(0x10000002, struct obj_ssid), + [DOT11_OID_STATE] = OID_U32(0x10000003), + [DOT11_OID_AID] = OID_U32(0x10000004), + [DOT11_OID_COUNTRYSTRING] = OID_STRUCT(0x10000005, u8[4]), + [DOT11_OID_SSIDOVERRIDE] = OID_STRUCT_C(0x10000006, struct obj_ssid), + + [DOT11_OID_MEDIUMLIMIT] = OID_U32(0x11000000), + [DOT11_OID_BEACONPERIOD] = OID_U32_C(0x11000001), + [DOT11_OID_DTIMPERIOD] = OID_U32(0x11000002), + [DOT11_OID_ATIMWINDOW] = OID_U32(0x11000003), + [DOT11_OID_LISTENINTERVAL] = OID_U32(0x11000004), + [DOT11_OID_CFPPERIOD] = OID_U32(0x11000005), + [DOT11_OID_CFPDURATION] = OID_U32(0x11000006), + + [DOT11_OID_AUTHENABLE] = OID_U32_C(0x12000000), + [DOT11_OID_PRIVACYINVOKED] = OID_U32_C(0x12000001), + [DOT11_OID_EXUNENCRYPTED] = OID_U32_C(0x12000002), + [DOT11_OID_DEFKEYID] = OID_U32_C(0x12000003), + [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), OID_FLAG_CACHED}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + [DOT11_OID_STAKEY] = OID_UNKNOWN(0x12000008), + [DOT11_OID_REKEYTHRESHOLD] = OID_U32(0x12000009), + [DOT11_OID_STASC] = OID_UNKNOWN(0x1200000a), + + [DOT11_OID_PRIVTXREJECTED] = OID_U32(0x1a000000), + [DOT11_OID_PRIVRXPLAIN] = OID_U32(0x1a000001), + [DOT11_OID_PRIVRXFAILED] = OID_U32(0x1a000002), + [DOT11_OID_PRIVRXNOKEY] = OID_U32(0x1a000003), + + [DOT11_OID_RTSTHRESH] = OID_U32_C(0x13000000), + [DOT11_OID_FRAGTHRESH] = OID_U32_C(0x13000001), + [DOT11_OID_SHORTRETRIES] = OID_U32_C(0x13000002), + [DOT11_OID_LONGRETRIES] = OID_U32_C(0x13000003), + [DOT11_OID_MAXTXLIFETIME] = OID_U32_C(0x13000004), + [DOT11_OID_MAXRXLIFETIME] = OID_U32(0x13000005), + [DOT11_OID_AUTHRESPTIMEOUT] = OID_U32(0x13000006), + [DOT11_OID_ASSOCRESPTIMEOUT] = OID_U32(0x13000007), + + [DOT11_OID_ALOFT_TABLE] = OID_UNKNOWN(0x1d000000), + [DOT11_OID_ALOFT_CTRL_TABLE] = OID_UNKNOWN(0x1d000001), + [DOT11_OID_ALOFT_RETREAT] = OID_UNKNOWN(0x1d000002), + [DOT11_OID_ALOFT_PROGRESS] = OID_UNKNOWN(0x1d000003), + [DOT11_OID_ALOFT_FIXEDRATE] = OID_U32(0x1d000004), + [DOT11_OID_ALOFT_RSSIGRAPH] = OID_UNKNOWN(0x1d000005), + [DOT11_OID_ALOFT_CONFIG] = OID_UNKNOWN(0x1d000006), + + [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, + [DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008), /* in microseconds */ + + [DOT11_OID_PSM] = OID_U32(0x14000000), + [DOT11_OID_CAMTIMEOUT] = OID_U32(0x14000001), + [DOT11_OID_RECEIVEDTIMS] = OID_U32(0x14000002), + [DOT11_OID_ROAMPREFERENCE] = OID_U32(0x14000003), + + [DOT11_OID_BRIDGELOCAL] = OID_U32(0x15000000), + [DOT11_OID_CLIENTS] = OID_U32(0x15000001), + [DOT11_OID_CLIENTSASSOCIATED] = OID_U32(0x15000002), + [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + [DOT11_OID_CLIENTFIND] = OID_STRUCT(0x150007DB, u8[6]), + [DOT11_OID_WDSLINKADD] = OID_STRUCT(0x150007DC, u8[6]), + [DOT11_OID_WDSLINKREMOVE] = OID_STRUCT(0x150007DD, u8[6]), + [DOT11_OID_EAPAUTHSTA] = OID_STRUCT(0x150007DE, u8[6]), + [DOT11_OID_EAPUNAUTHSTA] = OID_STRUCT(0x150007DF, u8[6]), + [DOT11_OID_DOT1XENABLE] = OID_U32_C(0x150007E0), + [DOT11_OID_MICFAILURE] = OID_UNKNOWN(0x150007E1), + [DOT11_OID_REKEYINDICATE] = OID_UNKNOWN(0x150007E2), + + [DOT11_OID_MPDUTXSUCCESSFUL] = OID_U32(0x16000000), + [DOT11_OID_MPDUTXONERETRY] = OID_U32(0x16000001), + [DOT11_OID_MPDUTXMULTIPLERETRIES] = OID_U32(0x16000002), + [DOT11_OID_MPDUTXFAILED] = OID_U32(0x16000003), + [DOT11_OID_MPDURXSUCCESSFUL] = OID_U32(0x16000004), + [DOT11_OID_MPDURXDUPS] = OID_U32(0x16000005), + [DOT11_OID_RTSSUCCESSFUL] = OID_U32(0x16000006), + [DOT11_OID_RTSFAILED] = OID_U32(0x16000007), + [DOT11_OID_ACKFAILED] = OID_U32(0x16000008), + [DOT11_OID_FRAMERECEIVES] = OID_U32(0x16000009), + [DOT11_OID_FRAMEERRORS] = OID_U32(0x1600000A), + [DOT11_OID_FRAMEABORTS] = OID_U32(0x1600000B), + [DOT11_OID_FRAMEABORTSPHY] = OID_U32(0x1600000C), + + [DOT11_OID_SLOTTIME] = OID_U32(0x17000000), + [DOT11_OID_CWMIN] = OID_U32(0x17000001), + [DOT11_OID_CWMAX] = OID_U32(0x17000002), + [DOT11_OID_ACKWINDOW] = OID_U32(0x17000003), + [DOT11_OID_ANTENNARX] = OID_U32(0x17000004), + [DOT11_OID_ANTENNATX] = OID_U32(0x17000005), + [DOT11_OID_ANTENNADIVERSITY] = OID_U32(0x17000006), + [DOT11_OID_CHANNEL] = OID_U32_C(0x17000007), + [DOT11_OID_EDTHRESHOLD] = OID_U32_C(0x17000008), + [DOT11_OID_PREAMBLESETTINGS] = OID_U32(0x17000009), + [DOT11_OID_RATES] = OID_STRUCT(0x1700000A, u8[IWMAX_BITRATES + 1]), + [DOT11_OID_CCAMODESUPPORTED] = OID_U32(0x1700000B), + [DOT11_OID_CCAMODE] = OID_U32(0x1700000C), + [DOT11_OID_RSSIVECTOR] = OID_U32(0x1700000D), + [DOT11_OID_OUTPUTPOWERTABLE] = OID_U32(0x1700000E), + [DOT11_OID_OUTPUTPOWER] = OID_U32_C(0x1700000F), + [DOT11_OID_SUPPORTEDRATES] = + OID_STRUCT(0x17000010, u8[IWMAX_BITRATES + 1]), + [DOT11_OID_FREQUENCY] = OID_U32_C(0x17000011), + [DOT11_OID_SUPPORTEDFREQUENCIES] = {0x17000012, 0, sizeof (struct + obj_frequencies) + + sizeof (u16) * IWMAX_FREQ, 0}, + + [DOT11_OID_NOISEFLOOR] = OID_U32(0x17000013), + [DOT11_OID_FREQUENCYACTIVITY] = + OID_STRUCT(0x17000014, u8[IWMAX_FREQ + 1]), + [DOT11_OID_IQCALIBRATIONTABLE] = OID_UNKNOWN(0x17000015), + [DOT11_OID_NONERPPROTECTION] = OID_U32(0x17000016), + [DOT11_OID_SLOTSETTINGS] = OID_U32(0x17000017), + [DOT11_OID_NONERPTIMEOUT] = OID_U32(0x17000018), + [DOT11_OID_PROFILES] = OID_U32(0x17000019), + [DOT11_OID_EXTENDEDRATES] = + OID_STRUCT(0x17000020, u8[IWMAX_BITRATES + 1]), + + [DOT11_OID_DEAUTHENTICATE] = OID_STRUCT_MLME(0x18000000), + [DOT11_OID_AUTHENTICATE] = OID_STRUCT_MLME(0x18000001), + [DOT11_OID_DISASSOCIATE] = OID_STRUCT_MLME(0x18000002), + [DOT11_OID_ASSOCIATE] = OID_STRUCT_MLME(0x18000003), + [DOT11_OID_SCAN] = OID_UNKNOWN(0x18000004), + [DOT11_OID_BEACON] = OID_STRUCT_MLMEEX(0x18000005), + [DOT11_OID_PROBE] = OID_STRUCT_MLMEEX(0x18000006), + [DOT11_OID_DEAUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000007), + [DOT11_OID_AUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000008), + [DOT11_OID_DISASSOCIATEEX] = OID_STRUCT_MLMEEX(0x18000009), + [DOT11_OID_ASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000A), + [DOT11_OID_REASSOCIATE] = OID_STRUCT_MLMEEX(0x1800000B), + [DOT11_OID_REASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000C), + + [DOT11_OID_NONERPSTATUS] = OID_U32(0x1E000000), + + [DOT11_OID_STATIMEOUT] = OID_U32(0x19000000), + [DOT11_OID_MLMEAUTOLEVEL] = OID_U32_C(0x19000001), + [DOT11_OID_BSSTIMEOUT] = OID_U32(0x19000002), + [DOT11_OID_ATTACHMENT] = OID_UNKNOWN(0x19000003), + [DOT11_OID_PSMBUFFER] = OID_STRUCT_C(0x19000004, struct obj_buffer), + + [DOT11_OID_BSSS] = OID_U32(0x1C000000), + [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), 0}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + [DOT11_OID_BSSFIND] = OID_STRUCT(0x1C000042, struct obj_bss), + [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct + obj_bsslist) + + sizeof (struct obj_bss[IWMAX_BSS]), 0}, + + [OID_INL_TUNNEL] = OID_UNKNOWN(0xFF020000), + [OID_INL_MEMADDR] = OID_UNKNOWN(0xFF020001), + [OID_INL_MEMORY] = OID_UNKNOWN(0xFF020002), + [OID_INL_MODE] = OID_U32_C(0xFF020003), + [OID_INL_COMPONENT_NR] = OID_UNKNOWN(0xFF020004), + [OID_INL_VERSION] = OID_UNKNOWN(0xFF020005), + [OID_INL_INTERFACE_ID] = OID_UNKNOWN(0xFF020006), + [OID_INL_COMPONENT_ID] = OID_UNKNOWN(0xFF020007), + [OID_INL_CONFIG] = OID_U32_C(0xFF020008), + [OID_INL_DOT11D_CONFORMANCE] = OID_U32_C(0xFF02000C), + [OID_INL_PHYCAPABILITIES] = OID_U32(0xFF02000D), + [OID_INL_OUTPUTPOWER] = OID_U32_C(0xFF02000F), + +}; + +int +mgt_init(islpci_private *priv) +{ + int i; + + priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL); + if (!priv->mib) + return -ENOMEM; + + memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *)); + + /* Alloc the cache */ + for (i = 0; i < OID_NUM_LAST; i++) { + if (isl_oid[i].flags & OID_FLAG_CACHED) { + priv->mib[i] = kmalloc(isl_oid[i].size * + (isl_oid[i].range + 1), + GFP_KERNEL); + if (!priv->mib[i]) + return -ENOMEM; + memset(priv->mib[i], 0, + isl_oid[i].size * (isl_oid[i].range + 1)); + } else + priv->mib[i] = NULL; + } + + init_rwsem(&priv->mib_sem); + prism54_mib_init(priv); + + return 0; +} + +void +mgt_clean(islpci_private *priv) +{ + int i; + + if (!priv->mib) + return; + for (i = 0; i < OID_NUM_LAST; i++) + if (priv->mib[i]) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } + kfree(priv->mib); + priv->mib = NULL; +} + +int +mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) +{ + int ret = 0; + struct islpci_mgmtframe *response; + int response_op = PIMFOR_OP_ERROR; + int dlen; + void *cache, *_data = data; + u32 oid, u; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += (cache ? extra * dlen : 0); + oid = isl_oid[n].oid + extra; + + if (data == NULL) + /* we are requested to re-set a cached value */ + _data = cache; + if ((isl_oid[n].flags & OID_FLAG_U32) && data) { + u = cpu_to_le32(*(u32 *) data); + _data = &u; + } + /* If we are going to write to the cache, we don't want anyone to read + * it -> acquire write lock. + * Else we could acquire a read lock to be sure we don't bother the + * commit process (which takes a write lock). But I'm not sure if it's + * needed. + */ + if (cache) + down_write(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + _data, dlen, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else if (!cache) + ret = -EIO; + + if (cache) { + if (!ret && data) + memcpy(cache, _data, dlen); + up_write(&priv->mib_sem); + } + + return ret; +} + +int +mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, + union oid_res_t *res) +{ + + int ret = -EIO; + int reslen = 0; + struct islpci_mgmtframe *response = NULL; + + int dlen; + void *cache, *_res=NULL; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += cache ? extra * dlen : 0; + oid = isl_oid[n].oid + extra; + reslen = dlen; + + if (cache) + down_read(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + oid, data, dlen, &response); + if (ret || !response || + response->header->operation == PIMFOR_OP_ERROR) { + if (response) + islpci_mgt_release(response); + ret = -EIO; + } + if (!ret) { + _res = response->data; + reslen = response->header->length; + } + } else if (cache) { + _res = cache; + ret = 0; + } + if (isl_oid[n].flags & OID_FLAG_U32) { + if (ret) + res->u = 0; + else + res->u = le32_to_cpu(*(u32 *) _res); + } else { + res->ptr = kmalloc(reslen, GFP_KERNEL); + BUG_ON(res->ptr == NULL); + if (ret) + memset(res->ptr, 0, reslen); + else + memcpy(res->ptr, _res, reslen); + } + + if (cache) + up_read(&priv->mib_sem); + + if (response && !ret) + islpci_mgt_release(response); + + if (reslen > isl_oid[n].size) + printk(KERN_DEBUG + "mgt_get_request(0x%x): received data length was bigger " + "than expected (%d > %d). Memory is probably corrupted... ", + oid, reslen, isl_oid[n].size); + + return ret; +} + +/* lock outside */ +int +mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) +{ + int i, ret = 0; + struct islpci_mgmtframe *response; + + for (i = 0; i < n; i++) { + struct oid_t *t = &(isl_oid[l[i]]); + void *data = priv->mib[l[i]]; + int j = 0; + u32 oid = t->oid; + BUG_ON(data == NULL); + while (j <= t->range){ + response = NULL; + ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + oid, data, t->size, + &response); + if (response) { + ret |= (response->header->operation == + PIMFOR_OP_ERROR); + islpci_mgt_release(response); + } + j++; + oid++; + data += t->size; + } + } + return ret; +} + +/* Lock outside */ + +void +mgt_set(islpci_private *priv, enum oid_num_t n, void *data) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + + memcpy(priv->mib[n], data, isl_oid[n].size); + if (isl_oid[n].flags & OID_FLAG_U32) + *(u32 *) priv->mib[n] = cpu_to_le32(*(u32 *) priv->mib[n]); +} + +/* Commits the cache. If something goes wrong, it restarts the device. Lock + * outside + */ + +static enum oid_num_t commit_part1[] = { + OID_INL_CONFIG, + OID_INL_MODE, + DOT11_OID_BSSTYPE, + DOT11_OID_CHANNEL, + DOT11_OID_MLMEAUTOLEVEL +}; + +static enum oid_num_t commit_part2[] = { + DOT11_OID_SSID, + DOT11_OID_PSMBUFFER, + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYX, /* MULTIPLE */ + DOT11_OID_DEFKEYID, + DOT11_OID_DOT1XENABLE, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_OUTPUTPOWER, +}; + +void +mgt_commit(islpci_private *priv) +{ + int rvalue; + u32 u; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return; + + rvalue = mgt_commit_list(priv, commit_part1, + sizeof (commit_part1) / + sizeof (commit_part1[0])); + + if (priv->iw_mode != IW_MODE_MONITOR) + rvalue |= mgt_commit_list(priv, commit_part2, + sizeof (commit_part2) / + sizeof (commit_part2[0])); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + + if (rvalue) { + /* some request have failed. The device might be in an + incoherent state. We should reset it ! */ + printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the " + "device \n", priv->ndev->name); + } + + /* update the MAC addr. As it's not cached, no lock will be acquired by + * the mgt_get_request + */ + mgt_get_request(priv, GEN_OID_MACADDRESS, 0, NULL, &r); + memcpy(priv->ndev->dev_addr, r.ptr, 6); + kfree(r.ptr); + +} + +/* This will tell you if you are allowed to answer a mlme(ex) request .*/ + +inline int +mgt_mlme_answer(islpci_private *priv) +{ + u32 mlmeautolevel; + /* Acquire a read lock because if we are in a mode change, it's + * possible to answer true, while the card is leaving master to managed + * mode. Answering to a mlme in this situation could hang the card. + */ + down_read(&priv->mib_sem); + mlmeautolevel = + le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); + up_read(&priv->mib_sem); + + return ((priv->iw_mode == IW_MODE_MASTER) && + (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); +} + +inline enum oid_num_t +mgt_oidtonum(u32 oid) +{ + int i; + + for (i = 0; i < OID_NUM_LAST - 1; i++) + if (isl_oid[i].oid == oid) + return i; + + printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); + + return 0; +} diff -Nru a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/oid_mgt.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_OID_MGT_H) +#define _OID_MGT_H + +#include "isl_oid.h" +#include "islpci_dev.h" + +extern struct oid_t isl_oid[]; + +int mgt_init(islpci_private *); + +void mgt_clean(islpci_private *); + +extern const int frequency_list_bg[]; + +extern const int frequency_list_a[]; + +int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); + +int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, + union oid_res_t *); + +int mgt_commit_list(islpci_private *, enum oid_num_t *, int); + +void mgt_set(islpci_private *, enum oid_num_t, void *); + +void mgt_commit(islpci_private *); + +int mgt_mlme_answer(islpci_private *); + +enum oid_num_t mgt_oidtonum(u32 oid); + +#endif /* !defined(_OID_MGT_H) */ +/* EOF */ diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c --- a/drivers/net/yellowfin.c Sat Apr 3 19:38:42 2004 +++ b/drivers/net/yellowfin.c Sat Apr 3 19:38:42 2004 @@ -1124,7 +1124,7 @@ if(!desc->result_status) break; - pci_dma_sync_single(yp->pci_dev, desc->addr, + pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr, yp->rx_buf_sz, PCI_DMA_FROMDEVICE); desc_status = le32_to_cpu(desc->result_status) >> 16; buf_addr = rx_skb->tail; @@ -1208,6 +1208,9 @@ memcpy(skb_put(skb, pkt_len), rx_skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(yp->pci_dev, desc->addr, + yp->rx_buf_sz, + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c --- a/drivers/net/zorro8390.c Sat Apr 3 19:38:44 2004 +++ b/drivers/net/zorro8390.c Sat Apr 3 19:38:44 2004 @@ -227,6 +227,10 @@ ei_status.reg_offset = zorro8390_offsets; dev->open = &zorro8390_open; dev->stop = &zorro8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); err = register_netdev(dev); if (err) diff -Nru a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c --- a/drivers/parisc/ccio-dma.c Sat Apr 3 19:38:41 2004 +++ b/drivers/parisc/ccio-dma.c Sat Apr 3 19:38:41 2004 @@ -38,9 +38,8 @@ #include #include #include -#define PCI_DEBUG #include -#undef PCI_DEBUG +#include #include #include /* for L1_CACHE_BYTES */ @@ -63,6 +62,18 @@ #undef DEBUG_CCIO_INIT #undef DEBUG_CCIO_RUN_SG +#ifdef CONFIG_PROC_FS +/* + * CCIO_SEARCH_TIME can help measure how fast the bitmap search is. + * impacts performance though - ditch it if you don't use it. + */ +#define CCIO_SEARCH_TIME +#undef CCIO_MAP_STATS +#else +#undef CCIO_SEARCH_TIME +#undef CCIO_MAP_STATS +#endif + #include #include /* for proc_runway_root */ @@ -219,15 +230,18 @@ struct ioa_registers *ioc_hpa; /* I/O MMU base address */ u8 *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ + u32 pdir_size; /* bytes, function of IOV Space size */ u32 res_hint; /* next available IOVP - circular search */ u32 res_size; /* size of resource map in bytes */ spinlock_t res_lock; -#ifdef CONFIG_PROC_FS +#ifdef CCIO_SEARCH_TIME #define CCIO_SEARCH_SAMPLE 0x100 unsigned long avg_search[CCIO_SEARCH_SAMPLE]; unsigned long avg_idx; /* current index into avg_search */ +#endif +#ifdef CCIO_MAP_STATS unsigned long used_pages; unsigned long msingle_calls; unsigned long msingle_pages; @@ -237,12 +251,10 @@ unsigned long usingle_pages; unsigned long usg_calls; unsigned long usg_pages; - - unsigned short cujo20_bug; #endif + unsigned short cujo20_bug; /* STUFF We don't need in performance path */ - u32 pdir_size; /* in bytes, determined by IOV Space size */ u32 chainid_shift; /* specify bit location of chain_id */ struct ioc *next; /* Linked list of discovered iocs */ const char *name; /* device name from firmware */ @@ -289,11 +301,11 @@ ** If the search wraps around, and passes the res_hint, it will ** cause the kernel to panic anyhow. */ -#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size) \ +#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ for(; res_ptr < res_end; ++res_ptr) { \ - if(0 == (*res_ptr & *mask_ptr)) { \ - *res_ptr |= *mask_ptr; \ - res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + if(0 == (*res_ptr & mask)) { \ + *res_ptr |= mask; \ + res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ ioc->res_hint = res_idx + (size >> 3); \ goto resource_found; \ } \ @@ -302,10 +314,9 @@ #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ - u##size *mask_ptr = (u##size *)&mask; \ - CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \ + CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \ res_ptr = (u##size *)&(ioc)->res_map[0]; \ - CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size); + CCIO_SEARCH_LOOP(ioa, res_idx, mask, size); /* ** Find available bit in this ioa's resource map. @@ -331,40 +342,51 @@ * of available pages for the requested size. */ static int -ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed) +ccio_alloc_range(struct ioc *ioc, size_t size) { - int res_idx; - unsigned long mask; -#ifdef CONFIG_PROC_FS + unsigned int pages_needed = size >> IOVP_SHIFT; + unsigned int res_idx; +#ifdef CCIO_SEARCH_TIME unsigned long cr_start = mfctl(16); #endif - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE); - ASSERT(pages_needed <= BITS_PER_LONG); - - mask = ~(~0UL >> pages_needed); + BUG_ON(pages_needed == 0); + BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE); - DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", - __FUNCTION__, size, pages_needed, mask); + DBG_RES("%s() size: %d pages_needed %d\n", + __FUNCTION__, size, pages_needed); /* ** "seek and ye shall find"...praying never hurts either... ** ggg sacrifices another 710 to the computer gods. */ - if(pages_needed <= 8) { + if (pages_needed <= 8) { + /* + * LAN traffic will not thrash the TLB IFF the same NIC + * uses 8 adjacent pages to map seperate payload data. + * ie the same byte in the resource bit map. + */ +#if 0 + /* FIXME: bit search should shift it's way through + * an unsigned long - not byte at a time. As it is now, + * we effectively allocate this byte to this mapping. + */ + unsigned long mask = ~(~0UL >> pages_needed); CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); - } else if(pages_needed <= 16) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16); - } else if(pages_needed <= 32) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32); +#else + CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xff, 8); +#endif + } else if (pages_needed <= 16) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xffff, 16); + } else if (pages_needed <= 32) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~(unsigned int)0, 32); #ifdef __LP64__ - } else if(pages_needed <= 64) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); + } else if (pages_needed <= 64) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~0UL, 64); #endif } else { - panic("%s: %s() Too many pages to map. pages_needed: %ld\n", + panic("%s: %s() Too many pages to map. pages_needed: %u\n", __FILE__, __FUNCTION__, pages_needed); } @@ -373,10 +395,10 @@ resource_found: - DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n", - __FUNCTION__, res_idx, mask, ioc->res_hint); + DBG_RES("%s() res_idx %d res_hint: %d\n", + __FUNCTION__, res_idx, ioc->res_hint); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_SEARCH_TIME { unsigned long cr_end = mfctl(16); unsigned long tmp = cr_end - cr_start; @@ -385,10 +407,10 @@ } ioc->avg_search[ioc->avg_idx++] = cr_start; ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; - +#endif +#ifdef CCIO_MAP_STATS ioc->used_pages += pages_needed; #endif - /* ** return the bit address. */ @@ -397,9 +419,8 @@ #define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ - u##size *mask_ptr = (u##size *)&mask; \ - ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \ - *res_ptr &= ~(*mask_ptr); + BUG_ON((*res_ptr & mask) != mask); \ + *res_ptr &= ~(mask); /** * ccio_free_range - Free pages from the ioc's resource map. @@ -413,32 +434,35 @@ static void ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) { - unsigned long mask; unsigned long iovp = CCIO_IOVP(iova); unsigned int res_idx = PDIR_INDEX(iovp) >> 3; - ASSERT(pages_mapped); - ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE); - ASSERT(pages_mapped <= BITS_PER_LONG); + BUG_ON(pages_mapped == 0); + BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE); + BUG_ON(pages_mapped > BITS_PER_LONG); - mask = ~(~0UL >> pages_mapped); + DBG_RES("%s(): res_idx: %d pages_mapped %d\n", + __FUNCTION__, res_idx, pages_mapped); - DBG_RES("%s(): res_idx: %d pages_mapped %d mask 0x%08lx\n", - __FUNCTION__, res_idx, pages_mapped, mask); - -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->used_pages -= pages_mapped; #endif if(pages_mapped <= 8) { +#if 0 + /* see matching comments in alloc_range */ + unsigned long mask = ~(~0UL >> pages_mapped); CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); +#else + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8); +#endif } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16); + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16); } else if(pages_mapped <= 32) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32); + CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32); #ifdef __LP64__ } else if(pages_mapped <= 64) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); + CCIO_FREE_MAPPINGS(ioc, res_idx, ~0UL, 64); #endif } else { panic("%s:%s() Too many pages to unmap.\n", __FILE__, @@ -533,13 +557,14 @@ * index are bits 12:19 of the value returned by LCI. */ void CCIO_INLINE -ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints) +ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + unsigned long hints) { register unsigned long pa = (volatile unsigned long) vba; register unsigned long ci; /* coherent index */ /* We currently only support kernel addresses */ - ASSERT(sid == KERNEL_SPACE); + BUG_ON(sid != KERNEL_SPACE); mtsp(sid,1); @@ -652,7 +677,7 @@ unsigned int idx = PDIR_INDEX(iovp); char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); - ASSERT(idx < (ioc->pdir_size / sizeof(u64))); + BUG_ON(idx >= (ioc->pdir_size / sizeof(u64))); pdir_ptr[7] = 0; /* clear only VALID bit */ /* ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) @@ -722,7 +747,7 @@ BUG_ON(!dev); ioc = GET_IOC(dev); - ASSERT(size > 0); + BUG_ON(size <= 0); /* save offset bits */ offset = ((unsigned long) addr) & ~IOVP_MASK; @@ -731,12 +756,12 @@ size = ROUNDUP(size + offset, IOVP_SIZE); spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->msingle_calls++; ioc->msingle_pages += size >> IOVP_SHIFT; #endif - idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT)); + idx = ccio_alloc_range(ioc, size); iovp = (dma_addr_t)MKIOVP(idx); pdir_start = &(ioc->pdir_base[idx]); @@ -749,7 +774,7 @@ hint |= HINT_SAFE_DMA; while(size > 0) { - ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); + ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint); DBG_RUN(" pdir %p %08x%08x\n", pdir_start, @@ -795,7 +820,7 @@ spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usingle_calls++; ioc->usingle_pages += size >> IOVP_SHIFT; #endif @@ -861,180 +886,10 @@ */ #define PIDE_FLAG 0x80000000UL -/** - * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir. - * @ioc: The I/O Controller. - * @startsg: The scatter/gather list of coalesced chunks. - * @nents: The number of entries in the scatter/gather list. - * @hint: The DMA Hint. - * - * This function inserts the coalesced scatter/gather list chunks into the - * I/O Controller's I/O Pdir. - */ -static CCIO_INLINE int -ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, - unsigned long hint) -{ - struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ - int n_mappings = 0; - u64 *pdirp = 0; - unsigned long dma_offset = 0; - - dma_sg--; - while (nents-- > 0) { - int cnt = sg_dma_len(startsg); - sg_dma_len(startsg) = 0; - - DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents, - (unsigned long)sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); - - /* - ** Look for the start of a new DMA stream - */ - if(sg_dma_address(startsg) & PIDE_FLAG) { - u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; - dma_offset = (unsigned long) pide & ~IOVP_MASK; - sg_dma_address(startsg) = 0; - dma_sg++; - sg_dma_address(dma_sg) = pide; - pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); - n_mappings++; - } - - /* - ** Look for a VCONTIG chunk - */ - if (cnt) { - unsigned long vaddr = sg_virt_addr(startsg); - ASSERT(pdirp); - - /* Since multiple Vcontig blocks could make up - ** one DMA stream, *add* cnt to dma_len. - */ - sg_dma_len(dma_sg) += cnt; - cnt += dma_offset; - dma_offset=0; /* only want offset on first chunk */ - cnt = ROUNDUP(cnt, IOVP_SIZE); -#ifdef CONFIG_PROC_FS - ioc->msg_pages += cnt >> IOVP_SHIFT; +#ifdef CCIO_MAP_STATS +#define IOMMU_MAP_STATS #endif - do { - ccio_io_pdir_entry(pdirp, KERNEL_SPACE, - (void *)vaddr, hint); - vaddr += IOVP_SIZE; - cnt -= IOVP_SIZE; - pdirp++; - } while (cnt > 0); - } - startsg++; - } - return(n_mappings); -} - -/* -** First pass is to walk the SG list and determine where the breaks are -** in the DMA stream. Allocates PDIR entries but does not fill them. -** Returns the number of DMA chunks. -** -** Doing the fill separate from the coalescing/allocation keeps the -** code simpler. Future enhancement could make one pass through -** the sglist do both. -*/ - -static CCIO_INLINE int -ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents) -{ - struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ - unsigned long vcontig_len; /* len of VCONTIG chunk */ - unsigned long vcontig_end; - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - int n_mappings = 0; - - while (nents > 0) { - - /* - ** Prepare for first/next DMA stream - */ - dma_sg = vcontig_sg = startsg; - dma_len = vcontig_len = vcontig_end = startsg->length; - vcontig_end += sg_virt_addr(startsg); - dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** This loop terminates one iteration "early" since - ** it's always looking one "ahead". - */ - while(--nents > 0) { - unsigned long startsg_end; - - startsg++; - startsg_end = sg_virt_addr(startsg) + - startsg->length; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the - ** next entry. - */ - if(ROUNDUP(dma_len + dma_offset + startsg->length, - IOVP_SIZE) > DMA_CHUNK_SIZE) - break; - - /* - ** Append the next transaction? - */ - if (vcontig_end == sg_virt_addr(startsg)) { - vcontig_len += startsg->length; - vcontig_end += startsg->length; - dma_len += startsg->length; - continue; - } - - /* - ** Not virtually contigous. - ** Terminate prev chunk. - ** Start a new chunk. - ** - ** Once we start a new VCONTIG chunk, dma_offset - ** can't change. And we need the offset from the first - ** chunk - not the last one. Ergo Successive chunks - ** must start on page boundaries and dove tail - ** with its predecessor. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - - vcontig_sg = startsg; - vcontig_len = startsg->length; - break; - } - - /* - ** End of DMA Stream - ** Terminate last VCONTIG block. - ** Allocate space for DMA stream. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE); - sg_dma_address(dma_sg) = - PIDE_FLAG - | (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT) - | dma_offset; - n_mappings++; - } - - return n_mappings; -} +#include "iommu-helpers.h" /** * ccio_map_sg - Map the scatter/gather list into the IOMMU. @@ -1053,6 +908,8 @@ int coalesced, filled = 0; unsigned long flags; unsigned long hint = hint_lookup[(int)direction]; + unsigned long prev_len = 0, current_len = 0; + int i; BUG_ON(!dev); ioc = GET_IOC(dev); @@ -1067,10 +924,13 @@ sg_dma_len(sglist) = sglist->length; return 1; } + + for(i = 0; i < nents; i++) + prev_len += sglist[i].length; spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->msg_calls++; #endif @@ -1082,7 +942,7 @@ ** w/o this association, we wouldn't have coherent DMA! ** Access to the virtual address is what forces a two pass algorithm. */ - coalesced = ccio_coalesce_chunks(ioc, sglist, nents); + coalesced = iommu_coalesce_chunks(ioc, sglist, nents, ccio_alloc_range); /* ** Program the I/O Pdir @@ -1092,13 +952,19 @@ ** o dma_len will contain the number of bytes to map ** o page/offset contain the virtual address. */ - filled = ccio_fill_pdir(ioc, sglist, nents, hint); + filled = iommu_fill_pdir(ioc, sglist, nents, hint, ccio_io_pdir_entry); spin_unlock_irqrestore(&ioc->res_lock, flags); - ASSERT(coalesced == filled); + BUG_ON(coalesced != filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + for (i = 0; i < filled; i++) + current_len += sg_dma_len(sglist + i); + + BUG_ON(current_len != prev_len); + return filled; } @@ -1123,13 +989,13 @@ DBG_RUN_SG("%s() START %d entries, %08lx,%x\n", __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usg_calls++; #endif while(sg_dma_len(sglist) && nents--) { -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; #endif ccio_unmap_single(dev, sg_dma_address(sglist), @@ -1149,8 +1015,10 @@ .unmap_single = ccio_unmap_single, .map_sg = ccio_map_sg, .unmap_sg = ccio_unmap_sg, - .dma_sync_single = NULL, /* NOP for U2/Uturn */ - .dma_sync_sg = NULL, /* ditto */ + .dma_sync_single_for_cpu = NULL, /* NOP for U2/Uturn */ + .dma_sync_single_for_device = NULL, /* NOP for U2/Uturn */ + .dma_sync_sg_for_cpu = NULL, /* ditto */ + .dma_sync_sg_for_device = NULL, /* ditto */ }; #ifdef CONFIG_PROC_FS @@ -1199,18 +1067,18 @@ total_pages * 8, total_pages); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#ifdef CCIO_MAP_STATS len = sprintf(tmp, "IO PDIR entries : %ld free %ld used (%d%%)\n", total_pages - ioc->used_pages, ioc->used_pages, (int)(ioc->used_pages * 100 / total_pages)); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", ioc->res_size, total_pages); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#ifdef CCIO_SEARCH_TIME min = max = ioc->avg_search[0]; for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { avg += ioc->avg_search[j]; @@ -1224,7 +1092,8 @@ min, avg, max); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif +#ifdef CCIO_MAP_STATS len = sprintf(tmp, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", ioc->msingle_calls, ioc->msingle_pages, (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); @@ -1250,7 +1119,7 @@ (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif /* CCIO_MAP_STATS */ ioc = ioc->next; } @@ -1336,9 +1205,7 @@ struct ioc *ioc = ccio_get_iommu(dev); u8 *res_ptr; -#ifdef CONFIG_PROC_FS ioc->cujo20_bug = 1; -#endif res_ptr = ioc->res_map; idx = PDIR_INDEX(iovp) >> 3; @@ -1429,16 +1296,16 @@ */ iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT); - ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ - ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + BUG_ON(iov_order > (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + BUG_ON(iov_order < (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ iova_space_size = 1 << (iov_order + IOVP_SHIFT); ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - ASSERT(ioc->pdir_size < 4 * 1024 * 1024); /* max pdir size < 4MB */ + BUG_ON(ioc->pdir_size >= 4 * 1024 * 1024); /* max pdir size < 4MB */ /* Verify it's a power of two */ - ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT)); + BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x", __FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20, @@ -1452,7 +1319,7 @@ } memset(ioc->pdir_base, 0, ioc->pdir_size); - ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base); + BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base); DBG_INIT(" base %p", ioc->pdir_base); /* resource map size dictated by pdir_size */ @@ -1684,13 +1551,14 @@ if (ioc_count == 0) { - /* XXX: Create separate entries for each ioc */ + /* FIXME: Create separate entries for each ioc */ create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root, ccio_proc_info, NULL); create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU, proc_runway_root, ccio_resource_map, NULL); } - + parisc_vmerge_boundary = IOVP_SIZE; + parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE; ioc_count++; return 0; } diff -Nru a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c --- a/drivers/parisc/ccio-rm-dma.c Sat Apr 3 19:38:42 2004 +++ b/drivers/parisc/ccio-rm-dma.c Sat Apr 3 19:38:42 2004 @@ -151,8 +151,10 @@ ccio_unmap_single, ccio_map_sg, ccio_unmap_sg, - NULL, /* dma_sync_single : NOP for U2 */ - NULL, /* dma_sync_sg : ditto */ + NULL, /* dma_sync_single_for_cpu : NOP for U2 */ + NULL, /* dma_sync_single_for_device : NOP for U2 */ + NULL, /* dma_sync_sg_for_cpu : ditto */ + NULL, /* dma_sync_sg_for_device : ditto */ }; diff -Nru a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c --- a/drivers/parisc/eisa.c Sat Apr 3 19:38:40 2004 +++ b/drivers/parisc/eisa.c Sat Apr 3 19:38:40 2004 @@ -116,6 +116,16 @@ gsc_writel(cpu_to_le32(data), eisa_permute(port)); } +#ifndef CONFIG_PCI +/* We call these directly without PCI. See asm/io.h. */ +EXPORT_SYMBOL(eisa_in8); +EXPORT_SYMBOL(eisa_in16); +EXPORT_SYMBOL(eisa_in32); +EXPORT_SYMBOL(eisa_out8); +EXPORT_SYMBOL(eisa_out16); +EXPORT_SYMBOL(eisa_out32); +#endif + /* Interrupt handling */ /* cached interrupt mask registers */ diff -Nru a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c --- a/drivers/parisc/gsc.c Sat Apr 3 19:38:56 2004 +++ b/drivers/parisc/gsc.c Sat Apr 3 19:38:56 2004 @@ -29,6 +29,11 @@ #include "gsc.h" +/* This sets the vmerge boundary and size, it's here because it has to + * be available on all platforms (zero means no-virtual merging) */ +unsigned long parisc_vmerge_boundary = 0; +unsigned long parisc_vmerge_max_size = 0; + #undef DEBUG #ifdef DEBUG diff -Nru a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/iommu-helpers.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,163 @@ +/** + * iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir. + * @ioc: The I/O Controller. + * @startsg: The scatter/gather list of coalesced chunks. + * @nents: The number of entries in the scatter/gather list. + * @hint: The DMA Hint. + * + * This function inserts the coalesced scatter/gather list chunks into the + * I/O Controller's I/O Pdir. + */ +static inline unsigned int +iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, + unsigned long hint, + void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long, + unsigned long)) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + unsigned int n_mappings = 0; + unsigned long dma_offset = 0, dma_len = 0; + u64 *pdirp = NULL; + + /* Horrible hack. For efficiency's sake, dma_sg starts one + * entry below the true start (it is immediately incremented + * in the loop) */ + dma_sg--; + + while (nents-- > 0) { + unsigned long vaddr; + long size; + + DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), cnt, + sg_virt_addr(startsg), startsg->length + ); + + + /* + ** Look for the start of a new DMA stream + */ + + if (sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + + BUG_ON(pdirp && (dma_len != sg_dma_len(dma_sg))); + + dma_sg++; + + dma_len = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + n_mappings++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + prefetchw(pdirp); + } + + BUG_ON(pdirp == NULL); + + vaddr = sg_virt_addr(startsg); + sg_dma_len(dma_sg) += startsg->length; + size = startsg->length + dma_offset; + dma_offset = 0; +#ifdef IOMMU_MAP_STATS + ioc->msg_pages += startsg->length >> IOVP_SHIFT; +#endif + do { + iommu_io_pdir_entry(pdirp, KERNEL_SPACE, + vaddr, hint); + vaddr += IOVP_SIZE; + size -= IOVP_SIZE; + pdirp++; + } while(unlikely(size > 0)); + startsg++; + } + return(n_mappings); +} + + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill separate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ + +static inline unsigned int +iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents, + int (*iommu_alloc_range)(struct ioc *, size_t)) +{ + struct scatterlist *contig_sg; /* contig chunk head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + unsigned int n_mappings = 0; + + while (nents > 0) { + + /* + ** Prepare for first/next DMA stream + */ + contig_sg = startsg; + dma_len = startsg->length; + dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while(--nents > 0) { + unsigned long prevstartsg_end, startsg_end; + + prevstartsg_end = sg_virt_addr(startsg) + + startsg->length; + + startsg++; + startsg_end = sg_virt_addr(startsg) + + startsg->length; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. + */ + if(unlikely(ROUNDUP(dma_len + dma_offset + startsg->length, + IOVP_SIZE) > DMA_CHUNK_SIZE)) + break; + + /* + ** Next see if we can append the next chunk (i.e. + ** it must end on one page and begin on another + */ + if (unlikely(((prevstartsg_end | sg_virt_addr(startsg)) & ~PAGE_MASK) != 0)) + break; + + dma_len += startsg->length; + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(contig_sg) = dma_len; + dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE); + sg_dma_address(contig_sg) = + PIDE_FLAG + | (iommu_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; + } + + return n_mappings; +} + diff -Nru a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c --- a/drivers/parisc/lba_pci.c Sat Apr 3 19:38:54 2004 +++ b/drivers/parisc/lba_pci.c Sat Apr 3 19:38:54 2004 @@ -533,10 +533,10 @@ */ LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); switch(size) { - case 1: *(u8 *) data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA); - break; - case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA); - break; + case 1: *(u8 *) data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3)); + break; + case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2)); + break; case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); break; } @@ -613,13 +613,14 @@ /* Basic Algorithm */ LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); switch(size) { - case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA); + case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3)); break; - case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2)); break; case 4: WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); break; } + /* flush posted write */ lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); return 0; } diff -Nru a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c --- a/drivers/parisc/sba_iommu.c Sat Apr 3 19:38:54 2004 +++ b/drivers/parisc/sba_iommu.c Sat Apr 3 19:38:54 2004 @@ -700,7 +700,8 @@ void SBA_INLINE -sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba) +sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + unsigned long hint) { u64 pa; /* physical address */ register unsigned ci; /* coherent index */ @@ -874,7 +875,7 @@ while (size > 0) { ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ - sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr); + sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0); DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n", pdir_start, @@ -1027,243 +1028,15 @@ */ #define PIDE_FLAG 0x80000000UL -#ifdef DEBUG_LARGE_SG_ENTRIES -int dump_run_sg = 0; -#endif - - -/** - * sba_fill_pdir - write allocated SG entries into IO PDIR - * @ioc: IO MMU structure which owns the pdir we are interested in. - * @startsg: list of IOVA/size pairs - * @nents: number of entries in startsg list - * - * Take preprocessed SG list and write corresponding entries - * in the IO PDIR. - */ - -static SBA_INLINE int -sba_fill_pdir( - struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ - int n_mappings = 0; - u64 *pdirp = 0; - unsigned long dma_offset = 0; - - dma_sg--; - while (nents-- > 0) { - int cnt = sg_dma_len(startsg); - sg_dma_len(startsg) = 0; - -#ifdef DEBUG_LARGE_SG_ENTRIES - if (dump_run_sg) - printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); -#else - DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); -#endif - /* - ** Look for the start of a new DMA stream - */ - if (sg_dma_address(startsg) & PIDE_FLAG) { - u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; - dma_offset = (unsigned long) pide & ~IOVP_MASK; - sg_dma_address(startsg) = 0; - dma_sg++; - sg_dma_address(dma_sg) = pide; - pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); - n_mappings++; - } - - /* - ** Look for a VCONTIG chunk - */ - if (cnt) { - unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); - ASSERT(pdirp); - - /* Since multiple Vcontig blocks could make up - ** one DMA stream, *add* cnt to dma_len. - */ - sg_dma_len(dma_sg) += cnt; - cnt += dma_offset; - dma_offset=0; /* only want offset on first chunk */ - cnt = ROUNDUP(cnt, IOVP_SIZE); #ifdef SBA_COLLECT_STATS - ioc->msg_pages += cnt >> IOVP_SHIFT; -#endif - do { - sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr); - vaddr += IOVP_SIZE; - cnt -= IOVP_SIZE; - pdirp++; - } while (cnt > 0); - } - startsg++; - } -#ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = 0; +#define IOMMU_MAP_STATS #endif - return(n_mappings); -} - - -/* -** Two address ranges are DMA contiguous *iff* "end of prev" and -** "start of next" are both on a page boundary. -** -** (shift left is a quick trick to mask off upper bits) -*/ -#define DMA_CONTIG(__X, __Y) \ - (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) - - -/** - * sba_coalesce_chunks - preprocess the SG list - * @ioc: IO MMU structure which owns the pdir we are interested in. - * @startsg: list of IOVA/size pairs - * @nents: number of entries in startsg list - * - * First pass is to walk the SG list and determine where the breaks are - * in the DMA stream. Allocates PDIR entries but does not fill them. - * Returns the number of DMA chunks. - * - * Doing the fill separate from the coalescing/allocation keeps the - * code simpler. Future enhancement could make one pass through - * the sglist do both. - */ -static SBA_INLINE int -sba_coalesce_chunks( struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ - unsigned long vcontig_len; /* len of VCONTIG chunk */ - unsigned long vcontig_end; - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - int n_mappings = 0; - - while (nents > 0) { - unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); - - /* - ** Prepare for first/next DMA stream - */ - dma_sg = vcontig_sg = startsg; - dma_len = vcontig_len = vcontig_end = startsg->length; - vcontig_end += vaddr; - dma_offset = vaddr & ~IOVP_MASK; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** This loop terminates one iteration "early" since - ** it's always looking one "ahead". - */ - while (--nents > 0) { - unsigned long vaddr; /* tmp */ - - startsg++; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* catch brokenness in SCSI layer */ - ASSERT(startsg->length <= DMA_CHUNK_SIZE); - - /* - ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the - ** next entry. - */ - if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE) - break; - - /* - ** Then look for virtually contiguous blocks. - ** PARISC needs to associate a virtual address - ** with each IO address mapped. The CPU cache is - ** virtually tagged and the IOMMU uses part - ** of the virtual address to participate in - ** CPU cache coherency. - ** - ** append the next transaction? - */ - vaddr = (unsigned long) sg_virt_addr(startsg); - if (vcontig_end == vaddr) - { - vcontig_len += startsg->length; - vcontig_end += startsg->length; - dma_len += startsg->length; - continue; - } +#include "iommu-helpers.h" #ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = (vcontig_len > IOVP_SIZE); +int dump_run_sg = 0; #endif - /* - ** Not virtually contigous. - ** Terminate prev chunk. - ** Start a new chunk. - ** - ** Once we start a new VCONTIG chunk, dma_offset - ** can't change. And we need the offset from the first - ** chunk - not the last one. Ergo Successive chunks - ** must start on page boundaries and dove tail - ** with its predecessor. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - - vcontig_sg = startsg; - vcontig_len = startsg->length; - - /* - ** 3) do the entries end/start on page boundaries? - ** Don't update vcontig_end until we've checked. - */ - if (DMA_CONTIG(vcontig_end, vaddr)) - { - vcontig_end = vcontig_len + vaddr; - dma_len += vcontig_len; - continue; - } else { - break; - } - } - - /* - ** End of DMA Stream - ** Terminate last VCONTIG block. - ** Allocate space for DMA stream. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; - ASSERT(dma_len <= DMA_CHUNK_SIZE); - sg_dma_address(dma_sg) = - PIDE_FLAG - | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) - | dma_offset; - n_mappings++; - } - - return n_mappings; -} - /** * sba_map_sg - map Scatter/Gather list @@ -1318,7 +1091,7 @@ ** w/o this association, we wouldn't have coherent DMA! ** Access to the virtual address is what forces a two pass algorithm. */ - coalesced = sba_coalesce_chunks(ioc, sglist, nents); + coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range); /* ** Program the I/O Pdir @@ -1328,7 +1101,7 @@ ** o dma_len will contain the number of bytes to map ** o address contains the virtual address. */ - filled = sba_fill_pdir(ioc, sglist, nents); + filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) @@ -1410,8 +1183,10 @@ .unmap_single = sba_unmap_single, .map_sg = sba_map_sg, .unmap_sg = sba_unmap_sg, - .dma_sync_single = NULL, - .dma_sync_sg = NULL, + .dma_sync_single_for_cpu = NULL, + .dma_sync_single_for_device = NULL, + .dma_sync_sg_for_cpu = NULL, + .dma_sync_sg_for_device = NULL, }; @@ -2045,6 +1820,9 @@ create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map); #endif #endif + parisc_vmerge_boundary = IOVP_SIZE; + parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG; + return 0; } diff -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c --- a/drivers/parisc/superio.c Sat Apr 3 19:38:45 2004 +++ b/drivers/parisc/superio.c Sat Apr 3 19:38:45 2004 @@ -69,11 +69,15 @@ #include #include #include +#include +#include #include #include #include #include +#define SUPERIO_IDE_MAX_RETRIES 25 + static struct superio_device sio_dev; @@ -161,7 +165,6 @@ printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n", pci_name(pdev),pdev->irq); - /* Find our I/O devices */ pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base); sio->sp1_base &= ~1; printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base); @@ -462,16 +465,72 @@ } -int -superio_get_ide_irq(void) +static u8 superio_ide_inb (unsigned long port); +static unsigned long superio_ide_status[2]; +static unsigned long superio_ide_select[2]; +static unsigned long superio_ide_dma_status[2]; + +void superio_fixup_pci(struct pci_dev *pdev) { - if (sio_dev.irq_region) - return sio_dev.irq_region->data.irqbase + IDE_IRQ; - else - return 0; + u8 prog; + + pdev->class |= 0x5; + pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class); + + pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); + printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog); } -EXPORT_SYMBOL(superio_get_ide_irq); +/* Because of a defect in Super I/O, all reads of the PCI DMA status + * registers, IDE status register and the IDE select register need to be + * retried + */ +static u8 superio_ide_inb (unsigned long port) +{ + if (port == superio_ide_status[0] || + port == superio_ide_status[1] || + port == superio_ide_select[0] || + port == superio_ide_select[1] || + port == superio_ide_dma_status[0] || + port == superio_ide_dma_status[1]) { + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + + /* printk(" [ reading port 0x%x with retry ] ", port); */ + + do { + tmp = inb(port); + if (tmp == 0) + udelay(50); + } while (tmp == 0 && retries-- > 0); + + return tmp; + } + + return inb(port); +} + +void __init superio_ide_init_iops (struct hwif_s *hwif) +{ + u32 base, dmabase; + u8 tmp; + struct pci_dev *pdev = hwif->pci_dev; + u8 port = hwif->channel; + + base = pci_resource_start(pdev, port * 2) & ~3; + dmabase = pci_resource_start(pdev, 4) & ~3; + + superio_ide_status[port] = base + IDE_STATUS_OFFSET; + superio_ide_select[port] = base + IDE_SELECT_OFFSET; + superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa); + + /* Clear error/interrupt, enable dma */ + tmp = superio_ide_inb(superio_ide_dma_status[port]); + outb(tmp | 0x66, superio_ide_dma_status[port]); + + /* We need to override inb to workaround a SuperIO errata */ + hwif->INB = superio_ide_inb; +} static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id) { diff -Nru a/drivers/parport/daisy.c b/drivers/parport/daisy.c --- a/drivers/parport/daisy.c Sat Apr 3 19:38:42 2004 +++ b/drivers/parport/daisy.c Sat Apr 3 19:38:42 2004 @@ -27,7 +27,7 @@ #include #include -#define DEBUG /* undef me for production */ +#undef DEBUG #ifdef DEBUG #define DPRINTK(stuff...) printk (stuff) diff -Nru a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c --- a/drivers/parport/parport_gsc.c Sat Apr 3 19:38:55 2004 +++ b/drivers/parport/parport_gsc.c Sat Apr 3 19:38:55 2004 @@ -476,7 +476,7 @@ return 0; } -static void __devexit parport_remove_chip(struct parisc_device *dev) +static int __devexit parport_remove_chip(struct parisc_device *dev) { struct parport *p = dev->dev.driver_data; if (p) { @@ -495,6 +495,7 @@ parport_put_port(p); kfree (ops); /* hope no-one cached it */ } + return 0; } static struct parisc_device_id parport_tbl[] = { @@ -508,7 +509,7 @@ .name = "Parallel", .id_table = parport_tbl, .probe = parport_init_chip, - .remove = parport_remove_chip, + .remove = __devexit_p(parport_remove_chip), }; int __devinit parport_gsc_init(void) diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c --- a/drivers/parport/parport_pc.c Sat Apr 3 19:38:56 2004 +++ b/drivers/parport/parport_pc.c Sat Apr 3 19:38:56 2004 @@ -13,6 +13,7 @@ * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. * Various hacks, Fred Barnes, 04/2001 + * Updated probing logic - Adam Belay */ /* This driver should work with any hardware that is broadly compatible @@ -98,7 +99,8 @@ (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) static int verbose_probing; #endif -static int registered_parport; +static int pci_registered_parport; +static int pnp_registered_parport; /* frob_control, but for ECR */ static void frob_econtrol (struct parport *pb, unsigned char m, @@ -2771,10 +2773,11 @@ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); -static int __devinit parport_pc_pci_probe (struct pci_dev *dev, +static int parport_pc_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) { int err, count, n, i = id->driver_data; + if (i < last_sio) /* This is an onboard Super-IO and has already been probed */ return 0; @@ -2847,23 +2850,72 @@ static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} #endif /* CONFIG_PCI */ -#ifdef CONFIG_PNP -static const struct pnp_device_id pnp_dev_table[] = { + +static const struct pnp_device_id parport_pc_pnp_tbl[] = { /* Standard LPT Printer Port */ {.id = "PNP0400", .driver_data = 0}, /* ECP Printer Port */ {.id = "PNP0401", .driver_data = 0}, - {.id = ""} + { } }; +MODULE_DEVICE_TABLE(pnp,parport_pc_pnp_tbl); + +static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) +{ + struct parport *pdata; + unsigned long io_lo, io_hi; + int dma, irq; + + if (pnp_port_valid(dev,0) && + !(pnp_port_flags(dev,0) & IORESOURCE_DISABLED)) { + io_lo = pnp_port_start(dev,0); + } else + return -EINVAL; + + if (pnp_port_valid(dev,1) && + !(pnp_port_flags(dev,1) & IORESOURCE_DISABLED)) { + io_hi = pnp_port_start(dev,1); + } else + io_hi = 0; + + if (pnp_irq_valid(dev,0) && + !(pnp_irq_flags(dev,0) & IORESOURCE_DISABLED)) { + irq = pnp_irq(dev,0); + } else + irq = PARPORT_IRQ_NONE; + + if (pnp_dma_valid(dev,0) && + !(pnp_dma_flags(dev,0) & IORESOURCE_DISABLED)) { + dma = pnp_dma(dev,0); + } else + dma = PARPORT_DMA_NONE; + + printk(KERN_INFO "parport: PnPBIOS parport detected.\n"); + if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, NULL))) + return -ENODEV; + + pnp_set_drvdata(dev,pdata); + return 0; +} + +static void parport_pc_pnp_remove(struct pnp_dev *dev) +{ + struct parport *pdata = (struct parport *)pnp_get_drvdata(dev); + if (!pdata) + return; + + parport_pc_unregister_port(pdata); +} + /* we only need the pnp layer to activate the device, at least for now */ static struct pnp_driver parport_pc_pnp_driver = { .name = "parport_pc", - .id_table = pnp_dev_table, + .id_table = parport_pc_pnp_tbl, + .probe = parport_pc_pnp_probe, + .remove = parport_pc_pnp_remove, }; -#else -static struct pnp_driver parport_pc_pnp_driver; -#endif + /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ static int __init __attribute__((unused)) @@ -2903,12 +2955,18 @@ /* Onboard SuperIO chipsets that show themselves on the PCI bus. */ count += parport_pc_init_superio (autoirq, autodma); + r = pnp_register_driver (&parport_pc_pnp_driver); + if (r >= 0) { + pnp_registered_parport = 1; + count += r; + } + /* ISA ports and whatever (see asm/parport.h). */ count += parport_pc_find_nonpci_ports (autoirq, autodma); r = pci_register_driver (&parport_pc_pci_driver); if (r >= 0) { - registered_parport = 1; + pci_registered_parport = 1; count += r; } @@ -3104,9 +3162,6 @@ if (parse_parport_params()) return -EINVAL; - /* try to activate any PnP parports first */ - pnp_register_driver(&parport_pc_pnp_driver); - if (io[0]) { int i; /* Only probe the ports we were given. */ @@ -3120,24 +3175,18 @@ irqval[i], dmaval[i], NULL)) count++; } - } else { + } else count += parport_pc_find_ports (irqval[0], dmaval[0]); - if (!count && registered_parport) - pci_unregister_driver (&parport_pc_pci_driver); - } - - if (!count) { - pnp_unregister_driver (&parport_pc_pnp_driver); - return -ENODEV; - } return 0; } static void __exit parport_pc_exit(void) { - if (registered_parport) + if (pci_registered_parport) pci_unregister_driver (&parport_pc_pci_driver); + if (pnp_registered_parport) + pnp_unregister_driver (&parport_pc_pnp_driver); spin_lock(&ports_lock); while (!list_empty(&ports_list)) { @@ -3151,13 +3200,8 @@ spin_lock(&ports_lock); } spin_unlock(&ports_lock); - pnp_unregister_driver (&parport_pc_pnp_driver); } - -MODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); -MODULE_DESCRIPTION("PC-style parallel port driver"); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); MODULE_DESCRIPTION("PC-style parallel port driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile --- a/drivers/pci/hotplug/Makefile Sat Apr 3 19:38:54 2004 +++ b/drivers/pci/hotplug/Makefile Sat Apr 3 19:38:54 2004 @@ -40,7 +40,9 @@ acpiphp_res.o rpaphp-objs := rpaphp_core.o \ - rpaphp_pci.o + rpaphp_pci.o \ + rpaphp_slot.o \ + rpaphp_vio.o rpadlpar_io-objs := rpadlpar_core.o \ rpadlpar_sysfs.o diff -Nru a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h --- a/drivers/pci/hotplug/acpiphp.h Sat Apr 3 19:38:56 2004 +++ b/drivers/pci/hotplug/acpiphp.h Sat Apr 3 19:38:56 2004 @@ -235,7 +235,7 @@ extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); extern int acpiphp_configure_slot (struct acpiphp_slot *slot); extern int acpiphp_configure_function (struct acpiphp_func *func); -extern int acpiphp_unconfigure_function (struct acpiphp_func *func); +extern void acpiphp_unconfigure_function (struct acpiphp_func *func); extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); extern int acpiphp_init_func_resource (struct acpiphp_func *func); diff -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c --- a/drivers/pci/hotplug/acpiphp_glue.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pci/hotplug/acpiphp_glue.c Sat Apr 3 19:38:42 2004 @@ -694,14 +694,14 @@ func = list_entry(l, struct acpiphp_func, sibling); if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0 on %s\n", __FUNCTION__, - pci_name(func->pci_dev)); + dbg("%s: executing _PS0\n", __FUNCTION__); status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS0 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } + } else + break; } } @@ -737,7 +737,8 @@ warn("%s: _PS3 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } + } else + break; } } @@ -757,7 +758,8 @@ warn("%s: _EJ0 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } + } else + break; } } @@ -865,15 +867,8 @@ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->pci_dev) { - if (acpiphp_unconfigure_function(func) == 0) { - func->pci_dev = NULL; - } else { - err("failed to unconfigure device\n"); - retval = -1; - goto err_exit; - } - } + if (func->pci_dev) + acpiphp_unconfigure_function(func); } slot->flags &= (~SLOT_ENABLED); @@ -1269,7 +1264,7 @@ up(&slot->crit_sect); goto err_exit; } - enabled++; + disabled++; } } else { /* if disabled but present, enable */ @@ -1280,7 +1275,7 @@ up(&slot->crit_sect); goto err_exit; } - disabled++; + enabled++; } } } diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c --- a/drivers/pci/hotplug/acpiphp_pci.c Sat Apr 3 19:38:40 2004 +++ b/drivers/pci/hotplug/acpiphp_pci.c Sat Apr 3 19:38:40 2004 @@ -83,8 +83,8 @@ if (bar & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ - len = bar & 0xFFFFFFFC; - len = ~len + 1; + len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("len in IO %x, BAR %d\n", len, count); @@ -226,8 +226,8 @@ if (len & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; + len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); @@ -351,8 +351,8 @@ if (len & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; + len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); @@ -485,14 +485,13 @@ * @func: function to be unconfigured * */ -int acpiphp_unconfigure_function (struct acpiphp_func *func) +void acpiphp_unconfigure_function (struct acpiphp_func *func) { struct acpiphp_bridge *bridge; - int retval = 0; /* if pci_dev is NULL, ignore it */ if (!func->pci_dev) - goto err_exit; + return; pci_remove_bus_device(func->pci_dev); @@ -505,7 +504,4 @@ acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); acpiphp_move_resource(&func->bus_head, &bridge->bus_head); spin_unlock(&bridge->res_lock); - - err_exit: - return retval; } diff -Nru a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c --- a/drivers/pci/hotplug/acpiphp_res.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pci/hotplug/acpiphp_res.c Sat Apr 3 19:38:42 2004 @@ -224,7 +224,7 @@ } /* End of too big on top end */ /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) + if ((node->base & 0x300L) && !(node->base & 0xfffff000)) continue; /* If we got here, then it is the right size diff -Nru a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c --- a/drivers/pci/hotplug/cpqphp_core.c Sat Apr 3 19:38:40 2004 +++ b/drivers/pci/hotplug/cpqphp_core.c Sat Apr 3 19:38:40 2004 @@ -1342,7 +1342,7 @@ cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); if (!cpqhp_rom_start) { err ("Could not ioremap memory region for ROM\n"); - retval = -EIO;; + retval = -EIO; goto error; } @@ -1353,14 +1353,14 @@ smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); if (!smbios_table) { err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO;; + retval = -EIO; goto error; } smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); if (!smbios_start) { err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO;; + retval = -EIO; goto error; } diff -Nru a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c --- a/drivers/pci/hotplug/pci_hotplug_core.c Sat Apr 3 19:38:55 2004 +++ b/drivers/pci/hotplug/pci_hotplug_core.c Sat Apr 3 19:38:55 2004 @@ -104,19 +104,7 @@ .release = &hotplug_slot_release, }; -/* - * We create a struct subsystem on our own and not use decl_subsys so - * we can have a sane name "slots" in sysfs, yet still keep a good - * global variable name "pci_hotplug_slots_subsys. - * If the decl_subsys() #define ever changes, this declaration will - * need to be update to make sure everything is initialized properly. - */ -struct subsystem pci_hotplug_slots_subsys = { - .kset = { - .kobj = { .name = "slots" }, - .ktype = &hotplug_slot_ktype, - } -}; +decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL); /* these strings match up with the values in pci_bus_speed */ static char *pci_bus_speed_strings[] = { diff -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c --- a/drivers/pci/hotplug/pciehp_hpc.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pci/hotplug/pciehp_hpc.c Sat Apr 3 19:38:44 2004 @@ -915,7 +915,7 @@ rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE;; + return IRQ_NONE; } temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x00; @@ -923,7 +923,7 @@ rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE;; + return IRQ_NONE; } } diff -Nru a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c --- a/drivers/pci/hotplug/pciehp_pci.c Sat Apr 3 19:38:55 2004 +++ b/drivers/pci/hotplug/pciehp_pci.c Sat Apr 3 19:38:55 2004 @@ -103,7 +103,7 @@ */ int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) { -#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) +#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) int rc; u16 temp_word; struct pci_dev fakedev; diff -Nru a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c --- a/drivers/pci/hotplug/pciehprm_acpi.c Sat Apr 3 19:38:55 2004 +++ b/drivers/pci/hotplug/pciehprm_acpi.c Sat Apr 3 19:38:55 2004 @@ -1268,7 +1268,8 @@ int pciehprm_print_pirt(void) { dbg("PCIEHPRM ACPI Slots\n"); - print_acpi_resources (acpi_bridges_head); + if (acpi_bridges_head) + print_acpi_resources (acpi_bridges_head); return 0; } diff -Nru a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c --- a/drivers/pci/hotplug/rpadlpar_core.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pci/hotplug/rpadlpar_core.c Sat Apr 3 19:38:44 2004 @@ -43,7 +43,28 @@ return ptr; } -static struct device_node *find_php_slot_node(char *drc_name) +static struct device_node *find_php_slot_vio_node(char *drc_name) +{ + struct device_node *child; + struct device_node *parent = of_find_node_by_name(NULL, "vdevice"); + + if (!parent) + return NULL; + + for (child = of_get_next_child(parent, NULL); + child; child = of_get_next_child(parent, child)) { + + char *loc_code; + + loc_code = get_property(child, "ibm,loc-code", NULL); + if (loc_code && !strcmp(loc_code, drc_name)) + return child; + } + + return NULL; +} + +static struct device_node *find_php_slot_pci_node(char *drc_name) { struct device_node *np = NULL; char *name; @@ -72,7 +93,7 @@ static struct slot *find_slot(char *drc_name) { struct hotplug_slot *php_slot = find_php_slot(drc_name); - + if (!php_slot) return NULL; @@ -127,14 +148,14 @@ rpadlpar_claim_one_bus(bridge_dev->bus); if (hose->last_busno < child->number) - hose->last_busno = child->number; + hose->last_busno = child->number; dn->bussubno = child->number; /* ioremap() for child bus */ if (remap_bus_range(child)) { printk(KERN_ERR "%s: could not ioremap() child bus\n", - __FUNCTION__); + __FUNCTION__); return 1; } @@ -162,9 +183,9 @@ return NULL; } - if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { + if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { printk(KERN_ERR "%s: unexpected header type %d\n", - __FUNCTION__, dev->hdr_type); + __FUNCTION__, dev->hdr_type); return NULL; } @@ -180,7 +201,7 @@ if (!bridge_dev) { printk(KERN_ERR "%s: unexpected null device\n", - __FUNCTION__); + __FUNCTION__); return 1; } @@ -188,11 +209,25 @@ if (unmap_bus_range(secondary_bus)) { printk(KERN_ERR "%s: failed to unmap bus range\n", - __FUNCTION__); + __FUNCTION__); return 1; } pci_remove_bus_device(bridge_dev); + return 0; +} + +static inline int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) +{ + struct pci_dev *dev; + + /* Add pci bus */ + dev = dlpar_pci_add_bus(dn); + if (!dev) { + printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__, + drc_name); + return -EIO; + } return 0; } @@ -212,37 +247,33 @@ */ int dlpar_add_slot(char *drc_name) { - struct device_node *dn = find_php_slot_node(drc_name); - struct pci_dev *dev; + struct device_node *dn; int rc = 0; if (down_interruptible(&rpadlpar_sem)) return -ERESTARTSYS; - if (!dn) { - rc = -ENODEV; - goto exit; - } - /* Check for existing hotplug slot */ if (find_slot(drc_name)) { rc = -EINVAL; goto exit; } - /* Add pci bus */ - dev = dlpar_pci_add_bus(dn); - if (!dev) { - printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__, - drc_name); - rc = -EIO; - goto exit; + dn = find_php_slot_vio_node(drc_name); + if (!dn) { + dn = find_php_slot_pci_node(drc_name); + if (dn) + rc = dlpar_add_pci_slot(drc_name, dn); + else { + rc = -ENODEV; + goto exit; + } } - /* Add hotplug slot for new bus */ - if (rpaphp_add_slot(drc_name)) { + /* Add hotplug slot for new VIOA or PCI */ + if (!rc && rpaphp_add_slot(dn)) { printk(KERN_ERR "%s: unable to add hotplug slot %s\n", - __FUNCTION__, drc_name); + __FUNCTION__, drc_name); rc = -EIO; } exit: @@ -251,60 +282,107 @@ } /** - * dlpar_remove_slot - DLPAR remove an I/O Slot + * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot * @drc_name: drc-name of newly added slot * * Remove the kernel and hotplug representations * of an I/O Slot. * Return Codes: * 0 Success + * -EIO Internal Error + */ +int dlpar_remove_vio_slot(struct slot *slot, char *drc_name) +{ + /* Remove hotplug slot */ + + if (rpaphp_remove_slot(slot)) { + printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", + __FUNCTION__, drc_name); + return -EIO; + } + return 0; +} + +/** + * dlpar_remove_slot - DLPAR remove a PCI I/O Slot + * @drc_name: drc-name of newly added slot + * + * Remove the kernel and hotplug representations + * of a PCI I/O Slot. + * Return Codes: + * 0 Success * -ENODEV Not a valid drc_name - * -EINVAL Slot already removed - * -ERESTARTSYS Signalled before obtaining lock * -EIO Internal PCI Error */ -int dlpar_remove_slot(char *drc_name) +int dlpar_remove_pci_slot(struct slot *slot, char *drc_name) { - struct device_node *dn = find_php_slot_node(drc_name); - struct slot *slot; + struct device_node *dn = find_php_slot_pci_node(drc_name); struct pci_dev *bridge_dev; - int rc = 0; - - if (down_interruptible(&rpadlpar_sem)) - return -ERESTARTSYS; - if (!dn) { - rc = -ENODEV; - goto exit; - } - - slot = find_slot(drc_name); - if (!slot) { - rc = -EINVAL; - goto exit; - } + if (!dn) + return -ENODEV; bridge_dev = slot->bridge; if (!bridge_dev) { printk(KERN_ERR "%s: unexpected null bridge device\n", - __FUNCTION__); - rc = -EIO; - goto exit; + __FUNCTION__); + return -EIO; } /* Remove hotplug slot */ if (rpaphp_remove_slot(slot)) { printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", - __FUNCTION__, drc_name); - rc = -EIO; - goto exit; + __FUNCTION__, drc_name); + return -EIO; } /* Remove pci bus */ if (dlpar_pci_remove_bus(bridge_dev)) { printk(KERN_ERR "%s: unable to remove pci bus %s\n", - __FUNCTION__, drc_name); - rc = -EIO; + __FUNCTION__, drc_name); + return -EIO; + } + return 0; +} + +/** + * dlpar_remove_slot - DLPAR remove an I/O Slot + * @drc_name: drc-name of newly added slot + * + * Remove the kernel and hotplug representations + * of an I/O Slot. + * Return Codes: + * 0 Success + * -ENODEV Not a valid drc_name + * -EINVAL Slot already removed + * -ERESTARTSYS Signalled before obtaining lock + * -EIO Internal Error + */ +int dlpar_remove_slot(char *drc_name) +{ + struct slot *slot; + int rc = 0; + + if (down_interruptible(&rpadlpar_sem)) + return -ERESTARTSYS; + + slot = find_slot(drc_name); + if (!slot) { + rc = -EINVAL; + goto exit; + } + + switch (slot->dev_type) { + case PCI_DEV: + rc = dlpar_remove_pci_slot(slot, drc_name); + break; + + case VIO_DEV: + rc = dlpar_remove_vio_slot(slot, drc_name); + break; + + default: + rc = -EIO; } exit: up(&rpadlpar_sem); @@ -324,7 +402,7 @@ if (!is_dlpar_capable()) { printk(KERN_WARNING "%s: partition not DLPAR capable\n", - __FUNCTION__); + __FUNCTION__); return -EPERM; } diff -Nru a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h --- a/drivers/pci/hotplug/rpaphp.h Sat Apr 3 19:38:42 2004 +++ b/drivers/pci/hotplug/rpaphp.h Sat Apr 3 19:38:42 2004 @@ -26,6 +26,8 @@ #ifndef _PPC64PHP_H #define _PPC64PHP_H + +#include #include "pci_hotplug.h" #define DR_INDICATOR 9002 @@ -34,24 +36,22 @@ #define POWER_ON 100 #define POWER_OFF 0 -#define LED_OFF 0 -#define LED_ON 1 /* continuous on */ +#define LED_OFF 0 +#define LED_ON 1 /* continuous on */ #define LED_ID 2 /* slow blinking */ #define LED_ACTION 3 /* fast blinking */ -#define SLOT_NAME_SIZE 12 - /* Error status from rtas_get-sensor */ -#define NEED_POWER -9000 /* slot must be power up and unisolated to get state */ -#define PWR_ONLY -9001 /* slot must be powerd up to get state, leave isolated */ -#define ERR_SENSE_USE -9002 /* No DR operation will succeed, slot is unusable */ +#define NEED_POWER -9000 /* slot must be power up and unisolated to get state */ +#define PWR_ONLY -9001 /* slot must be powerd up to get state, leave isolated */ +#define ERR_SENSE_USE -9002 /* No DR operation will succeed, slot is unusable */ /* Sensor values from rtas_get-sensor */ -#define EMPTY 0 /* No card in slot */ -#define PRESENT 1 /* Card in slot */ +#define EMPTY 0 /* No card in slot */ +#define PRESENT 1 /* Card in slot */ #define MY_NAME "rpaphp" - +extern int debug; #define dbg(format, arg...) \ do { \ if (debug) \ @@ -64,6 +64,10 @@ #define SLOT_MAGIC 0x67267322 +/* slot types */ +#define VIO_DEV 1 +#define PCI_DEV 2 + /* slot states */ #define NOT_VALID 3 @@ -75,27 +79,55 @@ * struct slot - slot information for each *physical* slot */ struct slot { - u32 magic; - int state; - u32 index; - u32 type; - u32 power_domain; - char *name; - struct device_node *dn;/* slot's device_node in OFDT */ - /* dn has phb info */ - struct pci_dev *bridge;/* slot's pci_dev in pci_devices */ - - struct pci_dev *dev; /* pci_dev of device in this slot */ - /* it will be used for unconfig */ - /* NULL if slot is empty */ - - struct hotplug_slot *hotplug_slot; - struct list_head rpaphp_slot_list; + u32 magic; + int state; + u32 index; + u32 type; + u32 power_domain; + char *name; + struct device_node *dn; /* slot's device_node in OFDT */ + /* dn has phb info */ + struct pci_dev *bridge; /* slot's pci_dev in pci_devices */ + union { + struct pci_dev *pci_dev; /* pci_dev of device in this slot */ + /* it will be used for unconfig */ + /* NULL if slot is empty */ + struct vio_dev *vio_dev; /* vio_dev of the device in this slot */ + } dev; + u8 dev_type; /* VIO or PCI */ + struct hotplug_slot *hotplug_slot; + struct list_head rpaphp_slot_list; }; +extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; +extern struct list_head rpaphp_slot_head; +extern int num_slots; + +/* function prototypes */ + +/* rpaphp_pci.c */ extern struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn); -extern int rpaphp_add_slot(char *slot_name); -extern int rpaphp_remove_slot(struct slot *slot); extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); +extern int rpaphp_enable_pci_slot(struct slot *slot); +extern int register_pci_slot(struct slot *slot); +extern int rpaphp_unconfig_pci_adapter(struct slot *slot); +extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); + +/* rpaphp_core.c */ +extern int rpaphp_add_slot(struct device_node *dn); +extern int rpaphp_remove_slot(struct slot *slot); -#endif /* _PPC64PHP_H */ +/* rpaphp_vio.c */ +extern int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 * value); +extern int rpaphp_unconfig_vio_adapter(struct slot *slot); +extern int register_vio_slot(struct device_node *dn); +extern int rpaphp_enable_vio_slot(struct slot *slot); + +/* rpaphp_slot.c */ +extern void dealloc_slot_struct(struct slot *slot); +extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); +extern int register_slot(struct slot *slot); +extern int rpaphp_get_power_status(struct slot *slot, u8 * value); +extern int rpaphp_set_attention_status(struct slot *slot, u8 status); + +#endif /* _PPC64PHP_H */ diff -Nru a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c --- a/drivers/pci/hotplug/rpaphp_core.c Sat Apr 3 19:38:56 2004 +++ b/drivers/pci/hotplug/rpaphp_core.c Sat Apr 3 19:38:56 2004 @@ -31,18 +31,18 @@ #include #include #include +#include /* for eeh_add_device() */ #include /* rtas_call */ #include /* for pci_controller */ -#include "../pci.h" /* for pci_add_new_bus*/ - /* and pci_do_scan_bus*/ +#include "../pci.h" /* for pci_add_new_bus */ + /* and pci_do_scan_bus */ #include "rpaphp.h" #include "pci_hotplug.h" - -static int debug; +int debug; static struct semaphore rpaphp_sem; -static LIST_HEAD (rpaphp_slot_head); -static int num_slots; +LIST_HEAD(rpaphp_slot_head); +int num_slots; #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Linda Xie " @@ -59,109 +59,35 @@ static int enable_slot(struct hotplug_slot *slot); static int disable_slot(struct hotplug_slot *slot); static int set_attention_status(struct hotplug_slot *slot, u8 value); -static int get_power_status(struct hotplug_slot *slot, u8 *value); -static int get_attention_status(struct hotplug_slot *slot, u8 *value); -static int get_adapter_status(struct hotplug_slot *slot, u8 *value); +static int get_power_status(struct hotplug_slot *slot, u8 * value); +static int get_attention_status(struct hotplug_slot *slot, u8 * value); +static int get_adapter_status(struct hotplug_slot *slot, u8 * value); static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); -static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, +struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, }; -static int rpaphp_get_sensor_state(int index, int *state) -{ - int rc; - - rc = rtas_get_sensor(DR_ENTITY_SENSE, index, state); - - if (rc) { - if (rc == NEED_POWER || rc == PWR_ONLY) { - dbg("%s: slot must be power up to get sensor-state\n", - __FUNCTION__); - } else if (rc == ERR_SENSE_USE) - info("%s: slot is unusable\n", __FUNCTION__); - else err("%s failed to get sensor state\n", __FUNCTION__); - } - return rc; -} - -static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot) -{ - return rpaphp_find_pci_dev(slot->dn); -} - -static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot) -{ - return rpaphp_find_pci_dev(slot->dn->child); -} - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check(struct slot *slot, const char *function) +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) { - if (!slot) { - dbg("%s - slot == NULL\n", function); - return -1; - } - - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!\n", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - if (!hotplug_slot) { dbg("%s - hotplug_slot == NULL\n", function); return NULL; } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check(slot, function)) - return NULL; - return slot; -} - -static inline int rpaphp_set_attention_status(struct slot *slot, u8 status) -{ - int rc; - - /* status: LED_OFF or LED_ON */ - rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); - if (rc) - err("slot(%s) set attention-status(%d) failed! rc=0x%x\n", - slot->name, status, rc); - - return rc; -} - -static int rpaphp_get_power_status(struct slot *slot, u8 *value) -{ - int rc; - - rc = rtas_get_power_level(slot->power_domain, (int *)value); - if (rc) - err("failed to get power-level for slot(%s), rc=0x%x\n", - slot->name, rc); - - return rc; + return (struct slot *)hotplug_slot->private; } static int rpaphp_get_attention_status(struct slot *slot) { - return slot->hotplug_slot->info->attention_status; } @@ -172,7 +98,7 @@ * echo 2 > attention -- set LED ID(identify, light is blinking) * */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) +static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { int retval = 0; struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); @@ -182,25 +108,21 @@ down(&rpaphp_sem); switch (value) { - case 0: - retval = rpaphp_set_attention_status(slot, LED_OFF); - hotplug_slot->info->attention_status = 0; - break; - - case 1: - default: - retval = rpaphp_set_attention_status(slot, LED_ON); - hotplug_slot->info->attention_status = 1; - break; - - case 2: - retval = rpaphp_set_attention_status(slot, LED_ID); - hotplug_slot->info->attention_status = 2; - break; - + case 0: + retval = rpaphp_set_attention_status(slot, LED_OFF); + hotplug_slot->info->attention_status = 0; + break; + case 1: + default: + retval = rpaphp_set_attention_status(slot, LED_ON); + hotplug_slot->info->attention_status = 1; + break; + case 2: + retval = rpaphp_set_attention_status(slot, LED_ID); + hotplug_slot->info->attention_status = 2; + break; } up(&rpaphp_sem); - return retval; } @@ -211,7 +133,7 @@ * * */ -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) { int retval; struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); @@ -222,7 +144,6 @@ down(&rpaphp_sem); retval = rpaphp_get_power_status(slot, value); up(&rpaphp_sem); - return retval; } @@ -231,7 +152,7 @@ * * */ -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) { int retval = 0; struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); @@ -239,81 +160,36 @@ if (slot == NULL) return -ENODEV; - down(&rpaphp_sem); *value = rpaphp_get_attention_status(slot); up(&rpaphp_sem); - return retval; } -/* - * get_adapter_status - get the status of a slot - * - * 0-- slot is empty - * 1-- adapter is configured - * 2-- adapter is not configured - * 3-- not valid - */ -static int rpaphp_get_adapter_status(struct slot *slot, int is_init, u8 *value) -{ - int state, rc; - - *value = NOT_VALID; - - rc = rpaphp_get_sensor_state(slot->index, &state); - - if (rc) - return rc; - - if (state == PRESENT) { - dbg("slot is occupied\n"); - - if (!is_init) /* at run-time slot->state can be changed by */ - /* config/unconfig adapter */ - *value = slot->state; - else { - if (!slot->dn->child) - dbg("%s: %s is not valid OFDT node\n", - __FUNCTION__, slot->dn->full_name); - else - if (rpaphp_find_pci_dev(slot->dn->child)) - *value = CONFIGURED; - else { - dbg("%s: can't find pdev of adapter in slot[%s]\n", - __FUNCTION__, slot->name); - *value = NOT_CONFIGURED; - } - } - } else - if (state == EMPTY) { - dbg("slot is empty\n"); - *value = state; - } - - return 0; -} - -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) { struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); int retval = 0; if (slot == NULL) return -ENODEV; - down(&rpaphp_sem); - /* have to go through this */ - retval = rpaphp_get_adapter_status(slot, 0, value); - + switch (slot->dev_type) { + case PCI_DEV: + retval = rpaphp_get_pci_adapter_status(slot, 0, value); + break; + case VIO_DEV: + retval = rpaphp_get_vio_adapter_status(slot, 0, value); + break; + default: + retval = -EINVAL; + } up(&rpaphp_sem); - return retval; } - -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); @@ -321,46 +197,42 @@ return -ENODEV; down(&rpaphp_sem); - switch (slot->type) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - *value = PCI_SPEED_33MHz; /* speed for case 1-6 */ - break; - case 7: - case 8: - *value = PCI_SPEED_66MHz; - break; - case 11: - case 14: - *value = PCI_SPEED_66MHz_PCIX; - break; - case 12: - case 15: - *value = PCI_SPEED_100MHz_PCIX; - break; - case 13: - case 16: - *value = PCI_SPEED_133MHz_PCIX; - break; - default: - *value = PCI_SPEED_UNKNOWN; - break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + *value = PCI_SPEED_33MHz; /* speed for case 1-6 */ + break; + case 7: + case 8: + *value = PCI_SPEED_66MHz; + break; + case 11: + case 14: + *value = PCI_SPEED_66MHz_PCIX; + break; + case 12: + case 15: + *value = PCI_SPEED_100MHz_PCIX; + break; + case 13: + case 16: + *value = PCI_SPEED_133MHz_PCIX; + break; + default: + *value = PCI_SPEED_UNKNOWN; + break; } - up(&rpaphp_sem); - return 0; } - /* return dummy value because not sure if PRA provides any method... */ -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); @@ -368,416 +240,106 @@ return -ENODEV; *value = PCI_SPEED_UNKNOWN; - return 0; } -/* - * rpaphp_validate_slot - make sure the name of the slot matches - * the location code , if the slots is not - * empty. - */ -static int rpaphp_validate_slot(const char *slot_name, const int slot_index) -{ - struct device_node *dn; - - for(dn = find_all_nodes(); dn; dn = dn->next) { - - int *index; - unsigned char *loc_code; - - index = (int *)get_property(dn, "ibm,my-drc-index", NULL); - - if (index && *index == slot_index) { - char *slash, *tmp_str; - - loc_code = get_property(dn, "ibm,loc-code", NULL); - if (!loc_code) { - return -1; - } - - tmp_str = kmalloc(MAX_LOC_CODE, GFP_KERNEL); - if (!tmp_str) { - err("%s: out of memory\n", __FUNCTION__); - return -1; - } - - strcpy(tmp_str, loc_code); - slash = strrchr(tmp_str, '/'); - if (slash) - *slash = '\0'; - - if (strcmp(slot_name, tmp_str)) { - kfree(tmp_str); - return -1; - } - - kfree(tmp_str); - break; - } - } - - return 0; -} - -/* Must be called before pci_bus_add_devices */ -static void rpaphp_fixup_new_devices(struct pci_bus *bus) -{ - struct pci_dev *dev; - - list_for_each_entry(dev, &bus->devices, bus_list) { - /* - * Skip already-present devices (which are on the - * global device list.) - */ - if (list_empty(&dev->global_list)) { - int i; - pcibios_fixup_device_resources(dev, bus); - pci_read_irq_line(dev); - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - if (r->parent || !r->start || !r->flags) - continue; - rpaphp_claim_resource(dev, i); - } - } - } -} - -static struct pci_dev *rpaphp_config_adapter(struct slot *slot) -{ - struct pci_bus *pci_bus; - struct device_node *dn; - int num; - struct pci_dev *dev = NULL; - - if (slot->bridge) { - - pci_bus = slot->bridge->subordinate; - - if (!pci_bus) { - err("%s: can't find bus structure\n", __FUNCTION__); - goto exit; - } - - for (dn = slot->dn->child; dn; dn = dn->sibling) { - dbg("child dn's devfn=[%x]\n", dn->devfn); - num = pci_scan_slot(pci_bus, - PCI_DEVFN(PCI_SLOT(dn->devfn), 0)); - - dbg("pci_scan_slot return num=%d\n", num); - - if (num) { - rpaphp_fixup_new_devices(pci_bus); - pci_bus_add_devices(pci_bus); - } - } - - dev = rpaphp_find_pci_dev(slot->dn->child); - } else { - /* slot is not enabled */ - err("slot doesn't have pci_dev structure\n"); - dev = NULL; - goto exit; - } - -exit: - dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev? "found":"not found"); - - return dev; -} - -static int rpaphp_unconfig_adapter(struct slot *slot) -{ - if (!slot->dev) { - info("%s: no card in slot[%s]\n", - __FUNCTION__, slot->name); - - return -EINVAL; - } - - /* remove the device from the pci core */ - pci_remove_bus_device(slot->dev); - - pci_dev_put(slot->dev); - slot->state = NOT_CONFIGURED; - - dbg("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name); - - return 0; -} - -/* free up the memory user be a slot */ - -static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return; - - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - pci_dev_put(slot->bridge); - pci_dev_put(slot->dev); - kfree(slot); -} - int rpaphp_remove_slot(struct slot *slot) { int retval = 0; + char *rm_link; - sysfs_remove_link(slot->hotplug_slot->kobj.parent, - slot->bridge->slot_name); + dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name); + if (slot->dev_type == PCI_DEV) + rm_link = pci_name(slot->bridge); + else + rm_link = strstr(slot->dn->full_name, "@"); + sysfs_remove_link(slot->hotplug_slot->kobj.parent, rm_link); list_del(&slot->rpaphp_slot_list); retval = pci_hp_deregister(slot->hotplug_slot); if (retval) err("Problem unregistering a slot %s\n", slot->name); + num_slots--; + dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; } -static int is_php_dn(struct device_node *dn, int **indexes, int **names, int **types, int **power_domains) +static int is_php_dn(struct device_node *dn, int **indexes, int **names, int **types, + int **power_domains) { - *indexes = (int *)get_property(dn, "ibm,drc-indexes", NULL); + *indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL); if (!*indexes) - return(0); - + return (0); /* &names[1] contains NULL terminated slot names */ - *names = (int *)get_property(dn, "ibm,drc-names", NULL); + *names = (int *) get_property(dn, "ibm,drc-names", NULL); if (!*names) - return(0); - + return (0); /* &types[1] contains NULL terminated slot types */ - *types = (int *)get_property(dn, "ibm,drc-types", NULL); + *types = (int *) get_property(dn, "ibm,drc-types", NULL); if (!*types) - return(0); - + return (0); /* power_domains[1...n] are the slot power domains */ - *power_domains = (int *)get_property(dn, - "ibm,drc-power-domains", NULL); + *power_domains = (int *) get_property(dn, + "ibm,drc-power-domains", NULL); if (!*power_domains) - return(0); - - if (!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL)) - return(0); - - return(1); -} - -static struct slot *alloc_slot_struct(void) -{ - struct slot *slot; - - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) - return (NULL); - memset(slot, 0, sizeof(struct slot)); - slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), - GFP_KERNEL); - if (!slot->hotplug_slot) { - kfree(slot); - return (NULL); - } - memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!slot->hotplug_slot->info) { - kfree(slot->hotplug_slot); - kfree(slot); - return (NULL); - } - memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); - slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!slot->hotplug_slot->name) { - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot); - kfree(slot); - return (NULL); - } - return (slot); + return (0); + if (strcmp(dn->name, "pci") == 0 && + !get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL)) + return (0); + return (1); } -static int setup_hotplug_slot_info(struct slot *slot) +static inline int is_vdevice_root(struct device_node *dn) { - rpaphp_get_power_status(slot, - &slot->hotplug_slot->info->power_status); - - rpaphp_get_adapter_status(slot, 1, - &slot->hotplug_slot->info->adapter_status); - - if (slot->hotplug_slot->info->adapter_status == NOT_VALID) { - dbg("%s: NOT_VALID: skip dn->full_name=%s\n", - __FUNCTION__, slot->dn->full_name); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - return (-1); - } - return (0); -} - -static int register_slot(struct slot *slot) -{ - int retval; - - retval = pci_hp_register(slot->hotplug_slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - rpaphp_release_slot(slot->hotplug_slot); - return (retval); - } - /* create symlink between slot->name and it's bus_id */ - dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__, - slot->bridge->slot_name, slot->name); - retval = sysfs_create_link(slot->hotplug_slot->kobj.parent, - &slot->hotplug_slot->kobj, - slot->bridge->slot_name); - if (retval) { - err("sysfs_create_link failed with error %d\n", retval); - rpaphp_release_slot(slot->hotplug_slot); - return (retval); - } - /* add slot to our internal list */ - dbg("%s adding slot[%s] to rpaphp_slot_list\n", - __FUNCTION__, slot->name); - - list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); - - info("Slot [%s] (bus_id=%s) registered\n", - slot->name, slot->bridge->slot_name); - return (0); + return !strcmp(dn->name, "vdevice"); } /************************************* * Add Hot Plug slot(s) to sysfs * ************************************/ -int rpaphp_add_slot(char *slot_name) +int rpaphp_add_slot(struct device_node *dn) { - struct slot *slot; - int retval = 0; - int i; - struct device_node *dn; - int *indexes, *names, *types, *power_domains; - char *name, *type; - - for (dn = find_all_nodes(); dn; dn = dn->next) { - - if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { - if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) - continue; - - dbg("%s : found device_node in OFDT full_name=%s, name=%s\n", - __FUNCTION__, dn->full_name, dn->name); - - name = (char *)&names[1]; - type = (char *)&types[1]; - - for (i = 0; i < indexes[0]; - i++, - name += (strlen(name) + 1), - type += (strlen(type) + 1)) { - - dbg("%s: name[%s] index[%x]\n", - __FUNCTION__, name, indexes[i+1]); - - if (slot_name && strcmp(slot_name, name)) - continue; - - if (rpaphp_validate_slot(name, indexes[i + 1])) { - dbg("%s: slot(%s, 0x%x) is invalid.\n", - __FUNCTION__, name, indexes[i+ 1]); - continue; - } - - slot = alloc_slot_struct(); - if (!slot) { - retval = -ENOMEM; - goto exit; - } - - slot->name = slot->hotplug_slot->name; - slot->index = indexes[i + 1]; - strcpy(slot->name, name); - slot->type = simple_strtoul(type, NULL, 10); - if (slot->type < 1 || slot->type > 16) - slot->type = 0; - - slot->power_domain = power_domains[i + 1]; - slot->magic = SLOT_MAGIC; - slot->hotplug_slot->private = slot; - slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; - slot->hotplug_slot->release = &rpaphp_release_slot; - slot->dn = dn; - - /* - * Initilize the slot info structure with some known - * good values. - */ - if (setup_hotplug_slot_info(slot)) - continue; - - slot->bridge = rpaphp_find_bridge_pdev(slot); - if (!slot->bridge && slot_name) { /* slot being added doesn't have pci_dev yet*/ - dbg("%s: no pci_dev for bridge dn %s\n", - __FUNCTION__, slot_name); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - continue; - } - - /* find slot's pci_dev if it's not empty*/ - if (slot->hotplug_slot->info->adapter_status == EMPTY) { - slot->state = EMPTY; /* slot is empty */ - slot->dev = NULL; - } else { /* slot is occupied */ - if(!(slot->dn->child)) { /* non-empty slot has to have child */ - err("%s: slot[%s]'s device_node doesn't have child for adapter\n", - __FUNCTION__, slot->name); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - continue; - - } - - slot->dev = rpaphp_find_adapter_pdev(slot); - if(slot->dev) { - slot->state = CONFIGURED; - pci_dev_get(slot->dev); - } else { - /* DLPAR add as opposed to - * boot time */ - slot->state = NOT_CONFIGURED; - } - } - dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", - __FUNCTION__, dn->full_name, slot->index, slot->name, - slot->power_domain, slot->type); - - retval = register_slot(slot); - if (retval) - goto exit; - - num_slots++; - - if (slot_name) - goto exit; - - }/* for indexes */ - }/* "pci" */ - }/* find_all_nodes */ -exit: + struct slot *slot; + int retval = 0; + int i; + int *indexes, *names, *types, *power_domains; + char *name, *type; + + dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); + + if (dn->parent && is_vdevice_root(dn->parent)) { + /* register a VIO device */ + retval = register_vio_slot(dn); + goto exit; + } + + /* register PCI devices */ + if (dn->name != 0 && strcmp(dn->name, "pci") == 0 && + is_php_dn(dn, &indexes, &names, &types, &power_domains)) { + + name = (char *) &names[1]; + type = (char *) &types[1]; + for (i = 0; i < indexes[0]; + i++, + name += (strlen(name) + 1), type += (strlen(type) + 1)) { + if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, + power_domains[i + 1]))) { + retval = -ENOMEM; + goto exit; + } + slot->type = simple_strtoul(type, NULL, 10); + if (slot->type < 1 || slot->type > 16) + slot->type = 0; + retval = register_pci_slot(slot); + + } /* for indexes */ + } /* end of PCI device_node */ + exit: dbg("%s - Exit: num_slots=%d rc[%d]\n", - __FUNCTION__, num_slots, retval); + __FUNCTION__, num_slots, retval); return retval; } @@ -785,31 +347,28 @@ * init_slots - initialize 'struct slot' structures for each slot * */ -static int init_slots (void) +static void init_slots(void) { - int retval = 0; + struct device_node *dn; - retval = rpaphp_add_slot(NULL); - - return retval; + for (dn = find_all_nodes(); dn; dn = dn->next) + rpaphp_add_slot(dn); } - -static int init_rpa (void) +static int init_rpa(void) { - int retval = 0; init_MUTEX(&rpaphp_sem); /* initialize internal data structure etc. */ - retval = init_slots(); + init_slots(); if (!num_slots) - retval = -ENODEV; + return -ENODEV; - return retval; + return 0; } -static void cleanup_slots (void) +static void cleanup_slots(void) { struct list_head *tmp, *n; struct slot *slot; @@ -817,125 +376,100 @@ /* * Unregister all of our slots with the pci_hotplug subsystem, * and free up all memory that we had allocated. - * memory will be freed in release_slot callback. + * memory will be freed in release_slot callback. */ - list_for_each_safe (tmp, n, &rpaphp_slot_head) { + list_for_each_safe(tmp, n, &rpaphp_slot_head) { + char *rm_link; + slot = list_entry(tmp, struct slot, rpaphp_slot_list); - sysfs_remove_link(slot->hotplug_slot->kobj.parent, - slot->bridge->slot_name); + if (slot->dev_type == PCI_DEV) + rm_link = pci_name(slot->bridge); + else + rm_link = strstr(slot->dn->full_name, "@"); + sysfs_remove_link(slot->hotplug_slot->kobj.parent, rm_link); list_del(&slot->rpaphp_slot_list); pci_hp_deregister(slot->hotplug_slot); } - return; } - static int __init rpaphp_init(void) { - int retval = 0; - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); /* read all the PRA info from the system */ - retval = init_rpa(); - - return retval; + return init_rpa(); } - static void __exit rpaphp_exit(void) { cleanup_slots(); } - static int enable_slot(struct hotplug_slot *hotplug_slot) { - int retval = 0, state; - + int retval = 0; struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); if (slot == NULL) return -ENODEV; if (slot->state == CONFIGURED) { - dbg("%s: %s is already enabled\n", - __FUNCTION__, slot->name); + dbg("%s: %s is already enabled\n", __FUNCTION__, slot->name); goto exit; } dbg("ENABLING SLOT %s\n", slot->name); - down(&rpaphp_sem); - - retval = rpaphp_get_sensor_state(slot->index, &state); - - if (retval) - goto exit; - - dbg("%s: sensor state[%d]\n", __FUNCTION__, state); - - /* if slot is not empty, enable the adapter */ - if (state == PRESENT) { - dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name); - - - slot->dev = rpaphp_config_adapter(slot); - if (slot->dev != NULL) { - slot->state = CONFIGURED; - - dbg("%s: adapter %s in slot[%s] has been configured\n", - __FUNCTION__, slot->dev->slot_name, - slot->name); - } else { - slot->state = NOT_CONFIGURED; - - dbg("%s: no pci_dev struct for adapter in slot[%s]\n", - __FUNCTION__, slot->name); - } - - } else if (state == EMPTY) { - dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name); - slot->state = EMPTY; - } else { - err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name); - slot->state = NOT_VALID; + switch (slot->dev_type) { + case PCI_DEV: + retval = rpaphp_enable_pci_slot(slot); + break; + case VIO_DEV: + retval = rpaphp_enable_vio_slot(slot); + break; + default: retval = -EINVAL; } - -exit: - if (slot->state != NOT_VALID) - rpaphp_set_attention_status(slot, LED_ON); - else - rpaphp_set_attention_status(slot, LED_ID); - up(&rpaphp_sem); - + exit: + dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; } static int disable_slot(struct hotplug_slot *hotplug_slot) { - int retval; + int retval; struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); if (slot == NULL) return -ENODEV; - dbg("DISABLING SLOT %s\n", slot->name); - - down(&rpaphp_sem); - - rpaphp_set_attention_status(slot, LED_ID); + dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name); - retval = rpaphp_unconfig_adapter(slot); - - rpaphp_set_attention_status(slot, LED_OFF); + if (slot->state == NOT_CONFIGURED) { + dbg("%s: %s is already disabled\n", __FUNCTION__, slot->name); + goto exit; + } + dbg("DISABLING SLOT %s\n", slot->name); + down(&rpaphp_sem); + switch (slot->dev_type) { + case PCI_DEV: + rpaphp_set_attention_status(slot, LED_ID); + retval = rpaphp_unconfig_pci_adapter(slot); + rpaphp_set_attention_status(slot, LED_OFF); + break; + case VIO_DEV: + retval = rpaphp_unconfig_vio_adapter(slot); + break; + default: + retval = -ENODEV; + } up(&rpaphp_sem); - + exit: + dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; } diff -Nru a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c --- a/drivers/pci/hotplug/rpaphp_pci.c Sat Apr 3 19:38:40 2004 +++ b/drivers/pci/hotplug/rpaphp_pci.c Sat Apr 3 19:38:40 2004 @@ -23,32 +23,35 @@ * */ #include -#include /* for pci_controller */ -#include "rpaphp.h" +#include +#include "../pci.h" /* for pci_add_new_bus */ +#include "rpaphp.h" struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn) { - struct pci_dev *retval_dev = NULL, *dev = NULL; - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if(!dev->bus) - continue; + struct pci_dev *retval_dev = NULL, *dev = NULL; + char bus_id[BUS_ID_SIZE]; - if (dev->devfn != dn->devfn) - continue; + sprintf(bus_id, "%04x:%02x:%02x.%d",dn->phb->global_number, + dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn)); - if (dn->phb->global_number == pci_domain_nr(dev->bus) && - dn->busno == dev->bus->number) { + dbg("Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s\n", + dn->full_name, bus_id); + + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (!strcmp(pci_name(dev), bus_id)) { retval_dev = dev; + dbg("rpaphp_find_pci_dev(): found dev=%p\n\n", dev); break; } } - return retval_dev; } +EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); + int rpaphp_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; @@ -63,13 +66,335 @@ if (err) { err("PCI: %s region %d of %s %s [%lx:%lx]\n", - root ? "Address space collision on" : - "No parent found for", - resource, dtype, pci_name(dev), res->start, res->end); + root ? "Address space collision on" : + "No parent found for", + resource, dtype, pci_name(dev), res->start, res->end); } - return err; } -EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); EXPORT_SYMBOL_GPL(rpaphp_claim_resource); + +static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot) +{ + return rpaphp_find_pci_dev(slot->dn); +} + +static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot) +{ + return rpaphp_find_pci_dev(slot->dn->child); +} + +static int rpaphp_get_sensor_state(struct slot *slot, int *state) +{ + int rc; + int setlevel; + + rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state); + + if (rc) { + if (rc == NEED_POWER || rc == PWR_ONLY) { + dbg("%s: slot must be power up to get sensor-state\n", + __FUNCTION__); + + /* some slots have to be powered up + * before get-sensor will succeed. + */ + rc = rtas_set_power_level(slot->power_domain, POWER_ON, + &setlevel); + if (rc) { + dbg("%s: power on slot[%s] failed rc=%d.\n", + __FUNCTION__, slot->name, rc); + } else { + rc = rtas_get_sensor(DR_ENTITY_SENSE, + slot->index, state); + } + } else if (rc == ERR_SENSE_USE) + info("%s: slot is unusable\n", __FUNCTION__); + else + err("%s failed to get sensor state\n", __FUNCTION__); + } + return rc; +} + +/* + * get_pci_adapter_status - get the status of a slot + * + * 0-- slot is empty + * 1-- adapter is configured + * 2-- adapter is not configured + * 3-- not valid + */ +int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) +{ + int state, rc; + *value = NOT_VALID; + + rc = rpaphp_get_sensor_state(slot, &state); + if (rc) + goto exit; + if (state == PRESENT) { + if (!is_init) + /* at run-time slot->state can be changed by */ + /* config/unconfig adapter */ + *value = slot->state; + else { + if (!slot->dn->child) + dbg("%s: %s is not valid OFDT node\n", + __FUNCTION__, slot->dn->full_name); + else if (rpaphp_find_pci_dev(slot->dn->child)) + *value = CONFIGURED; + else { + dbg("%s: can't find pdev of adapter in slot[%s]\n", __FUNCTION__, slot->name); + *value = NOT_CONFIGURED; + } + } + } else if (state == EMPTY) { + dbg("slot is empty\n"); + *value = state; + } + + exit: + return rc; +} + +/* Must be called before pci_bus_add_devices */ +static void rpaphp_fixup_new_pci_devices(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + /* + * Skip already-present devices (which are on the + * global device list.) + */ + if (list_empty(&dev->global_list)) { + int i; + + pcibios_fixup_device_resources(dev, bus); + pci_read_irq_line(dev); + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + if (r->parent || !r->start || !r->flags) + continue; + rpaphp_claim_resource(dev, i); + } + } + } +} + +static void rpaphp_pci_config_device(struct pci_bus *pci_bus, struct device_node *dn) +{ + int num; + + num = pci_scan_slot(pci_bus, PCI_DEVFN(PCI_SLOT(dn->devfn), 0)); + if (num) { + rpaphp_fixup_new_pci_devices(pci_bus); + pci_bus_add_devices(pci_bus); + } + return; +} + +static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn); + +/***************************************************************************** + rpaphp_pci_config_dn() will recursively configure all devices under the + given slot->dn and return the dn's pci_dev. + *****************************************************************************/ +static struct pci_dev *rpaphp_pci_config_dn(struct device_node *dn, struct pci_bus *bus) +{ + struct device_node *local; + struct pci_dev *dev; + + for (local = dn->child; local; local = local->sibling) { + rpaphp_pci_config_device(bus, local); + dev = rpaphp_find_pci_dev(local); + if (!rpaphp_pci_config_bridge(dev, local)) + return NULL; + } + + return dev; +} + +static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn) +{ + if (dev && dn->child) { /* dn is a PCI bridge node */ + struct pci_bus *child; + u8 sec_busno; + + /* get busno of downstream bus */ + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); + + /* add to children of PCI bridge dev->bus */ + child = pci_add_new_bus(dev->bus, dev, sec_busno); + if (!child) { + err("%s: could not add second bus\n", __FUNCTION__); + return 0; + } + sprintf(child->name, "PCI Bus #%02x", child->number); + /* Fixup subordinate bridge bases and resureces */ + pcibios_fixup_bus(child); + + /* may need do more stuff here */ + rpaphp_pci_config_dn(dn, dev->subordinate); + } + return 1; +} + +static struct pci_dev *rpaphp_config_pci_adapter(struct slot *slot) +{ + struct pci_bus *pci_bus; + struct pci_dev *dev = NULL; + + dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); + + if (slot->bridge) { + + pci_bus = slot->bridge->subordinate; + if (!pci_bus) { + err("%s: can't find bus structure\n", __FUNCTION__); + goto exit; + } + + dev = rpaphp_pci_config_dn(slot->dn, pci_bus); + eeh_add_device(dev); + } else { + /* slot is not enabled */ + err("slot doesn't have pci_dev structure\n"); + dev = NULL; + goto exit; + } + + exit: + dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev ? "found" : "not found"); + return dev; +} + +int rpaphp_unconfig_pci_adapter(struct slot *slot) +{ + int retval = 0; + + dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); + if (!slot->dev.pci_dev) { + info("%s: no card in slot[%s]\n", __FUNCTION__, slot->name); + + retval = -EINVAL; + goto exit; + } + /* remove the device from the pci core */ + eeh_remove_device(slot->dev.pci_dev); + pci_remove_bus_device(slot->dev.pci_dev); + + slot->state = NOT_CONFIGURED; + info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, + slot->name); +exit: + dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval); + return retval; +} + +static int setup_pci_hotplug_slot_info(struct slot *slot) +{ + dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", + __FUNCTION__); + rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status); + rpaphp_get_pci_adapter_status(slot, 1, + &slot->hotplug_slot->info-> + adapter_status); + if (slot->hotplug_slot->info->adapter_status == NOT_VALID) { + dbg("%s: NOT_VALID: skip dn->full_name=%s\n", + __FUNCTION__, slot->dn->full_name); + dealloc_slot_struct(slot); + return (-1); + } + return (0); +} + +static int setup_pci_slot(struct slot *slot) +{ + slot->bridge = rpaphp_find_bridge_pdev(slot); + if (!slot->bridge) { /* slot being added doesn't have pci_dev yet */ + dbg("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name); + dealloc_slot_struct(slot); + return 1; + } + + /* find slot's pci_dev if it's not empty */ + if (slot->hotplug_slot->info->adapter_status == EMPTY) { + slot->state = EMPTY; /* slot is empty */ + slot->dev.pci_dev = NULL; + } else { + /* slot is occupied */ + if (!(slot->dn->child)) { + /* non-empty slot has to have child */ + err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __FUNCTION__, slot->name); + dealloc_slot_struct(slot); + return 1; + } + slot->dev.pci_dev = rpaphp_find_adapter_pdev(slot); + if (slot->dev.pci_dev) { + slot->state = CONFIGURED; + + } else { + /* DLPAR add as opposed to + * boot time */ + slot->state = NOT_CONFIGURED; + } + } + return 0; +} + +int register_pci_slot(struct slot *slot) +{ + int rc = 1; + + slot->dev_type = PCI_DEV; + if (setup_pci_hotplug_slot_info(slot)) + goto exit_rc; + if (setup_pci_slot(slot)) + goto exit_rc; + rc = register_slot(slot); + exit_rc: + if (rc) + dealloc_slot_struct(slot); + return rc; +} + +int rpaphp_enable_pci_slot(struct slot *slot) +{ + int retval = 0, state; + + retval = rpaphp_get_sensor_state(slot, &state); + if (retval) + goto exit; + dbg("%s: sensor state[%d]\n", __FUNCTION__, state); + /* if slot is not empty, enable the adapter */ + if (state == PRESENT) { + dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name); + if ((slot->dev.pci_dev = + rpaphp_config_pci_adapter(slot)) != NULL) { + slot->state = CONFIGURED; + dbg("%s: PCI adapter %s in slot[%s] has been configured\n", + __FUNCTION__, pci_name(slot->dev.pci_dev), slot->name); + } else { + slot->state = NOT_CONFIGURED; + dbg("%s: no pci_dev struct for adapter in slot[%s]\n", + __FUNCTION__, slot->name); + } + } else if (state == EMPTY) { + dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name); + slot->state = EMPTY; + } else { + err("%s: slot[%s] is in invalid state\n", __FUNCTION__, + slot->name); + slot->state = NOT_VALID; + retval = -EINVAL; + } + exit: + if (slot->state != NOT_VALID) + rpaphp_set_attention_status(slot, LED_ON); + else + rpaphp_set_attention_status(slot, LED_ID); + dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); + return retval; +} diff -Nru a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/rpaphp_slot.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,188 @@ +/* + * RPA Virtual I/O device functions + * Copyright (C) 2004 Linda Xie + * + * 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. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to + * + */ +#include +#include +#include +#include +#include +#include "rpaphp.h" + +/* free up the memory user by a slot */ + +static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot? (struct slot *) hotplug_slot->private:NULL; + + if (slot == NULL) + return; + + dealloc_slot_struct(slot); +} + +void dealloc_slot_struct(struct slot *slot) +{ + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + return; +} + +struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, + int power_domain) +{ + struct slot *slot; + + dbg("Enter alloc_slot_struct(): dn->full_name=%s drc_index=0x%x drc_name=%s\n", + dn->full_name, drc_index, drc_name); + + slot = kmalloc(sizeof (struct slot), GFP_KERNEL); + if (!slot) + return (NULL); + memset(slot, 0, sizeof (struct slot)); + slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) { + kfree(slot); + return (NULL); + } + memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info), + GFP_KERNEL); + if (!slot->hotplug_slot->info) { + kfree(slot->hotplug_slot); + kfree(slot); + return (NULL); + } + memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); + if (!slot->hotplug_slot->name) { + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot); + kfree(slot); + return (NULL); + } + slot->name = slot->hotplug_slot->name; + slot->dn = dn; + slot->index = drc_index; + strcpy(slot->name, drc_name); + slot->power_domain = power_domain; + slot->magic = SLOT_MAGIC; + slot->hotplug_slot->private = slot; + slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; + slot->hotplug_slot->release = &rpaphp_release_slot; + dbg("Exit alloc_slot_struct(): slot->dn->full_name=%s drc_index=0x%x drc_name=%s\n", + slot->dn->full_name, slot->index, slot->name); + return (slot); +} + +int register_slot(struct slot *slot) +{ + int retval; + char *vio_uni_addr = NULL; + + dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", __FUNCTION__, slot->dn->full_name, slot->index, slot->name, slot->power_domain, slot->type); + + retval = pci_hp_register(slot->hotplug_slot); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + rpaphp_release_slot(slot->hotplug_slot); + return (retval); + } + switch (slot->dev_type) { + case PCI_DEV: + /* create symlink between slot->name and it's bus_id */ + + dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__, + pci_name(slot->bridge), slot->name); + + retval = sysfs_create_link(slot->hotplug_slot->kobj.parent, + &slot->hotplug_slot->kobj, + pci_name(slot->bridge)); + if (retval) { + err("sysfs_create_link failed with error %d\n", retval); + rpaphp_release_slot(slot->hotplug_slot); + return (retval); + } + break; + case VIO_DEV: + /* create symlink between slot->name and it's uni-address */ + vio_uni_addr = strchr(slot->dn->full_name, '@'); + if (!vio_uni_addr) + return (1); + dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__, + vio_uni_addr, slot->name); + retval = sysfs_create_link(slot->hotplug_slot->kobj.parent, + &slot->hotplug_slot->kobj, + vio_uni_addr); + if (retval) { + err("sysfs_create_link failed with error %d\n", retval); + rpaphp_release_slot(slot->hotplug_slot); + return (retval); + } + break; + default: + return (1); + } + + /* add slot to our internal list */ + dbg("%s adding slot[%s] to rpaphp_slot_list\n", + __FUNCTION__, slot->name); + + list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); + + if (vio_uni_addr) + info("Slot [%s](vio_uni_addr=%s) registered\n", + slot->name, vio_uni_addr); + else + info("Slot [%s](bus_id=%s) registered\n", + slot->name, pci_name(slot->bridge)); + num_slots++; + return (0); +} + +int rpaphp_get_power_status(struct slot *slot, u8 * value) +{ + int rc; + + rc = rtas_get_power_level(slot->power_domain, (int *) value); + if (rc) + err("failed to get power-level for slot(%s), rc=0x%x\n", + slot->name, rc); + + return rc; +} + +int rpaphp_set_attention_status(struct slot *slot, u8 status) +{ + int rc; + + /* status: LED_OFF or LED_ON */ + rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); + if (rc) + err("slot(%s) set attention-status(%d) failed! rc=0x%x\n", + slot->name, status, rc); + + return rc; +} diff -Nru a/drivers/pci/hotplug/rpaphp_vio.c b/drivers/pci/hotplug/rpaphp_vio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/rpaphp_vio.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,121 @@ +/* + * RPA Hot Plug Virtual I/O device functions + * Copyright (C) 2004 Linda Xie + * + * 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. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to + * + */ +#include +#include "rpaphp.h" + +/* + * get_vio_adapter_status - get the status of a slot + * + * status: + * + * 1-- adapter is configured + * 2-- adapter is not configured + * 3-- not valid + */ +inline int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 *value) +{ + *value = slot->state; + return 0; +} + +int rpaphp_unconfig_vio_adapter(struct slot *slot) +{ + int retval = 0; + + dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); + if (!slot->dev.vio_dev) { + info("%s: no VIOA in slot[%s]\n", __FUNCTION__, slot->name); + retval = -EINVAL; + goto exit; + } + /* remove the device from the vio core */ + vio_unregister_device(slot->dev.vio_dev); + slot->state = NOT_CONFIGURED; + info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name); +exit: + dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval); + return retval; +} + +static int setup_vio_hotplug_slot_info(struct slot *slot) +{ + slot->hotplug_slot->info->power_status = 1; + rpaphp_get_vio_adapter_status(slot, 1, + &slot->hotplug_slot->info->adapter_status); + return 0; +} + +int register_vio_slot(struct device_node *dn) +{ + u32 *index; + char *name; + int rc = 1; + struct slot *slot = NULL; + + index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL); + if (!index) + goto exit_rc; + name = get_property(dn, "ibm,loc-code", NULL); + if (!name) + goto exit_rc; + if (!(slot = alloc_slot_struct(dn, *index, name, 0))) { + rc = -ENOMEM; + goto exit_rc; + } + slot->dev_type = VIO_DEV; + slot->dev.vio_dev = vio_find_node(dn); + if (!slot->dev.vio_dev) + slot->dev.vio_dev = vio_register_device(dn); + if (slot->dev.vio_dev) + slot->state = CONFIGURED; + else + slot->state = NOT_CONFIGURED; + if (setup_vio_hotplug_slot_info(slot)) + goto exit_rc; + info("%s: registered VIO device[name=%s vio_dev=%p]\n", + __FUNCTION__, slot->name, slot->dev.vio_dev); + rc = register_slot(slot); +exit_rc: + if (rc && slot) + dealloc_slot_struct(slot); + return (rc); +} + +int rpaphp_enable_vio_slot(struct slot *slot) +{ + int retval = 0; + + if ((slot->dev.vio_dev = vio_register_device(slot->dn))) { + info("%s: VIO adapter %s in slot[%s] has been configured\n", + __FUNCTION__, slot->dn->name, slot->name); + slot->state = CONFIGURED; + } else { + info("%s: no vio_dev struct for adapter in slot[%s]\n", + __FUNCTION__, slot->name); + slot->state = NOT_CONFIGURED; + } + + return retval; +} diff -Nru a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c --- a/drivers/pci/hotplug/shpchp_pci.c Sat Apr 3 19:38:43 2004 +++ b/drivers/pci/hotplug/shpchp_pci.c Sat Apr 3 19:38:43 2004 @@ -101,7 +101,7 @@ */ int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) { -#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) +#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) int rc; u16 temp_word; struct pci_dev fakedev; diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pci/pci.c Sat Apr 3 19:38:42 2004 @@ -686,7 +686,7 @@ if (!pci_dma_supported(dev, mask)) return -EIO; - dev->consistent_dma_mask = mask; + dev->dev.coherent_dma_mask = mask; return 0; } diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c Sat Apr 3 19:38:54 2004 +++ b/drivers/pci/probe.c Sat Apr 3 19:38:54 2004 @@ -570,7 +570,6 @@ /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; - dev->consistent_dma_mask = 0xffffffff; if (pci_setup_device(dev) < 0) { kfree(dev); return NULL; @@ -582,6 +581,7 @@ pci_name_device(dev); dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = 0xffffffffull; return dev; } diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c Sat Apr 3 19:38:40 2004 +++ b/drivers/pci/quirks.c Sat Apr 3 19:38:40 2004 @@ -760,7 +760,7 @@ #define SIS_DETECT_REGISTER 0x40 -static void __init quirk_sis_503_smbus(struct pci_dev *dev) +static void __init quirk_sis_503(struct pci_dev *dev) { u8 reg; u16 devid; @@ -768,7 +768,7 @@ pci_read_config_byte(dev, SIS_DETECT_REGISTER, ®); pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg | (1 << 6)); pci_read_config_word(dev, PCI_DEVICE_ID, &devid); - if ((devid & 0xfff0) != 0x0960) { + if (((devid & 0xfff0) != 0x0960) && (devid != 0x0018)) { pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg); return; } @@ -905,12 +905,14 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503_smbus }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus }, diff -Nru a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c --- a/drivers/pci/setup-res.c Sat Apr 3 19:38:55 2004 +++ b/drivers/pci/setup-res.c Sat Apr 3 19:38:55 2004 @@ -94,13 +94,18 @@ pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; - struct resource *root = pci_find_parent_resource(dev, res); + struct resource *root = NULL; char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; int err; + if (res->flags & IORESOURCE_IO) + root = &ioport_resource; + if (res->flags & IORESOURCE_MEM) + root = &iomem_resource; + err = -EINVAL; if (root != NULL) - err = request_resource(root, res); + err = insert_resource(root, res); if (err) { printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n", diff -Nru a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig --- a/drivers/pcmcia/Kconfig Sat Apr 3 19:38:54 2004 +++ b/drivers/pcmcia/Kconfig Sat Apr 3 19:38:54 2004 @@ -26,6 +26,25 @@ To compile this driver as modules, choose M here: the modules will be called pcmcia_core and ds. +config PCMCIA_DEBUG + bool "Enable PCMCIA debugging" + depends on PCMCIA != n + help + Say Y here to enable PCMCIA subsystem debugging. You + will need to choose the debugging level either via the + kernel command line, or module options depending whether + you build the PCMCIA as modules. + + The kernel command line options are: + pcmcia_core.pc_debug=N + ds.pc_debug=N + sa11xx_core.pc_debug=N + + The module option is called pc_debug=N + + In all the above examples, N is the debugging verbosity + level. + config YENTA tristate "CardBus yenta-compatible bridge support" depends on PCMCIA && PCI diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile --- a/drivers/pcmcia/Makefile Sat Apr 3 19:38:55 2004 +++ b/drivers/pcmcia/Makefile Sat Apr 3 19:38:55 2004 @@ -2,6 +2,10 @@ # Makefile for the kernel pcmcia subsystem (c/o David Hinds) # +ifeq ($(CONFIG_PCMCIA_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif + obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o obj-$(CONFIG_YENTA) += yenta_socket.o diff -Nru a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c --- a/drivers/pcmcia/au1000_generic.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pcmcia/au1000_generic.c Sat Apr 3 19:38:44 2004 @@ -26,6 +26,7 @@ * */ #include +#include #include #include #include @@ -54,8 +55,17 @@ #include #include -#ifdef PCMCIA_DEBUG +#ifdef DEBUG static int pc_debug; + +module_param(pc_debug, int, 0644); + +#define debug(lvl,fmt) do { \ + if (pc_debug > (lvl)) \ + printk(KERN_DEBUG fmt); \ +} while (0) +#else +#define debug(lvl,fmt) do { } while (0) #endif MODULE_LICENSE("GPL"); @@ -209,7 +219,7 @@ */ au1000_pcmcia_poll_event(0); - DEBUG(1, "au1000: initialization complete\n"); + debug(1, "au1000: initialization complete\n"); return 0; } /* au1000_pcmcia_driver_init() */ @@ -228,7 +238,7 @@ if (pcmcia_socket[i].virt_io) iounmap((void *)pcmcia_socket[i].virt_io); } - DEBUG(1, "au1000: shutdown complete\n"); + debug(1, "au1000: shutdown complete\n"); } module_exit(au1000_pcmcia_driver_shutdown); @@ -249,14 +259,14 @@ unsigned int events=0; if(state->detect!=prev_state->detect){ - DEBUG(2, "%s(): card detect value %u\n", + debug(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect); events |= mask&SS_DETECT; } if(state->ready!=prev_state->ready){ - DEBUG(2, "%s(): card ready value %u\n", + debug(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready); events |= mask&((flags&SS_IOCARD)?0:SS_READY); } @@ -429,7 +439,7 @@ *status|=state.vs_Xv?SS_XVCARD:0; - DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n", + debug(2, "\tstatus: %s%s%s%s%s%s%s%s\n", (*status&SS_DETECT)?"DETECT ":"", (*status&SS_READY)?"READY ":"", (*status&SS_BATDEAD)?"BATDEAD ":"", @@ -457,7 +467,7 @@ { struct pcmcia_configure configure; - DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" + debug(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" "\tVcc %d Vpp %d irq %d\n", (state->csc_mask==0)?"":"", (state->csc_mask&SS_DETECT)?"DETECT ":"", @@ -494,7 +504,7 @@ static int au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) { - DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock); + debug(1, "au1000_pcmcia_get_io_map: sock %d\n", sock); if(map->map>=MAX_IO_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); @@ -531,7 +541,7 @@ map->start=pcmcia_socket[sock].virt_io; map->stop=map->start+(map->stop-start); pcmcia_socket[sock].io_map[map->map]=*map; - DEBUG(3, "set_io_map %d start %x stop %x\n", + debug(3, "set_io_map %d start %x stop %x\n", map->map, map->start, map->stop); return 0; @@ -595,7 +605,7 @@ map->sys_stop=map->sys_start+(map->sys_stop-start); pcmcia_socket[sock].mem_map[map->map]=*map; spin_unlock_irqrestore(&pcmcia_lock, flags); - DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n", + debug(3, "set_mem_map %d start %x stop %x card_start %x\n", map->map, map->sys_start, map->sys_stop, map->card_start); return 0; diff -Nru a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c --- a/drivers/pcmcia/au1000_pb1x00.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pcmcia/au1000_pb1x00.c Sat Apr 3 19:38:42 2004 @@ -48,6 +48,8 @@ #include #include +#define debug(fmt, arg...) do { } while (0) + #ifdef CONFIG_MIPS_PB1000 #include #define PCMCIA_IRQ AU1000_GPIO_15 @@ -213,7 +215,7 @@ } pcr &= ~PCR_SLOT_0_RST; - DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", + debug("Vcc %dV Vpp %dV, pcr %x\n", configure->vcc, configure->vpp, pcr); switch(configure->vcc){ case 0: /* Vcc 0 */ @@ -324,7 +326,7 @@ pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; - DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x, reset %d\n", + debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n", configure->vcc, configure->vpp, pcr, configure->reset); diff -Nru a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c --- a/drivers/pcmcia/bulkmem.c Sat Apr 3 19:38:57 2004 +++ b/drivers/pcmcia/bulkmem.c Sat Apr 3 19:38:57 2004 @@ -48,6 +48,8 @@ #include #include "cs_internal.h" +static void retry_erase_list(erase_busy_t *list, u_int cause); + /*====================================================================== This function handles submitting an MTD request, and retrying @@ -108,18 +110,18 @@ ======================================================================*/ -static void insert_queue(erase_busy_t *head, erase_busy_t *entry) +static void insert_queue(struct pcmcia_socket *s, erase_busy_t *head, erase_busy_t *entry) { - DEBUG(2, "cs: adding 0x%p to queue 0x%p\n", entry, head); + cs_dbg(s, 2, "adding 0x%p to queue 0x%p\n", entry, head); entry->next = head; entry->prev = head->prev; head->prev->next = entry; head->prev = entry; } -static void remove_queue(erase_busy_t *entry) +static void remove_queue(struct pcmcia_socket *s, erase_busy_t *entry) { - DEBUG(2, "cs: unqueueing 0x%p\n", entry); + cs_dbg(s, 2, "unqueueing 0x%p\n", entry); entry->next->prev = entry->prev; entry->prev->next = entry->next; } @@ -132,34 +134,35 @@ struct pcmcia_socket *s; int ret; - DEBUG(2, "cs: trying erase request 0x%p...\n", busy); + mtd = erase->Handle->mtd; + s = SOCKET(mtd); + + cs_dbg(s, 2, "trying erase request 0x%p...\n", busy); if (busy->next) - remove_queue(busy); + remove_queue(s, busy); req.Function = MTD_REQ_ERASE | cause; req.TransferLength = erase->Size; req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset; req.MediaID = erase->Handle->MediaID; - mtd = erase->Handle->mtd; - s = SOCKET(mtd); mtd->event_callback_args.mtdrequest = &req; ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW); if (ret == CS_BUSY) { - DEBUG(2, " Status = %d, requeueing.\n", req.Status); + cs_dbg(s, 2, " Status = %d, requeueing.\n", req.Status); switch (req.Status) { case MTD_WAITREQ: case MTD_WAITPOWER: - insert_queue(&mtd->erase_busy, busy); + insert_queue(s, &mtd->erase_busy, busy); break; case MTD_WAITTIMER: case MTD_WAITRDY: if (req.Status == MTD_WAITRDY) - insert_queue(&s->erase_busy, busy); + insert_queue(s, &s->erase_busy, busy); mod_timer(&busy->timeout, jiffies + req.Timeout*HZ/1000); break; } } else { /* update erase queue status */ - DEBUG(2, " Ret = %d\n", ret); + cs_dbg(s, 2, " Ret = %d\n", ret); switch (ret) { case CS_SUCCESS: erase->State = ERASE_PASSED; break; @@ -183,11 +186,11 @@ } } /* retry_erase */ -void retry_erase_list(erase_busy_t *list, u_int cause) +static void retry_erase_list(erase_busy_t *list, u_int cause) { erase_busy_t tmp = *list; - DEBUG(2, "cs: rescanning erase queue list 0x%p\n", list); + cs_dbg(SOCKET(list->client), 2, "rescanning erase queue list 0x%p\n", list); if (list->next == list) return; /* First, truncate the original list */ @@ -204,8 +207,9 @@ static void handle_erase_timeout(u_long arg) { - DEBUG(0, "cs: erase timeout for entry 0x%lx\n", arg); - retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT); + erase_busy_t *busy = (erase_busy_t *)arg; + cs_dbg(SOCKET(busy->client), 0, "erase timeout for entry 0x%lx\n", arg); + retry_erase(busy, MTD_REQ_TIMEOUT); } static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) @@ -333,8 +337,8 @@ cistpl_device_geo_t geo; memory_handle_t r; - DEBUG(1, "cs: setup_regions(0x%p, %d, 0x%p)\n", - handle, attr, list); + cs_dbg(SOCKET(handle), 1, "setup_regions(0x%p, %d, 0x%p)\n", + handle, attr, list); code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE; if (read_tuple(handle, code, &device) != CS_SUCCESS) @@ -342,17 +346,13 @@ code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C; has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS); if (has_jedec && (device.ndev != jedec.nid)) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n"); -#endif + cs_dbg(SOCKET(handle), 0, "Device info does not match JEDEC info.\n"); has_jedec = 0; } code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO; has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS); if (has_geo && (device.ndev != geo.ngeo)) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n"); -#endif + cs_dbg(SOCKET(handle), 0, "Device info does not match geometry tuple.\n"); has_geo = 0; } @@ -458,7 +458,7 @@ list = s->a_region; else list = s->c_region; - DEBUG(1, "cs: register_mtd(0x%p, '%s', 0x%x)\n", + cs_dbg(s, 1, "register_mtd(0x%p, '%s', 0x%x)\n", handle, handle->dev_info, reg->Offset); while (list) { if (list->info.CardOffset == reg->Offset) break; @@ -548,8 +548,8 @@ } if (region && region->mtd) { *mh = region; - DEBUG(1, "cs: open_memory(0x%p, 0x%x) = 0x%p\n", - handle, open->Offset, region); + cs_dbg(s, 1, "open_memory(0x%p, 0x%x) = 0x%p\n", + handle, open->Offset, region); return CS_SUCCESS; } else return CS_BAD_OFFSET; @@ -565,7 +565,7 @@ int pcmcia_close_memory(memory_handle_t handle) { - DEBUG(1, "cs: close_memory(0x%p)\n", handle); + cs_dbg(SOCKET(handle->mtd), 1, "cs: close_memory(0x%p)\n", handle); if (CHECK_REGION(handle)) return CS_BAD_HANDLE; return CS_SUCCESS; diff -Nru a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c --- a/drivers/pcmcia/cardbus.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pcmcia/cardbus.c Sat Apr 3 19:38:42 2004 @@ -58,10 +58,6 @@ #include #include "cs_internal.h" -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -#endif - /*====================================================================*/ #define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) @@ -119,7 +115,7 @@ static void cb_release_cis_mem(struct pcmcia_socket * s) { if (s->cb_cis_virt) { - DEBUG(1, "cs: cb_release_cis_mem()\n"); + cs_dbg(s, 1, "cb_release_cis_mem()\n"); iounmap(s->cb_cis_virt); s->cb_cis_virt = NULL; s->cb_cis_res = 0; @@ -160,7 +156,7 @@ struct pci_dev *dev; struct resource *res; - DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); + cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); dev = pci_find_slot(s->cb_dev->subordinate->number, 0); if (!dev) diff -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c --- a/drivers/pcmcia/cistpl.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pcmcia/cistpl.c Sat Apr 3 19:38:42 2004 @@ -143,7 +143,7 @@ { u_char *sys, *end, *buf = ptr; - DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); + cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -195,7 +195,7 @@ addr = 0; } } - DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", + cs_dbg(s, 3, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", *(u_char *)(ptr+0), *(u_char *)(ptr+1), *(u_char *)(ptr+2), *(u_char *)(ptr+3)); return 0; @@ -206,7 +206,7 @@ { u_char *sys, *end, *buf = ptr; - DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); + cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -578,8 +578,7 @@ ofs += link[1] + 2; } if (i == MAX_TUPLES) { - DEBUG(1, "cs: overrun in pcmcia_get_next_tuple for socket %d\n", - handle->Socket); + cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n"); return CS_NO_MORE_ITEMS; } diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Sat Apr 3 19:38:42 2004 +++ b/drivers/pcmcia/cs.c Sat Apr 3 19:38:42 2004 @@ -32,6 +32,7 @@ ======================================================================*/ #include +#include #include #include #include @@ -110,12 +111,17 @@ /* Access speed for IO windows */ INT_MODULE_PARM(io_speed, 0); /* ns */ -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -static const char *version = -"cs.c 1.279 2001/10/13 00:08:28 (David Hinds)"; +#ifdef DEBUG +static int pc_debug; + +module_param(pc_debug, int, 0644); + +int cs_debug_level(int level) +{ + return pc_debug > level; +} #endif - + /*====================================================================*/ socket_state_t dead_socket = { @@ -127,103 +133,6 @@ LIST_HEAD(pcmcia_socket_list); DECLARE_RWSEM(pcmcia_socket_list_rwsem); -/*====================================================================*/ - -/* String tables for error messages */ - -typedef struct lookup_t { - int key; - char *msg; -} lookup_t; - -static const lookup_t error_table[] = { - { CS_SUCCESS, "Operation succeeded" }, - { CS_BAD_ADAPTER, "Bad adapter" }, - { CS_BAD_ATTRIBUTE, "Bad attribute", }, - { CS_BAD_BASE, "Bad base address" }, - { CS_BAD_EDC, "Bad EDC" }, - { CS_BAD_IRQ, "Bad IRQ" }, - { CS_BAD_OFFSET, "Bad offset" }, - { CS_BAD_PAGE, "Bad page number" }, - { CS_READ_FAILURE, "Read failure" }, - { CS_BAD_SIZE, "Bad size" }, - { CS_BAD_SOCKET, "Bad socket" }, - { CS_BAD_TYPE, "Bad type" }, - { CS_BAD_VCC, "Bad Vcc" }, - { CS_BAD_VPP, "Bad Vpp" }, - { CS_BAD_WINDOW, "Bad window" }, - { CS_WRITE_FAILURE, "Write failure" }, - { CS_NO_CARD, "No card present" }, - { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, - { CS_UNSUPPORTED_MODE, "Unsupported mode" }, - { CS_BAD_SPEED, "Bad speed" }, - { CS_BUSY, "Resource busy" }, - { CS_GENERAL_FAILURE, "General failure" }, - { CS_WRITE_PROTECTED, "Write protected" }, - { CS_BAD_ARG_LENGTH, "Bad argument length" }, - { CS_BAD_ARGS, "Bad arguments" }, - { CS_CONFIGURATION_LOCKED, "Configuration locked" }, - { CS_IN_USE, "Resource in use" }, - { CS_NO_MORE_ITEMS, "No more items" }, - { CS_OUT_OF_RESOURCE, "Out of resource" }, - { CS_BAD_HANDLE, "Bad handle" }, - { CS_BAD_TUPLE, "Bad CIS tuple" } -}; -#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) - -static const lookup_t service_table[] = { - { AccessConfigurationRegister, "AccessConfigurationRegister" }, - { AddSocketServices, "AddSocketServices" }, - { AdjustResourceInfo, "AdjustResourceInfo" }, - { CheckEraseQueue, "CheckEraseQueue" }, - { CloseMemory, "CloseMemory" }, - { DeregisterClient, "DeregisterClient" }, - { DeregisterEraseQueue, "DeregisterEraseQueue" }, - { GetCardServicesInfo, "GetCardServicesInfo" }, - { GetClientInfo, "GetClientInfo" }, - { GetConfigurationInfo, "GetConfigurationInfo" }, - { GetEventMask, "GetEventMask" }, - { GetFirstClient, "GetFirstClient" }, - { GetFirstRegion, "GetFirstRegion" }, - { GetFirstTuple, "GetFirstTuple" }, - { GetNextClient, "GetNextClient" }, - { GetNextRegion, "GetNextRegion" }, - { GetNextTuple, "GetNextTuple" }, - { GetStatus, "GetStatus" }, - { GetTupleData, "GetTupleData" }, - { MapMemPage, "MapMemPage" }, - { ModifyConfiguration, "ModifyConfiguration" }, - { ModifyWindow, "ModifyWindow" }, - { OpenMemory, "OpenMemory" }, - { ParseTuple, "ParseTuple" }, - { ReadMemory, "ReadMemory" }, - { RegisterClient, "RegisterClient" }, - { RegisterEraseQueue, "RegisterEraseQueue" }, - { RegisterMTD, "RegisterMTD" }, - { ReleaseConfiguration, "ReleaseConfiguration" }, - { ReleaseIO, "ReleaseIO" }, - { ReleaseIRQ, "ReleaseIRQ" }, - { ReleaseWindow, "ReleaseWindow" }, - { RequestConfiguration, "RequestConfiguration" }, - { RequestIO, "RequestIO" }, - { RequestIRQ, "RequestIRQ" }, - { RequestSocketMask, "RequestSocketMask" }, - { RequestWindow, "RequestWindow" }, - { ResetCard, "ResetCard" }, - { SetEventMask, "SetEventMask" }, - { ValidateCIS, "ValidateCIS" }, - { WriteMemory, "WriteMemory" }, - { BindDevice, "BindDevice" }, - { BindMTD, "BindMTD" }, - { ReportError, "ReportError" }, - { SuspendCard, "SuspendCard" }, - { ResumeCard, "ResumeCard" }, - { EjectCard, "EjectCard" }, - { InsertCard, "InsertCard" }, - { ReplaceCIS, "ReplaceCIS" } -}; -#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t)) - /*==================================================================== @@ -306,7 +215,7 @@ if (!socket || !socket->ops || !socket->dev.dev) return -EINVAL; - DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ops); + cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); /* try to obtain a socket number [yes, it gets ugly if we * register more than 2^sizeof(unsigned int) pcmcia @@ -377,7 +286,7 @@ if (!socket) return; - DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ops); + cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); if (socket->thread) { init_completion(&socket->thread_done); @@ -443,10 +352,9 @@ { client_t **c; - DEBUG(1, "cs: shutdown_socket(%p)\n", s); + cs_dbg(s, 1, "shutdown_socket\n"); /* Blank out the socket state */ - s->state &= SOCKET_PRESENT|SOCKET_INUSE; s->socket = dead_socket; s->ops->init(s); s->ops->set_socket(s, &s->socket); @@ -499,8 +407,8 @@ { client_t *client = s->clients; int ret; - DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n", - s->sock, event, priority); + cs_dbg(s, 1, "send_event(event %d, pri %d)\n", + event, priority); ret = 0; if (s->state & SOCKET_CARDBUS) return 0; @@ -516,26 +424,14 @@ return ret; } /* send_event */ -static void pcmcia_error(struct pcmcia_socket *skt, const char *fmt, ...) -{ - static char buf[128]; - va_list ap; - int len; - - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - buf[len] = '\0'; - - printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf); -} - #define cs_to_timeout(cs) (((cs) * HZ + 99) / 100) static void socket_remove_drivers(struct pcmcia_socket *skt) { client_t *client; + cs_dbg(skt, 4, "remove_drivers\n"); + send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); for (client = skt->clients; client; client = client->next) @@ -545,10 +441,13 @@ static void socket_shutdown(struct pcmcia_socket *skt) { + cs_dbg(skt, 4, "shutdown\n"); + socket_remove_drivers(skt); + skt->state &= SOCKET_INUSE|SOCKET_PRESENT; set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(cs_to_timeout(shutdown_delay)); - skt->state &= ~SOCKET_PRESENT; + skt->state &= SOCKET_INUSE; shutdown_socket(skt); } @@ -556,6 +455,8 @@ { int status, i; + cs_dbg(skt, 4, "reset\n"); + skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET; skt->ops->set_socket(skt, &skt->socket); udelay((long)reset_time); @@ -578,7 +479,7 @@ schedule_timeout(cs_to_timeout(unreset_check)); } - pcmcia_error(skt, "time out after reset.\n"); + cs_err(skt, "time out after reset.\n"); return CS_GENERAL_FAILURE; } @@ -586,6 +487,8 @@ { int status, i; + cs_dbg(skt, 4, "setup\n"); + skt->ops->get_status(skt, &status); if (!(status & SS_DETECT)) return CS_NO_CARD; @@ -606,14 +509,14 @@ } if (status & SS_PENDING) { - pcmcia_error(skt, "voltage interrogation timed out.\n"); + cs_err(skt, "voltage interrogation timed out.\n"); return CS_GENERAL_FAILURE; } if (status & SS_CARDBUS) { skt->state |= SOCKET_CARDBUS; #ifndef CONFIG_CARDBUS - pcmcia_error(skt, "cardbus cards are not supported.\n"); + cs_err(skt, "cardbus cards are not supported.\n"); return CS_BAD_TYPE; #endif } @@ -626,7 +529,7 @@ else if (!(status & SS_XVCARD)) skt->socket.Vcc = skt->socket.Vpp = 50; else { - pcmcia_error(skt, "unsupported voltage key.\n"); + cs_err(skt, "unsupported voltage key.\n"); return CS_BAD_TYPE; } skt->socket.flags = 0; @@ -640,7 +543,7 @@ skt->ops->get_status(skt, &status); if (!(status & SS_POWERON)) { - pcmcia_error(skt, "unable to apply power.\n"); + cs_err(skt, "unable to apply power.\n"); return CS_BAD_TYPE; } @@ -655,6 +558,8 @@ { int ret; + cs_dbg(skt, 4, "insert\n"); + if (!cs_socket_get(skt)) return CS_NO_CARD; @@ -667,6 +572,8 @@ skt->state |= SOCKET_CARDBUS_CONFIG; } #endif + cs_dbg(skt, 4, "insert done\n"); + send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); } else { socket_shutdown(skt); @@ -832,6 +739,7 @@ */ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) { + cs_dbg(s, 4, "parse_events: events %08x\n", events); if (s->thread) { spin_lock(&s->thread_lock); s->thread_events |= events; @@ -857,15 +765,15 @@ align = (*base) ? (lines ? 1<features & SS_CAP_STATIC_MAP) && s->io_offset) { @@ -979,77 +887,6 @@ return CS_SUCCESS; } /* access_configuration_register */ -/*====================================================================== - - Bind_device() associates a device driver with a particular socket. - It is normally called by Driver Services after it has identified - a newly inserted card. An instance of that driver will then be - eligible to register as a client of this socket. - -======================================================================*/ - -int pcmcia_bind_device(bind_req_t *req) -{ - client_t *client; - struct pcmcia_socket *s; - - s = req->Socket; - if (!s) - return CS_BAD_SOCKET; - - client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL); - if (!client) return CS_OUT_OF_RESOURCE; - memset(client, '\0', sizeof(client_t)); - client->client_magic = CLIENT_MAGIC; - strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); - client->Socket = s; - client->Function = req->Function; - client->state = CLIENT_UNBOUND; - client->erase_busy.next = &client->erase_busy; - client->erase_busy.prev = &client->erase_busy; - init_waitqueue_head(&client->mtd_req); - client->next = s->clients; - s->clients = client; - DEBUG(1, "cs: bind_device(): client 0x%p, sock %p, dev %s\n", - client, client->Socket, client->dev_info); - return CS_SUCCESS; -} /* bind_device */ - -/*====================================================================== - - Bind_mtd() associates a device driver with a particular memory - region. It is normally called by Driver Services after it has - identified a memory device type. An instance of the corresponding - driver will then be able to register to control this region. - -======================================================================*/ - -int pcmcia_bind_mtd(mtd_bind_t *req) -{ - struct pcmcia_socket *s; - memory_handle_t region; - - s = req->Socket; - if (!s) - return CS_BAD_SOCKET; - - if (req->Attributes & REGION_TYPE_AM) - region = s->a_region; - else - region = s->c_region; - - while (region) { - if (region->info.CardOffset == req->CardOffset) break; - region = region->info.next; - } - if (!region || (region->mtd != NULL)) - return CS_BAD_OFFSET; - strlcpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN); - - DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n", - req->Attributes, req->CardOffset, (char *)req->dev_info); - return CS_SUCCESS; -} /* bind_mtd */ /*====================================================================*/ @@ -1061,9 +898,12 @@ u_long flags; int i; - DEBUG(1, "cs: deregister_client(%p)\n", handle); if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; + + s = SOCKET(handle); + cs_dbg(s, 1, "deregister_client(%p)\n", handle); + if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) return CS_IN_USE; @@ -1072,7 +912,6 @@ return CS_IN_USE; /* Disconnect all MTD links */ - s = SOCKET(handle); if (handle->mtd_count) { for (region = s->a_region; region; region = region->info.next) if (region->mtd == handle) region->mtd = NULL; @@ -1543,8 +1382,8 @@ memset(s->config, 0, sizeof(config_t) * s->functions); } - DEBUG(1, "cs: register_client(): client 0x%p, sock %p, dev %s\n", - client, client->Socket, client->dev_info); + cs_dbg(s, 1, "register_client(): client 0x%p, dev %s\n", + client, client->dev_info); if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); @@ -2077,8 +1916,8 @@ if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; - DEBUG(1, "cs: resetting socket %p\n", handle->Socket); skt = SOCKET(handle); + cs_dbg(skt, 1, "resetting socket\n"); down(&skt->skt_sem); do { @@ -2119,15 +1958,11 @@ ======================================================================*/ -int pcmcia_suspend_card(client_handle_t handle, client_req_t *req) +int pcmcia_suspend_card(struct pcmcia_socket *skt) { - struct pcmcia_socket *skt; int ret; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - DEBUG(1, "cs: suspending socket %p\n", handle->Socket); - skt = SOCKET(handle); + cs_dbg(skt, 1, "suspending socket\n"); down(&skt->skt_sem); do { @@ -2146,15 +1981,11 @@ return ret; } /* suspend_card */ -int pcmcia_resume_card(client_handle_t handle, client_req_t *req) +int pcmcia_resume_card(struct pcmcia_socket *skt) { - struct pcmcia_socket *skt; int ret; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - DEBUG(1, "cs: waking up socket %p\n", handle->Socket); - skt = SOCKET(handle); + cs_dbg(skt, 1, "waking up socket\n"); down(&skt->skt_sem); do { @@ -2179,15 +2010,11 @@ ======================================================================*/ -int pcmcia_eject_card(client_handle_t handle, client_req_t *req) +int pcmcia_eject_card(struct pcmcia_socket *skt) { - struct pcmcia_socket *skt; int ret; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - DEBUG(1, "cs: user eject request on socket %p\n", handle->Socket); - skt = SOCKET(handle); + cs_dbg(skt, 1, "user eject request\n"); down(&skt->skt_sem); do { @@ -2208,15 +2035,11 @@ return ret; } /* eject_card */ -int pcmcia_insert_card(client_handle_t handle, client_req_t *req) +int pcmcia_insert_card(struct pcmcia_socket *skt) { - struct pcmcia_socket *skt; int ret; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - DEBUG(1, "cs: user insert request on socket %p\n", handle->Socket); - skt = SOCKET(handle); + cs_dbg(skt, 1, "user insert request\n"); down(&skt->skt_sem); do { @@ -2260,35 +2083,6 @@ return CS_SUCCESS; } /* set_event_mask */ -/*====================================================================*/ - -int pcmcia_report_error(client_handle_t handle, error_info_t *err) -{ - int i; - char *serv; - - if (CHECK_HANDLE(handle)) - printk(KERN_NOTICE); - else - printk(KERN_NOTICE "%s: ", handle->dev_info); - - for (i = 0; i < SERVICE_COUNT; i++) - if (service_table[i].key == err->func) break; - if (i < SERVICE_COUNT) - serv = service_table[i].msg; - else - serv = "Unknown service number"; - - for (i = 0; i < ERROR_COUNT; i++) - if (error_table[i].key == err->retcode) break; - if (i < ERROR_COUNT) - printk("%s: %s\n", serv, error_table[i].msg); - else - printk("%s: Unknown error code %#x\n", serv, err->retcode); - - return CS_SUCCESS; -} /* report_error */ - /*====================================================================== OS-specific module glue goes here @@ -2297,8 +2091,6 @@ /* in alpha order */ EXPORT_SYMBOL(pcmcia_access_configuration_register); EXPORT_SYMBOL(pcmcia_adjust_resource_info); -EXPORT_SYMBOL(pcmcia_bind_device); -EXPORT_SYMBOL(pcmcia_bind_mtd); EXPORT_SYMBOL(pcmcia_check_erase_queue); EXPORT_SYMBOL(pcmcia_close_memory); EXPORT_SYMBOL(pcmcia_copy_memory); @@ -2333,7 +2125,6 @@ EXPORT_SYMBOL(pcmcia_release_irq); EXPORT_SYMBOL(pcmcia_release_window); EXPORT_SYMBOL(pcmcia_replace_cis); -EXPORT_SYMBOL(pcmcia_report_error); EXPORT_SYMBOL(pcmcia_request_configuration); EXPORT_SYMBOL(pcmcia_request_io); EXPORT_SYMBOL(pcmcia_request_irq); @@ -2360,7 +2151,6 @@ { printk(KERN_INFO "%s\n", release); printk(KERN_INFO " %s\n", options); - DEBUG(0, "%s\n", version); class_register(&pcmcia_socket_class); return 0; diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h --- a/drivers/pcmcia/cs_internal.h Sat Apr 3 19:38:57 2004 +++ b/drivers/pcmcia/cs_internal.h Sat Apr 3 19:38:57 2004 @@ -167,7 +167,6 @@ int read_tuple(client_handle_t handle, cisdata_t code, void *parse); /* In bulkmem.c */ -void retry_erase_list(struct erase_busy_t *list, u_int cause); int get_first_region(client_handle_t handle, region_info_t *rgn); int get_next_region(client_handle_t handle, region_info_t *rgn); int register_mtd(client_handle_t handle, mtd_reg_t *reg); @@ -194,11 +193,22 @@ extern struct rw_semaphore pcmcia_socket_list_rwsem; extern struct list_head pcmcia_socket_list; -#ifdef PCMCIA_DEBUG -extern int pc_debug; -#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0) +#define cs_socket_name(skt) ((skt)->dev.class_id) + +#ifdef DEBUG +extern int cs_debug_level(int); + +#define cs_dbg(skt, lvl, fmt, arg...) do { \ + if (cs_debug_level(lvl)) \ + printk(KERN_DEBUG "cs: %s: " fmt, \ + cs_socket_name(skt) , ## arg); \ +} while (0) + #else -#define DEBUG(n, args...) do { } while (0) +#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0) #endif + +#define cs_err(skt, fmt, arg...) \ + printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg) #endif /* _LINUX_CS_INTERNAL_H */ diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c --- a/drivers/pcmcia/ds.c Sat Apr 3 19:38:54 2004 +++ b/drivers/pcmcia/ds.c Sat Apr 3 19:38:54 2004 @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include +#define IN_CARD_SERVICES #include #include #include @@ -61,6 +63,8 @@ #include #include +#include "cs_internal.h" + /*====================================================================*/ /* Module parameters */ @@ -69,13 +73,17 @@ MODULE_DESCRIPTION("PCMCIA Driver Services"); MODULE_LICENSE("Dual MPL/GPL"); -#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") +#ifdef DEBUG +static int pc_debug; + +module_param(pc_debug, int, 0644); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#define ds_dbg(lvl, fmt, arg...) do { \ + if (pc_debug > (lvl)) \ + printk(KERN_DEBUG "ds: " fmt , ## arg); \ +} while (0) #else -#define DEBUG(n, args...) +#define ds_dbg(lvl, fmt, arg...) do { } while (0) #endif /*====================================================================*/ @@ -113,10 +121,10 @@ struct pcmcia_socket *parent; }; -#define SOCKET_PRESENT 0x01 -#define SOCKET_BUSY 0x02 -#define SOCKET_REMOVAL_PENDING 0x10 -#define SOCKET_DEAD 0x80 +#define DS_SOCKET_PRESENT 0x01 +#define DS_SOCKET_BUSY 0x02 +#define DS_SOCKET_REMOVAL_PENDING 0x10 +#define DS_SOCKET_DEAD 0x80 /*====================================================================*/ @@ -129,6 +137,214 @@ /*====================================================================*/ +/* code which was in cs.c before */ + +/*====================================================================== + + Bind_device() associates a device driver with a particular socket. + It is normally called by Driver Services after it has identified + a newly inserted card. An instance of that driver will then be + eligible to register as a client of this socket. + +======================================================================*/ + +static int pcmcia_bind_device(bind_req_t *req) +{ + client_t *client; + struct pcmcia_socket *s; + + s = req->Socket; + if (!s) + return CS_BAD_SOCKET; + + client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL); + if (!client) + return CS_OUT_OF_RESOURCE; + memset(client, '\0', sizeof(client_t)); + client->client_magic = CLIENT_MAGIC; + strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); + client->Socket = s; + client->Function = req->Function; + client->state = CLIENT_UNBOUND; + client->erase_busy.next = &client->erase_busy; + client->erase_busy.prev = &client->erase_busy; + init_waitqueue_head(&client->mtd_req); + client->next = s->clients; + s->clients = client; + ds_dbg(1, "%s: bind_device(): client 0x%p, dev %s\n", + cs_socket_name(client->Socket), client, client->dev_info); + return CS_SUCCESS; +} /* bind_device */ + + +/*====================================================================== + + Bind_mtd() associates a device driver with a particular memory + region. It is normally called by Driver Services after it has + identified a memory device type. An instance of the corresponding + driver will then be able to register to control this region. + +======================================================================*/ + +static int pcmcia_bind_mtd(mtd_bind_t *req) +{ + struct pcmcia_socket *s; + memory_handle_t region; + + s = req->Socket; + if (!s) + return CS_BAD_SOCKET; + + if (req->Attributes & REGION_TYPE_AM) + region = s->a_region; + else + region = s->c_region; + + while (region) { + if (region->info.CardOffset == req->CardOffset) + break; + region = region->info.next; + } + if (!region || (region->mtd != NULL)) + return CS_BAD_OFFSET; + strlcpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN); + + ds_dbg(1, "%s: bind_mtd: attr 0x%x, offset 0x%x, dev %s\n", + cs_socket_name(s), req->Attributes, req->CardOffset, + (char *)req->dev_info); + return CS_SUCCESS; +} /* bind_mtd */ + + +/* String tables for error messages */ + +typedef struct lookup_t { + int key; + char *msg; +} lookup_t; + +static const lookup_t error_table[] = { + { CS_SUCCESS, "Operation succeeded" }, + { CS_BAD_ADAPTER, "Bad adapter" }, + { CS_BAD_ATTRIBUTE, "Bad attribute", }, + { CS_BAD_BASE, "Bad base address" }, + { CS_BAD_EDC, "Bad EDC" }, + { CS_BAD_IRQ, "Bad IRQ" }, + { CS_BAD_OFFSET, "Bad offset" }, + { CS_BAD_PAGE, "Bad page number" }, + { CS_READ_FAILURE, "Read failure" }, + { CS_BAD_SIZE, "Bad size" }, + { CS_BAD_SOCKET, "Bad socket" }, + { CS_BAD_TYPE, "Bad type" }, + { CS_BAD_VCC, "Bad Vcc" }, + { CS_BAD_VPP, "Bad Vpp" }, + { CS_BAD_WINDOW, "Bad window" }, + { CS_WRITE_FAILURE, "Write failure" }, + { CS_NO_CARD, "No card present" }, + { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, + { CS_UNSUPPORTED_MODE, "Unsupported mode" }, + { CS_BAD_SPEED, "Bad speed" }, + { CS_BUSY, "Resource busy" }, + { CS_GENERAL_FAILURE, "General failure" }, + { CS_WRITE_PROTECTED, "Write protected" }, + { CS_BAD_ARG_LENGTH, "Bad argument length" }, + { CS_BAD_ARGS, "Bad arguments" }, + { CS_CONFIGURATION_LOCKED, "Configuration locked" }, + { CS_IN_USE, "Resource in use" }, + { CS_NO_MORE_ITEMS, "No more items" }, + { CS_OUT_OF_RESOURCE, "Out of resource" }, + { CS_BAD_HANDLE, "Bad handle" }, + { CS_BAD_TUPLE, "Bad CIS tuple" } +}; + + +static const lookup_t service_table[] = { + { AccessConfigurationRegister, "AccessConfigurationRegister" }, + { AddSocketServices, "AddSocketServices" }, + { AdjustResourceInfo, "AdjustResourceInfo" }, + { CheckEraseQueue, "CheckEraseQueue" }, + { CloseMemory, "CloseMemory" }, + { DeregisterClient, "DeregisterClient" }, + { DeregisterEraseQueue, "DeregisterEraseQueue" }, + { GetCardServicesInfo, "GetCardServicesInfo" }, + { GetClientInfo, "GetClientInfo" }, + { GetConfigurationInfo, "GetConfigurationInfo" }, + { GetEventMask, "GetEventMask" }, + { GetFirstClient, "GetFirstClient" }, + { GetFirstRegion, "GetFirstRegion" }, + { GetFirstTuple, "GetFirstTuple" }, + { GetNextClient, "GetNextClient" }, + { GetNextRegion, "GetNextRegion" }, + { GetNextTuple, "GetNextTuple" }, + { GetStatus, "GetStatus" }, + { GetTupleData, "GetTupleData" }, + { MapMemPage, "MapMemPage" }, + { ModifyConfiguration, "ModifyConfiguration" }, + { ModifyWindow, "ModifyWindow" }, + { OpenMemory, "OpenMemory" }, + { ParseTuple, "ParseTuple" }, + { ReadMemory, "ReadMemory" }, + { RegisterClient, "RegisterClient" }, + { RegisterEraseQueue, "RegisterEraseQueue" }, + { RegisterMTD, "RegisterMTD" }, + { ReleaseConfiguration, "ReleaseConfiguration" }, + { ReleaseIO, "ReleaseIO" }, + { ReleaseIRQ, "ReleaseIRQ" }, + { ReleaseWindow, "ReleaseWindow" }, + { RequestConfiguration, "RequestConfiguration" }, + { RequestIO, "RequestIO" }, + { RequestIRQ, "RequestIRQ" }, + { RequestSocketMask, "RequestSocketMask" }, + { RequestWindow, "RequestWindow" }, + { ResetCard, "ResetCard" }, + { SetEventMask, "SetEventMask" }, + { ValidateCIS, "ValidateCIS" }, + { WriteMemory, "WriteMemory" }, + { BindDevice, "BindDevice" }, + { BindMTD, "BindMTD" }, + { ReportError, "ReportError" }, + { SuspendCard, "SuspendCard" }, + { ResumeCard, "ResumeCard" }, + { EjectCard, "EjectCard" }, + { InsertCard, "InsertCard" }, + { ReplaceCIS, "ReplaceCIS" } +}; + + +int pcmcia_report_error(client_handle_t handle, error_info_t *err) +{ + int i; + char *serv; + + if (CHECK_HANDLE(handle)) + printk(KERN_NOTICE); + else + printk(KERN_NOTICE "%s: ", handle->dev_info); + + for (i = 0; i < ARRAY_SIZE(service_table); i++) + if (service_table[i].key == err->func) + break; + if (i < ARRAY_SIZE(service_table)) + serv = service_table[i].msg; + else + serv = "Unknown service number"; + + for (i = 0; i < ARRAY_SIZE(error_table); i++) + if (error_table[i].key == err->retcode) + break; + if (i < ARRAY_SIZE(error_table)) + printk("%s: %s\n", serv, error_table[i].msg); + else + printk("%s: Unknown error code %#x\n", serv, err->retcode); + + return CS_SUCCESS; +} /* report_error */ +EXPORT_SYMBOL(pcmcia_report_error); + +/* end of code which was in cs.c before */ + +/*======================================================================*/ + void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; @@ -249,12 +465,12 @@ { if (s->req_pending != 0) return CS_IN_USE; - if (s->state & SOCKET_BUSY) + if (s->state & DS_SOCKET_BUSY) s->req_pending = 1; handle_event(s, event); if (wait_event_interruptible(s->request, s->req_pending <= 0)) return CS_IN_USE; - if (s->state & SOCKET_BUSY) + if (s->state & DS_SOCKET_BUSY) return s->req_result; return CS_SUCCESS; } @@ -263,7 +479,7 @@ { struct pcmcia_bus_socket *s = data; handle_event(s, CS_EVENT_CARD_REMOVAL); - s->state &= ~SOCKET_REMOVAL_PENDING; + s->state &= ~DS_SOCKET_REMOVAL_PENDING; } /*====================================================================== @@ -277,22 +493,22 @@ { struct pcmcia_bus_socket *s; - DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n", + ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", event, priority, args->client_handle); s = args->client_data; switch (event) { case CS_EVENT_CARD_REMOVAL: - s->state &= ~SOCKET_PRESENT; - if (!(s->state & SOCKET_REMOVAL_PENDING)) { - s->state |= SOCKET_REMOVAL_PENDING; + s->state &= ~DS_SOCKET_PRESENT; + if (!(s->state & DS_SOCKET_REMOVAL_PENDING)) { + s->state |= DS_SOCKET_REMOVAL_PENDING; schedule_delayed_work(&s->removal, HZ/10); } break; case CS_EVENT_CARD_INSERTION: - s->state |= SOCKET_PRESENT; + s->state |= DS_SOCKET_PRESENT; handle_event(s, event); break; @@ -353,7 +569,7 @@ if (!s) return -EINVAL; - DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock, + ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); driver = get_pcmcia_driver(&bind_info->dev_info); if (!driver) @@ -484,7 +700,7 @@ { socket_bind_t **b, *c; - DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock, + ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); for (b = &s->bind; *b; b = &(*b)->next) if ((strcmp((char *)(*b)->driver->drv.name, @@ -518,17 +734,17 @@ struct pcmcia_bus_socket *s; user_info_t *user; - DEBUG(0, "ds_open(socket %d)\n", i); + ds_dbg(0, "ds_open(socket %d)\n", i); s = pcmcia_get_bus_socket(i); if (!s) return -ENODEV; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - if (s->state & SOCKET_BUSY) + if (s->state & DS_SOCKET_BUSY) return -EBUSY; else - s->state |= SOCKET_BUSY; + s->state |= DS_SOCKET_BUSY; } user = kmalloc(sizeof(user_info_t), GFP_KERNEL); @@ -540,7 +756,7 @@ s->user = user; file->private_data = user; - if (s->state & SOCKET_PRESENT) + if (s->state & DS_SOCKET_PRESENT) queue_event(user, CS_EVENT_CARD_INSERTION); return 0; } /* ds_open */ @@ -552,7 +768,7 @@ struct pcmcia_bus_socket *s; user_info_t *user, **link; - DEBUG(0, "ds_release(socket %d)\n", iminor(inode)); + ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); user = file->private_data; if (CHECK_USER(user)) @@ -562,7 +778,7 @@ /* Unlink user data structure */ if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - s->state &= ~SOCKET_BUSY; + s->state &= ~DS_SOCKET_BUSY; s->req_pending = 0; wake_up_interruptible(&s->request); } @@ -588,7 +804,7 @@ user_info_t *user; int ret; - DEBUG(2, "ds_read(socket %d)\n", iminor(inode)); + ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode)); if (count < 4) return -EINVAL; @@ -598,7 +814,7 @@ return -EIO; s = user->socket; - if (s->state & SOCKET_DEAD) + if (s->state & DS_SOCKET_DEAD) return -EIO; ret = wait_event_interruptible(s->queue, !queue_empty(user)); @@ -616,7 +832,7 @@ struct pcmcia_bus_socket *s; user_info_t *user; - DEBUG(2, "ds_write(socket %d)\n", iminor(inode)); + ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode)); if (count != 4) return -EINVAL; @@ -628,7 +844,7 @@ return -EIO; s = user->socket; - if (s->state & SOCKET_DEAD) + if (s->state & DS_SOCKET_DEAD) return -EIO; if (s->req_pending) { @@ -650,7 +866,7 @@ struct pcmcia_bus_socket *s; user_info_t *user; - DEBUG(2, "ds_poll(socket %d)\n", iminor(inode)); + ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode)); user = file->private_data; if (CHECK_USER(user)) @@ -677,14 +893,14 @@ ds_ioctl_arg_t buf; user_info_t *user; - DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); + ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); user = file->private_data; if (CHECK_USER(user)) return -EIO; s = user->socket; - if (s->state & SOCKET_DEAD) + if (s->state & DS_SOCKET_DEAD) return -EIO; size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; @@ -697,14 +913,14 @@ if (cmd & IOC_IN) { err = verify_area(VERIFY_READ, (char *)arg, size); if (err) { - DEBUG(3, "ds_ioctl(): verify_read = %d\n", err); + ds_dbg(3, "ds_ioctl(): verify_read = %d\n", err); return err; } } if (cmd & IOC_OUT) { err = verify_area(VERIFY_WRITE, (char *)arg, size); if (err) { - DEBUG(3, "ds_ioctl(): verify_write = %d\n", err); + ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err); return err; } } @@ -748,16 +964,16 @@ ret = pcmcia_validate_cis(s->handle, &buf.cisinfo); break; case DS_SUSPEND_CARD: - ret = pcmcia_suspend_card(s->handle, NULL); + ret = pcmcia_suspend_card(s->parent); break; case DS_RESUME_CARD: - ret = pcmcia_resume_card(s->handle, NULL); + ret = pcmcia_resume_card(s->parent); break; case DS_EJECT_CARD: - ret = pcmcia_eject_card(s->handle, NULL); + ret = pcmcia_eject_card(s->parent); break; case DS_INSERT_CARD: - ret = pcmcia_insert_card(s->handle, NULL); + ret = pcmcia_insert_card(s->parent); break; case DS_ACCESS_CONFIGURATION_REGISTER: if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) @@ -806,7 +1022,7 @@ } if ((err == 0) && (ret != CS_SUCCESS)) { - DEBUG(2, "ds_ioctl: ret = %d\n", ret); + ds_dbg(2, "ds_ioctl: ret = %d\n", ret); switch (ret) { case CS_BAD_SOCKET: case CS_NO_CARD: err = -ENODEV; break; @@ -916,7 +1132,7 @@ pcmcia_deregister_client(socket->pcmcia->handle); - socket->pcmcia->state |= SOCKET_DEAD; + socket->pcmcia->state |= DS_SOCKET_DEAD; pcmcia_put_bus_socket(socket->pcmcia); socket->pcmcia = NULL; diff -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c --- a/drivers/pcmcia/i82365.c Sat Apr 3 19:38:55 2004 +++ b/drivers/pcmcia/i82365.c Sat Apr 3 19:38:55 2004 @@ -32,6 +32,7 @@ ======================================================================*/ #include +#include #include #include #include @@ -66,14 +67,20 @@ #include "ricoh.h" #include "o2micro.h" -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#ifdef DEBUG static const char *version = "i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)"; + +static int pc_debug; + +module_param(pc_debug, int, 0644); + +#define debug(lvl, fmt, arg...) do { \ + if (pc_debug > (lvl)) \ + printk(KERN_DEBUG "i82365: " fmt , ## arg); \ +} while (0) #else -#define DEBUG(n, args...) do { } while (0) +#define debug(lvl, fmt, arg...) do { } while (0) #endif static irqreturn_t i365_count_irq(int, void *, struct pt_regs *); @@ -496,13 +503,13 @@ { i365_get(irq_sock, I365_CSC); irq_hits++; - DEBUG(2, "-> hit on irq %d\n", irq); + debug(2, "-> hit on irq %d\n", irq); return IRQ_HANDLED; } static u_int __init test_irq(u_short sock, int irq) { - DEBUG(2, " testing ISA irq %d\n", irq); + debug(2, " testing ISA irq %d\n", irq); if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0) return 1; irq_hits = 0; irq_sock = sock; @@ -510,7 +517,7 @@ schedule_timeout(HZ/100); if (irq_hits) { free_irq(irq, i365_count_irq); - DEBUG(2, " spurious hit!\n"); + debug(2, " spurious hit!\n"); return 1; } @@ -523,7 +530,7 @@ /* mask all interrupts */ i365_set(sock, I365_CSCINT, 0); - DEBUG(2, " hits = %d\n", irq_hits); + debug(2, " hits = %d\n", irq_hits); return (irq_hits != 1); } @@ -850,7 +857,7 @@ u_long flags = 0; int handled = 0; - DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq); + debug(4, "pcic_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; @@ -874,7 +881,7 @@ events |= (csc & I365_CSC_READY) ? SS_READY : 0; } ISA_UNLOCK(i, flags); - DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events); + debug(2, "socket %d event 0x%02x\n", i, events); if (events) pcmcia_parse_events(&socket[i].socket, events); @@ -886,7 +893,7 @@ if (j == 20) printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n"); - DEBUG(4, "i82365: interrupt done\n"); + debug(4, "interrupt done\n"); return IRQ_RETVAL(handled); } /* pcic_interrupt */ @@ -928,7 +935,7 @@ } } - DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value); + debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value); return 0; } /* i365_get_status */ @@ -998,7 +1005,7 @@ state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; } - DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); return 0; @@ -1011,7 +1018,7 @@ struct i82365_socket *t = &socket[sock]; u_char reg; - DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -1120,7 +1127,7 @@ { u_char map, ioctl; - DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, " + debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " "%#4.4x-%#4.4x)\n", sock, io->map, io->flags, io->speed, io->start, io->stop); map = io->map; @@ -1150,7 +1157,7 @@ u_short base, i; u_char map; - DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5" + debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5" "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); diff -Nru a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c --- a/drivers/pcmcia/sa1100_pangolin.c Sat Apr 3 19:38:41 2004 +++ b/drivers/pcmcia/sa1100_pangolin.c Sat Apr 3 19:38:41 2004 @@ -54,7 +54,7 @@ pangolin_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels = GPLR;; + unsigned long levels = GPLR; state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0; diff -Nru a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c --- a/drivers/pcmcia/sa11xx_core.c Sat Apr 3 19:38:41 2004 +++ b/drivers/pcmcia/sa11xx_core.c Sat Apr 3 19:38:41 2004 @@ -35,6 +35,7 @@ */ #include +#include #include #include #include @@ -54,8 +55,19 @@ #include "sa11xx_core.h" #include "sa1100.h" -#ifdef PCMCIA_DEBUG +#ifdef DEBUG static int pc_debug; + +module_param(pc_debug, int, 0644); + +#define debug(skt, lvl, fmt, arg...) do { \ + if (pc_debug > (lvl)) \ + printk(KERN_DEBUG "skt%u: %s: " fmt, \ + (skt)->nr, __func__ , ## arg); \ +} while (0) + +#else +#define debug(skt, lvl, fmt, arg...) do { } while (0) #endif #define to_sa1100_socket(x) container_of(x, struct sa1100_pcmcia_socket, socket) @@ -133,8 +145,8 @@ local_irq_restore(flags); - DEBUG(4, "%s(): sock %u FAST %X BSM %X BSA %X BSIO %X\n", - __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr), + debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n", + MECR_FAST_GET(mecr, skt->nr), MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), MECR_BSIO_GET(mecr, skt->nr)); @@ -221,7 +233,7 @@ { struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, skt->nr); + debug(skt, 2, "initializing socket\n"); skt->ops->socket_init(skt); return 0; @@ -242,7 +254,7 @@ struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); int ret; - DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr); + debug(skt, 2, "suspending socket\n"); ret = sa1100_pcmcia_config_skt(skt, &dead_socket); if (ret == 0) @@ -260,7 +272,7 @@ { unsigned int events; - DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + debug(skt, 4, "entering PCMCIA monitoring thread\n"); do { unsigned int status; @@ -273,7 +285,7 @@ skt->status = status; spin_unlock_irqrestore(&status_lock, flags); - DEBUG(2, "events: %s%s%s%s%s%s\n", + debug(skt, 4, "events: %s%s%s%s%s%s\n", events == 0 ? "" : "", events & SS_DETECT ? "DETECT " : "", events & SS_READY ? "READY " : "", @@ -293,7 +305,7 @@ static void sa1100_pcmcia_poll_event(unsigned long dummy) { struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy; - DEBUG(4, "%s(): polling for events\n", __FUNCTION__); + debug(skt, 4, "polling for events\n"); mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD); @@ -314,7 +326,7 @@ { struct sa1100_pcmcia_socket *skt = dev; - DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); + debug(skt, 3, "servicing IRQ %d\n", irq); sa1100_check_status(skt); @@ -363,7 +375,7 @@ { struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + debug(skt, 2, "\n"); *state = skt->cs_state; @@ -385,22 +397,19 @@ { struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", - (state->csc_mask==0)?"":"", + debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", + (state->csc_mask==0)?" ":"", (state->csc_mask&SS_DETECT)?"DETECT ":"", (state->csc_mask&SS_READY)?"READY ":"", (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", (state->csc_mask&SS_BATWARN)?"BATWARN ":"", (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"":"", + (state->flags==0)?" ":"", (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", (state->flags&SS_IOCARD)?"IOCARD ":"", (state->flags&SS_RESET)?"RESET ":"", (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); - DEBUG(3, "\tVcc %d Vpp %d irq %d\n", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", state->Vcc, state->Vpp, state->io_irq); return sa1100_pcmcia_config_skt(skt, state); @@ -422,11 +431,9 @@ struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); unsigned short speed = map->speed; - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", + debug(skt, 2, "map %u speed %u start 0x%08x stop 0x%08x\n", map->map, map->speed, map->start, map->stop); - DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", @@ -479,11 +486,9 @@ struct resource *res; unsigned short speed = map->speed; - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmap %u speed %u card_start %08x\n", + debug(skt, 2, "map %u speed %u card_start %08x\n", map->map, map->speed, map->card_start); - DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", @@ -920,23 +925,13 @@ switch (val) { case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, " - "pre-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); + if (freqs->new > freqs->old) sa1100_pcmcia_update_mecr(freqs->new); - } break; case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, " - "post-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); + if (freqs->new < freqs->old) sa1100_pcmcia_update_mecr(freqs->new); - } break; } diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c --- a/drivers/pcmcia/tcic.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pcmcia/tcic.c Sat Apr 3 19:38:44 2004 @@ -32,6 +32,7 @@ ======================================================================*/ #include +#include #include #include #include @@ -55,14 +56,20 @@ #include #include "tcic.h" -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; +#ifdef DEBUG +static int pc_debug; + +module_param(pc_debug, int, 0644); MODULE_PARM(pc_debug, "i"); static const char *version = "tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)"; -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + +#define debug(lvl, fmt, arg...) do { \ + if (pc_debug > (lvl)) \ + printk(KERN_DEBUG "tcic: " fmt , ## arg); \ +} while (0) #else -#define DEBUG(n, args...) +#define debug(lvl, fmt, arg...) do { } while (0) #endif MODULE_AUTHOR("David Hinds "); @@ -133,7 +140,7 @@ to map to irq 11, but is coded as 0 or 1 in the irq registers. */ #define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15) -#ifdef PCMCIA_DEBUG_X +#ifdef DEBUG_X static u_char tcic_getb(u_char reg) { u_char val = inb(tcic_base+reg); @@ -168,7 +175,7 @@ static void tcic_setl(u_char reg, u_int data) { -#ifdef PCMCIA_DEBUG_X +#ifdef DEBUG_X printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data); #endif outw(data & 0xffff, tcic_base+reg); @@ -573,7 +580,7 @@ } else active = 1; - DEBUG(2, "tcic: tcic_interrupt()\n"); + debug(2, "tcic_interrupt()\n"); for (i = 0; i < sockets; i++) { psock = socket_table[i].psock; @@ -610,13 +617,13 @@ } active = 0; - DEBUG(2, "tcic: interrupt done\n"); + debug(2, "interrupt done\n"); return IRQ_HANDLED; } /* tcic_interrupt */ static void tcic_timer(u_long data) { - DEBUG(2, "tcic: tcic_timer()\n"); + debug(2, "tcic_timer()\n"); tcic_timer_pending = 0; tcic_interrupt(0, NULL, NULL); } /* tcic_timer */ @@ -643,7 +650,7 @@ reg = tcic_getb(TCIC_PWR); if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock))) *value |= SS_POWERON; - DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", psock, *value); + debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value); return 0; } /* tcic_get_status */ @@ -694,7 +701,7 @@ state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY; } - DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x\n", psock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); return 0; @@ -708,7 +715,7 @@ u_char reg; u_short scf1, scf2; - DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG); @@ -783,7 +790,7 @@ u_int addr; u_short base, len, ioctl; - DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, " + debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " "%#4.4x-%#4.4x)\n", psock, io->map, io->flags, io->speed, io->start, io->stop); if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || @@ -820,7 +827,7 @@ u_short addr, ctl; u_long base, len, mmap; - DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, " + debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5lx-%#5.5lx, %#5.5x)\n", psock, mem->map, mem->flags, mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || diff -Nru a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c --- a/drivers/pcmcia/yenta_socket.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pcmcia/yenta_socket.c Sat Apr 3 19:38:44 2004 @@ -30,9 +30,9 @@ #if 0 -#define DEBUG(x,args...) printk(KERN_DEBUG "%s: " x, __FUNCTION__, ##args) +#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) #else -#define DEBUG(x,args...) +#define debug(x,args...) #endif /* Don't ask.. */ @@ -47,13 +47,13 @@ static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg) { u32 val = readl(socket->base + reg); - DEBUG("%p %04x %08x\n", socket, reg, val); + debug("%p %04x %08x\n", socket, reg, val); return val; } static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) { - DEBUG("%p %04x %08x\n", socket, reg, val); + debug("%p %04x %08x\n", socket, reg, val); writel(val, socket->base + reg); } @@ -61,7 +61,7 @@ { u8 val; pci_read_config_byte(socket->dev, offset, &val); - DEBUG("%p %04x %02x\n", socket, offset, val); + debug("%p %04x %02x\n", socket, offset, val); return val; } @@ -69,7 +69,7 @@ { u16 val; pci_read_config_word(socket->dev, offset, &val); - DEBUG("%p %04x %04x\n", socket, offset, val); + debug("%p %04x %04x\n", socket, offset, val); return val; } @@ -77,32 +77,32 @@ { u32 val; pci_read_config_dword(socket->dev, offset, &val); - DEBUG("%p %04x %08x\n", socket, offset, val); + debug("%p %04x %08x\n", socket, offset, val); return val; } static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val) { - DEBUG("%p %04x %02x\n", socket, offset, val); + debug("%p %04x %02x\n", socket, offset, val); pci_write_config_byte(socket->dev, offset, val); } static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val) { - DEBUG("%p %04x %04x\n", socket, offset, val); + debug("%p %04x %04x\n", socket, offset, val); pci_write_config_word(socket->dev, offset, val); } static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val) { - DEBUG("%p %04x %08x\n", socket, offset, val); + debug("%p %04x %08x\n", socket, offset, val); pci_write_config_dword(socket->dev, offset, val); } static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg) { u8 val = readb(socket->base + 0x800 + reg); - DEBUG("%p %04x %02x\n", socket, reg, val); + debug("%p %04x %02x\n", socket, reg, val); return val; } @@ -111,19 +111,19 @@ u16 val; val = readb(socket->base + 0x800 + reg); val |= readb(socket->base + 0x800 + reg + 1) << 8; - DEBUG("%p %04x %04x\n", socket, reg, val); + debug("%p %04x %04x\n", socket, reg, val); return val; } static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val) { - DEBUG("%p %04x %02x\n", socket, reg, val); + debug("%p %04x %02x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); } static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) { - DEBUG("%p %04x %04x\n", socket, reg, val); + debug("%p %04x %04x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); writeb(val >> 8, socket->base + 0x800 + reg + 1); } @@ -1016,6 +1016,11 @@ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), + + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, TI12XX), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, TI1250), + CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, TI12XX), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), diff -Nru a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig --- a/drivers/pnp/isapnp/Kconfig Sat Apr 3 19:38:43 2004 +++ b/drivers/pnp/isapnp/Kconfig Sat Apr 3 19:38:43 2004 @@ -2,8 +2,8 @@ # ISA Plug and Play configuration # config ISAPNP - bool "ISA Plug and Play support (EXPERIMENTAL)" - depends on PNP && EXPERIMENTAL + bool "ISA Plug and Play support" + depends on PNP help Say Y here if you would like support for ISA Plug and Play devices. Some information is in . diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c --- a/drivers/pnp/isapnp/core.c Sat Apr 3 19:38:43 2004 +++ b/drivers/pnp/isapnp/core.c Sat Apr 3 19:38:43 2004 @@ -99,6 +99,7 @@ static unsigned char isapnp_checksum_value; static DECLARE_MUTEX(isapnp_cfg_mutex); static int isapnp_detected; +static int isapnp_csn_count; /* some prototypes */ @@ -371,11 +372,14 @@ break; } __next: + if (csn == 255) + break; checksum = 0x6a; chksum = 0x00; bit = 0x00; } isapnp_wait(); + isapnp_csn_count = csn; return csn; } @@ -880,7 +884,7 @@ isapnp_wait(); isapnp_key(); - for (csn = 1; csn <= 10; csn++) { + for (csn = 1; csn <= isapnp_csn_count; csn++) { isapnp_wake(csn); isapnp_peek(header, 9); checksum = isapnp_checksum(header); @@ -890,12 +894,6 @@ header[4], header[5], header[6], header[7], header[8]); printk(KERN_DEBUG "checksum = 0x%x\n", checksum); #endif - /* Don't be strict on the checksum, here ! - e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/ - if (header[8] == 0) - ; - else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */ - continue; if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL) continue; @@ -932,9 +930,8 @@ int isapnp_cfg_begin(int csn, int logdev) { - if (csn < 1 || csn > 10 || logdev > 10) + if (csn < 1 || csn > isapnp_csn_count || logdev > 10) return -EINVAL; - MOD_INC_USE_COUNT; down(&isapnp_cfg_mutex); isapnp_wait(); isapnp_key(); @@ -962,7 +959,6 @@ { isapnp_wait(); up(&isapnp_cfg_mutex); - MOD_DEC_USE_COUNT; return 0; } @@ -1050,7 +1046,7 @@ for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++) isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start); for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++) - isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (res->mem_resource[tmp].start >> 8) & 0xffff); + isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<3), (res->mem_resource[tmp].start >> 8) & 0xffff); /* FIXME: We aren't handling 32bit mems properly here */ isapnp_activate(dev->number); isapnp_cfg_end(); diff -Nru a/drivers/pnp/resource.c b/drivers/pnp/resource.c --- a/drivers/pnp/resource.c Sat Apr 3 19:38:44 2004 +++ b/drivers/pnp/resource.c Sat Apr 3 19:38:44 2004 @@ -231,15 +231,9 @@ #define length(start, end) (*(end) - *(start) + 1) -/* ranged_conflict - used to determine if two resource ranges conflict - * condition 1: check if the start of a is within b - * condition 2: check if the end of a is within b - * condition 3: check if b is engulfed by a */ - +/* Two ranges conflict if one doesn't end before the other starts */ #define ranged_conflict(starta, enda, startb, endb) \ -((*(starta) >= *(startb) && *(starta) <= *(endb)) || \ - (*(enda) >= *(startb) && *(enda) <= *(endb)) || \ - (*(starta) < *(startb) && *(enda) > *(endb))) + !((*(enda) < *(startb)) || (*(endb) < *(starta))) #define cannot_compare(flags) \ ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) diff -Nru a/drivers/pnp/system.c b/drivers/pnp/system.c --- a/drivers/pnp/system.c Sat Apr 3 19:38:57 2004 +++ b/drivers/pnp/system.c Sat Apr 3 19:38:57 2004 @@ -21,7 +21,7 @@ { "", 0 } }; -static void __init reserve_ioport_range(char *pnpid, int start, int end) +static void reserve_ioport_range(char *pnpid, int start, int end) { struct resource *res; char *regionid; @@ -49,7 +49,7 @@ return; } -static void __init reserve_resources_of_dev( struct pnp_dev *dev ) +static void reserve_resources_of_dev( struct pnp_dev *dev ) { int i; diff -Nru a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig --- a/drivers/s390/block/Kconfig Sat Apr 3 19:38:40 2004 +++ b/drivers/s390/block/Kconfig Sat Apr 3 19:38:40 2004 @@ -48,12 +48,12 @@ say "Y". config DASD_DIAG - tristate "Support for DIAG access to CMS reserved Disks" + tristate "Support for DIAG access to Disks" depends on DASD && ARCH_S390X = 'n' help - Select this option if you want to use CMS reserved Disks under VM - with the Diagnose250 command. If you are not running under VM or - unsure what it is, say "N". + Select this option if you want to use Diagnose250 command to access + Disks under VM. If you are not running under VM or unsure what it is, + say "N". config DASD_CMB tristate "Compatibility interface for DASD channel measurement blocks" diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c --- a/drivers/s390/block/dasd.c Sat Apr 3 19:38:43 2004 +++ b/drivers/s390/block/dasd.c Sat Apr 3 19:38:43 2004 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.129 $ + * $Revision: 1.136 $ */ #include @@ -224,7 +224,8 @@ return rc; dasd_setup_queue(device); device->state = DASD_STATE_READY; - dasd_scan_partitions(device); + if (dasd_scan_partitions(device) != 0) + device->state = DASD_STATE_BASIC; return 0; } @@ -687,7 +688,10 @@ rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ - cqr->status = DASD_CQR_FAILED; + if (cqr->retries > 0) + cqr->status = DASD_CQR_QUEUED; + else + cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); break; case -ENODEV: @@ -779,7 +783,7 @@ device = (struct dasd_device *) ptr; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - /* re-activate first request in queue */ + /* re-activate request queue */ device->stopped &= ~DASD_STOPPED_PENDING; spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_bh(device); @@ -827,12 +831,25 @@ struct dasd_device *device; } *p; struct dasd_device *device; + struct dasd_ccw_req *cqr; + struct list_head *l, *n; + unsigned long flags; p = data; device = p->device; DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s", device->cdev->dev.bus_id); device->stopped &= ~DASD_STOPPED_PENDING; + + /* restart all 'running' IO on queue */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + list_for_each_safe(l, n, &device->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, list); + if (cqr->status == DASD_CQR_IN_IO) + cqr->status = DASD_CQR_QUEUED; + } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + dasd_set_timer (device, 0); dasd_schedule_bh(device); dasd_put_device(device); kfree(p); @@ -847,7 +864,8 @@ cqr = (struct dasd_ccw_req *) intparm; if (cqr->status != DASD_CQR_IN_IO) { MESSAGE(KERN_DEBUG, - "invalid status: bus_id %s, status %02x", + "invalid status in handle_killed_request: " + "bus_id %s, status %02x", cdev->dev.bus_id, cqr->status); return; } @@ -1142,7 +1160,8 @@ elv_next_request(queue) && nr_queued < DASD_CHANQ_MAX_SIZE) { req = elv_next_request(queue); - if (device->ro_flag && rq_data_dir(req) == WRITE) { + if (test_bit(DASD_FLAG_RO, &device->flags) && + rq_data_dir(req) == WRITE) { DBF_EVENT(DBF_ERR, "(%s) Rejecting write request %p", device->cdev->dev.bus_id, @@ -1186,13 +1205,11 @@ __dasd_check_expire(struct dasd_device * device) { struct dasd_ccw_req *cqr; - unsigned long long now; if (list_empty(&device->ccw_queue)) return; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { - now = get_clock(); if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { if (device->discipline->term_IO(cqr) != 0) /* Hmpf, try again in 1/100 sec */ @@ -1517,7 +1534,8 @@ * terminated if it is currently in i/o. * Returns 1 if the request has been terminated. */ -int dasd_cancel_req(struct dasd_ccw_req *cqr) +int +dasd_cancel_req(struct dasd_ccw_req *cqr) { struct dasd_device *device = cqr->device; unsigned long flags; @@ -1657,9 +1675,17 @@ struct dasd_device *device = disk->private_data; int rc; - if (!try_module_get(device->discipline->owner)) - return -EINVAL; - + atomic_inc(&device->open_count); + if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + rc = -ENODEV; + goto unlock; + } + + if (!try_module_get(device->discipline->owner)) { + rc = -EINVAL; + goto unlock; + } + if (dasd_probeonly) { MESSAGE(KERN_INFO, "No access to device %s due to probeonly mode", @@ -1668,7 +1694,6 @@ goto out; } - rc = -ENODEV; if (device->state < DASD_STATE_BASIC) { DBF_DEV_EVENT(DBF_ERR, device, " %s", " Cannot open unrecognized device"); @@ -1676,11 +1701,12 @@ goto out; } - atomic_inc(&device->open_count); return 0; out: module_put(device->discipline->owner); +unlock: + atomic_dec(&device->open_count); return rc; } @@ -1690,12 +1716,6 @@ struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; - if (device->state < DASD_STATE_BASIC) { - DBF_DEV_EVENT(DBF_ERR, device, " %s", - " Cannot release unrecognized device"); - return -EINVAL; - } - atomic_dec(&device->open_count); module_put(device->discipline->owner); return 0; @@ -1741,7 +1761,7 @@ ret = dasd_add_sysfs_files(cdev); if (ret) { printk(KERN_WARNING - "dasd_generic_probe: could not add driverfs entries" + "dasd_generic_probe: could not add sysfs entries " "for %s\n", cdev->dev.bus_id); } @@ -1757,12 +1777,23 @@ { struct dasd_device *device; + dasd_remove_sysfs_files(cdev); device = dasd_device_from_cdev(cdev); - if (!IS_ERR(device)) { - dasd_set_target_state(device, DASD_STATE_NEW); - /* dasd_delete_device destroys the device reference. */ - dasd_delete_device(device); + if (IS_ERR(device)) + return; + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* Already doing offline processing */ + dasd_put_device(device); + return; } + /* + * This device is removed unconditionally. Set offline + * flag to prevent dasd_open from opening it while it is + * no quite down yet. + */ + dasd_set_target_state(device, DASD_STATE_NEW); + /* dasd_delete_device destroys the device reference. */ + dasd_delete_device(device); } /* activate a device. This is called from dasd_{eckd,fba}_probe() when either @@ -1780,7 +1811,7 @@ if (IS_ERR(device)) return PTR_ERR(device); - if (device->use_diag_flag) { + if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) { if (!dasd_diag_discipline_pointer) { printk (KERN_WARNING "dasd_generic couldn't online device %s " @@ -1828,17 +1859,35 @@ dasd_generic_set_offline (struct ccw_device *cdev) { struct dasd_device *device; + int max_count; device = dasd_device_from_cdev(cdev); - if (atomic_read(&device->open_count) > 0) { + if (IS_ERR(device)) + return PTR_ERR(device); + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* Already doing offline processing */ + dasd_put_device(device); + return 0; + } + /* + * We must make sure that this device is currently not in use. + * The open_count is increased for every opener, that includes + * the blkdev_get in dasd_scan_partitions. We are only interested + * in the other openers. + */ + max_count = device->bdev ? 1 : 0; + if (atomic_read(&device->open_count) > max_count) { printk (KERN_WARNING "Can't offline dasd device with open" " count = %i.\n", atomic_read(&device->open_count)); + clear_bit(DASD_FLAG_OFFLINE, &device->flags); dasd_put_device(device); return -EBUSY; } - dasd_put_device(device); - dasd_generic_remove (cdev); + dasd_set_target_state(device, DASD_STATE_NEW); + /* dasd_delete_device destroys the device reference. */ + dasd_delete_device(device); + return 0; } @@ -1861,7 +1910,7 @@ if (device->state < DASD_STATE_BASIC) break; /* Device is active. We want to keep it. */ - if (device->disconnect_error_flag) { + if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) { list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_FAILED; diff -Nru a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c --- a/drivers/s390/block/dasd_3990_erp.c Sat Apr 3 19:38:55 2004 +++ b/drivers/s390/block/dasd_3990_erp.c Sat Apr 3 19:38:55 2004 @@ -5,7 +5,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * - * $Revision: 1.27 $ + * $Revision: 1.28 $ */ #include @@ -229,7 +229,7 @@ struct dasd_device *device = erp->device; DEV_MESSAGE(KERN_INFO, device, - "blocking request queue for %is", expires); + "blocking request queue for %is", expires/HZ); device->stopped |= DASD_STOPPED_PENDING; erp->status = DASD_CQR_QUEUED; @@ -2623,7 +2623,7 @@ #ifdef ERP_DEBUG /* print current erp_chain */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at BEGINNING of ERP-ACTION"); { struct dasd_ccw_req *temp_erp = NULL; @@ -2631,9 +2631,10 @@ for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_DEBUG, device, - " erp %p refers to %p", - temp_erp, temp_erp->refers); + DEV_MESSAGE(KERN_ERR, device, + " erp %p (%02x) refers to %p", + temp_erp, temp_erp->status, + temp_erp->refers); } } #endif /* ERP_DEBUG */ @@ -2675,15 +2676,16 @@ #ifdef ERP_DEBUG /* print current erp_chain */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION"); + DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at END of ERP-ACTION"); { struct dasd_ccw_req *temp_erp = NULL; for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_DEBUG, device, - " erp %p refers to %p", - temp_erp, temp_erp->refers); + DEV_MESSAGE(KERN_ERR, device, + " erp %p (%02x) refers to %p", + temp_erp, temp_erp->status, + temp_erp->refers); } } #endif /* ERP_DEBUG */ diff -Nru a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c --- a/drivers/s390/block/dasd_devmap.c Sat Apr 3 19:38:43 2004 +++ b/drivers/s390/block/dasd_devmap.c Sat Apr 3 19:38:43 2004 @@ -11,7 +11,7 @@ * functions may not be called from interrupt context. In particular * dasd_get_device is a no-no from interrupt context. * - * $Revision: 1.25 $ + * $Revision: 1.27 $ */ #include @@ -466,10 +466,14 @@ if (!devmap->device) { devmap->device = device; device->devindex = devmap->devindex; - device->ro_flag = - (devmap->features & DASD_FEATURE_READONLY) != 0; - device->use_diag_flag = - (devmap->features & DASD_FEATURE_USEDIAG) != 0; + if (devmap->features & DASD_FEATURE_READONLY) + set_bit(DASD_FLAG_RO, &device->flags); + else + clear_bit(DASD_FLAG_RO, &device->flags); + if (devmap->features & DASD_FEATURE_USEDIAG) + set_bit(DASD_FLAG_USE_DIAG, &device->flags); + else + clear_bit(DASD_FLAG_USE_DIAG, &device->flags); get_device(&cdev->dev); device->cdev = cdev; rc = 0; @@ -596,7 +600,10 @@ if (devmap->device) { if (devmap->device->gdp) set_disk_ro(devmap->device->gdp, ro_flag); - devmap->device->ro_flag = ro_flag; + if (ro_flag) + set_bit(DASD_FLAG_RO, &devmap->device->flags); + else + clear_bit(DASD_FLAG_RO, &devmap->device->flags); } spin_unlock(&dasd_devmap_lock); return count; @@ -680,6 +687,13 @@ { return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group); } + +void +dasd_remove_sysfs_files(struct ccw_device *cdev) +{ + sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group); +} + int dasd_devmap_init(void) diff -Nru a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c --- a/drivers/s390/block/dasd_diag.c Sat Apr 3 19:38:40 2004 +++ b/drivers/s390/block/dasd_diag.c Sat Apr 3 19:38:40 2004 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.33 $ + * $Revision: 1.34 $ */ #include @@ -173,7 +173,6 @@ if (!ip) { /* no intparm: unsolicited interrupt */ MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt"); - irq_exit(); return; } cqr = (struct dasd_ccw_req *)(addr_t) ip; @@ -183,7 +182,6 @@ " magic number of dasd_ccw_req 0x%08X doesn't" " match discipline 0x%08X", cqr->magic, *(int *) (&device->discipline->name)); - irq_exit(); return; } diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c --- a/drivers/s390/block/dasd_eckd.c Sat Apr 3 19:38:40 2004 +++ b/drivers/s390/block/dasd_eckd.c Sat Apr 3 19:38:40 2004 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.51 $ + * $Revision: 1.53 $ */ #include @@ -1131,7 +1131,7 @@ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1174,7 +1174,7 @@ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1216,7 +1216,7 @@ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1274,6 +1274,7 @@ stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t)); + ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof (struct dasd_rssd_perf_stats_t); ccw->cda = (__u32)(addr_t) stats; diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c --- a/drivers/s390/block/dasd_genhd.c Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/block/dasd_genhd.c Sat Apr 3 19:38:54 2004 @@ -9,7 +9,7 @@ * * gendisk related functions for the dasd driver. * - * $Revision: 1.44 $ + * $Revision: 1.46 $ */ #include @@ -71,7 +71,7 @@ sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); - if (device->ro_flag) + if (test_bit(DASD_FLAG_RO, &device->flags)) set_disk_ro(gdp, 1); gdp->private_data = device; gdp->queue = device->request_queue; @@ -96,22 +96,33 @@ /* * Trigger a partition detection. */ -void +int dasd_scan_partitions(struct dasd_device * device) { struct block_device *bdev; /* Make the disk known. */ set_capacity(device->gdp, device->blocks << device->s2b_shift); - /* See fs/partition/check.c:register_disk,rescan_partitions */ bdev = bdget_disk(device->gdp, 0); - if (bdev) { - if (blkdev_get(bdev, FMODE_READ, 1) >= 0) { - /* Can't call rescan_partitions directly. Use ioctl. */ - ioctl_by_bdev(bdev, BLKRRPART, 0); - blkdev_put(bdev); - } - } + if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0) + return -ENODEV; + /* + * See fs/partition/check.c:register_disk,rescan_partitions + * Can't call rescan_partitions directly. Use ioctl. + */ + ioctl_by_bdev(bdev, BLKRRPART, 0); + /* + * Since the matching blkdev_put call to the blkdev_get in + * this function is not called before dasd_destroy_partitions + * the offline open_count limit needs to be increased from + * 0 to 1. This is done by setting device->bdev (see + * dasd_generic_set_offline). As long as the partition + * detection is running no offline should be allowed. That + * is why the assignment to device->bdev is done AFTER + * the BLKRRPART ioctl. + */ + device->bdev = bdev; + return 0; } /* @@ -121,13 +132,32 @@ void dasd_destroy_partitions(struct dasd_device * device) { - int p; + /* The two structs have 168/176 byte on 31/64 bit. */ + struct blkpg_partition bpart; + struct blkpg_ioctl_arg barg; + struct block_device *bdev; + + /* + * Get the bdev pointer from the device structure and clear + * device->bdev to lower the offline open_count limit again. + */ + bdev = device->bdev; + device->bdev = 0; + + /* + * See fs/partition/check.c:delete_partition + * Can't call delete_partitions directly. Use ioctl. + * The ioctl also does locking and invalidation. + */ + memset(&bpart, sizeof(struct blkpg_partition), 0); + memset(&barg, sizeof(struct blkpg_ioctl_arg), 0); + barg.data = &bpart; + for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) + ioctl_by_bdev(bdev, BLKPG_DEL_PARTITION, (unsigned long) &barg); - for (p = device->gdp->minors - 1; p > 0; p--) { - invalidate_partition(device->gdp, p); - delete_partition(device->gdp, p); - } invalidate_partition(device->gdp, 0); + /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ + blkdev_put(bdev); set_capacity(device->gdp, 0); } diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h --- a/drivers/s390/block/dasd_int.h Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/block/dasd_int.h Sat Apr 3 19:38:54 2004 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.54 $ + * $Revision: 1.56 $ */ #ifndef DASD_INT_H @@ -268,14 +268,12 @@ struct gendisk *gdp; request_queue_t *request_queue; spinlock_t request_queue_lock; + struct block_device *bdev; unsigned int devindex; unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ - int ro_flag; /* read-only flag */ - int use_diag_flag; /* diag allowed flag */ - int disconnect_error_flag; /* return -EIO when disconnected */ - + unsigned long flags; /* per device flags */ /* Device discipline stuff. */ struct dasd_discipline *discipline; @@ -318,6 +316,11 @@ #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ #define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */ +/* per device flags */ +#define DASD_FLAG_RO 0 /* device is read-only */ +#define DASD_FLAG_USE_DIAG 1 /* use diag disciplnie */ +#define DASD_FLAG_DSC_ERROR 2 /* return -EIO when disconnected */ +#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ void dasd_put_device_wake(struct dasd_device *); @@ -485,6 +488,8 @@ void dasd_delete_device(struct dasd_device *); int dasd_add_sysfs_files(struct ccw_device *); +void dasd_remove_sysfs_files(struct ccw_device *); + struct dasd_device *dasd_device_from_cdev(struct ccw_device *); struct dasd_device *dasd_device_from_devindex(int); @@ -496,7 +501,7 @@ void dasd_gendisk_exit(void); int dasd_gendisk_alloc(struct dasd_device *); void dasd_gendisk_free(struct dasd_device *); -void dasd_scan_partitions(struct dasd_device *); +int dasd_scan_partitions(struct dasd_device *); void dasd_destroy_partitions(struct dasd_device *); /* externals in dasd_ioctl.c */ diff -Nru a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c --- a/drivers/s390/block/dasd_ioctl.c Sat Apr 3 19:38:44 2004 +++ b/drivers/s390/block/dasd_ioctl.c Sat Apr 3 19:38:44 2004 @@ -303,7 +303,7 @@ if (device == NULL) return -ENODEV; - if (device->ro_flag) + if (test_bit(DASD_FLAG_RO, &device->flags)) return -EROFS; if (copy_from_user(&fdata, (void *) args, sizeof (struct format_data_t))) @@ -415,8 +415,8 @@ (dasd_check_blocksize(device->bp_block))) dasd_info->format = DASD_FORMAT_NONE; - dasd_info->features |= device->ro_flag ? DASD_FEATURE_READONLY - : DASD_FEATURE_DEFAULT; + dasd_info->features |= test_bit(DASD_FLAG_RO, &device->flags) ? + DASD_FEATURE_READONLY : DASD_FEATURE_DEFAULT; if (device->discipline) memcpy(dasd_info->type, device->discipline->name, 4); @@ -472,7 +472,10 @@ if (device == NULL) return -ENODEV; set_disk_ro(bdev->bd_disk, intval); - device->ro_flag = intval; + if (intval) + set_bit(DASD_FLAG_RO, &device->flags); + else + clear_bit(DASD_FLAG_RO, &device->flags); return 0; } diff -Nru a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c --- a/drivers/s390/block/dasd_proc.c Sat Apr 3 19:38:41 2004 +++ b/drivers/s390/block/dasd_proc.c Sat Apr 3 19:38:41 2004 @@ -9,7 +9,7 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.26 $ + * $Revision: 1.27 $ */ #include @@ -77,7 +77,7 @@ else seq_printf(m, " is ????????"); /* Print devices features. */ - substr = device->ro_flag ? "(ro)" : " "; + substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " "; seq_printf(m, "%4s: ", substr); /* Print device status information. */ switch ((device != NULL) ? device->state : -1) { diff -Nru a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile --- a/drivers/s390/char/Makefile Sat Apr 3 19:38:43 2004 +++ b/drivers/s390/char/Makefile Sat Apr 3 19:38:43 2004 @@ -18,6 +18,6 @@ tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o tape-$(CONFIG_PROC_FS) += tape_proc.o -tape-objs := tape_core.o tape_std.o tape_char.o tape_class.o $(tape-y) -obj-$(CONFIG_S390_TAPE) += tape.o +tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) +obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o diff -Nru a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c --- a/drivers/s390/char/sclp.c Sat Apr 3 19:38:44 2004 +++ b/drivers/s390/char/sclp.c Sat Apr 3 19:38:44 2004 @@ -335,8 +335,8 @@ unsigned long psw_mask; unsigned long cr0, cr0_sync; - /* Need to irq_enter() to prevent BH from executing. */ - irq_enter(); + /* Prevent BH from executing. */ + local_bh_disable(); /* * save cr0 * enable service signal external interruption (cr0.22) @@ -365,7 +365,7 @@ /* restore cr0 */ __ctl_load(cr0, 0, 0); - irq_exit(); + __local_bh_enable(); } /* diff -Nru a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h --- a/drivers/s390/char/tape.h Sat Apr 3 19:38:45 2004 +++ b/drivers/s390/char/tape.h Sat Apr 3 19:38:45 2004 @@ -198,9 +198,10 @@ /* entry in tape_device_list */ struct list_head node; + int cdev_id; struct ccw_device * cdev; - struct cdev * nt; - struct cdev * rt; + struct tape_class_device * nt; + struct tape_class_device * rt; /* Device discipline information. */ struct tape_discipline * discipline; @@ -263,8 +264,8 @@ extern int tape_mtop(struct tape_device *, int, int); extern void tape_state_set(struct tape_device *, enum tape_state); -extern int tape_enable_device(struct tape_device *, struct tape_discipline *); -extern void tape_disable_device(struct tape_device *device); +extern int tape_generic_online(struct tape_device *, struct tape_discipline *); +extern int tape_generic_offline(struct tape_device *device); /* Externals from tape_devmap.c */ extern int tape_generic_probe(struct ccw_device *); diff -Nru a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c --- a/drivers/s390/char/tape_34xx.c Sat Apr 3 19:38:42 2004 +++ b/drivers/s390/char/tape_34xx.c Sat Apr 3 19:38:42 2004 @@ -202,8 +202,7 @@ tape_34xx_delete_sbid_from(device, 0); tape_34xx_schedule_work(device, TO_MSEN); } else { - DBF_EVENT(3, "unsol.irq! dev end: %s\n", - device->cdev->dev.bus_id); + DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } @@ -1314,17 +1313,18 @@ }; static int -tape_34xx_enable(struct ccw_device *cdev) +tape_34xx_online(struct ccw_device *cdev) { - return tape_enable_device(cdev->dev.driver_data, - &tape_discipline_34xx); + return tape_generic_online( + cdev->dev.driver_data, + &tape_discipline_34xx + ); } static int -tape_34xx_disable(struct ccw_device *cdev) +tape_34xx_offline(struct ccw_device *cdev) { - tape_disable_device(cdev->dev.driver_data); - return 0; + return tape_generic_offline(cdev->dev.driver_data); } static struct ccw_driver tape_34xx_driver = { @@ -1333,8 +1333,8 @@ .ids = tape_34xx_ids, .probe = tape_generic_probe, .remove = tape_generic_remove, - .set_online = tape_34xx_enable, - .set_offline = tape_34xx_disable, + .set_online = tape_34xx_online, + .set_offline = tape_34xx_offline, }; static int @@ -1342,7 +1342,7 @@ { int rc; - DBF_EVENT(3, "34xx init: $Revision: 1.18 $\n"); + DBF_EVENT(3, "34xx init: $Revision: 1.19 $\n"); /* Register driver for 3480/3490 tapes. */ rc = ccw_driver_register(&tape_34xx_driver); if (rc) @@ -1361,7 +1361,7 @@ MODULE_DEVICE_TABLE(ccw, tape_34xx_ids); MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH"); MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape " - "device driver ($Revision: 1.18 $)"); + "device driver ($Revision: 1.19 $)"); MODULE_LICENSE("GPL"); module_init(tape_34xx_init); diff -Nru a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c --- a/drivers/s390/char/tape_block.c Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/char/tape_block.c Sat Apr 3 19:38:54 2004 @@ -274,12 +274,19 @@ flush_scheduled_work(); device->blk_data.requeue_task.data = tape_put_device(device); + if (!device->blk_data.disk) { + PRINT_ERR("(%s): No gendisk to clean up!\n", + device->cdev->dev.bus_id); + goto cleanup_queue; + } + del_gendisk(device->blk_data.disk); device->blk_data.disk->private_data = tape_put_device(device->blk_data.disk->private_data); put_disk(device->blk_data.disk); device->blk_data.disk = NULL; +cleanup_queue: device->blk_data.request_queue->queuedata = tape_put_device(device); blk_cleanup_queue(device->blk_data.request_queue); diff -Nru a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c --- a/drivers/s390/char/tape_char.c Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/char/tape_char.c Sat Apr 3 19:38:54 2004 @@ -48,38 +48,29 @@ static int tapechar_major = TAPECHAR_MAJOR; -struct cdev * -tapechar_register_tape_dev(struct tape_device *device, char *name, int i) -{ - struct cdev * cdev; - char devname[11]; - - sprintf(devname, "%s%i", name, i / 2); - cdev = register_tape_dev( - &device->cdev->dev, - MKDEV(tapechar_major, i), - &tape_fops, - devname - ); - - return ((IS_ERR(cdev)) ? NULL : cdev); -} - /* * This function is called for every new tapedevice */ int tapechar_setup_device(struct tape_device * device) { - device->nt = tapechar_register_tape_dev( - device, - "ntibm", - device->first_minor + char device_name[20]; + + sprintf(device_name, "ntibm%i", device->first_minor / 2); + device->nt = register_tape_dev( + &device->cdev->dev, + MKDEV(tapechar_major, device->first_minor), + &tape_fops, + device_name, + "non-rewinding" ); - device->rt = tapechar_register_tape_dev( - device, - "rtibm", - device->first_minor + 1 + device_name[0] = 'r'; + device->rt = register_tape_dev( + &device->cdev->dev, + MKDEV(tapechar_major, device->first_minor + 1), + &tape_fops, + device_name, + "rewinding" ); return 0; @@ -500,9 +491,6 @@ tapechar_major = MAJOR(dev); PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev)); -#ifdef TAPE390_INTERNAL_CLASS - tape_setup_class(); -#endif return 0; } @@ -512,9 +500,6 @@ void tapechar_exit(void) { -#ifdef TAPE390_INTERNAL_CLASS - tape_cleanup_class(); -#endif PRINT_INFO("tape releases major %d for character devices\n", tapechar_major); unregister_chrdev_region(MKDEV(tapechar_major, 0), 256); diff -Nru a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c --- a/drivers/s390/char/tape_class.c Sat Apr 3 19:38:55 2004 +++ b/drivers/s390/char/tape_class.c Sat Apr 3 19:38:55 2004 @@ -1,4 +1,7 @@ /* + * (C) Copyright IBM Corp. 2004 + * tape_class.c ($Revision: 1.6 $) + * * Tape class device support * * Author: Stefan Bader @@ -6,11 +9,12 @@ */ #include "tape_class.h" -#ifndef TAPE390_INTERNAL_CLASS MODULE_AUTHOR("Stefan Bader "); -MODULE_DESCRIPTION("Tape class"); +MODULE_DESCRIPTION( + "(C) Copyright IBM Corp. 2004 All Rights Reserved.\n" + "tape_class.c ($Revision: 1.6 $)" +); MODULE_LICENSE("GPL"); -#endif struct class_simple *tape_class; @@ -29,72 +33,94 @@ * devname * The pointer to the name of the character device. */ -struct cdev *register_tape_dev( +struct tape_class_device *register_tape_dev( struct device * device, dev_t dev, struct file_operations *fops, - char * devname -) { - struct cdev * cdev; + char * device_name, + char * mode_name) +{ + struct tape_class_device * tcd; int rc; char * s; - cdev = cdev_alloc(); - if (!cdev) + tcd = kmalloc(sizeof(struct tape_class_device), GFP_KERNEL); + if (!tcd) return ERR_PTR(-ENOMEM); - cdev->owner = fops->owner; - cdev->ops = fops; - cdev->dev = dev; - strcpy(cdev->kobj.name, devname); - for (s = strchr(cdev->kobj.name, '/'); s; s = strchr(s, '/')) + memset(tcd, 0, sizeof(struct tape_class_device)); + strncpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN); + for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/')) + *s = '!'; + strncpy(tcd->mode_name, mode_name, TAPECLASS_NAME_LEN); + for (s = strchr(tcd->mode_name, '/'); s; s = strchr(s, '/')) *s = '!'; - rc = cdev_add(cdev, cdev->dev, 1); - if (rc) { - kobject_put(&cdev->kobj); - return ERR_PTR(rc); + tcd->char_device = cdev_alloc(); + if (!tcd->char_device) { + rc = -ENOMEM; + goto fail_with_tcd; } - class_simple_device_add(tape_class, cdev->dev, device, "%s", devname); - return cdev; + tcd->char_device->owner = fops->owner; + tcd->char_device->ops = fops; + tcd->char_device->dev = dev; + + rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1); + if (rc) + goto fail_with_cdev; + + tcd->class_device = class_simple_device_add( + tape_class, + tcd->char_device->dev, + device, + "%s", tcd->device_name + ); + sysfs_create_link( + &device->kobj, + &tcd->class_device->kobj, + tcd->mode_name + ); + + return tcd; + +fail_with_cdev: + cdev_del(&tcd->char_device); + +fail_with_tcd: + kfree(tcd); + + return ERR_PTR(rc); } EXPORT_SYMBOL(register_tape_dev); -void unregister_tape_dev(struct cdev *cdev) +void unregister_tape_dev(struct tape_class_device *tcd) { - if (cdev != NULL) { - class_simple_device_remove(cdev->dev); - cdev_del(cdev); + if (tcd != NULL && !IS_ERR(tcd)) { + sysfs_remove_link( + &tcd->class_device->dev->kobj, + tcd->mode_name + ); + class_simple_device_remove(tcd->char_device->dev); + cdev_del(tcd->char_device); + kfree(tcd); } } EXPORT_SYMBOL(unregister_tape_dev); -#ifndef TAPE390_INTERNAL_CLASS static int __init tape_init(void) -#else -int tape_setup_class(void) -#endif { tape_class = class_simple_create(THIS_MODULE, "tape390"); + return 0; } -#ifndef TAPE390_INTERNAL_CLASS static void __exit tape_exit(void) -#else -void tape_cleanup_class(void) -#endif { class_simple_destroy(tape_class); tape_class = NULL; } -#ifndef TAPE390_INTERNAL_CLASS postcore_initcall(tape_init); module_exit(tape_exit); -#else -EXPORT_SYMBOL(tape_setup_class); -EXPORT_SYMBOL(tape_cleanup_class); -#endif diff -Nru a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h --- a/drivers/s390/char/tape_class.h Sat Apr 3 19:38:42 2004 +++ b/drivers/s390/char/tape_class.h Sat Apr 3 19:38:42 2004 @@ -1,4 +1,7 @@ /* + * (C) Copyright IBM Corp. 2004 All Rights Reserved. + * tape_class.h ($Revision: 1.4 $) + * * Tape class device support * * Author: Stefan Bader @@ -7,11 +10,8 @@ #ifndef __TAPE_CLASS_H__ #define __TAPE_CLASS_H__ -#if 0 #include #include -#endif - #include #include #include @@ -21,34 +21,41 @@ #include #include -#define TAPE390_INTERNAL_CLASS +#define TAPECLASS_NAME_LEN 32 + +struct tape_class_device { + struct cdev * char_device; + struct class_device * class_device; + char device_name[TAPECLASS_NAME_LEN]; + char mode_name[TAPECLASS_NAME_LEN]; +}; /* - * Register a tape device and return a pointer to the cdev structure. + * Register a tape device and return a pointer to the tape class device + * created by the call. * * device * The pointer to the struct device of the physical (base) device. - * drivername - * The pointer to the drivers name for it's character devices. * dev * The intended major/minor number. The major number may be 0 to * get a dynamic major number. * fops * The pointer to the drivers file operations for the tape device. - * devname - * The pointer to the name of the character device. + * device_name + * Pointer to the logical device name (will also be used as kobject name + * of the cdev). This can also be called the name of the tape class + * device. + * mode_name + * Points to the name of the tape mode. This creates a link with that + * name from the physical device to the logical device (class). */ -struct cdev *register_tape_dev( +struct tape_class_device *register_tape_dev( struct device * device, dev_t dev, struct file_operations *fops, - char * devname + char * device_name, + char * node_name ); -void unregister_tape_dev(struct cdev *cdev); - -#ifdef TAPE390_INTERNAL_CLASS -int tape_setup_class(void); -void tape_cleanup_class(void); -#endif +void unregister_tape_dev(struct tape_class_device *tcd); #endif /* __TAPE_CLASS_H__ */ diff -Nru a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c --- a/drivers/s390/char/tape_core.c Sat Apr 3 19:38:42 2004 +++ b/drivers/s390/char/tape_core.c Sat Apr 3 19:38:42 2004 @@ -69,6 +69,34 @@ [TO_UNASSIGN] = "UAS" }; +static inline int +busid_to_int(char *bus_id) +{ + int dec; + int d; + char * s; + + for(s = bus_id, d = 0; *s != '\0' && *s != '.'; s++) + d = (d * 10) + (*s - '0'); + dec = d; + for(s++, d = 0; *s != '\0' && *s != '.'; s++) + d = (d * 10) + (*s - '0'); + dec = (dec << 8) + d; + + for(s++; *s != '\0'; s++) { + if (*s >= '0' && *s <= '9') { + d = *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + d = *s - 'a' + 10; + } else { + d = *s - 'A' + 10; + } + dec = (dec << 4) + d; + } + + return dec; +} + /* * Some channel attached tape specific attributes. * @@ -296,10 +324,15 @@ } /* - * Enable tape device + * Set a device online. + * + * This function is called by the common I/O layer to move a device from the + * detected but offline into the online state. + * If we return an error (RC < 0) the device remains in the offline state. This + * can happen if the device is assigned somewhere else, for example. */ int -tape_enable_device(struct tape_device *device, +tape_generic_online(struct tape_device *device, struct tape_discipline *discipline) { int rc; @@ -328,6 +361,9 @@ goto out_char; tape_state_set(device, TS_UNUSED); + + DBF_LH(3, "(%08x): Drive set online\n", device->cdev_id); + return 0; out_char: @@ -342,37 +378,49 @@ } /* - * Disable tape device. Check if there is a running request and - * terminate it. Post all queued requests with -EIO. + * Set device offline. + * + * Called by the common I/O layer if the drive should set offline on user + * request. We may prevent this by returning an error. + * Manual offline is only allowed while the drive is not in use. */ -void -tape_disable_device(struct tape_device *device) +int +tape_generic_offline(struct tape_device *device) { - struct list_head *l, *n; - struct tape_request *request; + if (!device) { + PRINT_ERR("tape_generic_offline: no such device\n"); + return -ENODEV; + } + + DBF_LH(3, "(%08x): tape_generic_offline(%p)\n", + device->cdev_id, device); spin_lock_irq(get_ccwdev_lock(device->cdev)); - /* Post remaining requests with -EIO */ - list_for_each_safe(l, n, &device->req_queue) { - request = list_entry(l, struct tape_request, list); - if (request->status == TAPE_REQUEST_IN_IO) - __tape_halt_io(device, request); - list_del(&request->list); - /* Decrease ref_count for removed request. */ - request->device = tape_put_device(device); - request->rc = -EIO; - if (request->callback != NULL) - request->callback(request, request->callback_data); + switch (device->tape_state) { + case TS_INIT: + case TS_NOT_OPER: + break; + case TS_UNUSED: + tapeblock_cleanup_device(device); + tapechar_cleanup_device(device); + device->discipline->cleanup_device(device); + tape_remove_minor(device); + default: + DBF_EVENT(3, "(%08x): Set offline failed " + "- drive in use.\n", + device->cdev_id); + PRINT_WARN("(%s): Set offline failed " + "- drive in use.\n", + device->cdev->dev.bus_id); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + return -EBUSY; } spin_unlock_irq(get_ccwdev_lock(device->cdev)); - tapeblock_cleanup_device(device); - tapechar_cleanup_device(device); - device->discipline->cleanup_device(device); - tape_remove_minor(device); - tape_med_state_set(device, MS_UNKNOWN); - device->tape_state = TS_INIT; + + DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id); + return 0; } /* @@ -479,14 +527,14 @@ tape_generic_probe(struct ccw_device *cdev) { struct tape_device *device; - char *bus_id = cdev->dev.bus_id; device = tape_alloc_device(); if (IS_ERR(device)) return -ENODEV; - PRINT_INFO("tape device %s found\n", bus_id); + PRINT_INFO("tape device %s found\n", cdev->dev.bus_id); cdev->dev.driver_data = device; device->cdev = cdev; + device->cdev_id = busid_to_int(cdev->dev.bus_id); cdev->handler = __tape_do_irq; ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); @@ -497,15 +545,58 @@ /* * Driverfs tape remove function. + * + * This function is called whenever the common I/O layer detects the device + * gone. This can happen at any time and we cannot refuse. */ void tape_generic_remove(struct ccw_device *cdev) { - ccw_device_set_offline(cdev); + struct tape_device * device; + struct tape_request * request; + struct list_head * l, *n; + + device = cdev->dev.driver_data; + DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev); + + /* + * No more requests may be processed. So just post them as i/o errors. + */ + spin_lock_irq(get_ccwdev_lock(device->cdev)); + list_for_each_safe(l, n, &device->req_queue) { + request = list_entry(l, struct tape_request, list); + if (request->status == TAPE_REQUEST_IN_IO) + request->status = TAPE_REQUEST_DONE; + list_del(&request->list); + + /* Decrease ref_count for removed request. */ + request->device = tape_put_device(device); + request->rc = -EIO; + if (request->callback != NULL) + request->callback(request, request->callback_data); + } + + if (device->tape_state != TS_UNUSED && device->tape_state != TS_INIT) { + DBF_EVENT(3, "(%08x): Drive in use vanished!\n", + device->cdev_id); + PRINT_WARN("(%s): Drive in use vanished - expect trouble!\n", + device->cdev->dev.bus_id); + PRINT_WARN("State was %i\n", device->tape_state); + device->tape_state = TS_NOT_OPER; + tapeblock_cleanup_device(device); + tapechar_cleanup_device(device); + device->discipline->cleanup_device(device); + tape_remove_minor(device); + } + device->tape_state = TS_NOT_OPER; + tape_med_state_set(device, MS_UNKNOWN); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + if (cdev->dev.driver_data != NULL) { sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group); cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data); } + } /* @@ -665,7 +756,7 @@ op = "---"; DBF_EVENT(3, "DSTAT : %02x CSTAT: %02x\n", irb->scsw.dstat,irb->scsw.cstat); - DBF_EVENT(3, "DEVICE: %s OP\t: %s\n", device->cdev->dev.bus_id,op); + DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op); sptr = (unsigned int *) irb->ecw; DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]); DBF_EVENT(3, "%08x %08x\n", sptr[2], sptr[3]); @@ -815,7 +906,7 @@ spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = __tape_halt_io(device, request); if (rc == 0) { - DBF_EVENT(3, "IO stopped on %s\n", device->cdev->dev.bus_id); + DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id); rc = -ERESTARTSYS; } spin_unlock_irq(get_ccwdev_lock(device->cdev)); @@ -823,6 +914,24 @@ } /* + * Handle requests that return an i/o error in the irb. + */ +static inline void +tape_handle_killed_request( + struct tape_device *device, + struct tape_request *request) +{ + if(request != NULL) { + /* Set ending status. FIXME: Should the request be retried? */ + request->rc = -EIO; + request->status = TAPE_REQUEST_DONE; + __tape_remove_request(device, request); + } else { + __tape_do_io_list(device); + } +} + +/* * Tape interrupt routine, called from the ccw_device layer */ static void @@ -835,7 +944,7 @@ device = (struct tape_device *) cdev->dev.driver_data; if (device == NULL) { - PRINT_ERR("could not get device structure for bus_id %s " + PRINT_ERR("could not get device structure for %s " "in interrupt\n", cdev->dev.bus_id); return; } @@ -843,6 +952,23 @@ DBF_LH(6, "__tape_do_irq(device=%p, request=%p)\n", device, request); + /* On special conditions irb is an error pointer */ + if (IS_ERR(irb)) { + switch (PTR_ERR(irb)) { + case -ETIMEDOUT: + PRINT_WARN("(%s): Request timed out\n", + cdev->dev.bus_id); + case -EIO: + tape_handle_killed_request(device, request); + break; + default: + PRINT_ERR("(%s): Unexpected i/o error %li\n", + cdev->dev.bus_id, + PTR_ERR(irb)); + } + return; + } + /* May be an unsolicited irq */ if(request != NULL) request->rescnt = irb->scsw.count; @@ -1023,7 +1149,7 @@ #ifdef DBF_LIKE_HELL debug_set_level(tape_dbf_area, 6); #endif - DBF_EVENT(3, "tape init: ($Revision: 1.44 $)\n"); + DBF_EVENT(3, "tape init: ($Revision: 1.48 $)\n"); tape_proc_init(); tapechar_init (); tapeblock_init (); @@ -1048,7 +1174,7 @@ MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and " "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)"); MODULE_DESCRIPTION("Linux on zSeries channel attached " - "tape device driver ($Revision: 1.44 $)"); + "tape device driver ($Revision: 1.48 $)"); MODULE_LICENSE("GPL"); module_init(tape_init); @@ -1056,9 +1182,9 @@ EXPORT_SYMBOL(tape_dbf_area); EXPORT_SYMBOL(tape_generic_remove); -EXPORT_SYMBOL(tape_disable_device); EXPORT_SYMBOL(tape_generic_probe); -EXPORT_SYMBOL(tape_enable_device); +EXPORT_SYMBOL(tape_generic_online); +EXPORT_SYMBOL(tape_generic_offline); EXPORT_SYMBOL(tape_put_device); EXPORT_SYMBOL(tape_get_device_reference); EXPORT_SYMBOL(tape_state_verbose); diff -Nru a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c --- a/drivers/s390/char/tape_std.c Sat Apr 3 19:38:40 2004 +++ b/drivers/s390/char/tape_std.c Sat Apr 3 19:38:40 2004 @@ -42,8 +42,8 @@ spin_lock_irq(get_ccwdev_lock(device->cdev)); if (request->callback != NULL) { - DBF_EVENT(3, "%s: Assignment timeout. Device busy.\n", - device->cdev->dev.bus_id); + DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n", + device->cdev_id); PRINT_ERR("%s: Assignment timeout. Device busy.\n", device->cdev->dev.bus_id); ccw_device_clear(device->cdev, (long) request); @@ -84,10 +84,10 @@ if (rc != 0) { PRINT_WARN("%s: assign failed - device might be busy\n", device->cdev->dev.bus_id); - DBF_EVENT(3, "%s: assign failed - device might be busy\n", - device->cdev->dev.bus_id); + DBF_EVENT(3, "%08x: assign failed - device might be busy\n", + device->cdev_id); } else { - DBF_EVENT(3, "%s: Tape assigned\n", device->cdev->dev.bus_id); + DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id); } tape_free_request(request); return rc; @@ -102,6 +102,14 @@ int rc; struct tape_request *request; + if (device->tape_state == TS_NOT_OPER) { + DBF_EVENT(3, "(%08x): Can't unassign device\n", + device->cdev_id); + PRINT_WARN("(%s): Can't unassign device - device gone\n", + device->cdev->dev.bus_id); + return -EIO; + } + request = tape_alloc_request(2, 11); if (IS_ERR(request)) return PTR_ERR(request); @@ -111,10 +119,10 @@ tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL); if ((rc = tape_do_io(device, request)) != 0) { - DBF_EVENT(3, "%s: Unassign failed\n", device->cdev->dev.bus_id); + DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id); PRINT_WARN("%s: Unassign failed\n", device->cdev->dev.bus_id); } else { - DBF_EVENT(3, "%s: Tape unassigned\n", device->cdev->dev.bus_id); + DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id); } tape_free_request(request); return rc; diff -Nru a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c --- a/drivers/s390/cio/blacklist.c Sat Apr 3 19:38:42 2004 +++ b/drivers/s390/cio/blacklist.c Sat Apr 3 19:38:42 2004 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.29 $ + * $Revision: 1.31 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -72,7 +72,10 @@ blacklist_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; - + char *sav; + + sav = *str; + /* check for leading '0x' */ old_style = 0; if ((*str)[0] == '0' && (*str)[1] == 'x') { @@ -80,44 +83,54 @@ old_style = 1; } if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; + goto confused; val = simple_strtoul(*str, str, 16); if (old_style || (*str)[0] != '.') { *id0 = *id1 = 0; if (val < 0 || val > 0xffff) - return -EINVAL; + goto confused; *devno = val; + if ((*str)[0] != ',' && (*str)[0] != '-' && + (*str)[0] != '\n' && (*str)[0] != '\0') + goto confused; return 0; } /* New style x.y.z busid */ if (val < 0 || val > 0xff) - return -EINVAL; + goto confused; *id0 = val; (*str)++; if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; + goto confused; val = simple_strtoul(*str, str, 16); if (val < 0 || val > 0xff || (*str)++[0] != '.') - return -EINVAL; + goto confused; *id1 = val; if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; + goto confused; val = simple_strtoul(*str, str, 16); if (val < 0 || val > 0xffff) - return -EINVAL; + goto confused; *devno = val; + if ((*str)[0] != ',' && (*str)[0] != '-' && + (*str)[0] != '\n' && (*str)[0] != '\0') + goto confused; return 0; +confused: + strsep(str, ",\n"); + printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav); + return 1; } static inline int blacklist_parse_parameters (char *str, range_action action) { unsigned int from, to, from_id0, to_id0, from_id1, to_id1; - char *sav; - sav = str; while (*str != 0 && *str != '\n') { range_action ra = action; + while(*str == ',') + str++; if (*str == '!') { ra = !action; ++str; @@ -138,32 +151,37 @@ rc = blacklist_busid(&str, &from_id0, &from_id1, &from); if (rc) - goto out_err; + continue; to = from; to_id0 = from_id0; to_id1 = from_id1; if (*str == '-') { str++; - rc = blacklist_busid(&str, &to_id0, &to_id1, - &to); + rc = blacklist_busid(&str, &to_id0, + &to_id1, &to); if (rc) - goto out_err; + continue; + } + if (*str == '-') { + printk(KERN_WARNING "invalid cio_ignore " + "parameter '%s'\n", + strsep(&str, ",\n")); + continue; + } + if ((from_id0 != to_id0) || (from_id1 != to_id1)) { + printk(KERN_WARNING "invalid cio_ignore range " + "%x.%x.%04x-%x.%x.%04x\n", + from_id0, from_id1, from, + to_id0, to_id1, to); + continue; } - if ((from_id0 != to_id0) || (from_id1 != to_id1)) - goto out_err; } /* FIXME: ignoring id0 and id1 here. */ pr_debug("blacklist_setup: adding range " "from 0.0.%04x to 0.0.%04x\n", from, to); blacklist_range (ra, from, to); - - if (*str == ',') - str++; } return 1; -out_err: - printk(KERN_WARNING "blacklist_setup: error parsing \"%s\"\n", sav); - return 0; } /* Parsing the commandline for blacklist parameters, e.g. to blacklist diff -Nru a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c --- a/drivers/s390/cio/ccwgroup.c Sat Apr 3 19:38:44 2004 +++ b/drivers/s390/cio/ccwgroup.c Sat Apr 3 19:38:44 2004 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.24 $ + * $Revision: 1.25 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -102,8 +102,10 @@ gdev = to_ccwgroupdev(dev); - for (i = 0; i < gdev->count; i++) + for (i = 0; i < gdev->count; i++) { + gdev->cdev[i]->dev.driver_data = NULL; put_device(&gdev->cdev[i]->dev); + } kfree(gdev); } @@ -155,6 +157,7 @@ struct ccwgroup_device *gdev; int i; int rc; + int del_drvdata; if (argc > 256) /* disallow dumb users */ return -EINVAL; @@ -166,6 +169,7 @@ memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0])); atomic_set(&gdev->onoff, 0); + del_drvdata = 0; for (i = 0; i < argc; i++) { gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); @@ -177,7 +181,15 @@ rc = -EINVAL; goto error; } + /* Don't allow a device to belong to more than one group. */ + if (gdev->cdev[i]->dev.driver_data) { + rc = -EINVAL; + goto error; + } } + for (i = 0; i < argc; i++) + gdev->cdev[i]->dev.driver_data = gdev; + del_drvdata = 1; *gdev = (struct ccwgroup_device) { .creator_id = creator_id, @@ -212,9 +224,11 @@ device_unregister(&gdev->dev); error: for (i = 0; i < argc; i++) - if (gdev->cdev[i]) + if (gdev->cdev[i]) { put_device(&gdev->cdev[i]->dev); - + if (del_drvdata) + gdev->cdev[i]->dev.driver_data = NULL; + } kfree(gdev); return rc; @@ -399,40 +413,14 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; - struct list_head *entry; - struct device *dev; - int i, found; - - /* - * Find groupdevice cdev belongs to. - * Unfortunately, we can't use bus_for_each_dev() because of the - * semaphore (and return value of fn() is int). - */ - if (!get_bus(&ccwgroup_bus_type)) - return NULL; - - gdev = NULL; - down_read(&ccwgroup_bus_type.subsys.rwsem); - list_for_each(entry, &ccwgroup_bus_type.devices.list) { - dev = get_device(container_of(entry, struct device, bus_list)); - found = 0; - if (!dev) - continue; - gdev = to_ccwgroupdev(dev); - for (i = 0; i < gdev->count && (!found); i++) { - if (gdev->cdev[i] == cdev) - found = 1; - } - if (found) - break; - put_device(dev); - gdev = NULL; + if (cdev->dev.driver_data) { + gdev = (struct ccwgroup_device *)cdev->dev.driver_data; + if (get_device(&gdev->dev)) + return gdev; + return NULL; } - up_read(&ccwgroup_bus_type.subsys.rwsem); - put_bus(&ccwgroup_bus_type); - - return gdev; + return NULL; } void diff -Nru a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h --- a/drivers/s390/cio/css.h Sat Apr 3 19:38:57 2004 +++ b/drivers/s390/cio/css.h Sat Apr 3 19:38:57 2004 @@ -82,6 +82,7 @@ unsigned int dosense:1; /* delayed SENSE required */ unsigned int doverify:1; /* delayed path verification */ unsigned int donotify:1; /* call notify function */ + unsigned int recog_done:1; /* dev. recog. complete */ } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; diff -Nru a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c --- a/drivers/s390/cio/device.c Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/cio/device.c Sat Apr 3 19:38:54 2004 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.107 $ + * $Revision: 1.110 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -263,10 +263,10 @@ if (!cdev) return -ENODEV; - if (!cdev->online) + if (!cdev->online || !cdev->drv) return -EINVAL; - if (cdev->drv && cdev->drv->set_offline) { + if (cdev->drv->set_offline) { ret = cdev->drv->set_offline(cdev); if (ret != 0) return ret; @@ -292,7 +292,7 @@ if (!cdev) return -ENODEV; - if (cdev->online) + if (cdev->online || !cdev->drv) return -EINVAL; spin_lock_irq(cdev->ccwlock); @@ -307,8 +307,7 @@ } if (cdev->private->state != DEV_STATE_ONLINE) return -ENODEV; - if (!cdev->drv || !cdev->drv->set_online || - cdev->drv->set_online(cdev) == 0) { + if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { cdev->online = 1; return 0; } @@ -327,7 +326,7 @@ online_store (struct device *dev, const char *buf, size_t count) { struct ccw_device *cdev = to_ccwdev(dev); - int i, force; + int i, force, ret; char *tmp; if (atomic_compare_and_swap(0, 1, &cdev->private->onoff)) @@ -347,29 +346,46 @@ if (i == 1) { /* Do device recognition, if needed. */ if (cdev->id.cu_type == 0) { - ccw_device_recognition(cdev); + ret = ccw_device_recognition(cdev); + if (ret) { + printk(KERN_WARNING"Couldn't start recognition " + "for device %s (ret=%d)\n", + cdev->dev.bus_id, ret); + goto out; + } wait_event(cdev->private->wait_q, - dev_fsm_final_state(cdev)); + cdev->private->flags.recog_done); } - ccw_device_set_online(cdev); + if (cdev->drv && cdev->drv->set_online) + ccw_device_set_online(cdev); } else if (i == 0) { if (cdev->private->state == DEV_STATE_DISCONNECTED) ccw_device_remove_disconnected(cdev); - else + else if (cdev->drv && cdev->drv->set_offline) ccw_device_set_offline(cdev); } if (force && cdev->private->state == DEV_STATE_BOXED) { - int ret; ret = ccw_device_stlck(cdev); - if (ret) + if (ret) { + printk(KERN_WARNING"ccw_device_stlck for device %s " + "returned %d!\n", cdev->dev.bus_id, ret); goto out; + } /* Do device recognition, if needed. */ if (cdev->id.cu_type == 0) { - ccw_device_recognition(cdev); + cdev->private->state = DEV_STATE_NOT_OPER; + ret = ccw_device_recognition(cdev); + if (ret) { + printk(KERN_WARNING"Couldn't start recognition " + "for device %s (ret=%d)\n", + cdev->dev.bus_id, ret); + goto out; + } wait_event(cdev->private->wait_q, - dev_fsm_final_state(cdev)); + cdev->private->flags.recog_done); } - ccw_device_set_online(cdev); + if (cdev->drv && cdev->drv->set_online) + ccw_device_set_online(cdev); } out: if (cdev->drv) @@ -530,7 +546,9 @@ __func__, sch->dev.bus_id); put_device(&cdev->dev); out: + cdev->private->flags.recog_done = 1; put_device(&sch->dev); + wake_up(&cdev->private->wait_q); } static void @@ -555,10 +573,13 @@ { struct subchannel *sch; - if (css_init_done == 0) + if (css_init_done == 0) { + cdev->private->flags.recog_done = 1; return; + } switch (cdev->private->state) { case DEV_STATE_NOT_OPER: + cdev->private->flags.recog_done = 1; /* Remove device found not operational. */ if (!get_device(&cdev->dev)) break; diff -Nru a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c --- a/drivers/s390/cio/device_fsm.c Sat Apr 3 19:38:43 2004 +++ b/drivers/s390/cio/device_fsm.c Sat Apr 3 19:38:43 2004 @@ -148,6 +148,7 @@ struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); + cdev->private->flags.recog_done = 1; /* * Check if cu type and device type still match. If * not, it is certainly another device and we have to @@ -217,6 +218,7 @@ __recover_lost_chpids(sch, old_lpm); if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { if (state == DEV_STATE_NOT_OPER) { + cdev->private->flags.recog_done = 1; cdev->private->state = DEV_STATE_DISCONNECTED; return; } @@ -393,6 +395,7 @@ * timeout (or if sense pgid during path verification detects the device * is locked, as may happen on newer devices). */ + cdev->private->flags.recog_done = 0; cdev->private->state = DEV_STATE_SENSE_ID; ccw_device_sense_id_start(cdev); return 0; @@ -728,6 +731,9 @@ (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (cdev->handler) cdev->handler (cdev, 0, irb); + if (irb->scsw.cc == 1) + /* Basic sense hasn't started. Try again. */ + ccw_device_do_sense(cdev, irb); return; } /* Add basic sense info to irb. */ @@ -825,6 +831,8 @@ (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (cdev->handler) cdev->handler (cdev, 0, irb); + if (irb->scsw.cc == 1) + goto call_handler; return; } /* @@ -838,6 +846,7 @@ } return; } +call_handler: /* Iff device is idle, reset timeout. */ sch = to_subchannel(cdev->dev.parent); if (!stsch(sch->irq, &sch->schib)) @@ -905,6 +914,8 @@ /* Check for unsolicited interrupt. */ if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) + /* FIXME: we should restart stlck here, but this + * is extremely unlikely ... */ goto out_wakeup; ccw_device_accumulate_irb(cdev, irb); diff -Nru a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c --- a/drivers/s390/cio/device_ops.c Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/cio/device_ops.c Sat Apr 3 19:38:54 2004 @@ -79,7 +79,8 @@ if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE || - sch->schib.scsw.actl != 0 || + ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || cdev->private->flags.doverify) return -EBUSY; ret = cio_set_options (sch, flags); @@ -347,7 +348,9 @@ cdev->handler = ccw_device_wake_up; if (cdev->private->state != DEV_STATE_ONLINE) ret = -ENODEV; - else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify) + else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || + cdev->private->flags.doverify) ret = -EBUSY; else /* 0x00D9C4C3 == ebcdic "RDC" */ @@ -414,7 +417,9 @@ cdev->handler = ccw_device_wake_up; if (cdev->private->state != DEV_STATE_ONLINE) ret = -ENODEV; - else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify) + else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || + cdev->private->flags.doverify) ret = -EBUSY; else /* 0x00D9C3C4 == ebcdic "RCD" */ @@ -441,12 +446,12 @@ } /* - * Try to issue an unconditional reserve on a boxed device. + * Try to break the lock on a boxed device. */ int ccw_device_stlck(struct ccw_device *cdev) { - char buf[32]; + void *buf, *buf2; unsigned long flags; struct subchannel *sch; int ret; @@ -462,16 +467,30 @@ CIO_TRACE_EVENT(2, "stl lock"); CIO_TRACE_EVENT(2, cdev->dev.bus_id); + buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf2 = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL); + if (!buf2) { + kfree(buf); + return -ENOMEM; + } spin_lock_irqsave(&sch->lock, flags); ret = cio_enable_subchannel(sch, 3); if (ret) goto out_unlock; - /* Setup ccw. This cmd code seems not to be in use elsewhere. */ + /* + * Setup ccw. We chain an unconditional reserve and a release so we + * only break the lock. + */ cdev->private->iccws[0].cmd_code = CCW_CMD_STLCK; cdev->private->iccws[0].cda = (__u32) __pa(buf); cdev->private->iccws[0].count = 32; - cdev->private->iccws[0].flags = CCW_FLAG_SLI; - + cdev->private->iccws[0].flags = CCW_FLAG_CC; + cdev->private->iccws[1].cmd_code = CCW_CMD_RELEASE; + cdev->private->iccws[1].cda = (__u32) __pa(buf2); + cdev->private->iccws[1].count = 32; + cdev->private->iccws[1].flags = 0; ret = cio_start(sch, cdev->private->iccws, 0); if (ret) { cio_disable_subchannel(sch); //FIXME: return code? @@ -486,10 +505,13 @@ (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) || (cdev->private->irb.scsw.cstat != 0)) ret = -EIO; - /* Clear irb. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); out_unlock: + if (buf) + kfree(buf); + if (buf2) + kfree(buf2); spin_unlock_irqrestore(&sch->lock, flags); return ret; } diff -Nru a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c --- a/drivers/s390/cio/device_status.c Sat Apr 3 19:38:43 2004 +++ b/drivers/s390/cio/device_status.c Sat Apr 3 19:38:43 2004 @@ -99,7 +99,7 @@ static inline int ccw_device_accumulate_esw_valid(struct irb *irb) { - if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) + if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) return 0; if (irb->scsw.stctl == (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) && diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c --- a/drivers/s390/cio/qdio.c Sat Apr 3 19:38:44 2004 +++ b/drivers/s390/cio/qdio.c Sat Apr 3 19:38:44 2004 @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.74 $" +#define VERSION_QDIO_C "$Revision: 1.78 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -545,6 +545,7 @@ qdio_kick_outbound_q(struct qdio_q *q) { int result; + char dbf_text[15]; QDIO_DBF_TEXT4(0,trace,"kickoutq"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -552,15 +553,75 @@ if (!q->siga_out) return; - result=qdio_siga_output(q); + /* here's the story with cc=2 and busy bit set (thanks, Rick): + * VM's CP could present us cc=2 and busy bit set on SIGA-write + * during reconfiguration of their Guest LAN (only in HIPERS mode, + * QDIO mode is asynchronous -- cc=2 and busy bit there will take + * the queues down immediately; and not being under VM we have a + * problem on cc=2 and busy bit set right away). + * + * Therefore qdio_siga_output will try for a short time constantly, + * if such a condition occurs. If it doesn't change, it will + * increase the busy_siga_counter and save the timestamp, and + * schedule the queue for later processing (via mark_q, using the + * queue tasklet). __qdio_outbound_processing will check out the + * counter. If non-zero, it will call qdio_kick_outbound_q as often + * as the value of the counter. This will attempt further SIGA + * instructions. For each successful SIGA, the counter is + * decreased, for failing SIGAs the counter remains the same, after + * all. + * After some time of no movement, qdio_kick_outbound_q will + * finally fail and reflect corresponding error codes to call + * the upper layer module and have it take the queues down. + * + * Note that this is a change from the original HiperSockets design + * (saying cc=2 and busy bit means take the queues down), but in + * these days Guest LAN didn't exist... excessive cc=2 with busy bit + * conditions will still take the queues down, but the threshold is + * higher due to the Guest LAN environment. + */ - if (!result) - return; - if (q->siga_error) - q->error_status_flags|=QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR; - q->error_status_flags |= QDIO_STATUS_LOOK_FOR_ERROR; - q->siga_error=result; + result=qdio_siga_output(q); + + switch (result) { + case 0: + /* went smooth this time, reset timestamp */ + QDIO_DBF_TEXT3(0,trace,"cc2reslv"); + sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no, + atomic_read(&q->busy_siga_counter)); + QDIO_DBF_TEXT3(0,trace,dbf_text); + q->timing.busy_start=0; + break; + case (2|QDIO_SIGA_ERROR_B_BIT_SET): + /* cc=2 and busy bit: */ + atomic_inc(&q->busy_siga_counter); + + /* if the last siga was successful, save + * timestamp here */ + if (!q->timing.busy_start) + q->timing.busy_start=NOW; + + /* if we're in time, don't touch error_status_flags + * and siga_error */ + if (NOW-q->timing.busy_startirq,q->q_no, + atomic_read(&q->busy_siga_counter)); + QDIO_DBF_TEXT3(0,trace,dbf_text); + /* else fallthrough and report error */ + default: + /* for plain cc=1, 2 or 3: */ + if (q->siga_error) + q->error_status_flags|= + QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR; + q->error_status_flags|= + QDIO_STATUS_LOOK_FOR_ERROR; + q->siga_error=result; + } } inline static void @@ -599,6 +660,8 @@ static inline void __qdio_outbound_processing(struct qdio_q *q) { + int siga_attempts; + QDIO_DBF_TEXT4(0,trace,"qoutproc"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -619,6 +682,14 @@ perf_stats.tl_runs++; #endif /* QDIO_PERFORMANCE_STATS */ + /* see comment in qdio_kick_outbound_q */ + siga_attempts=atomic_read(&q->busy_siga_counter); + while (siga_attempts) { + atomic_dec(&q->busy_siga_counter); + qdio_kick_outbound_q(q); + siga_attempts--; + } + if (qdio_has_outbound_q_moved(q)) qdio_kick_outbound_handler(q); @@ -1368,6 +1439,10 @@ ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: &qdio_inbound_processing); + /* actually this is not used for inbound queues. yet. */ + atomic_set(&q->busy_siga_counter,0); + q->timing.busy_start=0; + /* for (j=0;jtiming.last_transfer_times[j]=(qdio_get_micros()/ QDIO_STATS_NUMBER)*j; @@ -1432,6 +1507,9 @@ q->tasklet.func=(void(*)(unsigned long)) &qdio_outbound_processing; + atomic_set(&q->busy_siga_counter,0); + q->timing.busy_start=0; + /* fill in slib */ if (i>0) irq_ptr->output_qs[i-1]->slib->nsliba= (unsigned long)(q->slib); @@ -2134,7 +2212,7 @@ QDIO_DBF_TEXT0(0,setup,dbf_text); rc = qdio_shutdown(cdev, how); - if (rc == 0) + if ((rc == 0) || (rc == -EINPROGRESS)) rc = qdio_free(cdev); return rc; } @@ -2145,6 +2223,7 @@ struct qdio_irq *irq_ptr; int i; int result = 0; + int rc; unsigned long flags; int timeout; char dbf_text[15]; @@ -2191,27 +2270,23 @@ result=-EINPROGRESS; } - if (result) - goto out; - /* cleanup subchannel */ spin_lock_irqsave(get_ccwdev_lock(cdev),flags); if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) { - result = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); + rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_CLEAR_TIMEOUT; } else if (how&QDIO_FLAG_CLEANUP_USING_HALT) { - result = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); + rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_HALT_TIMEOUT; } else { /* default behaviour */ - result = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); + rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_HALT_TIMEOUT; } - if (result == -ENODEV) { + if (rc == -ENODEV) { /* No need to wait for device no longer present. */ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); - result = 0; /* No error. */ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); - } else if (result == 0) { + } else if (rc == 0) { qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); ccw_device_set_timeout(cdev, timeout); spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); @@ -2223,6 +2298,7 @@ QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " "device %s\n", result, cdev->dev.bus_id); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + result = rc; goto out; } if (irq_ptr->is_thinint_irq) { diff -Nru a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h --- a/drivers/s390/cio/qdio.h Sat Apr 3 19:38:41 2004 +++ b/drivers/s390/cio/qdio.h Sat Apr 3 19:38:41 2004 @@ -1,7 +1,7 @@ #ifndef _CIO_QDIO_H #define _CIO_QDIO_H -#define VERSION_CIO_QDIO_H "$Revision: 1.22 $" +#define VERSION_CIO_QDIO_H "$Revision: 1.23 $" //#define QDIO_DBF_LIKE_HELL @@ -33,7 +33,8 @@ #define TIQDIO_THININT_ISC 3 #define TIQDIO_DELAY_TARGET 0 -#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */ +#define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */ +#define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */ #define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */ #define IQDIO_GLOBAL_LAPS_INT 1 /* don't global summary */ #define IQDIO_LOCAL_LAPS 4 @@ -599,7 +600,9 @@ int last_transfer_index; */ __u64 last_transfer_time; + __u64 busy_start; } timing; + atomic_t busy_siga_counter; unsigned int queue_type; /* leave this member at the end. won't be cleared in qdio_fill_qs */ diff -Nru a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c --- a/drivers/s390/net/ctcmain.c Sat Apr 3 19:38:42 2004 +++ b/drivers/s390/net/ctcmain.c Sat Apr 3 19:38:42 2004 @@ -1,5 +1,5 @@ /* - * $Id: ctcmain.c,v 1.56 2004/02/27 17:53:26 mschwide Exp $ + * $Id: ctcmain.c,v 1.58 2004/03/24 10:51:56 ptiedem Exp $ * * CTC / ESCON network driver * @@ -36,7 +36,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.56 $ + * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.58 $ * */ @@ -319,7 +319,7 @@ print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.56 $"; + char vbuf[] = "$Revision: 1.58 $"; char *version = vbuf; if (printed) @@ -2067,7 +2067,8 @@ return; } - priv = cdev->dev.driver_data; + priv = ((struct ccwgroup_device *)cdev->dev.driver_data) + ->dev.driver_data; /* Try to extract channel from driver data. */ if (priv->channel[READ]->cdev == cdev) @@ -2963,8 +2964,6 @@ cgdev->cdev[0]->handler = ctc_irq_handler; cgdev->cdev[1]->handler = ctc_irq_handler; cgdev->dev.driver_data = priv; - cgdev->cdev[0]->dev.driver_data = priv; - cgdev->cdev[1]->dev.driver_data = priv; return 0; } @@ -3043,26 +3042,13 @@ privptr->channel[direction]->protocol = privptr->protocol; privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT; } + /* sysfs magic */ + SET_NETDEV_DEV(dev, &cgdev->dev); + if (ctc_netdev_register(dev) != 0) { ctc_free_netdevice(dev, 1); goto out; } - /* Create symlinks. */ - if (sysfs_create_link(&cgdev->dev.kobj, &dev->class_dev.kobj, - dev->name)) { - ctc_netdev_unregister(dev); - dev->priv = 0; - ctc_free_netdevice(dev, 1); - goto out; - } - if (sysfs_create_link(&dev->class_dev.kobj, &cgdev->dev.kobj, - cgdev->dev.bus_id)) { - sysfs_remove_link(&cgdev->dev.kobj, dev->name); - ctc_netdev_unregister(dev); - dev->priv = 0; - ctc_free_netdevice(dev, 1); - goto out; - } ctc_add_attributes(&cgdev->dev); @@ -3118,8 +3104,6 @@ channel_free(priv->channel[WRITE]); if (ndev) { - sysfs_remove_link(&ndev->class_dev.kobj, cgdev->dev.bus_id); - sysfs_remove_link(&cgdev->dev.kobj, ndev->name); ctc_netdev_unregister(ndev); ndev->priv = NULL; ctc_free_netdevice(ndev, 1); diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c --- a/drivers/s390/net/iucv.c Sat Apr 3 19:38:41 2004 +++ b/drivers/s390/net/iucv.c Sat Apr 3 19:38:41 2004 @@ -1,5 +1,5 @@ /* - * $Id: iucv.c,v 1.24 2004/02/05 14:16:01 braunu Exp $ + * $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.24 $ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.27 $ * */ @@ -351,7 +351,7 @@ static void iucv_banner(void) { - char vbuf[] = "$Revision: 1.24 $"; + char vbuf[] = "$Revision: 1.27 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -374,14 +374,14 @@ { int ret; + if (iucv_external_int_buffer) + return 0; + if (!MACHINE_IS_VM) { printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); return -EPROTONOSUPPORT; } - if (iucv_external_int_buffer) - return 0; - ret = bus_register(&iucv_bus); if (ret != 0) { printk(KERN_ERR "IUCV: failed to register bus.\n"); @@ -670,10 +670,12 @@ ulong b2f0_result = 0x0deadbeef; iucv_debug(1, "entering"); + preempt_disable(); if (smp_processor_id() == 0) iucv_declare_buffer_cpu0(&b2f0_result); else smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1); + preempt_enable(); iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); if (b2f0_result == 0x0deadbeef) b2f0_result = 0xaa; @@ -692,11 +694,13 @@ { iucv_debug(1, "entering"); if (declare_flag) { + preempt_disable(); if (smp_processor_id() == 0) iucv_retrieve_buffer_cpu0(0); else smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1); declare_flag = 0; + preempt_enable(); } iucv_debug(1, "exiting"); return 0; @@ -826,7 +830,7 @@ memset (new_handler->id.mask, 0xFF, sizeof (new_handler->id.mask)); } - memset (new_handler->id.mask, 0x00, + memset (new_handler->id.userid, 0x00, sizeof (new_handler->id.userid)); } /* fill in the rest of handler */ @@ -2216,10 +2220,12 @@ } u; u.param = SetMaskFlag; + preempt_disable(); if (smp_processor_id() == 0) iucv_setmask_cpu0(&u); else smp_call_function(iucv_setmask_cpu0, &u, 0, 1); + preempt_enable(); return u.result; } @@ -2519,10 +2525,6 @@ /** * Export all public stuff - * FIXME: I have commented out all the functions that - * are not used in netiucv. Is anyone else - * using them or should some of them be made - * static / removed? pls review. Arnd */ EXPORT_SYMBOL (iucv_bus); EXPORT_SYMBOL (iucv_root); diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c --- a/drivers/s390/net/lcs.c Sat Apr 3 19:38:41 2004 +++ b/drivers/s390/net/lcs.c Sat Apr 3 19:38:41 2004 @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky * - * $Revision: 1.67 $ $Date: 2004/02/26 18:26:50 $ + * $Revision: 1.72 $ $Date: 2004/03/22 09:34:27 $ * * 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 @@ -58,9 +58,10 @@ /** * initialization string for output */ -#define VERSION_LCS_C "$Revision: 1.67 $" +#define VERSION_LCS_C "$Revision: 1.72 $" static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; +static char debug_buffer[255]; /** * Some prototypes. @@ -112,7 +113,7 @@ { int cnt; - LCS_DBF_TEXT(3, setup, "ichalloc"); + LCS_DBF_TEXT(2, setup, "ichalloc"); for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { /* alloc memory fo iobuffer */ channel->iob[cnt].data = (void *) @@ -124,7 +125,7 @@ } if (cnt < LCS_NUM_BUFFS) { /* Not all io buffers could be allocated. */ - LCS_DBF_TEXT(3, setup, "echalloc"); + LCS_DBF_TEXT(2, setup, "echalloc"); while (cnt-- > 0) kfree(channel->iob[cnt].data); return -ENOMEM; @@ -140,7 +141,7 @@ { int cnt; - LCS_DBF_TEXT(3, setup, "ichfree"); + LCS_DBF_TEXT(2, setup, "ichfree"); for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { if (channel->iob[cnt].data != NULL) kfree(channel->iob[cnt].data); @@ -148,6 +149,30 @@ } } +/* + * Cleanup channel. + */ +static void +lcs_cleanup_channel(struct lcs_channel *channel) +{ + LCS_DBF_TEXT(3, setup, "cleanch"); + /* Kill write channel tasklets. */ + tasklet_kill(&channel->irq_tasklet); + /* Free channel buffers. */ + lcs_free_channel(channel); +} + +/** + * LCS free memory for card and channels. + */ +static void +lcs_free_card(struct lcs_card *card) +{ + LCS_DBF_TEXT(2, setup, "remcard"); + LCS_DBF_HEX(2, setup, &card, sizeof(void*)); + kfree(card); +} + /** * LCS alloc memory for card and channels */ @@ -155,25 +180,34 @@ lcs_alloc_card(void) { struct lcs_card *card; + int rc; + + LCS_DBF_TEXT(2, setup, "alloclcs"); - LCS_DBF_TEXT(3, setup, "alloclcs"); card = kmalloc(sizeof(struct lcs_card), GFP_KERNEL | GFP_DMA); if (card == NULL) return NULL; memset(card, 0, sizeof(struct lcs_card)); card->lan_type = LCS_FRAME_TYPE_AUTO; card->lancmd_timeout = LCS_LANCMD_TIMEOUT_DEFAULT; - return card; -} + /* Allocate io buffers for the read channel. */ + rc = lcs_alloc_channel(&card->read); + if (rc){ + LCS_DBF_TEXT(2, setup, "iccwerr"); + lcs_free_card(card); + return NULL; + } + /* Allocate io buffers for the write channel. */ + rc = lcs_alloc_channel(&card->write); + if (rc) { + LCS_DBF_TEXT(2, setup, "iccwerr"); + lcs_cleanup_channel(&card->read); + lcs_free_card(card); + return NULL; + } -/** - * LCS free memory for card and channels. - */ -static void -lcs_free_card(struct lcs_card *card) -{ - LCS_DBF_TEXT(2, setup, "remcard"); - kfree(card); + LCS_DBF_HEX(2, setup, &card, sizeof(void*)); + return card; } /* @@ -218,25 +252,17 @@ card->read.buf_idx = 0; } -static int +static void lcs_setup_read(struct lcs_card *card) { - int rc; + LCS_DBF_TEXT(3, setup, "initread"); - LCS_DBF_TEXT(3, setup, "readirq"); - /* Allocate io buffers for the read channel. */ - rc = lcs_alloc_channel(&card->read); - if (rc){ - LCS_DBF_TEXT(3, setup, "iccwerr"); - return rc; - } lcs_setup_read_ccws(card); /* Initialize read channel tasklet. */ card->read.irq_tasklet.data = (unsigned long) &card->read; card->read.irq_tasklet.func = lcs_tasklet; /* Initialize waitqueue. */ init_waitqueue_head(&card->read.wait_q); - return 0; } /* @@ -247,7 +273,7 @@ { int cnt; - LCS_DBF_TEXT(2, setup, "iwritccw"); + LCS_DBF_TEXT(3, setup, "iwritccw"); /* Setup write ccws. */ memset(card->write.ccws, 0, sizeof(struct ccw1) * LCS_NUM_BUFFS + 1); for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { @@ -273,61 +299,32 @@ card->write.buf_idx = 0; } -static int +static void lcs_setup_write(struct lcs_card *card) { - int rc; + LCS_DBF_TEXT(3, setup, "initwrit"); - LCS_DBF_TEXT(3, setup, "writeirq"); - /* Allocate io buffers for the write channel. */ - rc = lcs_alloc_channel(&card->write); - if (rc) { - LCS_DBF_TEXT(3, setup, "iccwerr"); - return rc; - } lcs_setup_write_ccws(card); /* Initialize write channel tasklet. */ card->write.irq_tasklet.data = (unsigned long) &card->write; card->write.irq_tasklet.func = lcs_tasklet; /* Initialize waitqueue. */ init_waitqueue_head(&card->write.wait_q); - return 0; } -/* - * Cleanup channel. - */ -static void -lcs_cleanup_channel(struct lcs_channel *channel) -{ - LCS_DBF_TEXT(3, setup, "cleanch"); - /* Kill write channel tasklets. */ - tasklet_kill(&channel->irq_tasklet); - /* Free channel buffers. */ - lcs_free_channel(channel); -} + /** * Initialize channels,card and state machines. */ -static int +static void lcs_setup_card(struct lcs_card *card) { - int rc; - - LCS_DBF_TEXT(3, setup, "initcard"); + LCS_DBF_TEXT(2, setup, "initcard"); + LCS_DBF_HEX(2, setup, &card, sizeof(void*)); - rc = lcs_setup_read(card); - if (rc) { - PRINT_ERR("Could not initialize read channel\n"); - return rc; - } - rc = lcs_setup_write(card); - if (rc) { - PRINT_ERR("Could not initialize write channel\n"); - lcs_cleanup_channel(&card->read); - return rc; - } + lcs_setup_read(card); + lcs_setup_write(card); /* Set cards initial state. */ card->state = DEV_STATE_DOWN; card->tx_buffer = NULL; @@ -342,7 +339,6 @@ INIT_LIST_HEAD(&card->ipm_list); #endif INIT_LIST_HEAD(&card->lancmd_waiters); - return 0; } /** @@ -355,6 +351,7 @@ struct lcs_ipm_list *ipm_list; LCS_DBF_TEXT(3, setup, "cleancrd"); + LCS_DBF_HEX(2,setup,&card,sizeof(void*)); #ifdef CONFIG_IP_MULTICAST /* Free multicast list. */ list_for_each_safe(l, n, &card->ipm_list) { @@ -376,12 +373,10 @@ static int lcs_start_channel(struct lcs_channel *channel) { - char dbf_text[15]; unsigned long flags; int rc; - sprintf(dbf_text,"ssch%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_start(channel->ccwdev, channel->ccws + channel->io_idx, 0, 0, @@ -390,37 +385,56 @@ channel->state = CH_STATE_RUNNING; spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - sprintf(dbf_text,"essc%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); PRINT_ERR("Error in starting channel, rc=%d!\n", rc); } return rc; } +static int +lcs_clear_channel(struct lcs_channel *channel) +{ + unsigned long flags; + int rc; + + LCS_DBF_TEXT(4,trace,"clearch"); + LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); + spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + rc = ccw_device_clear(channel->ccwdev, (addr_t) channel); + spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + if (rc) { + LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); + return rc; + } + wait_event(channel->wait_q, (channel->state == CH_STATE_CLEARED)); + channel->state = CH_STATE_STOPPED; + return rc; +} + + /** * Stop channel. */ static int lcs_stop_channel(struct lcs_channel *channel) { - char dbf_text[15]; unsigned long flags; int rc; if (channel->state == CH_STATE_STOPPED) return 0; - sprintf(dbf_text,"hsch%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT(4,trace,"haltsch"); + LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - sprintf(dbf_text,"ehsc%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id); return rc; } /* Asynchronous halt initialted. Wait for its completion. */ wait_event(channel->wait_q, (channel->state == CH_STATE_HALTED)); + lcs_clear_channel(channel); return 0; } @@ -464,6 +478,7 @@ { int index; + LCS_DBF_TEXT(5, trace, "_getbuff"); index = channel->io_idx; do { if (channel->iob[index].state == BUF_STATE_EMPTY) { @@ -481,6 +496,7 @@ struct lcs_buffer *buffer; unsigned long flags; + LCS_DBF_TEXT(5, trace, "getbuff"); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); buffer = __lcs_get_buffer(channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); @@ -493,19 +509,16 @@ static int __lcs_resume_channel(struct lcs_channel *channel) { - char dbf_text[15]; int rc; if (channel->state != CH_STATE_SUSPENDED) return 0; if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) return 0; - sprintf(dbf_text,"rsch%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id); rc = ccw_device_resume(channel->ccwdev); if (rc) { - sprintf(dbf_text,"ersc%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(4, trace, dbf_text); + LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); } else channel->state = CH_STATE_RUNNING; @@ -521,6 +534,7 @@ { int prev, next; + LCS_DBF_TEXT(5, trace, "rdybits"); prev = (index - 1) & (LCS_NUM_BUFFS - 1); next = (index + 1) & (LCS_NUM_BUFFS - 1); /* Check if we may clear the suspend bit of this buffer. */ @@ -540,6 +554,7 @@ unsigned long flags; int index, rc; + LCS_DBF_TEXT(5, trace, "rdybuff"); if (buffer->state != BUF_STATE_LOCKED && buffer->state != BUF_STATE_PROCESSED) BUG(); @@ -565,6 +580,7 @@ { int index, prev, next; + LCS_DBF_TEXT(5, trace, "prcsbuff"); if (buffer->state != BUF_STATE_READY) BUG(); buffer->state = BUF_STATE_PROCESSED; @@ -597,6 +613,7 @@ { unsigned long flags; + LCS_DBF_TEXT(5, trace, "relbuff"); if (buffer->state != BUF_STATE_LOCKED && buffer->state != BUF_STATE_PROCESSED) BUG(); @@ -614,6 +631,7 @@ struct lcs_buffer *buffer; struct lcs_cmd *cmd; + LCS_DBF_TEXT(4, trace, "getlncmd"); /* Get buffer and wait if none is available. */ wait_event(card->write.wait_q, ((buffer = lcs_get_buffer(&card->write)) != NULL)); @@ -637,6 +655,7 @@ struct list_head *l, *n; struct lcs_reply *reply; + LCS_DBF_TEXT(4, trace, "notiwait"); spin_lock(&card->lock); list_for_each_safe(l, n, &card->lancmd_waiters) { reply = list_entry(l, struct lcs_reply, list); @@ -661,6 +680,7 @@ { struct lcs_reply *reply; + LCS_DBF_TEXT(4, trace, "timeout"); reply = (struct lcs_reply *) data; list_del(&reply->list); reply->received = 1; @@ -676,8 +696,8 @@ struct lcs_cmd *cmd; struct timer_list timer; int rc; - char buf[16]; + LCS_DBF_TEXT(4, trace, "sendcmd"); cmd = (struct lcs_cmd *) buffer->data; cmd->sequence_no = ++card->sequence_no; cmd->return_code = 0; @@ -700,9 +720,7 @@ add_timer(&timer); wait_event(reply.wait_q, reply.received); del_timer(&timer); - LCS_DBF_TEXT(5, trace, "sendcmd"); - sprintf(buf, "rc:%d", reply.rc); - LCS_DBF_TEXT(5, trace, buf); + LCS_DBF_TEXT_(4, trace, "rc:%d",reply.rc); return reply.rc ? -EIO : 0; } @@ -747,6 +765,7 @@ static void __lcs_lanstat_cb(struct lcs_card *card, struct lcs_cmd *cmd) { + LCS_DBF_TEXT(2, trace, "statcb"); memcpy(card->mac, cmd->cmd.lcs_lanstat_cmd.mac_addr, LCS_MAC_LENGTH); } @@ -756,7 +775,7 @@ struct lcs_buffer *buffer; struct lcs_cmd *cmd; - LCS_DBF_TEXT(2, trace, "cmdstat"); + LCS_DBF_TEXT(2,trace, "cmdstat"); buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); cmd = (struct lcs_cmd *) buffer->data; /* Setup lanstat command. */ @@ -792,6 +811,7 @@ static void __lcs_send_startlan_cb(struct lcs_card *card, struct lcs_cmd *cmd) { + LCS_DBF_TEXT(2, trace, "srtlancb"); card->lan_type = cmd->cmd.lcs_std_cmd.lan_type; card->portno = cmd->cmd.lcs_std_cmd.portno; } @@ -833,6 +853,7 @@ cmd->cmd.lcs_qipassist.num_ip_pairs = 1; memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair, &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair)); + LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr); return lcs_send_lancmd(card, buffer, NULL); } @@ -856,6 +877,7 @@ cmd->cmd.lcs_qipassist.num_ip_pairs = 1; memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair, &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair)); + LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr); return lcs_send_lancmd(card, buffer, NULL); } @@ -865,6 +887,7 @@ static void __lcs_check_multicast_cb(struct lcs_card *card, struct lcs_cmd *cmd) { + LCS_DBF_TEXT(2, trace, "chkmccb"); card->ip_assists_supported = cmd->cmd.lcs_qipassist.ip_assists_supported; card->ip_assists_enabled = @@ -919,7 +942,7 @@ card = (struct lcs_card *) data; daemonize("fixipm"); - LCS_DBF_TEXT(5, trace, "fixipm"); + LCS_DBF_TEXT(4,trace, "fixipm"); spin_lock(&card->lock); list_for_each_safe(l, n, &card->ipm_list) { ipm = list_entry(l, struct lcs_ipm_list, list); @@ -952,6 +975,7 @@ static void lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) { + LCS_DBF_TEXT(4,trace, "getmac"); if (dev->type == ARPHRD_IEEE802_TR) ip_tr_mc_map(ipm, mac); else @@ -971,7 +995,7 @@ struct lcs_ipm_list *ipm, *tmp; struct lcs_card *card; - LCS_DBF_TEXT(5, trace, "setmulti"); + LCS_DBF_TEXT(4, trace, "setmulti"); in4_dev = in_dev_get(dev); if (in4_dev == NULL) return; @@ -1033,21 +1057,18 @@ static void lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { - char dbf_text[15]; struct lcs_card *card; struct lcs_channel *channel; int index; - card = (struct lcs_card *)cdev->dev.driver_data; + card = CARD_FROM_DEV(cdev); if (card->read.ccwdev == cdev) channel = &card->read; else channel = &card->write; - sprintf(dbf_text, "Rint%s", cdev->dev.bus_id); - LCS_DBF_TEXT(5, trace, dbf_text); - sprintf(dbf_text, "%4x%4x", irb->scsw.cstat, irb->scsw.dstat); - LCS_DBF_TEXT(5, trace, dbf_text); + LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); + LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); /* How far in the ccw chain have we processed? */ if ((channel->state != CH_STATE_INIT) && @@ -1084,6 +1105,9 @@ channel->state = CH_STATE_HALTED; } + if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { + channel->state = CH_STATE_CLEARED; + } /* Do the rest in the tasklet. */ tasklet_schedule(&channel->irq_tasklet); } @@ -1094,7 +1118,6 @@ static void lcs_tasklet(unsigned long data) { - char dbf_text[15]; unsigned long flags; struct lcs_channel *channel; struct lcs_buffer *iob; @@ -1102,8 +1125,7 @@ int rc; channel = (struct lcs_channel *) data; - sprintf(dbf_text, "tlet%s", channel->ccwdev->dev.bus_id); - LCS_DBF_TEXT(5, trace, dbf_text); + LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id); /* Check for processed buffers. */ iob = channel->iob; @@ -1137,6 +1159,7 @@ static void __lcs_emit_txbuffer(struct lcs_card *card) { + LCS_DBF_TEXT(5, trace, "emittx"); *(__u16 *)(card->tx_buffer->data + card->tx_buffer->count) = 0; card->tx_buffer->count += 2; lcs_ready_buffer(&card->write, card->tx_buffer); @@ -1152,6 +1175,7 @@ { struct lcs_card *card; + LCS_DBF_TEXT(5, trace, "txbuffcb"); /* Put buffer back to pool. */ lcs_release_buffer(channel, buffer); card = (struct lcs_card *) @@ -1176,6 +1200,7 @@ { struct lcs_header *header; + LCS_DBF_TEXT(5, trace, "hardxmit"); if (skb == NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; @@ -1201,7 +1226,6 @@ /* Get new tx buffer */ card->tx_buffer = lcs_get_buffer(&card->write); if (card->tx_buffer == NULL) { - netif_stop_queue(dev); card->stats.tx_dropped++; return -EBUSY; } @@ -1246,6 +1270,7 @@ { int rc; + LCS_DBF_TEXT(2, trace, "strtauto"); #ifdef CONFIG_NET_ETHERNET card->lan_type = LCS_FRAME_TYPE_ENET; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); @@ -1307,7 +1332,7 @@ { int rc = 0; - LCS_DBF_TEXT(3, setup," lcsdetct"); + LCS_DBF_TEXT(2, setup, "lcsdetct"); /* start/reset card */ if (card->dev) netif_stop_queue(card->dev); @@ -1340,7 +1365,7 @@ { int retries; - LCS_DBF_TEXT(4, trace, "rescard"); + LCS_DBF_TEXT(2, trace, "rescard"); for (retries = 0; retries < 10; retries++) { if (lcs_detect(card) == 0) { netif_wake_queue(card->dev); @@ -1364,13 +1389,16 @@ int rc; LCS_DBF_TEXT(3, setup, "stopcard"); + if (card->read.state != CH_STATE_STOPPED && card->write.state != CH_STATE_STOPPED && - card->state == DEV_STATE_UP) + card->state == DEV_STATE_UP) { rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); - rc = lcs_send_shutdown(card); + rc = lcs_send_shutdown(card); + } rc = lcs_stop_channels(card); card->state = DEV_STATE_DOWN; + return rc; } @@ -1492,6 +1520,7 @@ static void lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) { + LCS_DBF_TEXT(5, trace, "getctrl"); if (cmd->initiator == LCS_INITIATOR_LGW) { switch(cmd->cmd_code) { case LCS_CMD_STARTUP: @@ -1522,6 +1551,7 @@ { struct sk_buff *skb; + LCS_DBF_TEXT(5, trace, "getskb"); if (card->dev == NULL || card->state != DEV_STATE_UP) /* The card isn't up. Ignore the packet. */ @@ -1619,6 +1649,7 @@ LCS_DBF_TEXT(2, trace, "stopdev"); card = (struct lcs_card *) dev->priv; netif_stop_queue(dev); + dev->flags &= ~IFF_UP; rc = lcs_stopcard(card); if (rc) PRINT_ERR("Try it again!\n "); @@ -1643,6 +1674,7 @@ PRINT_ERR("LCS:Error in opening device!\n"); } else { + dev->flags |= IFF_UP; netif_wake_queue(dev); card->state = DEV_STATE_UP; } @@ -1757,7 +1789,7 @@ if (!get_device(&ccwgdev->dev)) return -ENODEV; - LCS_DBF_TEXT(3, setup, "add_dev"); + LCS_DBF_TEXT(2, setup, "add_dev"); card = lcs_alloc_card(); if (!card) { PRINT_ERR("Allocation of lcs card failed\n"); @@ -1772,46 +1804,62 @@ return ret; } ccwgdev->dev.driver_data = card; - ccwgdev->cdev[0]->dev.driver_data = card; ccwgdev->cdev[0]->handler = lcs_irq; - ccwgdev->cdev[1]->dev.driver_data = card; ccwgdev->cdev[1]->handler = lcs_irq; return 0; } +static int +lcs_register_netdev(struct ccwgroup_device *ccwgdev) +{ + struct lcs_card *card; + + LCS_DBF_TEXT(2, setup, "regnetdv"); + card = (struct lcs_card *)ccwgdev->dev.driver_data; + if (card->dev->reg_state != NETREG_UNINITIALIZED) + return 0; + SET_NETDEV_DEV(card->dev, &ccwgdev->dev); + return register_netdev(card->dev); +} + /** * lcs_new_device will be called by setting the group device online. */ + static int lcs_new_device(struct ccwgroup_device *ccwgdev) { struct lcs_card *card; - struct net_device *dev; + struct net_device *dev=NULL; + enum lcs_dev_states recover_state; int rc; card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return -ENODEV; + LCS_DBF_TEXT(2, setup, "newdev"); + LCS_DBF_HEX(3, setup, &card, sizeof(void*)); card->read.ccwdev = ccwgdev->cdev[0]; card->write.ccwdev = ccwgdev->cdev[1]; + recover_state = card->state; ccw_device_set_online(card->read.ccwdev); ccw_device_set_online(card->write.ccwdev); LCS_DBF_TEXT(3, setup, "lcsnewdv"); - rc = lcs_setup_card(card); - if (rc) { - LCS_DBF_TEXT(3, setup, "errinit"); - PRINT_ERR("LCS card Initialization failed\n"); - return rc; - } + lcs_setup_card(card); rc = lcs_detect(card); if (rc) { lcs_stopcard(card); lcs_cleanup_card(card); - return -ENODEV; + goto out; + } + if (card->dev) { + LCS_DBF_TEXT(2, setup, "samedev"); + LCS_DBF_HEX(3, setup, &card, sizeof(void*)); + goto netdev_out; } switch (card->lan_type) { #ifdef CONFIG_NET_ETHERNET @@ -1840,36 +1888,34 @@ } if (!dev) goto out; - memcpy(dev->dev_addr, card->mac, LCS_MAC_LENGTH); card->dev = dev; - dev->priv = card; - dev->open = lcs_open_device; - dev->stop = lcs_stop_device; - dev->hard_start_xmit = lcs_start_xmit; +netdev_out: + card->dev->priv = card; + card->dev->open = lcs_open_device; + card->dev->stop = lcs_stop_device; + card->dev->hard_start_xmit = lcs_start_xmit; + card->dev->get_stats = lcs_getstats; + SET_MODULE_OWNER(dev); + if (lcs_register_netdev(ccwgdev) != 0) + goto out; + memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); #ifdef CONFIG_IP_MULTICAST if (lcs_check_multicast_support(card)) - dev->set_multicast_list = lcs_set_multicast_list; + card->dev->set_multicast_list = lcs_set_multicast_list; #endif - dev->get_stats = lcs_getstats; - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) - goto out; - /* Create symlinks. */ - if (sysfs_create_link(&ccwgdev->dev.kobj, &dev->class_dev.kobj, - dev->name)) { - unregister_netdev(dev); - goto out; - } - if (sysfs_create_link(&dev->class_dev.kobj, &ccwgdev->dev.kobj, - ccwgdev->dev.bus_id)) { - sysfs_remove_link(&ccwgdev->dev.kobj, dev->name); - unregister_netdev(dev); - goto out; - } - netif_stop_queue(dev); - lcs_stopcard(card); + netif_stop_queue(card->dev); + if (recover_state == DEV_STATE_RECOVER) { + card->dev->flags |= IFF_UP; + netif_wake_queue(card->dev); + card->state = DEV_STATE_UP; + } else + lcs_stopcard(card); + return 0; out: + + ccw_device_set_offline(card->read.ccwdev); + ccw_device_set_offline(card->write.ccwdev); lcs_cleanup_card(card); return -ENODEV; } @@ -1881,6 +1927,7 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) { struct lcs_card *card; + enum lcs_dev_states recover_state; int ret; LCS_DBF_TEXT(3, setup, "shtdndev"); @@ -1888,12 +1935,17 @@ if (!card) return -ENODEV; + LCS_DBF_HEX(3, setup, &card, sizeof(void*)); + recover_state = card->state; + ret = lcs_stop_device(card->dev); + ret = ccw_device_set_offline(card->read.ccwdev); + ret = ccw_device_set_offline(card->write.ccwdev); + if (recover_state == DEV_STATE_UP) { + card->state = DEV_STATE_RECOVER; + } if (ret) return ret; - sysfs_remove_link(&card->dev->class_dev.kobj, ccwgdev->dev.bus_id); - sysfs_remove_link(&ccwgdev->dev.kobj, card->dev->name); - unregister_netdev(card->dev); return 0; } @@ -1905,17 +1957,17 @@ { struct lcs_card *card; - LCS_DBF_TEXT(3, setup, "remdev"); card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return; + + PRINT_INFO("Removing lcs group device ....\n"); + LCS_DBF_TEXT(3, setup, "remdev"); + LCS_DBF_HEX(3, setup, &card, sizeof(void*)); if (ccwgdev->state == CCWGROUP_ONLINE) { - lcs_stop_device(card->dev); /* Ignore rc. */ - sysfs_remove_link(&card->dev->class_dev.kobj, - ccwgdev->dev.bus_id); - sysfs_remove_link(&ccwgdev->dev.kobj, card->dev->name); - unregister_netdev(card->dev); + lcs_shutdown_device(ccwgdev); } + unregister_netdev(card->dev); sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group); lcs_cleanup_card(card); lcs_free_card(card); diff -Nru a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h --- a/drivers/s390/net/lcs.h Sat Apr 3 19:38:54 2004 +++ b/drivers/s390/net/lcs.h Sat Apr 3 19:38:54 2004 @@ -6,19 +6,36 @@ #include #include -#define VERSION_LCS_H "$Revision: 1.13 $" +#define VERSION_LCS_H "$Revision: 1.15 $" #define LCS_DBF_TEXT(level, name, text) \ do { \ debug_text_event(lcs_dbf_##name, level, text); \ } while (0) +#define LCS_DBF_HEX(level,name,addr,len) \ +do { \ + debug_event(lcs_dbf_##name,level,(void*)(addr),len); \ +} while (0) + +#define LCS_DBF_TEXT_(level,name,text...) \ +do { \ + sprintf(debug_buffer, text); \ + debug_text_event(lcs_dbf_##name,level, debug_buffer);\ +} while (0) + /** * some more definitions for debug or output stuff */ #define PRINTK_HEADER " lcs: " /** + * sysfs related stuff + */ +#define CARD_FROM_DEV(cdev) \ + (struct lcs_card *) \ + ((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data; +/** * CCW commands used in this driver */ #define LCS_CCW_WRITE 0x01 @@ -123,6 +140,7 @@ CH_STATE_STOPPED, CH_STATE_RUNNING, CH_STATE_SUSPENDED, + CH_STATE_CLEARED, }; /** @@ -131,6 +149,7 @@ enum lcs_dev_states { DEV_STATE_DOWN, DEV_STATE_UP, + DEV_STATE_RECOVER, }; /** diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c --- a/drivers/s390/net/netiucv.c Sat Apr 3 19:38:44 2004 +++ b/drivers/s390/net/netiucv.c Sat Apr 3 19:38:44 2004 @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.38 2004/02/19 13:12:57 mschwide Exp $ + * $Id: netiucv.c,v 1.47 2004/03/22 07:41:42 braunu Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.38 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.47 $ * */ @@ -229,6 +229,7 @@ "StartWait", "StopWait", "Running", + "StartRetry", }; /** @@ -251,6 +252,7 @@ "Stop", "Connection up", "Connection down", + "Timer", }; /** @@ -345,11 +347,6 @@ CONN_STATE_TX, /** - * Terminating - */ - CONN_STATE_TERM, - - /** * Error during registration. */ CONN_STATE_REGERR, @@ -495,7 +492,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) { struct net_device *dev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)dev->priv; + struct netiucv_priv *privptr = dev->priv; __u16 offset = 0; skb_put(pskb, NETIUCV_HDRLEN); @@ -767,7 +764,7 @@ { struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; - + __u16 msglimit; int rc; pr_debug("%s() called\n", __FUNCTION__); @@ -796,10 +793,11 @@ fsm_newstate(fi, CONN_STATE_SETUPWAIT); rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, NULL, conn->handle, + conn->userid, iucv_host, 0, NULL, &msglimit, conn->handle, conn); switch (rc) { case 0: + conn->netdev->tx_queue_len = msglimit; return; case 11: printk(KERN_NOTICE @@ -1214,7 +1212,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) { int rc = 0; - struct netiucv_priv *privptr = (struct netiucv_priv *)dev->priv; + struct netiucv_priv *privptr = dev->priv; /** * Some sanity checks ... @@ -1290,7 +1288,6 @@ /** * attributes in sysfs *****************************************************************************/ -#define CTRL_BUFSIZE 40 static ssize_t user_show (struct device *dev, char *buf) @@ -1300,7 +1297,57 @@ return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } -static DEVICE_ATTR(user, 0444, user_show, NULL); +static ssize_t +user_write (struct device *dev, const char *buf, size_t count) +{ + struct netiucv_priv *priv = dev->driver_data; + struct net_device *ndev = priv->conn->netdev; + char *p; + char *tmp; + char username[10]; + int i; + + if (count>9) { + printk(KERN_WARNING + "netiucv: username too long (%d)!\n", (int)count); + return -EINVAL; + } + + tmp = strsep((char **) &buf, "\n"); + for (i=0, p=tmp; i<8 && *p; i++, p++) { + if (isalnum(*p) || (*p == '$')) + username[i]= *p; + else if (*p == '\n') { + /* trailing lf, grr */ + break; + } else { + printk(KERN_WARNING + "netiucv: Invalid character in username!\n"); + return -EINVAL; + } + } + while (i<9) + username[i++] = ' '; + username[9] = '\0'; + + if (memcmp(username, priv->conn->userid, 8) != 0) { + /* username changed */ + if (ndev->flags & (IFF_UP | IFF_RUNNING)) { + printk(KERN_WARNING + "netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + printk(KERN_WARNING + "netiucv: user cannot be updated\n"); + return -EBUSY; + } + } + memcpy(priv->conn->userid, username, 9); + + return count; + +} + +static DEVICE_ATTR(user, 0644, user_show, user_write); static ssize_t buffer_show (struct device *dev, char *buf) @@ -1317,26 +1364,30 @@ struct net_device *ndev = priv->conn->netdev; char *e; int bs1; - char tmp[CTRL_BUFSIZE]; if (count >= 39) return -EINVAL; - if (copy_from_user(tmp, buf, count)) - return -EFAULT; - tmp[count+1] = '\0'; - bs1 = simple_strtoul(tmp, &e, 0); + bs1 = simple_strtoul(buf, &e, 0); + + if (e && (!isspace(*e))) { + printk(KERN_WARNING + "netiucv: Invalid character in buffer!\n"); + return -EINVAL; + } + if (bs1 > NETIUCV_BUFSIZE_MAX) { + printk(KERN_WARNING + "netiucv: Given buffer size %d too large.\n", + bs1); - if ((bs1 > NETIUCV_BUFSIZE_MAX) || - (e && (!isspace(*e)))) return -EINVAL; + } if ((ndev->flags & IFF_RUNNING) && (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) return -EINVAL; if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) return -EINVAL; - priv->conn->max_buffsize = bs1; if (!(ndev->flags & IFF_RUNNING)) ndev->mtu = bs1 - NETIUCV_HDRLEN - NETIUCV_HDRLEN; @@ -1606,20 +1657,10 @@ ret = netiucv_add_files(dev); if (ret) goto out_unreg; - ret = sysfs_create_link(&dev->kobj, &ndev->class_dev.kobj, ndev->name); - if (ret) - goto out_rm_files; - ret = sysfs_create_link(&ndev->class_dev.kobj, &dev->kobj, dev->bus_id); - if (ret) - goto out_rm_link; dev->driver_data = priv; priv->dev = dev; return 0; -out_rm_link: - sysfs_remove_link(&dev->kobj, ndev->name); -out_rm_files: - netiucv_remove_files(dev); out_unreg: device_unregister(dev); return ret; @@ -1628,12 +1669,7 @@ static void netiucv_unregister_device(struct device *dev) { - struct netiucv_priv *priv = dev->driver_data; - struct net_device *ndev = priv->conn->netdev; - pr_debug("%s() called\n", __FUNCTION__); - sysfs_remove_link(&ndev->class_dev.kobj, dev->bus_id); - sysfs_remove_link(&dev->kobj, ndev->name); netiucv_remove_files(dev); device_unregister(dev); } @@ -1814,7 +1850,7 @@ { char *p; char username[10]; - int i; + int i, ret; struct net_device *dev; if (count>9) { @@ -1846,30 +1882,37 @@ return -ENODEV; } - if (register_netdev(dev)) { - printk(KERN_WARNING - "netiucv: Could not register '%s'\n", dev->name); - netiucv_free_netdevice(dev); - return -ENODEV; + if ((ret = netiucv_register_device(dev, ifno))) + goto out_free_ndev; + /* sysfs magic */ + SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev); + if ((ret = register_netdev(dev))) { + netiucv_unregister_device((struct device*)((struct netiucv_priv*)dev->priv)->dev); + goto out_free_ndev; } printk(KERN_INFO "%s: '%s'\n", dev->name, netiucv_printname(username)); - netiucv_register_device(dev, ifno); ifno++; return count; + +out_free_ndev: + printk(KERN_WARNING + "netiucv: Could not register '%s'\n", dev->name); + netiucv_free_netdevice(dev); + return ret; } DRIVER_ATTR(connection, 0200, NULL, conn_write); static struct device_driver netiucv_driver = { - .name = "NETIUCV", + .name = "netiucv", .bus = &iucv_bus, }; static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.38 $"; + char vbuf[] = "$Revision: 1.47 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff -Nru a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c --- a/drivers/s390/net/qeth.c Sat Apr 3 19:38:57 2004 +++ b/drivers/s390/net/qeth.c Sat Apr 3 19:38:57 2004 @@ -755,7 +755,7 @@ int problem = 0; struct qeth_card *card; - card = cdev->dev.driver_data; + card = CARD_FROM_CDEV(cdev); if (atomic_read(&card->shutdown_phase)) return 0; @@ -5930,7 +5930,7 @@ LOW_WATERMARK_PACK); /* first_element is the last buffer that we got back from hydra */ if (!switch_state && !last_pci_hit) - return;; + return; QETH_DBF_CARD3(0, trace, "stchcw", card); if (atomic_swap(&card->outbound_ringbuffer_lock[queue], QETH_LOCK_FLUSH) == QETH_LOCK_UNLOCKED) { @@ -6105,7 +6105,7 @@ sprintf(dbf_text, "%4x", rqparam); QETH_DBF_TEXT4(0, trace, dbf_text); - card = cdev->dev.driver_data; + card = CARD_FROM_CDEV(cdev); if (!card) return; @@ -6231,7 +6231,7 @@ sprintf(dbf_text, "%4x", rqparam); QETH_DBF_TEXT4(0, trace, dbf_text); - card = cdev->dev.driver_data; + card = CARD_FROM_CDEV(cdev); if (!card) return; @@ -6343,7 +6343,7 @@ sprintf(dbf_text, "%4x", rqparam); QETH_DBF_TEXT4(0, trace, dbf_text); - card = cdev->dev.driver_data; + card = CARD_FROM_CDEV(cdev); if (!card) return; @@ -6404,6 +6404,8 @@ QETH_DBF_CARD3(0, trace, "rgnd", card); + /* sysfs magic */ + SET_NETDEV_DEV(card->dev, &card->gdev->dev); result = register_netdev(card->dev); return result; @@ -6681,10 +6683,6 @@ hard_start_xmit */ if (atomic_read(&card->is_registered)) { - /* Remove sysfs symlinks. */ - sysfs_remove_link(&card->gdev->dev.kobj, card->dev_name); - sysfs_remove_link(&card->dev->class_dev.kobj, - CARD_BUS_ID(card)); QETH_DBF_TEXT2(0, trace, "unregdev"); qeth_unregister_netdev(card); qeth_wait_nonbusy(QETH_REMOVE_WAIT_TIME); @@ -6885,7 +6883,7 @@ card->portname_required = ((!QETH_IDX_NO_PORTNAME_REQUIRED(card->dma_stuff->recbuf)) && - (card->type == QETH_CARD_TYPE_OSAE));; + (card->type == QETH_CARD_TYPE_OSAE)); /* * however, as the portname indication of OSA is wrong, we have to @@ -10622,13 +10620,10 @@ card->gdev = gdev; gdev->cdev[0]->handler = qeth_interrupt_handler_read; - gdev->cdev[0]->dev.driver_data = card; gdev->cdev[1]->handler = qeth_interrupt_handler_write; - gdev->cdev[1]->dev.driver_data = card; gdev->cdev[2]->handler = qeth_interrupt_handler_qdio; - gdev->cdev[2]->dev.driver_data = card; ret = __qeth_create_attributes(&gdev->dev); if (ret != 0) @@ -10694,17 +10689,6 @@ if (qeth_init_netdev(card)) goto out_remove; - if (sysfs_create_link(&card->gdev->dev.kobj, &card->dev->class_dev.kobj, - card->dev_name)) { - qeth_unregister_netdev(card); - goto out_remove; - } - if (sysfs_create_link(&card->dev->class_dev.kobj, &card->gdev->dev.kobj, - CARD_BUS_ID(card))) { - sysfs_remove_link(&card->gdev->dev.kobj, card->dev_name); - qeth_unregister_netdev(card); - goto out_remove; - } return 0; /* success */ out_remove: diff -Nru a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h --- a/drivers/s390/net/qeth.h Sat Apr 3 19:38:40 2004 +++ b/drivers/s390/net/qeth.h Sat Apr 3 19:38:40 2004 @@ -696,6 +696,8 @@ #define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id #define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id #define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id +#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \ + ((struct ccwgroup_device *) cdev->dev.driver_data)->dev.driver_data #define SENSE_COMMAND_REJECT_BYTE 0 #define SENSE_COMMAND_REJECT_FLAG 0x80 diff -Nru a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c --- a/drivers/s390/scsi/zfcp_erp.c Sat Apr 3 19:38:41 2004 +++ b/drivers/s390/scsi/zfcp_erp.c Sat Apr 3 19:38:41 2004 @@ -2706,7 +2706,7 @@ ZFCP_LOG_INFO("error: Exchange of configuration data between " "the adapter %s and the device driver failed.\n", zfcp_get_busid_by_adapter(adapter)); - retval = ZFCP_ERP_FAILED;; + retval = ZFCP_ERP_FAILED; } return retval; diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c --- a/drivers/scsi/53c700.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/53c700.c Sat Apr 3 19:38:41 2004 @@ -137,6 +137,9 @@ #include "scsi.h" #include "hosts.h" +#include +#include + #include "53c700.h" /* NOTE: For 64 bit drivers there are points in the code where we use @@ -173,6 +176,8 @@ STATIC struct device_attribute *NCR_700_dev_attrs[]; +STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; + static char *NCR_700_phase[] = { "", "after selection", @@ -236,6 +241,53 @@ NCR_700_MAX_OFFSET }; +/* This translates the SDTR message offset and period to a value + * which can be loaded into the SXFER_REG. + * + * NOTE: According to SCSI-2, the true transfer period (in ns) is + * actually four times this period value */ +static inline __u8 +NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, + __u8 offset, __u8 period) +{ + int XFERP; + + __u8 min_xferp = (hostdata->chip710 + ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); + __u8 max_offset = (hostdata->chip710 + ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); + + if(offset == 0) + return 0; + + if(period < hostdata->min_period) { + printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); + period = hostdata->min_period; + } + XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; + if(offset > max_offset) { + printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", + offset, max_offset); + offset = max_offset; + } + if(XFERP < min_xferp) { + printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", + XFERP, min_xferp); + XFERP = min_xferp; + } + return (offset & 0x0f) | (XFERP & 0x07)<<4; +} + +static inline __u8 +NCR_700_get_SXFER(Scsi_Device *SDp) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + + return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp), + spi_period(SDp)); +} + struct Scsi_Host * NCR_700_detect(Scsi_Host_Template *tpnt, struct NCR_700_Host_Parameters *hostdata) @@ -321,11 +373,13 @@ hostdata->script = script; hostdata->pScript = pScript; - dma_sync_single(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); + dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; host->max_id = 7; host->max_lun = NCR_700_MAX_LUNS; + BUG_ON(NCR_700_transport_template == NULL); + host->transportt = NCR_700_transport_template; host->unique_id = hostdata->base; host->base = hostdata->base; hostdata->eh_complete = NULL; @@ -520,40 +574,6 @@ hostdata->cmd = NULL; } -/* This translates the SDTR message offset and period to a value - * which can be loaded into the SXFER_REG. - * - * NOTE: According to SCSI-2, the true transfer period (in ns) is - * actually four times this period value */ -STATIC inline __u8 -NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, - __u8 offset, __u8 period) -{ - int XFERP; - __u8 min_xferp = (hostdata->chip710 - ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); - __u8 max_offset = (hostdata->chip710 - ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); - /* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum - * period. It is set in NCR_700_chip_setup() */ - if(period < NCR_700_SDTR_msg[3]) { - printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); - period = NCR_700_SDTR_msg[3]; - } - XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; - if(offset > max_offset) { - printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", - offset, max_offset); - offset = max_offset; - } - if(XFERP < min_xferp) { - printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", - XFERP, min_xferp); - XFERP = min_xferp; - } - return (offset & 0x0f) | (XFERP & 0x07)<<4; -} - STATIC inline void NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, struct NCR_700_command_slot *slot) @@ -724,11 +744,9 @@ * exact details of this calculation which is based on a * setting of the SXFER register */ min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); - if(min_period > NCR_700_MIN_PERIOD) { - NCR_700_SDTR_msg[3] = min_period; - } - if(hostdata->chip710) - NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET; + hostdata->min_period = NCR_700_MIN_PERIOD; + if(min_period > NCR_700_MIN_PERIOD) + hostdata->min_period = min_period; } STATIC void @@ -777,20 +795,25 @@ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { __u8 period = hostdata->msgin[3]; __u8 offset = hostdata->msgin[4]; - __u8 sxfer; - if(offset != 0 && period != 0) - sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period); - else - sxfer = 0; + if(offset == 0 || period == 0) { + offset = 0; + period = 0; + } - if(sxfer != NCR_700_get_SXFER(SCp->device)) { - printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n", - host->host_no, pun, lun, - offset, period*4); - - NCR_700_set_SXFER(SCp->device, sxfer); + if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) { + if(spi_offset(SCp->device) != 0) + printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n", + host->host_no, pun, lun, + offset, period*4); + else + printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n", + host->host_no, pun, lun); + NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); } + + spi_offset(SCp->device) = offset; + spi_period(SCp->device) = period; NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); @@ -870,7 +893,7 @@ case A_REJECT_MSG: if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { /* Rejected our sync negotiation attempt */ - NCR_700_set_SXFER(SCp->device, 0); + spi_period(SCp->device) = spi_offset(SCp->device) = 0; NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { @@ -982,8 +1005,8 @@ SCp->cmnd[7] = hostdata->status[0]; SCp->use_sg = 0; SCp->sc_data_direction = SCSI_DATA_READ; - dma_sync_single(hostdata->dev, slot->pCmd, - SCp->cmd_len, DMA_TO_DEVICE); + dma_sync_single_for_device(hostdata->dev, slot->pCmd, + SCp->cmd_len, DMA_TO_DEVICE); SCp->request_bufflen = sizeof(SCp->sense_buffer); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); @@ -1007,7 +1030,7 @@ // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { // /* Piggy back the tag queueing support // * on this command */ - // dma_sync_single(hostdata->dev, + // dma_sync_single_for_cpu(hostdata->dev, // slot->dma_handle, // SCp->request_bufflen, // DMA_FROM_DEVICE); @@ -1396,6 +1419,8 @@ NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) { memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg, sizeof(NCR_700_SDTR_msg)); + hostdata->msgout[count+3] = spi_period(SCp->device); + hostdata->msgout[count+4] = spi_offset(SCp->device); count += sizeof(NCR_700_SDTR_msg); NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } @@ -1497,6 +1522,8 @@ printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); + scsi_report_bus_reset(host, 0); + /* clear all the negotiated parameters */ __shost_for_each_device(SDp, host) SDp->hostdata = 0; @@ -1942,6 +1969,9 @@ wait_for_completion(&complete); spin_lock_irq(SCp->device->host->host_lock); hostdata->eh_complete = NULL; + /* Revalidate the transport parameters of the failing device */ + if(hostdata->fast) + spi_schedule_dv_device(SCp->device); return SUCCESS; } @@ -1967,9 +1997,57 @@ return SUCCESS; } +STATIC void +NCR_700_set_period(struct scsi_device *SDp, int period) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + + if(!hostdata->fast) + return; + + if(period < hostdata->min_period) + period = hostdata->min_period; + + spi_period(SDp) = period; + NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC); + NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); + NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); +} + +STATIC void +NCR_700_set_offset(struct scsi_device *SDp, int offset) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + int max_offset = hostdata->chip710 + ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET; + + if(!hostdata->fast) + return; + + if(offset > max_offset) + offset = max_offset; + + /* if we're currently async, make sure the period is reasonable */ + if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period || + spi_period(SDp) > 0xff)) + spi_period(SDp) = hostdata->min_period; + + spi_offset(SDp) = offset; + NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC); + NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); + NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); +} + + + STATIC int NCR_700_slave_configure(Scsi_Device *SDp) { + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { /* do TCQ stuff here */ @@ -1977,6 +2055,13 @@ /* initialise to default depth */ scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); } + if(hostdata->fast) { + /* Find the correct offset and period via domain validation */ + spi_dv_device(SDp); + } else { + spi_offset(SDp) = 0; + spi_period(SDp) = 0; + } return 0; } @@ -2033,3 +2118,27 @@ EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); + +static struct spi_function_template NCR_700_transport_functions = { + .set_period = NCR_700_set_period, + .show_period = 1, + .set_offset = NCR_700_set_offset, + .show_offset = 1, +}; + +static int __init NCR_700_init(void) +{ + NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions); + if(!NCR_700_transport_template) + return -ENODEV; + return 0; +} + +static void __exit NCR_700_exit(void) +{ + spi_release_transport(NCR_700_transport_template); +} + +module_init(NCR_700_init); +module_exit(NCR_700_exit); + diff -Nru a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h --- a/drivers/scsi/53c700.h Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/53c700.h Sat Apr 3 19:38:41 2004 @@ -99,19 +99,9 @@ #define NCR_700_DEV_NEGOTIATED_SYNC (1<<16) #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) #define NCR_700_DEV_BEGIN_TAG_QUEUEING (1<<18) -#define NCR_700_DEV_TAG_STARVATION_WARNED (1<<19) +#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) static inline void -NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer) -{ - SDp->hostdata = (void *)(((long)SDp->hostdata & 0xffffff00) | - (sxfer & 0xff)); -} -static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp) -{ - return (((unsigned long)SDp->hostdata) & 0xff); -} -static inline void NCR_700_set_depth(Scsi_Device *SDp, __u8 depth) { long l = (long)SDp->hostdata; @@ -215,6 +205,7 @@ __u8 tag_negotiated; __u8 rev; __u8 reselection_id; + __u8 min_period; /* Free list, singly linked by ITL_forw elements */ struct NCR_700_command_slot *free_list; @@ -438,6 +429,7 @@ #symbol, A_##symbol##_used[i], val)); \ } \ } + static inline __u8 NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg) diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/BusLogic.c Sat Apr 3 19:38:56 2004 @@ -140,7 +140,7 @@ Name, Copyright Notice, and Electronic Mail Address. */ -static void __init BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) +static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) { BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/Kconfig Sat Apr 3 19:38:55 2004 @@ -196,6 +196,25 @@ there should be no noticeable performance impact as long as you have logging turned off. +menu "SCSI Transport Attributes" + depends on SCSI + +config SCSI_SPI_ATTRS + tristate "Parallel SCSI (SPI) Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached SCSI device to sysfs, say Y. Otherwise, say N. + +config SCSI_FC_ATTRS + tristate "FiberChannel Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached FiberChannel device to sysfs, say Y. + Otherwise, say N. + +endmenu menu "SCSI low-level drivers" depends on SCSI!=n @@ -424,7 +443,7 @@ config SCSI_SATA_SIL tristate "Silicon Image SATA support" - depends on SCSI_SATA && PCI && BROKEN + depends on SCSI_SATA && PCI && EXPERIMENTAL help This option enables support for Silicon Image Serial ATA. @@ -438,6 +457,14 @@ If unsure, say N. +config SCSI_SATA_VITESSE + tristate "VITESSE VSC-7174 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Vitesse VSC7174 Serial ATA. + + If unsure, say N. + config SCSI_BUSLOGIC tristate "BusLogic SCSI support" depends on (PCI || ISA || MCA) && SCSI @@ -845,6 +872,7 @@ config SCSI_NCR_D700 tristate "NCR Dual 700 MCA SCSI support" depends on MCA && SCSI + select SCSI_SPI_ATTRS help This is a driver for the MicroChannel Dual 700 card produced by NCR and commonly used in 345x/35xx/4100 class machines. It always @@ -861,6 +889,7 @@ config SCSI_LASI700 tristate "HP Lasi SCSI support for 53c700/710" depends on GSC && SCSI + select SCSI_SPI_ATTRS help This is a driver for the SCSI controller in the Lasi chip found in many PA-RISC workstations & servers. If you do not know whether you @@ -1212,6 +1241,7 @@ config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" depends on (EISA || MCA) && SCSI + select SCSI_SPI_ATTRS ---help--- This driver for NCR53c710 based SCSI host adapters. diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/Makefile Sat Apr 3 19:38:55 2004 @@ -22,6 +22,14 @@ obj-$(CONFIG_SCSI) += scsi_mod.o +# --- NOTE ORDERING HERE --- +# For kernel non-modular link, transport attributes need to +# be initialised before drivers +# -------------------------- +obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o +obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o + + obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o @@ -41,7 +49,7 @@ obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o -obj-$(CONFIG_SCSI_SIM710) += sim710.o 53c700.o +obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o obj-$(CONFIG_SCSI_PCI2000) += pci2000.o obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o @@ -64,7 +72,7 @@ obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o -obj-$(CONFIG_SCSI_NCR_D700) += NCR_D700.o 53c700.o +obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o @@ -107,13 +115,14 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o -obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o +obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o +obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_ARM) += arm/ @@ -130,7 +139,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o scsi_mod-$(CONFIG_X86_PC9800) += scsi_pc98.o - + sd_mod-objs := sd.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/aacraid/linit.c Sat Apr 3 19:38:42 2004 @@ -99,8 +99,8 @@ { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier)*/ { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado)*/ - { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/ - { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/ + { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020 ZCR PCI-X U320 */ + { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025 ZCR DIMM U320 */ { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/ @@ -116,6 +116,8 @@ { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */ { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 32 }, /* ASR-2020SA (ZCR PCI-X SATA) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 33 }, /* ASR-2025SA (ZCR DIMM SATA) */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -145,8 +147,8 @@ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier)*/ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020 ZCR PCI-X U320 */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025 ZCR DIMM U320 */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ @@ -162,6 +164,8 @@ { aac_rx_init, "aacraid", "ADAPTEC ", "SATA 6Channel ", 1 }, /* SATA 6Ch (Bearcat) */ { aac_rkt_init,"aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA (ZCR PCI-X SATA) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA (ZCR DIMM SATA) */ }; /** diff -Nru a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c --- a/drivers/scsi/aacraid/rkt.c Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/aacraid/rkt.c Sat Apr 3 19:38:55 2004 @@ -427,6 +427,7 @@ dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt; dev->a_ops.adapter_notify = aac_rkt_notify_adapter; dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; + dev->a_ops.adapter_check_health = aac_rkt_check_health; if (aac_init_adapter(dev) == NULL) return -1; diff -Nru a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c --- a/drivers/scsi/aacraid/rx.c Sat Apr 3 19:38:57 2004 +++ b/drivers/scsi/aacraid/rx.c Sat Apr 3 19:38:57 2004 @@ -427,6 +427,7 @@ dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; + dev->a_ops.adapter_check_health = aac_rx_check_health; if (aac_init_adapter(dev) == NULL) return -1; diff -Nru a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c --- a/drivers/scsi/aacraid/sa.c Sat Apr 3 19:38:44 2004 +++ b/drivers/scsi/aacraid/sa.c Sat Apr 3 19:38:44 2004 @@ -407,6 +407,7 @@ dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; + dev->a_ops.adapter_check_health = aac_sa_check_health; dprintk(("FUNCDONE\n")); diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx Sat Apr 3 19:38:43 2004 @@ -4,7 +4,7 @@ # config SCSI_AIC79XX tristate "Adaptec AIC79xx U320 support" - depends on PCI + depends on PCI && SCSI help This driver supports all of Adaptec's Ultra 320 PCI-X based SCSI controllers. diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx Sat Apr 3 19:38:42 2004 @@ -4,7 +4,7 @@ # config SCSI_AIC7XXX tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" - depends on PCI || EISA + depends on (PCI || EISA) && SCSI ---help--- This driver supports all of Adaptec's Fast through Ultra 160 PCI based SCSI controllers as well as the aic7770 based EISA and VLB diff -Nru a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c --- a/drivers/scsi/aic7xxx/aic7770.c Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/aic7xxx/aic7770.c Sat Apr 3 19:38:56 2004 @@ -64,7 +64,7 @@ static int aic7770_resume(struct ahc_softc *ahc); static int aha2840_load_seeprom(struct ahc_softc *ahc); static ahc_device_setup_t ahc_aic7770_VL_setup; -static ahc_device_setup_t ahc_aic7770_EISA_setup;; +static ahc_device_setup_t ahc_aic7770_EISA_setup; static ahc_device_setup_t ahc_aic7770_setup; struct aic7770_identity aic7770_ident_table[] = diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/ata_piix.c Sat Apr 3 19:38:43 2004 @@ -16,7 +16,7 @@ May be copied or modified under the terms of the GNU General Public License */ -#include + #include #include #include @@ -125,7 +125,6 @@ .exec_command = ata_exec_command_pio, .phy_reset = piix_pata_phy_reset, - .phy_config = pata_phy_config, .bmdma_start = ata_bmdma_start_pio, .fill_sg = ata_fill_sg, @@ -148,7 +147,6 @@ .exec_command = ata_exec_command_pio, .phy_reset = piix_sata_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ .bmdma_start = ata_bmdma_start_pio, .fill_sg = ata_fill_sg, diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/constants.c Sat Apr 3 19:38:54 2004 @@ -1135,7 +1135,7 @@ static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/cpqfcTSinit.c Sat Apr 3 19:38:41 2004 @@ -46,10 +46,6 @@ #include // request_region() prototype #include -#ifdef __alpha__ -#define __KERNEL_SYSCALLS__ -#endif -#include #include #include // ioctl related #include @@ -220,7 +216,7 @@ cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite; cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl; cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry; - cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;; + cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager; cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN; cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM; diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/dc395x.c Sat Apr 3 19:38:41 2004 @@ -62,6 +62,10 @@ #include #include +#define DC395X_NAME "dc395x" +#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" +#define DC395X_VERSION "v2.05, 2004/03/08" + /*--------------------------------------------------------------------------- Features ---------------------------------------------------------------------------*/ @@ -82,22 +86,16 @@ #define DBG_KG 0x0001 #define DBG_0 0x0002 #define DBG_1 0x0004 -#define DBG_DCB 0x0008 -#define DBG_PARSE 0x0010 /* debug command line parsing */ -#define DBG_SGPARANOIA 0x0020 +#define DBG_SG 0x0020 #define DBG_FIFO 0x0040 #define DBG_PIO 0x0080 -#define DBG_RECURSION 0x0100 /* check for excessive recursion */ -#define DBG_MALLOC 0x0200 /* report on memory allocations */ -#define DBG_TRACE 0x0400 -#define DBG_TRACEALL 0x0800 /* * Set set of things to output debugging for. * Undefine to remove all debugging */ -/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_DCB|DBG_PARSE|DBG_SGPARANOIA|DBG_FIFO|DBG_PIO|DBG_TRACE|DBG_TRACEALL)*/ +/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/ /*#define DEBUG_MASK DBG_0*/ @@ -138,72 +136,6 @@ #endif -/* - * The recursion debugging just counts entries into the driver and - * prints out a messge if it exceeds a certain limit. This variable - * hold the count. - */ -#if debug_enabled(DBG_RECURSION) -static int dbg_in_driver = 0; -#endif - - -/* - * Memory allocation debugging - * Just reports when memory is allocated and/or released. - */ -#if debug_enabled(DBG_MALLOC) -inline void *dc395x_kmalloc(size_t sz, int fl) -{ - void *ptr = kmalloc(sz, fl); - dprintkl(KERN_DEBUG, "Alloc %i bytes @ %p w/ fl %08x\n", sz, ptr, fl); - return ptr; -} -inline void dc395x_kfree(const void *adr) -{ - dprintkl(KERN_DEBUG, "Free mem @ %p\n", adr); - kfree(adr); -} -#else -#define dc395x_kmalloc(sz, fl) kmalloc(sz, fl) -#define dc395x_kfree(adr) kfree(adr) -#endif - - -/* - * Debug/trace stuff - */ -#if debug_enabled(DBG_TRACEALL) -# define TRACEOUTALL(x...) printk ( x) -#else -# define TRACEOUTALL(x...) do {} while (0) -#endif - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) -# define DEBUGTRACEBUFSZ 512 -static char tracebuf[64]; -static char traceoverflow[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -# define TRACEPRINTF(x...) \ - do { \ - int ln = sprintf(tracebuf, x); \ - if (srb->debugpos + ln >= DEBUGTRACEBUFSZ) { \ - srb->debugtrace[srb->debugpos] = 0; \ - srb->debugpos = DEBUGTRACEBUFSZ/5; \ - srb->debugtrace[srb->debugpos++] = '>'; \ - } \ - sprintf(srb->debugtrace + srb->debugpos, "%s", tracebuf); \ - srb->debugpos += ln - 1; \ - } while (0) -# define TRACEOUT(x...) printk (x) -#else -# define TRACEPRINTF(x...) do {} while (0) -# define TRACEOUT(x...) do {} while (0) -#endif - - -/*--------------------------------------------------------------------------- - ---------------------------------------------------------------------------*/ - #ifndef PCI_VENDOR_ID_TEKRAM #define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ #endif @@ -212,32 +144,16 @@ #endif - #define DC395x_LOCK_IO(dev,flags) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags) #define DC395x_UNLOCK_IO(dev,flags) spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags) -#define DC395x_ACB_INITLOCK(acb) spin_lock_init(&acb->smp_lock) -#define DC395x_ACB_LOCK(acb,acb_flags) if (!acb->lock_level_count[cpuid]) { spin_lock_irqsave(&acb->smp_lock,acb_flags); acb->lock_level_count[cpuid]++; } else { acb->lock_level_count[cpuid]++; } -#define DC395x_ACB_UNLOCK(acb,acb_flags) if (--acb->lock_level_count[cpuid] == 0) { spin_unlock_irqrestore(&acb->smp_lock,acb_flags); } - -#define DC395x_SMP_IO_LOCK(dev,irq_flags) spin_lock_irqsave(((struct Scsi_Host*)dev)->host_lock,irq_flags) -#define DC395x_SMP_IO_UNLOCK(dev,irq_flags) spin_unlock_irqrestore(((struct Scsi_Host*)dev)->host_lock,irq_flags) - - #define DC395x_read8(acb,address) (u8)(inb(acb->io_port_base + (address))) -#define DC395x_read8_(address, base) (u8)(inb((USHORT)(base) + (address))) #define DC395x_read16(acb,address) (u16)(inw(acb->io_port_base + (address))) #define DC395x_read32(acb,address) (u32)(inl(acb->io_port_base + (address))) #define DC395x_write8(acb,address,value) outb((value), acb->io_port_base + (address)) -#define DC395x_write8_(address,value,base) outb((value), (USHORT)(base) + (address)) #define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address)) #define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address)) - -#define BUS_ADDR(sg) sg_dma_address(&(sg)) -#define CPU_ADDR(sg) (page_address((sg).page)+(sg).offset) -#define PAGE_ADDRESS(sg) page_address((sg)->page) - /* cmd->result */ #define RES_TARGET 0x000000FF /* Target State */ #define RES_TARGET_LNX STATUS_MASK /* Only official ... */ @@ -254,20 +170,22 @@ #define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } #define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } -/* -************************************************************************** -*/ #define TAG_NONE 255 +/* + * srb->segement_x is the hw sg list. It is always allocated as a + * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not + * cross a page boundy. + */ +#define SEGMENTX_LEN (sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY) + + struct SGentry { u32 address; /* bus! address */ u32 length; }; - -/* - * The SEEPROM structure for TRM_S1040 - */ +/* The SEEPROM structure for TRM_S1040 */ struct NVRamTarget { u8 cfg0; /* Target configuration byte 0 */ u8 period; /* Target period */ @@ -275,7 +193,6 @@ u8 cfg3; /* Target configuration byte 3 */ }; - struct NvRamType { u8 sub_vendor_id[2]; /* 0,1 Sub Vendor ID */ u8 sub_sys_id[2]; /* 2,3 Sub System ID */ @@ -302,28 +219,31 @@ u16 cksum; /* 126,127 */ }; - -/*----------------------------------------------------------------------- - SCSI Request Block - -----------------------------------------------------------------------*/ struct ScsiReqBlk { struct list_head list; /* next/prev ptrs for srb lists */ struct DeviceCtlBlk *dcb; - - /* HW scatter list (up to 64 entries) */ - struct SGentry *segment_x; Scsi_Cmnd *cmd; - unsigned char *virt_addr; /* set by update_sg_list */ + struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ + u32 sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ - u32 total_xfer_length; - u32 xferred; /* Backup for the already xferred len */ + u8 sg_count; /* No of HW sg entries for this request */ + u8 sg_index; /* Index of HW sg entry for this request */ + u32 total_xfer_length; /* Total number of bytes remaining to be transfered */ + unsigned char *virt_addr; /* Virtual address of current transfer position */ - u32 sg_bus_addr; /* bus address of DC395x scatterlist */ + /* + * The sense buffer handling function, request_sense, uses + * the first hw sg entry (segment_x[0]) and the transfer + * length (total_xfer_length). While doing this it stores the + * original values into the last sg hw list + * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the + * total_xfer_length in xferred. These values are restored in + * pci_unmap_srb_sense. This is the only place xferred is used. + */ + u32 xferred; /* Saved copy of total_xfer_length */ u16 state; - u8 sg_count; - u8 sg_index; u8 msgin_buf[6]; u8 msgout_buf[6]; @@ -339,17 +259,8 @@ u8 flag; u8 scsi_phase; - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - u16 debugpos; - char *debugtrace; -#endif }; - -/*----------------------------------------------------------------------- - Device Control Block - -----------------------------------------------------------------------*/ struct DeviceCtlBlk { struct list_head list; /* next/prev ptrs for the dcb list */ struct AdapterCtlBlk *acb; @@ -377,9 +288,6 @@ u8 init_tcq_flag; }; -/*----------------------------------------------------------------------- - Adapter Control Block - -----------------------------------------------------------------------*/ struct AdapterCtlBlk { struct Scsi_Host *scsi_host; @@ -423,80 +331,63 @@ }; - - /*--------------------------------------------------------------------------- Forward declarations ---------------------------------------------------------------------------*/ -static void data_out_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_in_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void command_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void status_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgout_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgin_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_out_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_in_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void command_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void status_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgout_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgin_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); +static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status); + u16 *pscsi_status); +static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); static void set_basic_config(struct AdapterCtlBlk *acb); static void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); static void reset_scsi_bus(struct AdapterCtlBlk *acb); static void data_io_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, u16 io_dir); + struct ScsiReqBlk *srb, u16 io_dir); static void disconnect(struct AdapterCtlBlk *acb); static void reselect(struct AdapterCtlBlk *acb); static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); +static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, - Scsi_Cmnd * cmd, u8 force); + Scsi_Cmnd *cmd, u8 force); static void scsi_reset_detect(struct AdapterCtlBlk *acb); -static void pci_unmap_srb(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); +static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); -static void srb_done(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void request_sense(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); +static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); +static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); static inline void set_xfer_rate(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb); + struct DeviceCtlBlk *dcb); static void waiting_timeout(unsigned long ptr); @@ -504,11 +395,7 @@ Static Data ---------------------------------------------------------------------------*/ static u16 current_sync_offset = 0; -static char monitor_next_irq = 0; -/* - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - */ static void *dc395x_scsi_phase0[] = { data_out_phase0,/* phase:0 */ data_in_phase0, /* phase:1 */ @@ -520,9 +407,6 @@ msgin_phase0, /* phase:7 */ }; -/* - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - */ static void *dc395x_scsi_phase1[] = { data_out_phase1,/* phase:0 */ data_in_phase1, /* phase:1 */ @@ -558,8 +442,6 @@ /* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 }; static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; -/* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ - /*--------------------------------------------------------------------------- @@ -655,8 +537,9 @@ /* - * Safe settings. If set to zero the the BIOS/default values with command line - * overrides will be used. If set to 1 then safe and slow settings will be used. + * Safe settings. If set to zero the the BIOS/default values with + * command line overrides will be used. If set to 1 then safe and + * slow settings will be used. */ static int use_safe_settings = 0; module_param_named(safe, use_safe_settings, bool, 0); @@ -686,8 +569,7 @@ * set_safe_settings - if the use_safe_settings option is set then * set all values to the safe and slow values. **/ -static -void __init set_safe_settings(void) +static void __init set_safe_settings(void) { if (use_safe_settings) { @@ -706,25 +588,24 @@ * fix_settings - reset any boot parameters which are out of range * back to the default values. **/ -static -void __init fix_settings(void) +static void __init fix_settings(void) { int i; - dprintkdbg(DBG_PARSE, "setup %08x %08x %08x %08x %08x %08x\n", - cfg_data[CFG_ADAPTER_ID].value, - cfg_data[CFG_MAX_SPEED].value, - cfg_data[CFG_DEV_MODE].value, - cfg_data[CFG_ADAPTER_MODE].value, - cfg_data[CFG_TAGS].value, - cfg_data[CFG_RESET_DELAY].value); + dprintkdbg(DBG_1, + "setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x " + "AdapterMode=%08x Tags=%08x ResetDelay=%08x\n", + cfg_data[CFG_ADAPTER_ID].value, + cfg_data[CFG_MAX_SPEED].value, + cfg_data[CFG_DEV_MODE].value, + cfg_data[CFG_ADAPTER_MODE].value, + cfg_data[CFG_TAGS].value, + cfg_data[CFG_RESET_DELAY].value); for (i = 0; i < CFG_NUM; i++) { - if (cfg_data[i].value < cfg_data[i].min || - cfg_data[i].value > cfg_data[i].max) - { + if (cfg_data[i].value < cfg_data[i].min + || cfg_data[i].value > cfg_data[i].max) cfg_data[i].value = cfg_data[i].def; - } } } @@ -734,8 +615,8 @@ * Mapping from the eeprom delay index value (index into this array) * to the the number of actual seconds that the delay should be for. */ -static -char __initdata eeprom_index_to_delay_map[] = { 1, 3, 5, 10, 16, 30, 60, 120 }; +static char __initdata eeprom_index_to_delay_map[] = + { 1, 3, 5, 10, 16, 30, 60, 120 }; /** @@ -744,25 +625,24 @@ * * @eeprom: The eeprom structure in which we find the delay index to map. **/ -static -void __init eeprom_index_to_delay(struct NvRamType *eeprom) +static void __init eeprom_index_to_delay(struct NvRamType *eeprom) { eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time]; } /** - * delay_to_eeprom_index - Take a delay in seconds and return the closest - * eeprom index which will delay for at least that amount of seconds. + * delay_to_eeprom_index - Take a delay in seconds and return the + * closest eeprom index which will delay for at least that amount of + * seconds. * * @delay: The delay, in seconds, to find the eeprom index for. **/ static int __init delay_to_eeprom_index(int delay) { u8 idx = 0; - while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) { + while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) idx++; - } return idx; } @@ -774,38 +654,34 @@ * * @eeprom: The eeprom data to override with command line options. **/ -static -void __init eeprom_override(struct NvRamType *eeprom) +static void __init eeprom_override(struct NvRamType *eeprom) { u8 id; /* Adapter Settings */ - if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) { - eeprom->scsi_id = - (u8)cfg_data[CFG_ADAPTER_ID].value; - } - if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) { - eeprom->channel_cfg = - (u8)cfg_data[CFG_ADAPTER_MODE].value; - } - if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) { - eeprom->delay_time = - delay_to_eeprom_index(cfg_data[CFG_RESET_DELAY].value); - } - if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) { + if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) + eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value; + + if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) + eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value; + + if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) + eeprom->delay_time = delay_to_eeprom_index( + cfg_data[CFG_RESET_DELAY].value); + + if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value; - } /* Device Settings */ for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { - if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) { + if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) eeprom->target[id].cfg0 = - (u8)cfg_data[CFG_DEV_MODE].value; - } - if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) { + (u8)cfg_data[CFG_DEV_MODE].value; + + if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) eeprom->target[id].period = - (u8)cfg_data[CFG_MAX_SPEED].value; - } + (u8)cfg_data[CFG_MAX_SPEED].value; + } } @@ -813,39 +689,21 @@ /*--------------------------------------------------------------------------- ---------------------------------------------------------------------------*/ -/** - * list_size - Returns the size (in number of entries) of the - * supplied list. - * - * @head: The pointer to the head of the list to count the items in. - **/ -static -unsigned int list_size(struct list_head *head) +static unsigned int list_size(struct list_head *head) { unsigned int count = 0; struct list_head *pos; list_for_each(pos, head) count++; return count; -} +} -/** - * dcb_get_next - Given a dcb return the next dcb in the list of - * dcb's, wrapping back to the start of the dcb list if required. - * Returns the supplied dcb if there is only one dcb in the list. - * - * @head: The pointer to the head of the list to count the items in. - * @pos: The pointer the dcb for which we are searching for the - * following dcb. - **/ -static -struct DeviceCtlBlk *dcb_get_next( - struct list_head *head, +static struct DeviceCtlBlk *dcb_get_next(struct list_head *head, struct DeviceCtlBlk *pos) { int use_next = 0; - struct DeviceCtlBlk* next = NULL; + struct DeviceCtlBlk* next = NULL; struct DeviceCtlBlk* i; if (list_empty(head)) @@ -870,22 +728,7 @@ } -/* - * Queueing philosphy: - * There are a couple of lists: - * - Waiting: Contains a list of SRBs not yet sent (per DCB) - * - Free: List of free SRB slots - * - * If there are no waiting commands for the DCB, the new one is sent to the bus - * otherwise the oldest one is taken from the Waiting list and the new one is - * queued to the Waiting List - * - * Lists are managed using two pointers and eventually a counter - */ - -/* Nomen est omen ... */ -static inline -void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { if (srb->tag_number < 255) { dcb->tag_mask &= ~(1 << srb->tag_number); /* free tag mask */ @@ -895,9 +738,8 @@ /* Find cmd in SRB list */ -inline static -struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd, - struct list_head *head) +inline static struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd, + struct list_head *head) { struct ScsiReqBlk *i; list_for_each_entry(i, head, list) @@ -907,88 +749,59 @@ } -/* - * srb_get_free - Return a free srb from the list of free SRBs that - * is stored with the acb. - */ -static -struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) +static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) { struct list_head *head = &acb->srb_free_list; - struct ScsiReqBlk *srb; + struct ScsiReqBlk *srb = NULL; if (!list_empty(head)) { srb = list_entry(head->next, struct ScsiReqBlk, list); list_del(head->next); - dprintkdbg(DBG_0, "srb_get_free: got srb %p\n", srb); - } else { - srb = NULL; - dprintkl(KERN_ERR, "Out of Free SRBs :-(\n"); + dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb); } return srb; } -/* - * srb_free_insert - Insert an srb to the head of the free list - * stored in the acb. - */ -static -void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_free_insert: put srb %p\n", srb); - list_add_tail(&srb->list, &acb->srb_free_list); + dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb); + list_add_tail(&srb->list, &acb->srb_free_list); } -/* - * srb_waiting_insert - Insert an srb to the head of the wiating list - * stored in the dcb. - */ -static -void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_waiting_insert(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_insert: srb %p cmd %li\n", srb, srb->cmd->pid); - list_add(&srb->list, &dcb->srb_waiting_list); + dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_waiting_append - Append an srb to the tail of the waiting list - * stored in the dcb. - */ -static inline -void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_waiting_append(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n", srb, srb->cmd->pid); - list_add_tail(&srb->list, &dcb->srb_waiting_list); + dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add_tail(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_going_append - Append an srb to the tail of the going list - * stored in the dcb. - */ -static inline -void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_append: srb %p\n", srb); - list_add_tail(&srb->list, &dcb->srb_going_list); + dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add_tail(&srb->list, &dcb->srb_going_list); } - -/* - * srb_going_remove - Remove an srb from the going list stored in the - * dcb. - */ -static -void srb_going_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: srb %p\n", srb); + dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) if (i == srb) { @@ -998,17 +811,13 @@ } -/* - * srb_waiting_remove - Remove an srb from the waiting list stored in the - * dcb. - */ -static -void srb_waiting_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_waiting_remove(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: srb %p\n", srb); + dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) if (i == srb) { @@ -1018,37 +827,28 @@ } -/* - * srb_going_to_waiting_move - Remove an srb from the going list in - * the dcb and insert it at the head of the waiting list in the dcb. - */ -static -void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_waiting_move: srb %p, pid = %li\n", srb, srb->cmd->pid); + dprintkdbg(DBG_0, + "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_waiting_to_going_move - Remove an srb from the waiting list in - * the dcb and insert it at the head of the going list in the dcb. - */ -static -void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - /* Remove from waiting list */ - dprintkdbg(DBG_0, "srb_waiting_to_going: srb %p\n", srb); - TRACEPRINTF("WtG *"); +static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) +{ + dprintkdbg(DBG_0, + "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_going_list); } /* Sets the timer to wake us up */ -static -void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) +static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) { if (timer_pending(&acb->waiting_timer)) return; @@ -1065,8 +865,7 @@ /* Send the next command from the waiting list to the bus */ -static -void waiting_process_next(struct AdapterCtlBlk *acb) +static void waiting_process_next(struct AdapterCtlBlk *acb) { struct DeviceCtlBlk *start = NULL; struct DeviceCtlBlk *pos; @@ -1074,7 +873,7 @@ struct ScsiReqBlk *srb; struct list_head *dcb_list_head = &acb->dcb_list; - if ((acb->active_dcb) + if (acb->active_dcb || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) return; @@ -1135,8 +934,9 @@ static void waiting_timeout(unsigned long ptr) { unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr; - dprintkdbg(DBG_KG, "Debug: Waiting queue woken up by timer.\n"); + struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; + dprintkdbg(DBG_1, + "waiting_timeout: Queue woken up by timer. acb=%p\n", acb); DC395x_LOCK_IO(acb->scsi_host, flags); waiting_process_next(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); @@ -1144,28 +944,17 @@ /* Get the DCB for a given ID/LUN combination */ -static inline -struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) +static struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) { return acb->children[id][lun]; } -/*********************************************************************** - * Function: static void send_srb (struct AdapterCtlBlk* acb, struct ScsiReqBlk* srb) - * - * Purpose: Send SCSI Request Block (srb) to adapter (acb) - * - * dc395x_queue_command - * waiting_process_next - * - ***********************************************************************/ -static -void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* Send SCSI Request Block (srb) to adapter (acb) */ +static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = srb->dcb; - dcb = srb->dcb; if (dcb->max_command <= list_size(&dcb->srb_going_list) || acb->active_dcb || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) { @@ -1174,130 +963,29 @@ return; } - if (!start_scsi(acb, dcb, srb)) { + if (!start_scsi(acb, dcb, srb)) srb_going_append(dcb, srb); - } else { + else { srb_waiting_insert(dcb, srb); waiting_set_timer(acb, HZ / 50); } } -/* - ********************************************************************* - * - * Function: static void build_srb (Scsi_Cmd *cmd, struct DeviceCtlBlk* dcb, struct ScsiReqBlk* srb) - * - * Purpose: Prepare SRB for being sent to Device DCB w/ command *cmd - * - ********************************************************************* - */ -static -void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - int i, max; - struct SGentry *sgp; - struct scatterlist *sl; - u32 request_size; - int dir; +/* Prepare SRB for being sent to Device DCB w/ command *cmd */ +static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) +{ + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", + cmd->pid, dcb->target_id, dcb->target_lun); - dprintkdbg(DBG_0, "build_srb..............\n"); - /*memset (srb, 0, sizeof (struct ScsiReqBlk)); */ srb->dcb = dcb; srb->cmd = cmd; - /* Find out about direction */ - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - - if (cmd->use_sg && dir != PCI_DMA_NONE) { - unsigned int len = 0; - /* TODO: In case usg_sg and the no of segments differ, things - * will probably go wrong. */ - max = srb->sg_count = - pci_map_sg(dcb->acb->dev, - (struct scatterlist *) cmd->request_buffer, - cmd->use_sg, dir); - sgp = srb->segment_x; - request_size = cmd->request_bufflen; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", - cmd->request_bufflen, cmd->request_buffer, - cmd->use_sg); - dprintkdbg(DBG_SGPARANOIA, - "Mapped %i Segments to %i\n", cmd->use_sg, - srb->sg_count); - sl = (struct scatterlist *) cmd->request_buffer; - - srb->virt_addr = page_address(sl->page); - for (i = 0; i < max; i++) { - u32 busaddr = (u32) sg_dma_address(&sl[i]); - u32 seglen = (u32) sl[i].length; - sgp[i].address = busaddr; - sgp[i].length = seglen; - len += seglen; - dprintkdbg(DBG_SGPARANOIA, - "Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n", - i, busaddr, seglen, len); - } - sgp += max - 1; - /* Fixup for last buffer too big as it is allocated on even page boundaries */ - if (len > request_size) { -#if debug_enabled(DBG_KG) || debug_enabled(DBG_SGPARANOIA) - dprintkdbg(DBG_KG|DBG_SGPARANOIA, - "Fixup SG total length: %d->%d, last seg %d->%d\n", - len, request_size, sgp->length, - sgp->length - (len - request_size)); -#endif - sgp->length -= (len - request_size); - len = request_size; - } - /* WIDE padding */ - if (dcb->sync_period & WIDE_SYNC && len % 2) { - len++; - sgp->length++; - } - srb->total_xfer_length = len; /*? */ - /* Hopefully this does not cross a page boundary ... */ - srb->sg_bus_addr = - pci_map_single(dcb->acb->dev, srb->segment_x, - sizeof(struct SGentry) * - DC395x_MAX_SG_LISTENTRY, - PCI_DMA_TODEVICE); - dprintkdbg(DBG_SGPARANOIA, - "Map SG descriptor list %p (%05x) to %08x\n", - srb->segment_x, - sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY, - srb->sg_bus_addr); - } else { - if (cmd->request_buffer && dir != PCI_DMA_NONE) { - u32 len = cmd->request_bufflen; /* Actual request size */ - srb->sg_count = 1; - srb->segment_x[0].address = - pci_map_single(dcb->acb->dev, - cmd->request_buffer, len, dir); - /* WIDE padding */ - if (dcb->sync_period & WIDE_SYNC && len % 2) - len++; - srb->segment_x[0].length = len; - srb->total_xfer_length = len; - srb->virt_addr = cmd->request_buffer; - srb->sg_bus_addr = 0; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n", - len, cmd->request_buffer, cmd->use_sg, - srb->segment_x[0].address); - } else { - srb->sg_count = 0; - srb->total_xfer_length = 0; - srb->sg_bus_addr = 0; - srb->virt_addr = 0; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n", - cmd->bufflen, cmd->request_buffer, - cmd->use_sg, srb->segment_x[0].address); - } - } - + srb->sg_count = 0; + srb->total_xfer_length = 0; + srb->sg_bus_addr = 0; + srb->virt_addr = 0; srb->sg_index = 0; srb->adapter_status = 0; srb->target_status = 0; @@ -1306,29 +994,80 @@ srb->flag = 0; srb->state = 0; srb->retry_count = 0; - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) && debug_enabled(DBG_SGPARANOIA) - if ((unsigned long)srb->debugtrace & (DEBUGTRACEBUFSZ - 1)) { - dprintkdbg(DBG_SGPARANOIA, - "SRB %i (%p): debugtrace %p corrupt!\n", - (srb - dcb->acb->srb_array) / - sizeof(struct ScsiReqBlk), srb, srb->debugtrace); - } -#endif -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - srb->debugpos = 0; - srb->debugtrace = 0; -#endif - TRACEPRINTF("pid %li(%li):%02x %02x..(%i-%i) *", cmd->pid, - jiffies, cmd->cmnd[0], cmd->cmnd[1], - cmd->device->id, cmd->device->lun); srb->tag_number = TAG_NONE; - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ srb->end_message = 0; - return; -} + if (dir == PCI_DMA_NONE || !cmd->request_buffer) { + dprintkdbg(DBG_0, + "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", + cmd->bufflen, cmd->request_buffer, + cmd->use_sg, srb->segment_x[0].address); + } else if (cmd->use_sg) { + int i; + u32 reqlen = cmd->request_bufflen; + struct scatterlist *sl = (struct scatterlist *) + cmd->request_buffer; + struct SGentry *sgp = srb->segment_x; + srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg, + dir); + dprintkdbg(DBG_0, + "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", + reqlen, cmd->request_buffer, cmd->use_sg, + srb->sg_count); + + srb->virt_addr = page_address(sl->page); + for (i = 0; i < srb->sg_count; i++) { + u32 busaddr = (u32)sg_dma_address(&sl[i]); + u32 seglen = (u32)sl[i].length; + sgp[i].address = busaddr; + sgp[i].length = seglen; + srb->total_xfer_length += seglen; + } + sgp += srb->sg_count - 1; + + /* + * adjust last page if too big as it is allocated + * on even page boundaries + */ + if (srb->total_xfer_length > reqlen) { + sgp->length -= (srb->total_xfer_length - reqlen); + srb->total_xfer_length = reqlen; + } + + /* Fixup for WIDE padding - make sure length is even */ + if (dcb->sync_period & WIDE_SYNC && + srb->total_xfer_length % 2) { + srb->total_xfer_length++; + sgp->length++; + } + + srb->sg_bus_addr = pci_map_single(dcb->acb->dev, + srb->segment_x, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); + + dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", + srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); + } else { + srb->total_xfer_length = cmd->request_bufflen; + srb->sg_count = 1; + srb->segment_x[0].address = + pci_map_single(dcb->acb->dev, cmd->request_buffer, + srb->total_xfer_length, dir); + + /* Fixup for WIDE padding - make sure length is even */ + if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2) + srb->total_xfer_length++; + + srb->segment_x[0].length = srb->total_xfer_length; + srb->virt_addr = cmd->request_buffer; + dprintkdbg(DBG_0, + "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n", + srb->total_xfer_length, cmd->request_buffer, + cmd->use_sg, srb->segment_x[0].address); + } +} /** @@ -1350,27 +1089,14 @@ * and is expected to be held on return. * **/ -static int -dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - - dprintkdbg(DBG_0, "Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n", - cmd->cmnd[0], - cmd->device->id, - cmd->device->lun, - cmd->pid); - -#if debug_enabled(DBG_RECURSION) - if (dbg_in_driver++ > NORM_REC_LVL) { - dprintkl(KERN_DEBUG, - "%i queue_command () recursion? (pid=%li)\n", - dbg_in_driver, cmd->pid); - } -#endif + dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ cmd->result = DID_BAD_TARGET << 16; @@ -1384,8 +1110,8 @@ /* does the specified lun on the specified device exist */ if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) { - dprintkl(KERN_INFO, "Ignore target %02x lun %02x\n", cmd->device->id, - cmd->device->lun); + dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n", + cmd->device->id, cmd->device->lun); goto complete; } @@ -1393,9 +1119,8 @@ dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { /* should never happen */ - dprintkl(KERN_ERR, "no DCB failed, target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - dprintkl(KERN_ERR, "No DCB in queuecommand (2)!\n"); + dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>", + cmd->device->id, cmd->device->lun); goto complete; } @@ -1403,7 +1128,6 @@ cmd->scsi_done = done; cmd->result = 0; - /* get a free SRB */ srb = srb_get_free(acb); if (!srb) { @@ -1411,11 +1135,10 @@ * Return 1 since we are unable to queue this command at this * point in time. */ - dprintkdbg(DBG_0, "No free SRB's in queuecommand\n"); + dprintkdbg(DBG_0, "queue_command: No free srb's\n"); return 1; } - /* build srb for the command */ build_srb(cmd, dcb, srb); if (!list_empty(&dcb->srb_waiting_list)) { @@ -1426,11 +1149,7 @@ /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "... command (pid %li) queued successfully.\n", cmd->pid); - -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif + dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid); return 0; complete: @@ -1440,28 +1159,16 @@ * done when the commad is for things like non existent * devices. */ -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif done(cmd); return 0; } - - /* - ********************************************************************* - * - * Function : dc395x_bios_param - * Description: Return the disk geometry for the given SCSI device. - ********************************************************************* + * Return the disk geometry for the given SCSI device. */ -static -int dc395x_bios_param(struct scsi_device *sdev, - struct block_device *bdev, - sector_t capacity, - int *info) +static int dc395x_bios_param(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, int *info) { #ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP int heads, sectors, cylinders; @@ -1469,7 +1176,7 @@ int size = capacity; dprintkdbg(DBG_0, "dc395x_bios_param..............\n"); - acb = (struct AdapterCtlBlk *) sdev->host->hostdata; + acb = (struct AdapterCtlBlk *)sdev->host->hostdata; heads = 64; sectors = 32; cylinders = size / (heads * sectors); @@ -1489,12 +1196,8 @@ } -/* - * DC395x register dump - */ -static -void dump_register_info(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void dump_register_info(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { u16 pstat; struct pci_dev *dev = acb->dev; @@ -1504,64 +1207,58 @@ if (!srb && dcb) srb = dcb->active_srb; if (srb) { - if (!(srb->cmd)) - dprintkl(KERN_INFO, "dump: SRB %p: cmd %p OOOPS!\n", srb, - srb->cmd); + if (!srb->cmd) + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", + srb, srb->cmd); else - dprintkl(KERN_INFO, "dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n", - srb, srb->cmd, srb->cmd->pid, - srb->cmd->cmnd[0], srb->cmd->device->id, - srb->cmd->device->lun); - printk(" SGList %p Cnt %i Idx %i Len %i\n", + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) " + "cmnd=0x%02x <%02i-%i>\n", + srb, srb->cmd, srb->cmd->pid, + srb->cmd->cmnd[0], srb->cmd->device->id, + srb->cmd->device->lun); + printk(" sglist=%p cnt=%i idx=%i len=%i\n", srb->segment_x, srb->sg_count, srb->sg_index, srb->total_xfer_length); - printk - (" State %04x Status %02x Phase %02x (%sconn.)\n", - srb->state, srb->status, srb->scsi_phase, - (acb->active_dcb) ? "" : "not"); - TRACEOUT(" %s\n", srb->debugtrace); - } - dprintkl(KERN_INFO, "dump: SCSI block\n"); - printk - (" Status %04x FIFOCnt %02x Signals %02x IRQStat %02x\n", - DC395x_read16(acb, TRM_S1040_SCSI_STATUS), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS)); - printk - (" Sync %02x Target %02x RSelID %02x SCSICtr %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_SYNC), - DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), - DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - printk - (" IRQEn %02x Config %04x Cfg2 %02x Cmd %02x SelTO %02x\n", - DC395x_read8(acb, TRM_S1040_SCSI_INTEN), - DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), - DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), - DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), - DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); - dprintkl(KERN_INFO, "dump: DMA block\n"); - printk - (" Cmd %04x FIFOCnt %02x FStat %02x IRQStat %02x IRQEn %02x Cfg %04x\n", - DC395x_read16(acb, TRM_S1040_DMA_COMMAND), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - DC395x_read8(acb, TRM_S1040_DMA_INTEN), - DC395x_read16(acb, TRM_S1040_DMA_CONFIG)); - printk(" TCtr %08x CTCtr %08x Addr %08x%08x\n", - DC395x_read32(acb, TRM_S1040_DMA_XCNT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), - DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); - dprintkl(KERN_INFO, "dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n", - DC395x_read8(acb, TRM_S1040_GEN_CONTROL), - DC395x_read8(acb, TRM_S1040_GEN_STATUS), - DC395x_read8(acb, TRM_S1040_GEN_TIMER)); - dprintkl(KERN_INFO, "dump: PCI Status %04x\n", pstat); - - + printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", + srb->state, srb->status, srb->scsi_phase, + (acb->active_dcb) ? "" : "not"); + } + dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x " + "signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x " + "rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x " + "config2=0x%02x cmd=0x%02x selto=0x%02x}\n", + DC395x_read16(acb, TRM_S1040_SCSI_STATUS), + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), + DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS), + DC395x_read8(acb, TRM_S1040_SCSI_SYNC), + DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), + DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_SCSI_INTEN), + DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), + DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), + DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), + DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); + dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x " + "irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x " + "ctctr=0x%08x addr=0x%08x:0x%08x}\n", + DC395x_read16(acb, TRM_S1040_DMA_COMMAND), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read8(acb, TRM_S1040_DMA_STATUS), + DC395x_read8(acb, TRM_S1040_DMA_INTEN), + DC395x_read16(acb, TRM_S1040_DMA_CONFIG), + DC395x_read32(acb, TRM_S1040_DMA_XCNT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT), + DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), + DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); + dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} " + "pci{status=0x%04x}\n", + DC395x_read8(acb, TRM_S1040_GEN_CONTROL), + DC395x_read8(acb, TRM_S1040_GEN_STATUS), + DC395x_read8(acb, TRM_S1040_GEN_TIMER), + pstat); } @@ -1572,32 +1269,19 @@ u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); if (!(fifocnt & 0x40)) dprintkdbg(DBG_FIFO, - "Clr FIFO (%i bytes) on phase %02x in %s\n", + "clear_fifo: (%i bytes) on phase %02x in %s\n", fifocnt & 0x3f, lines, txt); #endif -#if debug_enabled(DBG_TRACE) - if (acb->active_dcb && acb->active_dcb->active_srb) { - struct ScsiReqBlk *srb = acb->active_dcb->active_srb; - TRACEPRINTF("#*"); - } -#endif DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } -/* - ******************************************************************** - * - * DC395x_reset scsi_reset_detect - * - ******************************************************************** - */ static void reset_dev_param(struct AdapterCtlBlk *acb) { struct DeviceCtlBlk *dcb; struct NvRamType *eeprom = &acb->eeprom; + dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb); - dprintkdbg(DBG_0, "reset_dev_param..............\n"); list_for_each_entry(dcb, &acb->dcb_list, list) { u8 period_index; @@ -1616,22 +1300,17 @@ /* - ********************************************************************* - * Function : int dc395x_eh_bus_reset(Scsi_Cmnd *cmd) - * Purpose : perform a hard reset on the SCSI bus - * Inputs : cmd - some command for this host (for fetching hooks) - * Returns : SUCCESS (0x2002) on success, else FAILED (0x2003). - ********************************************************************* + * perform a hard reset on the SCSI bus + * @cmd - some command for this host (for fetching hooks) + * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). */ -static int dc395x_eh_bus_reset(Scsi_Cmnd * cmd) +static int dc395x_eh_bus_reset(Scsi_Cmnd *cmd) { - struct AdapterCtlBlk *acb; - /*u32 acb_flags=0; */ - - dprintkl(KERN_INFO, "reset requested!\n"); - acb = (struct AdapterCtlBlk *) cmd->device->host->hostdata; - /* mid level guarantees no recursion */ - /*DC395x_ACB_LOCK(acb,acb_flags); */ + struct AdapterCtlBlk *acb = + (struct AdapterCtlBlk *)cmd->device->host->hostdata; + dprintkl(KERN_INFO, + "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -1657,52 +1336,42 @@ */ /* Clear SCSI FIFO */ DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - clear_fifo(acb, "reset"); + clear_fifo(acb, "eh_bus_reset"); /* Delete pending IRQ */ DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); set_basic_config(acb); reset_dev_param(acb); doing_srb_done(acb, DID_RESET, cmd, 0); - acb->active_dcb = NULL; - acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ waiting_process_next(acb); - /*DC395x_ACB_LOCK(acb,acb_flags); */ return SUCCESS; } /* - ********************************************************************* - * Function : int dc395x_eh_abort(Scsi_Cmnd *cmd) - * Purpose : abort an errant SCSI command - * Inputs : cmd - command to be aborted - * Returns : SUCCESS (0x2002) on success, else FAILED (0x2003). - ********************************************************************* + * abort an errant SCSI command + * @cmd - command to be aborted + * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). */ -static int dc395x_eh_abort(Scsi_Cmnd * cmd) +static int dc395x_eh_abort(Scsi_Cmnd *cmd) { /* * Look into our command queues: If it has not been sent already, * we remove it and return success. Otherwise fail. */ struct AdapterCtlBlk *acb = - (struct AdapterCtlBlk *) cmd->device->host->hostdata; + (struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; - - dprintkl(KERN_INFO, "eh abort: cmd %p (pid %li, %02i-%i) ", - cmd, - cmd->pid, - cmd->device->id, - cmd->device->lun); + dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { - dprintkl(KERN_DEBUG, "abort - no DCB found"); + dprintkl(KERN_DEBUG, "eh_abort: No such device\n"); return FAILED; } @@ -1713,32 +1382,31 @@ pci_unmap_srb(acb, srb); free_tag(dcb, srb); srb_free_insert(acb, srb); - dprintkl(KERN_DEBUG, "abort - command found in waiting commands queue"); + dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); cmd->result = DID_ABORT << 16; return SUCCESS; } srb = find_cmd(cmd, &dcb->srb_going_list); if (srb) { - dprintkl(KERN_DEBUG, "abort - command currently in progress"); + dprintkl(KERN_DEBUG, "eh_abort: Command in progress"); /* XXX: Should abort the command here */ } else { - dprintkl(KERN_DEBUG, "abort - command not found"); + dprintkl(KERN_DEBUG, "eh_abort: Command not found"); } return FAILED; } /* SDTR */ -static -void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, +static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { u8 *ptr = srb->msgout_buf + srb->msg_count; if (srb->msg_count > 1) { dprintkl(KERN_INFO, - "Build_SDTR: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); + "build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n", + srb->msg_count, srb->msgout_buf[0], + srb->msgout_buf[1]); return; } if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) { @@ -1754,25 +1422,21 @@ *ptr++ = dcb->sync_offset; /* Transfer period (max. REQ/ACK dist) */ srb->msg_count += 5; srb->state |= SRB_DO_SYNC_NEGO; - TRACEPRINTF("S *"); } -/* SDTR */ -static -void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, +/* WDTR */ +static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - u8 wide = - ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & (acb-> - config & HCC_WIDE_CARD)) - ? 1 : 0; + u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & + (acb->config & HCC_WIDE_CARD)) ? 1 : 0; u8 *ptr = srb->msgout_buf + srb->msg_count; if (srb->msg_count > 1) { dprintkl(KERN_INFO, - "Build_WDTR: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); + "build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n", + srb->msg_count, srb->msgout_buf[0], + srb->msgout_buf[1]); return; } *ptr++ = MSG_EXTENDED; /* (01h) */ @@ -1781,7 +1445,6 @@ *ptr++ = wide; srb->msg_count += 4; srb->state |= SRB_DO_WIDE_NEGO; - TRACEPRINTF("W *"); } @@ -1809,7 +1472,7 @@ void selection_timeout_missed(unsigned long ptr) { unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr; + struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; struct ScsiReqBlk *srb; dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); if (!acb->active_dcb || !acb->active_dcb->active_srb) { @@ -1818,39 +1481,30 @@ } DC395x_LOCK_IO(acb->scsi_host, flags); srb = acb->active_dcb->active_srb; - TRACEPRINTF("N/TO *"); disconnect(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); } #endif -/* - * scsiio - * DC395x_DoWaitingSRB srb_done - * send_srb request_sense - */ -static -u8 start_scsi(struct AdapterCtlBlk * acb, struct DeviceCtlBlk * dcb, - struct ScsiReqBlk * srb) +static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, + struct ScsiReqBlk* srb) { u16 s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; + dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); - dprintkdbg(DBG_0, "start_scsi..............\n"); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); s_stat2 = 0; s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); - TRACEPRINTF("Start %02x *", s_stat); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, - "StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, - s_stat, s_stat2); + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n", + srb->cmd->pid, s_stat, s_stat2); /* * Try anyway? * @@ -1861,41 +1515,32 @@ * Instead let this fail and have the timer make sure the command is * tried again after a short time */ - TRACEPRINTF("^*"); /*selto_timer (acb); */ - /*monitor_next_irq = 1; */ return 1; } #endif if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "We try to start a SCSI command (%li)!\n", - srb->cmd->pid); - dprintkl(KERN_DEBUG, "While another one (%li) is active!!\n", - (acb->active_dcb->active_srb ? acb->active_dcb-> - active_srb->cmd->pid : 0)); - TRACEOUT(" %s\n", srb->debugtrace); - if (acb->active_dcb->active_srb) - TRACEOUT(" %s\n", - acb->active_dcb->active_srb->debugtrace); + dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a" + "command while another command (pid#%li) is active.", + srb->cmd->pid, + acb->active_dcb->active_srb ? + acb->active_dcb->active_srb->cmd->pid : 0); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, - "StartSCSI failed (busy) for pid %li(%02i-%i)\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); - TRACEPRINTF("°*"); + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n", + srb->cmd->pid); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level * to queue them again after a reset */ if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) { - dprintkdbg(DBG_KG, - "We were just reset and don't accept commands yet!\n"); + dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); return 1; } /* Flush FIFO */ - clear_fifo(acb, "Start"); + clear_fifo(acb, "start_scsi"); DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); @@ -1939,9 +1584,7 @@ } srb->msg_count = 0; } - /* - ** Send identify message - */ + /* Send identify message */ DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message); scsicommand = SCMD_SEL_ATN; @@ -1958,37 +1601,29 @@ tag_number++; } if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, - "Start_SCSI: Out of tags for pid %li (%i-%i)\n", - srb->cmd->pid, srb->cmd->device->id, - srb->cmd->device->lun); + dprintkl(KERN_WARNING, "start_scsi: (pid#%li) " + "Out of tags target=<%02i-%i>)\n", + srb->cmd->pid, srb->cmd->device->id, + srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); return 1; } - /* - ** Send Tag id - */ + /* Send Tag id */ DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number); dcb->tag_mask |= tag_mask; srb->tag_number = tag_number; - TRACEPRINTF("Tag %i *", tag_number); - scsicommand = SCMD_SEL_ATN3; srb->state = SRB_START_; } #endif /*polling:*/ - /* - * Send CDB ..command block ......... - */ - dprintkdbg(DBG_KG, - "StartSCSI (pid %li) %02x (%i-%i): Tag %i\n", - srb->cmd->pid, srb->cmd->cmnd[0], - srb->cmd->device->id, srb->cmd->device->lun, - srb->tag_number); + /* Send CDB ..command block ......... */ + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); @@ -1998,7 +1633,7 @@ sizeof(srb->cmd->sense_buffer)); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); } else { - ptr = (u8 *) srb->cmd->cmnd; + ptr = (u8 *)srb->cmd->cmnd; for (i = 0; i < srb->cmd->cmd_len; i++) DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); } @@ -2011,10 +1646,8 @@ * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - dprintkdbg(DBG_0, "Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", + dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n", srb->cmd->pid, dcb->target_id, dcb->target_lun); - /*clear_fifo (acb, "Start2"); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -2032,23 +1665,13 @@ /* it's important for atn stop */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT); - /* - ** SCSI command - */ - TRACEPRINTF("%02x *", scsicommand); + /* SCSI command */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand); } return return_code; } -/* - ******************************************************************** - * scsiio - * init_adapter - ******************************************************************** - */ - /** * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to * have been triggered for this card. @@ -2056,37 +1679,29 @@ * @acb: a pointer to the adpter control block * @scsi_status: the status return when we checked the card **/ -static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, u16 scsi_status) +static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, + u16 scsi_status) { struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; u16 phase; u8 scsi_intstatus; unsigned long flags; - void (*dc395x_statev) (struct AdapterCtlBlk *, struct ScsiReqBlk *, - u16 *); + void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, + u16 *); DC395x_LOCK_IO(acb->scsi_host, flags); /* This acknowledges the IRQ */ scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); if ((scsi_status & 0x2007) == 0x2002) - dprintkl(KERN_DEBUG, "COP after COP completed? %04x\n", - scsi_status); -#if 1 /*def DBG_0 */ - if (monitor_next_irq) { - dprintkl(KERN_INFO, - "status=%04x intstatus=%02x\n", scsi_status, - scsi_intstatus); - monitor_next_irq--; - } -#endif - /*DC395x_ACB_LOCK(acb,acb_flags); */ + dprintkl(KERN_DEBUG, + "COP after COP completed? %04x\n", scsi_status); if (debug_enabled(DBG_KG)) { if (scsi_intstatus & INT_SELTIMEOUT) - dprintkdbg(DBG_KG, "Sel Timeout IRQ\n"); + dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n"); } - /*dprintkl(KERN_DEBUG, "DC395x_IRQ: intstatus = %02x ", scsi_intstatus); */ + /*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */ if (timer_pending(&acb->selto_timer)) del_timer(&acb->selto_timer); @@ -2111,8 +1726,8 @@ dcb = acb->active_dcb; if (!dcb) { dprintkl(KERN_DEBUG, - "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", - scsi_status, scsi_intstatus); + "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", + scsi_status, scsi_intstatus); goto out_unlock; } srb = dcb->active_srb; @@ -2120,12 +1735,10 @@ dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); enable_msgout_abort(acb, srb); } - /* - ************************************************************ - * software sequential machine - ************************************************************ - */ - phase = (u16) srb->scsi_phase; + + /* software sequential machine */ + phase = (u16)srb->scsi_phase; + /* * 62037 or 62137 * call dc395x_scsi_phase0[]... "phase entry" @@ -2139,22 +1752,20 @@ /* nop0, phase:5 PH_BUS_FREE .. initial phase */ /* msgout_phase0, phase:6 */ /* msgin_phase0, phase:7 */ - dc395x_statev = (void *) dc395x_scsi_phase0[phase]; + dc395x_statev = dc395x_scsi_phase0[phase]; dc395x_statev(acb, srb, &scsi_status); + /* - *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ - * - * if there were any exception occured - * scsi_status will be modify to bus free phase - * new scsi_status transfer out from ... previous dc395x_statev - * - *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + * if there were any exception occured scsi_status + * will be modify to bus free phase new scsi_status + * transfer out from ... previous dc395x_statev */ srb->scsi_phase = scsi_status & PHASEMASK; - phase = (u16) scsi_status & PHASEMASK; + phase = (u16)scsi_status & PHASEMASK; + /* - * call dc395x_scsi_phase1[]... "phase entry" - * handle every phase do transfer + * call dc395x_scsi_phase1[]... "phase entry" handle + * every phase to do transfer */ /* data_out_phase1, phase:0 */ /* data_in_phase1, phase:1 */ @@ -2164,30 +1775,22 @@ /* nop1, phase:5 PH_BUS_FREE .. initial phase */ /* msgout_phase1, phase:6 */ /* msgin_phase1, phase:7 */ - dc395x_statev = (void *) dc395x_scsi_phase1[phase]; + dc395x_statev = dc395x_scsi_phase1[phase]; dc395x_statev(acb, srb, &scsi_status); } out_unlock: DC395x_UNLOCK_IO(acb->scsi_host, flags); - return; } -static -irqreturn_t dc395x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc395x_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id; u16 scsi_status; u8 dma_status; irqreturn_t handled = IRQ_NONE; - dprintkdbg(DBG_0, "dc395x_interrupt..............\n"); -#if debug_enabled(DBG_RECURSION) - if (dbg_in_driver++ > NORM_REC_LVL) { - dprintkl(KERN_DEBUG, "%i interrupt recursion?\n", dbg_in_driver); - } -#endif - /* * Check for pending interupt */ @@ -2200,7 +1803,7 @@ } else if (dma_status & 0x20) { /* Error from the DMA engine */ - dprintkl(KERN_INFO, "Interrupt from DMA engine: %02x!\n", dma_status); + dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status); #if 0 dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); if (acb->active_dcb) { @@ -2216,135 +1819,75 @@ handled = IRQ_HANDLED; } -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif return handled; } -/* - ******************************************************************** - * scsiio - * msgout_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =6 - ******************************************************************** - */ -static -void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0.....\n"); - if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) { + dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid); + if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - } + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ srb->state &= ~SRB_MSGOUT; - TRACEPRINTF("MOP0 *"); } -/* - ******************************************************************** - * scsiio - * msgout_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =6 - ******************************************************************** - */ -static -void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { u16 i; u8 *ptr; - struct DeviceCtlBlk *dcb; + dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid); - dprintkdbg(DBG_0, "msgout_phase1..............\n"); - TRACEPRINTF("MOP1*"); - dcb = acb->active_dcb; - clear_fifo(acb, "MOP1"); + clear_fifo(acb, "msgout_phase1"); if (!(srb->state & SRB_MSGOUT)) { srb->state |= SRB_MSGOUT; - dprintkl(KERN_DEBUG, "Debug: pid %li: MsgOut Phase unexpected.\n", srb->cmd->pid); /* So what ? */ + dprintkl(KERN_DEBUG, + "msgout_phase1: (pid#%li) Phase unexpected\n", + srb->cmd->pid); /* So what ? */ } if (!srb->msg_count) { - dprintkdbg(DBG_0, "Debug: pid %li: NOP Msg (no output message there).\n", + dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n", srb->cmd->pid); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); - TRACEPRINTF("\\*"); - TRACEOUT(" %s\n", srb->debugtrace); return; } - ptr = (u8 *) srb->msgout_buf; - TRACEPRINTF("(*"); - /*dprintkl(KERN_DEBUG, "Send msg: "); print_msg (ptr, srb->msg_count); */ - /*dprintkl(KERN_DEBUG, "MsgOut: "); */ - for (i = 0; i < srb->msg_count; i++) { - TRACEPRINTF("%02x *", *ptr); + ptr = (u8 *)srb->msgout_buf; + for (i = 0; i < srb->msg_count; i++) DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); - } - TRACEPRINTF(")*"); srb->msg_count = 0; - /*printk("\n"); */ - if (/*(dcb->flag & ABORT_DEV_) && */ - (srb->msgout_buf[0] == MSG_ABORT)) + if (srb->msgout_buf[0] == MSG_ABORT) srb->state = SRB_ABORT_SENT; - /*1.25 */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); *//* it's important for atn stop */ - /* - ** SCSI command - */ - /*TRACEPRINTF (".*"); */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } -/* - ******************************************************************** - * scsiio - * command_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =2 - ******************************************************************** - */ -static -void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - TRACEPRINTF("COP0 *"); - /*1.25 */ - /*clear_fifo (acb, COP0); */ + dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } -/* - ******************************************************************** - * scsiio - * command_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =2 - ******************************************************************** - */ -static -void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; + dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid); - dprintkdbg(DBG_0, "command_phase1..............\n"); - TRACEPRINTF("COP1*"); - clear_fifo(acb, "COP1"); + clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); if (!(srb->flag & AUTO_REQSENSE)) { - ptr = (u8 *) srb->cmd->cmnd; + ptr = (u8 *)srb->cmd->cmnd; for (i = 0; i < srb->cmd->cmd_len; i++) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr); ptr++; @@ -2364,22 +1907,24 @@ /* it's important for atn stop */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* SCSI command */ - TRACEPRINTF(".*"); DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } -/* Do sanity checks for S/G list */ -static inline void check_sg_list(struct ScsiReqBlk *srb) +/* + * Verify that the remaining space in the hw sg lists is the same as + * the count of remaining bytes in srb->total_xfer_length + */ +static void sg_verify_length(struct ScsiReqBlk *srb) { - if (debug_enabled(DBG_SGPARANOIA)) { + if (debug_enabled(DBG_SG)) { unsigned len = 0; unsigned idx = srb->sg_index; struct SGentry *psge = srb->segment_x + idx; for (; idx < srb->sg_count; psge++, idx++) len += psge->length; if (len != srb->total_xfer_length) - dprintkdbg(DBG_SGPARANOIA, + dprintkdbg(DBG_SG, "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", srb->total_xfer_length, len); } @@ -2390,75 +1935,90 @@ * Compute the next Scatter Gather list index and adjust its length * and address if necessary; also compute virt_addr */ -static void update_sg_list(struct ScsiReqBlk *srb, u32 left) +static void sg_update_list(struct ScsiReqBlk *srb, u32 left) { - struct SGentry *psge; - u32 xferred = 0; u8 idx; - Scsi_Cmnd *cmd = srb->cmd; struct scatterlist *sg; + Scsi_Cmnd *cmd = srb->cmd; int segment = cmd->use_sg; + u32 xferred = srb->total_xfer_length - left; /* bytes transfered */ + struct SGentry *psge = srb->segment_x + srb->sg_index; - dprintkdbg(DBG_KG, "Update SG: Total %i, Left %i\n", - srb->total_xfer_length, left); - check_sg_list(srb); - psge = srb->segment_x + srb->sg_index; - /* data that has already been transferred */ - xferred = srb->total_xfer_length - left; - if (srb->total_xfer_length != left) { - /*check_sg_list_TX (srb, xferred); */ - /* Remaining */ - srb->total_xfer_length = left; - /* parsing from last time disconnect SGIndex */ - for (idx = srb->sg_index; idx < srb->sg_count; idx++) { + dprintkdbg(DBG_0, + "sg_update_list: Transfered %i of %i bytes, %i remain\n", + xferred, srb->total_xfer_length, left); + if (xferred == 0) { + /* nothing to update since we did not transfer any data */ + return; + } + + sg_verify_length(srb); + srb->total_xfer_length = left; /* update remaining count */ + for (idx = srb->sg_index; idx < srb->sg_count; idx++) { + if (xferred >= psge->length) { /* Complete SG entries done */ - if (xferred >= psge->length) - xferred -= psge->length; - /* Partial SG entries done */ - else { - psge->length -= xferred; /* residue data length */ - psge->address += xferred; /* residue data pointer */ - srb->sg_index = idx; - pci_dma_sync_single(srb->dcb-> - acb->dev, - srb->sg_bus_addr, - sizeof(struct SGentry) - * - DC395x_MAX_SG_LISTENTRY, - PCI_DMA_TODEVICE); - break; - } - psge++; + xferred -= psge->length; + } else { + /* Partial SG entry done */ + psge->length -= xferred; + psge->address += xferred; + srb->sg_index = idx; + pci_dma_sync_single_for_device(srb->dcb-> + acb->dev, + srb->sg_bus_addr, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); + break; } - check_sg_list(srb); + psge++; } - /* We need the corresponding virtual address sg_to_virt */ - /*dprintkl(KERN_DEBUG, "sg_to_virt: bus %08x -> virt ", psge->address); */ + sg_verify_length(srb); + + /* we need the corresponding virtual address */ if (!segment) { srb->virt_addr += xferred; - /*printk("%p\n", srb->virt_addr); */ return; } + /* We have to walk the scatterlist to find it */ - sg = (struct scatterlist *) cmd->request_buffer; + sg = (struct scatterlist *)cmd->request_buffer; while (segment--) { - /*printk("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */ unsigned long mask = - ~((unsigned long) sg->length - 1) & PAGE_MASK; - if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) { - srb->virt_addr = (PAGE_ADDRESS(sg) + ~((unsigned long)sg->length - 1) & PAGE_MASK; + if ((sg_dma_address(sg) & mask) == (psge->address & mask)) { + srb->virt_addr = (page_address(sg->page) + psge->address - (psge->address & PAGE_MASK)); - /*printk("%p\n", srb->virt_addr); */ return; } ++sg; } - dprintkl(KERN_ERR, "sg_to_virt failed!\n"); + + dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n"); srb->virt_addr = 0; } +/* + * We have transfered a single byte (PIO mode?) and need to update + * the count of bytes remaining (total_xfer_length) and update the sg + * entry to either point to next byte in the current sg entry, or of + * already at the end to point to the start of the next sg entry + */ +static void sg_subtract_one(struct ScsiReqBlk *srb) +{ + srb->total_xfer_length--; + srb->segment_x[srb->sg_index].length--; + if (srb->total_xfer_length && + !srb->segment_x[srb->sg_index].length) { + if (debug_enabled(DBG_PIO)) + printk(" (next segment)"); + srb->sg_index++; + sg_update_list(srb, srb->total_xfer_length); + } +} + + /* * cleanup_after_transfer * @@ -2467,27 +2027,21 @@ * Should probably also be called from other places * Best might be to call it in DataXXPhase0, if new phase will differ */ -static -void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static void cleanup_after_transfer(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { - TRACEPRINTF(" Cln*"); /*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */ if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) { /* read */ if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "ClnIn"); - + clear_fifo(acb, "cleanup/in"); if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); } else { /* write */ if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "ClnOut"); - + clear_fifo(acb, "cleanup/out"); } - /*1.25 */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -2497,26 +2051,16 @@ * Seems to be needed for unknown reasons; could be a hardware bug :-( */ #define DC395x_LASTPIO 4 -/* - ******************************************************************** - * scsiio - * data_out_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =0 - ******************************************************************** - */ -static -void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) + + +static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - u16 scsi_status; - u32 d_left_counter = 0; struct DeviceCtlBlk *dcb = srb->dcb; - - dprintkdbg(DBG_0, "data_out_phase0.....\n"); - TRACEPRINTF("DOP0*"); - dcb = srb->dcb; - scsi_status = *pscsi_status; + u16 scsi_status = *pscsi_status; + u32 d_left_counter = 0; + dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -2530,12 +2074,14 @@ * KG: Stop DMA engine pushing more data into the SCSI FIFO * If we need more data, the DMA SG list will be freshly set up, anyway */ - dprintkdbg(DBG_PIO, "DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, - srb->total_xfer_length); + dprintkdbg(DBG_PIO, "data_out_phase0: " + "DMA{fifcnt=0x%02x fifostat=0x%02x} " + "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, + srb->total_xfer_length); DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); if (!(srb->state & SRB_XFERPAD)) { @@ -2554,31 +2100,21 @@ * if there was some data left in SCSI FIFO */ d_left_counter = - (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); + (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & + 0x1F); if (dcb->sync_period & WIDE_SYNC) d_left_counter <<= 1; - dprintkdbg(DBG_KG, - "Debug: SCSI FIFO contains %i %s in DOP0\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - (dcb-> - sync_period & WIDE_SYNC) ? "words" : - "bytes"); - dprintkdbg(DBG_KG, - "SCSI FIFOCNT %02x, SCSI CTR %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - dprintkdbg(DBG_KG, - "DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); - - /* - * if WIDE scsi SCSI FIFOCNT unit is word !!! - * so need to *= 2 - */ + dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n" + "SCSI{fifocnt=0x%02x cnt=0x%08x} " + "DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + (dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); } /* * calculate all the residue data that not yet tranfered @@ -2592,16 +2128,16 @@ if (srb->total_xfer_length > DC395x_LASTPIO) d_left_counter += DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); - TRACEPRINTF("%06x *", d_left_counter); /* Is this a good idea? */ - /*clear_fifo (acb, "DOP1"); */ + /*clear_fifo(acb, "DOP1"); */ /* KG: What is this supposed to be useful for? WIDE padding stuff? */ if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC && srb->cmd->request_bufflen % 2) { d_left_counter = 0; - dprintkl(KERN_INFO, "DOP0: Discard 1 byte. (%02x)\n", - scsi_status); + dprintkl(KERN_INFO, + "data_out_phase0: Discard 1 byte (0x%02x)\n", + scsi_status); } /* * KG: Oops again. Same thinko as above: The SCSI might have been @@ -2613,19 +2149,9 @@ * KG: This is nonsense: We have been WRITING data to the bus * If the SCSI engine has no bytes left, how should the DMA engine? */ - if ((d_left_counter == - 0) /*|| (scsi_status & SCSIXFERCNT_2_ZERO) ) */ ) { - /* - * int ctr = 6000000; u8 TempDMAstatus; - * do - * { - * TempDMAstatus = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - * } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr); - * if (ctr < 6000000-1) dprintkl(KERN_DEBUG, "DMA should be complete ... in DOP1\n"); - * if (!ctr) dprintkl(KERN_ERR, "Deadlock in DataOutPhase0 !!\n"); - */ + if (d_left_counter == 0) { srb->total_xfer_length = 0; - } else { /* Update SG list */ + } else { /* * if transfer not yet complete * there were some data residue in SCSI FIFO or @@ -2635,18 +2161,18 @@ srb->total_xfer_length - d_left_counter; const int diff = (dcb->sync_period & WIDE_SYNC) ? 2 : 1; - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); /* KG: Most ugly hack! Apparently, this works around a chip bug */ if ((srb->segment_x[srb->sg_index].length == diff && srb->cmd->use_sg) || ((oldxferred & ~PAGE_MASK) == (PAGE_SIZE - diff)) ) { - dprintkl(KERN_INFO, - "Work around chip bug (%i)?\n", diff); + dprintkl(KERN_INFO, "data_out_phase0: " + "Work around chip bug (%i)?\n", diff); d_left_counter = srb->total_xfer_length - diff; - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); /*srb->total_xfer_length -= diff; */ /*srb->virt_addr += diff; */ /*if (srb->cmd->use_sg) */ @@ -2654,71 +2180,30 @@ } } } -#if 0 - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - dprintkl(KERN_DEBUG, - "DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n", - srb->cmd->pid, - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f); -#endif - /*clear_fifo (acb, "DOP0"); */ - /*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */ -#if 1 if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { - /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data Out ...\n"); */ cleanup_after_transfer(acb, srb); } -#endif - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_out_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =0 - * 62037 - ******************************************************************** - */ -static -void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - - dprintkdbg(DBG_0, "data_out_phase1.....\n"); - /*1.25 */ - TRACEPRINTF("DOP1*"); - clear_fifo(acb, "DOP1"); - /* - ** do prepare befor transfer when data out phase - */ + dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + clear_fifo(acb, "data_out_phase1"); + /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_in_phase0: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =1 - ******************************************************************** - */ -static -void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - u16 scsi_status; + u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; - /*struct DeviceCtlBlk* dcb = srb->dcb; */ - /*u8 bval; */ - - dprintkdbg(DBG_0, "data_in_phase0..............\n"); - TRACEPRINTF("DIP0*"); - scsi_status = *pscsi_status; + dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2735,10 +2220,8 @@ */ if (!(srb->state & SRB_XFERPAD)) { if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, - "Parity Error (pid %li, target %02i-%i)\n", - srb->cmd->pid, srb->cmd->device->id, - srb->cmd->device->lun); + dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " + "Parity Error\n", srb->cmd->pid); srb->status |= PARITY_ERROR; } /* @@ -2751,7 +2234,7 @@ #if 0 int ctr = 6000000; dprintkl(KERN_DEBUG, - "DIP0: Wait for DMA FIFO to flush ...\n"); + "DIP0: Wait for DMA FIFO to flush ...\n"); /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ @@ -2766,73 +2249,56 @@ "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ #endif - dprintkdbg(DBG_KG, "DIP0: DMA_FIFO: %02x %02x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); + dprintkdbg(DBG_KG, "data_in_phase0: " + "DMA{fifocnt=0x%02x fifostat=0x%02x}\n", + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); } /* Now: Check remainig data: The SCSI counters should tell us ... */ d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER) + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f) << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 0)); - - dprintkdbg(DBG_KG, "SCSI FIFO contains %i %s in DIP0\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, - (srb->dcb-> - sync_period & WIDE_SYNC) ? "words" : "bytes"); - dprintkdbg(DBG_KG, "SCSI FIFOCNT %02x, SCSI CTR %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - dprintkdbg(DBG_KG, "DMA FIFOCNT %02x,%02x DMA CTR %08x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); - dprintkdbg(DBG_KG, "Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n", - srb->total_xfer_length, d_left_counter); + dprintkdbg(DBG_KG, "data_in_phase0: " + "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " + "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " + "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT), + srb->total_xfer_length, d_left_counter); #if DC395x_LASTPIO /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ if (d_left_counter && srb->total_xfer_length <= DC395x_LASTPIO) { /*u32 addr = (srb->segment_x[srb->sg_index].address); */ - /*update_sg_list (srb, d_left_counter); */ - dprintkdbg(DBG_PIO, "DIP0: PIO (%i %s) to %p for remaining %i bytes:", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1f, - (srb->dcb-> - sync_period & WIDE_SYNC) ? "words" : - "bytes", srb->virt_addr, - srb->total_xfer_length); - + /*sg_update_list (srb, d_left_counter); */ + dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to " + "%p for remaining %i bytes:", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, + (srb->dcb->sync_period & WIDE_SYNC) ? + "words" : "bytes", + srb->virt_addr, + srb->total_xfer_length); if (srb->dcb->sync_period & WIDE_SYNC) DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - - while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != - 0x40) { - u8 byte = - DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) { + u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); *(srb->virt_addr)++ = byte; if (debug_enabled(DBG_PIO)) printk(" %02x", byte); - srb->total_xfer_length--; d_left_counter--; - srb->segment_x[srb->sg_index].length--; - if (srb->total_xfer_length - && !srb->segment_x[srb->sg_index]. - length) { - if (debug_enabled(DBG_PIO)) - printk(" (next segment)"); - srb->sg_index++; - update_sg_list(srb, - d_left_counter); - } + sg_subtract_one(srb); } if (srb->dcb->sync_period & WIDE_SYNC) { -#if 1 /* Read the last byte ... */ +#if 1 + /* Read the last byte ... */ if (srb->total_xfer_length > 0) { - u8 byte = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); + u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); *(srb->virt_addr)++ = byte; srb->total_xfer_length--; if (debug_enabled(DBG_PIO)) @@ -2859,8 +2325,8 @@ * if there was some data left in SCSI FIFO */ d_left_counter = - (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); + (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & + 0x1F); if (srb->dcb->sync_period & WIDE_SYNC) d_left_counter <<= 1; /* @@ -2870,19 +2336,8 @@ */ } #endif - /*d_left_counter += DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); */ -#if 0 - dprintkl(KERN_DEBUG, - "DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n", - d_left_counter, DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT)); - dprintkl(KERN_DEBUG, "DIP0: DMAStat %02x\n", - DC395x_read8(acb, TRM_S1040_DMA_STATUS)); -#endif - /* KG: This should not be needed any more! */ - if ((d_left_counter == 0) + if (d_left_counter == 0 || (scsi_status & SCSIXFERCNT_2_ZERO)) { #if 0 int ctr = 6000000; @@ -2896,12 +2351,6 @@ "Deadlock in DataInPhase0 waiting for DMA!!\n"); srb->total_xfer_length = 0; #endif -#if 0 /*def DBG_KG */ - dprintkl(KERN_DEBUG, - "DIP0: DMA not yet ready: %02x: %i -> %i bytes\n", - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - srb->total_xfer_length, d_left_counter); -#endif srb->total_xfer_length = d_left_counter; } else { /* phase changed */ /* @@ -2912,333 +2361,209 @@ * there were some data residue in SCSI FIFO or * SCSI transfer counter not empty */ - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); } } /* KG: The target may decide to disconnect: Empty FIFO before! */ if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { - /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data In ...\n"); */ cleanup_after_transfer(acb, srb); } -#if 0 - /* KG: Make sure, no previous transfers are pending! */ - bval = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - if (!(bval & 0x40)) { - bval &= 0x1f; - dprintkl(KERN_DEBUG, - "DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n", - srb->cmd->pid, bval & 0x1f, scsi_status, - d_left_counter); - if ((d_left_counter == 0) - || (scsi_status & SCSIXFERCNT_2_ZERO)) { - dprintkl(KERN_DEBUG, "Clear FIFO!\n"); - clear_fifo(acb, "DIP0"); - } - } -#endif - /*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */ - - /*clear_fifo (acb, "DIP0"); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */ - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_in_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =1 - ******************************************************************** - */ -static -void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "data_in_phase1.....\n"); - /* FIFO should be cleared, if previous phase was not DataPhase */ - /*clear_fifo (acb, "DIP1"); */ - /* Allow data in! */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */ - TRACEPRINTF("DIP1:*"); - /* - ** do prepare before transfer when data in phase - */ +static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_out_phase1 - * data_in_phase1 - ******************************************************************** - */ -static -void data_io_transfer(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 io_dir) +static void data_io_transfer(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb, u16 io_dir) { + struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; - struct DeviceCtlBlk *dcb; - - dprintkdbg(DBG_0, "DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n", - ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->cmd->pid, - srb->total_xfer_length, srb->sg_index, - srb->sg_count); - TRACEPRINTF("%05x(%i/%i)*", srb->total_xfer_length, - srb->sg_index, srb->sg_count); - dcb = srb->dcb; - if (srb == acb->tmp_srb) { - dprintkl(KERN_ERR, "Using tmp_srb in DataPhase!\n"); - } - if (srb->sg_index < srb->sg_count) { - if (srb->total_xfer_length > DC395x_LASTPIO) { - u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - /* - * KG: What should we do: Use SCSI Cmd 0x90/0x92? - * Maybe, even ABORTXFER would be appropriate - */ - if (dma_status & XFERPENDING) { - dprintkl(KERN_DEBUG, "Xfer pending! Expect trouble!!\n"); - dump_register_info(acb, dcb, srb); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, - CLRXFIFO); - } - /*clear_fifo (acb, "IO"); */ - /* - * load what physical address of Scatter/Gather list table want to be - * transfer - */ - srb->state |= SRB_DATA_XFER; - DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); - if (srb->cmd->use_sg) { /* with S/G */ - io_dir |= DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->sg_bus_addr + - sizeof(struct SGentry) * - srb->sg_index); - /* load how many bytes in the Scatter/Gather list table */ - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - ((u32) - (srb->sg_count - - srb->sg_index) << 3)); - } else { /* without S/G */ - io_dir &= ~DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->segment_x[0].address); - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - srb->segment_x[0].length); - } - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_IN); - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, - io_dir); - } else { - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, - io_dir); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_OUT); - } + dprintkdbg(DBG_0, + "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + ((io_dir & DMACMD_DIR) ? 'r' : 'w'), + srb->total_xfer_length, srb->sg_index, srb->sg_count); + if (srb == acb->tmp_srb) + dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n"); + if (srb->sg_index >= srb->sg_count) { + /* can't happen? out of bounds error */ + return; + } + if (srb->total_xfer_length > DC395x_LASTPIO) { + u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); + /* + * KG: What should we do: Use SCSI Cmd 0x90/0x92? + * Maybe, even ABORTXFER would be appropriate + */ + if (dma_status & XFERPENDING) { + dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! " + "Expect trouble!\n"); + dump_register_info(acb, dcb, srb); + DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); } + /* clear_fifo(acb, "IO"); */ + /* + * load what physical address of Scatter/Gather list table + * want to be transfer + */ + srb->state |= SRB_DATA_XFER; + DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); + if (srb->cmd->use_sg) { /* with S/G */ + io_dir |= DMACMD_SG; + DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, + srb->sg_bus_addr + + sizeof(struct SGentry) * + srb->sg_index); + /* load how many bytes in the sg list table */ + DC395x_write32(acb, TRM_S1040_DMA_XCNT, + ((u32)(srb->sg_count - + srb->sg_index) << 3)); + } else { /* without S/G */ + io_dir &= ~DMACMD_SG; + DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, + srb->segment_x[0].address); + DC395x_write32(acb, TRM_S1040_DMA_XCNT, + srb->segment_x[0].length); + } + /* load total transfer length (24bits) max value 16Mbyte */ + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, + srb->total_xfer_length); + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + if (io_dir & DMACMD_DIR) { /* read */ + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_DMA_IN); + DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); + } else { + DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_DMA_OUT); + } + + } #if DC395x_LASTPIO - else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ - /*clear_fifo (acb, "IO"); */ - /* - * load what physical address of Scatter/Gather list table want to be - * transfer - */ - srb->state |= SRB_DATA_XFER; - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_IN); - } else { /* write */ - int ln = srb->total_xfer_length; - if (srb->dcb->sync_period & WIDE_SYNC) - DC395x_write8 - (acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - dprintkdbg(DBG_PIO, "DOP1: PIO %i bytes from %p:", - srb->total_xfer_length, - srb->virt_addr); - while (srb->total_xfer_length) { - if (debug_enabled(DBG_PIO)) - printk(" %02x", (unsigned char) *(srb->virt_addr)); - DC395x_write8 - (acb, TRM_S1040_SCSI_FIFO, - *(srb->virt_addr)++); - srb->total_xfer_length--; - srb->segment_x[srb->sg_index]. - length--; - if (srb->total_xfer_length - && !srb->segment_x[srb-> - sg_index]. - length) { - if (debug_enabled(DBG_PIO)) - printk(" (next segment)"); - srb->sg_index++; - update_sg_list(srb, - srb->total_xfer_length); - } - } - if (srb->dcb->sync_period & WIDE_SYNC) { - if (ln % 2) { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - if (debug_enabled(DBG_PIO)) - printk(" |00"); - } - DC395x_write8 - (acb, TRM_S1040_SCSI_CONFIG2, 0); - } - /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ + else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ + /* + * load what physical address of Scatter/Gather list table + * want to be transfer + */ + srb->state |= SRB_DATA_XFER; + /* load total transfer length (24bits) max value 16Mbyte */ + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, + srb->total_xfer_length); + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + if (io_dir & DMACMD_DIR) { /* read */ + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_FIFO_IN); + } else { /* write */ + int ln = srb->total_xfer_length; + if (srb->dcb->sync_period & WIDE_SYNC) + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, + CFG2_WIDEFIFO); + dprintkdbg(DBG_PIO, + "data_io_transfer: PIO %i bytes from %p:", + srb->total_xfer_length, srb->virt_addr); + + while (srb->total_xfer_length) { if (debug_enabled(DBG_PIO)) - printk("\n"); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_OUT); - } - } -#endif /* DC395x_LASTPIO */ - else { /* xfer pad */ + printk(" %02x", (unsigned char) *(srb->virt_addr)); - u8 data = 0, data2 = 0; - if (srb->sg_count) { - srb->adapter_status = H_OVER_UNDER_RUN; - srb->status |= OVER_RUN; + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, + *(srb->virt_addr)++); + + sg_subtract_one(srb); } - /* - * KG: despite the fact that we are using 16 bits I/O ops - * the SCSI FIFO is only 8 bits according to the docs - * (we can set bit 1 in 0x8f to serialize FIFO access ...) - */ - if (dcb->sync_period & WIDE_SYNC) { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - if (io_dir & DMACMD_DIR) { /* read */ - data = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - data2 = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x %02x\n", data, data2); */ - } else { - /* Danger, Robinson: If you find KGs scattered over the wide - * disk, the driver or chip is to blame :-( */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'K'); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'G'); + if (srb->dcb->sync_period & WIDE_SYNC) { + if (ln % 2) { + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); + if (debug_enabled(DBG_PIO)) + printk(" |00"); } DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); + } + /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ + if (debug_enabled(DBG_PIO)) + printk("\n"); + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_FIFO_OUT); + } + } +#endif /* DC395x_LASTPIO */ + else { /* xfer pad */ + u8 data = 0, data2 = 0; + if (srb->sg_count) { + srb->adapter_status = H_OVER_UNDER_RUN; + srb->status |= OVER_RUN; + } + /* + * KG: despite the fact that we are using 16 bits I/O ops + * the SCSI FIFO is only 8 bits according to the docs + * (we can set bit 1 in 0x8f to serialize FIFO access ...) + */ + if (dcb->sync_period & WIDE_SYNC) { + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, + CFG2_WIDEFIFO); + if (io_dir & DMACMD_DIR) { + data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); } else { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); - /* Danger, Robinson: If you find a collection of Ks on your disk - * something broke :-( */ - if (io_dir & DMACMD_DIR) { /* read */ - data = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x\n", data); */ - } else { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'K'); - } + /* Danger, Robinson: If you find KGs + * scattered over the wide disk, the driver + * or chip is to blame :-( */ + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G'); } - srb->state |= SRB_XFERPAD; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ - bval = - (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : - SCMD_FIFO_OUT; - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); + } else { + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); + /* Danger, Robinson: If you find a collection of Ks on your disk + * something broke :-( */ + if (io_dir & DMACMD_DIR) + data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + else + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); } + srb->state |= SRB_XFERPAD; + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + /* SCSI command */ + bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT; + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); } - /*monitor_next_irq = 2; */ - /*printk(" done\n"); */ } -/* - ******************************************************************** - * scsiio - * status_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =3 - ******************************************************************** - */ -static -void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - dprintkdbg(DBG_0, "StatusPhase0 (pid %li)\n", srb->cmd->pid); - TRACEPRINTF("STP0 *"); + dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - /*1.25 */ - /*clear_fifo (acb, "STP0"); */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - ** SCSI command - */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); } -/* - ******************************************************************** - * scsiio - * status_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =3 - ******************************************************************** - */ -static -void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "StatusPhase1 (pid=%li)\n", srb->cmd->pid); - TRACEPRINTF("STP1 *"); - /* Cleanup is now done at the end of DataXXPhase0 */ - /*cleanup_after_transfer (acb, srb); */ - +static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); } -/* Message handling */ - -#if 0 -/* Print received message */ -static void print_msg(u8 * msg_buf, u32 len) -{ - int i; - printk(" %02x", msg_buf[0]); - for (i = 1; i < len; i++) - printk(" %02x", msg_buf[i]); - printk("\n"); -} -#endif /* Check if the message is complete */ static inline u8 msgin_completed(u8 * msgbuf, u32 len) @@ -3260,53 +2585,44 @@ /* reject_msg */ -static inline -void msgin_reject(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static inline void msgin_reject(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { srb->msgout_buf[0] = MESSAGE_REJECT; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; srb->state &= ~SRB_MSGIN; srb->state |= SRB_MSGOUT; - dprintkl(KERN_INFO, - "Reject message %02x from %02i-%i\n", srb->msgin_buf[0], - srb->dcb->target_id, srb->dcb->target_lun); - TRACEPRINTF("\\*"); + dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n", + srb->msgin_buf[0], + srb->dcb->target_id, srb->dcb->target_lun); } /* abort command */ -static inline -void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { srb->msgout_buf[0] = ABORT; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; srb->state &= ~SRB_MSGIN; srb->state |= SRB_MSGOUT; - /* - if (srb->dcb) - srb->dcb->flag &= ~ABORT_DEV_; - */ - TRACEPRINTF("#*"); } -static -struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - u8 tag) +static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb, u8 tag) { struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; - + dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n", + srb->cmd->pid, tag, srb); - dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", srb, tag); if (!(dcb->tag_mask & (1 << tag))) dprintkl(KERN_DEBUG, - "MsgIn_QTag: tag_mask (%08x) does not reserve tag %i!\n", - dcb->tag_mask, tag); + "msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n", + dcb->tag_mask, tag); if (list_empty(&dcb->srb_going_list)) goto mingx0; @@ -3319,8 +2635,8 @@ if (!srb) goto mingx0; - dprintkdbg(DBG_0, "pid %li (%i-%i)\n", srb->cmd->pid, - srb->dcb->target_id, srb->dcb->target_lun); + dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -3329,20 +2645,6 @@ if (!(srb->state & SRB_DISCONNECT)) goto mingx0; - /* Tag found */ - { - struct ScsiReqBlk *last_srb; - - TRACEPRINTF("[%s]*", dcb->active_srb->debugtrace); - TRACEPRINTF("RTag*"); - /* Just for debugging ... */ - - last_srb = srb; - srb = dcb->active_srb; - TRACEPRINTF("Found.*"); - srb = last_srb; - } - memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len); srb->state |= dcb->active_srb->state; srb->state |= SRB_DATA_XFER; @@ -3357,15 +2659,13 @@ srb->msgout_buf[0] = MSG_ABORT_TAG; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; - TRACEPRINTF("?*"); - dprintkl(KERN_DEBUG, "Unknown tag received: %i: abort !!\n", tag); + dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag); return srb; } -/* Reprogram registers */ -static inline void -reprogram_regs(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static inline void reprogram_regs(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); @@ -3375,12 +2675,12 @@ /* set async transfer mode */ -static -void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkl(KERN_DEBUG, "Target %02i: No sync transfers\n", dcb->target_id); - TRACEPRINTF("!S *"); + dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n", + dcb->target_id, dcb->target_lun); + dcb->sync_mode &= ~(SYNC_NEGO_ENABLE); dcb->sync_mode |= SYNC_NEGO_DONE; /*dcb->sync_period &= 0; */ @@ -3392,26 +2692,23 @@ && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "SDTR(rej): Try WDTR anyway ...\n"); + dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n"); } } /* set sync transfer mode */ -static -void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { + struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; int fact; - struct DeviceCtlBlk *dcb = srb->dcb; - /*u8 oldsyncperiod = dcb->sync_period; */ - /*u8 oldsyncoffset = dcb->sync_offset; */ - - dprintkdbg(DBG_1, "Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n", - dcb->target_id, srb->msgin_buf[3] << 2, - (250 / srb->msgin_buf[3]), - ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], - srb->msgin_buf[4]); + dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins " + "(%02i.%01i MHz) Offset %i\n", + dcb->target_id, srb->msgin_buf[3] << 2, + (250 / srb->msgin_buf[3]), + ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], + srb->msgin_buf[4]); if (srb->msgin_buf[4] > 15) srb->msgin_buf[4] = 15; @@ -3430,8 +2727,8 @@ bval++; if (srb->msgin_buf[3] < clock_period[bval]) dprintkl(KERN_INFO, - "Increase sync nego period to %ins\n", - clock_period[bval] << 2); + "msgin_set_sync: Increase sync nego period to %ins\n", + clock_period[bval] << 2); srb->msgin_buf[3] = clock_period[bval]; dcb->sync_period &= 0xf0; dcb->sync_period |= ALT_SYNC | bval; @@ -3443,18 +2740,17 @@ fact = 250; dprintkl(KERN_INFO, - "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", - dcb->target_id, (fact == 500) ? "Wide16" : "", - dcb->min_nego_period << 2, dcb->sync_offset, - (fact / dcb->min_nego_period), - ((fact % dcb->min_nego_period) * 10 + + "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", + dcb->target_id, (fact == 500) ? "Wide16" : "", + dcb->min_nego_period << 2, dcb->sync_offset, + (fact / dcb->min_nego_period), + ((fact % dcb->min_nego_period) * 10 + dcb->min_nego_period / 2) / dcb->min_nego_period); - TRACEPRINTF("S%i *", dcb->min_nego_period << 2); if (!(srb->state & SRB_DO_SYNC_NEGO)) { /* Reply with corrected SDTR Message */ - dprintkl(KERN_DEBUG, " .. answer w/ %ins %i\n", - srb->msgin_buf[3] << 2, srb->msgin_buf[4]); + dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n", + srb->msgin_buf[3] << 2, srb->msgin_buf[4]); memcpy(srb->msgout_buf, srb->msgin_buf, 5); srb->msg_count = 5; @@ -3465,7 +2761,7 @@ && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "SDTR: Also try WDTR ...\n"); + dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n"); } } srb->state &= ~SRB_DO_SYNC_NEGO; @@ -3475,14 +2771,12 @@ } -static inline -void msgin_set_nowide(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static inline void msgin_set_nowide(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkdbg(DBG_KG, "WDTR got rejected from target %02i\n", - dcb->target_id); - TRACEPRINTF("!W *"); + dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id); + dcb->sync_period &= ~WIDE_SYNC; dcb->sync_mode &= ~(WIDE_NEGO_ENABLE); dcb->sync_mode |= WIDE_NEGO_DONE; @@ -3492,23 +2786,24 @@ && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "WDTR(rej): Try SDTR anyway ...\n"); + dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n"); } } -static -void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO && acb->config & HCC_WIDE_CARD) ? 1 : 0; + dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id); + if (srb->msgin_buf[3] > wide) srb->msgin_buf[3] = wide; /* Completed */ if (!(srb->state & SRB_DO_WIDE_NEGO)) { dprintkl(KERN_DEBUG, - "Target %02i initiates Wide Nego ...\n", - dcb->target_id); + "msgin_set_wide: Wide nego initiated <%02i>\n", + dcb->target_id); memcpy(srb->msgout_buf, srb->msgin_buf, 4); srb->msg_count = 4; srb->state |= SRB_DO_WIDE_NEGO; @@ -3521,28 +2816,21 @@ else dcb->sync_period &= ~WIDE_SYNC; srb->state &= ~SRB_DO_WIDE_NEGO; - TRACEPRINTF("W%i *", (dcb->sync_period & WIDE_SYNC ? 1 : 0)); /*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ - dprintkdbg(DBG_KG, - "Wide transfers (%i bit) negotiated with target %02i\n", - (8 << srb->msgin_buf[3]), dcb->target_id); + dprintkdbg(DBG_1, + "msgin_set_wide: Wide (%i bit) negotiated <%02i>\n", + (8 << srb->msgin_buf[3]), dcb->target_id); reprogram_regs(acb, dcb); if ((dcb->sync_mode & SYNC_NEGO_ENABLE) && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "WDTR: Also try SDTR ...\n"); + dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n"); } } /* - ******************************************************************** - * scsiio - * msgin_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =7 - * * extended message codes: * * code description @@ -3553,25 +2841,15 @@ * 03h WIDE DATA TRANSFER REQUEST * 04h - 7Fh Reserved * 80h - FFh Vendor specific - * - ******************************************************************** */ -static -void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - struct DeviceCtlBlk *dcb; - - dprintkdbg(DBG_0, "msgin_phase0..............\n"); - TRACEPRINTF("MIP0*"); - dcb = acb->active_dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { - TRACEPRINTF("(%02x)*", srb->msgin_buf[0]); - /*dprintkl(KERN_INFO, "MsgIn:"); */ - /*print_msg (srb->msgin_buf, acb->msg_len); */ - /* Now eval the msg */ switch (srb->msgin_buf[0]) { case DISCONNECT: @@ -3581,7 +2859,6 @@ case SIMPLE_QUEUE_TAG: case HEAD_OF_QUEUE_TAG: case ORDERED_QUEUE_TAG: - TRACEPRINTF("(%02x)*", srb->msgin_buf[1]); srb = msgin_qtag(acb, dcb, srb->msgin_buf[1]); @@ -3605,7 +2882,6 @@ break; case EXTENDED_MESSAGE: - TRACEPRINTF("(%02x)*", srb->msgin_buf[2]); /* SDTR */ if (srb->msgin_buf[1] == 3 && srb->msgin_buf[2] == EXTENDED_SDTR) { @@ -3613,52 +2889,51 @@ break; } /* WDTR */ - if (srb->msgin_buf[1] == 2 && srb->msgin_buf[2] == EXTENDED_WDTR && srb->msgin_buf[3] <= 2) { /* sanity check ... */ + if (srb->msgin_buf[1] == 2 + && srb->msgin_buf[2] == EXTENDED_WDTR + && srb->msgin_buf[3] <= 2) { /* sanity check ... */ msgin_set_wide(acb, srb); break; } msgin_reject(acb, srb); break; - /* Discard wide residual */ case MSG_IGNOREWIDE: - dprintkdbg(DBG_0, "Ignore Wide Residual!\n"); - /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); */ - /*DC395x_read8 (TRM_S1040_SCSI_FIFO); */ + /* Discard wide residual */ + dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n"); break; - /* nothing has to be done */ case COMMAND_COMPLETE: + /* nothing has to be done */ break; + case SAVE_POINTERS: /* - * SAVE POINTER may be ignored as we have the struct ScsiReqBlk* associated with the - * scsi command. Thanks, Gérard, for pointing it out. + * SAVE POINTER may be ignored as we have the struct + * ScsiReqBlk* associated with the scsi command. */ - case SAVE_POINTERS: - dprintkdbg(DBG_0, "SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n", - srb->cmd->pid, srb->total_xfer_length); - /*srb->Saved_Ptr = srb->TotalxferredLen; */ + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + "SAVE POINTER rem=%i Ignore\n", + srb->cmd->pid, srb->total_xfer_length); break; - /* The device might want to restart transfer with a RESTORE */ + case RESTORE_POINTERS: - dprintkl(KERN_DEBUG, - "RESTORE POINTER message received ... ignore :-(\n"); - /*dc395x_restore_ptr (acb, srb); */ + dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n"); break; + case ABORT: - dprintkl(KERN_DEBUG, - "ABORT msg received (pid %li %02i-%i)\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun); + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + "<%02i-%i> ABORT msg\n", + srb->cmd->pid, dcb->target_id, + dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); break; - /* reject unknown messages */ + default: + /* reject unknown messages */ if (srb->msgin_buf[0] & IDENTIFY_BASE) { - dprintkl(KERN_DEBUG, "Identify Message received?\n"); - /*TRACEOUT (" %s\n", srb->debugtrace); */ + dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n"); srb->msg_count = 1; srb->msgout_buf[0] = dcb->identify_msg; DC395x_ENABLE_MSGOUT; @@ -3666,104 +2941,51 @@ /*break; */ } msgin_reject(acb, srb); - TRACEOUT(" %s\n", srb->debugtrace); } - TRACEPRINTF(".*"); /* Clear counter and MsgIn state */ srb->state &= ~SRB_MSGIN; acb->msg_len = 0; } - - /*1.25 */ - if ((*pscsi_status & PHASEMASK) != PH_MSG_IN) -#if 0 - clear_fifo(acb, "MIP0_"); -#else - TRACEPRINTF("N/Cln *"); -#endif *pscsi_status = PH_BUS_FREE; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important ... you know! */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); } -/* - ******************************************************************** - * scsiio - * msgin_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =7 - ******************************************************************** - */ -static -void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "msgin_phase1..............\n"); - TRACEPRINTF("MIP1 *"); - clear_fifo(acb, "MIP1"); +static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid); + clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { srb->state &= ~SRB_DISCONNECT; srb->state |= SRB_MSGIN; } DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ + /* SCSI command */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); } -/* - ******************************************************************** - * scsiio - * nop0: one of dc395x_scsi_phase1[] ,dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =4 ..PH_BUS_FREE - ******************************************************************** - */ -static -void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - /*TRACEPRINTF("NOP0 *"); */ } -/* - ******************************************************************** - * scsiio - * nop1: one of dc395x_scsi_phase0[] ,dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =5 - ******************************************************************** - */ -static -void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - /*TRACEPRINTF("NOP1 *"); */ } -/* - ******************************************************************** - * scsiio - * msgin_phase0 - ******************************************************************** - */ -static -void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) { struct DeviceCtlBlk *i; - /* - * set all lun device's period , offset - */ + /* set all lun device's period, offset */ if (dcb->identify_msg & 0x07) return; @@ -3782,47 +3004,39 @@ } -/* - ******************************************************************** - * scsiio - * dc395x_interrupt - ******************************************************************** - */ static void disconnect(struct AdapterCtlBlk *acb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; struct ScsiReqBlk *srb; - dprintkdbg(DBG_0, "Disconnect (pid=%li)\n", acb->active_dcb->active_srb->cmd->pid); - dcb = acb->active_dcb; if (!dcb) { - dprintkl(KERN_ERR, "Disc: Exception Disconnect dcb=NULL !!\n "); + dprintkl(KERN_ERR, "disconnect: No such device\n"); udelay(500); /* Suspend queue for a while */ acb->scsi_host->last_reset = jiffies + HZ / 2 + HZ * acb->eeprom.delay_time; - clear_fifo(acb, "DiscEx"); + clear_fifo(acb, "disconnectEx"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); return; } srb = dcb->active_srb; acb->active_dcb = NULL; - TRACEPRINTF("DISC *"); + dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - clear_fifo(acb, "Disc"); + clear_fifo(acb, "disconnect"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); if (srb->state & SRB_UNEXPECT_RESEL) { - dprintkl(KERN_ERR, "Disc: Unexpected Reselection (%i-%i)\n", - dcb->target_id, dcb->target_lun); + dprintkl(KERN_ERR, + "disconnect: Unexpected reselection <%02i-%i>\n", + dcb->target_id, dcb->target_lun); srb->state = 0; waiting_process_next(acb); } else if (srb->state & SRB_ABORT_SENT) { - /*Scsi_Cmnd* cmd = srb->cmd; */ dcb->flag &= ~ABORT_DEV_; acb->scsi_host->last_reset = jiffies + HZ / 2 + 1; - dprintkl(KERN_ERR, "Disc: SRB_ABORT_SENT!\n"); + dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); doing_srb_done(acb, DID_ABORT, srb->cmd, 1); waiting_process_next(acb); } else { @@ -3837,19 +3051,16 @@ if (srb->state != SRB_START_ && srb->state != SRB_MSGOUT) { srb->state = SRB_READY; - dprintkl(KERN_DEBUG, "Unexpected Disconnection (pid %li)!\n", - srb->cmd->pid); + dprintkl(KERN_DEBUG, + "disconnect: (pid#%li) Unexpected\n", + srb->cmd->pid); srb->target_status = SCSI_STAT_SEL_TIMEOUT; - TRACEPRINTF("UnExpD *"); - TRACEOUT("%s\n", srb->debugtrace); goto disc1; } else { /* Normal selection timeout */ - TRACEPRINTF("SlTO *"); - dprintkdbg(DBG_KG, - "Disc: SelTO (pid=%li) for dev %02i-%i\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun); + dprintkdbg(DBG_KG, "disconnect: (pid#%li) " + "<%02i-%i> SelTO\n", srb->cmd->pid, + dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { srb->target_status = @@ -3858,8 +3069,9 @@ } free_tag(dcb, srb); srb_going_to_waiting_move(dcb, srb); - dprintkdbg(DBG_KG, "Retry pid %li ...\n", - srb->cmd->pid); + dprintkdbg(DBG_KG, + "disconnect: (pid#%li) Retry\n", + srb->cmd->pid); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -3867,18 +3079,11 @@ /* * SRB_DISCONNECT (This is what we expect!) */ - /* dprintkl(KERN_DEBUG, "DoWaitingSRB (pid=%li)\n", srb->cmd->pid); */ - TRACEPRINTF("+*"); if (bval & 0x40) { - dprintkdbg(DBG_0, "Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n", + dprintkdbg(DBG_0, "disconnect: SCSI bus stat " + " 0x%02x: ACK set! Other controllers?\n", bval); /* It could come from another initiator, therefore don't do much ! */ - TRACEPRINTF("ACK(%02x) *", bval); - /*dump_register_info (acb, dcb, srb); */ - /*TRACEOUT (" %s\n", srb->debugtrace); */ - /*dcb->flag |= ABORT_DEV_; */ - /*enable_msgout_abort (acb, srb); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_CLRATN | DO_HWRESELECT); */ } else waiting_process_next(acb); } else if (srb->state & SRB_COMPLETED) { @@ -3889,51 +3094,40 @@ free_tag(dcb, srb); dcb->active_srb = NULL; srb->state = SRB_FREE; - /*dprintkl(KERN_DEBUG, "done (pid=%li)\n", srb->cmd->pid); */ srb_done(acb, dcb, srb); } } - return; } -/* - ******************************************************************** - * scsiio - * reselect - ******************************************************************** - */ static void reselect(struct AdapterCtlBlk *acb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; struct ScsiReqBlk *srb = NULL; u16 rsel_tar_lun_id; u8 id, lun; u8 arblostflag = 0; + dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); - dprintkdbg(DBG_0, "reselect..............\n"); - - clear_fifo(acb, "Resel"); + clear_fifo(acb, "reselect"); /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ /* Read Reselected Target ID and LUN */ rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID); - dcb = acb->active_dcb; if (dcb) { /* Arbitration lost but Reselection win */ srb = dcb->active_srb; if (!srb) { - dprintkl(KERN_DEBUG, "Arb lost Resel won, but active_srb == NULL!\n"); + dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, " + "but active_srb == NULL\n"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } /* Why the if ? */ - if (!(acb->scan_devices)) { - dprintkdbg(DBG_KG, - "Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun, rsel_tar_lun_id, - DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); - TRACEPRINTF("ArbLResel!*"); - /*TRACEOUT (" %s\n", srb->debugtrace); */ + if (!acb->scan_devices) { + dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> " + "Arb lost but Resel win rsel=%i stat=0x%04x\n", + srb->cmd->pid, dcb->target_id, + dcb->target_lun, rsel_tar_lun_id, + DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); arblostflag = 1; /*srb->state |= SRB_DISCONNECT; */ @@ -3947,47 +3141,37 @@ } /* Read Reselected Target Id and LUN */ if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8))) - dprintkl(KERN_DEBUG, "Resel expects identify msg! Got %04x!\n", - rsel_tar_lun_id); + dprintkl(KERN_DEBUG, "reselect: Expects identify msg. " + "Got %i!\n", rsel_tar_lun_id); id = rsel_tar_lun_id & 0xff; lun = (rsel_tar_lun_id >> 8) & 7; dcb = find_dcb(acb, id, lun); if (!dcb) { - dprintkl(KERN_ERR, "Reselect from non existing device (%02i-%i)\n", - id, lun); + dprintkl(KERN_ERR, "reselect: From non existent device " + "<%02i-%i>\n", id, lun); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } - acb->active_dcb = dcb; if (!(dcb->dev_mode & NTC_DO_DISCONNECT)) - dprintkl(KERN_DEBUG, "Reselection in spite of forbidden disconnection? (%02i-%i)\n", - dcb->target_id, dcb->target_lun); + dprintkl(KERN_DEBUG, "reselect: in spite of forbidden " + "disconnection? <%02i-%i>\n", + dcb->target_id, dcb->target_lun); - if ((dcb->sync_mode & EN_TAG_QUEUEING) /*&& !arblostflag */ ) { - struct ScsiReqBlk *oldSRB = srb; + if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) { srb = acb->tmp_srb; -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - srb->debugpos = 0; - srb->debugtrace[0] = 0; -#endif dcb->active_srb = srb; - if (oldSRB) - TRACEPRINTF("ArbLResel(%li):*", oldSRB->cmd->pid); - /*if (arblostflag) dprintkl(KERN_DEBUG, "Reselect: Wait for Tag ... \n"); */ } else { /* There can be only one! */ srb = dcb->active_srb; - if (srb) - TRACEPRINTF("RSel *"); if (!srb || !(srb->state & SRB_DISCONNECT)) { /* * abort command */ dprintkl(KERN_DEBUG, - "Reselected w/o disconnected cmds from %02i-%i?\n", - dcb->target_id, dcb->target_lun); + "reselect: w/o disconnected cmds <%02i-%i>\n", + dcb->target_id, dcb->target_lun); srb = acb->tmp_srb; srb->state = SRB_UNEXPECT_RESEL; dcb->active_srb = srb; @@ -4000,14 +3184,11 @@ srb->state = SRB_DATA_XFER; } - /*if (arblostflag) TRACEOUT (" %s\n", srb->debugtrace); */ } srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - /* - *********************************************** - ** Program HA ID, target ID, period and offset - *********************************************** - */ + + /* Program HA ID, target ID, period and offset */ + dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); /* host ID */ DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); /* target ID */ DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); /* offset */ @@ -4018,10 +3199,6 @@ } - - - - static inline u8 tagq_blacklist(char *name) { #ifndef DC395x_NO_TAGQ @@ -4038,8 +3215,7 @@ } -static -void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) +static void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) { /* Check for SCSI format (ANSI and Response data format) */ if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { @@ -4048,7 +3224,7 @@ /*(dcb->dev_mode & NTC_DO_DISCONNECT) */ /* ((dcb->dev_type == TYPE_DISK) || (dcb->dev_type == TYPE_MOD)) && */ - !tagq_blacklist(((char *) ptr) + 8)) { + !tagq_blacklist(((char *)ptr) + 8)) { if (dcb->max_command == 1) dcb->max_command = dcb->acb->tag_max_num; @@ -4060,9 +3236,8 @@ } -static -void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiInqData *ptr) +static void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiInqData *ptr) { u8 bval1 = ptr->DevType & SCSI_DEVTYPE; dcb->dev_type = bval1; @@ -4071,59 +3246,45 @@ } -/* - ******************************************************************** - * unmap mapped pci regions from SRB - ******************************************************************** - */ -static -void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* unmap mapped pci regions from SRB */ +static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - int dir; Scsi_Cmnd *cmd = srb->cmd; - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); if (cmd->use_sg && dir != PCI_DMA_NONE) { /* unmap DC395x SG list */ - dprintkdbg(DBG_SGPARANOIA, - "Unmap SG descriptor list %08x (%05x)\n", - srb->sg_bus_addr, - sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY); + dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", + srb->sg_bus_addr, SEGMENTX_LEN); pci_unmap_single(acb->dev, srb->sg_bus_addr, - sizeof(struct SGentry) * - DC395x_MAX_SG_LISTENTRY, + SEGMENTX_LEN, PCI_DMA_TODEVICE); - dprintkdbg(DBG_SGPARANOIA, "Unmap %i SG segments from %p\n", - cmd->use_sg, cmd->request_buffer); + dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", + cmd->use_sg, cmd->request_buffer); /* unmap the sg segments */ pci_unmap_sg(acb->dev, - (struct scatterlist *) cmd->request_buffer, + (struct scatterlist *)cmd->request_buffer, cmd->use_sg, dir); } else if (cmd->request_buffer && dir != PCI_DMA_NONE) { - dprintkdbg(DBG_SGPARANOIA, "Unmap buffer at %08x (%05x)\n", - srb->segment_x[0].address, cmd->request_bufflen); + dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n", + srb->segment_x[0].address, cmd->request_bufflen); pci_unmap_single(acb->dev, srb->segment_x[0].address, cmd->request_bufflen, dir); } } -/* - ******************************************************************** - * unmap mapped pci sense buffer from SRB - ******************************************************************** - */ -static -void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* unmap mapped pci sense buffer from SRB */ +static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { if (!(srb->flag & AUTO_REQSENSE)) return; /* Unmap sense buffer */ - dprintkdbg(DBG_SGPARANOIA, "Unmap sense buffer from %08x\n", + dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", srb->segment_x[0].address); pci_unmap_single(acb->dev, srb->segment_x[0].address, srb->segment_x[0].length, PCI_DMA_FROMDEVICE); /* Restore SG stuff */ - /*printk ("Auto_ReqSense finished: Restore Counters ...\n"); */ srb->total_xfer_length = srb->xferred; srb->segment_x[0].address = srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; @@ -4133,42 +3294,33 @@ /* - ******************************************************************** - * scsiio - * disconnect - * Complete execution of a SCSI command - * Signal completion to the generic SCSI driver - ******************************************************************** + * Complete execution of a SCSI command + * Signal completion to the generic SCSI driver */ -static -void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { u8 tempcnt, status; - Scsi_Cmnd *cmd; + Scsi_Cmnd *cmd = srb->cmd; struct ScsiInqData *ptr; - /*u32 drv_flags=0; */ int dir; - cmd = srb->cmd; - TRACEPRINTF("DONE *"); - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - ptr = (struct ScsiInqData *) (cmd->request_buffer); - if (cmd->use_sg) - ptr = - (struct ScsiInqData *) CPU_ADDR(*(struct scatterlist *) - ptr); - dprintkdbg(DBG_SGPARANOIA, - "SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n", - cmd->use_sg, srb->sg_index, srb->sg_count, - cmd->request_buffer, ptr); - dprintkdbg(DBG_KG, - "SRBdone (pid %li, target %02i-%i): ", srb->cmd->pid, - srb->cmd->device->id, srb->cmd->device->lun); + if (cmd->use_sg) { + struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer; + ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset); + } else { + ptr = (struct ScsiInqData *)(cmd->request_buffer); + } + + dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid, + srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p addr=%p\n", + srb, cmd->use_sg, srb->sg_index, srb->sg_count, + cmd->request_buffer, ptr); status = srb->target_status; if (srb->flag & AUTO_REQSENSE) { - dprintkdbg(DBG_0, "AUTO_REQSENSE1..............\n"); + dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); pci_unmap_srb_sense(acb, srb); /* ** target status.......................... @@ -4176,61 +3328,60 @@ srb->flag &= ~AUTO_REQSENSE; srb->adapter_status = 0; srb->target_status = CHECK_CONDITION << 1; - if (debug_enabled(DBG_KG)) { + if (debug_enabled(DBG_1)) { switch (cmd->sense_buffer[2] & 0x0f) { case NOT_READY: dprintkl(KERN_DEBUG, - "ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case UNIT_ATTENTION: dprintkl(KERN_DEBUG, - "ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case ILLEGAL_REQUEST: dprintkl(KERN_DEBUG, - "ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case MEDIUM_ERROR: dprintkl(KERN_DEBUG, - "ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case HARDWARE_ERROR: dprintkl(KERN_DEBUG, - "ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; } if (cmd->sense_buffer[7] >= 6) - dprintkl(KERN_DEBUG, - "Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ", - cmd->sense_buffer[2], cmd->sense_buffer[12], - cmd->sense_buffer[13], - *((unsigned int *) (cmd->sense_buffer + 3)), - *((unsigned int *) (cmd->sense_buffer + 8))); + printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x " + "(0x%08x 0x%08x)\n", + cmd->sense_buffer[2], cmd->sense_buffer[12], + cmd->sense_buffer[13], + *((unsigned int *)(cmd->sense_buffer + 3)), + *((unsigned int *)(cmd->sense_buffer + 8))); else - dprintkl(KERN_DEBUG, - "Sense=%02x, No ASC/ASCQ (%08x) ", - cmd->sense_buffer[2], - *((unsigned int *) (cmd->sense_buffer + 3))); + printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n", + cmd->sense_buffer[2], + *((unsigned int *)(cmd->sense_buffer + 3))); } if (status == (CHECK_CONDITION << 1)) { cmd->result = DID_BAD_TARGET << 16; goto ckc_e; } - dprintkdbg(DBG_0, "AUTO_REQSENSE2..............\n"); + dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n"); - if ((srb->total_xfer_length) - && (srb->total_xfer_length >= cmd->underflow)) + if (srb->total_xfer_length + && srb->total_xfer_length >= cmd->underflow) cmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, srb->end_message, CHECK_CONDITION); @@ -4253,8 +3404,7 @@ return; } else if (status_byte(status) == QUEUE_FULL) { tempcnt = (u8)list_size(&dcb->srb_going_list); - printk - ("\nDC395x: QUEUE_FULL for dev %02i-%i with %i cmnds\n", + dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n", dcb->target_id, dcb->target_lun, tempcnt); if (tempcnt > 1) tempcnt--; @@ -4298,11 +3448,11 @@ if (dir != PCI_DMA_NONE) { if (cmd->use_sg) - pci_dma_sync_sg(acb->dev, - (struct scatterlist *) cmd-> + pci_dma_sync_sg_for_cpu(acb->dev, + (struct scatterlist *)cmd-> request_buffer, cmd->use_sg, dir); else if (cmd->request_buffer) - pci_dma_sync_single(acb->dev, + pci_dma_sync_single_for_cpu(acb->dev, srb->segment_x[0].address, cmd->request_bufflen, dir); } @@ -4336,48 +3486,35 @@ cmd->SCp.buffers_residual = 0; if (debug_enabled(DBG_KG)) { if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "pid %li: %02x (%02i-%i): Missed %i bytes\n", - cmd->pid, cmd->cmnd[0], cmd->device->id, - cmd->device->lun, srb->total_xfer_length); + dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> " + "cmnd=0x%02x Missed %i bytes\n", + cmd->pid, cmd->device->id, cmd->device->lun, + cmd->cmnd[0], srb->total_xfer_length); } srb_going_remove(dcb, srb); /* Add to free list */ if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "ERROR! Completed Cmnd with tmp_srb!\n"); - else + dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); + else { + dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n", + cmd->pid, cmd->result); srb_free_insert(acb, srb); - - dprintkdbg(DBG_0, "SRBdone: done pid %li\n", cmd->pid); - if (debug_enabled(DBG_KG)) { - printk(" 0x%08x\n", cmd->result); } - TRACEPRINTF("%08x(%li)*", cmd->result, jiffies); pci_unmap_srb(acb, srb); - /*DC395x_UNLOCK_ACB_NI; */ - cmd->scsi_done(cmd); - /*DC395x_LOCK_ACB_NI; */ - TRACEOUTALL(KERN_INFO " %s\n", srb->debugtrace); + cmd->scsi_done(cmd); waiting_process_next(acb); - return; } -/* - ******************************************************************** - * scsiio - * DC395x_reset - * abort all cmds in our queues - ******************************************************************** - */ -static -void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, - Scsi_Cmnd * cmd, u8 force) +/* abort all cmds in our queues */ +static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, + Scsi_Cmnd *cmd, u8 force) { struct DeviceCtlBlk *dcb; - dprintkl(KERN_INFO, "doing_srb_done: pids "); + list_for_each_entry(dcb, &acb->dcb_list, list) { struct ScsiReqBlk *srb; struct ScsiReqBlk *tmp; @@ -4390,16 +3527,8 @@ p = srb->cmd; dir = scsi_to_pci_dma_dir(p->sc_data_direction); result = MK_RES(0, did_flag, 0, 0); - - /*result = MK_RES(0,DID_RESET,0,0); */ - TRACEPRINTF("Reset(%li):%08x*", jiffies, result); - printk(" (G)"); -#if 1 /*ndef DC395x_DEBUGTRACE */ - printk("%li(%02i-%i) ", p->pid, + printk("G:%li(%02i-%i) ", p->pid, p->device->id, p->device->lun); -#endif - TRACEOUT("%s\n", srb->debugtrace); - srb_going_remove(dcb, srb); free_tag(dcb, srb); srb_free_insert(acb, srb); @@ -4414,11 +3543,11 @@ } if (!list_empty(&dcb->srb_going_list)) dprintkl(KERN_DEBUG, - "How could the ML send cmnds to the Going queue? (%02i-%i)!!\n", + "How could the ML send cmnds to the Going queue? <%02i-%i>\n", dcb->target_id, dcb->target_lun); if (dcb->tag_mask) dprintkl(KERN_DEBUG, - "tag_mask for %02i-%i should be empty, is %08x!\n", + "tag_mask for <%02i-%i> should be empty, is %08x!\n", dcb->target_id, dcb->target_lun, dcb->tag_mask); @@ -4428,16 +3557,10 @@ p = srb->cmd; result = MK_RES(0, did_flag, 0, 0); - TRACEPRINTF("Reset(%li):%08x*", jiffies, result); - printk(" (W)"); -#if 1 /*ndef DC395x_DEBUGTRACE */ - printk("%li(%i-%i)", p->pid, p->device->id, + printk("W:%li<%02i-%i>", p->pid, p->device->id, p->device->lun); -#endif - TRACEOUT("%s\n", srb->debugtrace); srb_waiting_remove(dcb, srb); srb_free_insert(acb, srb); - p->result = result; pci_unmap_srb_sense(acb, srb); pci_unmap_srb(acb, srb); @@ -4448,41 +3571,26 @@ } } if (!list_empty(&dcb->srb_waiting_list)) - printk - ("\nDC395x: Debug: ML queued %i cmnds again to %02i-%i\n", + dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n", list_size(&dcb->srb_waiting_list), dcb->target_id, dcb->target_lun); - dcb->flag &= ~ABORT_DEV_; } printk("\n"); } -/* - ******************************************************************** - * scsiio - * DC395x_shutdown DC395x_reset - ******************************************************************** - */ static void reset_scsi_bus(struct AdapterCtlBlk *acb) { - /*u32 drv_flags=0; */ - - dprintkdbg(DBG_0, "reset_scsi_bus..............\n"); - - /*DC395x_DRV_LOCK(drv_flags); */ + dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb); acb->acb_flag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); - while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)); - /*DC395x_DRV_UNLOCK(drv_flags); */ - return; + while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)) + /* nothing */; } -/* Set basic config */ static void set_basic_config(struct AdapterCtlBlk *acb) { u8 bval; @@ -4508,7 +3616,6 @@ wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL; wval |= DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ; - /*dprintkl(KERN_INFO, "DMA_Config: %04x\n", wval); */ DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval); /* Clear pending interrupt status */ DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); @@ -4520,15 +3627,9 @@ } -/* - ******************************************************************** - * scsiio - * dc395x_interrupt - ******************************************************************** - */ static void scsi_reset_detect(struct AdapterCtlBlk *acb) { - dprintkl(KERN_INFO, "scsi_reset_detect\n"); + dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb); /* delay half a second */ if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -4542,7 +3643,7 @@ jiffies + 5 * HZ / 2 + HZ * acb->eeprom.delay_time; - clear_fifo(acb, "RstDet"); + clear_fifo(acb, "scsi_reset_detect"); set_basic_config(acb); /*1.25 */ /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */ @@ -4558,28 +3659,16 @@ acb->acb_flag = 0; waiting_process_next(acb); } - - return; } -/* - ******************************************************************** - * scsiio - * srb_done - ******************************************************************** - */ -static -void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - Scsi_Cmnd *cmd; + Scsi_Cmnd *cmd = srb->cmd; + dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n", + cmd->pid, cmd->device->id, cmd->device->lun); - cmd = srb->cmd; - dprintkdbg(DBG_KG, - "request_sense for pid %li, target %02i-%i\n", - cmd->pid, cmd->device->id, cmd->device->lun); - TRACEPRINTF("RqSn*"); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; srb->target_status = 0; @@ -4600,27 +3689,22 @@ srb->segment_x[0].address = pci_map_single(acb->dev, cmd->sense_buffer, sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE); - dprintkdbg(DBG_SGPARANOIA, "Map sense buffer at %p (%05x) to %08x\n", - cmd->sense_buffer, sizeof(cmd->sense_buffer), - srb->segment_x[0].address); + dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", + cmd->sense_buffer, srb->segment_x[0].address, + sizeof(cmd->sense_buffer)); srb->sg_count = 1; srb->sg_index = 0; if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ dprintkl(KERN_DEBUG, - "Request Sense failed for pid %li (%02i-%i)!\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); - TRACEPRINTF("?*"); + "request_sense: (pid#%li) failed <%02i-%i>\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun); srb_going_to_waiting_move(dcb, srb); waiting_set_timer(acb, HZ / 100); } - TRACEPRINTF(".*"); } - - - /** * device_alloc - Allocate a new device instance. This create the * devices instance and sets up all the data items. The adapter @@ -4634,18 +3718,17 @@ * * Return the new device if succesfull or NULL on failure. **/ -static -struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, u8 target, u8 lun) +static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, + u8 target, u8 lun) { struct NvRamType *eeprom = &acb->eeprom; u8 period_index = eeprom->target[target].period & 0x07; struct DeviceCtlBlk *dcb; - dcb = dc395x_kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); - dprintkdbg(DBG_0, "device_alloc: device %p\n", dcb); - if (!dcb) { + dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); + dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun); + if (!dcb) return NULL; - } dcb->acb = NULL; INIT_LIST_HEAD(&dcb->srb_going_list); INIT_LIST_HEAD(&dcb->srb_waiting_list); @@ -4684,10 +3767,10 @@ list_for_each_entry(p, &acb->dcb_list, list) if (p->target_id == dcb->target_id) break; - dprintkdbg(DBG_KG, - "Copy settings from %02i-%02i to %02i-%02i\n", - p->target_id, p->target_lun, - dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_1, + "device_alloc: <%02i-%i> copy from <%02i-%i>\n", + dcb->target_id, dcb->target_lun, + p->target_id, p->target_lun); dcb->sync_mode = p->sync_mode; dcb->sync_period = p->sync_period; dcb->min_nego_period = p->min_nego_period; @@ -4704,8 +3787,8 @@ * @acb: The adapter device to be updated * @dcb: A newly created and intialised device instance to add. **/ -static -void adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_add_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { /* backpointer to adapter */ dcb->acb = acb; @@ -4732,13 +3815,13 @@ * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter. **/ -static -void adapter_remove_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_remove_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { struct DeviceCtlBlk *i; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_0, "adapter_remove_device: Remove device (ID %i, LUN %i): %p\n", - dcb->target_id, dcb->target_lun, dcb); + dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n", + dcb->target_id, dcb->target_lun); /* fix up any pointers to this device that we have in the adapter */ if (acb->active_dcb == dcb) @@ -4767,17 +3850,18 @@ * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter. */ -static -void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { if (list_size(&dcb->srb_going_list) > 1) { - dprintkdbg(DBG_DCB, "adapter_remove_and_free_device: " - "Won't remove because of %i active requests\n", + dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> " + "Won't remove because of %i active requests.\n", + dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); return; } adapter_remove_device(acb, dcb); - dc395x_kfree(dcb); + kfree(dcb); } @@ -4787,12 +3871,11 @@ * * @acb: The adapter from which all devices should be removed. **/ -static -void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) +static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) { struct DeviceCtlBlk *dcb; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_DCB, "adapter_remove_and_free_all_devices: Free all devices (%i devices)\n", + dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n", list_size(&acb->dcb_list)); list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) @@ -4807,8 +3890,7 @@ * * @scsi_device: The new scsi device that we need to handle. **/ -static -int dc395x_slave_alloc(struct scsi_device *scsi_device) +static int dc395x_slave_alloc(struct scsi_device *scsi_device) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb; @@ -4828,8 +3910,7 @@ * * @scsi_device: The new scsi device that we need to handle. **/ -static -void dc395x_slave_destroy(struct scsi_device *scsi_device) +static void dc395x_slave_destroy(struct scsi_device *scsi_device) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun); @@ -4847,14 +3928,12 @@ * * @io_port: base I/O address **/ -static -void __init trms1040_wait_30us(u16 io_port) +static void __init trms1040_wait_30us(u16 io_port) { /* ScsiPortStallExecution(30); wait 30 us */ outb(5, io_port + TRM_S1040_GEN_TIMER); while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT)) /* nothing */ ; - return; } @@ -4866,8 +3945,7 @@ * @cmd: SB + op code (command) to send * @addr: address to send **/ -static -void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr) +static void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr) { int i; u8 send_data; @@ -4912,8 +3990,7 @@ * @addr: offset into EEPROM * @byte: bytes to write **/ -static -void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte) +static void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte) { int i; u8 send_data; @@ -4967,10 +4044,9 @@ * @eeprom: the data to write * @io_port: the base io port **/ -static -void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port) +static void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port) { - u8 *b_eeprom = (u8 *) eeprom; + u8 *b_eeprom = (u8 *)eeprom; u8 addr; /* Enable SEEPROM */ @@ -4983,9 +4059,8 @@ trms1040_wait_30us(io_port); /* write */ - for (addr = 0; addr < 128; addr++, b_eeprom++) { + for (addr = 0; addr < 128; addr++, b_eeprom++) trms1040_set_data(io_port, addr, *b_eeprom); - } /* write disable */ trms1040_write_cmd(io_port, 0x04, 0x00); @@ -5009,8 +4084,7 @@ * * Returns the the byte read. **/ -static -u8 __init trms1040_get_data(u16 io_port, u8 addr) +static u8 __init trms1040_get_data(u16 io_port, u8 addr) { int i; u8 read_byte; @@ -5048,10 +4122,9 @@ * @eeprom: where to store the data * @io_port: the base io port **/ -static -void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port) +static void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port) { - u8 *b_eeprom = (u8 *) eeprom; + u8 *b_eeprom = (u8 *)eeprom; u8 addr; /* Enable SEEPROM */ @@ -5059,9 +4132,8 @@ io_port + TRM_S1040_GEN_CONTROL); /* read details */ - for (addr = 0; addr < 128; addr++, b_eeprom++) { + for (addr = 0; addr < 128; addr++, b_eeprom++) *b_eeprom = trms1040_get_data(io_port, addr); - } /* Disable SEEPROM */ outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), @@ -5080,10 +4152,9 @@ * @eeprom: caller allocated strcuture to read the eeprom data into * @io_port: io port to read from **/ -static -void __init check_eeprom(struct NvRamType *eeprom, u16 io_port) +static void __init check_eeprom(struct NvRamType *eeprom, u16 io_port) { - u16 *w_eeprom = (u16 *) eeprom; + u16 *w_eeprom = (u16 *)eeprom; u16 w_addr; u16 cksum; u32 d_addr; @@ -5092,7 +4163,7 @@ trms1040_read_all(eeprom, io_port); /* read eeprom */ cksum = 0; - for (w_addr = 0, w_eeprom = (u16 *) eeprom; w_addr < 64; + for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64; w_addr++, w_eeprom++) cksum += *w_eeprom; if (cksum != 0x1234) { @@ -5101,21 +4172,21 @@ * Load a set of defaults into the eeprom buffer */ dprintkl(KERN_WARNING, - "EEProm checksum error: using default values and options.\n"); - eeprom->sub_vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM; - eeprom->sub_vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->sub_sys_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040; + "EEProm checksum error: using default values and options.\n"); + eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; + eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); + eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; eeprom->sub_sys_id[1] = - (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); + (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); eeprom->sub_class = 0x00; - eeprom->vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM; - eeprom->vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->device_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040; + eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; + eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); + eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; eeprom->device_id[1] = - (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); + (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); eeprom->reserved = 0x00; - for (d_addr = 0, d_eeprom = (u32 *) eeprom->target; + for (d_addr = 0, d_eeprom = (u32 *)eeprom->target; d_addr < 16; d_addr++, d_eeprom++) *d_eeprom = 0x00000077; /* cfg3,cfg2,period,cfg0 */ @@ -5130,7 +4201,7 @@ eeprom_override(eeprom); eeprom->cksum = 0x00; - for (w_addr = 0, cksum = 0, w_eeprom = (u16 *) eeprom; + for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom; w_addr < 63; w_addr++, w_eeprom++) cksum += *w_eeprom; @@ -5145,113 +4216,47 @@ } - - /** * print_eeprom_settings - output the eeprom settings * to the kernel log so people can see what they were. * * @eeprom: The eeprom data strucutre to show details for. **/ -static -void __init print_eeprom_settings(struct NvRamType *eeprom) +static void __init print_eeprom_settings(struct NvRamType *eeprom) { dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n", - eeprom->scsi_id, - eeprom->target[0].period, - clock_speed[eeprom->target[0].period] / 10, - clock_speed[eeprom->target[0].period] % 10, - eeprom->target[0].cfg0); + eeprom->scsi_id, + eeprom->target[0].period, + clock_speed[eeprom->target[0].period] / 10, + clock_speed[eeprom->target[0].period] % 10, + eeprom->target[0].cfg0); dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", - eeprom->channel_cfg, - eeprom->max_tag, - 1 << eeprom->max_tag, - eeprom->delay_time); + eeprom->channel_cfg, eeprom->max_tag, + 1 << eeprom->max_tag, eeprom->delay_time); } - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) -/* - * Memory for trace buffers - */ -static -void free_tracebufs(struct AdapterCtlBlk *acb) -{ - int i; - const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ; - - for (i = 0; i < srb_idx; i += bufs_per_page) - if (acb->srb_array[i].debugtrace) - dc395x_kfree(acb->srb_array[i].debugtrace); -} - - -static -int alloc_tracebufs(struct AdapterCtlBlk *acb) -{ - const unsigned mem_needed = - (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ; - int pages = (mem_needed + (PAGE_SIZE - 1)) / PAGE_SIZE; - const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ; - int srb_idx = 0; - unsigned i = 0; - unsigned char *ptr; - - for (i = 0; i < DC395x_MAX_SRB_CNT; i++) - acb->srb_array[i].debugtrace = NULL; - - while (pages--) { - ptr = dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!ptr) { - free_tracebufs(acb); - return 1; - } - /*dprintkl(KERN_DEBUG, "Alloc %li bytes at %p for tracebuf %i\n", */ - /* PAGE_SIZE, ptr, srb_idx); */ - i = 0; - while (i < bufs_per_page && srb_idx < DC395x_MAX_SRB_CNT) - acb->srb_array[srb_idx++].debugtrace = - ptr + (i++ * DEBUGTRACEBUFSZ); - } - if (i < bufs_per_page) { - acb->srb.debugtrace = ptr + (i * DEBUGTRACEBUFSZ); - acb->srb.debugtrace[0] = 0; - } else - dprintkl(KERN_DEBUG, "No space for tmsrb tracebuf reserved?!\n"); - return 0; -} -#else -static void free_tracebufs(struct AdapterCtlBlk *acb) {} -static int alloc_tracebufs(struct AdapterCtlBlk *acb) { return 0; } -#endif - /* Free SG tables */ -static -void adapter_sg_tables_free(struct AdapterCtlBlk *acb) +static void adapter_sg_tables_free(struct AdapterCtlBlk *acb) { int i; - const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry)); + const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page) if (acb->srb_array[i].segment_x) - dc395x_kfree(acb->srb_array[i].segment_x); + kfree(acb->srb_array[i].segment_x); } /* * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*) * should never cross a page boundary */ -static -int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) +static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) { const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1) - *DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry); + *SEGMENTX_LEN; int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE; - const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry)); + const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; struct SGentry *ptr; @@ -5261,13 +4266,13 @@ dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages); while (pages--) { - ptr = (struct SGentry *)dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); + ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) { adapter_sg_tables_free(acb); return 1; } dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n", - PAGE_SIZE, ptr, srb_idx); + PAGE_SIZE, ptr, srb_idx); i = 0; while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT) acb->srb_array[srb_idx++].segment_x = @@ -5292,14 +4297,13 @@ * * @acb: The adapter to print the information for. **/ -static -void __init adapter_print_config(struct AdapterCtlBlk *acb) +static void __init adapter_print_config(struct AdapterCtlBlk *acb) { u8 bval; bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS); - dprintkl(KERN_INFO, "%s Connectors: ", - ((bval & WIDESCSI) ? "(Wide)" : "")); + dprintkl(KERN_INFO, "%sConnectors: ", + ((bval & WIDESCSI) ? "(Wide) " : "")); if (!(bval & CON5068)) printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); if (!(bval & CON68)) @@ -5337,8 +4341,7 @@ * * @acb: The adapter to initialize. **/ -static -void __init adapter_init_params(struct AdapterCtlBlk *acb) +static void __init adapter_init_params(struct AdapterCtlBlk *acb) { struct NvRamType *eeprom = &acb->eeprom; int i; @@ -5400,8 +4403,7 @@ * * @host: The scsi host instance to fill in the values for. **/ -static -void __init adapter_init_scsi_host(struct Scsi_Host *host) +static void __init adapter_init_scsi_host(struct Scsi_Host *host) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; struct NvRamType *eeprom = &acb->eeprom; @@ -5495,8 +4497,8 @@ * Returns 0 if the initialization succeeds, any other value on * failure. **/ -static -int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port, u32 io_port_len, u8 irq) +static int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port, + u32 io_port_len, u8 irq) { if (!request_region(io_port, io_port_len, DC395X_NAME)) { dprintkl(KERN_ERR, "Failed to reserve IO region 0x%x\n", io_port); @@ -5528,19 +4530,15 @@ dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n"); goto failed; } - if (alloc_tracebufs(acb)) { - dprintkl(KERN_DEBUG, "Memory allocation for trace buffers failed\n"); - goto failed; - } adapter_init_scsi_host(acb->scsi_host); adapter_init_chip(acb); set_basic_config(acb); - dprintkdbg(DBG_0, "adapter_init: acb=%p, pdcb_map=%p " - "psrb_array=%p ACB size=%04x, DCB size=%04x " - "SRB size=%04x\n", - acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), - sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); + dprintkdbg(DBG_0, + "adapter_init: acb=%p, pdcb_map=%p psrb_array=%p " + "size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n", + acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), + sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); return 0; failed: @@ -5549,7 +4547,6 @@ if (acb->io_port_base) release_region(acb->io_port_base, acb->io_port_len); adapter_sg_tables_free(acb); - free_tracebufs(acb); return 1; } @@ -5562,8 +4559,7 @@ * * @acb: The adapter which we are to shutdown. **/ -static -void adapter_uninit_chip(struct AdapterCtlBlk *acb) +static void adapter_uninit_chip(struct AdapterCtlBlk *acb) { /* disable interrupts */ DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0); @@ -5586,8 +4582,7 @@ * * @acb: The adapter which we are to un-initialize. **/ -static -void adapter_uninit(struct AdapterCtlBlk *acb) +static void adapter_uninit(struct AdapterCtlBlk *acb) { unsigned long flags; DC395x_LOCK_IO(acb->scsi_host, flags); @@ -5608,31 +4603,9 @@ release_region(acb->io_port_base, acb->io_port_len); adapter_sg_tables_free(acb); - free_tracebufs(acb); } -/* - ****************************************************************** - * Function: dc395x_proc_info(char* buffer, char **start, - * off_t offset, int length, int hostno, int inout) - * Purpose: return SCSI Adapter/Device Info - * Input: - * buffer: Pointer to a buffer where to write info - * start : - * offset: - * hostno: Host adapter index - * inout : Read (=0) or set(!=0) info - * Output: - * buffer: contains info length - * - * return value: length of info in buffer - * - ****************************************************************** - */ - -/* KG: dc395x_proc_info taken from driver aha152x.c */ - #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, args) @@ -5641,9 +4614,8 @@ if (YN) SPRINTF(" Yes ");\ else SPRINTF(" No ") -static -int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, - int inout) +static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, + char **start, off_t offset, int length, int inout) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; int spd, spd1; @@ -5741,16 +4713,12 @@ dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); list_for_each_entry(srb, &dcb->srb_going_list, list) -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - SPRINTF("\n %s", srb->debugtrace); -#else SPRINTF(" %li", srb->cmd->pid); -#endif if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) SPRINTF("\n"); } - if (debug_enabled(DBG_DCB)) { + if (debug_enabled(DBG_1)) { SPRINTF("DCB list for ACB %p:\n", acb); list_for_each_entry(dcb, &acb->dcb_list, list) { SPRINTF("%p -> ", dcb); @@ -5770,11 +4738,6 @@ } - - -/* - * SCSI host template - */ static Scsi_Host_Template dc395x_driver_template = { .module = THIS_MODULE, .proc_name = DC395X_NAME, @@ -5799,8 +4762,7 @@ * banner_display - Display banner on first instance of driver * initialized. **/ -static -void banner_display(void) +static void banner_display(void) { static int banner_done = 0; if (!banner_done) @@ -5824,9 +4786,8 @@ * * Returns 0 on success, or an error code (-ve) on failure. **/ -static -int __devinit dc395x_init_one(struct pci_dev *dev, - const struct pci_device_id *id) +static int __devinit dc395x_init_one(struct pci_dev *dev, + const struct pci_device_id *id) { struct Scsi_Host *scsi_host; struct AdapterCtlBlk *acb; @@ -5859,7 +4820,7 @@ /* initialise the adapter and everything we need */ if (adapter_init(acb, io_port_base, io_port_len, irq)) { - dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n"); + dprintkl(KERN_INFO, "adapter init failed\n"); scsi_host_put(scsi_host); return -ENODEV; } @@ -5870,7 +4831,7 @@ if (scsi_add_host(scsi_host, &dev->dev)) { dprintkl(KERN_ERR, "scsi_add_host failed\n"); adapter_uninit(acb); - scsi_host_put(scsi_host); + scsi_host_put(scsi_host); return -ENODEV; } pci_set_drvdata(dev, scsi_host); @@ -5891,7 +4852,7 @@ struct Scsi_Host *scsi_host = pci_get_drvdata(dev); struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata); - dprintkdbg(DBG_0, "Removing instance\n"); + dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb); scsi_remove_host(scsi_host); adapter_uninit(acb); @@ -5900,10 +4861,6 @@ } -/* - * Table which identifies the PCI devices which - * are handled by this device driver. - */ static struct pci_device_id dc395x_pci_table[] = { { .vendor = PCI_VENDOR_ID_TEKRAM, @@ -5916,10 +4873,6 @@ MODULE_DEVICE_TABLE(pci, dc395x_pci_table); -/* - * PCI driver operations. - * Tells the PCI sub system what can be done with the card. - */ static struct pci_driver dc395x_driver = { .name = DC395X_NAME, .id_table = dc395x_pci_table, @@ -5933,8 +4886,7 @@ * * Used by both module and built-in driver to initialise this driver. **/ -static -int __init dc395x_module_init(void) +static int __init dc395x_module_init(void) { return pci_module_init(&dc395x_driver); } @@ -5943,8 +4895,7 @@ /** * dc395x_module_exit - Module cleanup function. **/ -static -void __exit dc395x_module_exit(void) +static void __exit dc395x_module_exit(void) { pci_unregister_driver(&dc395x_driver); } diff -Nru a/drivers/scsi/dc395x.h b/drivers/scsi/dc395x.h --- a/drivers/scsi/dc395x.h Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/dc395x.h Sat Apr 3 19:38:56 2004 @@ -7,18 +7,8 @@ /* (SCSI chip set used Tekram ASIC TRM-S1040) */ /* */ /************************************************************************/ - #ifndef DC395x_H #define DC395x_H - -/************************************************************************/ -/* */ -/* Name, Banner and Version */ -/* */ -/************************************************************************/ -#define DC395X_NAME "dc395x" -#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" -#define DC395X_VERSION "v2.04, 2003/05/19" /************************************************************************/ /* */ diff -Nru a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c --- a/drivers/scsi/dec_esp.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/dec_esp.c Sat Apr 3 19:38:54 2004 @@ -378,7 +378,7 @@ static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp) { - return sp->SCp.this_residual;; + return sp->SCp.this_residual; } static void dma_dump_state(struct NCR_ESP *esp) diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/dpt_i2o.c Sat Apr 3 19:38:55 2004 @@ -2161,7 +2161,7 @@ (adpt_hba*)(host->hostdata[0]) = pHba; pHba->host = host; - host->irq = pHba->pDev->irq;; + host->irq = pHba->pDev->irq; /* no IO ports, so don't have to set host->io_port and * host->n_io_port */ diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/eata.c Sat Apr 3 19:38:55 2004 @@ -1598,17 +1598,17 @@ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; if (DEV2H(cpp->data_address)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), DEV2H(cpp->data_len), pci_dir); } diff -Nru a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c --- a/drivers/scsi/gdth.c Sat Apr 3 19:38:44 2004 +++ b/drivers/scsi/gdth.c Sat Apr 3 19:38:44 2004 @@ -1358,7 +1358,7 @@ /* disable board interrupts, deinit services */ gdth_writeb(0xff, &dp6_ptr->io.irqdel); - gdth_writeb(0x00, &dp6_ptr->io.irqen);; + gdth_writeb(0x00, &dp6_ptr->io.irqen); gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status); gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/hosts.c Sat Apr 3 19:38:41 2004 @@ -32,6 +32,7 @@ #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -221,6 +222,11 @@ shost->max_channel = 0; shost->max_id = 8; shost->max_lun = 8; + + /* Give each shost a default transportt if the driver + * doesn't yet support Transport Attributes */ + if (!shost->transportt) + shost->transportt = &blank_transport_template; /* * All drivers right now should be able to handle 12 byte diff -Nru a/drivers/scsi/i91uscsi.c b/drivers/scsi/i91uscsi.c --- a/drivers/scsi/i91uscsi.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/i91uscsi.c Sat Apr 3 19:38:41 2004 @@ -2133,7 +2133,7 @@ tul_append_done_scb(pCurHcb, pCurScb); } for (i = 0; i < pCurHcb->HCS_MaxTar; i++) { - pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);; + pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); } return (-1); } diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/ide-scsi.c Sat Apr 3 19:38:45 2004 @@ -78,6 +78,7 @@ #define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */ #define PC_WRITING 1 /* Data direction */ #define PC_TRANSFORM 2 /* transform SCSI commands */ +#define PC_TIMEDOUT 3 /* command timed out */ #define PC_DMA_OK 4 /* Use DMA */ /* @@ -307,6 +308,41 @@ return ide_do_drive_cmd(drive, rq, ide_preempt); } +ide_startstop_t idescsi_atapi_error (ide_drive_t *drive, const char *msg, byte stat) +{ + struct request *rq; + byte err; + + err = ide_dump_atapi_status(drive, msg, stat); + + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + + if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) + /* force an abort */ + HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + + rq->errors++; + DRIVER(drive)->end_request(drive, 0, 0); + return ide_stopped; +} + +ide_startstop_t idescsi_atapi_abort (ide_drive_t *drive, const char *msg) +{ + struct request *rq; + + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + +#if IDESCSI_DEBUG_LOG + printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n", + ((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number); +#endif + rq->errors |= ERROR_MAX; + DRIVER(drive)->end_request(drive, 0, 0); + return ide_stopped; +} + static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); @@ -334,7 +370,13 @@ kfree(rq); pc = opc; rq = pc->rq; - pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); + pc->scsi_cmd->result = (CHECK_CONDITION << 1) | + ((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16); + } else if (test_bit(PC_TIMEDOUT, &pc->flags)) { + if (log) + printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", + drive->name, pc->scsi_cmd->serial_number); + pc->scsi_cmd->result = DID_TIME_OUT << 16; } else if (rq->errors >= ERROR_MAX) { pc->scsi_cmd->result = DID_ERROR << 16; if (log) @@ -374,6 +416,19 @@ return IDE_MAX(WAIT_CMD, pc->timeout - jiffies); } +static int idescsi_expiry(ide_drive_t *drive) +{ + idescsi_scsi_t *scsi = drive->driver_data; + idescsi_pc_t *pc = scsi->pc; + +#if IDESCSI_DEBUG_LOG + printk(KERN_WARNING "idescsi_expiry called for %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies); +#endif + set_bit(PC_TIMEDOUT, &pc->flags); + + return 0; /* we do not want the ide subsystem to retry */ +} + /* * Our interrupt handler. */ @@ -393,6 +448,15 @@ printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n"); #endif /* IDESCSI_DEBUG_LOG */ + if (test_bit(PC_TIMEDOUT, &pc->flags)){ +#if IDESCSI_DEBUG_LOG + printk(KERN_WARNING "idescsi_pc_intr: got timed out packet %lu at %lu\n", + pc->scsi_cmd->serial_number, jiffies); +#endif + /* end this request now - scsi should retry it*/ + idescsi_end_request (drive, 1, 0); + return ide_stopped; + } if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { #if IDESCSI_DEBUG_LOG printk ("ide-scsi: %s: DMA complete\n", drive->name); @@ -442,7 +506,7 @@ pc->actually_transferred += temp; pc->current_position += temp; idescsi_discard_data(drive, bcount.all - temp); - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } #if IDESCSI_DEBUG_LOG @@ -467,7 +531,8 @@ pc->actually_transferred += bcount.all; pc->current_position += bcount.all; - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* And set the interrupt handler again */ + /* And set the interrupt handler again */ + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } @@ -492,7 +557,7 @@ if (HWGROUP(drive)->handler != NULL) BUG(); /* Set the interrupt routine */ - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); /* Send the actual packet */ atapi_output_bytes(drive, scsi->pc->c, 12); if (test_bit (PC_DMA_OK, &pc->flags)) { @@ -540,7 +605,7 @@ if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &idescsi_transfer_pc, - get_timeout(pc), NULL); + get_timeout(pc), idescsi_expiry); /* Issue the packet command */ HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); return ide_started; @@ -633,6 +698,8 @@ .cleanup = idescsi_cleanup, .do_request = idescsi_do_request, .end_request = idescsi_end_request, + .error = idescsi_atapi_error, + .abort = idescsi_atapi_abort, .drives = LIST_HEAD_INIT(idescsi_driver.drives), }; @@ -852,66 +919,132 @@ return 1; } -static int idescsi_abort (Scsi_Cmnd *cmd) +static int idescsi_eh_abort (Scsi_Cmnd *cmd) { - int countdown = 8; - unsigned long flags; - idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); - ide_drive_t *drive = scsi->drive; + idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); + ide_drive_t *drive = scsi->drive; + int busy; + int ret = FAILED; - printk (KERN_ERR "ide-scsi: abort called for %lu\n", cmd->serial_number); - while (countdown--) { - /* is cmd active? - * need to lock so this stuff doesn't change under us */ - spin_lock_irqsave(&ide_lock, flags); - if (scsi->pc && scsi->pc->scsi_cmd && - scsi->pc->scsi_cmd->serial_number == cmd->serial_number) { - /* yep - let's give it some more time - - * we can do that, we're in _our_ error kernel thread */ - spin_unlock_irqrestore(&ide_lock, flags); - scsi_sleep(HZ); - continue; - } - /* no, but is it queued in the ide subsystem? */ - if (elv_queue_empty(drive->queue)) { - spin_unlock_irqrestore(&ide_lock, flags); - return SUCCESS; - } - spin_unlock_irqrestore(&ide_lock, flags); - schedule_timeout(HZ/10); + /* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */ + + if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) + printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number); + + if (!drive) { + printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n"); + WARN_ON(1); + goto no_drive; + } + + /* First give it some more time, how much is "right" is hard to say :-( */ + + busy = ide_wait_not_busy(HWIF(drive), 100); /* FIXME - uses mdelay which causes latency? */ + if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) + printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":""); + + spin_lock_irq(&ide_lock); + + /* If there is no pc running we're done (our interrupt took care of it) */ + if (!scsi->pc) { + ret = SUCCESS; + goto ide_unlock; } - return FAILED; + + /* It's somewhere in flight. Does ide subsystem agree? */ + if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy && + elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) { + /* + * FIXME - not sure this condition can ever occur + */ + printk (KERN_ERR "ide-scsi: cmd aborted!\n"); + + idescsi_free_bio(scsi->pc->rq->bio); + if (scsi->pc->rq->flags & REQ_SENSE) + kfree(scsi->pc->buffer); + kfree(scsi->pc->rq); + kfree(scsi->pc); + scsi->pc = NULL; + + ret = SUCCESS; + } + +ide_unlock: + spin_unlock_irq(&ide_lock); +no_drive: + if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) + printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed"); + + return ret; } -static int idescsi_reset (Scsi_Cmnd *cmd) +static int idescsi_eh_reset (Scsi_Cmnd *cmd) { - unsigned long flags; struct request *req; - idescsi_scsi_t *idescsi = scsihost_to_idescsi(cmd->device->host); - ide_drive_t *drive = idescsi->drive; + idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); + ide_drive_t *drive = scsi->drive; + int ready = 0; + int ret = SUCCESS; + + /* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */ + + if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) + printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number); + + if (!drive) { + printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n"); + WARN_ON(1); + return FAILED; + } + + spin_lock_irq(&ide_lock); + + if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) { + printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n"); + spin_unlock(&ide_lock); + return FAILED; + } + + /* kill current request */ + blkdev_dequeue_request(req); + end_that_request_last(req); + idescsi_free_bio(req->bio); + if (req->flags & REQ_SENSE) + kfree(scsi->pc->buffer); + kfree(scsi->pc); + scsi->pc = NULL; + kfree(req); - printk (KERN_ERR "ide-scsi: reset called for %lu\n", cmd->serial_number); - /* first null the handler for the drive and let any process - * doing IO (on another CPU) run to (partial) completion - * the lock prevents processing new requests */ - spin_lock_irqsave(&ide_lock, flags); - while (HWGROUP(drive)->handler) { - HWGROUP(drive)->handler = NULL; - schedule_timeout(1); - } /* now nuke the drive queue */ while ((req = elv_next_request(drive->queue))) { blkdev_dequeue_request(req); end_that_request_last(req); } - /* FIXME - this will probably leak memory */ + HWGROUP(drive)->rq = NULL; - if (drive_to_idescsi(drive)) - drive_to_idescsi(drive)->pc = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - /* finally, reset the drive (and its partner on the bus...) */ - ide_do_reset (drive); - return SUCCESS; + HWGROUP(drive)->handler = NULL; + HWGROUP(drive)->busy = 1; /* will set this to zero when ide reset finished */ + spin_unlock_irq(&ide_lock); + + ide_do_reset(drive); + + /* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */ + + do { + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irq(cmd->device->host->host_lock); + schedule_timeout(HZ/20); + spin_lock_irq(cmd->device->host->host_lock); + } while ( HWGROUP(drive)->handler ); + + ready = drive_is_ready(drive); + HWGROUP(drive)->busy--; + if (!ready) { + printk (KERN_ERR "ide-scsi: reset failed!\n"); + ret = FAILED; + } + + return ret; } static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev, @@ -935,8 +1068,8 @@ .slave_configure = idescsi_slave_configure, .ioctl = idescsi_ioctl, .queuecommand = idescsi_queue, - .eh_abort_handler = idescsi_abort, - .eh_device_reset_handler = idescsi_reset, + .eh_abort_handler = idescsi_eh_abort, + .eh_host_reset_handler = idescsi_eh_reset, .bios_param = idescsi_bios, .can_queue = 40, .this_id = -1, @@ -967,7 +1100,16 @@ return 1; host->max_id = 1; - host->max_lun = 1; + +#if IDESCSI_DEBUG_LOG + if (drive->id->last_lun) + printk(KERN_NOTICE "%s: id->last_lun=%u\n", drive->name, drive->id->last_lun); +#endif + if ((drive->id->last_lun & 0x7) != 7) + host->max_lun = (drive->id->last_lun & 0x7) + 1; + else + host->max_lun = 1; + drive->driver_data = host; idescsi = scsihost_to_idescsi(host); idescsi->drive = drive; diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c --- a/drivers/scsi/in2000.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/in2000.c Sat Apr 3 19:38:54 2004 @@ -2288,7 +2288,7 @@ return 0; /* return 0 to signal end-of-file */ } if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ - stop = 1;; + stop = 1; if (hd->proc & PR_STOP) /* stop every other time */ stop = 1; return strlen(bp); diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c --- a/drivers/scsi/ini9100u.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/ini9100u.c Sat Apr 3 19:38:42 2004 @@ -180,15 +180,6 @@ static char *setup_str = (char *) NULL; -static irqreturn_t i91u_intr0(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr1(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr2(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr3(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr4(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr5(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr6(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr7(int irq, void *dev_id, struct pt_regs *); - static void i91u_panic(char *msg); static void i91uSCBPost(BYTE * pHcb, BYTE * pScb); @@ -278,7 +269,7 @@ unsigned long flags; spin_lock_irqsave(dev->host_lock, flags); - tul_isr((HCS *)hreg->base); + tul_isr((HCS *)dev->base); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/libata-core.c Sat Apr 3 19:38:40 2004 @@ -49,13 +49,16 @@ unsigned long tmout_pat, unsigned long tmout); static void __ata_dev_select (struct ata_port *ap, unsigned int device); +#if 0 /* to be used eventually */ static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append); +#endif static void ata_dma_complete(struct ata_port *ap, u8 host_stat, unsigned int done_late); static void ata_host_set_pio(struct ata_port *ap); static void ata_host_set_udma(struct ata_port *ap); static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); +static void ata_set_mode(struct ata_port *ap); static unsigned int ata_unique_id = 1; @@ -141,7 +144,7 @@ } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - outb(tf->hob_feature, ioaddr->error_addr); + outb(tf->hob_feature, ioaddr->feature_addr); outb(tf->hob_nsect, ioaddr->nsect_addr); outb(tf->hob_lbal, ioaddr->lbal_addr); outb(tf->hob_lbam, ioaddr->lbam_addr); @@ -155,7 +158,7 @@ } if (is_addr) { - outb(tf->feature, ioaddr->error_addr); + outb(tf->feature, ioaddr->feature_addr); outb(tf->nsect, ioaddr->nsect_addr); outb(tf->lbal, ioaddr->lbal_addr); outb(tf->lbam, ioaddr->lbam_addr); @@ -199,7 +202,7 @@ } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void *) ioaddr->error_addr); + writeb(tf->hob_feature, (void *) ioaddr->feature_addr); writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr); writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr); writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr); @@ -213,7 +216,7 @@ } if (is_addr) { - writeb(tf->feature, (void *) ioaddr->error_addr); + writeb(tf->feature, (void *) ioaddr->feature_addr); writeb(tf->nsect, (void *) ioaddr->nsect_addr); writeb(tf->lbal, (void *) ioaddr->lbal_addr); writeb(tf->lbam, (void *) ioaddr->lbam_addr); @@ -250,7 +253,7 @@ { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - outb(tf->command, ap->ioaddr.cmdstat_addr); + outb(tf->command, ap->ioaddr.command_addr); ata_pause(ap); } @@ -271,7 +274,7 @@ { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void *) ap->ioaddr.cmdstat_addr); + writeb(tf->command, (void *) ap->ioaddr.command_addr); ata_pause(ap); } @@ -417,7 +420,7 @@ */ u8 ata_check_status_pio(struct ata_port *ap) { - return inb(ap->ioaddr.cmdstat_addr); + return inb(ap->ioaddr.status_addr); } /** @@ -433,7 +436,7 @@ */ u8 ata_check_status_mmio(struct ata_port *ap) { - return readb((void *) ap->ioaddr.cmdstat_addr); + return readb((void *) ap->ioaddr.status_addr); } static const char * udma_str[] = { @@ -1029,7 +1032,7 @@ if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED)) goto err_out_disable; - ap->ops->phy_config(ap); + ata_set_mode(ap); if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out_disable; @@ -1118,13 +1121,13 @@ } /** - * pata_phy_config - - * @ap: + * ata_set_mode - Program timings and issue SET FEATURES - XFER + * @ap: port on which timings will be programmed * * LOCKING: * */ -void pata_phy_config(struct ata_port *ap) +static void ata_set_mode(struct ata_port *ap) { unsigned int force_pio; @@ -1156,6 +1159,8 @@ return; } + if (ap->ops->post_set_mode) + ap->ops->post_set_mode(ap); } /** @@ -1346,12 +1351,6 @@ DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no); - /* set up device control */ - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - /* determine if device 0/1 are present */ if (ap->flags & ATA_FLAG_SATA_RESET) dev0 = 1; @@ -1372,8 +1371,14 @@ /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) rc = ata_bus_softreset(ap, devmask); - else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) + else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { + /* set up device control */ + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); rc = ata_bus_edd(ap); + } if (rc) goto err_out; @@ -1399,6 +1404,14 @@ (ap->device[1].class == ATA_DEV_NONE)) goto err_out; + if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { + /* set up device control for ATA_FLAG_SATA_RESET */ + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + } + DPRINTK("EXIT\n"); return; @@ -1445,7 +1458,8 @@ if (ata_dev_present(&ap->device[i])) { ap->device[i].pio_mode = (pio == 3) ? XFER_PIO_3 : XFER_PIO_4; - ap->ops->set_piomode(ap, &ap->device[i], pio); + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, &ap->device[i], pio); } return; @@ -1509,7 +1523,9 @@ for (i = 0; i < ATA_MAX_DEVICES; i++) if (ata_dev_present(&ap->device[i])) { ap->device[i].udma_mode = udma_mode; - ap->ops->set_udmamode(ap, &ap->device[i], udma_mode); + if (ap->ops->set_udmamode) + ap->ops->set_udmamode(ap, &ap->device[i], + udma_mode); } return; @@ -1960,6 +1976,7 @@ kunmap(sg[qc->cursg].page); } +#if 0 /* to be used eventually */ /** * ata_eng_schedule - run an iteration of the pio/dma/whatever engine * @ap: port on which activity will occur @@ -1972,6 +1989,7 @@ { /* FIXME */ } +#endif /** * ata_eng_timeout - Handle timeout of queued command @@ -2161,6 +2179,7 @@ clear_bit(tag, &ap->qactive); } +#if 0 /* to be used eventually */ /** * ata_qc_push - * @qc: @@ -2182,6 +2201,7 @@ if (!test_and_set_bit(ATA_EFLG_ACTIVE, &eng->flags)) ata_eng_schedule(ap, eng); } +#endif /** * ata_qc_issue - @@ -2246,9 +2266,12 @@ mb(); /* make sure PRD table writes are visible to controller */ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); - /* specify data direction */ - /* FIXME: redundant to later start-dma command? */ - writeb(rw ? 0 : ATA_DMA_WR, mmio + ATA_DMA_CMD); + /* specify data direction, triple-check start bit is clear */ + dmactl = readb(mmio + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + writeb(dmactl, mmio + ATA_DMA_CMD); /* clear interrupt, error bits */ host_stat = readb(mmio + ATA_DMA_STATUS); @@ -2258,7 +2281,6 @@ ap->ops->exec_command(ap, &qc->tf); /* start host DMA transaction */ - dmactl = readb(mmio + ATA_DMA_CMD); writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); /* Strictly, one may wish to issue a readb() here, to @@ -2291,9 +2313,12 @@ /* load PRD table addr. */ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); - /* specify data direction */ - /* FIXME: redundant to later start-dma command? */ - outb(rw ? 0 : ATA_DMA_WR, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + /* specify data direction, triple-check start bit is clear */ + dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* clear interrupt, error bits */ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); @@ -2304,7 +2329,6 @@ ap->ops->exec_command(ap, &qc->tf); /* start host DMA transaction */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); outb(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } @@ -2327,14 +2351,16 @@ void *mmio = (void *) ap->ioaddr.bmdma_addr; /* clear start/stop bit */ - writeb(0, mmio + ATA_DMA_CMD); + writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); /* ack intr, err bits */ writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS); } else { /* clear start/stop bit */ - outb(0, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* ack intr, err bits */ outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, @@ -2369,8 +2395,8 @@ * One if interrupt was handled, zero if not (shared irq). */ -static inline unsigned int ata_host_intr (struct ata_port *ap, - struct ata_queued_cmd *qc) +inline unsigned int ata_host_intr (struct ata_port *ap, + struct ata_queued_cmd *qc) { u8 status, host_stat; unsigned int handled = 0; @@ -2728,7 +2754,7 @@ if (!ap->prd) return -ENOMEM; - DPRINTK("prd alloc, virt %p, dma %x\n", ap->prd, ap->prd_dma); + DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma); return 0; } @@ -3026,12 +3052,14 @@ { ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR; + ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE; ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT; ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL; ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM; ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH; ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE; - ioaddr->cmdstat_addr = ioaddr->cmd_addr + ATA_REG_CMD; + ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS; + ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } /** @@ -3121,6 +3149,9 @@ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { @@ -3153,12 +3184,14 @@ if (legacy_mode) { probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = 0x3f6; probe_ent->n_ports = 1; probe_ent->irq = 14; ata_std_ports(&probe_ent->port[0]); probe_ent2->port[0].cmd_addr = 0x170; + probe_ent2->port[0].altstatus_addr = probe_ent2->port[0].ctl_addr = 0x376; probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; probe_ent2->n_ports = 1; @@ -3173,11 +3206,13 @@ } else { probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = probe_ent->port[1].ctl_addr = pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; @@ -3358,7 +3393,6 @@ EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); -EXPORT_SYMBOL_GPL(pata_phy_config); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_pci_init_one); @@ -3367,4 +3401,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); - +EXPORT_SYMBOL_GPL(ata_host_intr); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/libata-scsi.c Sat Apr 3 19:38:43 2004 @@ -251,6 +251,8 @@ tf->lbam = scsicmd[2]; tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ + tf->device |= ATA_LBA; + VPRINTK("six-byte command\n"); return 0; } diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/libata.h Sat Apr 3 19:38:41 2004 @@ -26,7 +26,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "1.01" /* must be exactly four chars */ +#define DRV_VERSION "1.02" /* must be exactly four chars */ struct ata_scsi_args { struct ata_port *ap; diff -Nru a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c --- a/drivers/scsi/mac53c94.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/mac53c94.c Sat Apr 3 19:38:41 2004 @@ -25,8 +25,11 @@ #include #include -#include "scsi.h" -#include "hosts.h" +#include +#include +#include +#include + #include "mac53c94.h" enum fsc_phase { @@ -44,9 +47,9 @@ int dmaintr; int clk_freq; struct Scsi_Host *host; - Scsi_Cmnd *request_q; - Scsi_Cmnd *request_qtail; - Scsi_Cmnd *current_req; /* req we're currently working on */ + struct scsi_cmnd *request_q; + struct scsi_cmnd *request_qtail; + struct scsi_cmnd *current_req; /* req we're currently working on */ enum fsc_phase phase; /* what we're currently trying to do */ struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ void *dma_cmd_space; @@ -60,15 +63,15 @@ static void mac53c94_interrupt(int, void *, struct pt_regs *); static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *); static void cmd_done(struct fsc_state *, int result); -static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *); +static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); -static int mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct fsc_state *state; #if 0 - if (cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { int i; printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd); for (i = 0; i < cmd->cmd_len; ++i) @@ -95,12 +98,12 @@ return 0; } -static int mac53c94_abort(Scsi_Cmnd *cmd) +static int mac53c94_abort(struct scsi_cmnd *cmd) { - return SCSI_ABORT_SNOOZE; + return FAILED; } -static int mac53c94_host_reset(Scsi_Cmnd *cmd) +static int mac53c94_host_reset(struct scsi_cmnd *cmd) { struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata; struct mac53c94_regs *regs = state->regs; @@ -139,7 +142,7 @@ */ static void mac53c94_start(struct fsc_state *state) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; struct mac53c94_regs *regs = state->regs; int i; @@ -148,7 +151,7 @@ if (state->request_q == NULL) return; state->current_req = cmd = state->request_q; - state->request_q = (Scsi_Cmnd *) cmd->host_scribble; + state->request_q = (struct scsi_cmnd *) cmd->host_scribble; /* Off we go */ writeb(0, ®s->count_lo); @@ -190,10 +193,9 @@ struct fsc_state *state = (struct fsc_state *) dev_id; struct mac53c94_regs *regs = state->regs; struct dbdma_regs *dma = state->dma; - Scsi_Cmnd *cmd = state->current_req; + struct scsi_cmnd *cmd = state->current_req; int nb, stat, seq, intr; static int mac53c94_errors; - int dma_dir; /* * Apparently, reading the interrupt register unlatches @@ -308,14 +310,13 @@ printk(KERN_DEBUG "intr %x before data xfer complete\n", intr); } writel(RUN << 16, &dma->control); /* stop dma */ - dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); if (cmd->use_sg != 0) { pci_unmap_sg(state->pdev, (struct scatterlist *)cmd->request_buffer, - cmd->use_sg, dma_dir); + cmd->use_sg, cmd->sc_data_direction); } else { pci_unmap_single(state->pdev, state->dma_addr, - cmd->request_bufflen, dma_dir); + cmd->request_bufflen, cmd->sc_data_direction); } /* should check dma status */ writeb(CMD_I_COMPLETE, ®s->command); @@ -347,7 +348,7 @@ static void cmd_done(struct fsc_state *state, int result) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; cmd = state->current_req; if (cmd != 0) { @@ -362,24 +363,24 @@ /* * Set up DMA commands for transferring data. */ -static void set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd) +static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd) { int i, dma_cmd, total; struct scatterlist *scl; struct dbdma_cmd *dcmds; dma_addr_t dma_addr; u32 dma_len; - int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - dma_cmd = cmd->sc_data_direction == SCSI_DATA_WRITE? OUTPUT_MORE: - INPUT_MORE; + dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ? + OUTPUT_MORE : INPUT_MORE; dcmds = state->dma_cmds; if (cmd->use_sg > 0) { int nseg; total = 0; scl = (struct scatterlist *) cmd->buffer; - nseg = pci_map_sg(state->pdev, scl, cmd->use_sg, dma_dir); + nseg = pci_map_sg(state->pdev, scl, cmd->use_sg, + cmd->sc_data_direction); for (i = 0; i < nseg; ++i) { dma_addr = sg_dma_address(scl); dma_len = sg_dma_len(scl); @@ -398,7 +399,7 @@ if (total > 0xffff) panic("mac53c94: transfer size >= 64k"); dma_addr = pci_map_single(state->pdev, cmd->request_buffer, - total, dma_dir); + total, cmd->sc_data_direction); state->dma_addr = dma_addr; st_le16(&dcmds->req_count, total); st_le32(&dcmds->phy_addr, dma_addr); @@ -411,7 +412,7 @@ cmd->SCp.this_residual = total; } -static Scsi_Host_Template mac53c94_template = { +static struct scsi_host_template mac53c94_template = { .proc_name = "53c94", .name = "53C94", .queuecommand = mac53c94_queue, diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/megaraid.c Sat Apr 3 19:38:40 2004 @@ -261,10 +261,6 @@ "megaraid: Product_info cmd failed with error: %d\n", retval); - pci_dma_sync_single(adapter->dev, prod_info_dma_handle, - sizeof(mega_product_info), - PCI_DMA_FROMDEVICE); - pci_unmap_single(adapter->dev, prod_info_dma_handle, sizeof(mega_product_info), PCI_DMA_FROMDEVICE); } @@ -1651,26 +1647,11 @@ case MEGA_BULK_DATA: pci_unmap_page(adapter->dev, scb->dma_h_bulkdata, scb->cmd->request_bufflen, scb->dma_direction); - - if( scb->dma_direction == PCI_DMA_FROMDEVICE ) { - pci_dma_sync_single(adapter->dev, - scb->dma_h_bulkdata, - scb->cmd->request_bufflen, - PCI_DMA_FROMDEVICE); - } - break; case MEGA_SGLIST: pci_unmap_sg(adapter->dev, scb->cmd->request_buffer, scb->cmd->use_sg, scb->dma_direction); - - if( scb->dma_direction == PCI_DMA_FROMDEVICE ) { - pci_dma_sync_sg(adapter->dev, - scb->cmd->request_buffer, - scb->cmd->use_sg, PCI_DMA_FROMDEVICE); - } - break; default: @@ -1758,14 +1739,6 @@ *buf = (u32)scb->dma_h_bulkdata; *len = (u32)cmd->request_bufflen; } - - if( scb->dma_direction == PCI_DMA_TODEVICE ) { - pci_dma_sync_single(adapter->dev, - scb->dma_h_bulkdata, - cmd->request_bufflen, - PCI_DMA_TODEVICE); - } - return 0; } @@ -1804,11 +1777,6 @@ */ *len = (u32)cmd->request_bufflen; - if( scb->dma_direction == PCI_DMA_TODEVICE ) { - pci_dma_sync_sg(adapter->dev, sgl, cmd->use_sg, - PCI_DMA_TODEVICE); - } - /* Return count of SG requests */ return sgcnt; } @@ -4614,6 +4582,7 @@ } static struct scsi_host_template megaraid_template = { + .module = THIS_MODULE, .name = "MegaRAID", .proc_name = "megaraid", .info = megaraid_info, @@ -5118,10 +5087,6 @@ if (max_mbox_busy_wait > MBOX_BUSY_WAIT) max_mbox_busy_wait = MBOX_BUSY_WAIT; - error = pci_module_init(&megaraid_pci_driver); - if (error) - return error; - #ifdef CONFIG_PROC_FS mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root); if (!mega_proc_dir_entry) { @@ -5129,6 +5094,13 @@ "megaraid: failed to create megaraid root\n"); } #endif + error = pci_module_init(&megaraid_pci_driver); + if (error) { +#ifdef CONFIG_PROC_FS + remove_proc_entry("megaraid", &proc_root); +#endif + return error; + } /* * Register the driver as a character device, for applications diff -Nru a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c --- a/drivers/scsi/mesh.c Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/mesh.c Sat Apr 3 19:38:45 2004 @@ -44,8 +44,11 @@ #include #include -#include "scsi.h" -#include "hosts.h" +#include +#include +#include +#include + #include "mesh.h" #if 1 @@ -131,7 +134,7 @@ enum sdtr_phase sdtr_state; int sync_params; int data_goes_out; /* guess as to data direction */ - Scsi_Cmnd *current_req; + struct scsi_cmnd *current_req; u32 saved_ptr; #ifdef MESH_DBG int log_ix; @@ -147,12 +150,12 @@ int dmaintr; struct Scsi_Host *host; struct mesh_state *next; - Scsi_Cmnd *request_q; - Scsi_Cmnd *request_qtail; + struct scsi_cmnd *request_q; + struct scsi_cmnd *request_qtail; enum mesh_phase phase; /* what we're currently trying to do */ enum msg_phase msgphase; int conn_tgt; /* target we're connected to */ - Scsi_Cmnd *current_req; /* req we're currently working on */ + struct scsi_cmnd *current_req; /* req we're currently working on */ int data_ptr; int dma_started; int dma_count; @@ -185,7 +188,7 @@ static void mesh_done(struct mesh_state *ms, int start_next); static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs); static void cmd_complete(struct mesh_state *ms); -static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd); +static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd); static void halt_dma(struct mesh_state *ms); static void phase_mismatch(struct mesh_state *ms); @@ -344,7 +347,7 @@ /* * Complete a SCSI command */ -static void mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd) +static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd) { (*cmd->scsi_done)(cmd); } @@ -402,14 +405,14 @@ } -static void mesh_start_cmd(struct mesh_state *ms, Scsi_Cmnd *cmd) +static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) { volatile struct mesh_regs *mr = ms->mesh; int t, id; id = cmd->device->id; ms->current_req = cmd; - ms->tgts[id].data_goes_out = cmd->sc_data_direction == SCSI_DATA_WRITE; + ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE; ms->tgts[id].current_req = cmd; #if 1 @@ -558,7 +561,7 @@ */ static void mesh_start(struct mesh_state *ms) { - Scsi_Cmnd *cmd, *prev, *next; + struct scsi_cmnd *cmd, *prev, *next; if (ms->phase != idle || ms->current_req != NULL) { printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)", @@ -568,14 +571,14 @@ while (ms->phase == idle) { prev = NULL; - for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) { + for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) { if (cmd == NULL) return; if (ms->tgts[cmd->device->id].current_req == NULL) break; prev = cmd; } - next = (Scsi_Cmnd *) cmd->host_scribble; + next = (struct scsi_cmnd *) cmd->host_scribble; if (prev == NULL) ms->request_q = next; else @@ -589,7 +592,7 @@ static void mesh_done(struct mesh_state *ms, int start_next) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; cmd = ms->current_req; @@ -679,7 +682,7 @@ int i, seq, nb; volatile struct mesh_regs *mr = ms->mesh; volatile struct dbdma_regs *md = ms->dma; - Scsi_Cmnd *cmd = ms->current_req; + struct scsi_cmnd *cmd = ms->current_req; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; dlog(ms, "start_phase nmo/exc/fc/seq = %.8x", @@ -854,7 +857,7 @@ static void reselected(struct mesh_state *ms) { volatile struct mesh_regs *mr = ms->mesh; - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; struct mesh_target *tp; int b, t, prev; @@ -985,7 +988,7 @@ { int tgt; struct mesh_target *tp; - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; volatile struct mesh_regs *mr = ms->mesh; for (tgt = 0; tgt < 8; ++tgt) { @@ -1000,7 +1003,7 @@ } ms->current_req = NULL; while ((cmd = ms->request_q) != NULL) { - ms->request_q = (Scsi_Cmnd *) cmd->host_scribble; + ms->request_q = (struct scsi_cmnd *) cmd->host_scribble; cmd->result = DID_RESET << 16; mesh_completed(ms, cmd); } @@ -1154,7 +1157,7 @@ static void handle_msgin(struct mesh_state *ms) { int i, code; - Scsi_Cmnd *cmd = ms->current_req; + struct scsi_cmnd *cmd = ms->current_req; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; if (ms->n_msgin == 0) @@ -1252,7 +1255,7 @@ /* * Set up DMA commands for transferring data. */ -static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd) +static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) { int i, dma_cmd, total, off, dtot; struct scatterlist *scl; @@ -1270,7 +1273,7 @@ scl = (struct scatterlist *) cmd->buffer; off = ms->data_ptr; nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg, - scsi_to_pci_dma_dir(cmd ->sc_data_direction)); + cmd->sc_data_direction); for (i = 0; i dma; volatile struct mesh_regs *mr = ms->mesh; - Scsi_Cmnd *cmd = ms->current_req; + struct scsi_cmnd *cmd = ms->current_req; int t, nb; if (!ms->tgts[ms->conn_tgt].data_goes_out) { @@ -1364,8 +1367,7 @@ if (cmd->use_sg != 0) { struct scatterlist *sg; sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(ms->pdev, sg, cmd->use_sg, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); + pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction); } ms->dma_started = 0; } @@ -1452,7 +1454,7 @@ static void cmd_complete(struct mesh_state *ms) { volatile struct mesh_regs *mr = ms->mesh; - Scsi_Cmnd *cmd = ms->current_req; + struct scsi_cmnd *cmd = ms->current_req; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; int seq, n, t; @@ -1635,7 +1637,7 @@ * Called by midlayer with host locked to queue a new * request */ -static int mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct mesh_state *ms; @@ -1692,7 +1694,7 @@ * queue if it isn't connected yet, and for pending command, assert * ATN until the bus gets freed. */ -static int mesh_abort(Scsi_Cmnd *cmd) +static int mesh_abort(struct scsi_cmnd *cmd) { struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; @@ -1700,7 +1702,7 @@ mesh_dump_regs(ms); dumplog(ms, cmd->device->id); dumpslog(ms); - return SCSI_ABORT_SNOOZE; + return FAILED; } /* @@ -1709,7 +1711,7 @@ * The midlayer will wait for devices to come back, we don't need * to do that ourselves */ -static int mesh_host_reset(Scsi_Cmnd *cmd) +static int mesh_host_reset(struct scsi_cmnd *cmd) { struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; volatile struct mesh_regs *mr = ms->mesh; @@ -1832,7 +1834,7 @@ return 0; } -static Scsi_Host_Template mesh_template = { +static struct scsi_host_template mesh_template = { .proc_name = "mesh", .name = "MESH", .queuecommand = mesh_queue, diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c --- a/drivers/scsi/ncr53c8xx.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/ncr53c8xx.c Sat Apr 3 19:38:42 2004 @@ -5140,9 +5140,10 @@ */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && cmd->cmnd[4] >= 7 && !cmd->use_sg) { - sync_scsi_data(np, cmd); /* SYNC the data */ + sync_scsi_data_for_cpu(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cmd->device->id, cmd->device->lun, (char *) cmd->request_buffer); + sync_scsi_data_for_device(np, cmd); /* SYNC the data */ } tp->bytes += cp->data_len; diff -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c --- a/drivers/scsi/oktagon_esp.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/oktagon_esp.c Sat Apr 3 19:38:41 2004 @@ -12,7 +12,6 @@ #define USE_BOTTOM_HALF #endif -#define __KERNEL_SYSCALLS__ #include #include @@ -42,8 +41,6 @@ #include #include #endif - -#include /* The controller registers can be found in the Z2 config area at these * offsets: diff -Nru a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c --- a/drivers/scsi/pci2000.c Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/pci2000.c Sat Apr 3 19:38:45 2004 @@ -320,7 +320,7 @@ outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op - goto irq_return;; // done, but, with what? + goto irq_return; // done, but, with what? unmapProceed:; if ( !bus ) diff -Nru a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c --- a/drivers/scsi/pci2220i.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/pci2220i.c Sat Apr 3 19:38:40 2004 @@ -1389,7 +1389,7 @@ (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) ) { if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) ) - break;; + break; if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor? testsize = SetReconstruct (pdev, 0); @@ -2613,7 +2613,7 @@ if ( ++Installed < MAXADAPTER ) continue; - break;; + break; unregister:; scsi_unregister (pshost); } @@ -2747,7 +2747,7 @@ if ( ++Installed < MAXADAPTER ) continue; - break;; + break; unregister1:; scsi_unregister (pshost); } diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c --- a/drivers/scsi/pcmcia/qlogic_stub.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/pcmcia/qlogic_stub.c Sat Apr 3 19:38:43 2004 @@ -43,9 +43,11 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" +#include "../qlogicfas.h" #include #include @@ -57,8 +59,10 @@ extern Scsi_Host_Template qlogicfas_driver_template; extern void qlogicfas_preset(int port, int irq); -extern struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *); extern int qlogicfas_bus_reset(Scsi_Cmnd *); +extern irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs); + +static char *qlogic_name = "qlogic_cs"; #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; @@ -100,6 +104,71 @@ static dev_info_t dev_info = "qlogic_cs"; +static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host, + dev_link_t *link, int qbase, int qlirq) +{ + int qltyp; /* type of chip */ + int qinitid; + struct Scsi_Host *shost; /* registered host structure */ + qlogicfas_priv_t priv; + + qltyp = inb(qbase + 0xe) & 0xf8; + qinitid = host->this_id; + if (qinitid < 0) + qinitid = 7; /* if no ID, use 7 */ + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + REG0; + outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ + outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9, qbase + 9); /* prescaler */ + +#if QL_RESET_AT_START + outb(3, qbase + 3); + REG1; + /* FIXME: timeout */ + while (inb(qbase + 0xf) & 4) + cpu_relax(); + REG0; +#endif + + host->name = qlogic_name; + shost = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); + if (!shost) + goto err; + shost->io_port = qbase; + shost->n_io_port = 16; + shost->dma_channel = -1; + if (qlirq != -1) + shost->irq = qlirq; + + priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv->qlirq = qlirq; + priv->qbase = qbase; + priv->qinitid = qinitid; + + if (request_irq(qlirq, do_ql_ihandl, 0, qlogic_name, shost)) + goto free_scsi_host; + + sprintf(priv->qinfo, + "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", + qltyp, qbase, qlirq, QL_TURBO_PDMA); + + if (scsi_add_host(shost, NULL)) + goto free_interrupt; + + scsi_scan_host(shost); + + return shost; + +free_interrupt: + free_irq(qlirq, shost); + +free_scsi_host: + scsi_host_put(shost); + +err: + return NULL; +} static dev_link_t *qlogic_attach(void) { scsi_info_t *info; @@ -238,18 +307,19 @@ outb(0x04, link->io.BasePort1 + 0xd); } - /* A bad hack... */ - release_region(link->io.BasePort1, link->io.NumPorts1); + qlogicfas_driver_template.name = qlogic_name; + qlogicfas_driver_template.proc_name = qlogic_name; /* The KXL-810AN has a bigger IO port window */ if (link->io.NumPorts1 == 32) - qlogicfas_preset(link->io.BasePort1 + 16, link->irq.AssignedIRQ); + host = qlogic_detect(&qlogicfas_driver_template, link, + link->io.BasePort1 + 16, link->irq.AssignedIRQ); else - qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); - - host = __qlogicfas_detect(&qlogicfas_driver_template); + host = qlogic_detect(&qlogicfas_driver_template, link, + link->io.BasePort1, link->irq.AssignedIRQ); + if (!host) { - printk(KERN_INFO "qlogic_cs: no SCSI devices found\n"); + printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); goto out; } @@ -257,16 +327,17 @@ link->dev = &info->node; info->host = host; - scsi_add_host(host, NULL); /* XXX handle failure */ - scsi_scan_host(host); - out: link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); - qlogic_release(link); + link->dev = NULL; + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + link->state &= ~DEV_CONFIG; return; } /* qlogic_config */ @@ -282,11 +353,13 @@ scsi_remove_host(info->host); link->dev = NULL; + free_irq(link->irq.AssignedIRQ, info->host); + pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); - scsi_unregister(info->host); + scsi_host_put(info->host); link->state &= ~DEV_CONFIG; } @@ -340,7 +413,7 @@ static struct pcmcia_driver qlogic_cs_driver = { .owner = THIS_MODULE, .drv = { - .name = "qlogic_cs", + .name = "qlogic_cs", }, .attach = qlogic_attach, .detach = qlogic_detach, @@ -360,5 +433,8 @@ qlogic_detach(dev_list); } +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); module_init(init_qlogic_cs); module_exit(exit_qlogic_cs); diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c --- a/drivers/scsi/qlogicfas.c Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/qlogicfas.c Sat Apr 3 19:38:56 2004 @@ -27,7 +27,6 @@ SCSI driver cleanup and audit. This driver still needs work on the following - Non terminating hardware waits - - Support multiple cards at a time - Some layering violations with its pcmcia stub Redistributable under terms of the GNU General Public License @@ -39,92 +38,6 @@ are deemed to be part of the source code. */ -/*----------------------------------------------------------------*/ -/* Configuration */ - -/* Set the following to 2 to use normal interrupt (active high/totempole- - tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - drain */ - -#define QL_INT_ACTIVE_HIGH 2 - -/* Set the following to 1 to enable the use of interrupts. Note that 0 tends - to be more stable, but slower (or ties up the system more) */ - -#define QL_USE_IRQ 1 - -/* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable. */ - -#define QL_TURBO_PDMA 1 - -/* This should be 1 to enable parity detection */ - -#define QL_ENABLE_PARITY 1 - -/* This will reset all devices when the driver is initialized (during bootup). - The other linux drivers don't do this, but the DOS drivers do, and after - using DOS or some kind of crash or lockup this will bring things back - without requiring a cold boot. It does take some time to recover from a - reset, so it is slower, and I have seen timeouts so that devices weren't - recognized when this was set. */ - -#define QL_RESET_AT_START 0 - -/* crystal frequency in megahertz (for offset 5 and 9) - Please set this for your card. Most Qlogic cards are 40 Mhz. The - Control Concepts ISA (not VLB) is 24 Mhz */ - -#define XTALFREQ 40 - -/**********/ -/* DANGER! modify these at your own risk */ -/* SLOWCABLE can usually be reset to zero if you have a clean setup and - proper termination. The rest are for synchronous transfers and other - advanced features if your device can transfer faster than 5Mb/sec. - If you are really curious, email me for a quick howto until I have - something official */ -/**********/ - -/*****/ -/* config register 1 (offset 8) options */ -/* This needs to be set to 1 if your cabling is long or noisy */ -#define SLOWCABLE 1 - -/*****/ -/* offset 0xc */ -/* This will set fast (10Mhz) synchronous timing when set to 1 - For this to have an effect, FASTCLK must also be 1 */ -#define FASTSCSI 0 - -/* This when set to 1 will set a faster sync transfer rate */ -#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ - -/*****/ -/* offset 6 */ -/* This is the sync transfer divisor, XTALFREQ/X will be the maximum - achievable data rate (assuming the rest of the system is capable - and set properly) */ -#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ - -/*****/ -/* offset 7 */ -/* This is the count of how many synchronous transfers can take place - i.e. how many reqs can occur before an ack is given. - The maximum value for this is 15, the upper bits can modify - REQ/ACK assertion and deassertion during synchronous transfers - If this is 0, the bus will only transfer asynchronously */ -#define SYNCOFFST 0 -/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles - of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will - cause the deassertion to be early by 1/2 clock. Bits 5&4 control - the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ - -/*----------------------------------------------------------------*/ -#ifdef PCMCIA -#undef QL_INT_ACTIVE_HIGH -#define QL_INT_ACTIVE_HIGH 0 -#endif #include #include /* to get disk capacity */ @@ -144,42 +57,21 @@ #include "scsi.h" #include "hosts.h" +#include "qlogicfas.h" /*----------------------------------------------------------------*/ -/* driver state info, local to driver */ -static int qbase; /* Port */ -static int qinitid; /* initiator ID */ -static int qabort; /* Flag to cause an abort */ -static int qlirq = -1; /* IRQ being used */ -static char qinfo[80]; /* description */ -static Scsi_Cmnd *qlcmd; /* current command being processed */ - -static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ -static int qlcfg6 = SYNCXFRPD; -static int qlcfg7 = SYNCOFFST; -static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); -static int qlcfg9 = ((XTALFREQ + 4) / 5); -static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); - -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ +int qlcfg6 = SYNCXFRPD; +int qlcfg7 = SYNCOFFST; +int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); +int qlcfg9 = ((XTALFREQ + 4) / 5); +int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); -/*----------------------------------------------------------------*/ -/* The qlogic card uses two register maps - These macros select which one */ -#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) +static char qlogicfas_name[] = "qlogicfas"; -/* following is watchdog timeout in microseconds */ -#define WATCHDOG 5000000 +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); /*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at and as a simple profiler) */ - -#if 0 -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif /*----------------------------------------------------------------*/ /* local functions */ @@ -187,9 +79,10 @@ /* error recovery - reset everything */ -static void ql_zap(void) +static void ql_zap(qlogicfas_priv_t priv) { int x; + int qbase = priv->qbase; x = inb(qbase + 0xd); REG0; @@ -203,9 +96,10 @@ * Do a pseudo-dma tranfer */ -static int ql_pdma(int phase, char *request, int reqlen) +static int ql_pdma(qlogicfas_priv_t priv, int phase, char *request, int reqlen) { int j; + int qbase = priv->qbase; j = 0; if (phase & 1) { /* in */ #if QL_TURBO_PDMA @@ -287,23 +181,25 @@ * Wait for interrupt flag (polled - not real hardware interrupt) */ -static int ql_wai(void) +static int ql_wai(qlogicfas_priv_t priv) { int k; + int qbase = priv->qbase; unsigned long i; k = 0; i = jiffies + WATCHDOG; - while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) { + while (time_before(jiffies, i) && !priv->qabort && + !((k = inb(qbase + 4)) & 0xe0)) { barrier(); cpu_relax(); } if (time_after_eq(jiffies, i)) return (DID_TIME_OUT); - if (qabort) - return (qabort == 1 ? DID_ABORT : DID_RESET); + if (priv->qabort) + return (priv->qabort == 1 ? DID_ABORT : DID_RESET); if (k & 0x60) - ql_zap(); + ql_zap(priv); if (k & 0x20) return (DID_PARITY); if (k & 0x40) @@ -318,9 +214,11 @@ static void ql_icmd(Scsi_Cmnd * cmd) { + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + int qbase = priv->qbase; unsigned int i; - qabort = 0; + priv->qabort = 0; REG0; /* clearing of interrupts and the fifo is needed */ @@ -341,7 +239,7 @@ /* configurables */ outb(qlcfgc, qbase + 0xc); /* config: no reset interrupt, (initiator) bus id */ - outb(0x40 | qlcfg8 | qinitid, qbase + 8); + outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); outb(qlcfg7, qbase + 7); outb(qlcfg6, qbase + 6); /**/ outb(qlcfg5, qbase + 5); /* select timer */ @@ -352,7 +250,7 @@ for (i = 0; i < cmd->cmd_len; i++) outb(cmd->cmnd[i], qbase + 2); - qlcmd = cmd; + priv->qlcmd = cmd; outb(0x41, qbase + 3); /* select and send command */ } @@ -372,6 +270,8 @@ struct scatterlist *sglist; /* scatter-gather list pointer */ unsigned int sgcount; /* sg counter */ char *buf; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + int qbase = priv->qbase; rtrc(1) j = inb(qbase + 6); @@ -382,7 +282,7 @@ i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ if (i != 0x18) { printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); - ql_zap(); + ql_zap(priv); return (DID_BAD_INTR << 16); } j &= 7; /* j = inb( qbase + 7 ) >> 5; */ @@ -395,7 +295,7 @@ if (j != 3 && j != 4) { printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb(qbase + 7) & 0x1f); - ql_zap(); + ql_zap(priv); return (DID_ERROR << 16); } result = DID_OK; @@ -413,18 +313,19 @@ /* PIO pseudo DMA to buffer or sglist */ REG1; if (!cmd->use_sg) - ql_pdma(phase, cmd->request_buffer, + ql_pdma(priv, phase, cmd->request_buffer, cmd->request_bufflen); else { sgcount = cmd->use_sg; sglist = cmd->request_buffer; while (sgcount--) { - if (qabort) { + if (priv->qabort) { REG0; - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + return ((priv->qabort == 1 ? + DID_ABORT : DID_RESET) << 16); } buf = page_address(sglist->page) + sglist->offset; - if (ql_pdma(phase, buf, sglist->length)) + if (ql_pdma(priv, phase, buf, sglist->length)) break; sglist++; } @@ -435,7 +336,7 @@ * Wait for irq (split into second state of irq handler * if this can take time) */ - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); k = inb(qbase + 5); /* should be 0x10, bus service */ } @@ -446,11 +347,12 @@ k = jiffies + WATCHDOG; - while (time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6)) + while (time_before(jiffies, k) && !priv->qabort && + !(inb(qbase + 4) & 6)) cpu_relax(); /* wait for status phase */ if (time_after_eq(jiffies, k)) { - ql_zap(); + ql_zap(priv); return (DID_TIME_OUT << 16); } @@ -458,11 +360,11 @@ while (inb(qbase + 5)) cpu_relax(); /* clear pending ints */ - if (qabort) - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); outb(0x11, qbase + 3); /* get status and message */ - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); i = inb(qbase + 5); /* get chip irq stat */ j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ @@ -479,7 +381,7 @@ } outb(0x12, qbase + 3); /* done, disconnect */ rtrc(1) - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); /* @@ -487,21 +389,19 @@ */ i = inb(qbase + 5); /* should be bus service */ - while (!qabort && ((i & 0x20) != 0x20)) { + while (!priv->qabort && ((i & 0x20) != 0x20)) { barrier(); cpu_relax(); i |= inb(qbase + 5); } rtrc(0) - if (qabort) - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); return (result << 16) | (message << 8) | (status & STATUS_MASK); } -#if QL_USE_IRQ - /* * Interrupt handler */ @@ -509,20 +409,23 @@ static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd *icmd; + struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); + int qbase = priv->qbase; REG0; if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ return; - if (qlcmd == NULL) { /* no command to process? */ + if (priv->qlcmd == NULL) { /* no command to process? */ int i; i = 16; while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ return; } - icmd = qlcmd; + icmd = priv->qlcmd; icmd->result = ql_pcmd(icmd); - qlcmd = NULL; + priv->qlcmd = NULL; /* * If result is CHECK CONDITION done calls qcommand to request * sense @@ -530,7 +433,7 @@ (icmd->scsi_done) (icmd); } -static irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; struct Scsi_Host *host = dev_id; @@ -541,17 +444,14 @@ return IRQ_HANDLED; } -#endif - -#if QL_USE_IRQ - /* * Queued command */ int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { - if (cmd->device->id == qinitid) { + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + if (cmd->device->id == priv->qinitid) { cmd->result = DID_BAD_TARGET << 16; done(cmd); return 0; @@ -559,44 +459,27 @@ cmd->scsi_done = done; /* wait for the last command's interrupt to finish */ - while (qlcmd != NULL) { + while (priv->qlcmd != NULL) { barrier(); cpu_relax(); } ql_icmd(cmd); return 0; } -#else -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - return 1; -} -#endif - -#ifdef PCMCIA - -/* - * Allow PCMCIA code to preset the port - * port should be 0 and irq to -1 respectively for autoprobing - */ - -void qlogicfas_preset(int port, int irq) -{ - qbase = port; - qlirq = irq; -} - -#endif +#ifndef PCMCIA /* * Look for qlogic card and init if found */ -struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host) +struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, int qbase, + int qlirq) { int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ + int qinitid; struct Scsi_Host *hreg; /* registered host structure */ + qlogicfas_priv_t priv; /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself * decodes the address - I check 230 first since MIDI cards are @@ -609,7 +492,7 @@ if (!qbase) { for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { - if (!request_region(qbase, 0x10, "qlogicfas")) + if (!request_region(qbase, 0x10, qlogicfas_name)) continue; REG1; if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) @@ -618,7 +501,7 @@ release_region(qbase, 0x10); } if (qbase == 0x430) - return NULL;; + return NULL; } else printk(KERN_INFO "Ql: Using preset base address of %03x\n", qbase); @@ -641,7 +524,6 @@ REG0; #endif -#if QL_USE_IRQ /* * IRQ probe - toggle pin and check request pending */ @@ -668,49 +550,98 @@ } else printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq); - if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL)) - host->can_queue = 1; -#endif - hreg = scsi_register(host, 0); /* no host data */ + hreg = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); if (!hreg) goto err_release_mem; + priv = (qlogicfas_priv_t)&(hreg->hostdata[0]); hreg->io_port = qbase; hreg->n_io_port = 16; hreg->dma_channel = -1; if (qlirq != -1) hreg->irq = qlirq; + priv->qbase = qbase; + priv->qlirq = qlirq; + priv->qinitid = qinitid; + priv->shost = hreg; - sprintf(qinfo, + sprintf(priv->qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", qltyp, qbase, qlirq, QL_TURBO_PDMA); - host->name = qinfo; + host->name = qlogicfas_name; + + if (request_irq(qlirq, do_ql_ihandl, 0, qlogicfas_name, hreg)) + goto free_scsi_host; + + if (scsi_add_host(hreg, NULL)) + goto free_interrupt; + + scsi_scan_host(hreg); return hreg; +free_interrupt: + free_irq(qlirq, hreg); + +free_scsi_host: + scsi_host_put(hreg); + err_release_mem: release_region(qbase, 0x10); - if (host->can_queue) - free_irq(qlirq, do_ql_ihandl); - return NULL;; - + return NULL; } +#define MAX_QLOGICFAS 8 +static qlogicfas_priv_t cards; +static int iobase[MAX_QLOGICFAS]; +static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 }; +MODULE_PARM(iobase, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i"); +MODULE_PARM_DESC(iobase, "I/O address"); +MODULE_PARM_DESC(irq, "IRQ"); + int __devinit qlogicfas_detect(Scsi_Host_Template *sht) { - return (__qlogicfas_detect(sht) != NULL); + struct Scsi_Host *shost; + qlogicfas_priv_t priv; + int i, + num = 0; + + for (i = 0; i < MAX_QLOGICFAS; i++) { + shost = __qlogicfas_detect(sht, iobase[num], irq[num]); + if (shost == NULL) { + /* no more devices */ + break; + } + priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv->next = cards; + cards = priv; + num++; + } + + return num; } static int qlogicfas_release(struct Scsi_Host *shost) { - if (shost->irq) - free_irq(shost->irq, NULL); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + int qbase = priv->qbase; + + if (shost->irq) { + REG1; + outb(0, qbase + 0xb); /* disable ints */ + + free_irq(shost->irq, shost); + } if (shost->dma_channel != 0xff) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); + scsi_remove_host(shost); + scsi_host_put(shost); + return 0; } +#endif /* ifndef PCMCIA */ /* * Return bios parameters @@ -742,8 +673,9 @@ static int qlogicfas_abort(Scsi_Cmnd * cmd) { - qabort = 1; - ql_zap(); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + priv->qabort = 1; + ql_zap(priv); return SUCCESS; } @@ -755,8 +687,9 @@ int qlogicfas_bus_reset(Scsi_Cmnd * cmd) { - qabort = 2; - ql_zap(); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + priv->qabort = 2; + ql_zap(priv); return SUCCESS; } @@ -784,22 +717,17 @@ static const char *qlogicfas_info(struct Scsi_Host *host) { - return qinfo; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); + return priv->qinfo; } -MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); -MODULE_LICENSE("GPL"); - /* * The driver template is also needed for PCMCIA */ Scsi_Host_Template qlogicfas_driver_template = { .module = THIS_MODULE, - .name = "qlogicfas", - .proc_name = "qlogicfas", - .detect = qlogicfas_detect, - .release = qlogicfas_release, + .name = qlogicfas_name, + .proc_name = qlogicfas_name, .info = qlogicfas_info, .queuecommand = qlogicfas_queuecommand, .eh_abort_handler = qlogicfas_abort, @@ -807,7 +735,7 @@ .eh_device_reset_handler= qlogicfas_device_reset, .eh_host_reset_handler = qlogicfas_host_reset, .bios_param = qlogicfas_biosparam, - .can_queue = 0, + .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, @@ -815,6 +743,28 @@ }; #ifndef PCMCIA -#define driver_template qlogicfas_driver_template -#include "scsi_module.c" -#endif +static __init int qlogicfas_init(void) +{ + if (!qlogicfas_detect(&qlogicfas_driver_template)) { + /* no cards found */ + return -ENODEV; + } + + return 0; +} + +static __exit void qlogicfas_exit(void) +{ + qlogicfas_priv_t priv; + + for (priv = cards; priv != NULL; priv = priv->next) + qlogicfas_release(priv->shost); +} + +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); +module_init(qlogicfas_init); +module_exit(qlogicfas_exit); +#endif /* ifndef PCMCIA */ + diff -Nru a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/qlogicfas.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,124 @@ +/* to be used by qlogicfas and qlogic_cs */ +#ifndef __QLOGICFAS_H +#define __QLOGICFAS_H + +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to 2 to use normal interrupt (active high/totempole- + tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + drain */ + +#define QL_INT_ACTIVE_HIGH 2 + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable. */ + +#define QL_TURBO_PDMA 1 + +/* This should be 1 to enable parity detection */ + +#define QL_ENABLE_PARITY 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back + without requiring a cold boot. It does take some time to recover from a + reset, so it is slower, and I have seen timeouts so that devices weren't + recognized when this was set. */ + +#define QL_RESET_AT_START 0 + +/* crystal frequency in megahertz (for offset 5 and 9) + Please set this for your card. Most Qlogic cards are 40 Mhz. The + Control Concepts ISA (not VLB) is 24 Mhz */ + +#define XTALFREQ 40 + +/**********/ +/* DANGER! modify these at your own risk */ +/* SLOWCABLE can usually be reset to zero if you have a clean setup and + proper termination. The rest are for synchronous transfers and other + advanced features if your device can transfer faster than 5Mb/sec. + If you are really curious, email me for a quick howto until I have + something official */ +/**********/ + +/*****/ +/* config register 1 (offset 8) options */ +/* This needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 1 + +/*****/ +/* offset 0xc */ +/* This will set fast (10Mhz) synchronous timing when set to 1 + For this to have an effect, FASTCLK must also be 1 */ +#define FASTSCSI 0 + +/* This when set to 1 will set a faster sync transfer rate */ +#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ + +/*****/ +/* offset 6 */ +/* This is the sync transfer divisor, XTALFREQ/X will be the maximum + achievable data rate (assuming the rest of the system is capable + and set properly) */ +#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ + +/*****/ +/* offset 7 */ +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ +#ifdef PCMCIA +#undef QL_INT_ACTIVE_HIGH +#define QL_INT_ACTIVE_HIGH 0 +#endif + +struct qlogicfas_priv; +typedef struct qlogicfas_priv *qlogicfas_priv_t; +struct qlogicfas_priv { + int qbase; /* Port */ + int qinitid; /* initiator ID */ + int qabort; /* Flag to cause an abort */ + int qlirq; /* IRQ being used */ + char qinfo[80]; /* description */ + Scsi_Cmnd *qlcmd; /* current command being processed */ + struct Scsi_Host *shost; /* pointer back to host */ + qlogicfas_priv_t next; /* next private struct */ +}; + +extern int qlcfg5; +extern int qlcfg6; +extern int qlcfg7; +extern int qlcfg8; +extern int qlcfg9; +extern int qlcfgc; + +/* The qlogic card uses two register maps - These macros select which one */ +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) + +/* following is watchdog timeout in microseconds */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#if 0 +#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} +#else +#define rtrc(i) {} +#endif +#endif /* __QLOGICFAS_H */ + diff -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c --- a/drivers/scsi/qlogicfc.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/qlogicfc.c Sat Apr 3 19:38:54 2004 @@ -1778,7 +1778,7 @@ LEAVE("isp2x00_reset"); - return return_status;; + return return_status; } diff -Nru a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c --- a/drivers/scsi/qlogicisp.c Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/qlogicisp.c Sat Apr 3 19:38:56 2004 @@ -1230,7 +1230,7 @@ LEAVE("isp1020_reset"); - return return_status;; + return return_status; } diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/sata_promise.c Sat Apr 3 19:38:54 2004 @@ -21,7 +21,6 @@ * */ -#include #include #include #include @@ -146,10 +145,6 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void pdc_dma_start(struct ata_queued_cmd *qc); static void pdc20621_dma_start(struct ata_queued_cmd *qc); @@ -200,14 +195,11 @@ static struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_sata_set_piomode, - .set_udmamode = pdc_sata_set_udmamode, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, .phy_reset = sata_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ .bmdma_start = pdc_dma_start, .fill_sg = pdc_fill_sg, .eng_timeout = pdc_eng_timeout, @@ -220,14 +212,11 @@ static struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_sata_set_piomode, - .set_udmamode = pdc_sata_set_udmamode, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, .phy_reset = pdc_20621_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ .bmdma_start = pdc20621_dma_start, .fill_sg = pdc20621_fill_sg, .eng_timeout = pdc_eng_timeout, @@ -378,19 +367,6 @@ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* dummy */ -} - - -static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* dummy */ -} - enum pdc_packet_bits { PDC_PKT_READ = (1 << 2), PDC_PKT_NODATA = (1 << 3), @@ -1172,13 +1148,16 @@ { port->cmd_addr = base; port->data_addr = base; + port->feature_addr = port->error_addr = base + 0x4; port->nsect_addr = base + 0x8; port->lbal_addr = base + 0xc; port->lbam_addr = base + 0x10; port->lbah_addr = base + 0x14; port->device_addr = base + 0x18; - port->cmdstat_addr = base + 0x1c; + port->command_addr = + port->status_addr = base + 0x1c; + port->altstatus_addr = port->ctl_addr = base + 0x38; } @@ -1690,6 +1669,9 @@ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -1809,13 +1791,7 @@ static int __init pdc_sata_init(void) { - int rc; - - rc = pci_module_init(&pdc_sata_pci_driver); - if (rc) - return rc; - - return 0; + return pci_module_init(&pdc_sata_pci_driver); } diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/sata_sil.c Sat Apr 3 19:38:40 2004 @@ -22,7 +22,6 @@ * */ -#include #include #include #include @@ -35,7 +34,7 @@ #include #define DRV_NAME "sata_sil" -#define DRV_VERSION "0.53" +#define DRV_VERSION "0.54" enum { sil_3112 = 0, @@ -50,39 +49,18 @@ SIL_MASK_4PORT = SIL_MASK_2PORT | SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT, - SIL_IDE0_TF = 0x80, - SIL_IDE0_CTL = 0x8A, - SIL_IDE0_BMDMA = 0x00, - SIL_IDE0_SCR = 0x100, - - SIL_IDE1_TF = 0xC0, - SIL_IDE1_CTL = 0xCA, - SIL_IDE1_BMDMA = 0x08, - SIL_IDE1_SCR = 0x180, - - SIL_IDE2_TF = 0x280, - SIL_IDE2_CTL = 0x28A, SIL_IDE2_BMDMA = 0x200, - SIL_IDE2_SCR = 0x300, - SIL_INTR_STEERING = (1 << 1), - - SIL_IDE3_TF = 0x2C0, - SIL_IDE3_CTL = 0x2CA, - SIL_IDE3_BMDMA = 0x208, - SIL_IDE3_SCR = 0x380, + SIL_INTR_STEERING = (1 << 1), SIL_QUIRK_MOD15WRITE = (1 << 0), SIL_QUIRK_UDMA5MAX = (1 << 1), }; -static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void sil_post_set_mode (struct ata_port *ap); static struct pci_device_id sil_pci_tbl[] = { { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, @@ -141,14 +119,12 @@ static struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, - .set_piomode = sil_set_piomode, - .set_udmamode = sil_set_udmamode, .tf_load = ata_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, .exec_command = ata_exec_command_mmio, .phy_reset = sata_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ + .post_set_mode = sil_post_set_mode, .bmdma_start = ata_bmdma_start_mmio, .fill_sg = ata_fill_sg, .eng_timeout = ata_eng_timeout, @@ -166,7 +142,7 @@ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6; FIXME */ + .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ { @@ -174,16 +150,61 @@ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6; FIXME */ + .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, }; +/* per-port register offsets */ +/* TODO: we can probably calculate rather than use a table */ +static const struct { + unsigned long tf; /* ATA taskfile register block */ + unsigned long ctl; /* ATA control/altstatus register block */ + unsigned long bmdma; /* DMA register block */ + unsigned long scr; /* SATA control register block */ + unsigned long sien; /* SATA Interrupt Enable register */ + unsigned long xfer_mode;/* data transfer mode register */ +} sil_port[] = { + /* port 0 ... */ + { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 }, + { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 }, + { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 }, + { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 }, + /* ... port 3 */ +}; + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sil_pci_tbl); +static void sil_post_set_mode (struct ata_port *ap) +{ + struct ata_host_set *host_set = ap->host_set; + struct ata_device *dev; + void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode; + u32 tmp, dev_mode[2]; + unsigned int i; + + for (i = 0; i < 2; i++) { + dev = &ap->device[i]; + if (!ata_dev_present(dev)) + dev_mode[i] = 0; /* PIO0/1/2 */ + else if (dev->flags & ATA_DFLAG_PIO) + dev_mode[i] = 1; /* PIO3/4 */ + else + dev_mode[i] = 3; /* UDMA */ + /* value 2 indicates MDMA */ + } + + tmp = readl(addr); + tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0)); + tmp |= dev_mode[0]; + tmp |= (dev_mode[1] << 4); + writel(tmp, addr); + readl(addr); /* flush */ +} + static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) { unsigned long offset = ap->ioaddr.scr_addr; @@ -250,13 +271,9 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { unsigned int n, quirks = 0; - u32 class_rev = 0; const char *s = &dev->product[0]; unsigned int len = strnlen(s, sizeof(dev->product)); - pci_read_config_dword(ap->host_set->pdev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - /* ATAPI specifies that empty space is blank-filled; remove blanks */ while ((len > 0) && (s[len - 1] == ' ')) len--; @@ -269,7 +286,7 @@ } /* limit requests to 15 sectors */ - if ((class_rev <= 0x01) && (quirks & SIL_QUIRK_MOD15WRITE)) { + if (quirks & SIL_QUIRK_MOD15WRITE) { printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n", ap->id, dev->devno); ap->host->max_sectors = 15; @@ -278,7 +295,6 @@ } /* limit to udma5 */ - /* is this for (class_rev <= 0x01) only, too? */ if (quirks & SIL_QUIRK_UDMA5MAX) { printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n", ap->id, dev->devno, s); @@ -287,22 +303,6 @@ } } -static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - -static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -310,6 +310,7 @@ unsigned long base; void *mmio_base; int rc; + unsigned int i; u32 tmp, irq_mask; if (!printed_version++) @@ -330,6 +331,9 @@ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -359,31 +363,17 @@ probe_ent->mmio_base = mmio_base; base = (unsigned long) mmio_base; - probe_ent->port[0].cmd_addr = base + SIL_IDE0_TF; - probe_ent->port[0].ctl_addr = base + SIL_IDE0_CTL; - probe_ent->port[0].bmdma_addr = base + SIL_IDE0_BMDMA; - probe_ent->port[0].scr_addr = base + SIL_IDE0_SCR; - ata_std_ports(&probe_ent->port[0]); - - probe_ent->port[1].cmd_addr = base + SIL_IDE1_TF; - probe_ent->port[1].ctl_addr = base + SIL_IDE1_CTL; - probe_ent->port[1].bmdma_addr = base + SIL_IDE1_BMDMA; - probe_ent->port[1].scr_addr = base + SIL_IDE1_SCR; - ata_std_ports(&probe_ent->port[1]); - if (ent->driver_data == sil_3114) { - probe_ent->port[2].cmd_addr = base + SIL_IDE2_TF; - probe_ent->port[2].ctl_addr = base + SIL_IDE2_CTL; - probe_ent->port[2].bmdma_addr = base + SIL_IDE2_BMDMA; - probe_ent->port[2].scr_addr = base + SIL_IDE2_SCR; - ata_std_ports(&probe_ent->port[2]); - - probe_ent->port[3].cmd_addr = base + SIL_IDE3_TF; - probe_ent->port[3].ctl_addr = base + SIL_IDE3_CTL; - probe_ent->port[3].bmdma_addr = base + SIL_IDE3_BMDMA; - probe_ent->port[3].scr_addr = base + SIL_IDE3_SCR; - ata_std_ports(&probe_ent->port[3]); + for (i = 0; i < probe_ent->n_ports; i++) { + probe_ent->port[i].cmd_addr = base + sil_port[i].tf; + probe_ent->port[i].altstatus_addr = + probe_ent->port[i].ctl_addr = base + sil_port[i].ctl; + probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma; + probe_ent->port[i].scr_addr = base + sil_port[i].scr; + ata_std_ports(&probe_ent->port[i]); + } + if (ent->driver_data == sil_3114) { irq_mask = SIL_MASK_4PORT; /* flip the magic "make 4 ports work" bit */ @@ -404,6 +394,11 @@ readl(mmio_base + SIL_SYSCFG); /* flush */ } + /* mask all SATA phy-related interrupts */ + /* TODO: unmask bit 6 (SError N bit) for hotplug */ + for (i = 0; i < probe_ent->n_ports; i++) + writel(0, mmio_base + sil_port[i].sien); + pci_set_master(pdev); /* FIXME: check ata_device_add return value */ @@ -423,13 +418,7 @@ static int __init sil_init(void) { - int rc; - - rc = pci_module_init(&sil_pci_driver); - if (rc) - return rc; - - return 0; + return pci_module_init(&sil_pci_driver); } static void __exit sil_exit(void) diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c Sat Apr 3 19:38:44 2004 +++ b/drivers/scsi/sata_svw.c Sat Apr 3 19:38:44 2004 @@ -103,13 +103,13 @@ ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr); + writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, ioaddr->error_addr); + writew(tf->feature, ioaddr->feature_addr); writew(tf->nsect, ioaddr->nsect_addr); writew(tf->lbal, ioaddr->lbal_addr); writew(tf->lbam, ioaddr->lbam_addr); @@ -146,27 +146,9 @@ static u8 k2_stat_check_status(struct ata_port *ap) { - return readl((void *) ap->ioaddr.cmdstat_addr); + return readl((void *) ap->ioaddr.status_addr); } -static void k2_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - - -static void k2_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - - #ifdef CONFIG_PPC_OF /* * k2_sata_proc_info @@ -239,14 +221,11 @@ static struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = k2_sata_set_piomode, - .set_udmamode = k2_sata_set_udmamode, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, .exec_command = ata_exec_command_mmio, .phy_reset = sata_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ .bmdma_start = ata_bmdma_start_mmio, .fill_sg = ata_fill_sg, .eng_timeout = ata_eng_timeout, @@ -261,13 +240,16 @@ { port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; port->data_addr = base + K2_SATA_TF_DATA_OFFSET; + port->feature_addr = port->error_addr = base + K2_SATA_TF_ERROR_OFFSET; port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET; port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET; port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET; port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET; port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET; - port->cmdstat_addr = base + K2_SATA_TF_CMDSTAT_OFFSET; + port->command_addr = + port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET; + port->altstatus_addr = port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET; port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET; port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET; @@ -307,6 +289,9 @@ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -350,7 +335,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x3f; + probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ k2_sata_setup_port(&probe_ent->port[0], base + 0 * K2_SATA_PORT_OFFSET); @@ -392,15 +377,8 @@ static int __init k2_sata_init(void) { - int rc; - - rc = pci_module_init(&k2_sata_pci_driver); - if (rc) - return rc; - - return 0; + return pci_module_init(&k2_sata_pci_driver); } - static void __exit k2_sata_exit(void) { diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/sata_via.c Sat Apr 3 19:38:41 2004 @@ -22,7 +22,6 @@ */ -#include #include #include #include @@ -32,23 +31,35 @@ #include "scsi.h" #include "hosts.h" #include +#include #define DRV_NAME "sata_via" -#define DRV_VERSION "0.11" +#define DRV_VERSION "0.20" enum { via_sata = 0, + + SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ + SATA_INT_GATE = 0x41, /* SATA interrupt gating */ + SATA_NATIVE_MODE = 0x42, /* Native mode enable */ + SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ + + PORT0 = (1 << 1), + PORT1 = (1 << 0), + + ENAB_ALL = PORT0 | PORT1, + + INT_GATE_ALL = PORT0 | PORT1, + + NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), + + SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ + SATA_2DEV = (1 << 5), /* SATA is master/slave */ }; static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void svia_sata_phy_reset(struct ata_port *ap); -static void svia_port_disable(struct ata_port *ap); -static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); - -static unsigned int in_module_init = 1; +static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static struct pci_device_id svia_pci_tbl[] = { { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata }, @@ -82,17 +93,14 @@ }; static struct ata_port_operations svia_sata_ops = { - .port_disable = svia_port_disable, - .set_piomode = svia_set_piomode, - .set_udmamode = svia_set_udmamode, + .port_disable = ata_port_disable, .tf_load = ata_tf_load_pio, .tf_read = ata_tf_read_pio, .check_status = ata_check_status_pio, .exec_command = ata_exec_command_pio, - .phy_reset = svia_sata_phy_reset, - .phy_config = pata_phy_config, /* not a typo */ + .phy_reset = sata_phy_reset, .bmdma_start = ata_bmdma_start_pio, .fill_sg = ata_fill_sg, @@ -100,102 +108,39 @@ .irq_handler = ata_interrupt, + .scr_read = svia_scr_read, + .scr_write = svia_scr_write, + .port_start = ata_port_start, .port_stop = ata_port_stop, }; -static struct ata_port_info svia_port_info[] = { - /* via_sata */ - { - .sht = &svia_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY - | ATA_FLAG_SRST, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &svia_sata_ops, - }, -}; - -static struct pci_bits svia_enable_bits[] = { - { 0x40U, 1U, 0x02UL, 0x02UL }, /* port 0 */ - { 0x40U, 1U, 0x01UL, 0x01UL }, /* port 1 */ -}; - - MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, svia_pci_tbl); -/** - * svia_sata_phy_reset - - * @ap: - * - * LOCKING: - * - */ - -static void svia_sata_phy_reset(struct ata_port *ap) +static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg) { - if (!pci_test_config_bits(ap->host_set->pdev, - &svia_enable_bits[ap->port_no])) { - ata_port_disable(ap); - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); - return; - } - - ata_port_probe(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; - - ata_bus_reset(ap); + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + return inl(ap->ioaddr.scr_addr + (4 * sc_reg)); } -/** - * svia_port_disable - - * @ap: - * - * LOCKING: - * - */ - -static void svia_port_disable(struct ata_port *ap) +static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - ata_port_disable(ap); - - /* FIXME */ -} - -/** - * svia_set_piomode - - * @ap: - * @adev: - * @pio: - * - * LOCKING: - * - */ - -static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* FIXME: needed? */ + if (sc_reg > SCR_CONTROL) + return; + outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } -/** - * svia_set_udmamode - - * @ap: - * @adev: - * @udma: - * - * LOCKING: - * - */ +static const unsigned int svia_bar_sizes[] = { + 8, 4, 8, 4, 16, 256 +}; -static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) +static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) { - /* FIXME: needed? */ + return addr + (port * 128); } /** @@ -212,19 +157,131 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info *port_info[1]; - unsigned int n_ports = 1; + unsigned int i; + int rc; + struct ata_probe_ent *probe_ent; + u8 tmp8; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); - /* no hotplugging support (FIXME) */ - if (!in_module_init) - return -ENODEV; + rc = pci_enable_device(pdev); + if (rc) + return rc; - port_info[0] = &svia_port_info[ent->driver_data]; + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); + if (tmp8 & SATA_2DEV) { + printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", + pci_name(pdev), (int) tmp8); + rc = -EIO; + goto err_out_regions; + } + + for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) + if ((pci_resource_start(pdev, i) == 0) || + (pci_resource_len(pdev, i) < svia_bar_sizes[i])) { + printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", + pci_name(pdev), i, + pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + rc = -ENODEV; + goto err_out_regions; + } + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; - return ata_pci_init_one(pdev, port_info, n_ports); + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) { + printk(KERN_ERR DRV_NAME "(%s): out of memory\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_regions; + } + memset(probe_ent, 0, sizeof(*probe_ent)); + INIT_LIST_HEAD(&probe_ent->node); + probe_ent->pdev = pdev; + probe_ent->sht = &svia_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &svia_sata_ops; + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->port[0].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 0); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + probe_ent->port[1].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 1); + + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); + printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", + pci_name(pdev), + (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); + + /* make sure SATA channels are enabled */ + pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); + if ((tmp8 & ENAB_ALL) != ENAB_ALL) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= ENAB_ALL; + pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); + } + + /* make sure interrupts for each channel sent to us */ + pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); + if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= INT_GATE_ALL; + pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); + } + + /* make sure native mode is enabled */ + pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); + if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= NATIVE_MODE_ALL; + pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); + } + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; } /** @@ -238,17 +295,7 @@ static int __init svia_init(void) { - int rc; - - DPRINTK("pci_module_init\n"); - rc = pci_module_init(&svia_pci_driver); - if (rc) - return rc; - - in_module_init = 0; - - DPRINTK("done\n"); - return 0; + return pci_module_init(&svia_pci_driver); } /** diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sata_vsc.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,376 @@ +/* + * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA + * + * Copyright 2004 SGI + * + * Bits from Jeff Garzik, Copyright RedHat, Inc. + * + * 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 "scsi.h" +#include "hosts.h" +#include + +#define DRV_NAME "sata_vsc" +#define DRV_VERSION "0.01" + +/* Interrupt register offsets (from chip base address) */ +#define VSC_SATA_INT_STAT_OFFSET 0x00 +#define VSC_SATA_INT_MASK_OFFSET 0x04 + +/* Taskfile registers offsets */ +#define VSC_SATA_TF_CMD_OFFSET 0x00 +#define VSC_SATA_TF_DATA_OFFSET 0x00 +#define VSC_SATA_TF_ERROR_OFFSET 0x04 +#define VSC_SATA_TF_FEATURE_OFFSET 0x06 +#define VSC_SATA_TF_NSECT_OFFSET 0x08 +#define VSC_SATA_TF_LBAL_OFFSET 0x0c +#define VSC_SATA_TF_LBAM_OFFSET 0x10 +#define VSC_SATA_TF_LBAH_OFFSET 0x14 +#define VSC_SATA_TF_DEVICE_OFFSET 0x18 +#define VSC_SATA_TF_STATUS_OFFSET 0x1c +#define VSC_SATA_TF_COMMAND_OFFSET 0x1d +#define VSC_SATA_TF_ALTSTATUS_OFFSET 0x28 +#define VSC_SATA_TF_CTL_OFFSET 0x29 + +/* DMA base */ +#define VSC_SATA_DMA_CMD_OFFSET 0x70 + +/* SCRs base */ +#define VSC_SATA_SCR_STATUS_OFFSET 0x100 +#define VSC_SATA_SCR_ERROR_OFFSET 0x104 +#define VSC_SATA_SCR_CONTROL_OFFSET 0x108 + +/* Port stride */ +#define VSC_SATA_PORT_OFFSET 0x200 + + +static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); +} + + +static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, + u32 val) +{ + if (sc_reg > SCR_CONTROL) + return; + writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); +} + + +static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) +{ + unsigned long mask_addr; + u8 mask; + + mask_addr = (unsigned long) ap->host_set->mmio_base + + VSC_SATA_INT_MASK_OFFSET + ap->port_no; + mask = readb(mask_addr); + if (ctl & ATA_NIEN) + mask |= 0x80; + else + mask &= 0x7F; + writeb(mask, mask_addr); +} + + +static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + /* + * The only thing the ctl register is used for is SRST. + * That is not enabled or disabled via tf_load. + * However, if ATA_NIEN is changed, then we need to change the interrupt register. + */ + if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) { + ap->last_ctl = tf->ctl; + vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN); + } + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); + writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); + writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); + writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); + writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); + } else if (is_addr) { + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + + +static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u16 nsect, lbal, lbam, lbah; + + nsect = tf->nsect = readw(ioaddr->nsect_addr); + lbal = tf->lbal = readw(ioaddr->lbal_addr); + lbam = tf->lbam = readw(ioaddr->lbam_addr); + lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = nsect >> 8; + tf->hob_lbal = lbal >> 8; + tf->hob_lbam = lbam >> 8; + tf->hob_lbah = lbah >> 8; + } +} + + +/* + * vsc_sata_interrupt + * + * Read the interrupt register and process for the devices that have them pending. + */ +irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int i; + unsigned int handled = 0; + u32 int_status; + + spin_lock(&host_set->lock); + + int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET); + + for (i = 0; i < host_set->n_ports; i++) { + if (int_status & ((u32) 0xFF << (8 * i))) { + struct ata_port *ap; + + ap = host_set->ports[i]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0)) + handled += ata_host_intr(ap, qc); + } + } + } + + spin_unlock(&host_set->lock); + + return IRQ_RETVAL(handled); +} + + +static Scsi_Host_Template vsc_sata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + + +static struct ata_port_operations vsc_sata_ops = { + .port_disable = ata_port_disable, + .tf_load = vsc_sata_tf_load, + .tf_read = vsc_sata_tf_read, + .exec_command = ata_exec_command_mmio, + .check_status = ata_check_status_mmio, + .phy_reset = sata_phy_reset, + .bmdma_start = ata_bmdma_start_mmio, + .fill_sg = ata_fill_sg, + .eng_timeout = ata_eng_timeout, + .irq_handler = vsc_sata_interrupt, + .scr_read = vsc_sata_scr_read, + .scr_write = vsc_sata_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET; + port->data_addr = base + VSC_SATA_TF_DATA_OFFSET; + port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET; + port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET; + port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET; + port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET; + port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET; + port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET; + port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET; + port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET; + port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET; + port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET; + port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET; + port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET; + port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET; +} + + +static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + unsigned long base; + void *mmio_base; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + /* + * Check if we have needed resource mapped. + */ + if (pci_resource_len(pdev, 0) == 0) { + rc = -ENODEV; + goto err_out; + } + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + /* + * Use 32 bit DMA mask, because 64 bit address support is poor. + */ + rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->pdev = pdev; + INIT_LIST_HEAD(&probe_ent->node); + + mmio_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_free_ent; + } + base = (unsigned long) mmio_base; + + /* + * Due to a bug in the chip, the default cache line size can't be used + */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + + probe_ent->sht = &vsc_sata_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET; + probe_ent->port_ops = &vsc_sata_ops; + probe_ent->n_ports = 4; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + + /* We don't care much about the PIO/UDMA masks, but the core won't like us + * if we don't fill these + */ + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; + + /* We have 4 ports per PCI function */ + vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET); + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + + +/* + * 0x1725/0x7174 is the Vitesse VSC-7174 + * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical + * compatibility is untested as of yet + */ +static struct pci_device_id vsc_sata_pci_tbl[] = { + { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { } +}; + + +static struct pci_driver vsc_sata_pci_driver = { + .name = DRV_NAME, + .id_table = vsc_sata_pci_tbl, + .probe = vsc_sata_init_one, + .remove = ata_pci_remove_one, +}; + + +static int __init vsc_sata_init(void) +{ + return pci_module_init(&vsc_sata_pci_driver); +} + + +static void __exit vsc_sata_exit(void) +{ + pci_unregister_driver(&vsc_sata_pci_driver); +} + + +MODULE_AUTHOR("Jeremy Higdon"); +MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl); + +module_init(vsc_sata_init); +module_exit(vsc_sata_exit); diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/scsi.c Sat Apr 3 19:38:43 2004 @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include #include "scsi.h" @@ -104,7 +106,7 @@ "Communications ", "Unknown ", "Unknown ", - "Unknown ", + "RAID ", "Enclosure ", }; @@ -1097,7 +1099,7 @@ struct list_head *lh, *lh_sf; unsigned long flags; - sdev->sdev_state = SDEV_CANCEL; + scsi_device_set_state(sdev, SDEV_CANCEL); spin_lock_irqsave(&sdev->list_lock, flags); list_for_each_entry(scmd, &sdev->cmd_list, list) { @@ -1130,6 +1132,38 @@ return 0; } +#ifdef CONFIG_HOTPLUG_CPU +static int scsi_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + int cpu = (unsigned long)hcpu; + + switch(action) { + case CPU_DEAD: + /* Drain scsi_done_q. */ + local_irq_disable(); + list_splice_init(&per_cpu(scsi_done_q, cpu), + &__get_cpu_var(scsi_done_q)); + raise_softirq_irqoff(SCSI_SOFTIRQ); + local_irq_enable(); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __devinitdata scsi_cpu_nb = { + .notifier_call = scsi_cpu_notify, +}; + +#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb) +#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb) +#else +#define register_scsi_cpu() +#define unregister_scsi_cpu() +#endif /* CONFIG_HOTPLUG_CPU */ + MODULE_DESCRIPTION("SCSI core"); MODULE_LICENSE("GPL"); @@ -1164,6 +1198,7 @@ devfs_mk_dir("scsi"); open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); + register_scsi_cpu(); printk(KERN_NOTICE "SCSI subsystem initialized\n"); return 0; @@ -1191,6 +1226,7 @@ devfs_remove("scsi"); scsi_exit_procfs(); scsi_exit_queue(); + unregister_scsi_cpu(); } subsys_initcall(init_scsi); diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/scsi_devinfo.c Sat Apr 3 19:38:42 2004 @@ -94,95 +94,93 @@ * The following causes a failed REQUEST SENSE on lun 1 for * seagate controller, which causes SCSI code to reset bus. */ - {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, + {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ + {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ + {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ + {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ + {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ + {"NEC", "D3856", "0009", BLIST_NOLUN}, {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* locks up */ {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* locks up */ {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */ - {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ + {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ - {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ - {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ - {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ - {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ - {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ - {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ - {"NEC", "D3856", "0009", BLIST_NOLUN}, /* * Other types of devices that have special flags. */ - {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, - {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, - {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, - {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, - {"INSITE", "I325VM", NULL, BLIST_KEY}, - {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"MICROP", "4110", NULL, BLIST_NOTQ}, - {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, + {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, + {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, - {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, - {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ + {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ + {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN}, {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, - {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, - {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, - {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, - {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ - {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ + {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, + {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ {"DELL", "PV530F", NULL, BLIST_SPARSELUN}, + {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, + {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ + {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, + {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN}, + {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, + {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, + {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ - {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ - {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ - {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ - {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, - {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, - {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ - {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, - {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, - {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, - {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"HP", "HSV100", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, - {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"SUN", "T300", "*", BLIST_SPARSELUN}, - {"SUN", "T4", "*", BLIST_SPARSELUN}, + {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, + {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, + {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, + {"INSITE", "I325VM", NULL, BLIST_KEY}, + {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, + {"MICROP", "4110", NULL, BLIST_NOTQ}, + {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, + {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SGI", "RAID3", "*", BLIST_SPARSELUN}, {"SGI", "RAID5", "*", BLIST_SPARSELUN}, {"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"SGI", "TP9300", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, + {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ + {"SUN", "T300", "*", BLIST_SPARSELUN}, + {"SUN", "T4", "*", BLIST_SPARSELUN}, + {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, + {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, + {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, + {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, { NULL, NULL, NULL, 0 }, }; diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/scsi_error.c Sat Apr 3 19:38:40 2004 @@ -37,6 +37,8 @@ #define SENSE_TIMEOUT (10*HZ) #endif +#define START_UNIT_TIMEOUT (30*HZ) + /* * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. @@ -282,6 +284,15 @@ (scmd->sense_buffer[13] == 0x01)) { return NEEDS_RETRY; } + /* + * if the device is not started, we need to wake + * the error handler to start the motor + */ + if (scmd->device->allow_restart && + (scmd->sense_buffer[12] == 0x04) && + (scmd->sense_buffer[13] == 0x02)) { + return FAILED; + } return SUCCESS; /* these three are not supported */ @@ -829,6 +840,105 @@ } /** + * scsi_eh_try_stu - Send START_UNIT to device. + * @scmd: Scsi cmd to send START_UNIT + * + * Return value: + * 0 - Device is ready. 1 - Device NOT ready. + **/ +static int scsi_eh_try_stu(struct scsi_cmnd *scmd) +{ + static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; + int rtn; + + if (!scmd->device->allow_restart) + return 1; + + memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); + + /* + * zero the sense buffer. the scsi spec mandates that any + * untransferred sense data should be interpreted as being zero. + */ + memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); + + scmd->request_buffer = NULL; + scmd->request_bufflen = 0; + scmd->use_sg = 0; + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); + scmd->underflow = 0; + scmd->sc_data_direction = DMA_NONE; + + rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT); + + /* + * when we eventually call scsi_finish, we really wish to complete + * the original request, so let's restore the original data. (db) + */ + scsi_setup_cmd_retry(scmd); + + /* + * hey, we are done. let's look to see what happened. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", + __FUNCTION__, scmd, rtn)); + if (rtn == SUCCESS) + return 0; + return 1; +} + + /** + * scsi_eh_stu - send START_UNIT if needed + * @shost: scsi host being recovered. + * @eh_done_q: list_head for processed commands. + * + * Notes: + * If commands are failing due to not ready, initializing command required, + * try revalidating the device, which will end up sending a start unit. + **/ +static int scsi_eh_stu(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) +{ + struct list_head *lh, *lh_sf; + struct scsi_cmnd *scmd, *stu_scmd; + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + stu_scmd = NULL; + list_for_each_entry(scmd, work_q, eh_entry) + if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) && + scsi_check_sense(scmd) == FAILED ) { + stu_scmd = scmd; + break; + } + + if (!stu_scmd) + continue; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:" + " 0x%p\n", current->comm, sdev)); + + if (!scsi_eh_try_stu(stu_scmd)) { + if (!sdev->online || !scsi_eh_tur(stu_scmd)) { + list_for_each_safe(lh, lh_sf, work_q) { + scmd = list_entry(lh, struct scsi_cmnd, eh_entry); + if (scmd->device == sdev) + scsi_eh_finish_cmd(scmd, done_q); + } + } + } else { + SCSI_LOG_ERROR_RECOVERY(3, + printk("%s: START_UNIT failed to sdev:" + " 0x%p\n", current->comm, sdev)); + } + } + + return list_empty(work_q); +} + + +/** * scsi_eh_bus_device_reset - send bdr if needed * @shost: scsi host being recovered. * @eh_done_q: list_head for processed commands. @@ -1033,7 +1143,9 @@ if (rtn == SUCCESS) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); - if (!scmd->device->online || !scsi_eh_tur(scmd)) + if (!scmd->device->online || + (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || + !scsi_eh_tur(scmd)) scsi_eh_finish_cmd(scmd, done_q); } } else { @@ -1181,6 +1293,8 @@ */ case DID_SOFT_ERROR: goto maybe_retry; + case DID_IMM_RETRY: + return NEEDS_RETRY; case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && @@ -1401,10 +1515,11 @@ struct list_head *work_q, struct list_head *done_q) { - if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) - if (!scsi_eh_bus_reset(shost, work_q, done_q)) - if (!scsi_eh_host_reset(work_q, done_q)) - scsi_eh_offline_sdevs(work_q, done_q); + if (!scsi_eh_stu(shost, work_q, done_q)) + if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) + if (!scsi_eh_bus_reset(shost, work_q, done_q)) + if (!scsi_eh_host_reset(work_q, done_q)) + scsi_eh_offline_sdevs(work_q, done_q); } /** diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/scsi_lib.c Sat Apr 3 19:38:43 2004 @@ -24,7 +24,7 @@ #include "scsi_logging.h" -#define SG_MEMPOOL_NR 5 +#define SG_MEMPOOL_NR (sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool)) #define SG_MEMPOOL_SIZE 32 struct scsi_host_sg_pool { @@ -34,9 +34,27 @@ mempool_t *pool; }; +#if (SCSI_MAX_PHYS_SEGMENTS < 32) +#error SCSI_MAX_PHYS_SEGMENTS is too small +#endif + #define SP(x) { x, "sgpool-" #x } -struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = { - SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS) +struct scsi_host_sg_pool scsi_sg_pools[] = { + SP(8), + SP(16), + SP(32), +#if (SCSI_MAX_PHYS_SEGMENTS > 32) + SP(64), +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + SP(128), +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + SP(256), +#if (SCSI_MAX_PHYS_SEGMENTS > 256) +#error SCSI_MAX_PHYS_SEGMENTS is too large +#endif +#endif +#endif +#endif }; #undef SP @@ -172,6 +190,10 @@ * like ioctls and character device requests - this is because * we essentially just inject a request into the queue for the * device. + * + * In order to support the scsi_device_quiesce function, we + * now inject requests on the *head* of the device queue + * rather than the tail. */ void scsi_do_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, @@ -202,11 +224,9 @@ sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]); /* - * At this point, we merely set up the command, stick it in the normal - * request queue, and return. Eventually that request will come to the - * top of the list, and will be dispatched. + * head injection *required* here otherwise quiesce won't work */ - scsi_insert_special_req(sreq, 0); + scsi_insert_special_req(sreq, 1); } static void scsi_wait_done(struct scsi_cmnd *cmd) @@ -558,12 +578,21 @@ case 17 ... 32: cmd->sglist_len = 2; break; +#if (SCSI_MAX_PHYS_SEGMENTS > 32) case 33 ... 64: cmd->sglist_len = 3; break; - case 65 ... MAX_PHYS_SEGMENTS: +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + case 65 ... 128: cmd->sglist_len = 4; break; +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + case 129 ... 256: + cmd->sglist_len = 5; + break; +#endif +#endif +#endif default: return NULL; } @@ -917,6 +946,7 @@ req->current_nr_sectors); /* release the command and kill it */ + scsi_release_buffers(cmd); scsi_put_command(cmd); return BLKPREP_KILL; } @@ -939,7 +969,7 @@ } /* OK, we only allow special commands (i.e. not * user initiated ones */ - specials_only = 1; + specials_only = sdev->sdev_state; } /* @@ -965,6 +995,9 @@ } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { if(unlikely(specials_only)) { + if(specials_only == SDEV_QUIESCE) + return BLKPREP_DEFER; + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n", sdev->host->host_no, sdev->id, sdev->lun); return BLKPREP_KILL; @@ -1285,7 +1318,7 @@ blk_queue_prep_rq(q, scsi_prep_fn); blk_queue_max_hw_segments(q, shost->sg_tablesize); - blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); + blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); @@ -1508,3 +1541,95 @@ return ret; } + +/** + * scsi_device_set_state - Take the given device through the device + * state model. + * @sdev: scsi device to change the state of. + * @state: state to change to. + * + * Returns zero if unsuccessful or an error if the requested + * transition is illegal. + **/ +int +scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) +{ + enum scsi_device_state oldstate = sdev->sdev_state; + + /* FIXME: eventually we will enforce all the state model + * transitions here */ + + if(oldstate == state) + return 0; + + switch(state) { + case SDEV_RUNNING: + if(oldstate != SDEV_CREATED && oldstate != SDEV_QUIESCE) + return -EINVAL; + break; + + case SDEV_QUIESCE: + if(oldstate != SDEV_RUNNING) + return -EINVAL; + break; + + default: + break; + } + sdev->sdev_state = state; + + return 0; +} +EXPORT_SYMBOL(scsi_device_set_state); + +/** + * scsi_device_quiesce - Block user issued commands. + * @sdev: scsi device to quiesce. + * + * This works by trying to transition to the SDEV_QUIESCE state + * (which must be a legal transition). When the device is in this + * state, only special requests will be accepted, all others will + * be deferred. Since special requests may also be requeued requests, + * a successful return doesn't guarantee the device will be + * totally quiescent. + * + * Must be called with user context, may sleep. + * + * Returns zero if unsuccessful or an error if not. + **/ +int +scsi_device_quiesce(struct scsi_device *sdev) +{ + int err = scsi_device_set_state(sdev, SDEV_QUIESCE); + if(err) + return err; + + scsi_run_queue(sdev->request_queue); + while(sdev->device_busy) { + schedule_timeout(HZ/5); + scsi_run_queue(sdev->request_queue); + } + return 0; +} +EXPORT_SYMBOL(scsi_device_quiesce); + +/** + * scsi_device_resume - Restart user issued commands to a quiesced device. + * @sdev: scsi device to resume. + * + * Moves the device from quiesced back to running and restarts the + * queues. + * + * Must be called with user context, may sleep. + **/ +void +scsi_device_resume(struct scsi_device *sdev) +{ + if(sdev->sdev_state != SDEV_QUIESCE) + return; + + scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_run_queue(sdev->request_queue); +} +EXPORT_SYMBOL(scsi_device_resume); + diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/scsi_priv.h Sat Apr 3 19:38:45 2004 @@ -155,6 +155,7 @@ extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); +extern struct scsi_transport_template blank_transport_template; extern struct class sdev_class; extern struct bus_type scsi_bus_type; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/scsi_scan.c Sat Apr 3 19:38:55 2004 @@ -35,6 +35,7 @@ #include #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -192,7 +193,7 @@ struct scsi_device *sdev, *device; unsigned long flags; - sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC); + sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC); if (!sdev) goto out; @@ -237,6 +238,11 @@ goto out_free_queue; } + if (shost->transportt->setup) { + if (shost->transportt->setup(sdev)) + goto out_cleanup_slave; + } + if (get_device(&sdev->host->shost_gendev)) { device_initialize(&sdev->sdev_gendev); @@ -253,8 +259,15 @@ snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); + + class_device_initialize(&sdev->transport_classdev); + sdev->transport_classdev.dev = &sdev->sdev_gendev; + sdev->transport_classdev.class = sdev->host->transportt->class; + snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE, + "%d:%d:%d:%d", sdev->host->host_no, + sdev->channel, sdev->id, sdev->lun); } else - goto out_cleanup_slave; + goto out_cleanup_transport; /* * If there are any same target siblings, add this to the @@ -283,6 +296,9 @@ spin_unlock_irqrestore(shost->host_lock, flags); return sdev; +out_cleanup_transport: + if (shost->transportt->cleanup) + shost->transportt->cleanup(sdev); out_cleanup_slave: if (shost->hostt->slave_destroy) shost->hostt->slave_destroy(sdev); @@ -627,6 +643,10 @@ if (*bflags & BLIST_USE_10_BYTE_MS) sdev->use_10_for_ms = 1; + /* set the device running here so that slave configure + * may do I/O */ + scsi_device_set_state(sdev, SDEV_RUNNING); + if(sdev->host->hostt->slave_configure) sdev->host->hostt->slave_configure(sdev); @@ -744,6 +764,8 @@ } else { if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } out: @@ -1300,5 +1322,7 @@ if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/scsi_sysfs.c Sat Apr 3 19:38:41 2004 @@ -13,6 +13,7 @@ #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -58,21 +59,24 @@ * shost_show_function: macro to create an attr function that can be used to * show a non-bit field. */ -#define shost_show_function(field, format_string) \ +#define shost_show_function(name, field, format_string) \ static ssize_t \ -show_##field (struct class_device *class_dev, char *buf) \ +show_##name (struct class_device *class_dev, char *buf) \ { \ struct Scsi_Host *shost = class_to_shost(class_dev); \ - return snprintf (buf, 20, format_string, shost->field); \ + return snprintf (buf, 20, format_string, shost->field); \ } /* * shost_rd_attr: macro to create a function and attribute variable for a * read only field. */ -#define shost_rd_attr(field, format_string) \ - shost_show_function(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL) +#define shost_rd_attr2(name, field, format_string) \ + shost_show_function(name, field, format_string) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +#define shost_rd_attr(field, format_string) \ +shost_rd_attr2(field, field, format_string) /* * Create the actual show/store functions and data structures. @@ -96,6 +100,7 @@ shost_rd_attr(cmd_per_lun, "%hd\n"); shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); +shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, @@ -103,6 +108,7 @@ &class_device_attr_cmd_per_lun, &class_device_attr_sg_tablesize, &class_device_attr_unchecked_isa_dma, + &class_device_attr_proc_name, &class_device_attr_scan, NULL }; @@ -344,13 +350,12 @@ **/ int scsi_sysfs_add_sdev(struct scsi_device *sdev) { - int error = -EINVAL, i; + struct class_device_attribute **attrs; + int error, i; - if (sdev->sdev_state != SDEV_CREATED) + if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) return error; - sdev->sdev_state = SDEV_RUNNING; - error = device_add(&sdev->sdev_gendev); if (error) { printk(KERN_INFO "error 1\n"); @@ -362,9 +367,20 @@ printk(KERN_INFO "error 2\n"); goto clean_device; } - + /* take a reference for the sdev_classdev; this is + * released by the sdev_class .release */ get_device(&sdev->sdev_gendev); + if (sdev->transport_classdev.class) { + error = class_device_add(&sdev->transport_classdev); + if (error) + goto clean_device2; + /* take a reference for the transport_classdev; this + * is released by the transport_class .release */ + get_device(&sdev->sdev_gendev); + + } + if (sdev->host->hostt->sdev_attrs) { for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { error = attr_add(&sdev->sdev_gendev, @@ -388,11 +404,25 @@ } } + if (sdev->transport_classdev.class) { + attrs = sdev->host->transportt->attrs; + for (i = 0; attrs[i]; i++) { + error = class_device_create_file(&sdev->transport_classdev, + attrs[i]); + if (error) { + scsi_remove_device(sdev); + goto out; + } + } + } + out: return error; -clean_device: - sdev->sdev_state = SDEV_CANCEL; + clean_device2: + class_device_del(&sdev->sdev_classdev); + clean_device: + scsi_device_set_state(sdev, SDEV_CANCEL); device_del(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); @@ -407,11 +437,15 @@ void scsi_remove_device(struct scsi_device *sdev) { if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) { - sdev->sdev_state = SDEV_DEL; + scsi_device_set_state(sdev, SDEV_DEL); class_device_unregister(&sdev->sdev_classdev); + if(sdev->transport_classdev.class) + class_device_unregister(&sdev->transport_classdev); device_del(&sdev->sdev_gendev); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } } @@ -498,3 +532,7 @@ return 0; } + +/* A blank transport template that is used in drivers that don't + * yet implement Transport Attributes */ +struct scsi_transport_template blank_transport_template = { 0, }; diff -Nru a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/scsi_transport_fc.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,104 @@ +/* + * FiberChannel transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +static void transport_class_release(struct class_device *class_dev); + +struct class fc_transport_class = { + .name = "fc_transport", + .release = transport_class_release, +}; + +static __init int fc_transport_init(void) +{ + return class_register(&fc_transport_class); +} + +static void __exit fc_transport_exit(void) +{ + class_unregister(&fc_transport_class); +} + +static int fc_setup_transport_attrs(struct scsi_device *sdev) +{ + /* FIXME: Callback into the driver */ + fc_node_name(sdev) = -1; + fc_port_name(sdev) = -1; + fc_port_id(sdev) = -1; + + return 0; +} + +static void transport_class_release(struct class_device *class_dev) +{ + struct scsi_device *sdev = transport_class_to_sdev(class_dev); + put_device(&sdev->sdev_gendev); +} + +#define fc_transport_show_function(field, format_string, cast) \ +static ssize_t \ +show_fc_transport_##field (struct class_device *cdev, char *buf) \ +{ \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct fc_transport_attrs *tp; \ + tp = (struct fc_transport_attrs *)&sdev->transport_data; \ + return snprintf(buf, 20, format_string, cast tp->field); \ +} + +#define fc_transport_rd_attr(field, format_string) \ + fc_transport_show_function(field, format_string, ) \ +static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL) + +#define fc_transport_rd_attr_cast(field, format_string, cast) \ + fc_transport_show_function(field, format_string, (cast)) \ +static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL) + +/* the FiberChannel Tranport Attributes: */ +fc_transport_rd_attr_cast(node_name, "0x%llx\n", unsigned long long); +fc_transport_rd_attr_cast(port_name, "0x%llx\n", unsigned long long); +fc_transport_rd_attr(port_id, "0x%06x\n"); + +struct class_device_attribute *fc_transport_attrs[] = { + &class_device_attr_node_name, + &class_device_attr_port_name, + &class_device_attr_port_id, + NULL +}; + +struct scsi_transport_template fc_transport_template = { + .attrs = fc_transport_attrs, + .class = &fc_transport_class, + .setup = &fc_setup_transport_attrs, + .cleanup = NULL, + .size = sizeof(struct fc_transport_attrs) - sizeof(unsigned long), +}; +EXPORT_SYMBOL(fc_transport_template); + +MODULE_AUTHOR("Martin Hicks"); +MODULE_DESCRIPTION("FC Transport Attributes"); +MODULE_LICENSE("GPL"); + +module_init(fc_transport_init); +module_exit(fc_transport_exit); diff -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/scsi_transport_spi.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,673 @@ +/* + * Parallel SCSI (SPI) transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPI_PRINTK(x, l, f, a...) printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a) + +static void transport_class_release(struct class_device *class_dev); + +#define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ + +#define SPI_MAX_ECHO_BUFFER_SIZE 4096 + +#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dv_pending) + +struct spi_internal { + struct scsi_transport_template t; + struct spi_function_template *f; + /* The actual attributes */ + struct class_device_attribute private_attrs[SPI_NUM_ATTRS]; + /* The array of null terminated pointers to attributes + * needed by scsi_sysfs.c */ + struct class_device_attribute *attrs[SPI_NUM_ATTRS + 1]; +}; + +#define to_spi_internal(tmpl) container_of(tmpl, struct spi_internal, t) + +static const char *const ppr_to_ns[] = { + /* The PPR values 0-6 are reserved, fill them in when + * the committee defines them */ + NULL, /* 0x00 */ + NULL, /* 0x01 */ + NULL, /* 0x02 */ + NULL, /* 0x03 */ + NULL, /* 0x04 */ + NULL, /* 0x05 */ + NULL, /* 0x06 */ + "3.125", /* 0x07 */ + "6.25", /* 0x08 */ + "12.5", /* 0x09 */ + "25", /* 0x0a */ + "30.3", /* 0x0b */ + "50", /* 0x0c */ +}; +/* The PPR values at which you calculate the period in ns by multiplying + * by 4 */ +#define SPI_STATIC_PPR 0x0c + +struct class spi_transport_class = { + .name = "spi_transport", + .release = transport_class_release, +}; + +static __init int spi_transport_init(void) +{ + return class_register(&spi_transport_class); +} + +static void __exit spi_transport_exit(void) +{ + class_unregister(&spi_transport_class); +} + +static int spi_setup_transport_attrs(struct scsi_device *sdev) +{ + spi_period(sdev) = -1; /* illegal value */ + spi_offset(sdev) = 0; /* async */ + spi_width(sdev) = 0; /* narrow */ + spi_iu(sdev) = 0; /* no IU */ + spi_dt(sdev) = 0; /* ST */ + spi_qas(sdev) = 0; + spi_wr_flow(sdev) = 0; + spi_rd_strm(sdev) = 0; + spi_rti(sdev) = 0; + spi_pcomp_en(sdev) = 0; + spi_dv_pending(sdev) = 0; + + return 0; +} + +static void transport_class_release(struct class_device *class_dev) +{ + struct scsi_device *sdev = transport_class_to_sdev(class_dev); + put_device(&sdev->sdev_gendev); +} + +#define spi_transport_show_function(field, format_string) \ + \ +static ssize_t \ +show_spi_transport_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct spi_transport_attrs *tp; \ + struct spi_internal *i = to_spi_internal(sdev->host->transportt); \ + tp = (struct spi_transport_attrs *)&sdev->transport_data; \ + if (i->f->get_##field) \ + i->f->get_##field(sdev); \ + return snprintf(buf, 20, format_string, tp->field); \ +} + +#define spi_transport_store_function(field, format_string) \ +static ssize_t \ +store_spi_transport_##field(struct class_device *cdev, const char *buf, \ + size_t count) \ +{ \ + int val; \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct spi_internal *i = to_spi_internal(sdev->host->transportt); \ + \ + val = simple_strtoul(buf, NULL, 0); \ + i->f->set_##field(sdev, val); \ + return count; \ +} + +#define spi_transport_rd_attr(field, format_string) \ + spi_transport_show_function(field, format_string) \ + spi_transport_store_function(field, format_string) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ + show_spi_transport_##field, \ + store_spi_transport_##field) + +/* The Parallel SCSI Tranport Attributes: */ +spi_transport_rd_attr(offset, "%d\n"); +spi_transport_rd_attr(width, "%d\n"); +spi_transport_rd_attr(iu, "%d\n"); +spi_transport_rd_attr(dt, "%d\n"); +spi_transport_rd_attr(qas, "%d\n"); +spi_transport_rd_attr(wr_flow, "%d\n"); +spi_transport_rd_attr(rd_strm, "%d\n"); +spi_transport_rd_attr(rti, "%d\n"); +spi_transport_rd_attr(pcomp_en, "%d\n"); + +/* Translate the period into ns according to the current spec + * for SDTR/PPR messages */ +static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) + +{ + struct scsi_device *sdev = transport_class_to_sdev(cdev); + struct spi_transport_attrs *tp; + const char *str; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); + + tp = (struct spi_transport_attrs *)&sdev->transport_data; + + if (i->f->get_period) + i->f->get_period(sdev); + + switch(tp->period) { + + case 0x07 ... SPI_STATIC_PPR: + str = ppr_to_ns[tp->period]; + if(!str) + str = "reserved"; + break; + + + case (SPI_STATIC_PPR+1) ... 0xff: + return sprintf(buf, "%d\n", tp->period * 4); + + default: + str = "unknown"; + } + return sprintf(buf, "%s\n", str); +} + +static ssize_t +store_spi_transport_period(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_device *sdev = transport_class_to_sdev(cdev); + struct spi_internal *i = to_spi_internal(sdev->host->transportt); + int j, period = -1; + + for (j = 0; j < SPI_STATIC_PPR; j++) { + int len; + + if(ppr_to_ns[j] == NULL) + continue; + + len = strlen(ppr_to_ns[j]); + + if(strncmp(ppr_to_ns[j], buf, len) != 0) + continue; + + if(buf[len] != '\n') + continue; + + period = j; + break; + } + + if (period == -1) { + int val = simple_strtoul(buf, NULL, 0); + + + /* Should probably check limits here, but this + * gets reasonably close to OK for most things */ + period = val/4; + } + + if (period > 0xff) + period = 0xff; + + i->f->set_period(sdev, period); + + return count; +} + +static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, + show_spi_transport_period, + store_spi_transport_period); + +#define DV_SET(x, y) \ + if(i->f->set_##x) \ + i->f->set_##x(sdev, y) + +#define DV_LOOPS 3 +#define DV_TIMEOUT (10*HZ) +#define DV_RETRIES 5 + + +/* This is for read/write Domain Validation: If the device supports + * an echo buffer, we do read/write tests to it */ +static int +spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, + u8 *ptr, const int retries) +{ + struct scsi_device *sdev = sreq->sr_device; + int len = ptr - buffer; + int j, k, r; + unsigned int pattern = 0x0000ffff; + + const char spi_write_buffer[] = { + WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 + }; + const char spi_read_buffer[] = { + READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 + }; + + /* set up the pattern buffer. Doesn't matter if we spill + * slightly beyond since that's where the read buffer is */ + for (j = 0; j < len; ) { + + /* fill the buffer with counting (test a) */ + for ( ; j < min(len, 32); j++) + buffer[j] = j; + k = j; + /* fill the buffer with alternating words of 0x0 and + * 0xffff (test b) */ + for ( ; j < min(len, k + 32); j += 2) { + u16 *word = (u16 *)&buffer[j]; + + *word = (j & 0x02) ? 0x0000 : 0xffff; + } + k = j; + /* fill with crosstalk (alternating 0x5555 0xaaa) + * (test c) */ + for ( ; j < min(len, k + 32); j += 2) { + u16 *word = (u16 *)&buffer[j]; + + *word = (j & 0x02) ? 0x5555 : 0xaaaa; + } + k = j; + /* fill with shifting bits (test d) */ + for ( ; j < min(len, k + 32); j += 4) { + u32 *word = (unsigned int *)&buffer[j]; + u32 roll = (pattern & 0x80000000) ? 1 : 0; + + *word = pattern; + pattern = (pattern << 1) | roll; + } + /* don't bother with random data (test e) */ + } + + for (r = 0; r < retries; r++) { + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_TO_DEVICE; + scsi_wait_req(sreq, spi_write_buffer, buffer, len, + DV_TIMEOUT, DV_RETRIES); + if(sreq->sr_result) { + SPI_PRINTK(sdev, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result); + return 0; + } + + memset(ptr, 0, len); + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + scsi_wait_req(sreq, spi_read_buffer, ptr, len, + DV_TIMEOUT, DV_RETRIES); + + if (memcmp(buffer, ptr, len) != 0) + return 0; + } + return 1; +} + +/* This is for the simplest form of Domain Validation: a read test + * on the inquiry data from the device */ +static int +spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, + u8 *ptr, const int retries) +{ + int r; + const int len = sreq->sr_device->inquiry_len; + const char spi_inquiry[] = { + INQUIRY, 0, 0, 0, len, 0 + }; + + for (r = 0; r < retries; r++) { + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + + memset(ptr, 0, len); + + scsi_wait_req(sreq, spi_inquiry, ptr, len, + DV_TIMEOUT, DV_RETRIES); + + /* If we don't have the inquiry data already, the + * first read gets it */ + if (ptr == buffer) { + ptr += len; + --r; + continue; + } + + if (memcmp(buffer, ptr, len) != 0) + /* failure */ + return 0; + } + return 1; +} + +static int +spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, + int (*compare_fn)(struct scsi_request *, u8 *, u8 *, int)) +{ + struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); + struct scsi_device *sdev = sreq->sr_device; + int period, prevperiod = 0; + + + for (;;) { + if (compare_fn(sreq, buffer, ptr, DV_LOOPS)) + /* Successful DV */ + break; + + /* OK, retrain, fallback */ + if (i->f->get_period) + i->f->get_period(sdev); + period = spi_period(sdev); + if (period < 0x0d) + period++; + else + period += period >> 1; + + if (unlikely(period > 0xff || period == prevperiod)) { + /* Total failure; set to async and return */ + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n"); + DV_SET(offset, 0); + return 0; + } + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation detected failure, dropping back\n"); + DV_SET(period, period); + prevperiod = period; + } + return 1; +} + +static int +spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) +{ + int l; + + /* first off do a test unit ready. This can error out + * because of reservations or some other reason. If it + * fails, the device won't let us write to the echo buffer + * so just return failure */ + + const char spi_test_unit_ready[] = { + TEST_UNIT_READY, 0, 0, 0, 0, 0 + }; + + const char spi_read_buffer_descriptor[] = { + READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0 + }; + + + sreq->sr_cmd_len = 0; + sreq->sr_data_direction = DMA_NONE; + + /* We send a set of three TURs to clear any outstanding + * unit attention conditions if they exist (Otherwise the + * buffer tests won't be happy). If the TUR still fails + * (reservation conflict, device not ready, etc) just + * skip the write tests */ + for (l = 0; ; l++) { + scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0, + DV_TIMEOUT, DV_RETRIES); + + if(sreq->sr_result) { + if(l >= 3) + return 0; + } else { + /* TUR succeeded */ + break; + } + } + + sreq->sr_cmd_len = 0; + sreq->sr_data_direction = DMA_FROM_DEVICE; + + scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4, + DV_TIMEOUT, DV_RETRIES); + + if (sreq->sr_result) + /* Device has no echo buffer */ + return 0; + + return buffer[3] + ((buffer[2] & 0x1f) << 8); +} + +static void +spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) +{ + struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); + struct scsi_device *sdev = sreq->sr_device; + int len = sdev->inquiry_len; + /* first set us up for narrow async */ + DV_SET(offset, 0); + DV_SET(width, 0); + + if (!spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)) { + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); + /* FIXME: should probably offline the device here? */ + return; + } + + /* test width */ + if (i->f->set_width) { + i->f->set_width(sdev, 1); + + if (!spi_dv_device_compare_inquiry(sreq, buffer, + buffer + len, + DV_LOOPS)) { + SPI_PRINTK(sdev, KERN_ERR, "Wide Transfers Fail\n"); + i->f->set_width(sdev, 0); + } + } + + if (!i->f->set_period) + return; + + /* now set up to the maximum */ + DV_SET(offset, 255); + DV_SET(period, 1); + if (!spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_device_compare_inquiry)) + return; + + /* OK, now we have our initial speed set by the read only inquiry + * test, now try an echo buffer test (if the device allows it) */ + + if ((len = spi_dv_device_get_echo_buffer(sreq, buffer)) == 0) { + SPI_PRINTK(sdev, KERN_INFO, "Domain Validation skipping write tests\n"); + return; + } + if (len > SPI_MAX_ECHO_BUFFER_SIZE) { + SPI_PRINTK(sdev, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE); + len = SPI_MAX_ECHO_BUFFER_SIZE; + } + + spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_device_echo_buffer); +} + + +/** spi_dv_device - Do Domain Validation on the device + * @sdev: scsi device to validate + * + * Performs the domain validation on the given device in the + * current execution thread. Since DV operations may sleep, + * the current thread must have user context. Also no SCSI + * related locks that would deadlock I/O issued by the DV may + * be held. + */ +void +spi_dv_device(struct scsi_device *sdev) +{ + struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); + u8 *buffer; + const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; + + if (unlikely(!sreq)) + return; + + if (unlikely(scsi_device_get(sdev))) + goto out_free_req; + + buffer = kmalloc(len, GFP_KERNEL); + + if (unlikely(!buffer)) + goto out_put; + + memset(buffer, 0, len); + + if (unlikely(scsi_device_quiesce(sdev))) + goto out_free; + + SPI_PRINTK(sdev, KERN_INFO, "Beginning Domain Validation\n"); + + spi_dv_device_internal(sreq, buffer); + + SPI_PRINTK(sdev, KERN_INFO, "Ending Domain Validation\n"); + + scsi_device_resume(sdev); + + out_free: + kfree(buffer); + out_put: + scsi_device_put(sdev); + out_free_req: + scsi_release_request(sreq); +} +EXPORT_SYMBOL(spi_dv_device); + +struct work_queue_wrapper { + struct work_struct work; + struct scsi_device *sdev; +}; + +static void +spi_dv_device_work_wrapper(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct scsi_device *sdev = wqw->sdev; + + kfree(wqw); + spi_dv_device(sdev); + spi_dv_pending(sdev) = 0; + scsi_device_put(sdev); +} + + +/** + * spi_schedule_dv_device - schedule domain validation to occur on the device + * @sdev: The device to validate + * + * Identical to spi_dv_device() above, except that the DV will be + * scheduled to occur in a workqueue later. All memory allocations + * are atomic, so may be called from any context including those holding + * SCSI locks. + */ +void +spi_schedule_dv_device(struct scsi_device *sdev) +{ + struct work_queue_wrapper *wqw = + kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); + + if (unlikely(!wqw)) + return; + + if (unlikely(spi_dv_pending(sdev))) { + kfree(wqw); + return; + } + + if (unlikely(scsi_device_get(sdev))) { + kfree(wqw); + spi_dv_pending(sdev) = 0; + return; + } + + INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw); + wqw->sdev = sdev; + + schedule_work(&wqw->work); +} +EXPORT_SYMBOL(spi_schedule_dv_device); + +#define SETUP_ATTRIBUTE(field) \ + i->private_attrs[count] = class_device_attr_##field; \ + if (!i->f->set_##field) { \ + i->private_attrs[count].attr.mode = S_IRUGO; \ + i->private_attrs[count].store = NULL; \ + } \ + i->attrs[count] = &i->private_attrs[count]; \ + if (i->f->show_##field) \ + count++ + +struct scsi_transport_template * +spi_attach_transport(struct spi_function_template *ft) +{ + struct spi_internal *i = kmalloc(sizeof(struct spi_internal), + GFP_KERNEL); + int count = 0; + if (unlikely(!i)) + return NULL; + + memset(i, 0, sizeof(struct spi_internal)); + + + i->t.attrs = &i->attrs[0]; + i->t.class = &spi_transport_class; + i->t.setup = &spi_setup_transport_attrs; + i->t.size = sizeof(struct spi_transport_attrs) - sizeof(unsigned long); + i->f = ft; + + SETUP_ATTRIBUTE(period); + SETUP_ATTRIBUTE(offset); + SETUP_ATTRIBUTE(width); + SETUP_ATTRIBUTE(iu); + SETUP_ATTRIBUTE(dt); + SETUP_ATTRIBUTE(qas); + SETUP_ATTRIBUTE(wr_flow); + SETUP_ATTRIBUTE(rd_strm); + SETUP_ATTRIBUTE(rti); + SETUP_ATTRIBUTE(pcomp_en); + + /* if you add an attribute but forget to increase SPI_NUM_ATTRS + * this bug will trigger */ + BUG_ON(count > SPI_NUM_ATTRS); + + i->attrs[count] = NULL; + + return &i->t; +} +EXPORT_SYMBOL(spi_attach_transport); + +void spi_release_transport(struct scsi_transport_template *t) +{ + struct spi_internal *i = to_spi_internal(t); + + kfree(i); +} +EXPORT_SYMBOL(spi_release_transport); + + +MODULE_AUTHOR("Martin Hicks"); +MODULE_DESCRIPTION("SPI Transport Attributes"); +MODULE_LICENSE("GPL"); + +module_init(spi_transport_init); +module_exit(spi_transport_exit); diff -Nru a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c --- a/drivers/scsi/scsiiom.c Sat Apr 3 19:38:41 2004 +++ b/drivers/scsi/scsiiom.c Sat Apr 3 19:38:41 2004 @@ -1674,7 +1674,7 @@ #endif psrb = psrb2; } - pdcb->GoingSRBCnt = 0;; + pdcb->GoingSRBCnt = 0; pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sat Apr 3 19:38:54 2004 +++ b/drivers/scsi/sd.c Sat Apr 3 19:38:54 2004 @@ -19,6 +19,9 @@ * not being read in sd_open. Fix problem where removable media * could be ejected after sd_open. * - Douglas Gilbert cleanup for lk 2.5.x + * - Badari Pulavarty , Matthew Wilcox + * , Kurt Garloff : + * Support 32k/1M disks. * * Logging policy (needs CONFIG_SCSI_LOGGING defined): * - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2 @@ -61,7 +64,7 @@ * Remaining dev_t-handling stuff */ #define SD_MAJORS 16 -#define SD_DISKS (SD_MAJORS << 4) +#define SD_DISKS 32768 /* anything between 256 and 262144 */ /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -121,6 +124,20 @@ .init_command = sd_init_command, }; +/* Device no to disk mapping: + * + * major disc2 disc p1 + * |............|.............|....|....| <- dev_t + * 31 20 19 8 7 4 3 0 + * + * Inside a major, we have 16k disks, however mapped non- + * contiguously. The first 16 disks are for major0, the next + * ones with major1, ... Disk 256 is for major0 again, disk 272 + * for major1, ... + * As we stay compatible with our numbering scheme, we can reuse + * the well-know SCSI majors 8, 65--71, 136--143. + */ + static int sd_major(int major_idx) { switch (major_idx) { @@ -136,6 +153,14 @@ } } +static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part) +{ + return (part & 0xf) | ((sd_nr & 0xf) << 4) | + (sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00); +} + +/* reverse mapping dev -> (sd_nr, part) not currently needed */ + #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kobj); static inline struct scsi_disk *scsi_disk(struct gendisk *disk) @@ -1301,7 +1326,7 @@ struct scsi_disk *sdkp; struct gendisk *gd; u32 index; - int error; + int error, devno; error = -ENODEV; if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) @@ -1319,6 +1344,12 @@ kobject_init(&sdkp->kobj); sdkp->kobj.ktype = &scsi_disk_kobj_type; + /* Note: We can accomodate 64 partitions, but the genhd code + * assumes partitions allocate consecutive minors, which they don't. + * So for now stay with max 16 partitions and leave two spare bits. + * Later, we may change the genhd code and the alloc_disk() call + * and the ->minors assignment here. KG, 2004-02-10 + */ gd = alloc_disk(16); if (!gd) goto out_free; @@ -1339,16 +1370,23 @@ sdkp->index = index; sdkp->openers = 0; - gd->major = sd_major(index >> 4); - gd->first_minor = (index & 15) << 4; + devno = make_sd_dev(index, 0); + gd->major = MAJOR(devno); + gd->first_minor = MINOR(devno); gd->minors = 16; gd->fops = &sd_fops; - if (index >= 26) { + if (index < 26) { + sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + } else if (index < (26*27)) { sprintf(gd->disk_name, "sd%c%c", - 'a' + index/26-1,'a' + index % 26); + 'a' + index / 26 - 1,'a' + index % 26); } else { - sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + const unsigned int m1 = (index / 26 - 1) / 26 - 1; + const unsigned int m2 = (index / 26 - 1) % 26; + const unsigned int m3 = index % 26; + sprintf(gd->disk_name, "sd%c%c%c", + 'a' + m1, 'a' + m2, 'a' + m3); } strcpy(gd->devfs_name, sdp->devfs_name); diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/sg.c Sat Apr 3 19:38:43 2004 @@ -1256,7 +1256,6 @@ SRpnt->sr_request->rq_disk = NULL; /* "sg" _disowns_ request blk */ srp->my_cmdp = NULL; - srp->done = 1; SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result)); @@ -1312,8 +1311,9 @@ } if (sfp && srp) { /* Now wake up any sg_read() that is waiting for this packet. */ - wake_up_interruptible(&sfp->read_wait); kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); + srp->done = 1; + wake_up_interruptible(&sfp->read_wait); } } @@ -1409,7 +1409,6 @@ SCSI_LOG_TIMEOUT(3, printk("sg_add: dev=%d \n", k)); memset(sdp, 0, sizeof(*sdp)); sprintf(disk->disk_name, "sg%d", k); - strncpy(cdev->kobj.name, disk->disk_name, KOBJ_NAME_LEN); cdev->owner = THIS_MODULE; cdev->ops = &sg_fops; disk->major = SCSI_GENERIC_MAJOR; @@ -1439,7 +1438,7 @@ MKDEV(SCSI_GENERIC_MAJOR, k), cl_dev->dev, "%s", disk->disk_name); - if (NULL == sg_class_member) + if (IS_ERR(sg_class_member)) printk(KERN_WARNING "sg_add: " "class_simple_device_add failed\n"); class_set_devdata(sg_class_member, sdp); @@ -1462,7 +1461,7 @@ out: put_disk(disk); if (cdev) - kobject_put(&cdev->kobj); + cdev_del(cdev); return error; } diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/sr.c Sat Apr 3 19:38:42 2004 @@ -566,12 +566,16 @@ snprintf(disk->devfs_name, sizeof(disk->devfs_name), "%s/cd", sdev->devfs_name); disk->driverfs_dev = &sdev->sdev_gendev; - register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); disk->private_data = &cd->driver; disk->queue = sdev->request_queue; + cd->cdi.disk = disk; + + if (register_cdrom(&cd->cdi)) + goto fail_put; dev_set_drvdata(dev, cd); + disk->flags |= GENHD_FL_REMOVABLE; add_disk(disk); printk(KERN_DEBUG @@ -695,7 +699,7 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; - int rc, n, mrw_write = 0, mrw = 1; + int rc, n, mrw_write = 0, mrw = 1,ram_write=0; struct scsi_mode_data data; struct scsi_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; @@ -780,6 +784,11 @@ if (!mrw_write) cd->cdi.mask |= CDC_MRW_W; + if (cdrom_is_random_writable(&cd->cdi, &ram_write)) + cd->cdi.mask |= CDC_RAM; + if (!ram_write) + cd->cdi.mask |= CDC_RAM; + n = data.header_length + data.block_descriptor_length; cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; cd->readcd_known = 1; @@ -829,8 +838,8 @@ /* * if DVD-RAM of MRW-W, we are randomly writeable */ - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) != - (CDC_DVD_RAM | CDC_MRW_W)) { + if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) != + (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) { cd->device->writeable = 1; set_disk_ro(cd->disk, 0); } diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/st.c Sat Apr 3 19:38:45 2004 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20040213"; +static char *verstr = "20040318"; #include @@ -121,7 +121,15 @@ }; #endif -static char *st_formats[ST_NBR_MODES] ={"", "l", "m", "a"}; +/* Restrict the number of modes so that names for all are assigned */ +#if ST_NBR_MODES > 16 +#error "Maximum number of modes is 16" +#endif +/* Bit reversed order to get same names for same minors with all + mode counts */ +static char *st_formats[] = { + "", "r", "k", "s", "l", "t", "o", "u", + "m", "v", "p", "x", "a", "y", "q", "z"}; /* The default definitions have been moved to st_options.h */ @@ -3888,8 +3896,6 @@ dev_num); goto out_free_tape; } - snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name, - mode, j ? "n" : ""); cdev->owner = THIS_MODULE; cdev->ops = &st_fops; @@ -3909,22 +3915,26 @@ } for (mode = 0; mode < ST_NBR_MODES; ++mode) { + /* Make sure that the minor numbers corresponding to the four + first modes always get the same names */ + i = mode << (4 - ST_NBR_MODE_BITS); /* Rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)), S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%s", SDp->devfs_name, st_formats[mode]); + "%s/mt%s", SDp->devfs_name, st_formats[i]); /* No-rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)), S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%sn", SDp->devfs_name, st_formats[mode]); + "%s/mt%sn", SDp->devfs_name, st_formats[i]); } disk->number = devfs_register_tape(SDp->devfs_name); printk(KERN_WARNING "Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n", tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - printk(KERN_WARNING "%s: try direct i/o: %s, max page reachable by HBA %lu\n", - tape_name(tpnt), tpnt->try_dio ? "yes" : "no", tpnt->max_pfn); + printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B), max page reachable by HBA %lu\n", + tape_name(tpnt), tpnt->try_dio ? "yes" : "no", + queue_dma_alignment(SDp->request_queue) + 1, tpnt->max_pfn); return 0; @@ -3944,7 +3954,7 @@ } } if (cdev) - kobject_put(&cdev->kobj); + cdev_del(cdev); write_lock(&st_dev_arr_lock); scsi_tapes[dev_num] = NULL; st_nr_dev--; @@ -3977,8 +3987,9 @@ sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape"); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]); - devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]); + j = mode << (4 - ST_NBR_MODE_BITS); + devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]); + devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]); for (j=0; j < 2; j++) { class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(i, mode, j))); @@ -4182,20 +4193,25 @@ static void do_create_class_files(Scsi_Tape *STp, int dev_num, int mode) { - int rew, error; + int i, rew, error; + char name[10]; struct class_device *st_class_member; if (!st_sysfs_class) return; for (rew=0; rew < 2; rew++) { + /* Make sure that the minor numbers corresponding to the four + first modes always get the same names */ + i = mode << (4 - ST_NBR_MODE_BITS); + snprintf(name, 10, "%s%s%s", rew ? "n" : "", + STp->disk->disk_name, st_formats[i]); st_class_member = class_simple_device_add(st_sysfs_class, MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew)), - &STp->device->sdev_gendev, "%s", - STp->modes[mode].cdevs[rew]->kobj.name); - if (!st_class_member) { + &STp->device->sdev_gendev, "%s", name); + if (IS_ERR(st_class_member)) { printk(KERN_WARNING "st%d: class_simple_device_add failed\n", dev_num); goto out; diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h --- a/drivers/scsi/st.h Sat Apr 3 19:38:55 2004 +++ b/drivers/scsi/st.h Sat Apr 3 19:38:55 2004 @@ -50,6 +50,8 @@ struct cdev *cdevs[2]; /* Auto-rewind and non-rewind devices */ } ST_mode; +/* Number of modes can be changed by changing ST_NBR_MODE_BITS. The maximum + number of modes is 16 (ST_NBR_MODE_BITS 4) */ #define ST_NBR_MODE_BITS 2 #define ST_NBR_MODES (1 << ST_NBR_MODE_BITS) #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) diff -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h --- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h Sat Apr 3 19:38:56 2004 @@ -70,13 +70,6 @@ #define SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE /* - * NCR PQS/PDS special device support. - */ -#if 1 -#define SYM_CONF_PQS_PDS_SUPPORT -#endif - -/* * NVRAM support. */ #if 1 diff -Nru a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h --- a/drivers/scsi/sym53c8xx_2/sym_defs.h Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h Sat Apr 3 19:38:42 2004 @@ -127,135 +127,6 @@ }; /* - * Symbios NVRAM data format - */ -#define SYMBIOS_NVRAM_SIZE 368 -#define SYMBIOS_NVRAM_ADDRESS 0x100 - -struct Symbios_nvram { -/* Header 6 bytes */ - u_short type; /* 0x0000 */ - u_short byte_count; /* excluding header/trailer */ - u_short checksum; - -/* Controller set up 20 bytes */ - u_char v_major; /* 0x00 */ - u_char v_minor; /* 0x30 */ - u32 boot_crc; - u_short flags; -#define SYMBIOS_SCAM_ENABLE (1) -#define SYMBIOS_PARITY_ENABLE (1<<1) -#define SYMBIOS_VERBOSE_MSGS (1<<2) -#define SYMBIOS_CHS_MAPPING (1<<3) -#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ - u_short flags1; -#define SYMBIOS_SCAN_HI_LO (1) - u_short term_state; -#define SYMBIOS_TERM_CANT_PROGRAM (0) -#define SYMBIOS_TERM_ENABLED (1) -#define SYMBIOS_TERM_DISABLED (2) - u_short rmvbl_flags; -#define SYMBIOS_RMVBL_NO_SUPPORT (0) -#define SYMBIOS_RMVBL_BOOT_DEVICE (1) -#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) - u_char host_id; - u_char num_hba; /* 0x04 */ - u_char num_devices; /* 0x10 */ - u_char max_scam_devices; /* 0x04 */ - u_char num_valid_scam_devices; /* 0x00 */ - u_char flags2; -#define SYMBIOS_AVOID_BUS_RESET (1<<2) - -/* Boot order 14 bytes * 4 */ - struct Symbios_host{ - u_short type; /* 4:8xx / 0:nok */ - u_short device_id; /* PCI device id */ - u_short vendor_id; /* PCI vendor id */ - u_char bus_nr; /* PCI bus number */ - u_char device_fn; /* PCI device/function number << 3*/ - u_short word8; - u_short flags; -#define SYMBIOS_INIT_SCAN_AT_BOOT (1) - u_short io_port; /* PCI io_port address */ - } host[4]; - -/* Targets 8 bytes * 16 */ - struct Symbios_target { - u_char flags; -#define SYMBIOS_DISCONNECT_ENABLE (1) -#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) -#define SYMBIOS_SCAN_LUNS (1<<2) -#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) - u_char rsvd; - u_char bus_width; /* 0x08/0x10 */ - u_char sync_offset; - u_short sync_period; /* 4*period factor */ - u_short timeout; - } target[16]; -/* Scam table 8 bytes * 4 */ - struct Symbios_scam { - u_short id; - u_short method; -#define SYMBIOS_SCAM_DEFAULT_METHOD (0) -#define SYMBIOS_SCAM_DONT_ASSIGN (1) -#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) -#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) - u_short status; -#define SYMBIOS_SCAM_UNKNOWN (0) -#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) -#define SYMBIOS_SCAM_ID_NOT_SET (2) -#define SYMBIOS_SCAM_ID_VALID (3) - u_char target_id; - u_char rsvd; - } scam[4]; - - u_char spare_devices[15*8]; - u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ -}; -typedef struct Symbios_nvram Symbios_nvram; -typedef struct Symbios_host Symbios_host; -typedef struct Symbios_target Symbios_target; -typedef struct Symbios_scam Symbios_scam; - -/* - * Tekram NvRAM data format. - */ -#define TEKRAM_NVRAM_SIZE 64 -#define TEKRAM_93C46_NVRAM_ADDRESS 0 -#define TEKRAM_24C16_NVRAM_ADDRESS 0x40 - -struct Tekram_nvram { - struct Tekram_target { - u_char flags; -#define TEKRAM_PARITY_CHECK (1) -#define TEKRAM_SYNC_NEGO (1<<1) -#define TEKRAM_DISCONNECT_ENABLE (1<<2) -#define TEKRAM_START_CMD (1<<3) -#define TEKRAM_TAGGED_COMMANDS (1<<4) -#define TEKRAM_WIDE_NEGO (1<<5) - u_char sync_index; - u_short word2; - } target[16]; - u_char host_id; - u_char flags; -#define TEKRAM_MORE_THAN_2_DRIVES (1) -#define TEKRAM_DRIVES_SUP_1GB (1<<1) -#define TEKRAM_RESET_ON_POWER_ON (1<<2) -#define TEKRAM_ACTIVE_NEGATION (1<<3) -#define TEKRAM_IMMEDIATE_SEEK (1<<4) -#define TEKRAM_SCAN_LUNS (1<<5) -#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */ - /* 1: boot device; 2:all */ - u_char boot_delay_index; - u_char max_tags_index; - u_short flags1; -#define TEKRAM_F2_F6_ENABLED (1) - u_short spare[29]; -}; -typedef struct Tekram_nvram Tekram_nvram; -typedef struct Tekram_target Tekram_target; - -/* * SYM53C8XX IO register data structure. */ struct sym_reg { diff -Nru a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c --- a/drivers/scsi/sym53c8xx_2/sym_fw.c Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_fw.c Sat Apr 3 19:38:56 2004 @@ -135,7 +135,7 @@ * Patch routine for firmware #1. */ static void -sym_fw1_patch(hcb_p np) +sym_fw1_patch(struct sym_hcb *np) { struct sym_fw1a_scr *scripta0; struct sym_fw1b_scr *scriptb0; @@ -176,7 +176,7 @@ * Patch routine for firmware #2. */ static void -sym_fw2_patch(hcb_p np) +sym_fw2_patch(struct sym_hcb *np) { struct sym_fw2a_scr *scripta0; struct sym_fw2b_scr *scriptb0; @@ -282,7 +282,7 @@ * To be done for all firmwares. */ static void -sym_fw_setup_bus_addresses(hcb_p np, struct sym_fw *fw) +sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) { u32 *pa; u_short *po; @@ -319,7 +319,7 @@ * Setup routine for firmware #1. */ static void -sym_fw1_setup(hcb_p np, struct sym_fw *fw) +sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) { struct sym_fw1a_scr *scripta0; struct sym_fw1b_scr *scriptb0; @@ -343,7 +343,7 @@ * Setup routine for firmware #2. */ static void -sym_fw2_setup(hcb_p np, struct sym_fw *fw) +sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) { struct sym_fw2a_scr *scripta0; struct sym_fw2b_scr *scriptb0; @@ -389,7 +389,7 @@ /* * Bind a script to physical addresses. */ -void sym_fw_bind_script (hcb_p np, u32 *start, int len) +void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) { u32 opcode, new, old, tmp1, tmp2; u32 *end, *cur; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Sat Apr 3 19:38:57 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Sat Apr 3 19:38:57 2004 @@ -57,7 +57,9 @@ #include #include #include + #include "sym_glue.h" +#include "sym_nvram.h" #define NAME53C "sym53c" #define NAME53C8XX "sym53c8xx" @@ -212,17 +214,32 @@ return use_sg; } -static void __sync_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) +static void __sync_scsi_data_for_cpu(struct pci_dev *pdev, struct scsi_cmnd *cmd) { int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); switch(SYM_UCMD_PTR(cmd)->data_mapped) { case 2: - pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + pci_dma_sync_sg_for_cpu(pdev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - pci_dma_sync_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); + pci_dma_sync_single_for_cpu(pdev, SYM_UCMD_PTR(cmd)->data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +static void __sync_scsi_data_for_device(struct pci_dev *pdev, struct scsi_cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(SYM_UCMD_PTR(cmd)->data_mapped) { + case 2: + pci_dma_sync_sg_for_device(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single_for_device(pdev, SYM_UCMD_PTR(cmd)->data_mapping, + cmd->request_bufflen, dma_dir); break; } } @@ -233,8 +250,10 @@ __map_scsi_single_data(np->s.device, cmd) #define map_scsi_sg_data(np, cmd) \ __map_scsi_sg_data(np->s.device, cmd) -#define sync_scsi_data(np, cmd) \ - __sync_scsi_data(np->s.device, cmd) +#define sync_scsi_data_for_cpu(np, cmd) \ + __sync_scsi_data_for_cpu(np->s.device, cmd) +#define sync_scsi_data_for_device(np, cmd) \ + __sync_scsi_data_for_device(np->s.device, cmd) /* * Complete a pending CAM CCB. @@ -394,10 +413,11 @@ if (!cmd || cmd->use_sg) return; - sync_scsi_data(np, cmd); + sync_scsi_data_for_cpu(np, cmd); retv = __sym_sniff_inquiry(np, cmd->device->id, cmd->device->lun, (u_char *) cmd->request_buffer, cmd->request_bufflen - resid); + sync_scsi_data_for_device(np, cmd); if (retv < 0) return; else if (retv) @@ -532,7 +552,7 @@ /* * Setup buffers and pointers that address the CDB. */ -static int __inline sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp) +static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp) { u32 cmd_ba; int cmd_len; @@ -1281,7 +1301,7 @@ { int verb_len = strlen(verb); - if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + if (len >= verb_len && !memcmp(verb, ptr, verb_len)) return verb_len; else return 0; @@ -1938,7 +1958,7 @@ char *cur = str; char *pc, *pv; unsigned long val; - int i, c; + unsigned int i, c; int xi = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { @@ -2171,6 +2191,55 @@ return 0; } +/* + * The NCR PQS and PDS cards are constructed as a DEC bridge + * behind which sits a proprietary NCR memory controller and + * either four or two 53c875s as separate devices. We can tell + * if an 875 is part of a PQS/PDS or not since if it is, it will + * be on the same bus as the memory controller. In its usual + * mode of operation, the 875s are slaved to the memory + * controller for all transfers. To operate with the Linux + * driver, the memory controller is disabled and the 875s + * freed to function independently. The only wrinkle is that + * the preset SCSI ID (which may be zero) must be read in from + * a special configuration space register of the 875. + */ +void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev) +{ + int slot; + + for (slot = 0; slot < 256; slot++) { + u8 tmp; + struct pci_dev *memc = pci_get_slot(pdev->bus, slot); + + if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) { + pci_dev_put(memc); + continue; + } + + /* + * We set these bits in the memory controller once per 875. + * This isn't a problem in practice. + */ + + /* bit 1: allow individual 875 configuration */ + pci_read_config_byte(memc, 0x44, &tmp); + tmp |= 0x2; + pci_write_config_byte(memc, 0x44, tmp); + + /* bit 2: drive individual 875 interrupts to the bus */ + pci_read_config_byte(memc, 0x45, &tmp); + tmp |= 0x4; + pci_write_config_byte(memc, 0x45, tmp); + + pci_read_config_byte(pdev, 0x84, &tmp); + sym_dev->host_id = tmp; + + pci_dev_put(memc); + + break; + } +} /* * Called before unloading the module. @@ -2221,79 +2290,6 @@ #endif }; -#ifdef _SYM_CONF_PQS_PDS_SUPPORT -#if 0 -/* - * Detect all NCR PQS/PDS boards and keep track of their bus nr. - * - * The NCR PQS or PDS card is constructed as a DEC bridge - * behind which sit a proprietary NCR memory controller and - * four or two 53c875s as separate devices. In its usual mode - * of operation, the 875s are slaved to the memory controller - * for all transfers. We can tell if an 875 is part of a - * PQS/PDS or not since if it is, it will be on the same bus - * as the memory controller. To operate with the Linux - * driver, the memory controller is disabled and the 875s - * freed to function independently. The only wrinkle is that - * the preset SCSI ID (which may be zero) must be read in from - * a special configuration space register of the 875 - */ -#ifndef SYM_CONF_MAX_PQS_BUS -#define SYM_CONF_MAX_PQS_BUS 16 -#endif -static int pqs_bus[SYM_CONF_MAX_PQS_BUS] __initdata = { 0 }; - -static void __init sym_detect_pqs_pds(void) -{ - short index; - struct pci_dev *dev = NULL; - - for(index=0; index < SYM_CONF_MAX_PQS_BUS; index++) { - u_char tmp; - - dev = pci_find_device(0x101a, 0x0009, dev); - if (dev == NULL) { - pqs_bus[index] = -1; - break; - } - printf_info(NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", dev->bus->number); - pci_read_config_byte(dev, 0x44, &tmp); - /* bit 1: allow individual 875 configuration */ - tmp |= 0x2; - pci_write_config_byte(dev, 0x44, tmp); - pci_read_config_byte(dev, 0x45, &tmp); - /* bit 2: drive individual 875 interrupts to the bus */ - tmp |= 0x4; - pci_write_config_byte(dev, 0x45, tmp); - - pqs_bus[index] = dev->bus->number; - } -} -#endif - -static int pqs_probe() -{ -} - -static void pqs_remove() -{ -} - -static struct pci_device_id pqs_id_table[] __devinitdata = { - { 0x101a, 0x0009, }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, pqs_id_table); - -static struct pci_driver pqs_driver = { - .name = NAME53C8XX " (PQS)", - .id_table = pqs_id_table, - .probe = pqs_probe, - .remove = __devexit_p(pqs_remove), -}; -#endif /* PQS */ - static int attach_count; static int __devinit sym2_probe(struct pci_dev *pdev, @@ -2318,6 +2314,8 @@ if (sym53c8xx_pci_init(pdev, &sym_dev)) goto free; + sym_config_pqs(pdev, &sym_dev); + sym_get_nvram(&sym_dev, &nvram); instance = sym_attach(&sym2_template, attach_count, &sym_dev); @@ -2406,9 +2404,6 @@ static int __init sym2_init(void) { -#ifdef _SYM_CONF_PQS_PDS_SUPPORT - pci_register_driver(&pqs_driver); -#endif pci_register_driver(&sym2_driver); return 0; } @@ -2416,9 +2411,6 @@ static void __exit sym2_exit(void) { pci_unregister_driver(&sym2_driver); -#ifdef _SYM_CONF_PQS_PDS_SUPPORT - pci_unregister_driver(&pqs_driver); -#endif } module_init(sym2_init); diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h --- a/drivers/scsi/sym53c8xx_2/sym_glue.h Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h Sat Apr 3 19:38:56 2004 @@ -77,9 +77,9 @@ /* * General driver includes. */ -#include "sym_misc.h" #include "sym_conf.h" #include "sym_defs.h" +#include "sym_misc.h" /* * Configuration addendum for Linux. @@ -113,6 +113,26 @@ #define sym_mdelay(ms) mdelay(ms) /* + * A 'read barrier' flushes any data that have been prefetched + * by the processor due to out of order execution. Such a barrier + * must notably be inserted prior to looking at data that have + * been DMAed, assuming that program does memory READs in proper + * order and that the device ensured proper ordering of WRITEs. + * + * A 'write barrier' prevents any previous WRITEs to pass further + * WRITEs. Such barriers must be inserted each time another agent + * relies on ordering of WRITEs. + * + * Note that, due to posting of PCI memory writes, we also must + * insert dummy PCI read transactions when some ordering involving + * both directions over the PCI does matter. PCI transactions are + * fully ordered in each direction. + */ + +#define MEMORY_READ_BARRIER() rmb() +#define MEMORY_WRITE_BARRIER() wmb() + +/* * Let the compiler know about driver data structure names. */ typedef struct sym_tcb *tcb_p; @@ -413,6 +433,8 @@ char inst_name[16]; }; +struct sym_nvram; + struct sym_device { struct pci_dev *pdev; struct sym_slot s; @@ -420,12 +442,7 @@ struct sym_nvram *nvram; u_short device_id; u_char host_id; -#ifdef SYM_CONF_PQS_PDS_SUPPORT - u_char pqs_pds; -#endif }; - -typedef struct sym_device *sdev_p; /* * The driver definitions (sym_hipd.h) must know about a diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c Sat Apr 3 19:38:40 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c Sat Apr 3 19:38:40 2004 @@ -50,13 +50,10 @@ * SUCH DAMAGE. */ -#define SYM_DRIVER_NAME "sym-2.1.18f" +#define SYM_DRIVER_NAME "sym-2.1.18i" -#ifdef __FreeBSD__ -#include -#else #include "sym_glue.h" -#endif +#include "sym_nvram.h" #if 0 #define SYM_DEBUG_GENERIC_SUPPORT @@ -616,8 +613,7 @@ if (dt) { fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ - } - else { + } else { fak = (kpc - 1) / div_10M[div] + 1 - 4; /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ } @@ -625,8 +621,10 @@ /* * Check against our hardware limits, or bugs :). */ - if (fak < 0) {fak = 0; ret = -1;} - if (fak > 2) {fak = 2; ret = -1;} + if (fak > 2) { + fak = 2; + ret = -1; + } /* * Compute and return sync parameters. @@ -1054,8 +1052,9 @@ sym_nvram_setup_target (np, i, nvram); /* - * For now, guess PPR/DT support from the period - * and BUS width. + * Some single-ended devices may crash on receiving a + * PPR negotiation attempt. Only try PPR if we're in + * LVD mode. */ if (np->features & FE_ULTRA3) { tp->tinfo.user.options |= PPR_OPT_DT; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h Sat Apr 3 19:38:42 2004 @@ -171,6 +171,15 @@ #define SYM_CONF_MIN_ASYNC (40) /* + * Shortest memory chunk is (1<hcb_ba + offsetof(struct sym_hcb, lbl)) -/* - * NVRAM reading (sym_nvram.c). - */ -#if SYM_CONF_NVRAM_SUPPORT -void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram); -void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp); -int sym_read_nvram (sdev_p np, struct sym_nvram *nvp); -#else -static inline void sym_nvram_setup_host(hcb_p np, struct sym_nvram *nvram) { } -static inline void sym_nvram_setup_target(hcb_p np, struct sym_nvram *nvram) { } -static inline int sym_read_nvram(sdev_p np, struct sym_nvram *nvp) -{ - nvp->type = 0; - return 0; -} -#endif - /* * FIRMWARES (sym_fw.c) @@ -1257,8 +1234,8 @@ * Set up data pointers used by SCRIPTS. * Called from O/S specific code. */ -static void __inline -sym_setup_data_pointers(hcb_p np, ccb_p cp, int dir) +static inline void sym_setup_data_pointers(struct sym_hcb *np, + struct sym_ccb *cp, int dir) { u32 lastp, goalp; @@ -1321,15 +1298,6 @@ /* * MEMORY ALLOCATOR. */ - -/* - * Shortest memory chunk is (1<inq_byte56; if (inq_version >= 4 && inq_len > 56) - tp->inq_byte56 = inq_data[56]; + inq_byte56 = inq_data[56]; #if 0 printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n", inq_len, inq_version, inq_byte7, inq_byte56); @@ -328,6 +328,7 @@ tp->inq_byte56 != inq_byte56) { tp->inq_version = inq_version; tp->inq_byte7 = inq_byte7; + tp->inq_byte56 = inq_byte56; return 1; } return 0; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h --- a/drivers/scsi/sym53c8xx_2/sym_misc.h Sat Apr 3 19:38:56 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h Sat Apr 3 19:38:56 2004 @@ -54,41 +54,6 @@ #define SYM_MISC_H /* - * A 'read barrier' flushes any data that have been prefetched - * by the processor due to out of order execution. Such a barrier - * must notably be inserted prior to looking at data that have - * been DMAed, assuming that program does memory READs in proper - * order and that the device ensured proper ordering of WRITEs. - * - * A 'write barrier' prevents any previous WRITEs to pass further - * WRITEs. Such barriers must be inserted each time another agent - * relies on ordering of WRITEs. - * - * Note that, due to posting of PCI memory writes, we also must - * insert dummy PCI read transactions when some ordering involving - * both directions over the PCI does matter. PCI transactions are - * fully ordered in each direction. - * - * IA32 processors insert implicit barriers when the processor - * accesses unchacheable either for reading or writing, and - * donnot reorder WRITEs. As a result, some 'read barriers' can - * be avoided (following access to uncacheable), and 'write - * barriers' should be useless (preventing compiler optimizations - * should be enough). - */ - -#define __READ_BARRIER() rmb() -#define __WRITE_BARRIER() wmb() - -#ifndef MEMORY_READ_BARRIER -#define MEMORY_READ_BARRIER() __READ_BARRIER() -#endif -#ifndef MEMORY_WRITE_BARRIER -#define MEMORY_WRITE_BARRIER() __WRITE_BARRIER() -#endif - - -/* * A la VMS/CAM-3 queue management. */ typedef struct sym_quehead { @@ -222,48 +187,11 @@ #define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f))) /* - * Portable but silly implemented byte order primitives. - */ -#if BYTE_ORDER == BIG_ENDIAN - -#define __revb16(x) ( (((u16)(x) & (u16)0x00ffU) << 8) | \ - (((u16)(x) & (u16)0xff00U) >> 8) ) -#define __revb32(x) ( (((u32)(x) & 0x000000ffU) << 24) | \ - (((u32)(x) & 0x0000ff00U) << 8) | \ - (((u32)(x) & 0x00ff0000U) >> 8) | \ - (((u32)(x) & 0xff000000U) >> 24) ) - -#define __htole16(v) __revb16(v) -#define __htole32(v) __revb32(v) -#define __le16toh(v) __htole16(v) -#define __le32toh(v) __htole32(v) - -static __inline u16 _htole16(u16 v) { return __htole16(v); } -static __inline u32 _htole32(u32 v) { return __htole32(v); } -#define _le16toh _htole16 -#define _le32toh _htole32 - -#else /* LITTLE ENDIAN */ - -#define __htole16(v) (v) -#define __htole32(v) (v) -#define __le16toh(v) (v) -#define __le32toh(v) (v) - -#define _htole16(v) (v) -#define _htole32(v) (v) -#define _le16toh(v) (v) -#define _le32toh(v) (v) - -#endif /* BYTE_ORDER */ - -/* * The below round up/down macros are to be used with a constant * as argument (sizeof(...) for example), for the compiler to * optimize the whole thing. */ #define _U_(a,m) (a)<=(1< -#else #include "sym_glue.h" -#endif +#include "sym_nvram.h" /* * Some poor and bogus sync table that refers to Tekram NVRAM layout. @@ -246,8 +243,8 @@ } } #else -static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { } -static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { } +static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } +static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } #endif /* SYM_CONF_DEBUG_NVRAM */ @@ -382,6 +379,61 @@ S24C16_write_ack(np, ack_data, gpreg, gpcntl); } + +#if SYM_CONF_NVRAM_WRITE_SUPPORT +/* + * Write 'len' bytes starting at 'offset'. + */ +static int sym_write_S24C16_nvram(struct sym_device *np, int offset, + u_char *data, int len) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_char ack_data; + int x; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + gpcntl = old_gpcntl & 0x1c; + + /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ + OUTB (nc_gpreg, old_gpreg); + OUTB (nc_gpcntl, gpcntl); + + /* this is to set NVRAM into a known state with GPIO0/1 both low */ + gpreg = old_gpreg; + S24C16_set_bit(np, 0, &gpreg, CLR_CLK); + S24C16_set_bit(np, 0, &gpreg, CLR_BIT); + + /* now set NVRAM inactive with GPIO0/1 both high */ + S24C16_stop(np, &gpreg); + + /* NVRAM has to be written in segments of 16 bytes */ + for (x = 0; x < len ; x += 16) { + do { + S24C16_start(np, &gpreg); + S24C16_write_byte(np, &ack_data, + 0xa0 | (((offset+x) >> 7) & 0x0e), + &gpreg, &gpcntl); + } while (ack_data & 0x01); + + S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, + &gpreg, &gpcntl); + + for (y = 0; y < 16; y++) + S24C16_write_byte(np, &ack_data, data[x+y], + &gpreg, &gpcntl); + S24C16_stop(np, &gpreg); + } + + /* return GPIO0/1 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return 0; +} +#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ /* * Read 'len' bytes starting at 'offset'. diff -Nru a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,216 @@ +/* + * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family + * of PCI-SCSI IO processors. + * + * Copyright (C) 1999-2001 Gerard Roudier + * + * This driver is derived from the Linux sym53c8xx driver. + * Copyright (C) 1998-2000 Gerard Roudier + * + * The sym53c8xx driver is derived from the ncr53c8xx driver that had been + * a port of the FreeBSD ncr driver to Linux-1.2.13. + * + * The original ncr driver has been written for 386bsd and FreeBSD by + * Wolfgang Stanglmeier + * Stefan Esser + * Copyright (C) 1994 Wolfgang Stanglmeier + * + * Other major contributions: + * + * NVRAM detection and reading. + * Copyright (C) 1997 Richard Waltham + * + *----------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SYM_NVRAM_H +#define SYM_NVRAM_H + +#include "sym_conf.h" + +/* + * Symbios NVRAM data format + */ +#define SYMBIOS_NVRAM_SIZE 368 +#define SYMBIOS_NVRAM_ADDRESS 0x100 + +struct Symbios_nvram { +/* Header 6 bytes */ + u_short type; /* 0x0000 */ + u_short byte_count; /* excluding header/trailer */ + u_short checksum; + +/* Controller set up 20 bytes */ + u_char v_major; /* 0x00 */ + u_char v_minor; /* 0x30 */ + u32 boot_crc; + u_short flags; +#define SYMBIOS_SCAM_ENABLE (1) +#define SYMBIOS_PARITY_ENABLE (1<<1) +#define SYMBIOS_VERBOSE_MSGS (1<<2) +#define SYMBIOS_CHS_MAPPING (1<<3) +#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ + u_short flags1; +#define SYMBIOS_SCAN_HI_LO (1) + u_short term_state; +#define SYMBIOS_TERM_CANT_PROGRAM (0) +#define SYMBIOS_TERM_ENABLED (1) +#define SYMBIOS_TERM_DISABLED (2) + u_short rmvbl_flags; +#define SYMBIOS_RMVBL_NO_SUPPORT (0) +#define SYMBIOS_RMVBL_BOOT_DEVICE (1) +#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) + u_char host_id; + u_char num_hba; /* 0x04 */ + u_char num_devices; /* 0x10 */ + u_char max_scam_devices; /* 0x04 */ + u_char num_valid_scam_devices; /* 0x00 */ + u_char flags2; +#define SYMBIOS_AVOID_BUS_RESET (1<<2) + +/* Boot order 14 bytes * 4 */ + struct Symbios_host{ + u_short type; /* 4:8xx / 0:nok */ + u_short device_id; /* PCI device id */ + u_short vendor_id; /* PCI vendor id */ + u_char bus_nr; /* PCI bus number */ + u_char device_fn; /* PCI device/function number << 3*/ + u_short word8; + u_short flags; +#define SYMBIOS_INIT_SCAN_AT_BOOT (1) + u_short io_port; /* PCI io_port address */ + } host[4]; + +/* Targets 8 bytes * 16 */ + struct Symbios_target { + u_char flags; +#define SYMBIOS_DISCONNECT_ENABLE (1) +#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) +#define SYMBIOS_SCAN_LUNS (1<<2) +#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) + u_char rsvd; + u_char bus_width; /* 0x08/0x10 */ + u_char sync_offset; + u_short sync_period; /* 4*period factor */ + u_short timeout; + } target[16]; +/* Scam table 8 bytes * 4 */ + struct Symbios_scam { + u_short id; + u_short method; +#define SYMBIOS_SCAM_DEFAULT_METHOD (0) +#define SYMBIOS_SCAM_DONT_ASSIGN (1) +#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) +#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) + u_short status; +#define SYMBIOS_SCAM_UNKNOWN (0) +#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) +#define SYMBIOS_SCAM_ID_NOT_SET (2) +#define SYMBIOS_SCAM_ID_VALID (3) + u_char target_id; + u_char rsvd; + } scam[4]; + + u_char spare_devices[15*8]; + u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ +}; +typedef struct Symbios_nvram Symbios_nvram; +typedef struct Symbios_host Symbios_host; +typedef struct Symbios_target Symbios_target; +typedef struct Symbios_scam Symbios_scam; + +/* + * Tekram NvRAM data format. + */ +#define TEKRAM_NVRAM_SIZE 64 +#define TEKRAM_93C46_NVRAM_ADDRESS 0 +#define TEKRAM_24C16_NVRAM_ADDRESS 0x40 + +struct Tekram_nvram { + struct Tekram_target { + u_char flags; +#define TEKRAM_PARITY_CHECK (1) +#define TEKRAM_SYNC_NEGO (1<<1) +#define TEKRAM_DISCONNECT_ENABLE (1<<2) +#define TEKRAM_START_CMD (1<<3) +#define TEKRAM_TAGGED_COMMANDS (1<<4) +#define TEKRAM_WIDE_NEGO (1<<5) + u_char sync_index; + u_short word2; + } target[16]; + u_char host_id; + u_char flags; +#define TEKRAM_MORE_THAN_2_DRIVES (1) +#define TEKRAM_DRIVES_SUP_1GB (1<<1) +#define TEKRAM_RESET_ON_POWER_ON (1<<2) +#define TEKRAM_ACTIVE_NEGATION (1<<3) +#define TEKRAM_IMMEDIATE_SEEK (1<<4) +#define TEKRAM_SCAN_LUNS (1<<5) +#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */ + /* 1: boot device; 2:all */ + u_char boot_delay_index; + u_char max_tags_index; + u_short flags1; +#define TEKRAM_F2_F6_ENABLED (1) + u_short spare[29]; +}; +typedef struct Tekram_nvram Tekram_nvram; +typedef struct Tekram_target Tekram_target; + +/* + * Union of supported NVRAM formats. + */ +struct sym_nvram { + int type; +#define SYM_SYMBIOS_NVRAM (1) +#define SYM_TEKRAM_NVRAM (2) +#if SYM_CONF_NVRAM_SUPPORT + union { + Symbios_nvram Symbios; + Tekram_nvram Tekram; + } data; +#endif +}; + +#if SYM_CONF_NVRAM_SUPPORT +void sym_nvram_setup_host (struct sym_hcb *np, struct sym_nvram *nvram); +void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp); +int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp); +#else +static inline void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) { } +static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { } +static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) +{ + nvp->type = 0; + return 0; +} +#endif + +#endif /* SYM_NVRAM_H */ diff -Nru a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h --- a/drivers/scsi/sym53c8xx_comm.h Sat Apr 3 19:38:43 2004 +++ b/drivers/scsi/sym53c8xx_comm.h Sat Apr 3 19:38:43 2004 @@ -703,7 +703,8 @@ #define __unmap_scsi_data(dev, cmd) do {; } while (0) #define __map_scsi_single_data(dev, cmd) (__vtobus(dev,(cmd)->request_buffer)) #define __map_scsi_sg_data(dev, cmd) ((cmd)->use_sg) -#define __sync_scsi_data(dev, cmd) do {; } while (0) +#define __sync_scsi_data_for_cpu(dev, cmd) do {; } while (0) +#define __sync_scsi_data_for_device(dev, cmd) do {; } while (0) #define scsi_sg_dma_address(sc) vtobus((sc)->address) #define scsi_sg_dma_len(sc) ((sc)->length) @@ -767,18 +768,34 @@ return use_sg; } -static void __sync_scsi_data(struct device *dev, Scsi_Cmnd *cmd) +static void __sync_scsi_data_for_cpu(struct device *dev, Scsi_Cmnd *cmd) { enum dma_data_direction dma_dir = (enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction); switch(cmd->__data_mapped) { case 2: - dma_sync_sg(dev, cmd->buffer, cmd->use_sg, dma_dir); + dma_sync_sg_for_cpu(dev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - dma_sync_single(dev, cmd->__data_mapping, - cmd->request_bufflen, dma_dir); + dma_sync_single_for_cpu(dev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +static void __sync_scsi_data_for_device(struct device *dev, Scsi_Cmnd *cmd) +{ + enum dma_data_direction dma_dir = + (enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + dma_sync_sg_for_device(dev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + dma_sync_single_for_device(dev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); break; } } @@ -791,7 +808,8 @@ #define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd) #define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->dev, cmd) #define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd) -#define sync_scsi_data(np, cmd) __sync_scsi_data(np->dev, cmd) +#define sync_scsi_data_for_cpu(np, cmd) __sync_scsi_data_for_cpu(np->dev, cmd) +#define sync_scsi_data_for_device(np, cmd) __sync_scsi_data_for_device(np->dev, cmd) /*========================================================== ** diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Sat Apr 3 19:38:42 2004 +++ b/drivers/scsi/u14-34f.c Sat Apr 3 19:38:42 2004 @@ -1184,17 +1184,17 @@ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; if (DEV2H(cpp->data_address)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), DEV2H(cpp->data_len), pci_dir); } diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c --- a/drivers/scsi/wd33c93.c Sat Apr 3 19:38:45 2004 +++ b/drivers/scsi/wd33c93.c Sat Apr 3 19:38:45 2004 @@ -2056,7 +2056,7 @@ return 0; } if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ - stop = 1;; + stop = 1; if (hd->proc & PR_STOP) /* stop every other time */ stop = 1; return strlen(bp); diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c --- a/drivers/serial/21285.c Sat Apr 3 19:38:54 2004 +++ b/drivers/serial/21285.c Sat Apr 3 19:38:54 2004 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -510,6 +511,7 @@ .owner = THIS_MODULE, .driver_name = "ttyFB", .dev_name = "ttyFB", + .devfs_name = "ttyFB", .major = SERIAL_21285_MAJOR, .minor = SERIAL_21285_MINOR, .nr = 1, @@ -542,3 +544,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $"); +MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c Sat Apr 3 19:38:41 2004 +++ b/drivers/serial/8250.c Sat Apr 3 19:38:41 2004 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -2194,3 +2195,4 @@ MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif +MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); diff -Nru a/drivers/serial/8250_acpi.c b/drivers/serial/8250_acpi.c --- a/drivers/serial/8250_acpi.c Sat Apr 3 19:38:56 2004 +++ b/drivers/serial/8250_acpi.c Sat Apr 3 19:38:56 2004 @@ -134,8 +134,7 @@ } serial_req.baud_base = BASE_BAUD; - serial_req.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | - UPF_AUTO_IRQ | UPF_RESOURCES; + serial_req.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES; priv->line = register_serial(&serial_req); if (priv->line < 0) { diff -Nru a/drivers/serial/8250_hcdp.c b/drivers/serial/8250_hcdp.c --- a/drivers/serial/8250_hcdp.c Sat Apr 3 19:38:55 2004 +++ b/drivers/serial/8250_hcdp.c Sat Apr 3 19:38:55 2004 @@ -186,8 +186,6 @@ port.irq = gsi; #endif port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES; - if (gsi) - port.flags |= ASYNC_AUTO_IRQ; /* * Note: the above memset() initializes port.line to 0, diff -Nru a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c --- a/drivers/serial/8250_pnp.c Sat Apr 3 19:38:41 2004 +++ b/drivers/serial/8250_pnp.c Sat Apr 3 19:38:41 2004 @@ -266,6 +266,8 @@ { "RSS00A0", 0 }, /* Viking 56K FAX INT */ { "RSS0262", 0 }, + /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */ + { "RSS0250", 0 }, /* SupraExpress 28.8 Data/Fax PnP modem */ { "SUP1310", 0 }, /* SupraExpress 33.6 Data/Fax PnP modem */ @@ -283,6 +285,8 @@ /* 3Com Corp. */ /* Gateway Telepath IIvi 33.6 */ { "USR0000", 0 }, + /* U.S. Robotics Sporster 33.6K Fax INT PnP */ + { "USR0002", 0 }, /* Sportster Vi 14.4 PnP FAX Voicemail */ { "USR0004", 0 }, /* U.S. Robotics 33.6K Voice INT PnP */ @@ -315,6 +319,8 @@ { "USR9180", 0 }, /* U.S. Robotics 56K Voice INT PnP*/ { "USR9190", 0 }, + /* Rockwell's (PORALiNK) 33600 INT PNP */ + { "WCI0003", 0 }, /* Unkown PnP modems */ { "PNPCXXX", UNKNOWN_DEV }, /* More unkown PnP modems */ @@ -390,7 +396,7 @@ return -ENODEV; } -static int +static int __devinit serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) { struct serial_struct serial_req; @@ -420,7 +426,7 @@ } -static void serial_pnp_remove(struct pnp_dev * dev) +static void __devexit serial_pnp_remove(struct pnp_dev * dev) { int line = (int)pnp_get_drvdata(dev); if (line) diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig Sat Apr 3 19:38:55 2004 +++ b/drivers/serial/Kconfig Sat Apr 3 19:38:55 2004 @@ -1,7 +1,7 @@ # # Serial device configuration # -# $Id: Config.in,v 1.15 2002/07/06 17:16:24 rmk Exp $ +# $Id: Kconfig,v 1.11 2004/03/11 18:08:04 lethal Exp $ # menu "Serial drivers" @@ -174,32 +174,6 @@ system, say Y to this option. The driver can handle 1, 2, or 3 port cards. If unsure, say N. -config SERIAL_ANAKIN - bool "Anakin serial port support" - depends on ARM && ARCH_ANAKIN - select SERIAL_CORE - help - ::: To be written ::: - -config SERIAL_ANAKIN_CONSOLE - bool "Console on Anakin serial port" - depends on SERIAL_ANAKIN - select SERIAL_CORE_CONSOLE - help - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyAN0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config ANAKIN_DEFAULT_BAUDRATE - int "Default Anakin serial baudrate" - depends on SERIAL_ANAKIN - default "9600" - help - ::: To be written ::: - config SERIAL_AMBA tristate "ARM AMBA serial port support" depends on ARM_AMBA @@ -501,6 +475,16 @@ config SERIAL98_CONSOLE bool "Support for console on PC-9800 standard serial port" depends on SERIAL98=y + select SERIAL_CORE_CONSOLE + +config SERIAL_SH_SCI + tristate "SH SCI(F) serial port support" + depends on SUPERH + select SERIAL_CORE + +config SERIAL_SH_SCI_CONSOLE + bool "Support for console on SH SCI(F)" + depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE config SERIAL_AU1X00 diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Sat Apr 3 19:38:43 2004 +++ b/drivers/serial/Makefile Sat Apr 3 19:38:43 2004 @@ -16,7 +16,6 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o -obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o obj-$(CONFIG_SERIAL_AMBA) += amba.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA) += pxa.o @@ -36,3 +35,4 @@ obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o obj-$(CONFIG_SERIAL_DZ) += dz.o +obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c --- a/drivers/serial/amba.c Sat Apr 3 19:38:41 2004 +++ b/drivers/serial/amba.c Sat Apr 3 19:38:41 2004 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -758,3 +759,4 @@ MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR); diff -Nru a/drivers/serial/anakin.c b/drivers/serial/anakin.c --- a/drivers/serial/anakin.c Sat Apr 3 19:38:42 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,543 +0,0 @@ -/* - * linux/drivers/char/anakin.c - * - * Based on driver for AMBA serial ports, by ARM Limited, - * Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o. - * - * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. - * - * Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 20-Apr-2001 TTC Created - * 05-May-2001 W/TTC Updated for serial_core.c - * 27-Jun-2001 jonm Minor changes; add mctrl support, switch to - * SA_INTERRUPT. Works reliably now. No longer requires - * changes to the serial_core API. - * - * $Id: anakin.c,v 1.32 2002/07/28 10:03:27 rmk Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#define UART_NR 5 - -#define SERIAL_ANAKIN_NAME "ttyAN" -#define SERIAL_ANAKIN_MAJOR 204 -#define SERIAL_ANAKIN_MINOR 32 - -static unsigned int txenable[NR_IRQS]; /* Software interrupt register */ - -static inline unsigned int -anakin_in(struct uart_port *port, unsigned int offset) -{ - return __raw_readl(port->base + offset); -} - -static inline void -anakin_out(struct uart_port *port, unsigned int offset, unsigned int value) -{ - __raw_writel(value, port->base + offset); -} - -static void -anakin_stop_tx(struct uart_port *port, unsigned int tty_stop) -{ - txenable[port->irq] = 0; -} - -static inline void -anakin_transmit_buffer(struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - - while (!(anakin_in(port, 0x10) & TXEMPTY)) - barrier(); - anakin_out(port, 0x14, xmit->buf[xmit->tail]); - anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); - port->icount.tx++; - - if (uart_circ_empty(xmit)) - anakin_stop_tx(port, 0); -} - -static inline void -anakin_transmit_x_char(struct uart_port *port) -{ - anakin_out(port, 0x14, port->x_char); - anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); - port->icount.tx++; - port->x_char = 0; -} - -static void -anakin_start_tx(struct uart_port *port, unsigned int tty_start) -{ - // is it this... or below - if (!txenable[port->irq]) { - txenable[port->irq] = TXENABLE; - - if ((anakin_in(port, 0x10) & TXEMPTY)) { - anakin_transmit_buffer(port); - } - } -} - -static void -anakin_stop_rx(struct uart_port *port) -{ - while (anakin_in(port, 0x10) & RXRELEASE) - anakin_in(port, 0x14); - anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX); -} - -static void -anakin_enable_ms(struct uart_port *port) -{ -} - -static inline void -anakin_rx_chars(struct uart_port *port) -{ - unsigned int ch; - struct tty_struct *tty = port->info->tty; - - if (!(anakin_in(port, 0x10) & RXRELEASE)) - return; - - ch = anakin_in(port, 0x14) & 0xff; - - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.char_buf_ptr++ = ch; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - port->icount.rx++; - tty->flip.count++; - } - tty_flip_buffer_push(tty); -} - -static inline void -anakin_overrun_chars(struct uart_port *port) -{ - unsigned int ch; - - ch = anakin_in(port, 0x14); - port->icount.overrun++; -} - -static inline void -anakin_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - - if (port->x_char) { - anakin_transmit_x_char(port); - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - anakin_stop_tx(port, 0); - return; - } - - anakin_transmit_buffer(port); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static void -anakin_int(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int status; - struct uart_port *port = dev_id; - - status = anakin_in(port, 0x1c); - - if (status & RX) - anakin_rx_chars(port); - - if (status & OVERRUN) - anakin_overrun_chars(port); - - if (txenable[port->irq] && (status & TX)) - anakin_tx_chars(port); -} - -static unsigned int -anakin_tx_empty(struct uart_port *port) -{ - return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int -anakin_get_mctrl(struct uart_port *port) -{ - unsigned int status = 0; - - status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0); - status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0); - status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0); - status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0); - - return status; -} - -static void -anakin_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned int status; - - status = anakin_in(port, 0x18); - - if (mctrl & TIOCM_RTS) - status |= RTS; - else - status &= ~RTS; - - if (mctrl & TIOCM_CAR) - status |= DCD; - else - status &= ~DCD; - - anakin_out(port, 0x18, status); -} - -static void -anakin_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - unsigned int status; - - spin_lock_irqsave(&port->lock, flags); - status = anakin_in(port, 0x20); - - if (break_state == -1) - status |= SETBREAK; - else - status &= ~SETBREAK; - - anakin_out(port, 0x20, status); - spin_unlock_irqrestore(&port->lock, flags); -} - -static int anakin_startup(struct uart_port *port) -{ - int retval; - unsigned int read,write; - - /* - * Allocate the IRQ - */ - retval = request_irq(port->irq, anakin_int, SA_INTERRUPT, - "serial_anakin", port); - if (retval) - return retval; - - /* - * initialise the old status of the modem signals - */ - port->old_status = 0; - - /* - * Finally, disable IRQ and softIRQs for first byte) - */ - txenable[port->irq] = 0; - read = anakin_in(port, 0x18); - write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE; - anakin_out(port, 0x18, write); - - return 0; -} - -static void anakin_shutdown(struct uart_port *port) -{ - /* - * Free the interrupt - */ - free_irq(port->irq, port); - - /* - * disable all interrupts, disable the port - */ - anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE); -} - -static void -anakin_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) -{ - unsigned long flags; - unsigned int baud, quot; - - /* - * We don't support parity, stop bits, or anything other - * than 8 bits, so clear these termios flags. - */ - termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CREAD); - termios->c_cflag |= CS8; - - /* - * We don't appear to support any error conditions either. - */ - termios->c_iflag &= ~(INPCK | IGNPAR | IGNBRK | BRKINT); - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&port->lock, flags); - - uart_update_timeout(port, termios->c_cflag, baud); - - while (!(anakin_in(port, 0x10) & TXEMPTY)) - barrier(); - - anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER) - | (quot << 3)); - - //parity always set to none - anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY); - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *anakin_type(struct port *port) -{ - return port->type == PORT_ANAKIN ? "ANAKIN" : NULL; -} - -static struct uart_ops anakin_pops = { - .tx_empty = anakin_tx_empty, - .set_mctrl = anakin_set_mctrl, - .get_mctrl = anakin_get_mctrl, - .stop_tx = anakin_stop_tx, - .start_tx = anakin_start_tx, - .stop_rx = anakin_stop_rx, - .enable_ms = anakin_enable_ms, - .break_ctl = anakin_break_ctl, - .startup = anakin_startup, - .shutdown = anakin_shutdown, - .set_termios = anakin_set_termios, - .type = anakin_type, -}; - -static struct uart_port anakin_ports[UART_NR] = { - { - .base = IO_BASE + UART0, - .irq = IRQ_UART0, - .uartclk = 3686400, - .fifosize = 0, - .ops = &anakin_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 0, - }, - { - .base = IO_BASE + UART1, - .irq = IRQ_UART1, - .uartclk = 3686400, - .fifosize = 0, - .ops = &anakin_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 1, - }, - { - .base = IO_BASE + UART2, - .irq = IRQ_UART2, - .uartclk = 3686400, - .fifosize = 0, - .ops = &anakin_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 2, - }, - { - .base = IO_BASE + UART3, - .irq = IRQ_UART3, - .uartclk = 3686400, - .fifosize = 0, - .ops = &anakin_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 3, - }, - { - .base = IO_BASE + UART4, - .irq = IRQ_UART4, - .uartclk = 3686400, - .fifosize = 0, - .ops = &anakin_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 4, - }, -}; - - -#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE - -static void -anakin_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_port *port = &anakin_ports[co->index]; - unsigned int flags, status, i; - - /* - * First save the status then disable the interrupts - */ - local_irq_save(flags); - status = anakin_in(port, 0x18); - anakin_out(port, 0x18, status & ~IRQENABLE); - local_irq_restore(flags); - - /* - * Now, do each character - */ - for (i = 0; i < count; i++, s++) { - while (!(anakin_in(port, 0x10) & TXEMPTY)) - barrier(); - - /* - * Send the character out. - * If a LF, also do CR... - */ - anakin_out(port, 0x14, *s); - anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); - - if (*s == 10) { - while (!(anakin_in(port, 0x10) & TXEMPTY)) - barrier(); - anakin_out(port, 0x14, 13); - anakin_out(port, 0x18, anakin_in(port, 0x18) - | SENDREQUEST); - } - } - - /* - * Finally, wait for transmitter to become empty - * and restore the interrupts - */ - while (!(anakin_in(port, 0x10) & TXEMPTY)) - barrier(); - - if (status & IRQENABLE) { - local_irq_save(flags); - anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE); - local_irq_restore(flags); - } -} - -/* - * Read the current UART setup. - */ -static void __init -anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -{ - int paritycode; - - *baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER); - paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY); - switch (paritycode) { - case NONEPARITY: *parity = 'n'; break; - case ODDPARITY: *parity = 'o'; break; - case EVENPARITY: *parity = 'e'; break; - } - *bits = 8; -} - -static int __init -anakin_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE; - int bits = 8; - int parity = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - port = &anakin_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits); - else - anakin_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits); -} - -extern struct uart_driver anakin_reg; -static struct console anakin_console = { - .name = SERIAL_ANAKIN_NAME, - .write = anakin_console_write, - .device = uart_console_device, - .setup = anakin_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init anakin_console_init(void) -{ - register_console(&anakin_console); - return 0; -} -console_initcall(anakin_console_init); - -#define ANAKIN_CONSOLE &anakin_console -#else -#define ANAKIN_CONSOLE NULL -#endif - -static struct uart_driver anakin_reg = { - .driver_name = SERIAL_ANAKIN_NAME, - .dev_name = SERIAL_ANAKIN_NAME, - .major = SERIAL_ANAKIN_MAJOR, - .minor = SERIAL_ANAKIN_MINOR, - .nr = UART_NR, - .cons = ANAKIN_CONSOLE, -}; - -static int __init -anakin_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: Anakin driver $Revision: 1.32 $\n"); - - ret = uart_register_driver(&anakin_reg); - if (ret == 0) { - int i; - - for (i = 0; i < UART_NR; i++) - uart_add_one_port(&anakin_reg, &anakin_ports[i]); - } - return ret; -} - -__initcall(anakin_init); - -MODULE_DESCRIPTION("Anakin serial driver"); -MODULE_AUTHOR("Tak-Shing Chan "); -MODULE_SUPPORTED_DEVICE("ttyAN"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c --- a/drivers/serial/clps711x.c Sat Apr 3 19:38:42 2004 +++ b/drivers/serial/clps711x.c Sat Apr 3 19:38:42 2004 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -611,3 +612,4 @@ MODULE_AUTHOR("Deep Blue Solutions Ltd"); MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.42 $"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); diff -Nru a/drivers/serial/mux.c b/drivers/serial/mux.c --- a/drivers/serial/mux.c Sat Apr 3 19:38:54 2004 +++ b/drivers/serial/mux.c Sat Apr 3 19:38:54 2004 @@ -25,6 +25,7 @@ #include #include #include /* for udelay */ +#include #include #include @@ -535,3 +536,4 @@ MODULE_AUTHOR("Ryan Bradetich"); MODULE_DESCRIPTION("Serial MUX driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR); diff -Nru a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c --- a/drivers/serial/pmac_zilog.c Sat Apr 3 19:38:40 2004 +++ b/drivers/serial/pmac_zilog.c Sat Apr 3 19:38:40 2004 @@ -1563,15 +1563,21 @@ static int pmz_suspend(struct macio_dev *mdev, u32 pm_state) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state = pmz_uart_reg.state + uap->port.line; + struct uart_state *state; unsigned long flags; - if (uap == NULL) + if (uap == NULL) { + printk("HRM... pmz_suspend with NULL uap\n"); return 0; + } if (pm_state == mdev->ofdev.dev.power_state || pm_state < 2) return 0; + pmz_debug("suspend, switching to state %d\n", pm_state); + + state = pmz_uart_reg.state + uap->port.line; + down(&pmz_irq_sem); down(&state->sem); @@ -1607,6 +1613,8 @@ up(&state->sem); up(&pmz_irq_sem); + pmz_debug("suspend, switching complete\n"); + mdev->ofdev.dev.power_state = pm_state; return 0; @@ -1616,9 +1624,9 @@ static int pmz_resume(struct macio_dev *mdev) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state = pmz_uart_reg.state + uap->port.line; + struct uart_state *state; unsigned long flags; - int pwr_delay; + int pwr_delay = 0; if (uap == NULL) return 0; @@ -1626,6 +1634,10 @@ if (mdev->ofdev.dev.power_state == 0) return 0; + pmz_debug("resume, switching to state 0\n"); + + state = pmz_uart_reg.state + uap->port.line; + down(&pmz_irq_sem); down(&state->sem); @@ -1658,6 +1670,7 @@ enable_irq(uap->port.irq); } + bail: up(&state->sem); up(&pmz_irq_sem); @@ -1670,7 +1683,8 @@ schedule_timeout((pwr_delay * HZ)/1000); } - bail: + pmz_debug("resume, switching complete\n"); + mdev->ofdev.dev.power_state = 0; return 0; @@ -1861,9 +1875,6 @@ /* Get rid of macio-driver (detach from macio) */ macio_unregister_driver(&pmz_driver); - /* Unregister UART driver */ - uart_unregister_driver(&pmz_uart_reg); - for (i = 0; i < pmz_ports_count; i++) { struct uart_pmac_port *uport = &pmz_ports[i]; if (uport->node != NULL) { @@ -1871,6 +1882,8 @@ pmz_dispose_port(uport); } } + /* Unregister UART driver */ + uart_unregister_driver(&pmz_uart_reg); } #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE diff -Nru a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c --- a/drivers/serial/sa1100.c Sat Apr 3 19:38:41 2004 +++ b/drivers/serial/sa1100.c Sat Apr 3 19:38:41 2004 @@ -953,3 +953,4 @@ MODULE_AUTHOR("Deep Blue Solutions Ltd"); MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR); diff -Nru a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/sh-sci.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,1503 @@ +/* + * drivers/serial/sh-sci.c + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * + * Copyright (C) 2002, 2003 Paul Mundt + * + * based off of the old drivers/char/sh-sci.c by: + * + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2000 Sugioka Toshinobu + * Modified to support multiple serial ports. Stuart Menefy (May 2000). + * Modified to support SecureEdge. David McCullough (2002) + * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003). + * + * 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. + */ + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CPU_FREQ +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_SH_STANDARD_BIOS +#include +#endif + +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include "sh-sci.h" + +#ifdef CONFIG_SH_KGDB +#include + +static int kgdb_get_char(struct sci_port *port); +static void kgdb_put_char(struct sci_port *port, char c); +static void kgdb_handle_error(struct sci_port *port); +static struct sci_port *kgdb_sci_port; +#endif /* CONFIG_SH_KGDB */ + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +static struct sci_port *serial_console_port = 0; +#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ + +/* Function prototypes */ +static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop); +static void sci_start_tx(struct uart_port *port, unsigned int tty_start); +static void sci_start_rx(struct uart_port *port, unsigned int tty_start); +static void sci_stop_rx(struct uart_port *port); +static int sci_request_irq(struct sci_port *port); +static void sci_free_irq(struct sci_port *port); + +static struct sci_port sci_ports[SCI_NPORTS]; +static struct uart_driver sci_uart_driver; + +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) + +static void handle_error(struct sci_port *port) +{ /* Clear error flags */ + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); +} + +static int get_char(struct sci_port *port) +{ + unsigned long flags; + unsigned short status; + int c; + + local_irq_save(flags); + do { + status = sci_in(port, SCxSR); + if (status & SCxSR_ERRORS(port)) { + handle_error(port); + continue; + } + } while (!(status & SCxSR_RDxF(port))); + c = sci_in(port, SCxRDR); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + local_irq_restore(flags); + + return c; +} + +/* Taken from sh-stub.c of GDB 4.18 */ +static const char hexchars[] = "0123456789abcdef"; + +static __inline__ char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +static __inline__ char lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ + +/* + * Send the packet in buffer. The host gets one chance to read it. + * This routine does not wait for a positive acknowledge. + */ + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +static void put_char(struct uart_port *port, char c) +{ + unsigned long flags; + unsigned short status; + + local_irq_save(flags); + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TDxE(port))); + + sci_out(port, SCxTDR, c); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + local_irq_restore(flags); +} + +static void put_string(struct sci_port *sci_port, const char *buffer, int count) +{ + struct uart_port *port = &sci_port->port; + const unsigned char *p = buffer; + int i; + +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) + int checksum; + int usegdb=0; + +#ifdef CONFIG_SH_STANDARD_BIOS + /* This call only does a trap the first time it is + * called, and so is safe to do here unconditionally + */ + usegdb |= sh_bios_in_gdb_mode(); +#endif +#ifdef CONFIG_SH_KGDB + usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); +#endif + + if (usegdb) { + /* $#. */ + do { + unsigned char c; + put_char(port, '$'); + put_char(port, 'O'); /* 'O'utput to console */ + checksum = 'O'; + + for (i=0; ibase - SMR0) >> 3; + unsigned char mask = 1 << (ch+1); + + if (ctrl == sci_disable) { + *mstpcrl |= mask; + } else { + *mstpcrl &= ~mask; + } +} +#endif + +#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) +#if defined(__H8300H__) || defined(__H8300S__) +static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag) +{ + int ch = (port->base - SMR0) >> 3; + + /* set DDR regs */ + H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT); + H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT); + /* tx mark output*/ + H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; +} +#else +static void sci_init_pins_sci(struct uart_port *port, unsigned int cflag) +{ +} +#endif +#endif + +#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) +#if defined(CONFIG_CPU_SH3) +/* For SH7707, SH7709, SH7709A, SH7729 */ +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ + ctrl_outw(data&0x0fcf, SCPCR); + } + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + else { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP4MD1,0, + Set SCP6MD1,0 = {01} (output) */ + ctrl_outw((data&0x0fcf)|0x1000, SCPCR); + + data = ctrl_inb(SCPDR); + /* Set /RTS2 (bit6) = 0 */ + ctrl_outb(data&0xbf, SCPDR); + } + sci_out(port, SCFCR, fcr_val); +} + +static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + + sci_out(port, SCFCR, fcr_val); +} + +#else + +/* For SH7750 */ +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) { + fcr_val |= SCFCR_MCE; + } else { + ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ + } + sci_out(port, SCFCR, fcr_val); +} + +#endif +#endif /* SCIF_ONLY || SCI_AND_SCIF */ + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +static void sci_transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + unsigned int stopped = uart_tx_stopped(port); + unsigned long flags; + unsigned short status; + unsigned short ctrl; + int count, txroom; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_TDxE(port))) { + local_irq_save(flags); + ctrl = sci_in(port, SCSCR); + if (uart_circ_empty(xmit)) { + ctrl &= ~SCI_CTRL_FLAGS_TIE; + } else { + ctrl |= SCI_CTRL_FLAGS_TIE; + } + sci_out(port, SCSCR, ctrl); + local_irq_restore(flags); + return; + } + + if (port->type == PORT_SCIF) { + txroom = 16 - (sci_in(port, SCFDR)>>8); + } else { + txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; + } + + count = txroom; + + do { + unsigned char c; + + if (port->x_char) { + c = port->x_char; + port->x_char = 0; + } else if (!uart_circ_empty(xmit) && !stopped) { + c = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else { + break; + } + + sci_out(port, SCxTDR, c); + + port->icount.tx++; + } while (--count > 0); + + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + if (uart_circ_empty(xmit)) { + sci_stop_tx(port, 0); + } else { + local_irq_save(flags); + ctrl = sci_in(port, SCSCR); + + if (port->type == PORT_SCIF) { + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + } + + ctrl |= SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); + local_irq_restore(flags); + } +} + +/* On SH3, SCIF may read end-of-break as a space->mark char */ +#define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); }) + +static inline void sci_receive_chars(struct uart_port *port, + struct pt_regs *regs) +{ + struct tty_struct *tty = port->info->tty; + int i, count, copied = 0; + unsigned short status; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_RDxF(port))) + return; + + while (1) { + if (port->type == PORT_SCIF) { + count = sci_in(port, SCFDR)&0x001f; + } else { + count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; + } + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + count > TTY_FLIPBUF_SIZE) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + /* If for any reason we can't copy more data, we're done! */ + if (count == 0) + break; + + if (port->type == PORT_SCI) { + char c = sci_in(port, SCxRDR); + if(((struct sci_port *)port)->break_flag + || uart_handle_sysrq_char(port, c, regs)) { + count = 0; + } else { + tty->flip.char_buf_ptr[0] = c; + tty->flip.flag_buf_ptr[0] = TTY_NORMAL; + } + } else { + for (i=0; ibreak_flag) { + if ((c == 0) && + (status & SCxSR_FER(port))) { + count--; i--; + continue; + } + /* Nonzero => end-of-break */ + pr_debug("scif: debounce<%02x>\n", c); + ((struct sci_port *)port)->break_flag = 0; + if (STEPFN(c)) { + count--; i--; + continue; + } + } +#endif /* CONFIG_CPU_SH3 */ + if (uart_handle_sysrq_char(port, c, regs)) { + count--; i--; + continue; + } + + /* Store data and status */ + tty->flip.char_buf_ptr[i] = c; + if (status&SCxSR_FER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_FRAME; + pr_debug("sci: frame error\n"); + } else if (status&SCxSR_PER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_PARITY; + pr_debug("sci: parity error\n"); + } else { + tty->flip.flag_buf_ptr[i] = TTY_NORMAL; + } + } + } + + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + + /* Update the kernel buffer end */ + tty->flip.count += count; + tty->flip.char_buf_ptr += count; + tty->flip.flag_buf_ptr += count; + copied += count; + port->icount.rx += count; + } + + if (copied) { + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tty); + } else { + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } +} + +#define SCI_BREAK_JIFFIES (HZ/20) +/* The sci generates interrupts during the break, + * 1 per millisecond or so during the break period, for 9600 baud. + * So dont bother disabling interrupts. + * But dont want more than 1 break event. + * Use a kernel timer to periodically poll the rx line until + * the break is finished. + */ +static void sci_schedule_break_timer(struct sci_port *port) +{ + port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES; + add_timer(&port->break_timer); +} +/* Ensure that two consecutive samples find the break over. */ +static void sci_break_timer(unsigned long data) +{ + struct sci_port * port = (struct sci_port *)data; + if(sci_rxd_in(&port->port) == 0) { + port->break_flag = 1; + sci_schedule_break_timer(port); + } else if(port->break_flag == 1){ + /* break is over. */ + port->break_flag = 2; + sci_schedule_break_timer(port); + } else port->break_flag = 0; +} + +static inline int sci_handle_errors(struct uart_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->info->tty; + + if (status&SCxSR_ORER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + pr_debug("sci: overrun error\n"); + } + + if (status&SCxSR_FER(port) && tty->flip.countbreak_flag) { + sci_port->break_flag = 1; + sci_schedule_break_timer((struct sci_port *)port); + /* Do sysrq handling. */ + if(uart_handle_break(port)) { + return 0; + } + pr_debug("sci: BREAK detected\n"); + copied++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + } + } + else { + /* frame error */ + copied++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + pr_debug("sci: frame error\n"); + } + } + + if (status&SCxSR_PER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_PARITY; + pr_debug("sci: parity error\n"); + } + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + +static inline int sci_handle_breaks(struct uart_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->info->tty; + struct sci_port *s = &sci_ports[port->line]; + + if (!s->break_flag && status & SCxSR_BRK(port) && + tty->flip.count < TTY_FLIPBUF_SIZE) { +#if defined(CONFIG_CPU_SH3) + /* Debounce break */ + s->break_flag = 1; +#endif + /* Notify of BREAK */ + copied++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + pr_debug("sci: BREAK detected\n"); + } + +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) || \ + defined(CONFIG_CPU_SUBTYPE_SH7760) + /* XXX: Handle SCIF overrun error */ + if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); + if(tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + pr_debug("sci: overrun error\n"); + } + } +#endif + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + +static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct uart_port *port = ptr; + + /* I think sci_receive_chars has to be called irrespective + * of whether the I_IXOFF is set, otherwise, how is the interrupt + * to be disabled? + */ + sci_receive_chars(port, regs); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct uart_port *port = ptr; + + sci_transmit_chars(port); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct uart_port *port = ptr; + + /* Handle errors */ + if (port->type == PORT_SCI) { + if (sci_handle_errors(port)) { + /* discard character in rx buffer */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } else { + sci_rx_interrupt(irq, ptr, regs); + } + + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + + /* Kick the transmission */ + sci_tx_interrupt(irq, ptr, regs); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct uart_port *port = ptr; + + /* Handle BREAKs */ + sci_handle_breaks(port); + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_CPU_FREQ +/* + * Here we define a transistion notifier so that we can update all of our + * ports' baud rate when the peripheral clock changes. + */ +static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) +{ + struct cpufreq_freqs *freqs = p; + int i; + + if (phase == CPUFREQ_POSTCHANGE) { + for (i = 0; i < SCI_NPORTS; i++) { + struct uart_port *port = &sci_ports[i]; + + /* + * Update the uartclk per-port if frequency has + * changed, since it will no longer necessarily be + * consistent with the old frequency. + * + * Really we want to be able to do something like + * uart_change_speed() or something along those lines + * here to implicitly reset the per-port baud rate.. + * + * Clean this up later.. + */ + port->uartclk = current_cpu_data.module_clock * 16; + } + + printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n", + __FUNCTION__, freqs->cpu, freqs->old, freqs->new); + } + + return NOTIFY_OK; +} + +static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; +#endif /* CONFIG_CPU_FREQ */ + +static int sci_request_irq(struct sci_port *port) +{ + int i; + irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, + }; + const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full", + "SCI Transmit Data Empty", "SCI Break" }; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + if (!port->irqs[i]) + continue; + if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, + desc[i], port)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } + + return 0; +} + +static void sci_free_irq(struct sci_port *port) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { + if (!port->irqs[i]) + continue; + + free_irq(port->irqs[i], port); + } +} + +static unsigned int sci_tx_empty(struct uart_port *port) +{ + /* Can't detect */ + return TIOCSER_TEMT; +} + +static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ + /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ + /* If you have signals for DTR and DCD, please implement here. */ +} + +static unsigned int sci_get_mctrl(struct uart_port *port) +{ + /* This routine is used for geting signals of: DTR, DCD, DSR, RI, + and CTS/RTS */ + + return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; +} + +static void sci_start_tx(struct uart_port *port, unsigned int tty_start) +{ + struct sci_port *s = &sci_ports[port->line]; + + disable_irq(s->irqs[SCIx_TXI_IRQ]); + sci_transmit_chars(port); + enable_irq(s->irqs[SCIx_TXI_IRQ]); +} + +static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + local_irq_save(flags); + ctrl = sci_in(port, SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); + local_irq_restore(flags); +} + +static void sci_start_rx(struct uart_port *port, unsigned int tty_start) +{ + unsigned long flags; + unsigned short ctrl; + + /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ + local_irq_save(flags); + ctrl = sci_in(port, SCSCR); + ctrl |= SCI_CTRL_FLAGS_RIE; + sci_out(port, SCSCR, ctrl); + local_irq_restore(flags); +} + +static void sci_stop_rx(struct uart_port *port) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ + local_irq_save(flags); + ctrl = sci_in(port, SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_RIE; + sci_out(port, SCSCR, ctrl); + local_irq_restore(flags); +} + +static void sci_enable_ms(struct uart_port *port) +{ + /* Nothing here yet .. */ +} + +static void sci_break_ctl(struct uart_port *port, int break_state) +{ + /* Nothing here yet .. */ +} + +static int sci_startup(struct uart_port *port) +{ + struct sci_port *s = &sci_ports[port->line]; + + sci_request_irq(s); + sci_start_tx(port, 1); + sci_start_rx(port, 1); + +#if defined(__H8300S__) + h8300_sci_enable(port, sci_enable); +#endif + + return 0; +} + +static void sci_shutdown(struct uart_port *port) +{ + struct sci_port *s = &sci_ports[port->line]; + + sci_stop_rx(port); + sci_stop_tx(port, 1); + sci_free_irq(s); + +#if defined(__H8300S__) + h8300_sci_enable(port, sci_disable); +#endif +} + +static void sci_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + struct sci_port *s = &sci_ports[port->line]; + unsigned int status, baud, smr_val; + unsigned long flags; + int t; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + + spin_lock_irqsave(&port->lock, flags); + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TEND(port))); + + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ + + if (port->type == PORT_SCIF) { + sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + } + + smr_val = sci_in(port, SCSMR) & 3; + if ((termios->c_cflag & CSIZE) == CS7) + smr_val |= 0x40; + if (termios->c_cflag & PARENB) + smr_val |= 0x20; + if (termios->c_cflag & PARODD) + smr_val |= 0x30; + if (termios->c_cflag & CSTOPB) + smr_val |= 0x08; + + uart_update_timeout(port, termios->c_cflag, baud); + + sci_out(port, SCSMR, smr_val); + + switch (baud) { + case 0: t = -1; break; + case 2400: t = BPS_2400; break; + case 4800: t = BPS_4800; break; + case 9600: t = BPS_9600; break; + case 19200: t = BPS_19200; break; + case 38400: t = BPS_38400; break; + case 57600: t = BPS_57600; break; + case 115200: t = BPS_115200; break; + default: t = BPS_115200; break; + } + + if (t > 0) { + if(t >= 256) { + sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); + t >>= 2; + } else { + sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); + } + sci_out(port, SCBRR, t); + udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ + } + + s->init_pins(port, termios->c_cflag); + sci_out(port, SCSCR, SCSCR_INIT(port)); + + if ((termios->c_cflag & CREAD) != 0) + sci_start_rx(port,0); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *sci_type(struct uart_port *port) +{ + switch (port->type) { + case PORT_SCI: return "sci"; + case PORT_SCIF: return "scif"; + case PORT_IRDA: return "irda"; + } + + return 0; +} + +static void sci_release_port(struct uart_port *port) +{ + /* Nothing here yet .. */ +} + +static int sci_request_port(struct uart_port *port) +{ + /* Nothing here yet .. */ + return 0; +} + +static void sci_config_port(struct uart_port *port, int flags) +{ + struct sci_port *s = &sci_ports[port->line]; + + port->type = s->type; +} + +static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct sci_port *s = &sci_ports[port->line]; + + if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > NR_IRQS) + return -EINVAL; + if (ser->baud_base < 2400) + /* No paper tape reader for Mitch.. */ + return -EINVAL; + + return 0; +} + +static struct uart_ops sci_uart_ops = { + .tx_empty = sci_tx_empty, + .set_mctrl = sci_set_mctrl, + .get_mctrl = sci_get_mctrl, + .start_tx = sci_start_tx, + .stop_tx = sci_stop_tx, + .stop_rx = sci_stop_rx, + .enable_ms = sci_enable_ms, + .break_ctl = sci_break_ctl, + .startup = sci_startup, + .shutdown = sci_shutdown, + .set_termios = sci_set_termios, + .type = sci_type, + .release_port = sci_release_port, + .request_port = sci_request_port, + .config_port = sci_config_port, + .verify_port = sci_verify_port, +}; + +static struct sci_port sci_ports[SCI_NPORTS] = { +#if defined(CONFIG_CPU_SUBTYPE_SH7708) + { + .port = { + .membase = (void *)0xfffffe80, + .mapbase = 0xfffffe80, + .iotype = SERIAL_IO_MEM, + .irq = 25, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCI, + .irqs = SCI_IRQS, + .init_pins = sci_init_pins_sci, + }, +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) + { + .port = { + .membase = (void *)0xfffffe80, + .mapbase = 0xfffffe80, + .iotype = SERIAL_IO_MEM, + .irq = 25, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCI, + .irqs = SCI_IRQS, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0xa4000150, + .mapbase = 0xa4000150, + .iotype = SERIAL_IO_MEM, + .irq = 59, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCIF, + .irqs = SH3_SCIF_IRQS, + .init_pins = sci_init_pins_scif, + }, + { + .port = { + .membase = (void *)0xa4000140, + .mapbase = 0xa4000140, + .iotype = SERIAL_IO_MEM, + .irq = 55, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .type = PORT_IRDA, + .irqs = SH3_IRDA_IRQS, + .init_pins = sci_init_pins_irda, + } +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) + { + .port = { + .membase = (void *)0xffe00000, + .mapbase = 0xffe00000, + .iotype = SERIAL_IO_MEM, + .irq = 25, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCI, + .irqs = SCI_IRQS, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0xffe80000, + .mapbase = 0xffe80000, + .iotype = SERIAL_IO_MEM, + .irq = 43, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCIF, + .irqs = SH4_SCIF_IRQS, + .init_pins = sci_init_pins_scif, + }, +#elif defined(CONFIG_CPU_SUBTYPE_SH7760) + { + .port = { + .membase = (void *)0xfe600000, + .mapbase = 0xfe600000, + .iotype = SERIAL_IO_MEM, + .irq = 55, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCIF, + .irqs = SH7760_SCIF0_IRQS, + .init_pins = sci_init_pins_scif, + }, + { + .port = { + .membase = (void *)0xfe610000, + .mapbase = 0xfe610000, + .iotype = SERIAL_IO_MEM, + .irq = 75, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCIF, + .irqs = SH7760_SCIF1_IRQS, + .init_pins = sci_init_pins_scif, + }, + { + .port = { + .membase = (void *)0xfe620000, + .mapbase = 0xfe620000, + .iotype = SERIAL_IO_MEM, + .irq = 79, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .type = PORT_SCIF, + .irqs = SH7760_SCIF2_IRQS, + .init_pins = sci_init_pins_scif, + }, +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) + { + .port = { + .membase = (void *)0xffe00000, + .mapbase = 0xffe00000, + .iotype = SERIAL_IO_MEM, + .irq = 26, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCIF, + .irqs = STB1_SCIF1_IRQS, + .init_pins = sci_init_pins_scif, + }, + { + .port = { + .membase = (void *)0xffe80000, + .mapbase = 0xffe80000, + .iotype = SERIAL_IO_MEM, + .irq = 43, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCIF, + .irqs = SH4_SCIF_IRQS, + .init_pins = sci_init_pins_scif, + }, +#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) + { + .port = { + .membase = (void *)0x00ffffb0, + .mapbase = 0x00ffffb0, + .iotype = SERIAL_IO_MEM, + .irq = 54, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCI, + .irqs = H8300H_SCI_IRQS0, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0x00ffffb8, + .mapbase = 0x00ffffb8, + .iotype = SERIAL_IO_MEM, + .irq = 58, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCI, + .irqs = H8300H_SCI_IRQS1, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0x00ffffc0, + .mapbase = 0x00ffffc0, + .iotype = SERIAL_IO_MEM, + .irq = 62, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .type = PORT_SCI, + .irqs = H8300H_SCI_IRQS2, + .init_pins = sci_init_pins_sci, + }, +#elif defined(CONFIG_H8S2678) + { + .port = { + .membase = (void *)0x00ffff78, + .mapbase = 0x00ffff78, + .iotype = SERIAL_IO_MEM, + .irq = 90, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCI, + .irqs = H8S_SCI_IRQS0, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0x00ffff80, + .mapbase = 0x00ffff80, + .iotype = SERIAL_IO_MEM, + .irq = 94, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .type = PORT_SCI, + .irqs = H8S_IRQS1, + .init_pins = sci_init_pins_sci, + }, + { + .port = { + .membase = (void *)0x00ffff88, + .mapbase = 0x00ffff88, + .iotype = SERIAL_IO_MEM, + .irq = 98, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .type = PORT_SCI, + .irqs = H8S_IRQS2, + .init_pins = sci_init_pins_sci, + }, +#else +#error "CPU subtype not defined" +#endif +}; + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + put_string(serial_console_port, s, count); +} + +static int __init serial_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= SCI_NPORTS) + co->index = 0; + + serial_console_port = &sci_ports[co->index]; + port = &serial_console_port->port; + port->type = serial_console_port->type; + + /* + * We need to set the initial uartclk here, since otherwise it will + * only ever be setup at sci_init() time. + */ + port->uartclk = current_cpu_data.module_clock * 16; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console serial_console = { + .name = "ttySC", + .device = uart_console_device, + .write = serial_console_write, + .setup = serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sci_uart_driver, +}; + +static int __init sci_console_init(void) +{ +#ifdef CONFIG_SH_EARLY_PRINTK + extern void sh_console_unregister(void); + + /* + * Now that the real console is available, unregister the one we + * used while first booting. + */ + sh_console_unregister(); +#endif + + register_console(&serial_console); + + return 0; +} + +console_initcall(sci_console_init); +#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ + +#ifdef CONFIG_SH_KGDB +/* + * FIXME: Most of this can go away.. at the moment, we rely on + * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though + * most of that can easily be done here instead. + * + * For the time being, just accept the values that were parsed earlier.. + */ +static void __init kgdb_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + *baud = kgdb_baud; + *parity = tolower(kgdb_parity); + *bits = kgdb_bits - '0'; +} + +/* + * The naming here is somewhat misleading, since kgdb_console_setup() takes + * care of the early-on initialization for kgdb, regardless of whether we + * actually use kgdb as a console or not. + * + * On the plus side, this lets us kill off the old kgdb_sci_setup() nonsense. + */ +int __init kgdb_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &sci_ports[kgdb_portnum].port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= SCI_NPORTS || co->index != kgdb_portnum) + co->index = kgdb_portnum; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + kgdb_console_get_options(port, &baud, &parity, &bits); + + kgdb_getchar = kgdb_sci_getchar; + kgdb_putchar = kgdb_sci_putchar; + + return uart_set_options(port, co, baud, parity, bits, flow); +} +#endif /* CONFIG_SH_KGDB */ + +#ifdef CONFIG_SH_KGDB_CONSOLE +static struct console kgdb_console = { + .name = "ttySC", + .write = kgdb_console_write, + .setup = kgdb_console_setup, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, + .data = &sci_uart_driver, +}; + +/* Register the KGDB console so we get messages (d'oh!) */ +static int __init kgdb_console_init(void) +{ + register_console(&kgdb_console); + + return 0; +} + +console_initcall(kgdb_console_init); +#endif /* CONFIG_SH_KGDB_CONSOLE */ + +#if defined(CONFIG_SH_KGDB_CONSOLE) +#define SCI_CONSOLE &kgdb_console +#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE) +#define SCI_CONSOLE &serial_console +#else +#define SCI_CONSOLE 0 +#endif + +static char banner[] __initdata = + KERN_INFO "SuperH SCI(F) driver initialized\n"; + +static struct uart_driver sci_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "sci", +#ifdef CONFIG_DEVFS_FS + .devfs_name = "ttsc/", +#endif + .dev_name = "ttySC", + .major = SCI_MAJOR, + .minor = SCI_MINOR_START, + .nr = SCI_NPORTS, + .cons = SCI_CONSOLE, +}; + +static int __init sci_init(void) +{ + int chan, ret; + + printk("%s", banner); + + ret = uart_register_driver(&sci_uart_driver); + if (ret == 0) { + for (chan = 0; chan < SCI_NPORTS; chan++) { + struct sci_port *sciport = &sci_ports[chan]; + + sciport->port.uartclk = (current_cpu_data.module_clock * 16); + uart_add_one_port(&sci_uart_driver, &sciport->port); + sciport->break_timer.data = (unsigned long)sciport; + sciport->break_timer.function = sci_break_timer; + init_timer(&sciport->break_timer); + } + } + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); + printk("sci: CPU frequency notifier registered\n"); +#endif + +#ifdef CONFIG_SH_STANDARD_BIOS + sh_bios_gdb_detach(); +#endif + + return ret; +} + +static void __exit sci_exit(void) +{ + int chan; + + for (chan = 0; chan < SCI_NPORTS; chan++) + uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port); + + uart_unregister_driver(&sci_uart_driver); +} + +module_init(sci_init); +module_exit(sci_exit); + diff -Nru a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/sh-sci.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,435 @@ +/* $Id: sh-sci.h,v 1.4 2004/02/19 16:43:56 lethal Exp $ + * + * linux/drivers/serial/sh-sci.h + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2000 Greg Banks + * Copyright (C) 2002, 2003 Paul Mundt + * Modified to support multiple serial ports. Stuart Menefy (May 2000). + * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). + */ +#include +#include + +#if defined(__H8300H__) || defined(__H8300S__) +#include +#if defined(CONFIG_H83007) || defined(CONFIG_H83068) +#include +#endif +#if defined(CONFIG_H8S2678) +#include +#endif +#endif + +/* Offsets into the sci_port->irqs array */ +#define SCIx_ERI_IRQ 0 +#define SCIx_RXI_IRQ 1 +#define SCIx_TXI_IRQ 2 + +/* ERI, RXI, TXI, BRI */ +#define SCI_IRQS { 23, 24, 25, 0 } +#define SH3_SCIF_IRQS { 56, 57, 59, 58 } +#define SH3_IRDA_IRQS { 52, 53, 55, 54 } +#define SH4_SCIF_IRQS { 40, 41, 43, 42 } +#define STB1_SCIF1_IRQS {23, 24, 26, 25 } +#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 } +#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 } +#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 } +#define H8300H_SCI_IRQS0 {52, 53, 54, 0 } +#define H8300H_SCI_IRQS1 {56, 57, 58, 0 } +#define H8300H_SCI_IRQS2 {60, 61, 62, 0 } +#define H8S_SCI_IRQS0 {88, 89, 90, 0 } +#define H8S_SCI_IRQS1 {92, 93, 94, 0 } +#define H8S_SCI_IRQS2 {96, 97, 98, 0 } + +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +# define SCI_NPORTS 1 +# define SCSPTR 0xffffff7c /* 8 bit */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +# define SCI_NPORTS 3 +# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ +# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) +# define SCI_NPORTS 2 +# define SCSPTR1 0xffe0001c /* 8 bit SCI */ +# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) +# define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_SH7760) +# define SCI_NPORTS 3 +# define SCSPTR0 0xfe600000 /* 16 bit SCIF */ +# define SCSPTR1 0xfe610000 /* 16 bit SCIF */ +# define SCSPTR2 0xfe620000 /* 16 bit SCIF */ +# define SCIF_ORDER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +# define SCI_NPORTS 2 +# define SCSPTR1 0xffe00020 /* 16 bit SCIF */ +# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY +#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) +# define SCI_NPORTS 3 +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_ONLY +# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#elif defined(CONFIG_H8S2678) +# define SCI_NPORTS 3 +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_ONLY +# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#else +# error CPU subtype not defined +#endif + +/* SCSCR */ +#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ +#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ +#define SCI_CTRL_FLAGS_TE 0x20 /* all */ +#define SCI_CTRL_FLAGS_RE 0x10 /* all */ +/* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */ +/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ +/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ + +/* SCxSR SCI */ +#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) + +/* SCxSR SCIF */ +#define SCIF_ER 0x0080 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TEND 0x0040 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TDFE 0x0020 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_BRK 0x0010 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_FER 0x0008 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_PER 0x0004 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_RDF 0x0002 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_DR 0x0001 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ + +#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) + +#if defined(SCI_ONLY) +# define SCxSR_TEND(port) SCI_TEND +# define SCxSR_ERRORS(port) SCI_ERRORS +# define SCxSR_RDxF(port) SCI_RDRF +# define SCxSR_TDxE(port) SCI_TDRE +# define SCxSR_ORER(port) SCI_ORER +# define SCxSR_FER(port) SCI_FER +# define SCxSR_PER(port) SCI_PER +# define SCxSR_BRK(port) 0x00 +# define SCxSR_RDxF_CLEAR(port) 0xbc +# define SCxSR_ERROR_CLEAR(port) 0xc4 +# define SCxSR_TDxE_CLEAR(port) 0x78 +# define SCxSR_BREAK_CLEAR(port) 0xc4 +#elif defined(SCIF_ONLY) +# define SCxSR_TEND(port) SCIF_TEND +# define SCxSR_ERRORS(port) SCIF_ERRORS +# define SCxSR_RDxF(port) SCIF_RDF +# define SCxSR_TDxE(port) SCIF_TDFE +# define SCxSR_ORER(port) 0x0000 +# define SCxSR_FER(port) SCIF_FER +# define SCxSR_PER(port) SCIF_PER +# define SCxSR_BRK(port) SCIF_BRK +# define SCxSR_RDxF_CLEAR(port) 0x00fc +# define SCxSR_ERROR_CLEAR(port) 0x0073 +# define SCxSR_TDxE_CLEAR(port) 0x00df +# define SCxSR_BREAK_CLEAR(port) 0x00e3 +#else +# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) +# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) +# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) +# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000) +# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) +# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) +# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) +# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) +# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) +# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) +#endif + +/* SCFCR */ +#define SCFCR_RFRST 0x0002 +#define SCFCR_TFRST 0x0004 +#define SCFCR_MCE 0x0008 + +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + +/* Generic serial flags */ +#define SCI_RX_THROTTLE 0x0000001 + +#define SCI_MAGIC 0xbabeface + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define SCI_EVENT_WRITE_WAKEUP 0 + +struct sci_port { + struct uart_port port; + int type; + unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */ + void (*init_pins)(struct uart_port *port, unsigned int cflag); + int break_flag; + struct timer_list break_timer; +}; + +#define SCI_IN(size, offset) \ + unsigned int addr = port->mapbase + (offset); \ + if ((size) == 8) { \ + return ctrl_inb(addr); \ + } else { \ + return ctrl_inw(addr); \ + } +#define SCI_OUT(size, offset, value) \ + unsigned int addr = port->mapbase + (offset); \ + if ((size) == 8) { \ + ctrl_outb(value, addr); \ + } else { \ + ctrl_outw(value, addr); \ + } + +#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_IN(sci_size, sci_offset) \ + } else { \ + SCI_IN(scif_size, scif_offset); \ + } \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_OUT(sci_size, sci_offset, value) \ + } else { \ + SCI_OUT(scif_size, scif_offset, value); \ + } \ + } + +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + SCI_IN(scif_size, scif_offset); \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + SCI_OUT(scif_size, scif_offset, value); \ + } + +#define CPU_SCI_FNS(name, sci_offset, sci_size) \ + static inline unsigned int sci_##name##_in(struct sci_port* port) \ + { \ + SCI_IN(sci_size, sci_offset); \ + } \ + static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ + { \ + SCI_OUT(sci_size, sci_offset, value); \ + } + +#ifdef CONFIG_CPU_SH3 +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) +#elif defined(__H8300H__) || defined(__H8300S__) +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) +#else +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#endif + +/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ +/* name off sz off sz off sz off sz off sz*/ +SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8) +SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8) +SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8) +SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) +SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) +SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) +SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) + +#define sci_in(port, reg) sci_##reg##_in(port) +#define sci_out(port, reg, value) sci_##reg##_out(port, value) + +/* H8/300 series SCI pins assignment */ +#if defined(__H8300H__) || defined(__H8300S__) +static const struct __attribute__((packed)) { + int port; /* GPIO port no */ + unsigned short rx,tx; /* GPIO bit no */ +} h8300_sci_pins[] = { +#if defined(CONFIG_H83007) || defined(CONFIG_H83068) + { /* SCI0 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_PB, + .rx = H8300_GPIO_B7, + .tx = H8300_GPIO_B6, + } +#elif defined(CONFIG_H8S2678) + { /* SCI0 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_P5, + .rx = H8300_GPIO_B1, + .tx = H8300_GPIO_B0, + } +#endif +}; +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xfffffe80) + return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xfffffe80) + return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */ + if (port->mapbase == 0xa4000150) + return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xa4000140) + return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) +static inline int sci_rxd_in(struct uart_port *port) +{ +#ifndef SCIF_ONLY + if (port->mapbase == 0xffe00000) + return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ +#endif +#ifndef SCI_ONLY + if (port->mapbase == 0xffe80000) + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ +#endif + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7760) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xfe600000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfe610000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfe620000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ +} +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */ + else + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + +} +#elif defined(__H8300H__) || defined(__H8300S__) +static inline int sci_rxd_in(struct sci_port *port) +{ + int ch = (port->base - SMR0) >> 3; + return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; +} +#endif + +/* + * Values for the BitRate Register (SCBRR) + * + * The values are actually divisors for a frequency which can + * be internal to the SH3 (14.7456MHz) or derived from an external + * clock source. This driver assumes the internal clock is used; + * to support using an external clock source, config options or + * possibly command-line options would need to be added. + * + * Also, to support speeds below 2400 (why?) the lower 2 bits of + * the SCSMR register would also need to be set to non-zero values. + * + * -- Greg Banks 27Feb2000 + * + * Answer: The SCBRR register is only eight bits, and the value in + * it gets larger with lower baud rates. At around 2400 (depending on + * the peripherial module clock) you run out of bits. However the + * lower two bits of SCSMR allow the module clock to be divided down, + * scaling the value which is needed in SCBRR. + * + * -- Stuart Menefy - 23 May 2000 + * + * I meant, why would anyone bother with bitrates below 2400. + * + * -- Greg Banks - 7Jul2000 + * + * You "speedist"! How will I use my 110bps ASR-33 teletype with paper + * tape reader as a console! + * + * -- Mitch Davis - 15 Jul 2000 + */ + +#define PCLK (current_cpu_data.module_clock) + +#if !defined(__H8300H__) && !defined(__H8300S__) +#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1) +#else +#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) +#endif +#define BPS_2400 SCBRR_VALUE(2400) +#define BPS_4800 SCBRR_VALUE(4800) +#define BPS_9600 SCBRR_VALUE(9600) +#define BPS_19200 SCBRR_VALUE(19200) +#define BPS_38400 SCBRR_VALUE(38400) +#define BPS_57600 SCBRR_VALUE(57600) +#define BPS_115200 SCBRR_VALUE(115200) + diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig --- a/drivers/usb/Kconfig Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/Kconfig Sat Apr 3 19:38:41 2004 @@ -6,32 +6,36 @@ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB - tristate "Support for USB" + tristate "Support for Host-side USB" depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the traditional PC serial port. The bus supplies power to peripherals and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB port in a tree structure. The USB port is - the root of the tree, the peripherals are the leaves and the inner - nodes are special USB devices called hubs. Many newer PC's have USB - ports and newer peripherals such as scanners, keyboards, mice, - modems, and printers support the USB protocol and can be connected - to the PC via those ports. + connected to a single USB host in a tree structure. + + The USB host is the root of the tree, the peripherals are the + leaves and the inner nodes are special USB devices called hubs. + Most PCs now have USB host ports, used to connect peripherals + such as scanners, keyboards, mice, modems, cameras, disks, + flash memory, network links, and printers to the PC. - Say Y here if your computer has a USB port and you want to use USB - devices. You then need to say Y to at least one of "UHCI HCD support" - or "OHCI HCD support" below (the type of interface that the USB hardware - in your computer provides to the operating system) and then choose - from amongst the drivers for USB peripherals. You may want to check - out the information provided in and - especially the links given in . + Say Y here if your computer has a host-side USB port and you want + to use USB devices. You then need to say Y to at least one of the + Host Controller Driver (HCD) options below. Choose a USB 1.1 + controller, such as "UHCI HCD support" or "OHCI HCD support", + and "EHCI HCD (USB 2.0) support" except for older systems that + do not have USB 2.0 support. It doesn't normally hurt to select + them all if you are not certain. - If you have a new USB 2.0 High Speed system, you should also choose - "EHCI HCD (USB 2.0) support" as well as at least one of UHCI or OHCI. + If your system has a device-side USB port, used in the peripheral + side of the USB protocol, see the "USB Gadget" framework instead. - It doesn't normally hurt to select them all if you are not certain. + After choosing your HCD, then select drivers for the USB peripherals + you'll be using. You may want to check out the information provided + in and especially the links given in + . To compile this driver as a module, choose M here: the module will be called usbcore. diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/Makefile Sat Apr 3 19:38:55 2004 @@ -20,10 +20,15 @@ obj-$(CONFIG_USB_STORAGE) += storage/ obj-$(CONFIG_USB_AIPTEK) += input/ +obj-$(CONFIG_USB_ATI_REMOTE) += input/ obj-$(CONFIG_USB_HID) += input/ obj-$(CONFIG_USB_KBD) += input/ +obj-$(CONFIG_USB_KBTAB) += input/ obj-$(CONFIG_USB_MOUSE) += input/ +obj-$(CONFIG_USB_MTOUCH) += input/ +obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_WACOM) += input/ +obj-$(CONFIG_USB_XPAD) += input/ obj-$(CONFIG_USB_DABUSB) += media/ obj-$(CONFIG_USB_DSBR) += media/ @@ -50,7 +55,6 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BRLVGER) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/class/audio.c Sat Apr 3 19:38:56 2004 @@ -3,7 +3,7 @@ /* * audio.c -- USB Audio Class driver * - * Copyright (C) 1999, 2000, 2001 + * Copyright (C) 1999, 2000, 2001, 2003, 2004 * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -101,6 +101,11 @@ * Fix SNDCTL_DSP_STEREO API violation * 2003-04-08: Oliver Neukum (oliver@neukum.name): * Setting a configuration is done by usbcore and must not be overridden + * 2004-02-27: Workaround for broken synch descriptors + * 2004-03-07: Alan Stern + * Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support. + * Use the in-memory descriptors instead of reading them from the device. + * */ /* @@ -141,8 +146,8 @@ * * How does the parsing work? First, all interfaces are searched * for an AudioControl class interface. If found, the config descriptor - * that belongs to the current configuration is fetched from the device. - * Then the HEADER descriptor is fetched. It contains a list of + * that belongs to the current configuration is searched and + * the HEADER descriptor is found. It contains a list of * all AudioStreaming and MIDIStreaming devices. This list is then walked, * and all AudioStreaming interfaces are classified into input and output * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming @@ -1512,7 +1517,6 @@ static int set_format_in(struct usb_audiodev *as) { struct usb_device *dev = as->state->usbdev; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct usbin *u = &as->usbin; @@ -1522,9 +1526,9 @@ unsigned char data[3]; int fmtnr, ret; - if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces) + iface = usb_ifnum_to_if(dev, u->interface); + if (!iface) return 0; - iface = config->interface[u->interface]; fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate); if (fmtnr < 0) { @@ -1533,7 +1537,7 @@ } fmt = as->fmtin + fmtnr; - alts = &iface->altsetting[fmt->altsetting]; + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); u->format = fmt->format; u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); u->syncpipe = u->syncinterval = 0; @@ -1542,18 +1546,20 @@ alts->endpoint[1].desc.bmAttributes != 0x01 || alts->endpoint[1].desc.bSynchAddress != 0 || alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in " + "but has invalid synch pipe; treating as asynchronous in\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].desc.bRefresh; } - u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting)); + dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", + u->interface, fmt->altsetting)); if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1600,7 +1606,6 @@ static int set_format_out(struct usb_audiodev *as) { struct usb_device *dev = as->state->usbdev; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct usbout *u = &as->usbout; @@ -1610,9 +1615,9 @@ unsigned char data[3]; int fmtnr, ret; - if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces) + iface = usb_ifnum_to_if(dev, u->interface); + if (!iface) return 0; - iface = config->interface[u->interface]; fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate); if (fmtnr < 0) { @@ -1622,7 +1627,7 @@ fmt = as->fmtout + fmtnr; u->format = fmt->format; - alts = &iface->altsetting[fmt->altsetting]; + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); u->syncpipe = u->syncinterval = 0; if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) { @@ -1637,18 +1642,20 @@ alts->endpoint[1].desc.bmAttributes != 0x01 || alts->endpoint[1].desc.bSynchAddress != 0 || alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out " + "but has invalid synch pipe; treating as adaptive out\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].desc.bRefresh; } - u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting)); + dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", + u->interface, fmt->altsetting)); if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -2697,7 +2704,6 @@ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; struct usb_audio_state *s; struct usb_device *dev; - struct usb_interface *iface; lock_kernel(); s = as->state; @@ -2707,19 +2713,15 @@ down(&open_sem); if (file->f_mode & FMODE_WRITE) { usbout_stop(as); - if (dev && as->usbout.interface >= 0) { - iface = dev->actconfig->interface[as->usbout.interface]; - usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0); - } + if (dev && as->usbout.interface >= 0) + usb_set_interface(dev, as->usbout.interface, 0); dmabuf_release(&as->usbout.dma); usbout_release(as); } if (file->f_mode & FMODE_READ) { usbin_stop(as); - if (dev && as->usbin.interface >= 0) { - iface = dev->actconfig->interface[as->usbin.interface]; - usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0); - } + if (dev && as->usbin.interface >= 0) + usb_set_interface(dev, as->usbin.interface, 0); dmabuf_release(&as->usbin.dma); usbin_release(as); } @@ -2824,12 +2826,11 @@ { struct usb_device *dev = s->usbdev; struct usb_audiodev *as; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct audioformat *fp; unsigned char *fmt, *csep; - unsigned int i, j, k, format; + unsigned int i, j, k, format, idx; if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL))) return; @@ -2870,9 +2871,10 @@ /* search for input formats */ if (asifin >= 0) { as->usbin.flags = FLG_CONNECTED; - iface = config->interface[asifin]; - for (i = 0; i < iface->num_altsetting; i++) { - alts = &iface->altsetting[i]; + iface = usb_ifnum_to_if(dev, asifin); + for (idx = 0; idx < iface->num_altsetting; idx++) { + alts = &iface->altsetting[idx]; + i = alts->desc.bAlternateSetting; if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) continue; if (alts->desc.bNumEndpoints < 1) { @@ -2951,14 +2953,15 @@ /* search for output formats */ if (asifout >= 0) { as->usbout.flags = FLG_CONNECTED; - iface = config->interface[asifout]; - for (i = 0; i < iface->num_altsetting; i++) { - alts = &iface->altsetting[i]; + iface = usb_ifnum_to_if(dev, asifout); + for (idx = 0; idx < iface->num_altsetting; idx++) { + alts = &iface->altsetting[idx]; + i = alts->desc.bAlternateSetting; if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) continue; if (alts->desc.bNumEndpoints < 1) { /* altsetting 0 should never have iso EPs */ - if (alts->desc.bAlternateSetting != 0) + if (i != 0) printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", dev->devnum, asifout, i); continue; @@ -3655,8 +3658,8 @@ static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif) { struct usb_audio_state *s; - struct usb_host_config *config = dev->actconfig; struct usb_interface *iface; + struct usb_host_interface *alt; unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES]; unsigned char *p1; unsigned int i, j, k, numifin = 0, numifout = 0; @@ -3685,54 +3688,63 @@ dev->devnum, ctrlif); for (i = 0; i < p1[7]; i++) { j = p1[8+i]; - if (j >= config->desc.bNumInterfaces) { + iface = usb_ifnum_to_if(dev, j); + if (!iface) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n", dev->devnum, ctrlif, j); continue; } - iface = config->interface[j]; - if (iface->altsetting[0].desc.bInterfaceClass != USB_CLASS_AUDIO) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n", - dev->devnum, ctrlif, j); + if (iface->num_altsetting == 1) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif); continue; } - if (iface->altsetting[0].desc.bInterfaceSubClass == 3) { - printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n", + alt = usb_altnum_to_altsetting(iface, 0); + if (!alt) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n", dev->devnum, ctrlif, j); continue; } - if (iface->altsetting[0].desc.bInterfaceSubClass != 2) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n", + if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n", dev->devnum, ctrlif, j); continue; } - if (iface->num_altsetting == 0) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif); + if (alt->desc.bInterfaceSubClass == 3) { + printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n", + dev->devnum, ctrlif, j); continue; } - if (iface->num_altsetting == 1) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif); + if (alt->desc.bInterfaceSubClass != 2) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n", + dev->devnum, ctrlif, j); continue; } - if (iface->altsetting[0].desc.bNumEndpoints > 0) { + if (alt->desc.bNumEndpoints > 0) { /* Check all endpoints; should they all have a bandwidth of 0 ? */ - for (k = 0; k < iface->altsetting[0].desc.bNumEndpoints; k++) { - if (iface->altsetting[0].endpoint[k].desc.wMaxPacketSize > 0) { + for (k = 0; k < alt->desc.bNumEndpoints; k++) { + if (alt->endpoint[k].desc.wMaxPacketSize > 0) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k); break; } } - if (k < iface->altsetting[0].desc.bNumEndpoints) + if (k < alt->desc.bNumEndpoints) continue; } - if (iface->altsetting[1].desc.bNumEndpoints < 1) { + + alt = usb_altnum_to_altsetting(iface, 1); + if (!alt) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n", + dev->devnum, ctrlif, j); + continue; + } + if (alt->desc.bNumEndpoints < 1) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n", dev->devnum, ctrlif, j); continue; } /* note: this requires the data endpoint to be ep0 and the optional sync ep to be ep1, which seems to be the case */ - if (iface->altsetting[1].endpoint[0].desc.bEndpointAddress & USB_DIR_IN) { + if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) { if (numifin < USB_MAXINTERFACES) { ifin[numifin++] = j; usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1); @@ -3779,12 +3791,9 @@ const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev (intf); - struct usb_host_config *config = dev->actconfig; struct usb_audio_state *s; unsigned char *buffer; - unsigned char buf[8]; - unsigned int i, buflen; - int ret; + unsigned int buflen; #if 0 printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum, @@ -3796,26 +3805,8 @@ * audiocontrol interface found * find which configuration number is active */ - i = dev->actconfig - config; - - ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8); - if (ret < 0) { - printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); - return -EIO; - } - if (buf[1] != USB_DT_CONFIG || buf[0] < 9) { - printk(KERN_ERR "usbaudio: invalid config descriptor %d of device %d\n", i, dev->devnum); - return -EIO; - } - buflen = buf[2] | (buf[3] << 8); - if (!(buffer = kmalloc(buflen, GFP_KERNEL))) - return -ENOMEM; - ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen); - if (ret < 0) { - kfree(buffer); - printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); - return -EIO; - } + buffer = dev->rawdescriptors[dev->actconfig - dev->config]; + buflen = dev->actconfig->desc.wTotalLength; s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber); if (s) { usb_set_intfdata (intf, s); diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/class/bluetty.c Sat Apr 3 19:38:54 2004 @@ -1025,7 +1025,7 @@ int num_bulk_in = 0; int num_bulk_out = 0; - interface = &intf->altsetting[0]; + interface = intf->cur_altsetting; control_out_endpoint = interface->desc.bInterfaceNumber; /* find the endpoints that we need */ diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/class/cdc-acm.c Sat Apr 3 19:38:45 2004 @@ -595,12 +595,12 @@ * is there it's not for call management ... so use * the cdc union descriptor whenever there is one. */ - ifcom = intf->altsetting + 0; + ifcom = intf->cur_altsetting; if (intf == cfacm->interface[j]) { - ifdata = cfacm->interface[j + 1]->altsetting + 0; + ifdata = cfacm->interface[j + 1]->cur_altsetting; data = cfacm->interface[j + 1]; } else if (intf == cfacm->interface[j + 1]) { - ifdata = cfacm->interface[j]->altsetting + 0; + ifdata = cfacm->interface[j]->cur_altsetting; data = cfacm->interface[j]; } else continue; diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/class/usb-midi.c Sat Apr 3 19:38:41 2004 @@ -39,9 +39,6 @@ #include #include -/** This declaration is missing from linux/usb.h **/ -extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size); - #include "usb-midi.h" /* ------------------------------------------------------------------------- */ @@ -1519,15 +1516,17 @@ static int get_alt_setting( struct usb_device *d, int ifnum ) { int alts, alt=0; + struct usb_interface *iface; struct usb_host_interface *interface; struct usb_endpoint_descriptor *ep; int epin, epout; int i; - alts = d->actconfig->interface[ifnum]->num_altsetting; + iface = usb_ifnum_to_if( d, ifnum ); + alts = iface->num_altsetting; for ( alt=0 ; altactconfig->interface[ifnum]->altsetting[alt]; + interface = &iface->altsetting[alt]; epin = -1; epout = -1; @@ -1542,7 +1541,7 @@ epout = i; } if ( epin >= 0 && epout >= 0 ) { - return alt; + return interface->desc.bAlternateSetting; } } } @@ -1780,12 +1779,13 @@ * Called by usb_midi_probe(); **/ -static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s) +static int detect_yamaha_device( struct usb_device *d, + struct usb_interface *iface, unsigned int ifnum, + struct usb_midi_state *s) { - struct usb_host_config *c = d->actconfig; struct usb_host_interface *interface; struct usb_midi_device *u; - unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; + unsigned char *buffer; int bufSize; int i; int alts=-1; @@ -1795,13 +1795,13 @@ return -EINVAL; } - for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) { - interface = c->interface[ifnum]->altsetting + i; + for ( i=0 ; i < iface->num_altsetting; i++ ) { + interface = iface->altsetting + i; if ( interface->desc.bInterfaceClass != 255 || interface->desc.bInterfaceSubClass != 0 ) continue; - alts = i; + alts = interface->desc.bAlternateSetting; } if ( alts == -1 ) { return -EINVAL; @@ -1810,30 +1810,11 @@ printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n", d->descriptor.idVendor, d->descriptor.idProduct, ifnum); - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); - return -EINVAL; - } - if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { - printk(KERN_INFO "usb-midi: config not as expected.\n"); - return -EINVAL; - } - bufSize = buf[2] | buf[3]<<8; - buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); - if ( !buffer ) { - printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); - return -EINVAL; - } - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); - kfree(buffer); - return -EINVAL; - } + i = d->actconfig - d->config; + buffer = d->rawdescriptors[i]; + bufSize = d->actconfig->desc.wTotalLength; u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1); - kfree(buffer); if ( u == NULL ) { return -EINVAL; } @@ -1878,24 +1859,25 @@ * Returns 0 on success, negative on failure. * Called by usb_midi_probe(); **/ -static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s) +static int detect_midi_subclass(struct usb_device *d, + struct usb_interface *iface, unsigned int ifnum, + struct usb_midi_state *s) { - struct usb_host_config *c = d->actconfig; struct usb_host_interface *interface; struct usb_midi_device *u; - unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; + unsigned char *buffer; int bufSize; int i; int alts=-1; int ret; - for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) { - interface = c->interface[ifnum]->altsetting + i; + for ( i=0 ; i < iface->num_altsetting; i++ ) { + interface = iface->altsetting + i; if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO || interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING ) continue; - alts = i; + alts = interface->desc.bAlternateSetting; } if ( alts == -1 ) { return -EINVAL; @@ -1915,30 +1897,11 @@ descriptor they modify or extend. */ - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); - return -EINVAL; - } - if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { - printk(KERN_INFO "usb-midi: config not as expected.\n"); - return -EINVAL; - } - bufSize = buf[2] | buf[3]<<8; - buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); - if ( !buffer ) { - printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); - return -EINVAL; - } - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); - kfree(buffer); - return -EINVAL; - } + i = d->actconfig - d->config; + buffer = d->rawdescriptors[i]; + bufSize = d->actconfig->desc.wTotalLength; u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0); - kfree(buffer); if ( u == NULL ) { return -EINVAL; } @@ -2002,7 +1965,7 @@ { struct usb_midi_state *s; struct usb_device *dev = interface_to_usbdev(intf); - int ifnum = intf->altsetting->desc.bInterfaceNumber; + int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL); if ( !s ) @@ -2018,9 +1981,9 @@ if ( detect_by_hand( dev, ifnum, s ) && - detect_midi_subclass( dev, ifnum, s ) && + detect_midi_subclass( dev, intf, ifnum, s ) && detect_vendor_specific_device( dev, ifnum, s ) && - detect_yamaha_device( dev, ifnum, s) ) { + detect_yamaha_device( dev, intf, ifnum, s) ) { kfree(s); return -EIO; } diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/class/usblp.c Sat Apr 3 19:38:41 2004 @@ -133,6 +133,7 @@ wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ int ifnum; /* Interface number */ + struct usb_interface *intf; /* The interface */ /* Alternate-setting numbers and endpoints for each protocol * (7/1/{index=1,2,3}) that the device supports: */ struct { @@ -609,8 +610,10 @@ while (writecount < count) { if (!usblp->wcomplete) { barrier(); - if (file->f_flags & O_NONBLOCK) + if (file->f_flags & O_NONBLOCK) { + writecount += transfer_length; return writecount ? writecount : -EAGAIN; + } timeout = USBLP_WRITE_TIMEOUT; add_wait_queue(&usblp->wait, &wait); @@ -670,7 +673,8 @@ usblp->writeurb->transfer_buffer_length = transfer_length; - if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) { + if (copy_from_user(usblp->writeurb->transfer_buffer, + buffer + writecount, transfer_length)) { up(&usblp->sem); return writecount ? writecount : -EFAULT; } @@ -837,7 +841,8 @@ usblp->dev = dev; init_MUTEX (&usblp->sem); init_waitqueue_head(&usblp->wait); - usblp->ifnum = intf->altsetting->desc.bInterfaceNumber; + usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + usblp->intf = intf; usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { @@ -973,7 +978,7 @@ struct usb_endpoint_descriptor *epd, *epwrite, *epread; int p, i, e; - if_alt = usblp->dev->actconfig->interface[usblp->ifnum]; + if_alt = usblp->intf; for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) usblp->protocol[p].alt_setting = -1; @@ -1022,7 +1027,8 @@ epread = NULL; } - usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = i; + usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = + ifd->desc.bAlternateSetting; usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite; usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread; } diff -Nru a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c --- a/drivers/usb/core/buffer.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/core/buffer.c Sat Apr 3 19:38:56 2004 @@ -51,8 +51,8 @@ * @hcd: the bus whose buffer pools are to be initialized * Context: !in_interrupt() * - * Call this as part of initializing a host controller that uses the pci dma - * memory allocators. It initializes some pools of dma-consistent memory that + * Call this as part of initializing a host controller that uses the dma + * memory allocators. It initializes some pools of dma-coherent memory that * will be shared by all drivers using that controller, or returns a negative * errno value on error. * @@ -115,6 +115,12 @@ struct usb_hcd *hcd = bus->hcpriv; int i; + /* some USB hosts just use PIO */ + if (!bus->controller->dma_mask) { + *dma = ~(dma_addr_t) 0; + return kmalloc (size, mem_flags); + } + for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) return dma_pool_alloc (hcd->pool [i], mem_flags, dma); @@ -134,6 +140,12 @@ if (!addr) return; + + if (!bus->controller->dma_mask) { + kfree (addr); + return; + } + for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) { dma_pool_free (hcd->pool [i], addr, dma); diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c Sat Apr 3 19:38:40 2004 +++ b/drivers/usb/core/config.c Sat Apr 3 19:38:40 2004 @@ -72,13 +72,10 @@ return buffer - buffer0; } -static void usb_release_intf(struct device *dev) +static void usb_free_intf(struct usb_interface *intf) { - struct usb_interface *intf; int j; - intf = to_usb_interface(dev); - if (intf->altsetting) { for (j = 0; j < intf->num_altsetting; j++) { struct usb_host_interface *as = &intf->altsetting[j]; @@ -235,8 +232,6 @@ return -ENOMEM; } memset(interface, 0, sizeof(struct usb_interface)); - interface->dev.release = usb_release_intf; - device_initialize(&interface->dev); } /* Go through the descriptors, checking their length and counting the @@ -374,7 +369,7 @@ struct usb_interface *ifp = cf->interface[i]; if (ifp) - put_device(&ifp->dev); + usb_free_intf(ifp); } } kfree(dev->config); diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/core/devio.c Sat Apr 3 19:38:43 2004 @@ -430,19 +430,14 @@ static int findintfif(struct usb_device *dev, unsigned int ifn) { - unsigned int i, j; - struct usb_interface *iface; - struct usb_host_interface *alts; + unsigned int i; if (ifn & ~0xff) return -EINVAL; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - iface = dev->actconfig->interface[i]; - for (j = 0; j < iface->num_altsetting; j++) { - alts = &iface->altsetting[j]; - if (alts->desc.bInterfaceNumber == ifn) - return i; - } + if (dev->actconfig->interface[i]-> + altsetting[0].desc.bInterfaceNumber == ifn) + return i; } return -ENOENT; } @@ -688,9 +683,7 @@ return -EFAULT; if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; - interface = usb_ifnum_to_if(ps->dev, gd.interface); - if (!interface) - return -EINVAL; + interface = ps->dev->actconfig->interface[ret]; if (!interface->driver) return -ENODATA; strcpy(gd.driver, interface->driver->name); @@ -744,9 +737,7 @@ return -EFAULT; if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; - interface = usb_ifnum_to_if(ps->dev, setintf.interface); - if (!interface) - return -EINVAL; + interface = ps->dev->actconfig->interface[ret]; if (interface->driver) { if ((ret = checkintf(ps, ret))) return ret; diff -Nru a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c --- a/drivers/usb/core/driverfs.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/core/driverfs.c Sat Apr 3 19:38:42 2004 @@ -166,13 +166,9 @@ static ssize_t \ show_##field (struct device *dev, char *buf) \ { \ - struct usb_interface *intf; \ - int alt; \ + struct usb_interface *intf = to_usb_interface (dev); \ \ - intf = to_usb_interface (dev); \ - alt = intf->act_altsetting; \ - \ - return sprintf (buf, format_string, intf->altsetting[alt].desc.field); \ + return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/core/hcd-pci.c Sat Apr 3 19:38:43 2004 @@ -147,8 +147,12 @@ hcd->driver = driver; hcd->description = driver->description; hcd->self.bus_name = pci_name(dev); +#ifdef CONFIG_PCI_NAMES + hcd->product_desc = dev->pretty_name; +#else if (hcd->product_desc == NULL) hcd->product_desc = "USB Host Controller"; +#endif hcd->self.controller = &dev->dev; if ((retval = hcd_buffer_create (hcd)) != 0) { diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Sat Apr 3 19:38:44 2004 +++ b/drivers/usb/core/hcd.c Sat Apr 3 19:38:44 2004 @@ -1213,7 +1213,7 @@ break; } if (tmp != &urb->urb_list) { - retval = -EINVAL; + retval = -EIDRM; goto done; } @@ -1294,7 +1294,7 @@ spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); bye: - if (retval && sys && sys->driver) + if (retval != -EIDRM && sys && sys->driver) dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; } diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/core/hub.c Sat Apr 3 19:38:43 2004 @@ -560,7 +560,7 @@ struct usb_hub *hub; unsigned long flags; - desc = intf->altsetting + intf->act_altsetting; + desc = intf->cur_altsetting; dev = interface_to_usbdev(intf); /* Some hubs have a subclass of 1, which AFAICT according to the */ @@ -1344,15 +1344,15 @@ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *intf = dev->actconfig->interface[i]; - struct usb_interface_descriptor *as; + struct usb_interface_descriptor *desc; - as = &intf->altsetting[intf->act_altsetting].desc; - ret = usb_set_interface(dev, as->bInterfaceNumber, - as->bAlternateSetting); + desc = &intf->cur_altsetting->desc; + ret = usb_set_interface(dev, desc->bInterfaceNumber, + desc->bAlternateSetting); if (ret < 0) { err("failed to set active alternate setting " "for dev %s interface %d (error=%d)", - dev->devpath, i, ret); + dev->devpath, desc->bInterfaceNumber, ret); return ret; } } diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/core/message.c Sat Apr 3 19:38:42 2004 @@ -783,16 +783,19 @@ */ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) { - struct usb_host_interface *hintf = - &intf->altsetting[intf->act_altsetting]; + struct usb_host_interface *alt = intf->cur_altsetting; int i; - for (i = 0; i < hintf->desc.bNumEndpoints; ++i) { + for (i = 0; i < alt->desc.bNumEndpoints; ++i) { usb_disable_endpoint(dev, - hintf->endpoint[i].desc.bEndpointAddress); + alt->endpoint[i].desc.bEndpointAddress); } } +static void release_interface(struct device *dev) +{ +} + /* * usb_disable_device - Disable all the endpoints for a USB device * @dev: the device whose endpoints are being disabled @@ -827,7 +830,7 @@ interface = dev->actconfig->interface[i]; dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); - device_del(&interface->dev); + device_unregister (&interface->dev); } dev->actconfig = 0; if (dev->state == USB_STATE_CONFIGURED) @@ -876,12 +879,11 @@ void usb_enable_interface(struct usb_device *dev, struct usb_interface *intf) { - struct usb_host_interface *hintf = - &intf->altsetting[intf->act_altsetting]; + struct usb_host_interface *alt = intf->cur_altsetting; int i; - for (i = 0; i < hintf->desc.bNumEndpoints; ++i) - usb_enable_endpoint(dev, &hintf->endpoint[i].desc); + for (i = 0; i < alt->desc.bNumEndpoints; ++i) + usb_enable_endpoint(dev, &alt->endpoint[i].desc); } /** @@ -920,6 +922,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) { struct usb_interface *iface; + struct usb_host_interface *alt; int ret; int manual = 0; @@ -929,14 +932,15 @@ return -EINVAL; } - if (alternate < 0 || alternate >= iface->num_altsetting) + alt = usb_altnum_to_altsetting(iface, alternate); + if (!alt) { + warn("selecting invalid altsetting %d", alternate); return -EINVAL; + } ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - iface->altsetting[alternate] - .desc.bAlternateSetting, - interface, NULL, 0, HZ * 5); + alternate, interface, NULL, 0, HZ * 5); /* 9.4.10 says devices don't need this and are free to STALL the * request if the interface only has one alternate setting. @@ -957,7 +961,7 @@ /* prevent submissions using previous endpoint settings */ usb_disable_interface(dev, iface); - iface->act_altsetting = alternate; + iface->cur_altsetting = alt; /* If the interface only has one altsetting and the device didn't * accept the request, we attempt to carry out the equivalent action @@ -965,13 +969,11 @@ * new altsetting. */ if (manual) { - struct usb_host_interface *iface_as = - &iface->altsetting[alternate]; int i; - for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { + for (i = 0; i < alt->desc.bNumEndpoints; i++) { unsigned int epaddr = - iface_as->endpoint[i].desc.bEndpointAddress; + alt->endpoint[i].desc.bEndpointAddress; unsigned int pipe = __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr) | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN); @@ -1045,8 +1047,19 @@ /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; + struct usb_host_interface *alt; + + alt = usb_altnum_to_altsetting(intf, 0); - intf->act_altsetting = 0; + /* No altsetting 0? We'll assume the first altsetting. + * We could use a GetInterface call, but if a device is + * so non-compliant that it doesn't have altsetting 0 + * then I wouldn't trust its reply anyway. + */ + if (!alt) + alt = &intf->altsetting[0]; + + intf->cur_altsetting = alt; usb_enable_interface(dev, intf); } return 0; @@ -1135,25 +1148,34 @@ */ for (i = 0; i < cp->desc.bNumInterfaces; ++i) { struct usb_interface *intf = cp->interface[i]; - struct usb_interface_descriptor *desc; + struct usb_host_interface *alt; - intf->act_altsetting = 0; - desc = &intf->altsetting [0].desc; - usb_enable_interface(dev, intf); + alt = usb_altnum_to_altsetting(intf, 0); + /* No altsetting 0? We'll assume the first altsetting. + * We could use a GetInterface call, but if a device is + * so non-compliant that it doesn't have altsetting 0 + * then I wouldn't trust its reply anyway. + */ + if (!alt) + alt = &intf->altsetting[0]; + + intf->cur_altsetting = alt; + usb_enable_interface(dev, intf); intf->dev.parent = &dev->dev; intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; intf->dev.dma_mask = dev->dev.dma_mask; + intf->dev.release = release_interface; sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, - desc->bInterfaceNumber); + alt->desc.bInterfaceNumber); dev_dbg (&dev->dev, "registering %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - desc->bInterfaceNumber); - device_add (&intf->dev); + alt->desc.bInterfaceNumber); + device_register (&intf->dev); usb_create_driverfs_intf_files (intf); } } diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Sat Apr 3 19:38:44 2004 +++ b/drivers/usb/core/urb.c Sat Apr 3 19:38:44 2004 @@ -116,7 +116,8 @@ * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink - * (also called "request cancellation"). + * (a software-induced fault, also called "request cancelation"). + * * URBs may be submitted in interrupt context. * * The caller must have correctly initialized the URB before submitting @@ -127,12 +128,23 @@ * * Successful submissions return 0; otherwise this routine returns a * negative error number. If the submission is successful, the complete() - * callback from the urb will be called exactly once, when the USB core and - * host controller driver are finished with the urb. When the completion + * callback from the URB will be called exactly once, when the USB core and + * Host Controller Driver (HCD) are finished with the URB. When the completion * function is called, control of the URB is returned to the device * driver which issued the request. The completion handler may then * immediately free or reuse that URB. * + * With few exceptions, USB device drivers should never access URB fields + * provided by usbcore or the HCD until its complete() is called. + * The exceptions relate to periodic transfer scheduling. For both + * interrupt and isochronous urbs, as part of successful URB submission + * urb->interval is modified to reflect the actual transfer period used + * (normally some power of two units). And for isochronous urbs, + * urb->start_frame is modified to reflect when the URB's transfers were + * scheduled to start. Not all isochronous transfer scheduling policies + * will work, but most host controller drivers should easily handle ISO + * queues going from now until 10-200 msec into the future. + * * For control endpoints, the synchronous usb_control_msg() call is * often used (in non-interrupt context) instead of this call. * That is often used through convenience wrappers, for the requests @@ -143,15 +155,17 @@ * * URBs may be submitted to endpoints before previous ones complete, to * minimize the impact of interrupt latencies and system overhead on data - * throughput. This is required for continuous isochronous data streams, + * throughput. With that queuing policy, an endpoint's queue would never + * be empty. This is required for continuous isochronous data streams, * and may also be required for some kinds of interrupt transfers. Such - * queueing also maximizes bandwidth utilization by letting USB controllers + * queuing also maximizes bandwidth utilization by letting USB controllers * start work on later requests before driver software has finished the - * completion processing for earlier requests. + * completion processing for earlier (successful) requests. * - * Bulk and Isochronous URBs may always be queued. At this writing, all - * mainstream host controller drivers support queueing for control and - * interrupt transfer requests. + * As of Linux 2.6, all USB endpoint transfer queues support depths greater + * than one. This was previously a HCD-specific behavior, except for ISO + * transfers. Non-isochronous endpoint queues are inactive during cleanup + * after faults (transfer errors or cancelation). * * Reserved Bandwidth Transfers: * @@ -389,7 +403,7 @@ * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this * request is synchronous. Success is indicated by returning zero, * at which time the urb will have been unlinked and its completion - * handler will have been called with urb->status -ENOENT. Failure is + * handler will have been called with urb->status == -ENOENT. Failure is * indicated by any other return value. * * The synchronous cancelation mode may not be used @@ -400,8 +414,37 @@ * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this * request is asynchronous. Success is indicated by returning -EINPROGRESS, * at which time the urb will normally not have been unlinked. - * The completion function will see urb->status -ECONNRESET. Failure + * The completion function will see urb->status == -ECONNRESET. Failure * is indicated by any other return value. + * + * Unlinking and Endpoint Queues: + * + * Host Controller Driver (HCDs) place all the URBs for a particular + * endpoint in a queue. Normally the queue advances as the controller + * hardware processes each request. But when an URB terminates with any + * fault (such as an error, or being unlinked) its queue stops, at least + * until that URB's completion routine returns. It is guaranteed that + * the queue will not restart until all its unlinked URBs have been fully + * retired, with their completion routines run, even if that's not until + * some time after the original completion handler returns. + * + * This means that USB device drivers can safely build deep queues for + * large or complex transfers, and clean them up reliably after any sort + * of aborted transfer by unlinking all pending URBs at the first fault. + * + * Note that an URB terminating early because a short packet was received + * will count as an error if and only if the URB_SHORT_NOT_OK flag is set. + * Also, that all unlinks performed in any URB completion handler must + * be asynchronous. + * + * Queues for isochronous endpoints are treated differently, because they + * advance at fixed rates. Such queues do not stop when an URB is unlinked. + * An unlinked URB may leave a gap in the stream of packets. It is undefined + * whether such gaps can be filled in. + * + * When control URBs terminates with an error, it is likely that the + * status stage of the transfer will not take place, even if it is merely + * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set. */ int usb_unlink_urb(struct urb *urb) { diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/core/usb.c Sat Apr 3 19:38:43 2004 @@ -189,7 +189,7 @@ } /** - * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal) + * usb_ifnum_to_if - get the interface object with a given interface number * @dev: the device whose current configuration is considered * @ifnum: the desired interface * @@ -220,6 +220,33 @@ } /** + * usb_altnum_to_altsetting - get the altsetting structure with a given + * alternate setting number. + * @intf: the interface containing the altsetting in question + * @altnum: the desired alternate setting number + * + * This searches the altsetting array of the specified interface for + * an entry with the correct bAlternateSetting value and returns a pointer + * to that entry, or null. + * + * Note that altsettings need not be stored sequentially by number, so + * it would be incorrect to assume that the first altsetting entry in + * the array corresponds to altsetting zero. This routine helps device + * drivers avoid such mistakes. + */ +struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, + unsigned int altnum) +{ + int i; + + for (i = 0; i < intf->num_altsetting; i++) { + if (intf->altsetting[i].desc.bAlternateSetting == altnum) + return &intf->altsetting[i]; + } + return NULL; +} + +/** * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number * @dev: the device whose current configuration+altsettings is considered * @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate. @@ -247,7 +274,7 @@ /* only endpoints in current altsetting are active */ intf = config->interface[i]; - alt = intf->altsetting + intf->act_altsetting; + alt = intf->cur_altsetting; for (k = 0; k < alt->desc.bNumEndpoints; k++) if (epnum == alt->endpoint[k].desc.bEndpointAddress) @@ -421,7 +448,7 @@ if (id == NULL) return NULL; - intf = &interface->altsetting [interface->act_altsetting]; + intf = interface->cur_altsetting; dev = interface_to_usbdev(interface); /* It is important to check that id->driver_info is nonzero, @@ -624,7 +651,7 @@ scratch += length; if (usb_dev->descriptor.bDeviceClass == 0) { - int alt = intf->act_altsetting; + struct usb_host_interface *alt = intf->cur_altsetting; /* 2.4 only exposed interface zero. in 2.5, hotplug * agents are called for all interfaces, and can use @@ -633,9 +660,9 @@ envp [i++] = scratch; length += snprintf (scratch, buffer_size - length, "INTERFACE=%d/%d/%d", - intf->altsetting[alt].desc.bInterfaceClass, - intf->altsetting[alt].desc.bInterfaceSubClass, - intf->altsetting[alt].desc.bInterfaceProtocol); + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol); if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; ++length; @@ -1297,6 +1324,13 @@ return urb; } +/* XXX DISABLED, no users currently. If you wish to re-enable this + * XXX please determine whether the sync is to transfer ownership of + * XXX the buffer from device to cpu or vice verse, and thusly use the + * XXX appropriate _for_{cpu,device}() method. -DaveM + */ +#if 0 + /** * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) * @urb: urb whose transfer_buffer/setup_packet will be synchronized @@ -1325,6 +1359,7 @@ DMA_TO_DEVICE); } } +#endif /** * usb_buffer_unmap - free DMA mapping(s) for an urb @@ -1403,6 +1438,13 @@ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +/* XXX DISABLED, no users currently. If you wish to re-enable this + * XXX please determine whether the sync is to transfer ownership of + * XXX the buffer from device to cpu or vice verse, and thusly use the + * XXX appropriate _for_{cpu,device}() method. -DaveM + */ +#if 0 + /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped @@ -1428,6 +1470,7 @@ dma_sync_sg (controller, sg, n_hw_ents, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +#endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist @@ -1582,6 +1625,7 @@ EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_find_interface); EXPORT_SYMBOL(usb_ifnum_to_if); +EXPORT_SYMBOL(usb_altnum_to_altsetting); EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_disconnect); @@ -1595,11 +1639,15 @@ EXPORT_SYMBOL (usb_buffer_free); EXPORT_SYMBOL (usb_buffer_map); +#if 0 EXPORT_SYMBOL (usb_buffer_dmasync); +#endif EXPORT_SYMBOL (usb_buffer_unmap); EXPORT_SYMBOL (usb_buffer_map_sg); +#if 0 EXPORT_SYMBOL (usb_buffer_dmasync_sg); +#endif EXPORT_SYMBOL (usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/gadget/Kconfig Sat Apr 3 19:38:42 2004 @@ -3,6 +3,15 @@ # (a) a peripheral controller, and # (b) the gadget driver using it. # +# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! +# +# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). +# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). +# - Some systems have both kinds of of controller. +# +# With help from a special transceiver and a "Mini-AB" jack, systems with +# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). +# menu "USB Gadget Support" config USB_GADGET @@ -11,7 +20,7 @@ USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. The USB hardware is asymmetric, which makes it easier to set up: - you can't connect two "to-the-host" connectors to each other. + you can't connect a "to-the-host" connector to a peripheral. Linux can run in the host, or in the peripheral. In both cases you need a low level bus controller driver, and some software @@ -43,6 +52,7 @@ config USB_GADGET_NET2280 boolean "NetChip 2280" depends on PCI + select USB_GADGET_DUALSPEED help NetChip 2280 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. @@ -126,6 +136,13 @@ endchoice +config USB_GADGET_DUALSPEED + bool + depends on USB_GADGET + default n + help + Means that gadget drivers should include extra descriptors + and code to handle dual-speed controllers. # # USB Gadget Drivers diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/gadget/Makefile Sat Apr 3 19:38:41 2004 @@ -8,8 +8,8 @@ # # USB gadget drivers # -g_zero-objs := zero.o usbstring.o -g_ether-objs := ether.o usbstring.o +g_zero-objs := zero.o usbstring.o config.o +g_ether-objs := ether.o usbstring.o config.o g_serial-objs := serial.o usbstring.o gadgetfs-objs := inode.o usbstring.o g_file_storage-objs := file_storage.o usbstring.o diff -Nru a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/config.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,116 @@ +/* + * usb/gadget/config.c -- simplify building config descriptors + * + * Copyright (C) 2003 David Brownell + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include + + +/** + * usb_descriptor_fillbuf - fill buffer with descriptors + * @buf: Buffer to be filled + * @buflen: Size of buf + * @src: Array of descriptor pointers, terminated by null pointer. + * + * Copies descriptors into the buffer, returning the length or a + * negative error code if they can't all be copied. Useful when + * assembling descriptors for an associated set of interfaces used + * as part of configuring a composite device; or in other cases where + * sets of descriptors need to be marshaled. + */ +int +usb_descriptor_fillbuf(void *buf, unsigned buflen, + const struct usb_descriptor_header **src) +{ + u8 *dest = buf; + + if (!src) + return -EINVAL; + + /* fill buffer from src[] until null descriptor ptr */ + for (; 0 != *src; src++) { + unsigned len = (*src)->bLength; + + if (len > buflen) + return -EINVAL; + memcpy(dest, *src, len); + buflen -= len; + dest += len; + } + return dest - (u8 *)buf; +} + + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} + diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/gadget/ether.c Sat Apr 3 19:38:56 2004 @@ -124,7 +124,6 @@ * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support * WAKEUP ... if hardware supports remote wakeup AND we will issue the * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * @@ -162,7 +161,6 @@ #define EP_IN_NUM 2 static const char EP_STATUS_NAME [] = "ep-f"; #define EP_STATUS_NUM 3 -#define HIGHSPEED /* supports remote wakeup, but this driver doesn't */ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); @@ -311,7 +309,7 @@ #define DEFAULT_QLEN 2 /* double buffering by default */ #endif -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED static unsigned qmult = 5; module_param (qmult, uint, S_IRUGO|S_IWUSR); @@ -324,7 +322,7 @@ /* also defer IRQs on highspeed TX */ #define TX_DELAY DEFAULT_QLEN -#else /* !HIGHSPEED ... full speed: */ +#else /* full speed (low speed doesn't do bulk) */ #define qlen(gadget) DEFAULT_QLEN #endif @@ -607,7 +605,26 @@ .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &fs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_sink_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -660,6 +677,25 @@ .bNumConfigurations = 1, }; +static const struct usb_descriptor_header *hs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &hs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -669,7 +705,7 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -704,86 +740,25 @@ static int config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { - const unsigned config_len = USB_DT_CONFIG_SIZE -#ifdef DEV_CONFIG_CDC - + 2 * USB_DT_INTERFACE_SIZE - + sizeof header_desc - + sizeof union_desc - + sizeof ether_desc -#ifdef EP_STATUS_NUM - + USB_DT_ENDPOINT_SIZE -#endif -#endif /* DEV_CONFIG_CDC */ - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; + int len; + const struct usb_descriptor_header **function = fs_function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (speed == USB_SPEED_HIGH); -#ifdef HIGHSPEED - int hs; -#endif - /* a single configuration must always be index 0 */ - if (index > 0) - return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; - - /* config (or other speed config) */ - memcpy (buf, ð_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#endif - -#ifdef DEV_CONFIG_CDC - /* control interface, class descriptors, optional status endpoint */ - memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - memcpy (buf, &header_desc, sizeof header_desc); - buf += sizeof header_desc; - memcpy (buf, &union_desc, sizeof union_desc); - buf += sizeof union_desc; - memcpy (buf, ðer_desc, sizeof ether_desc); - buf += sizeof ether_desc; - -#ifdef EP_STATUS_NUM -#ifdef HIGHSPEED if (hs) - memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE); - else -#endif /* HIGHSPEED */ - memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; -#endif /* EP_STATUS_NUM */ - - /* default data altsetting has no endpoints */ - memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#endif /* DEV_CONFIG_CDC */ - - /* the "real" data interface has two endpoints */ - memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#ifdef HIGHSPEED - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + function = hs_function; #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - return config_len; + /* a single configuration must always be index 0 */ + if (index > 0) + return -EINVAL; + len = usb_gadget_config_buf (ð_config, buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -992,7 +967,7 @@ switch (gadget->speed) { case USB_SPEED_FULL: speed = "full"; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: speed = "high"; break; #endif default: speed = "?"; break; @@ -1163,15 +1138,19 @@ value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, ctrl->wValue >> 8, @@ -1675,7 +1654,7 @@ #endif req->length = length; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) @@ -1798,7 +1777,7 @@ #endif device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; #endif @@ -1894,7 +1873,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff -Nru a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/gadget_chips.h Sat Apr 3 19:38:57 2004 @@ -0,0 +1,57 @@ +/* + * USB device controllers have lots of quirks. Use these macros in + * gadget drivers or other code that needs to deal with them, and which + * autoconfigures instead of using early binding to the hardware. + * + * This could eventually work like the ARM mach_is_*() stuff, driven by + * some config file that gets updated as new hardware is supported. + * + * NOTE: some of these controller drivers may not be available yet. + */ +#ifdef CONFIG_USB_GADGET_NET2280 +#define gadget_is_net2280(g) !strcmp("net2280", (g)->name) +#else +#define gadget_is_net2280(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_PXA +#define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) +#else +#define gadget_is_pxa(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_GOKU +#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name) +#else +#define gadget_is_goku(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SUPERH +#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name) +#else +#define gadget_is_sh(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SA1100 +#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name) +#else +#define gadget_is_sa1100(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_MQ11XX +#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) +#else +#define gadget_is_mq11xx(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_OMAP +#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) +#else +#define gadget_is_omap(g) 0 +#endif + +// CONFIG_USB_GADGET_AT91RM9200 +// CONFIG_USB_GADGET_SX2 +// CONFIG_USB_GADGET_AU1X00 +// ... + diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/gadget/net2280.c Sat Apr 3 19:38:41 2004 @@ -2663,7 +2663,7 @@ /* tear down the binding between this driver and the pci device */ -static void __exit net2280_remove (struct pci_dev *pdev) +static void net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); @@ -2736,6 +2736,7 @@ spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; + dev->gadget.is_dualspeed = 1; /* the "gadget" abstracts/virtualizes the controller */ strcpy (dev->gadget.dev.bus_id, "gadget"); @@ -2884,7 +2885,7 @@ .id_table = pci_ids, .probe = net2280_probe, - .remove = __exit_p(net2280_remove), + .remove = net2280_remove, /* FIXME add power management support */ }; diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c --- a/drivers/usb/gadget/usbstring.c Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/gadget/usbstring.c Sat Apr 3 19:38:45 2004 @@ -16,24 +16,89 @@ #include #include +#include + + +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len) +{ + int count = 0; + u8 c; + u16 uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u8) *s++) != 0) { + if (unlikely(c & 0x80)) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + put_unaligned (cpu_to_le16 (uchar), cp++); + count++; + len--; + } + return count; +fail: + return -1; +} + /** * usb_gadget_get_string - fill out a string descriptor - * @table: of c strings using iso latin/1 characters + * @table: of c strings encoded using UTF-8 * @id: string id, from low byte of wValue in get string descriptor * @buf: at least 256 bytes * - * Finds the iso latin/1 string matching the ID, and converts it into a + * Finds the UTF-8 string matching the ID, and converts it into a * string descriptor in utf16-le. * Returns length of descriptor (always even) or negative errno * - * If your driver needs stings in multiple languages, you'll need to - * to use some alternate solution for languages where the ISO 8859/1 - * (latin/1) character set can't be used. For example, they can't be - * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other - * languages. You'd likely "switch (wIndex) { ... }" in your ep0 - * string descriptor logic, using this routine in cases where "western - * european" characters suffice for the strings being returned. + * If your driver needs stings in multiple languages, you'll probably + * "switch (wIndex) { ... }" in your ep0 string descriptor logic, + * using this routine after choosing which set of UTF-8 strings to use. + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 + * characters (which are also widely used in C strings). */ int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) @@ -59,13 +124,12 @@ /* string descriptors have length, tag, then UTF16-LE text */ len = min ((size_t) 126, strlen (s->s)); + memset (buf + 2, 0, 2 * len); /* zero all the bytes */ + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len); + if (len < 0) + return -EINVAL; buf [0] = (len + 1) * 2; buf [1] = USB_DT_STRING; - memset (buf + 2, 0, 2 * len); /* zero all the high bytes */ - while (len) { - buf [2 * len] = s->s [len - 1]; - len--; - } return buf [0]; } diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/gadget/zero.c Sat Apr 3 19:38:43 2004 @@ -1,7 +1,7 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,6 +103,11 @@ /*-------------------------------------------------------------------------*/ /* + * driver assumes self-powered hardware, and + * has no way for users to trigger remote wakeup. + */ + +/* * hardware-specific configuration, controlled by which device * controller driver was configured. * @@ -110,11 +115,6 @@ * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * * add other defines for other portability issues, like hardware that * for some reason doesn't handle full speed bulk maxpacket of 64. @@ -138,9 +138,6 @@ #define EP_OUT_NUM 2 static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 -#define HIGHSPEED -/* specific hardware configs could be bus-powered */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -161,8 +158,6 @@ #define EP_OUT_NUM 12 static const char EP_IN_NAME [] = "ep11in-bulk"; #define EP_IN_NUM 11 -/* doesn't support bus-powered operation */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -183,8 +178,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2in-bulk"; #define EP_IN_NUM 2 -/* doesn't support bus-powered operation */ -/* doesn't support remote wakeup? */ #endif /* @@ -199,7 +192,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2-bulk"; #define EP_IN_NUM 2 -/* doesn't support remote wakeup */ #endif /*-------------------------------------------------------------------------*/ @@ -208,30 +200,6 @@ # error Configure some USB peripheral controller driver! #endif -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif - /*-------------------------------------------------------------------------*/ /* big enough to hold our biggest descriptor */ @@ -290,8 +258,8 @@ /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to - * work better with hosts (like Linux ... for now!) where config - * changes are problematic. + * work better with hosts where config changes are problematic. + * Or controllers (like superh) that only support one config. */ static int loopdefault = 0; @@ -301,7 +269,7 @@ /* Thanks to NetChip Technologies for donating this product ID. * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ @@ -353,8 +321,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_SOURCE_SINK, .iConfiguration = STRING_SOURCE_SINK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; static const struct usb_config_descriptor @@ -366,8 +334,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_LOOPBACK, .iConfiguration = STRING_LOOPBACK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; /* one interface in each configuration */ @@ -414,7 +382,21 @@ .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -425,22 +407,20 @@ * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; @@ -456,6 +436,20 @@ .bNumConfigurations = 2, }; +static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + +static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -464,13 +458,14 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static char manufacturer [40]; static char serial [40]; /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, { STRING_LOOPBACK, loopback, }, @@ -502,60 +497,42 @@ * device?) */ static int -config_buf (enum usb_device_speed speed, +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { - int is_source_sink; - const unsigned config_len = USB_DT_CONFIG_SIZE - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; -#ifdef HIGHSPEED - int hs; + int is_source_sink; + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (gadget->speed == USB_SPEED_HIGH); #endif + /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; is_source_sink = loopdefault ? (index == 1) : (index == 0); - /* config (or other speed config) */ - if (is_source_sink) - memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE); - else - memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; - - /* one interface */ - if (is_source_sink) - memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE); - else - memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* the endpoints in that interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + if (hs) + function = is_source_sink + ? hs_source_sink_function + : hs_loopback_function; + else #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - - return config_len; + function = is_source_sink + ? fs_source_sink_function + : fs_loopback_function; + + len = usb_gadget_config_buf (is_source_sink + ? &source_sink_config + : &loopback_config, + buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -1019,17 +996,21 @@ value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf (gadget, req->buf, ctrl->wValue >> 8, ctrl->wValue & 0xff); if (value >= 0) @@ -1212,14 +1193,26 @@ dev->req->complete = zero_setup_complete; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assume ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif gadget->ep0->driver_data = dev; INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME); + + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + return 0; enomem: @@ -1230,7 +1223,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver zero_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig --- a/drivers/usb/host/Kconfig Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/host/Kconfig Sat Apr 3 19:38:56 2004 @@ -29,6 +29,15 @@ To compile this driver as a module, choose M here: the module will be called ehci-hcd. +config USB_EHCI_SPLIT_ISO + bool "Full speed ISO transactions (EXPERIMENTAL)" + depends on USB_EHCI_HCD && EXPERIMENTAL + default n + ---help--- + This code is new and hasn't been used with many different + EHCI or USB 2.0 transaction translator implementations. + It should work for ISO-OUT transfers, like audio. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/host/ehci-dbg.c Sat Apr 3 19:38:55 2004 @@ -579,7 +579,11 @@ break; case Q_TYPE_SITD: temp = scnprintf (next, size, - " sitd/%p", p.sitd); + " sitd%d-%04x/%p", + p.sitd->stream->interval, + le32_to_cpup (&p.sitd->hw_uframe) + & 0x0000ffff, + p.sitd); tag = Q_NEXT_TYPE (p.sitd->hw_next); p = p.sitd->sitd_next; break; diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/host/ehci-hcd.c Sat Apr 3 19:38:45 2004 @@ -106,8 +106,6 @@ #undef EHCI_VERBOSE_DEBUG #undef EHCI_URB_TRACE -// #define have_split_iso - #ifdef DEBUG #define EHCI_STATS #endif @@ -676,6 +674,7 @@ /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. */ if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0)) timer_action (ehci, TIMER_IO_WATCHDOG); @@ -796,13 +795,8 @@ case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) return itd_submit (ehci, urb, mem_flags); -#ifdef have_split_iso else return sitd_submit (ehci, urb, mem_flags); -#else - dbg ("no split iso support yet"); - return -ENOSYS; -#endif /* have_split_iso */ } } diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/host/ehci-sched.c Sat Apr 3 19:38:42 2004 @@ -53,14 +53,10 @@ return &periodic->fstn->fstn_next; case Q_TYPE_ITD: return &periodic->itd->itd_next; -#ifdef have_split_iso - case Q_TYPE_SITD: + // case Q_TYPE_SITD: + default: return &periodic->sitd->sitd_next; -#endif /* have_split_iso */ } - dbg ("BAD shadow %p tag %d", periodic->ptr, tag); - // BUG (); - return 0; } /* returns true after successful unlink */ @@ -133,7 +129,6 @@ hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; -#ifdef have_split_iso case Q_TYPE_SITD: /* is it in the S-mask? (count SPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { @@ -154,7 +149,6 @@ hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; -#endif /* have_split_iso */ default: BUG (); } @@ -229,7 +223,8 @@ if (same_tt (dev, here.itd->urb->dev)) { u16 mask; - mask = le32_to_cpu (here.sitd->hw_uframe); + mask = le32_to_cpu (here.sitd + ->hw_uframe); /* FIXME assumes no gap for IN! */ mask |= mask >> 8; if (mask & uf_mask) @@ -237,7 +232,7 @@ } type = Q_NEXT_TYPE (here.qh->hw_next); here = here.sitd->sitd_next; - break; + continue; // case Q_TYPE_FSTN: default: ehci_dbg (ehci, @@ -698,12 +693,27 @@ // BUG_ON (!list_empty(&stream->td_list)); while (!list_empty (&stream->free_list)) { - struct ehci_itd *itd; + struct list_head *entry; - itd = list_entry (stream->free_list.next, - struct ehci_itd, itd_list); - list_del (&itd->itd_list); - dma_pool_free (ehci->itd_pool, itd, itd->itd_dma); + entry = stream->free_list.next; + list_del (entry); + + /* knows about ITD vs SITD */ + if (stream->highspeed) { + struct ehci_itd *itd; + + itd = list_entry (entry, struct ehci_itd, + itd_list); + dma_pool_free (ehci->itd_pool, itd, + itd->itd_dma); + } else { + struct ehci_sitd *sitd; + + sitd = list_entry (entry, struct ehci_sitd, + sitd_list); + dma_pool_free (ehci->sitd_pool, sitd, + sitd->sitd_dma); + } } is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; @@ -858,6 +868,7 @@ int i; unsigned num_itds; struct ehci_iso_sched *sched; + unsigned long flags; sched = iso_sched_alloc (urb->number_of_packets, mem_flags); if (unlikely (sched == 0)) @@ -871,6 +882,7 @@ num_itds = urb->number_of_packets; /* allocate/init ITDs */ + spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < num_itds; i++) { /* free_list.next might be cache-hot ... but maybe @@ -884,8 +896,14 @@ list_del (&itd->itd_list); itd_dma = itd->itd_dma; } else + itd = 0; + + if (!itd) { + spin_unlock_irqrestore (&ehci->lock, flags); itd = dma_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma); + spin_lock_irqsave (&ehci->lock, flags); + } if (unlikely (0 == itd)) { iso_sched_free (stream, sched); @@ -895,6 +913,7 @@ itd->itd_dma = itd_dma; list_add (&itd->itd_list, &sched->td_list); } + spin_unlock_irqrestore (&ehci->lock, flags); /* temporarily store schedule info in hcpriv */ urb->hcpriv = sched; @@ -909,11 +928,11 @@ struct ehci_hcd *ehci, u32 mod, u32 uframe, - u32 end, u8 usecs, u32 period ) { + uframe %= period; do { /* can't commit more than 80% periodic == 100 usec */ if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) @@ -922,8 +941,7 @@ /* we know urb->interval is 2^N uframes */ uframe += period; - uframe %= mod; - } while (uframe != end); + } while (uframe < mod); return 1; } @@ -933,7 +951,6 @@ u32 mod, struct ehci_iso_stream *stream, u32 uframe, - u32 end, struct ehci_iso_sched *sched, u32 period_uframes ) @@ -952,12 +969,20 @@ */ /* check bandwidth */ + uframe %= period_uframes; do { u32 max_used; frame = uframe >> 3; uf = uframe & 7; + /* tt must be idle for start(s), any gap, and csplit. + * assume scheduling slop leaves 10+% for control/bulk. + */ + if (!tt_no_collision (ehci, period_uframes << 3, + stream->udev, frame, mask)) + return 0; + /* check starts (OUT uses more than one) */ max_used = 100 - stream->usecs; for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { @@ -969,25 +994,19 @@ if (stream->c_usecs) { max_used = 100 - stream->c_usecs; do { - /* tt is busy in the gap before CSPLIT */ tmp = 1 << uf; - mask |= tmp; tmp <<= 8; - if (stream->raw_mask & tmp) - break; + if ((stream->raw_mask & tmp) == 0) + continue; + if (periodic_usecs (ehci, frame, uf) + > max_used) + return 0; } while (++uf < 8); - if (periodic_usecs (ehci, frame, uf) > max_used) - return 0; } /* we know urb->interval is 2^N uframes */ uframe += period_uframes; - uframe %= mod; - } while (uframe != end); - - /* tt must be idle for start(s), any gap, and csplit */ - if (!tt_no_collision (ehci, period_uframes, stream->udev, frame, mask)) - return 0; + } while (uframe < mod); stream->splits = stream->raw_mask << (uframe & 7); cpu_to_le32s (&stream->splits); @@ -1014,7 +1033,7 @@ struct ehci_iso_stream *stream ) { - u32 now, start, end, max, period; + u32 now, start, max, period; int status; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; @@ -1036,8 +1055,6 @@ /* when's the last uframe this urb could start? */ max = now + mod; - max -= sched->span; - max -= 8 * SCHEDULE_SLOP; /* typical case: reuse current schedule. stream is still active, * and no gaps from host falling behind (irq delays etc) @@ -1046,9 +1063,11 @@ start = stream->next_uframe; if (start < now) start += mod; - if (likely (start < max)) + if (likely ((start + sched->span) < max)) goto ready; - /* else fell behind; try to reschedule */ + /* else fell behind; someday, try to reschedule */ + status = -EL2NSYNC; + goto fail; } /* need to schedule; when's the next (u)frame we could start? @@ -1059,63 +1078,40 @@ */ start = SCHEDULE_SLOP * 8 + (now & ~0x07); start %= mod; - end = start; + stream->next_uframe = start; /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ period = urb->interval; if (!stream->highspeed) period <<= 3; - if (max > (start + period)) - max = start + period; - /* hack: account for itds already scheduled to this endpoint */ - if (list_empty (&stream->td_list)) - end = max; - - /* within [start..max] find a uframe slot with enough bandwidth */ - end %= mod; - do { + /* find a uframe slot with enough bandwidth */ + for (; start < (stream->next_uframe + period); start++) { int enough_space; /* check schedule: enough space? */ if (stream->highspeed) - enough_space = itd_slot_ok (ehci, mod, start, end, + enough_space = itd_slot_ok (ehci, mod, start, stream->usecs, period); else { if ((start % 8) >= 6) continue; enough_space = sitd_slot_ok (ehci, mod, stream, - start, end, sched, period); + start, sched, period); } - /* (re)schedule it here if there's enough bandwidth */ + /* schedule it here if there's enough bandwidth */ if (enough_space) { - start %= mod; - if (unlikely (!list_empty (&stream->td_list))) { - /* host fell behind ... maybe irq latencies - * delayed this request queue for too long. - */ - stream->rescheduled++; - dev_dbg (&urb->dev->dev, - "iso%d%s %d.%d skip %d.%d\n", - stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) - ? "in" : "out", - stream->next_uframe >> 3, - stream->next_uframe & 0x7, - start >> 3, start & 0x7); - } - stream->next_uframe = start; + stream->next_uframe = start % mod; goto ready; } - - } while (++start < max); + } /* no room in the schedule */ - ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n", + ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", list_empty (&stream->td_list) ? "" : "re", - urb, now, end, max); + urb, now, max); status = -ENOSPC; fail: @@ -1260,6 +1256,7 @@ iso_sched_free (stream, iso_sched); urb->hcpriv = 0; + timer_action (ehci, TIMER_IO_WATCHDOG); if (unlikely (!ehci->periodic_sched++)) return enable_periodic (ehci); return 0; @@ -1404,18 +1401,392 @@ return status; } -#ifdef have_split_iso +#ifdef CONFIG_USB_EHCI_SPLIT_ISO /*-------------------------------------------------------------------------*/ /* - * "Split ISO TDs" ... used for USB 1.1 devices going through - * the TTs in USB 2.0 hubs. - * - * FIXME not yet implemented + * "Split ISO TDs" ... used for USB 1.1 devices going through the + * TTs in USB 2.0 hubs. These need microframe scheduling. */ -#endif /* have_split_iso */ +static inline void +sitd_sched_init ( + struct ehci_iso_sched *iso_sched, + struct ehci_iso_stream *stream, + struct urb *urb +) +{ + unsigned i; + dma_addr_t dma = urb->transfer_dma; + + /* how many frames are needed for these transfers */ + iso_sched->span = urb->number_of_packets * stream->interval; + + /* figure out per-frame sitd fields that we'll need later + * when we fit new sitds into the schedule. + */ + for (i = 0; i < urb->number_of_packets; i++) { + struct ehci_iso_packet *packet = &iso_sched->packet [i]; + unsigned length; + dma_addr_t buf; + u32 trans; + + length = urb->iso_frame_desc [i].length & 0x03ff; + buf = dma + urb->iso_frame_desc [i].offset; + + trans = SITD_STS_ACTIVE; + if (((i + 1) == urb->number_of_packets) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) + trans |= SITD_IOC; + trans |= length << 16; + packet->transaction = cpu_to_le32 (trans); + + /* might need to cross a buffer page within a td */ + packet->bufp = buf; + buf += length; + packet->buf1 = buf & ~0x0fff; + if (packet->buf1 != (buf & ~(u64)0x0fff)) + packet->cross = 1; + + /* OUT uses multiple start-splits */ + if (stream->bEndpointAddress & USB_DIR_IN) + continue; + length = 1 + (length / 188); + packet->buf1 |= length; + if (length > 1) /* BEGIN vs ALL */ + packet->buf1 |= 1 << 3; + } +} + +static int +sitd_urb_transaction ( + struct ehci_iso_stream *stream, + struct ehci_hcd *ehci, + struct urb *urb, + int mem_flags +) +{ + struct ehci_sitd *sitd; + dma_addr_t sitd_dma; + int i; + struct ehci_iso_sched *iso_sched; + unsigned long flags; + + iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags); + if (iso_sched == 0) + return -ENOMEM; + + sitd_sched_init (iso_sched, stream, urb); + + /* allocate/init sITDs */ + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < urb->number_of_packets; i++) { + + /* NOTE: for now, we don't try to handle wraparound cases + * for IN (using sitd->hw_backpointer, like a FSTN), which + * means we never need two sitds for full speed packets. + */ + + /* free_list.next might be cache-hot ... but maybe + * the HC caches it too. avoid that issue for now. + */ + + /* prefer previously-allocated sitds */ + if (!list_empty(&stream->free_list)) { + sitd = list_entry (stream->free_list.prev, + struct ehci_sitd, sitd_list); + list_del (&sitd->sitd_list); + sitd_dma = sitd->sitd_dma; + } else + sitd = 0; + + if (!sitd) { + spin_unlock_irqrestore (&ehci->lock, flags); + sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags, + &sitd_dma); + spin_lock_irqsave (&ehci->lock, flags); + } + + if (!sitd) { + iso_sched_free (stream, iso_sched); + spin_unlock_irqrestore (&ehci->lock, flags); + return -ENOMEM; + } + memset (sitd, 0, sizeof *sitd); + sitd->sitd_dma = sitd_dma; + list_add (&sitd->sitd_list, &iso_sched->td_list); + } + + /* temporarily store schedule info in hcpriv */ + urb->hcpriv = iso_sched; + urb->error_count = 0; + + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +sitd_patch ( + struct ehci_iso_stream *stream, + struct ehci_sitd *sitd, + struct ehci_iso_sched *iso_sched, + unsigned index +) +{ + struct ehci_iso_packet *uf = &iso_sched->packet [index]; + u64 bufp = uf->bufp; + + sitd->hw_next = EHCI_LIST_END; + sitd->hw_fullspeed_ep = stream->address; + sitd->hw_uframe = stream->splits; + sitd->hw_results = uf->transaction; + sitd->hw_backpointer = EHCI_LIST_END; + + bufp = uf->bufp; + sitd->hw_buf [0] = cpu_to_le32 (bufp); + sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32); + + sitd->hw_buf [1] = cpu_to_le32 (uf->buf1); + if (uf->cross) { + bufp += 4096; + sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32); + } + sitd->index = index; +} + +static inline void +sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd) +{ + /* note: sitd ordering could matter (CSPLIT then SSPLIT) */ + sitd->sitd_next = ehci->pshadow [frame]; + sitd->hw_next = ehci->periodic [frame]; + ehci->pshadow [frame].sitd = sitd; + sitd->frame = frame; + wmb (); + ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD; +} + +/* fit urb's sitds into the selected schedule slot; activate as needed */ +static int +sitd_link_urb ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned mod, + struct ehci_iso_stream *stream +) +{ + int packet; + unsigned next_uframe; + struct ehci_iso_sched *sched = urb->hcpriv; + struct ehci_sitd *sitd; + + next_uframe = stream->next_uframe; + + if (list_empty(&stream->td_list)) { + /* usbfs ignores TT bandwidth */ + hcd_to_bus (&ehci->hcd)->bandwidth_allocated + += stream->bandwidth; + ehci_vdbg (ehci, + "sched dev%s ep%d%s-iso [%d] %dms/%04x\n", + urb->dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + (next_uframe >> 3) % ehci->periodic_size, + stream->interval, le32_to_cpu (stream->splits)); + stream->start = jiffies; + } + hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++; + + /* fill sITDs frame by frame */ + for (packet = 0, sitd = 0; + packet < urb->number_of_packets; + packet++) { + + /* ASSERT: we have all necessary sitds */ + BUG_ON (list_empty (&sched->td_list)); + + /* ASSERT: no itds for this endpoint in this frame */ + + sitd = list_entry (sched->td_list.next, + struct ehci_sitd, sitd_list); + list_move_tail (&sitd->sitd_list, &stream->td_list); + sitd->stream = iso_stream_get (stream); + sitd->urb = usb_get_urb (urb); + + sitd_patch (stream, sitd, sched, packet); + sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size, + sitd); + + next_uframe += stream->interval << 3; + stream->depth += stream->interval << 3; + } + stream->next_uframe = next_uframe % mod; + + /* don't need that schedule data any more */ + iso_sched_free (stream, sched); + urb->hcpriv = 0; + + timer_action (ehci, TIMER_IO_WATCHDOG); + if (!ehci->periodic_sched++) + return enable_periodic (ehci); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ + | SITD_STS_XACT | SITD_STS_MMF | SITD_STS_STS) + +static unsigned +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + struct pt_regs *regs +) { + struct urb *urb = sitd->urb; + struct usb_iso_packet_descriptor *desc; + u32 t; + int urb_index = -1; + struct ehci_iso_stream *stream = sitd->stream; + struct usb_device *dev; + + urb_index = sitd->index; + desc = &urb->iso_frame_desc [urb_index]; + t = le32_to_cpup (&sitd->hw_results); + + /* report transfer status */ + if (t & SITD_ERRS) { + urb->error_count++; + if (t & SITD_STS_DBE) + desc->status = usb_pipein (urb->pipe) + ? -ENOSR /* hc couldn't read */ + : -ECOMM; /* hc couldn't write */ + else if (t & SITD_STS_BABBLE) + desc->status = -EOVERFLOW; + else /* XACT, MMF, etc */ + desc->status = -EPROTO; + } else { + desc->status = 0; + desc->actual_length = desc->length - SITD_LENGTH (t); + } + + usb_put_urb (urb); + sitd->urb = 0; + sitd->stream = 0; + list_move (&sitd->sitd_list, &stream->free_list); + stream->depth -= stream->interval << 3; + iso_stream_put (ehci, stream); + + /* handle completion now? */ + if ((urb_index + 1) != urb->number_of_packets) + return 0; + + /* ASSERT: it's really the last sitd for this urb + list_for_each_entry (sitd, &stream->td_list, sitd_list) + BUG_ON (sitd->urb == urb); + */ + + /* give urb back to the driver */ + dev = usb_get_dev (urb->dev); + ehci_urb_done (ehci, urb, regs); + urb = 0; + + /* defer stopping schedule; completion can submit */ + ehci->periodic_sched--; + if (!ehci->periodic_sched) + (void) disable_periodic (ehci); + hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--; + + if (list_empty (&stream->td_list)) { + hcd_to_bus (&ehci->hcd)->bandwidth_allocated + -= stream->bandwidth; + ehci_vdbg (ehci, + "deschedule devp %s ep%d%s-iso\n", + dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); + } + iso_stream_put (ehci, stream); + usb_put_dev (dev); + + return 1; +} + + +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +{ + int status = -EINVAL; + unsigned long flags; + struct ehci_iso_stream *stream; + + // FIXME remove when csplits behave + if (usb_pipein(urb->pipe)) { + ehci_dbg (ehci, "no iso-IN split transactions yet\n"); + return -ENOMEM; + } + + /* Get iso_stream head */ + stream = iso_stream_find (ehci, urb); + if (stream == 0) { + ehci_dbg (ehci, "can't get iso stream\n"); + return -ENOMEM; + } + if (urb->interval != stream->interval) { + ehci_dbg (ehci, "can't change iso interval %d --> %d\n", + stream->interval, urb->interval); + goto done; + } + +#ifdef EHCI_URB_TRACE + ehci_dbg (ehci, + "submit %p dev%s ep%d%s-iso len %d\n", + urb, urb->dev->devpath, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + urb->transfer_buffer_length); +#endif + + /* allocate SITDs */ + status = sitd_urb_transaction (stream, ehci, urb, mem_flags); + if (status < 0) { + ehci_dbg (ehci, "can't init sitds\n"); + goto done; + } + + /* schedule ... need to lock */ + spin_lock_irqsave (&ehci->lock, flags); + status = iso_stream_schedule (ehci, urb, stream); + if (status == 0) + sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + spin_unlock_irqrestore (&ehci->lock, flags); + +done: + if (status < 0) + iso_stream_put (ehci, stream); + return status; +} + +#else + +static inline int +sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +{ + ehci_dbg (ehci, "split iso support is disabled\n"); + return -ENOSYS; +} + +static inline unsigned +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + struct pt_regs *regs +) { + ehci_err (ehci, "sitd_complete %p?\n", sitd); + return 0; +} + +#endif /* USB_EHCI_SPLIT_ISO */ /*-------------------------------------------------------------------------*/ @@ -1513,7 +1884,6 @@ modified = itd_complete (ehci, q.itd, regs); q = *q_p; break; -#ifdef have_split_iso case Q_TYPE_SITD: if (q.sitd->hw_results & SITD_ACTIVE) { q_p = &q.sitd->sitd_next; @@ -1529,7 +1899,6 @@ modified = sitd_complete (ehci, q.sitd, regs); q = *q_p; break; -#endif /* have_split_iso */ default: dbg ("corrupt type %d frame %d shadow %p", type, frame, q.ptr); diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/host/ehci.h Sat Apr 3 19:38:55 2004 @@ -492,16 +492,16 @@ /* * EHCI Specification 0.95 Section 3.4 * siTD, aka split-transaction isochronous Transfer Descriptor - * ... describe low/full speed iso xfers through TT in hubs + * ... describe full speed iso xfers through TT in hubs * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) */ struct ehci_sitd { /* first part defined by EHCI spec */ u32 hw_next; /* uses bit field macros above - see EHCI 0.95 Table 3-8 */ - u32 hw_fullspeed_ep; /* see EHCI table 3-9 */ - u32 hw_uframe; /* see EHCI table 3-10 */ - u32 hw_results; /* see EHCI table 3-11 */ + u32 hw_fullspeed_ep; /* EHCI table 3-9 */ + u32 hw_uframe; /* EHCI table 3-10 */ + u32 hw_results; /* EHCI table 3-11 */ #define SITD_IOC (1 << 31) /* interrupt on completion */ #define SITD_PAGE (1 << 30) /* buffer 0/1 */ #define SITD_LENGTH(x) (0x3ff & ((x)>>16)) @@ -515,8 +515,8 @@ #define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE) - u32 hw_buf [2]; /* see EHCI table 3-12 */ - u32 hw_backpointer; /* see EHCI table 3-13 */ + u32 hw_buf [2]; /* EHCI table 3-12 */ + u32 hw_backpointer; /* EHCI table 3-13 */ u32 hw_buf_hi [2]; /* Appendix B */ /* the rest is HCD-private */ @@ -551,8 +551,6 @@ } __attribute__ ((aligned (32))); /*-------------------------------------------------------------------------*/ - -#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) #ifndef DEBUG #define STUB_DEBUG_FILES diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/host/uhci-hcd.c Sat Apr 3 19:38:55 2004 @@ -781,7 +781,8 @@ /* * Map status to standard result codes * - * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)] + * is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)] + * Note: status does not include the TD_CTRL_NAK bit. * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) @@ -792,22 +793,18 @@ return -EPROTO; if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ if (dir_out) - return -ETIMEDOUT; + return -EPROTO; else return -EILSEQ; } - if (status & TD_CTRL_NAK) /* NAK */ - return -ETIMEDOUT; if (status & TD_CTRL_BABBLE) /* Babble */ return -EOVERFLOW; 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; + WARN_ON(status & TD_CTRL_ACTIVE); /* Active */ + return 0; } /* @@ -832,7 +829,7 @@ status |= TD_CTRL_LS; /* - * Build the TD for the control request + * Build the TD for the control request setup packet */ td = uhci_alloc_td(uhci, urb->dev); if (!td) @@ -990,13 +987,13 @@ if (urbp->short_control_packet) { tmp = head->prev; - goto status_phase; + goto status_stage; } tmp = head->next; td = list_entry(tmp, struct uhci_td, list); - /* The first TD is the SETUP phase, check the status, but skip */ + /* The first TD is the SETUP stage, check the status, but skip */ /* the count */ status = uhci_status_bits(td_status(td)); if (status & TD_CTRL_ACTIVE) @@ -1037,10 +1034,10 @@ } } -status_phase: +status_stage: td = list_entry(tmp, struct uhci_td, list); - /* Control status phase */ + /* Control status stage */ status = td_status(td); #ifdef I_HAVE_BUGGY_APC_BACKUPS @@ -1053,10 +1050,11 @@ return 0; #endif + status = uhci_status_bits(status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - if (uhci_status_bits(status)) + if (status) goto td_error; return 0; @@ -1273,12 +1271,6 @@ } /* - * Bulk and interrupt use common result - */ -#define uhci_result_bulk uhci_result_common -#define uhci_result_interrupt uhci_result_common - -/* * Isochronous transfers */ static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) @@ -1403,7 +1395,8 @@ urb->iso_frame_desc[i].actual_length = actlength; urb->actual_length += actlength; - status = uhci_map_status(uhci_status_bits(td_status(td)), usb_pipeout(urb->pipe)); + status = uhci_map_status(uhci_status_bits(td_status(td)), + usb_pipeout(urb->pipe)); urb->iso_frame_desc[i].status = status; if (status) { urb->error_count++; @@ -1508,12 +1501,9 @@ struct urb_priv *urbp = urb->hcpriv; list_del_init(&urbp->urb_list); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - uhci_destroy_urb_priv (uhci, urb); - - return ret; - } - ret = 0; + uhci_destroy_urb_priv(uhci, urb); + } else + ret = 0; out: spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -1541,11 +1531,9 @@ case PIPE_CONTROL: ret = uhci_result_control(uhci, urb); break; - case PIPE_INTERRUPT: - ret = uhci_result_interrupt(uhci, urb); - break; case PIPE_BULK: - ret = uhci_result_bulk(uhci, urb); + case PIPE_INTERRUPT: + ret = uhci_result_common(uhci, urb); break; case PIPE_ISOCHRONOUS: ret = uhci_result_isochronous(uhci, urb); @@ -1649,10 +1637,12 @@ { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp = urb->hcpriv; + struct urb_priv *urbp; spin_lock_irqsave(&uhci->urb_list_lock, flags); - + urbp = urb->hcpriv; + if (!urbp) /* URB was never linked! */ + goto done; list_del_init(&urbp->urb_list); uhci_unlink_generic(uhci, urb); @@ -1665,6 +1655,7 @@ list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); spin_unlock(&uhci->urb_remove_list_lock); +done: spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; } @@ -1861,17 +1852,12 @@ static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - spin_lock(&uhci->urb_remove_list_lock); - head = &uhci->urb_remove_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + spin_lock(&uhci->complete_list_lock); - tmp = tmp->next; - uhci_moveto_complete(uhci, urbp); - } + /* Splice the urb_remove_list onto the end of the complete_list */ + list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); + spin_unlock(&uhci->complete_list_lock); spin_unlock(&uhci->urb_remove_list_lock); } @@ -2458,9 +2444,11 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); /* Don't try to suspend broken motherboards, reset instead */ - if (suspend_allowed(uhci)) + if (suspend_allowed(uhci)) { suspend_hc(uhci); - else + uhci->saved_framenumber = + inw(uhci->io_addr + USBFRNUM) & 0x3ff; + } else reset_hc(uhci); return 0; } @@ -2471,9 +2459,20 @@ pci_set_master(to_pci_dev(uhci_dev(uhci))); - if (uhci->state == UHCI_SUSPENDED) + if (uhci->state == UHCI_SUSPENDED) { + + /* + * Some systems don't maintain the UHCI register values + * during a PM suspend/resume cycle, so reinitialize + * the Frame Number, the Framelist Base Address, and the + * Interrupt Enable registers. + */ + outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM); + outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | + USBINTR_SP, uhci->io_addr + USBINTR); uhci->resume_detect = 1; - else { + } else { reset_hc(uhci); start_hc(uhci); } diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/host/uhci-hcd.h Sat Apr 3 19:38:54 2004 @@ -141,7 +141,7 @@ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) #define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT) -#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xFE0000) +#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000) #define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ /* @@ -350,6 +350,7 @@ enum uhci_state state; /* FIXME: needs a spinlock */ unsigned long state_end; /* Time of next transition */ int resume_detect; /* Need a Global Resume */ + unsigned int saved_framenumber; /* Save during PM suspend */ /* Main list of URB's currently controlled by this HC */ spinlock_t urb_list_lock; diff -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c --- a/drivers/usb/image/hpusbscsi.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/image/hpusbscsi.c Sat Apr 3 19:38:56 2004 @@ -42,7 +42,7 @@ const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *altsetting = intf->altsetting; + struct usb_host_interface *altsetting = intf->cur_altsetting; struct hpusbscsi *new; int error = -ENOMEM; int i; diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c --- a/drivers/usb/image/mdc800.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/image/mdc800.c Sat Apr 3 19:38:43 2004 @@ -431,7 +431,7 @@ err ("probe fails -> wrong Number of Configuration"); return -ENODEV; } - intf_desc = &intf->altsetting[0]; + intf_desc = intf->cur_altsetting; if ( ( intf_desc->desc.bInterfaceClass != 0xff ) @@ -469,13 +469,6 @@ } - usb_driver_claim_interface (&mdc800_usb_driver, intf, mdc800); - if (usb_set_interface (dev, intf_desc->desc.bInterfaceNumber, 0) < 0) - { - err ("MDC800 Configuration fails."); - return -ENODEV; - } - info ("Found Mustek MDC800 on USB."); down (&mdc800->io_lock); @@ -550,8 +543,6 @@ usb_unlink_urb (mdc800->irq_urb); usb_unlink_urb (mdc800->write_urb); usb_unlink_urb (mdc800->download_urb); - - usb_driver_release_interface (&mdc800_usb_driver, intf); mdc800->dev=0; usb_set_intfdata(intf, NULL); diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c Sat Apr 3 19:38:57 2004 +++ b/drivers/usb/image/microtek.c Sat Apr 3 19:38:57 2004 @@ -693,7 +693,6 @@ const struct usb_device_id *id) { int i; - int result; int ep_out = -1; int ep_in_set[3]; /* this will break if we have more than three endpoints which is why we check */ @@ -703,7 +702,7 @@ struct vendor_product const* p; struct usb_device *dev = interface_to_usbdev (intf); - /* the altsettting 0 on the interface we're probing */ + /* the current altsetting on the interface we're probing */ struct usb_host_interface *altsetting; MTS_DEBUG_GOT_HERE(); @@ -724,8 +723,8 @@ MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", p->name ); - /* the altsettting 0 on the interface we're probing */ - altsetting = &(intf->altsetting[0]); + /* the current altsetting on the interface we're probing */ + altsetting = intf->cur_altsetting; /* Check if the config is sane */ @@ -765,20 +764,6 @@ if ( ep_out == -1 ) { MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); return -ENODEV; - } - - result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0); - - MTS_DEBUG("usb_set_interface returned %d.\n",result); - switch( result ) - { - case 0: /* no error */ - break; - - default: - MTS_DEBUG( "unknown error %d from usb_set_interface\n", - (int)result ); - return -ENODEV; } diff -Nru a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig --- a/drivers/usb/input/Kconfig Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/input/Kconfig Sat Apr 3 19:38:54 2004 @@ -179,6 +179,18 @@ To compile this driver as a module, choose M here: the module will be called powermate. +config USB_MTOUCH + tristate "MicroTouch USB Touchscreen Driver" + depends on USB && INPUT + ---help--- + Say Y here if you want to use a MicroTouch (Now 3M) USB + Touchscreen controller. + + See for additional information. + + To compile this driver as a module, choose M here: the + module will be called mtouchusb. + config USB_XPAD tristate "X-Box gamepad support" depends on USB && INPUT @@ -192,3 +204,17 @@ To compile this driver as a module, choose M here: the module will be called xpad. + +config USB_ATI_REMOTE + tristate "ATI USB RF remote control" + depends on USB && INPUT + ---help--- + Say Y here if you want to use one of ATI's USB remote controls. + These are RF remotes with USB receivers. They come with many of ATI's + All-In-Wonder video cards. This driver provides mouse pointer, left + and right mouse buttons, and maps all the other remote buttons to + keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote. + diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile --- a/drivers/usb/input/Makefile Sat Apr 3 19:38:44 2004 +++ b/drivers/usb/input/Makefile Sat Apr 3 19:38:44 2004 @@ -27,10 +27,12 @@ endif obj-$(CONFIG_USB_AIPTEK) += aiptek.o +obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += hid.o obj-$(CONFIG_USB_KBD) += usbkbd.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o -obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_MOUSE) += usbmouse.o +obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_POWERMATE) += powermate.o +obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_XPAD) += xpad.o diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/input/aiptek.c Sat Apr 3 19:38:54 2004 @@ -43,7 +43,8 @@ #include #include #include - +#include +#include /* * Version Information */ @@ -160,9 +161,9 @@ proximity = data[5] & 0x01; input_report_key(dev, BTN_TOOL_PEN, proximity); - x = ((__u32) data[1]) | ((__u32) data[2] << 8); - y = ((__u32) data[3]) | ((__u32) data[4] << 8); - pressure = ((__u32) data[6]) | ((__u32) data[7] << 8); + x = le16_to_cpu(get_unaligned((u16 *) &data[1])); + y = le16_to_cpu(get_unaligned((u16 *) &data[3])); + pressure = le16_to_cpu(*(u16 *) &data[6]); pressure -= aiptek->features->pressure_min; if (pressure < 0) { @@ -209,8 +210,10 @@ return 0; aiptek->irq->dev = aiptek->usbdev; - if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) + if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) { + aiptek->open--; return -EIO; + } return 0; } @@ -234,19 +237,27 @@ (type << 8) + id, inter->desc.bInterfaceNumber, buf, size, HZ); } -static void +static int aiptek_command(struct usb_device *dev, struct usb_host_interface *inter, unsigned char command, unsigned char data) { - __u8 buf[3]; + u8 *buf; + int err; + + buf = kmalloc(3, GFP_KERNEL); + if (!buf) + return -ENOMEM; buf[0] = 4; buf[1] = command; buf[2] = data; - if (usb_set_report(dev, inter, 3, 2, buf, 3) != 3) { + if ((err = usb_set_report(dev, inter, 3, 2, buf, 3)) != 3) { dbg("aiptek_command: 0x%x 0x%x\n", command, data); } + + kfree(buf); + return err < 0 ? err : 0; } static int @@ -257,30 +268,32 @@ struct usb_host_interface *interface = intf->altsetting + 0; struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; + int err = -ENOMEM; if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL))) - return -ENOMEM; + goto error_out_noalloc; memset(aiptek, 0, sizeof (struct aiptek)); - aiptek->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &aiptek->data_dma); + aiptek->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &aiptek->data_dma); if (!aiptek->data) { - kfree(aiptek); - return -ENOMEM; + goto error_out_nobuf; } aiptek->irq = usb_alloc_urb(0, GFP_KERNEL); if (!aiptek->irq) { - usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); - kfree(aiptek); - return -ENOMEM; + goto error_out_nourb; } /* Resolution500LPI */ - aiptek_command(dev, interface, 0x18, 0x04); + err = aiptek_command(dev, interface, 0x18, 0x04); + if (err) + goto error_out; /* SwitchToTablet */ - aiptek_command(dev, interface, 0x10, 0x01); + err = aiptek_command(dev, interface, 0x10, 0x01); + if (err) + goto error_out; aiptek->features = aiptek_features + id->driver_info; @@ -340,6 +353,16 @@ usb_set_intfdata(intf, aiptek); return 0; + +error_out: + usb_free_urb(aiptek->irq); +error_out_nourb: + usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); +error_out_nobuf: + kfree(aiptek); +error_out_noalloc: + return err; + } static void diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/input/ati_remote.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,851 @@ +/* + * USB ATI Remote support + * + * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman + * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev + * + * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including + * porting to the 2.6 kernel interfaces, along with other modification + * to better match the style of the existing usb/input drivers. However, the + * protocol and hardware handling is essentially unchanged from 2.1.1. + * + * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by + * Vojtech Pavlik. + * + * Changes: + * + * Feb 2004: Torrey Hoffman + * Version 2.2.0 + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Hardware & software notes + * + * These remote controls are distributed by ATI as part of their + * "All-In-Wonder" video card packages. The receiver self-identifies as a + * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". + * + * It is possible to use multiple receivers and remotes on multiple computers + * simultaneously by configuring them to use specific channels. + * + * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. + * Actually, it may even support more, at least in some revisions of the + * hardware. + * + * Each remote can be configured to transmit on one channel as follows: + * - Press and hold the "hand icon" button. + * - When the red LED starts to blink, let go of the "hand icon" button. + * - When it stops blinking, input the channel code as two digits, from 01 + * to 16, and press the hand icon again. + * + * The timing can be a little tricky. Try loading the module with debug=1 + * to have the kernel print out messages about the remote control number + * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. + * + * The driver has a "channel_mask" parameter. This bitmask specifies which + * channels will be ignored by the module. To mask out channels, just add + * all the 2^channel_number values together. + * + * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote + * ignore signals coming from remote controls transmitting on channel 4, but + * accept all other channels. + * + * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be + * ignored. + * + * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this + * parameter are unused. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Module and Version Information, Module Parameters + */ + +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define ATI_REMOTE_PRODUCT_ID 0x004 + +#define DRIVER_VERSION "2.2.0" +#define DRIVER_AUTHOR "Torrey Hoffman " +#define DRIVER_DESC "ATI/X10 RF USB Remote Control" + +#define NAME_BUFSIZE 80 /* size of product name, path buffers */ +#define DATA_BUFSIZE 63 /* size of URB data buffers */ +#define ATI_INPUTNUM 1 /* Which input device to register as */ + +unsigned long channel_mask = 0; +module_param(channel_mask, ulong, 444); +MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); + +static int debug = 0; +module_param(debug, int, 444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) +#undef err +#define err(format, arg...) printk(KERN_ERR format , ## arg) + +static struct usb_device_id ati_remote_table[] = { + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ati_remote_table); + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 + +/* Device initialization strings */ +static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; +static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; + +/* Acceleration curve for directional control pad */ +static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; + +/* Duplicate event filtering time. + * Sequential, identical KIND_FILTERED inputs with less than + * FILTER_TIME jiffies between them are dropped. + * (HZ >> 4) == 1/16th of a second and works well for me. + */ +#define FILTER_TIME (HZ >> 4) + +struct ati_remote { + struct input_dev idev; + struct usb_device *udev; + struct usb_interface *interface; + + struct urb *irq_urb; + struct urb *out_urb; + struct usb_endpoint_descriptor *endpoint_in; + struct usb_endpoint_descriptor *endpoint_out; + unsigned char *inbuf; + unsigned char *outbuf; + dma_addr_t inbuf_dma; + dma_addr_t outbuf_dma; + + int open; /* open counter */ + int present; /* device plugged in? */ + + unsigned char old_data[2]; /* Detect duplicate events */ + unsigned long old_jiffies; + unsigned long acc_jiffies; /* handle acceleration */ + + char name[NAME_BUFSIZE]; + char phys[NAME_BUFSIZE]; + + wait_queue_head_t wait; + int send_flags; +}; + +/* "Kinds" of messages sent from the hardware to the driver. */ +#define KIND_END 0 +#define KIND_LITERAL 1 /* Simply pass to input system */ +#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ +#define KIND_LU 3 /* Directional keypad diagonals - left up, */ +#define KIND_RU 4 /* right up, */ +#define KIND_LD 5 /* left down, */ +#define KIND_RD 6 /* right down */ +#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ + +/* Translation table from hardware messages to input events. */ +static struct +{ + short kind; + unsigned char data1, data2; + int type; + unsigned int code; + int value; +} ati_remote_tbl[] = +{ + /* Directional control pad axes */ + {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + /* Directional control pad diagonals */ + {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + + /* "Mouse button" buttons */ + {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + + /* Artificial "doubleclick" events are generated by the hardware. + * They are mapped to the "side" and "extra" mouse buttons here. */ + {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + + /* keyboard. */ + {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, + {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, + {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, + {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, + {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, + {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, + {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, + {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, + {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, + {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, + {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, + {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, + {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, + {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, + {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, + {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, + + /* "special" keys */ + {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ + {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ + {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ + {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1}, /* TV */ + {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1}, /* DVD */ + {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ + {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ + {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ + {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ + {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ + {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ + {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ + {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ + {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ + {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1}, /* "OK" */ + {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ + {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ + {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ + {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ + {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ + {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ + {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1}, /* ( >) */ + {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ + {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ + {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ + {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ + + {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} +}; + +/* Local function prototypes */ +static void ati_remote_dump (unsigned char *data, unsigned int actual_length); +static void ati_remote_delete (struct ati_remote *dev); +static int ati_remote_open (struct input_dev *inputdev); +static void ati_remote_close (struct input_dev *inputdev); +static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); +static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs); +static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs); +static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs); +static int ati_remote_initialize (struct ati_remote *ati_remote); +static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); +static void ati_remote_disconnect (struct usb_interface *interface); + +/* usb specific object to register with the usb subsystem */ +static struct usb_driver ati_remote_driver = { + .owner = THIS_MODULE, + .name = "ati_remote", + .probe = ati_remote_probe, + .disconnect = ati_remote_disconnect, + .id_table = ati_remote_table, +}; + +/* + * ati_remote_dump_input + */ +static void ati_remote_dump(unsigned char *data, unsigned int len) +{ + if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) + warn("Weird byte 0x%02x\n", data[0]); + else if (len == 4) + warn("Weird key %02x %02x %02x %02x\n", + data[0], data[1], data[2], data[3]); + else + warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + len, data[0], data[1], data[2], data[3], data[4], data[5]); +} + +/* + * ati_remote_open + */ +static int ati_remote_open(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = inputdev->private; + + if (ati_remote->open++) + return 0; + + /* On first open, submit the read urb which was set up previously. */ + ati_remote->irq_urb->dev = ati_remote->udev; + if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { + dev_err(&ati_remote->interface->dev, + "%s: usb_submit_urb failed!\n", __FUNCTION__); + ati_remote->open--; + return -EIO; + } + + return 0; +} + +/* + * ati_remote_close + */ +static void ati_remote_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = inputdev->private; + + if (ati_remote == NULL) { + err("ati_remote: %s: object is NULL!\n", __FUNCTION__); + return; + } + + if (ati_remote->open <= 0) + dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__); + else + --ati_remote->open; + + /* If still present, disconnect will call delete. */ + if (!ati_remote->present && !ati_remote->open) + ati_remote_delete(ati_remote); +} + +/* + * ati_remote_irq_out + */ +static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + + if (urb->status) { + dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", + __FUNCTION__, urb->status); + return; + } + + ati_remote->send_flags |= SEND_FLAG_COMPLETE; + wmb(); + if (waitqueue_active(&ati_remote->wait)) + wake_up(&ati_remote->wait); +} + +/* + * ati_remote_sendpacket + * + * Used to send device initialization strings + */ +static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) +{ + DECLARE_WAITQUEUE(wait, current); + int timeout = HZ; /* 1 second */ + int retval = 0; + + /* Set up out_urb */ + memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); + ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); + + ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; + ati_remote->out_urb->dev = ati_remote->udev; + ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ati_remote->wait, &wait); + + retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL); + if (retval) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&ati_remote->wait, &wait); + dev_dbg(&ati_remote->interface->dev, + "sendpacket: usb_submit_urb failed: %d\n", retval); + return retval; + } + + while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) + && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) { + timeout = schedule_timeout(timeout); + rmb(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&ati_remote->wait, &wait); + usb_unlink_urb(ati_remote->out_urb); + + return retval; +} + +/* + * ati_remote_event_lookup + */ +static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) +{ + int i; + + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + /* + * Decide if the table entry matches the remote input. + */ + if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && + ((((ati_remote_tbl[i].data1 >> 4) - + (d1 >> 4) + rem) & 0x0f) == 0x0f) && + (ati_remote_tbl[i].data2 == d2)) + return i; + + } + return -1; +} + +/* + * ati_remote_report_input + */ +static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + unsigned char *data= ati_remote->inbuf; + struct input_dev *dev = &ati_remote->idev; + int index, acc; + int remote_num; + + /* Deal with strange looking inputs */ + if ( (urb->actual_length != 4) || (data[0] != 0x14) || + ((data[3] & 0x0f) != 0x00) ) { + ati_remote_dump(data, urb->actual_length); + return; + } + + /* Mask unwanted remote channels. */ + /* note: remote_num is 0-based, channel 1 on remote == 0 here */ + remote_num = (data[3] >> 4) & 0x0f; + if (channel_mask & (1 << (remote_num + 1))) { + dbginfo(&ati_remote->interface->dev, + "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", + remote_num, data[1], data[2], channel_mask); + return; + } + + /* Look up event code index in translation table */ + index = ati_remote_event_lookup(remote_num, data[1], data[2]); + if (index < 0) { + dev_warn(&ati_remote->interface->dev, + "Unknown input from channel 0x%02x: data %02x,%02x\n", + remote_num, data[1], data[2]); + return; + } + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + + if (ati_remote_tbl[index].kind == KIND_LITERAL) { + input_regs(dev, regs); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value); + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + return; + } + + if (ati_remote_tbl[index].kind == KIND_FILTERED) { + /* Filter duplicate events which happen "too close" together. */ + if ((ati_remote->old_data[0] == data[1]) && + (ati_remote->old_data[1] == data[2]) && + ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) { + ati_remote->old_jiffies = jiffies; + return; + } + + input_regs(dev, regs); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 1); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 0); + input_sync(dev); + + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + ati_remote->old_jiffies = jiffies; + return; + } + + /* + * Other event kinds are from the directional control pad, and have an + * acceleration factor applied to them. Without this acceleration, the + * control pad is mostly unusable. + * + * If elapsed time since last event is > 1/4 second, user "stopped", + * so reset acceleration. Otherwise, user is probably holding the control + * pad down, so we increase acceleration, ramping up over two seconds to + * a maximum speed. The acceleration curve is #defined above. + */ + if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) { + acc = 1; + ati_remote->acc_jiffies = jiffies; + } + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = accel[0]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = accel[1]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = accel[2]; + else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = accel[3]; + else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = accel[4]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = accel[5]; + else acc = accel[6]; + + input_regs(dev, regs); + switch (ati_remote_tbl[index].kind) { + case KIND_ACCEL: + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value * acc); + break; + case KIND_LU: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_RU: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_LD: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, acc); + break; + case KIND_RD: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, acc); + break; + default: + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); + } + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; +} + +/* + * ati_remote_irq_in + */ +static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + int retval; + + switch (urb->status) { + case 0: /* success */ + ati_remote_input_report(urb, regs); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", + __FUNCTION__); + return; + default: /* error */ + dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + __FUNCTION__, urb->status); + } + + retval = usb_submit_urb(urb, SLAB_ATOMIC); + if (retval) + dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", + __FUNCTION__, retval); +} + +/* + * ati_remote_delete + */ +static void ati_remote_delete(struct ati_remote *ati_remote) +{ + if (!ati_remote) return; + + if (ati_remote->irq_urb) + usb_unlink_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_unlink_urb(ati_remote->out_urb); + + if (ati_remote->irq_urb) + usb_free_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_free_urb(ati_remote->out_urb); + + if (ati_remote->inbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); + + if (ati_remote->outbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->outbuf_dma); + + kfree(ati_remote); +} + +static void ati_remote_input_init(struct ati_remote *ati_remote) +{ + struct input_dev *idev = &(ati_remote->idev); + int i; + + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | + BIT(BTN_SIDE) | BIT(BTN_EXTRA) ); + idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) + if (ati_remote_tbl[i].type == EV_KEY) + set_bit(ati_remote_tbl[i].code, idev->keybit); + + idev->private = ati_remote; + idev->open = ati_remote_open; + idev->close = ati_remote_close; + + idev->name = ati_remote->name; + idev->phys = ati_remote->phys; + + idev->id.bustype = BUS_USB; + idev->id.vendor = ati_remote->udev->descriptor.idVendor; + idev->id.product = ati_remote->udev->descriptor.idProduct; + idev->id.version = ati_remote->udev->descriptor.bcdDevice; +} + +static int ati_remote_initialize(struct ati_remote *ati_remote) +{ + struct usb_device *udev = ati_remote->udev; + int pipe, maxp; + + init_waitqueue_head(&ati_remote->wait); + + /* Set up irq_urb */ + pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, + maxp, ati_remote_irq_in, ati_remote, + ati_remote->endpoint_in->bInterval); + ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; + ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* Set up out_urb */ + pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, + maxp, ati_remote_irq_out, ati_remote, + ati_remote->endpoint_out->bInterval); + ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; + ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* send initialization strings */ + if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || + (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { + dev_err(&ati_remote->interface->dev, + "Initializing ati_remote hardware failed.\n"); + return 1; + } + + return 0; +} + +/* + * ati_remote_probe + */ +static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct ati_remote *ati_remote = NULL; + struct usb_host_interface *iface_host; + int retval = -ENOMEM; + char path[64]; + char *buf = NULL; + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != ATI_REMOTE_VENDOR_ID) || + (udev->descriptor.idProduct != ATI_REMOTE_PRODUCT_ID)) { + return -ENODEV; + } + + /* Allocate and clear an ati_remote struct */ + if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL))) + return -ENOMEM; + memset(ati_remote, 0x00, sizeof (struct ati_remote)); + + iface_host = interface->cur_altsetting; + if (iface_host->desc.bNumEndpoints != 2) { + err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); + retval = -ENODEV; + goto error; + } + + ati_remote->endpoint_in = &(iface_host->endpoint[0].desc); + ati_remote->endpoint_out = &(iface_host->endpoint[1].desc); + ati_remote->udev = udev; + ati_remote->interface = interface; + + if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) { + err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__); + retval = -ENODEV; + goto error; + } + if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) { + err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__); + retval = -ENODEV; + goto error; + } + if (ati_remote->endpoint_in->wMaxPacketSize == 0) { + err("%s: endpoint_in message size==0? \n", __FUNCTION__); + retval = -ENODEV; + goto error; + } + if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL))) + goto error; + + /* Allocate URB buffers, URBs */ + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + goto error; + + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + goto error; + + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + goto error; + + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + goto error; + + usb_make_path(udev, path, NAME_BUFSIZE); + sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM); + if (udev->descriptor.iManufacturer && + (usb_string(udev, udev->descriptor.iManufacturer, buf, + NAME_BUFSIZE) > 0)) + strcat(ati_remote->name, buf); + + if (udev->descriptor.iProduct && + (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0)) + sprintf(ati_remote->name, "%s %s", ati_remote->name, buf); + + if (!strlen(ati_remote->name)) + sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", + ati_remote->udev->descriptor.idVendor, + ati_remote->udev->descriptor.idProduct); + + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ + retval = ati_remote_initialize(ati_remote); + if (retval) + goto error; + + /* Set up and register input device */ + ati_remote_input_init(ati_remote); + input_register_device(&ati_remote->idev); + + dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", + ati_remote->name, path); + + usb_set_intfdata(interface, ati_remote); + ati_remote->present = 1; + kfree(buf); + return 0; + +error: + if (buf) + kfree(buf); + + ati_remote_delete(ati_remote); + return retval; +} + +/* + * ati_remote_disconnect + */ +static void ati_remote_disconnect(struct usb_interface *interface) +{ + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + if (!ati_remote) { + warn("%s - null device?\n", __FUNCTION__); + return; + } + + input_unregister_device(&ati_remote->idev); + + /* Mark device as unplugged */ + ati_remote->present = 0; + + /* If device is still open, ati_remote_close will call delete. */ + if (!ati_remote->open) + ati_remote_delete(ati_remote); +} + +/* + * ati_remote_init + */ +static int __init ati_remote_init(void) +{ + int result; + + result = usb_register(&ati_remote_driver); + if (result) + err("usb_register error #%d\n", result); + else + info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION); + + return result; +} + +/* + * ati_remote_exit + */ +static void __exit ati_remote_exit(void) +{ + usb_deregister(&ati_remote_driver); +} + +/* + * module specification + */ + +module_init(ati_remote_init); +module_exit(ati_remote_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Sat Apr 3 19:38:44 2004 +++ b/drivers/usb/input/hid-core.c Sat Apr 3 19:38:44 2004 @@ -224,6 +224,9 @@ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + if (usages < parser->global.report_count) + usages = parser->global.report_count; + if (usages == 0) return 0; /* ignore padding fields */ @@ -235,9 +238,13 @@ field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); for (i = 0; i < usages; i++) { - field->usage[i].hid = parser->local.usage[i]; + int j = i; + /* Duplicate the last usage we parsed if we have excess values */ + if (i >= parser->local.usage_index) + j = parser->local.usage_index - 1; + field->usage[i].hid = parser->local.usage[j]; field->usage[i].collection_index = - parser->local.collection_index[i]; + parser->local.collection_index[j]; } field->maxusage = usages; @@ -1069,24 +1076,41 @@ { struct hid_report *report; unsigned char dir; + int len; report = hid->ctrl[hid->ctrltail].report; dir = hid->ctrl[hid->ctrltail].dir; - if (dir == USB_DIR_OUT) + len = ((report->size - 1) >> 3) + 1 + (report->id > 0); + if (dir == USB_DIR_OUT) { hid_output_report(report, hid->ctrlbuf); - - hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); + hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0); + hid->urbctrl->transfer_buffer_length = len; + } else { + int maxpacket, padlen; + + hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0); + maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0); + if (maxpacket > 0) { + padlen = (len + maxpacket - 1) / maxpacket; + padlen *= maxpacket; + if (padlen > HID_BUFFER_SIZE) + padlen = HID_BUFFER_SIZE; + } else + padlen = 0; + hid->urbctrl->transfer_buffer_length = padlen; + } hid->urbctrl->dev = hid->dev; hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); hid->cr->wIndex = cpu_to_le16(hid->ifnum); - hid->cr->wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); + hid->cr->wLength = cpu_to_le16(len); - dbg("submitting ctrl urb"); + dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", + hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", + hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength); if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); @@ -1262,9 +1286,25 @@ struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; - int len; int err, ret; + /* + * The Set_Idle request is supposed to affect only the + * "Interrupt In" pipe. Unfortunately, buggy devices such as + * the BTC keyboard (ID 046e:5303) the request also affects + * Get_Report requests on the control pipe. In the worst + * case, if the device was put on idle for an indefinite + * amount of time (as we do below) and there are no input + * events to report, the Get_Report requests will just hang + * until we get a USB timeout. To avoid this, we temporarily + * establish a minimal idle time of 1ms. This shouldn't hurt + * bugfree devices and will cause a worst-case extra delay of + * 1ms for buggy ones. + */ + usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8), + hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + report_enum = hid->report_enum + HID_INPUT_REPORT; list = report_enum->report_list.next; while (list != &report_enum->report_list) { @@ -1297,11 +1337,8 @@ list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; - len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; - if (len > hid->urbin->transfer_buffer_length) - hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), - 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); list = list->next; } @@ -1313,11 +1350,12 @@ #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 #define USB_DEVICE_ID_WACOM_PL 0x0030 #define USB_DEVICE_ID_WACOM_INTUOS2 0x0040 +#define USB_DEVICE_ID_WACOM_VOLITO 0x0060 +#define USB_DEVICE_ID_WACOM_PTU 0x0003 #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 - #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_DEVICE_ID_AIPTEK_6000 0x0020 @@ -1356,22 +1394,52 @@ #define USB_VENDOR_ID_A4TECH 0x09DA #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 +#define USB_VENDOR_ID_CYPRESS 0x04b4 +#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 + #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 #define USB_VENDOR_ID_ALPS 0x0433 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 +#define USB_VENDOR_ID_SAITEK 0x06a3 +#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 + +#define USB_VENDOR_ID_NEC 0x073e +#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 + +#define USB_VENDOR_ID_CHIC 0x05fe +#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; unsigned quirks; } hid_blacklist[] = { + + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, @@ -1383,37 +1451,34 @@ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK }, - { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_BACK }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA }, + { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, + { 0, 0 } }; @@ -1445,7 +1510,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) { - struct usb_host_interface *interface = intf->altsetting + intf->act_altsetting; + struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_device *hid; @@ -1518,12 +1583,17 @@ continue; if (endpoint->bEndpointAddress & USB_DIR_IN) { + int len; + if (hid->urbin) continue; if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, + len = usb_maxpacket(dev, pipe, 0); + if (len > HID_BUFFER_SIZE) + len = HID_BUFFER_SIZE; + usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, hid_irq_in, hid, endpoint->bInterval); hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c --- a/drivers/usb/input/hid-ff.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/input/hid-ff.c Sat Apr 3 19:38:43 2004 @@ -29,7 +29,7 @@ #include -#define DEBUG +#undef DEBUG #include #include "hid.h" diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c --- a/drivers/usb/input/hid-input.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/input/hid-input.c Sat Apr 3 19:38:43 2004 @@ -377,7 +377,8 @@ set_bit(usage->type, input->evbit); if ((usage->type == EV_REL) - && (device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK) + && (device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK + | HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA)) && (usage->code == REL_WHEEL)) { set_bit(REL_HWHEEL, bit); } @@ -431,21 +432,22 @@ input_regs(input, regs); - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK) - && (usage->code == BTN_BACK)) { + if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) && (usage->code == BTN_EXTRA)) + || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) && (usage->code == BTN_BACK))) { if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; return; } + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { input_event(input, usage->type, REL_HWHEEL, value); return; } - if (usage->hat_min != usage->hat_max) { + if (usage->hat_min != usage->hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */ value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; if (value < 0 || value > 8) value = 0; input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); @@ -484,7 +486,7 @@ return; } - if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */ + if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ return; input_event(input, usage->type, usage->code, value); @@ -567,8 +569,10 @@ while (list != &report_enum->report_list) { report = (struct hid_report *) list; - if (!report->maxfield) + if (!report->maxfield) { + list = list->next; continue; + } if (!hidinput) { hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h --- a/drivers/usb/input/hid.h Sat Apr 3 19:38:40 2004 +++ b/drivers/usb/input/hid.h Sat Apr 3 19:38:40 2004 @@ -201,15 +201,16 @@ * HID device quirks. */ -#define HID_QUIRK_INVERT 0x001 -#define HID_QUIRK_NOTOUCH 0x002 -#define HID_QUIRK_IGNORE 0x004 -#define HID_QUIRK_NOGET 0x008 -#define HID_QUIRK_HIDDEV 0x010 -#define HID_QUIRK_BADPAD 0x020 -#define HID_QUIRK_MULTI_INPUT 0x040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK 0x080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x100 +#define HID_QUIRK_INVERT 0x001 +#define HID_QUIRK_NOTOUCH 0x002 +#define HID_QUIRK_IGNORE 0x004 +#define HID_QUIRK_NOGET 0x008 +#define HID_QUIRK_HIDDEV 0x010 +#define HID_QUIRK_BADPAD 0x020 +#define HID_QUIRK_MULTI_INPUT 0x040 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_BACK 0x080 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA 0x100 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200 /* * This is the global environment of the parser. This information is @@ -309,7 +310,7 @@ #define HID_REPORT_TYPES 3 -#define HID_BUFFER_SIZE 32 +#define HID_BUFFER_SIZE 64 /* use 64 for compatibility with all possible packetlen */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_OUTPUT_FIFO_SIZE 64 diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/input/hiddev.c Sat Apr 3 19:38:43 2004 @@ -403,7 +403,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref uref; + struct hiddev_usage_ref_multi uref_multi; + struct hiddev_usage_ref *uref = &uref_multi.uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -575,68 +576,98 @@ return 0; case HIDIOCGUCODE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) return -EFAULT; - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; - uref.usage_code = field->usage[uref.usage_index].hid; + uref->usage_code = field->usage[uref->usage_index].hid; - if (copy_to_user((void *) arg, &uref, sizeof(uref))) + if (copy_to_user((void *) arg, uref, sizeof(*uref))) return -EFAULT; return 0; case HIDIOCGUSAGE: case HIDIOCSUSAGE: + case HIDIOCGUSAGES: + case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (copy_from_user(&uref_multi, (void *) arg, + sizeof(uref_multi))) + return -EFAULT; + } else { + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) + return -EFAULT; + } - if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + if (cmd != HIDIOCGUSAGE && + cmd != HIDIOCGUSAGES && + uref->report_type == HID_REPORT_TYPE_INPUT) + return -EINVAL; - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); + if (uref->report_id == HID_REPORT_ID_UNKNOWN) { + field = hiddev_lookup_usage(hid, uref); if (field == NULL) return -EINVAL; } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; + + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (uref_multi.num_values >= HID_MAX_USAGES || + uref->usage_index >= field->maxusage || + (uref->usage_index + uref_multi.num_values) >= field->maxusage) + return -EINVAL; + } } switch (cmd) { case HIDIOCGUSAGE: - uref.value = field->value[uref.usage_index]; - if (copy_to_user((void *) arg, &uref, sizeof(uref))) + uref->value = field->value[uref->usage_index]; + if (copy_to_user((void *) arg, uref, sizeof(*uref))) return -EFAULT; return 0; case HIDIOCSUSAGE: - field->value[uref.usage_index] = uref.value; + field->value[uref->usage_index] = uref->value; return 0; case HIDIOCGCOLLECTIONINDEX: - return field->usage[uref.usage_index].collection_index; + return field->usage[uref->usage_index].collection_index; + case HIDIOCGUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + uref_multi.values[i] = + field->value[uref->usage_index + i]; + if (copy_to_user((void *) arg, &uref_multi, + sizeof(uref_multi))) + return -EFAULT; + return 0; + case HIDIOCSUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + field->value[uref->usage_index + i] = + uref_multi.values[i]; + return 0; } return 0; diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c Sat Apr 3 19:38:40 2004 +++ b/drivers/usb/input/kbtab.c Sat Apr 3 19:38:40 2004 @@ -4,6 +4,8 @@ #include #include #include +#include +#include /* * Version Information @@ -65,8 +67,8 @@ goto exit; } - kbtab->x = (data[2] << 8) + data[1]; - kbtab->y = (data[4] << 8) + data[3]; + kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1])); + kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3])); kbtab->pressure = (data[5]); @@ -74,12 +76,15 @@ input_report_abs(dev, ABS_X, kbtab->x); input_report_abs(dev, ABS_Y, kbtab->y); - /*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/ /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ input_report_key(dev, BTN_RIGHT, data[0] & 0x02); - - input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); + + if( -1 == kb_pressure_click){ + input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); + } else { + input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); + }; input_sync(dev); @@ -105,8 +110,10 @@ return 0; kbtab->irq->dev = kbtab->usbdev; - if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) + if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) { + kbtab->open--; return -EIO; + } return 0; } @@ -130,7 +137,7 @@ return -ENOMEM; memset(kbtab, 0, sizeof(struct kbtab)); - kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma); + kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma); if (!kbtab->data) { kfree(kbtab); return -ENOMEM; diff -Nru a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/input/mtouchusb.c Sat Apr 3 19:38:57 2004 @@ -0,0 +1,391 @@ +/****************************************************************************** + * mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens + * + * 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. + * + * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl) + * (http://freshmeat.net/projects/3mtouchscreendriver) + * + * History + * + * 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com + * Updated to 2.4.18, then 2.4.19 + * Old version still relied on stealing a minor + * + * 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com + * Complete rewrite using Linux Input in 2.6.3 + * Unfortunately no calibration support at this time + * + *****************************************************************************/ + +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include + +#define MTOUCHUSB_MIN_XC 0xc8 +#define MTOUCHUSB_MAX_XC 0xff78 +#define MTOUCHUSB_XC_FUZZ 0x0 +#define MTOUCHUSB_XC_FLAT 0x0 +#define MTOUCHUSB_MIN_YC 0x0 +#define MTOUCHUSB_MAX_YC 0xff78 +#define MTOUCHUSB_YC_FUZZ 0x0 +#define MTOUCHUSB_YC_FLAT 0x0 +#define MTOUCHUSB_ASYC_REPORT 1 +#define MTOUCHUSB_REPORT_SIZE_DATA 11 +#define MTOUCHUSB_REQ_CTRLLR_ID 10 + +#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3]) +#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5]) +#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0) + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com" +#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver" + +struct mtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + struct urb *irq; + struct usb_device *udev; + struct input_dev input; + int open; + char name[128]; + char phys[64]; +}; + +static __s32 vendor=-1, product=-1; + +static struct usb_device_id mtouchusb_devices [] = { + { USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */ + { } /* Terminating entry */ +}; + +static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) +{ + struct mtouch_usb *mtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_regs(&mtouch->input, regs); + input_report_key(&mtouch->input, BTN_TOUCH, + MTOUCHUSB_GET_TOUCHED(mtouch->data)); + input_report_abs(&mtouch->input, ABS_X, + MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(&mtouch->input, ABS_Y, + MTOUCHUSB_GET_YC(mtouch->data)); + input_sync(&mtouch->input); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int mtouchusb_open (struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + if (mtouch->open++) + return 0; + + mtouch->irq->dev = mtouch->udev; + + if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) + return -EIO; + + return 0; +} + +static void mtouchusb_close (struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + if (!--mtouch->open) + usb_unlink_urb (mtouch->irq); +} + +static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA, + SLAB_ATOMIC, &mtouch->data_dma); + + if (!mtouch->data) + return -1; + + return 0; +} + +static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + if (mtouch->data) + usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA, + mtouch->data, mtouch->data_dma); +} + +static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct mtouch_usb *mtouch; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev (intf); + char path[64]; + char *buf; + int nRet; + int ix; + char valid_device = 0; + + dbg("%s - called", __FUNCTION__); + if (vendor != -1 && product != -1) { + info("%s - User specified USB Touch -- Vend:Prod - %x:%x", + __FUNCTION__, vendor, product); + } + + for (ix = 0; ix < sizeof (mtouchusb_devices) / + sizeof (struct usb_device_id); ix++) { + if ((udev->descriptor.idVendor == + mtouchusb_devices [ix].idVendor) && + (udev->descriptor.idProduct == + mtouchusb_devices [ix].idProduct)) { + valid_device = 1; + break; + } + } + + if (udev->descriptor.idVendor == vendor && + udev->descriptor.idProduct == product) { /* User specified */ + valid_device = 1; + } + + if (!valid_device) { + err("%s - No valid device!", __FUNCTION__); + return -EIO; + } + + if (udev->descriptor.bNumConfigurations != 1) { + err("%s - Only one device configuration is supported.", + __FUNCTION__); + return -EIO; + } + + dbg("%s - setting interface", __FUNCTION__); + interface = intf->cur_altsetting; + + dbg("%s - setting endpoint", __FUNCTION__); + endpoint = &interface->endpoint[0].desc; + + if (interface->desc.bNumEndpoints != 1) { + err("%s - Only one endpoint is supported.", __FUNCTION__); + return -EIO; + } + + if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { + err("%s - Out of memory.", __FUNCTION__); + return -ENOMEM; + } + + memset(mtouch, 0, sizeof(struct mtouch_usb)); + mtouch->udev = udev; + + dbg("%s - allocating buffers", __FUNCTION__); + if (mtouchusb_alloc_buffers(udev, mtouch)) { + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + mtouch->input.private = mtouch; + mtouch->input.open = mtouchusb_open; + mtouch->input.close = mtouchusb_close; + + usb_make_path(udev, path, 64); + sprintf(mtouch->phys, "%s/input0", path); + + mtouch->input.name = mtouch->name; + mtouch->input.phys = mtouch->phys; + mtouch->input.id.bustype = BUS_USB; + mtouch->input.id.vendor = udev->descriptor.idVendor; + mtouch->input.id.product = udev->descriptor.idProduct; + mtouch->input.id.version = udev->descriptor.bcdDevice; + mtouch->input.dev = &intf->dev; + + mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + /* Used to Scale Compensated Data and Flip Y */ + mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; + mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC; + mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; + mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; + mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC; + mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC; + mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; + mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + kfree(mtouch); + return -ENOMEM; + } + + if (udev->descriptor.iManufacturer && + usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(mtouch->name, buf); + if (udev->descriptor.iProduct && + usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0) + sprintf(mtouch->name, "%s %s", mtouch->name, buf); + + if (!strlen(mtouch->name)) + sprintf(mtouch->name, "USB Touchscreen %04x:%04x", + mtouch->input.id.vendor, mtouch->input.id.product); + + kfree(buf); + + nRet = usb_control_msg(mtouch->udev, + usb_rcvctrlpipe(udev, 0x80), + USB_REQ_GET_CONFIGURATION, + USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0, + 0x81, + NULL, + 0, + HZ * USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d", + __FUNCTION__, nRet); + + dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); + mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!mtouch->irq) { + dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + dbg("%s - usb_fill_int_urb", __FUNCTION__); + usb_fill_int_urb(mtouch->irq, + mtouch->udev, + usb_rcvintpipe(mtouch->udev, 0x81), + mtouch->data, + MTOUCHUSB_REPORT_SIZE_DATA, + mtouchusb_irq, + mtouch, + endpoint->bInterval); + + dbg("%s - input_register_device", __FUNCTION__); + input_register_device(&mtouch->input); + + nRet = usb_control_msg(mtouch->udev, + usb_rcvctrlpipe(udev, 0x80), + MTOUCHUSB_ASYC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MTOUCHUSB_ASYC_REPORT, + MTOUCHUSB_ASYC_REPORT, + NULL, + 0, + HZ * USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d", + __FUNCTION__, nRet); + + printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); + usb_set_intfdata(intf, mtouch); + + return 0; +} + +static void mtouchusb_disconnect(struct usb_interface *intf) +{ + struct mtouch_usb *mtouch = usb_get_intfdata (intf); + + dbg("%s - called", __FUNCTION__); + usb_set_intfdata(intf, NULL); + if (mtouch) { + dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); + usb_unlink_urb(mtouch->irq); + input_unregister_device(&mtouch->input); + usb_free_urb(mtouch->irq); + mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); + kfree(mtouch); + } +} + +MODULE_DEVICE_TABLE (usb, mtouchusb_devices); + +static struct usb_driver mtouchusb_driver = { + .owner = THIS_MODULE, + .name = "mtouchusb", + .probe = mtouchusb_probe, + .disconnect = mtouchusb_disconnect, + .id_table = mtouchusb_devices, +}; + +static int __init mtouchusb_init(void) { + dbg("%s - called", __FUNCTION__); + return usb_register(&mtouchusb_driver); +} + +static void __exit mtouchusb_cleanup(void) { + dbg("%s - called", __FUNCTION__); + usb_deregister(&mtouchusb_driver); +} + +module_init(mtouchusb_init); +module_exit(mtouchusb_cleanup); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); +MODULE_PARM(vendor, "i"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); +MODULE_PARM(product, "i"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); + + diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c --- a/drivers/usb/input/pid.c Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/input/pid.c Sat Apr 3 19:38:55 2004 @@ -200,6 +200,7 @@ break; if ( id == FF_EFFECTS_MAX) { + spin_unlock_irqrestore(&pid_private->lock,flags); // TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) { dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n"); return -ENOMEM; diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c --- a/drivers/usb/input/usbkbd.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/input/usbkbd.c Sat Apr 3 19:38:56 2004 @@ -240,7 +240,7 @@ char path[64]; char *buf; - interface = &iface->altsetting[iface->act_altsetting]; + interface = iface->cur_altsetting; if (interface->desc.bNumEndpoints != 1) return -ENODEV; diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c --- a/drivers/usb/input/usbmouse.c Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/input/usbmouse.c Sat Apr 3 19:38:55 2004 @@ -131,7 +131,7 @@ char path[64]; char *buf; - interface = &intf->altsetting[intf->act_altsetting]; + interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != 1) return -ENODEV; diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Sat Apr 3 19:38:41 2004 +++ b/drivers/usb/input/wacom.c Sat Apr 3 19:38:41 2004 @@ -1,14 +1,15 @@ /* * USB Wacom Graphire and Wacom Intuos tablet support * - * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2000-2004 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen * Copyright (c) 2000 Clifford Wolf * Copyright (c) 2000 Sam Mosel * Copyright (c) 2000 James E. Blair * Copyright (c) 2000 Daniel Egger * Copyright (c) 2001 Frederic Lepied - * Copyright (c) 2002 Ping Cheng + * Copyright (c) 2004 Panagiotis Issaris + * Copyright (c) 2002-2004 Ping Cheng * * ChangeLog: * v0.1 (vp) - Initial release @@ -48,6 +49,8 @@ * v1.30 (vp) - Merge 2.4 and 2.5 drivers * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse * - Cleanups here and there + * v1.30.1 (pi) - Added Graphire3 support + * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ... */ /* @@ -63,6 +66,8 @@ #include #include #include +#include +#include /* * Version Information @@ -106,7 +111,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type, unsigned char id, void *buf, int size) { - return usb_control_msg(interface_to_usbdev(intf), + return usb_control_msg(interface_to_usbdev(intf), usb_sndctrlpipe(interface_to_usbdev(intf), 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, @@ -137,14 +142,12 @@ } if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_pl_irq: received unknown report #%d", data[0]); prox = data[1] & 0x40; input_regs(dev, regs); - input_report_key(dev, BTN_TOOL_PEN, prox); - if (prox) { pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); @@ -152,15 +155,103 @@ pressure = (pressure << 1) | ((data[4] >> 6) & 1); pressure += (wacom->features->pressure_max + 1) / 2; + /* + * if going from out of proximity into proximity select between the eraser + * and the pen based on the state of the stylus2 button, choose eraser if + * pressed else choose pen. if not a proximity change from out to in, send + * an out of proximity for previous tool then a in for new tool. + */ + if (!wacom->tool[0]) { + /* Going into proximity select tool */ + wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + } + else { + /* was entered with stylus2 pressed */ + if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) { + /* report out proximity for previous tool */ + input_report_key(dev, wacom->tool[1], 0); + input_sync(dev); + wacom->tool[1] = BTN_TOOL_PEN; + goto exit; + } + } + if (wacom->tool[1] != BTN_TOOL_RUBBER) { + /* Unknown tool selected default to pen tool */ + wacom->tool[1] = BTN_TOOL_PEN; + } + input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14)); input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14)); input_report_abs(dev, ABS_PRESSURE, pressure); input_report_key(dev, BTN_TOUCH, data[4] & 0x08); input_report_key(dev, BTN_STYLUS, data[4] & 0x10); - input_report_key(dev, BTN_STYLUS2, data[4] & 0x20); + /* Only allow the stylus2 button to be reported for the pen tool. */ + input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); } - + else { + /* report proximity-out of a (valid) tool */ + if (wacom->tool[1] != BTN_TOOL_RUBBER) { + /* Unknown tool selected default to pen tool */ + wacom->tool[1] = BTN_TOOL_PEN; + } + input_report_key(dev, wacom->tool[1], prox); + } + + wacom->tool[0] = prox; /* Save proximity state */ + input_sync(dev); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) +{ + struct wacom *wacom = urb->context; + unsigned char *data = wacom->data; + struct input_dev *dev = &wacom->dev; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + goto exit; + } + + if (data[0] != 2) + { + printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); + } + + input_regs(dev, regs); + if (data[1] & 0x04) + { + input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); + input_report_key(dev, BTN_TOUCH, data[1] & 0x08); + } + else + { + input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); + input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + } + input_report_abs(dev, ABS_X, data[3] << 8 | data[2]); + input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]); + input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8)); + input_report_key(dev, BTN_STYLUS, data[1] & 0x02); + input_report_key(dev, BTN_STYLUS2, data[1] & 0x10); + input_sync(dev); exit: @@ -194,8 +285,8 @@ input_regs(dev, regs); input_report_key(dev, BTN_TOOL_PEN, 1); - input_report_abs(dev, ABS_X, data[2] << 8 | data[1]); - input_report_abs(dev, ABS_Y, data[4] << 8 | data[3]); + input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((u16 *) &data[1]))); + input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((u16 *) &data[3]))); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); @@ -231,11 +322,15 @@ goto exit; } + /* check if we can handle the data */ + if (data[0] == 99) + goto exit; + if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_graphire_irq: received unknown report #%d", data[0]); - x = data[2] | ((__u32)data[3] << 8); - y = data[4] | ((__u32)data[5] << 8); + x = le16_to_cpu(*(u16 *) &data[2]); + y = le16_to_cpu(*(u16 *) &data[4]); input_regs(dev, regs); @@ -249,13 +344,16 @@ input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80); break; - case 2: /* Mouse */ + case 2: /* Mouse with wheel */ + input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); + input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + /* fall through */ + + case 3: /* Mouse without wheel */ input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24); input_report_key(dev, BTN_LEFT, data[1] & 0x01); input_report_key(dev, BTN_RIGHT, data[1] & 0x02); - input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); input_report_abs(dev, ABS_DISTANCE, data[7]); - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_Y, y); @@ -269,7 +367,7 @@ input_report_abs(dev, ABS_Y, y); } - input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(u16 *) &data[6])); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); input_report_key(dev, BTN_STYLUS, data[1] & 0x02); input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); @@ -308,7 +406,7 @@ } if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_intuos_irq: received unknown report #%d", data[0]); input_regs(dev, regs); @@ -317,18 +415,18 @@ if ((data[1] & 0xfc) == 0xc0) { /* Enter report */ - wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 4) + /* serial number of the tool */ - ((__u32)data[4] << 16) + ((__u32)data[5] << 12) + + wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) + /* serial number of the tool */ + ((__u32)data[4] << 20) + ((__u32)data[5] << 12) + ((__u32)data[6] << 4) + (data[7] >> 4); switch (((__u32)data[2] << 4) | (data[3] >> 4)) { - case 0x832: + case 0x812: case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; /* Inking pen */ case 0x822: case 0x842: case 0x852: case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Pen */ - case 0x812: + case 0x832: case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH; break; /* Stroke pen */ case 0x007: case 0x09c: @@ -337,7 +435,10 @@ case 0x82a: case 0x85a: case 0x91a: + case 0xd1a: case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER; break; /* Eraser */ + case 0xd12: + case 0x912: case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; /* Airbrush */ default: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Unknown tool */ } @@ -350,13 +451,14 @@ if ((data[1] & 0xfe) == 0x80) { /* Exit report */ input_report_key(dev, wacom->tool[idx], 0); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); goto exit; } - input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); - input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); - input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); + input_report_abs(dev, ABS_X, be16_to_cpu(*(u16 *) &data[2])); + input_report_abs(dev, ABS_Y, be16_to_cpu(*(u16 *) &data[4])); + input_report_abs(dev, ABS_DISTANCE, data[9]); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); @@ -378,8 +480,8 @@ if (data[1] & 0x02) { /* Rotation packet */ input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? - ((__u32)data[6] << 2) | ((data[7] >> 6) & 3): - (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1); + ((__u32)data[6] << 3) | ((data[7] >> 5) & 7): + (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1); } else { @@ -391,17 +493,17 @@ input_report_key(dev, BTN_SIDE, data[8] & 0x20); input_report_key(dev, BTN_EXTRA, data[8] & 0x10); - input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? + input_report_abs(dev, ABS_THROTTLE, -((data[8] & 0x08) ? ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) : - -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); + -((__u32)data[6] << 2) | ((data[7] >> 6) & 3))); } else { if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_abs(dev, REL_WHEEL, - ((__u32)(data[8] & 0x01) - (__u32)((data[8] & 0x02) >> 1))); + input_report_rel(dev, REL_WHEEL, + (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1))); } else { /* Lens cursor packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x01); @@ -414,6 +516,8 @@ } } + input_report_key(dev, wacom->tool[idx], 1); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); exit: @@ -429,22 +533,26 @@ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 6x8", 10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 9x12", 10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 6x8", 10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 9x12", 10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { } }; @@ -454,6 +562,7 @@ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, @@ -470,6 +579,9 @@ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } }; @@ -483,8 +595,10 @@ return 0; wacom->irq->dev = wacom->usbdev; - if (usb_submit_urb(wacom->irq, GFP_KERNEL)) + if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { + wacom->open--; return -EIO; + } return 0; } @@ -509,7 +623,7 @@ return -ENOMEM; memset(wacom, 0, sizeof(struct wacom)); - wacom->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &wacom->data_dma); + wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); if (!wacom->data) { kfree(wacom); return -ENOMEM; @@ -538,8 +652,9 @@ break; case 2: - wacom->dev.evbit[0] |= BIT(EV_MSC); + wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); + wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig Sat Apr 3 19:38:40 2004 +++ b/drivers/usb/media/Kconfig Sat Apr 3 19:38:40 2004 @@ -202,4 +202,4 @@ 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 w9968cf.o. If you want to compile it as a - module, say M here and read . + module, say M here and read . diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c --- a/drivers/usb/media/se401.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/media/se401.c Sat Apr 3 19:38:42 2004 @@ -369,7 +369,7 @@ se401->scratch_overflow=0; se401->scratch_next++; if (se401->scratch_next>=SE401_NUMSCRATCH) - se401->scratch_next=0;; + se401->scratch_next=0; break; } } diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c --- a/drivers/usb/media/stv680.c Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/media/stv680.c Sat Apr 3 19:38:45 2004 @@ -641,7 +641,7 @@ stv680->scratch_overflow = 0; stv680->scratch_next++; if (stv680->scratch_next >= STV680_NUMSCRATCH) - stv680->scratch_next = 0;; + stv680->scratch_next = 0; break; } /* switch */ } else { diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig --- a/drivers/usb/misc/Kconfig Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/misc/Kconfig Sat Apr 3 19:38:56 2004 @@ -86,17 +86,6 @@ a module, say M here and read . -config USB_BRLVGER - tristate "Tieman Voyager USB Braille display support (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - help - Say Y here if you want to use the Voyager USB Braille display from - Tieman. See for more - information. - - To compile this driver as a module, choose M here: the - module will be called brlvger. - config USB_LCD tristate "USB LCD driver support" depends on USB diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile --- a/drivers/usb/misc/Makefile Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/misc/Makefile Sat Apr 3 19:38:43 2004 @@ -4,7 +4,6 @@ # obj-$(CONFIG_USB_AUERSWALD) += auerswald.o -obj-$(CONFIG_USB_BRLVGER) += brlvger.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_LCD) += usblcd.o diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c --- a/drivers/usb/misc/brlvger.c Sat Apr 3 19:38:43 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1016 +0,0 @@ -/* - * Tieman Voyager braille display USB driver. - * - * Copyright 2001-2002 Stephane Dalton - * and Stéphane Doyon - * Maintained by Stéphane Doyon . - */ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* History: - * 0.8 April 2002: Integration into the kernel tree. - * 0.7 October 2001: First public release as a module, distributed with - * the BRLTTY package (beta versions around 2.99y). - */ - -#define DRIVER_VERSION "v0.8" -#define DATE "April 2002" -#define DRIVER_AUTHOR \ - "Stephane Dalton " \ - "and Stéphane Doyon " -#define DRIVER_DESC "Tieman Voyager braille display USB driver for Linux 2.4" -#define DRIVER_SHORTDESC "Voyager" - -#define BANNER \ - KERN_INFO DRIVER_SHORTDESC " " DRIVER_VERSION " (" DATE ")\n" \ - KERN_INFO " by " DRIVER_AUTHOR "\n" - -static const char longbanner[] = { - DRIVER_DESC ", " DRIVER_VERSION " (" DATE "), by " DRIVER_AUTHOR -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - -/* Module parameters */ - -static int debug = 1; -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug level, 0-3"); - -static int write_repeats = 2; -MODULE_PARM(write_repeats, "i"); -MODULE_PARM_DESC(write_repeats, "Hack: repetitions for command to " - "display braille pattern"); - /* to get rid of weird extra dots (perhaps only on - early hardware versions?) */ - -static int stall_tries = 3; -MODULE_PARM(stall_tries, "i"); -MODULE_PARM_DESC(stall_tries, "Hack: retransmits of stalled USB " - "control messages"); - /* broken early hardware versions? */ - -#define BRLVGER_RAW_VOLTAGE 89 -/* from 0->300V to 255->200V, we are told 265V is normal operating voltage, - but we don't know the scale. Assuming it is linear. */ -static int raw_voltage = BRLVGER_RAW_VOLTAGE; -MODULE_PARM(raw_voltage, "i"); -MODULE_PARM_DESC(raw_voltage, "Parameter for the call to SET_DISPLAY_VOLTAGE"); - - -/* protocol and display type defines */ -#define MAX_BRLVGER_CELLS 72 -#define MAX_INTERRUPT_DATA 8 -/* control message request types */ -#define BRLVGER_READ_REQ 0xC2 -#define BRLVGER_WRITE_REQ 0x42 -/* control message request codes */ -#define BRLVGER_SET_DISPLAY_ON 0 -#define BRLVGER_SET_DISPLAY_VOLTAGE 1 -#define BRLVGER_GET_SERIAL 3 -#define BRLVGER_GET_HWVERSION 4 -#define BRLVGER_GET_FWVERSION 5 -#define BRLVGER_GET_LENGTH 6 -#define BRLVGER_SEND_BRAILLE 7 -#define BRLVGER_BEEP 9 -#if 0 /* not used and not sure they're working */ -#define BRLVGER_GET_DISPLAY_VOLTAGE 2 -#define BRLVGER_GET_CURRENT 8 -#endif - -/* Prototypes */ -static int brlvger_probe (struct usb_interface *intf, - const struct usb_device_id *id); -static void brlvger_disconnect(struct usb_interface *intf); -static int brlvger_open(struct inode *inode, struct file *file); -static int brlvger_release(struct inode *inode, struct file *file); -static ssize_t brlvger_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos); -static ssize_t brlvger_read(struct file *file, char __user *buffer, - size_t count, loff_t *unused_pos); -static int brlvger_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg); -static unsigned brlvger_poll(struct file *file, poll_table *wait); -static loff_t brlvger_llseek(struct file * file, loff_t offset, int orig); -static void intr_callback(struct urb *urb, struct pt_regs *regs); -struct brlvger_priv; -static int brlvger_get_hw_version(struct brlvger_priv *priv, - unsigned char *verbuf); -static int brlvger_get_fw_version(struct brlvger_priv *priv, - unsigned char *buf); -static int brlvger_get_serial(struct brlvger_priv *priv, - unsigned char *buf); -static int brlvger_get_display_length(struct brlvger_priv *priv); -static int brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on); -static int brlvger_beep(struct brlvger_priv *priv, __u16 duration); -static int brlvger_set_display_voltage(struct brlvger_priv *priv, - __u16 voltage); -static int mycontrolmsg(const char *funcname, - struct brlvger_priv *priv, unsigned pipe_dir, - __u8 request, __u8 requesttype, __u16 value, - __u16 index, void *data, __u16 size); - -#define controlmsg(priv,pipe_dir,a,b,c,d,e,f) \ - mycontrolmsg(__FUNCTION__, priv, pipe_dir, \ - a,b,c,d,e,f) -#define sndcontrolmsg(priv,a,b,c,d,e,f) \ - controlmsg(priv, 0, a,b,c,d,e,f) -#define rcvcontrolmsg(priv,a,b,c,d,e,f) \ - controlmsg(priv, USB_DIR_IN, a,b,c,d,e,f) - -/* ----------------------------------------------------------------------- */ - -/* Data */ - -/* key event queue size */ -#define MAX_INTERRUPT_BUFFER 10 - -/* private state */ -struct brlvger_priv { - struct usb_device *dev; /* USB device handle */ - struct usb_endpoint_descriptor *in_interrupt; - struct urb *intr_urb; - - int subminor; /* which minor dev #? */ - - unsigned char hwver[BRLVGER_HWVER_SIZE]; /* hardware version */ - unsigned char fwver[BRLVGER_FWVER_SIZE]; /* firmware version */ - unsigned char serialnum[BRLVGER_SERIAL_SIZE]; - - int llength; /* logical length */ - int plength; /* physical length */ - - __u8 obuf[MAX_BRLVGER_CELLS]; - __u8 intr_buff[MAX_INTERRUPT_DATA]; - __u8 event_queue[MAX_INTERRUPT_BUFFER][MAX_INTERRUPT_DATA]; - atomic_t intr_idx, read_idx; - spinlock_t intr_idx_lock; /* protects intr_idx */ - wait_queue_head_t read_wait; - - int opened; - struct semaphore open_sem; /* protects ->opened */ - struct semaphore dev_sem; /* protects ->dev */ -}; - -/* Globals */ - -/* For blocking open */ -static DECLARE_WAIT_QUEUE_HEAD(open_wait); - -/* Some print macros */ -#ifdef dbg -#undef dbg -#endif -#ifdef info -#undef info -#endif -#ifdef err -#undef err -#endif -#define info(args...) \ - ({ printk(KERN_INFO "Voyager: " args); \ - printk("\n"); }) -#define err(args...) \ - ({ printk(KERN_ERR "Voyager: " args); \ - printk("\n"); }) -#define dbgprint(fmt, args...) \ - ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \ - printk("\n"); }) -#define dbg(args...) \ - ({ if(debug >= 1) dbgprint(args); }) -#define dbg2(args...) \ - ({ if(debug >= 2) dbgprint(args); }) -#define dbg3(args...) \ - ({ if(debug >= 3) dbgprint(args); }) - -/* ----------------------------------------------------------------------- */ - -/* Driver registration */ - -static struct usb_device_id brlvger_ids [] = { - { USB_DEVICE(0x0798, 0x0001) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, brlvger_ids); - -static struct file_operations brlvger_fops = -{ - .owner = THIS_MODULE, - .llseek = brlvger_llseek, - .read = brlvger_read, - .write = brlvger_write, - .ioctl = brlvger_ioctl, - .open = brlvger_open, - .release = brlvger_release, - .poll = brlvger_poll, -}; - -static struct usb_class_driver brlvger_class = { - .name = "usb/brlvger%d", - .fops = &brlvger_fops, - .mode = S_IFCHR | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP, - .minor_base = BRLVGER_MINOR, -}; - -static struct usb_driver brlvger_driver = -{ - .owner = THIS_MODULE, - .name = "brlvger", - .probe = brlvger_probe, - .disconnect = brlvger_disconnect, - .id_table = brlvger_ids, -}; - -static int -__init brlvger_init (void) -{ - int retval; - printk(BANNER); - - if(stall_tries < 1 || write_repeats < 1) - return -EINVAL; - - retval = usb_register(&brlvger_driver); - if (retval) { - err("USB registration failed"); - goto out; - } - -out: - return retval; -} - -static void -__exit brlvger_cleanup (void) -{ - usb_deregister (&brlvger_driver); - dbg("Driver unregistered"); -} - -module_init (brlvger_init); -module_exit (brlvger_cleanup); - -/* ----------------------------------------------------------------------- */ - -/* Probe and disconnect functions */ - -static int -brlvger_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct brlvger_priv *priv = NULL; - int retval; - struct usb_endpoint_descriptor *endpoint; - struct usb_host_interface *actifsettings; - /* protects against reentrance: once we've found a free slot - we reserve it.*/ - static DECLARE_MUTEX(reserve_sem); - - actifsettings = dev->actconfig->interface[0]->altsetting; - - if( dev->descriptor.bNumConfigurations != 1 - || dev->config->desc.bNumInterfaces != 1 - || actifsettings->desc.bNumEndpoints != 1 ) { - err ("Bogus braille display config info"); - return -ENODEV; - } - - endpoint = &actifsettings->endpoint [0].desc; - if (!(endpoint->bEndpointAddress & 0x80) || - ((endpoint->bmAttributes & 3) != 0x03)) { - err ("Bogus braille display config info, wrong endpoints"); - return -ENODEV; - } - - down(&reserve_sem); - - retval = usb_register_dev(intf, &brlvger_class); - if (retval) { - err("Not able to get a minor for this device."); - goto error; - } - - if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){ - err("No more memory"); - goto error; - } - - memset(priv, 0, sizeof(*priv)); - atomic_set(&priv->intr_idx, 0); - atomic_set(&priv->read_idx, MAX_INTERRUPT_BUFFER-1); - spin_lock_init(&priv->intr_idx_lock); - init_waitqueue_head(&priv->read_wait); - /* opened is memset'ed to 0 */ - init_MUTEX(&priv->open_sem); - init_MUTEX(&priv->dev_sem); - - priv->subminor = intf->minor; - - /* we found a interrupt in endpoint */ - priv->in_interrupt = endpoint; - - priv->dev = dev; - - if(brlvger_get_hw_version(priv, priv->hwver) <0) { - err("Unable to get hardware version"); - goto error; - } - dbg("Hw ver %d.%d", priv->hwver[0], priv->hwver[1]); - if(brlvger_get_fw_version(priv, priv->fwver) <0) { - err("Unable to get firmware version"); - goto error; - } - dbg("Fw ver: %s", priv->fwver); - - if(brlvger_get_serial(priv, priv->serialnum) <0) { - err("Unable to get serial number"); - goto error; - } - dbg("Serial number: %s", priv->serialnum); - - if( (priv->llength = brlvger_get_display_length(priv)) <0 ){ - err("Unable to get display length"); - goto error; - } - switch(priv->llength) { - case 48: - priv->plength = 44; - break; - case 72: - priv->plength = 70; - break; - default: - err("Unsupported display length: %d", priv->llength); - goto error; - }; - dbg("Display length: %d", priv->plength); - - usb_set_intfdata (intf, priv); - info( "Braille display %d is device major %d minor %d", - intf->minor, USB_MAJOR, BRLVGER_MINOR + intf->minor); - - /* Tell anyone waiting on a blocking open */ - wake_up_interruptible(&open_wait); - - goto out; - - error: - if(priv) { - kfree( priv ); - priv = NULL; - } - - out: - up(&reserve_sem); - if (priv) { - usb_set_intfdata (intf, priv); - return 0; - } - return -EIO; -} - -static void -brlvger_disconnect(struct usb_interface *intf) -{ - struct brlvger_priv *priv = usb_get_intfdata (intf); - int r; - - usb_set_intfdata (intf, NULL); - if(priv){ - info("Display %d disconnecting", priv->subminor); - - usb_deregister_dev(intf, &brlvger_class); - - down(&priv->open_sem); - down(&priv->dev_sem); - if(priv->opened) { - /* Disable interrupts */ - if((r = usb_unlink_urb(priv->intr_urb)) <0) - err("usb_unlink_urb returns %d", r); - usb_free_urb(priv->intr_urb); - /* mark device as dead and prevent control - messages to it */ - priv->dev = NULL; - /* Tell anyone hung up on a read that it - won't be coming */ - wake_up_interruptible(&priv->read_wait); - up(&priv->dev_sem); - up(&priv->open_sem); - }else - /* no corresponding up()s */ - kfree(priv); - } -} - -/* ----------------------------------------------------------------------- */ - -/* fops implementation */ - -static int -brlvger_open(struct inode *inode, struct file *file) -{ - int devnum = iminor(inode); - struct usb_interface *intf = NULL; - struct brlvger_priv *priv = NULL; - int n, ret; - - if (devnum < 0) - return -ENXIO; - - n = devnum - BRLVGER_MINOR; - - do { - intf = usb_find_interface(&brlvger_driver, devnum); - if (!intf) { - if (file->f_flags & O_NONBLOCK) { - dbg3("Failing non-blocking open: " - "device %d not connected", n); - return -EAGAIN; - } - /* Blocking open. One global wait queue will - suffice. We wait until a device for the selected - minor is connected. */ - dbg2("Waiting for device %d to be connected", n); - ret = wait_event_interruptible(open_wait, - (intf = usb_find_interface(&brlvger_driver, devnum))); - if (ret) { - dbg2("Interrupted wait for device %d", n); - return ret; - } - } - } while(!intf); - priv = usb_get_intfdata(intf); - - /* We grabbed an existing device. */ - if(down_interruptible(&priv->open_sem)) - return -ERESTARTSYS; - - /* Only one process can open each device, no sharing. */ - ret = -EBUSY; - if(priv->opened) - goto out; - - dbg("Opening display %d", priv->subminor); - - /* Setup interrupt handler for receiving key input */ - priv->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if(!priv->intr_urb) { - err("Unable to allocate URB"); - goto out; - } - usb_fill_int_urb( priv->intr_urb, priv->dev, - usb_rcvintpipe(priv->dev, - priv->in_interrupt->bEndpointAddress), - priv->intr_buff, sizeof(priv->intr_buff), - intr_callback, priv, priv->in_interrupt->bInterval); - if((ret = usb_submit_urb(priv->intr_urb, GFP_KERNEL)) <0){ - err("Error %d while submitting URB", ret); - goto out; - } - - /* Set voltage */ - if(brlvger_set_display_voltage(priv, raw_voltage) <0) { - err("Unable to set voltage"); - goto out; - } - - /* Turn display on */ - if((ret = brlvger_set_display_on_off(priv, 1)) <0) { - err("Error %d while turning display on", ret); - goto out; - } - - /* Mark as opened, so disconnect cannot free priv. */ - priv->opened = 1; - - file->private_data = priv; - - ret = 0; - goto out; - - out: - up(&priv->open_sem); - return ret; -} - -static int -brlvger_release(struct inode *inode, struct file *file) -{ - struct brlvger_priv *priv = file->private_data; - int r; - - /* Turn display off. Safe even if disconnected. */ - brlvger_set_display_on_off(priv, 0); - - /* mutex with disconnect and with open */ - down(&priv->open_sem); - - if(!priv->dev) { - dbg("Releasing disconnected device %d", priv->subminor); - /* no up(&priv->open_sem) */ - kfree(priv); - }else{ - dbg("Closing display %d", priv->subminor); - /* Disable interrupts */ - if((r = usb_unlink_urb(priv->intr_urb)) <0) - err("usb_unlink_urb returns %d", r); - usb_free_urb(priv->intr_urb); - priv->opened = 0; - up(&priv->open_sem); - } - - return 0; -} - -static ssize_t -brlvger_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - struct brlvger_priv *priv = file->private_data; - char buf[MAX_BRLVGER_CELLS]; - int ret; - size_t rs; - loff_t off; - __u16 written; - - if(!priv->dev) - return -ENOLINK; - - off = *pos; - - if(off > priv->plength) - return -ESPIPE;; - - rs = priv->plength - off; - - if(count > rs) - count = rs; - written = count; - - if (copy_from_user (buf, buffer, count ) ) - return -EFAULT; - - memset(priv->obuf, 0xaa, sizeof(priv->obuf)); - - /* Firmware supports multiples of 8cells, so some cells are absent - and for some reason there actually are holes! euurkkk! */ - - if( priv->plength == 44 ) { - /* Two ghost cells at the beginning of the display, plus - two more after the sixth physical cell. */ - if(off > 5) { - off +=4; - memcpy(priv->obuf, buf, count); - }else{ - int firstpart = 6 - off; - -#ifdef WRITE_DEBUG - dbg3("off: %lld, rs: %d, count: %d, firstpart: %d", - off, rs, count, firstpart); -#endif - - firstpart = (firstpart < count) ? firstpart : count; - -#ifdef WRITE_DEBUG - dbg3("off: %lld", off); - dbg3("firstpart: %d", firstpart); -#endif - - memcpy(priv->obuf, buf, firstpart); - - if(firstpart != count) { - int secondpart = count - firstpart; -#ifdef WRITE_DEBUG - dbg3("secondpart: %d", secondpart); -#endif - - memcpy(priv->obuf+(firstpart+2), - buf+firstpart, secondpart); - written +=2; - } - - off +=2; - -#ifdef WRITE_DEBUG - dbg3("off: %lld, rs: %d, count: %d, firstpart: %d, " - "written: %d", off, rs, count, firstpart, written); -#endif - } - }else{ - /* Two ghost cells at the beginningg of the display. */ - memcpy(priv->obuf, buf, count); - off += 2; - } - - { - int repeat = write_repeats; - /* Dirty hack: sometimes some of the dots are wrong and somehow - right themselves if the command is repeated. */ - while(repeat--) { - ret = sndcontrolmsg(priv, - BRLVGER_SEND_BRAILLE, BRLVGER_WRITE_REQ, 0, - off, priv->obuf, written); - if(ret <0) - return ret; - } - } - - return count; -} - -static int -read_index(struct brlvger_priv *priv) -{ - int intr_idx, read_idx; - - read_idx = atomic_read(&priv->read_idx); - read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; - - intr_idx = atomic_read(&priv->intr_idx); - - return(read_idx == intr_idx ? -1 : read_idx); -} - -static ssize_t -brlvger_read(struct file *file, char __user *buffer, - size_t count, loff_t *unused_pos) -{ - struct brlvger_priv *priv = file->private_data; - int read_idx; - - if(count != MAX_INTERRUPT_DATA) - return -EINVAL; - - if(!priv->dev) - return -ENOLINK; - - if((read_idx = read_index(priv)) == -1) { - /* queue empty */ - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - else{ - int r = wait_event_interruptible(priv->read_wait, - (!priv->dev || (read_idx = read_index(priv)) != -1)); - if(!priv->dev) - return -ENOLINK; - if(r) - return r; - if(read_idx == -1) - /* should not happen */ - return 0; - } - } - - if (copy_to_user (buffer, priv->event_queue[read_idx], count) ) - return( -EFAULT); - - atomic_set(&priv->read_idx, read_idx); - /* Multiple opens are not allowed. Yet on SMP, two processes could - read at the same time (on a shared file descriptor); then it is not - deterministic whether or not they will get duplicates of a key - event. */ - return MAX_INTERRUPT_DATA; -} - -static int -brlvger_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return -ENOLINK; - - switch(cmd) { - case BRLVGER_GET_INFO: { - struct brlvger_info vi; - - memset(&vi, 0, sizeof(vi)); - strlcpy(vi.driver_version, DRIVER_VERSION, - sizeof(vi.driver_version)); - strlcpy(vi.driver_banner, longbanner, - sizeof(vi.driver_banner)); - - vi.display_length = priv->plength; - - memcpy(&vi.hwver, priv->hwver, BRLVGER_HWVER_SIZE); - memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE); - memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE); - - if(copy_to_user((void __user *)arg, &vi, sizeof(vi))) - return -EFAULT; - return 0; - } - case BRLVGER_DISPLAY_ON: - return brlvger_set_display_on_off(priv, 1); - case BRLVGER_DISPLAY_OFF: - return brlvger_set_display_on_off(priv, 0); - case BRLVGER_BUZZ: { - __u16 duration; - if(get_user(duration, (__u16 *)arg)) - return -EFAULT; - return brlvger_beep(priv, duration); - } - -#if 0 /* Underlying commands don't seem to work for some reason; not clear if - we'd want to export these anyway. */ - case BRLVGER_SET_VOLTAGE: { - __u16 voltage; - if(get_user(voltage, (__u16 *)arg)) - return -EFAULT; - return brlvger_set_display_voltage(priv, voltage); - } - case BRLVGER_GET_VOLTAGE: { - __u8 voltage; - int r = brlvger_get_display_voltage(priv); - if(r <0) - return r; - voltage = r; - if(put_user(voltage, (__u8 *)arg)) - return -EFAULT; - return 0; - } -#endif - default: - return -EINVAL; - }; -} - -static loff_t -brlvger_llseek(struct file *file, loff_t offset, int orig) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return -ENOLINK; - - switch (orig) { - case 0: - /* nothing to do */ - break; - case 1: - offset +=file->f_pos; - break; - case 2: - offset += priv->plength; - default: - return -EINVAL; - } - - if((offset >= priv->plength) || (offset < 0)) - return -EINVAL; - - return (file->f_pos = offset); -} - -static unsigned -brlvger_poll(struct file *file, poll_table *wait) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return POLLERR | POLLHUP; - - poll_wait(file, &priv->read_wait, wait); - - if(!priv->dev) - return POLLERR | POLLHUP; - if(read_index(priv) != -1) - return POLLIN | POLLRDNORM; - - return 0; -} - -static void -intr_callback(struct urb *urb, struct pt_regs *regs) -{ - struct brlvger_priv *priv = urb->context; - int intr_idx, read_idx; - int status; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - read_idx = atomic_read(&priv->read_idx); - spin_lock(&priv->intr_idx_lock); - intr_idx = atomic_read(&priv->intr_idx); - if(read_idx == intr_idx) { - dbg2("Queue full, dropping braille display input"); - spin_unlock(&priv->intr_idx_lock); - goto exit; /* queue full */ - } - - memcpy(priv->event_queue[intr_idx], urb->transfer_buffer, - MAX_INTERRUPT_DATA); - - intr_idx = (++intr_idx == MAX_INTERRUPT_BUFFER)? 0 : intr_idx; - atomic_set(&priv->intr_idx, intr_idx); - spin_unlock(&priv->intr_idx_lock); - - wake_up_interruptible(&priv->read_wait); - -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -/* ----------------------------------------------------------------------- */ - -/* Hardware access functions */ - -static int -mycontrolmsg(const char *funcname, - struct brlvger_priv *priv, unsigned pipe_dir, - __u8 request, __u8 requesttype, __u16 value, - __u16 index, void *data, __u16 size) -{ - int ret=0, tries = stall_tries; - - /* Make sure the device was not disconnected */ - if(down_interruptible(&priv->dev_sem)) - return -ERESTARTSYS; - if(!priv->dev) { - up(&priv->dev_sem); - return -ENOLINK; - } - - /* Dirty hack for retransmission: stalls and fails all the time - without this on the hardware we tested. */ - while(tries--) { - ret = usb_control_msg(priv->dev, - usb_sndctrlpipe(priv->dev,0) |pipe_dir, - request, requesttype, value, - index, data, size, - HZ); - if(ret != -EPIPE) - break; - dbg2("Stalled, remaining %d tries", tries); - } - up(&priv->dev_sem); - if(ret <0) { - err("%s: usb_control_msg returns %d", - funcname, ret); - return -EIO; - } - return 0; -} - -static int -brlvger_get_hw_version(struct brlvger_priv *priv, unsigned char *verbuf) -{ - return rcvcontrolmsg(priv, - BRLVGER_GET_HWVERSION, BRLVGER_READ_REQ, 0, - 0, verbuf, BRLVGER_HWVER_SIZE); - /* verbuf should be 2 bytes */ -} - -static int -brlvger_get_fw_version(struct brlvger_priv *priv, unsigned char *buf) -{ - unsigned char rawbuf[(BRLVGER_FWVER_SIZE-1)*2+2]; - int i, len; - int r = rcvcontrolmsg(priv, - BRLVGER_GET_FWVERSION, BRLVGER_READ_REQ, 0, - 0, rawbuf, sizeof(rawbuf)); - if(r<0) - return r; - - /* If I guess correctly: succession of 16bit words, the string is - formed of the first byte of each of these words. First byte in - buffer indicates total length of data; not sure what second byte is - for. */ - len = rawbuf[0]-2; - if(len<0) - len = 0; - else if(len+1 > BRLVGER_FWVER_SIZE) - len = BRLVGER_FWVER_SIZE-1; - for(i=0; i9) ? (n)+'A' : (n)+'0') - buf[2*i] = NUM_TO_HEX(rawserial[i] >>4); - buf[2*i+1] = NUM_TO_HEX(rawserial[i] &0xf); - } - buf[2*i] = 0; - return 0; -} - -static int -brlvger_get_display_length(struct brlvger_priv *priv) -{ - unsigned char data[2]; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_LENGTH, BRLVGER_READ_REQ, 0, - 0, data, 2); - if(ret<0) - return ret; - return data[1]; -} - -static int -brlvger_beep(struct brlvger_priv *priv, __u16 duration) -{ - return sndcontrolmsg(priv, - BRLVGER_BEEP, BRLVGER_WRITE_REQ, duration, - 0, NULL, 0); -} - -static int -brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on) -{ - dbg2("Turning display %s", ((on) ? "on" : "off")); - return sndcontrolmsg(priv, - BRLVGER_SET_DISPLAY_ON, BRLVGER_WRITE_REQ, on, - 0, NULL, 0); -} - -static int -brlvger_set_display_voltage(struct brlvger_priv *priv, __u16 voltage) -{ - dbg("SET_DISPLAY_VOLTAGE to %u", voltage); - return sndcontrolmsg(priv, - BRLVGER_SET_DISPLAY_VOLTAGE, BRLVGER_WRITE_REQ, voltage, - 0, NULL, 0); -} - -#if 0 /* Had problems testing these commands. Not particularly useful anyway.*/ - -static int -brlvger_get_display_voltage(struct brlvger_priv *priv) -{ - __u8 voltage = 0; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_DISPLAY_VOLTAGE, BRLVGER_READ_REQ, 0, - 0, &voltage, 1); - if(ret<0) - return ret; - return voltage; -} - -static int -brlvger_get_current(struct brlvger_priv *priv) -{ - unsigned char data; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_CURRENT, BRLVGER_READ_REQ, 0, - 0, &data, 1); - if(ret<0) - return ret; - return data; -} -#endif diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/misc/usbtest.c Sat Apr 3 19:38:56 2004 @@ -149,8 +149,6 @@ if (!out) out = e; } - if (in && out) - goto found; continue; try_iso: if (e->desc.bEndpointAddress & USB_DIR_IN) { @@ -160,9 +158,9 @@ if (!iso_out) iso_out = e; } - if (iso_in && iso_out) - goto found; } + if ((in && out) || (iso_in && iso_out)) + goto found; } return -EINVAL; @@ -181,7 +179,8 @@ in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out_pipe = usb_sndbulkpipe (udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - } else if (iso_in) { + } + if (iso_in) { dev->iso_in = &iso_in->desc; dev->in_iso_pipe = usb_rcvisocpipe (udev, iso_in->desc.bEndpointAddress @@ -211,7 +210,7 @@ static struct urb *simple_alloc_urb ( struct usb_device *udev, int pipe, - long bytes + unsigned long bytes ) { struct urb *urb; @@ -490,7 +489,7 @@ struct usb_interface *iface = dev->intf; struct usb_device *udev; - if (alternate < 0 || alternate >= iface->num_altsetting) + if (alternate < 0 || alternate >= 256) return -EINVAL; udev = interface_to_usbdev (iface); @@ -556,23 +555,19 @@ { struct usb_interface *iface = dev->intf; struct usb_device *udev = interface_to_usbdev (iface); - int i, retval; + int i, alt, retval; /* [9.2.3] if there's more than one altsetting, we need to be able to * set and get each one. mostly trusts the descriptors from usbcore. */ for (i = 0; i < iface->num_altsetting; i++) { - /* 9.2.3 constrains the range here, and Linux ensures - * they're ordered meaningfully in this array - */ - if (iface->altsetting [i].desc.bAlternateSetting != i) { + /* 9.2.3 constrains the range here */ + alt = iface->altsetting [i].desc.bAlternateSetting; + if (alt < 0 || alt >= iface->num_altsetting) { dev_dbg (&iface->dev, "invalid alt [%d].bAltSetting = %d\n", - i, - iface->altsetting [i].desc - .bAlternateSetting); - return -EDOM; + i, alt); } /* [real world] get/set unimplemented if there's only one */ @@ -580,18 +575,18 @@ continue; /* [9.4.10] set_interface */ - retval = set_altsetting (dev, i); + retval = set_altsetting (dev, alt); if (retval) { dev_dbg (&iface->dev, "can't set_interface = %d, %d\n", - i, retval); + alt, retval); return retval; } /* [9.4.4] get_interface always works */ retval = get_altsetting (dev); - if (retval != i) { + if (retval != alt) { dev_dbg (&iface->dev, "get alt should be %d, was %d\n", - i, retval); + alt, retval); return (retval < 0) ? retval : -EDOM; } @@ -916,7 +911,7 @@ req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); // interface == 0 len = sizeof (struct usb_interface_descriptor); - expected = -EPIPE; + expected = EPIPE; break; // NOTE: two consecutive stalls in the queue here. // that tests fault recovery a bit more aggressively. @@ -945,7 +940,7 @@ req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8); // endpoint == 0 len = sizeof (struct usb_interface_descriptor); - expected = -EPIPE; + expected = EPIPE; break; // NOTE: sometimes even a third fault in the queue! case 12: // get string 0 descriptor (MAY STALL) @@ -1072,7 +1067,7 @@ * due to errors, or is just NAKing requests. */ if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) { - dbg ("submit/unlink fail %d", retval); + dev_dbg (&dev->intf->dev, "submit fail %d\n", retval); return retval; } @@ -1087,18 +1082,22 @@ * "normal" drivers would prevent resubmission, but * since we're testing unlink paths, we can't. */ - dbg ("unlink retry"); + dev_dbg (&dev->intf->dev, "unlink retry\n"); goto retry; } if (!(retval == 0 || retval == -EINPROGRESS)) { - dbg ("submit/unlink fail %d", retval); + dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval); return retval; } wait_for_completion (&completion); retval = urb->status; simple_free_urb (urb); - return retval; + + if (async) + return (retval != -ECONNRESET) ? -ECONNRESET : 0; + else + return (retval != -ENOENT) ? -ENOENT : 0; } static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) @@ -1723,7 +1722,8 @@ retval = unlink_simple (dev, dev->in_pipe, param->length); if (retval) - dbg ("unlink reads failed, iterations left %d", i); + dev_dbg (&intf->dev, "unlink reads failed %d, " + "iterations left %d\n", retval, i); break; case 12: if (dev->out_pipe == 0 || !param->length) @@ -1735,7 +1735,8 @@ retval = unlink_simple (dev, dev->out_pipe, param->length); if (retval) - dbg ("unlink writes failed, iterations left %d", i); + dev_dbg (&intf->dev, "unlink writes failed %d, " + "iterations left %d\n", retval, i); break; /* ep halt tests */ @@ -1965,7 +1966,10 @@ .name = "usb test device", .ep_in = 2, .ep_out = 2, - .alt = 0, + .alt = 1, + .autoconf = 1, // iso and ctrl_out need autoconf + .ctrl_out = 1, + .iso = 1, // iso_ep's are #8 in/out }; /* peripheral running Linux and 'zero.c' test firmware, or diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig --- a/drivers/usb/net/Kconfig Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/net/Kconfig Sat Apr 3 19:38:54 2004 @@ -131,6 +131,14 @@ comment "USB Host-to-Host Cables" depends on USB_USBNET +config USB_ALI_M5632 + boolean "ALi M5632 based 'USB 2.0 Data Link' cables" + depends on USB_USBNET + default y + help + Choose this option if you're using a host-to-host cable + based on this design, which supports USB 2.0 high speed. + config USB_AN2720 boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" depends on USB_USBNET diff -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h --- a/drivers/usb/net/pegasus.h Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/net/pegasus.h Sat Apr 3 19:38:56 2004 @@ -128,6 +128,7 @@ #define VENDOR_DLINK 0x2001 #define VENDOR_ELCON 0x0db7 #define VENDOR_ELSA 0x05cc +#define VENDOR_GIGABYTE 0x1044 #define VENDOR_HAWKING 0x0e66 #define VENDOR_HP 0x03f0 #define VENDOR_IODATA 0x04bb @@ -178,6 +179,9 @@ PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet", VENDOR_ADMTEK, 0x8513, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet", + VENDOR_ADMTEK, 0x8515, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)", VENDOR_ADMTEK, 0x0986, DEFAULT_GPIO_RESET | HAS_HOME_PNA ) @@ -223,6 +227,8 @@ DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, @@ -262,6 +268,8 @@ PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, + DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, DEFAULT_GPIO_RESET | PEGASUS_II ) diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/net/usbnet.c Sat Apr 3 19:38:43 2004 @@ -384,6 +384,23 @@ } +#ifdef CONFIG_USB_ALI_M5632 +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * ALi M5632 driver ... does high speed + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info ali_m5632_info = { + .description = "ALi M5632", +}; + + +#endif + + #ifdef CONFIG_USB_AN2720 #define HAVE_HARDWARE @@ -3009,7 +3026,7 @@ return -ENODEV; } xdev = interface_to_usbdev (udev); - interface = &udev->altsetting [udev->act_altsetting]; + interface = udev->cur_altsetting; usb_get_dev (xdev); @@ -3133,6 +3150,13 @@ static const struct usb_device_id products [] = { +#ifdef CONFIG_USB_ALI_M5632 +{ + USB_DEVICE (0x0402, 0x5632), // ALi defaults + .driver_info = (unsigned long) &ali_m5632_info, +}, +#endif + #ifdef CONFIG_USB_AN2720 { USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults @@ -3310,6 +3334,15 @@ | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9032, /* SL-6000 */ + .bInterfaceClass = 0x02, + .bInterfaceSubClass = 0x0a, + .bInterfaceProtocol = 0x00, + .driver_info = (unsigned long) &zaurus_pxa_info, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9050, /* C-860 */ .bInterfaceClass = 0x02, .bInterfaceSubClass = 0x0a, .bInterfaceProtocol = 0x00, diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c --- a/drivers/usb/serial/empeg.c Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/serial/empeg.c Sat Apr 3 19:38:56 2004 @@ -155,7 +155,7 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; - int result = 0;; + int result = 0; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/serial/ftdi_sio.c Sat Apr 3 19:38:55 2004 @@ -286,6 +286,7 @@ static struct usb_device_id id_table_8U232AM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, @@ -358,6 +359,7 @@ static struct usb_device_id id_table_FT232BM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, @@ -451,6 +453,7 @@ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/serial/ftdi_sio.h Sat Apr 3 19:38:55 2004 @@ -30,6 +30,8 @@ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c --- a/drivers/usb/serial/kl5kusb105.c Sat Apr 3 19:38:44 2004 +++ b/drivers/usb/serial/kl5kusb105.c Sat Apr 3 19:38:44 2004 @@ -273,6 +273,7 @@ /* allocate the private data structure */ for (i=0; inum_ports; i++) { + int j; priv = kmalloc(sizeof(struct klsi_105_private), GFP_KERNEL); if (!priv) { @@ -293,10 +294,10 @@ usb_set_serial_port_data(serial->port[i], priv); spin_lock_init (&priv->lock); - for (i=0; iwrite_urb_pool[i] = urb; + priv->write_urb_pool[j] = urb; if (urb == NULL) { err("No more urbs???"); continue; diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c --- a/drivers/usb/serial/mct_u232.c Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/serial/mct_u232.c Sat Apr 3 19:38:45 2004 @@ -511,7 +511,7 @@ /* only do something if we have a bulk out endpoint */ if (!serial->num_bulk_out) - return(0);; + return(0); /* another write is still pending? */ if (port->write_urb->status == -EINPROGRESS) { diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/serial/pl2303.c Sat Apr 3 19:38:43 2004 @@ -403,7 +403,7 @@ { struct termios tmp_termios; struct usb_serial *serial = port->serial; - unsigned char buf[10]; + unsigned char *buf; int result; if (port_paranoia_check (port, __FUNCTION__)) @@ -414,6 +414,10 @@ usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); + buf = kmalloc(10, GFP_KERNEL); + if (buf==NULL) + return -ENOMEM; + #define FISH(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ b, a, c, d, buf, 1, 100); \ @@ -432,6 +436,8 @@ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + + kfree(buf); /* Setup termios */ if (port->tty) { diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/serial/usb-serial.c Sat Apr 3 19:38:43 2004 @@ -391,7 +391,7 @@ struct usb_serial *serial = serial_table[index]; if (serial) - kobject_get (&serial->kobj); + kref_get(&serial->kref); return serial; } @@ -486,7 +486,7 @@ if (retval) { port->open_count = 0; module_put(serial->type->owner); - kobject_put(&serial->kobj); + kref_put(&serial->kref); } } bailout: @@ -518,7 +518,7 @@ } module_put(port->serial->type->owner); - kobject_put(&port->serial->kobj); + kref_put(&port->serial->kref); } static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -748,7 +748,7 @@ begin += length; length = 0; } - kobject_put(&serial->kobj); + kref_put(&serial->kref); } *eof = 1; done: @@ -830,15 +830,15 @@ wake_up_interruptible(&tty->write_wait); } -static void destroy_serial (struct kobject *kobj) +static void destroy_serial(struct kref *kref) { struct usb_serial *serial; struct usb_serial_port *port; int i; - dbg ("%s - %s", __FUNCTION__, kobj->name); + serial = to_usb_serial(kref); - serial = to_usb_serial(kobj); + dbg ("%s - %s", __FUNCTION__, serial->type->name); serial_shutdown (serial); /* return the minor range that this device had */ @@ -886,10 +886,6 @@ kfree (serial); } -static struct kobj_type usb_serial_kobj_type = { - .release = destroy_serial, -}; - static void port_release(struct device *dev) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -930,10 +926,7 @@ serial->interface = interface; serial->vendor = dev->descriptor.idVendor; serial->product = dev->descriptor.idProduct; - - /* initialize the kobject portion of the usb_device */ - kobject_init(&serial->kobj); - serial->kobj.ktype = &usb_serial_kobj_type; + kref_init(&serial->kref, destroy_serial); return serial; } @@ -1006,7 +999,7 @@ /* descriptor matches, let's find the endpoints needed */ /* check out the endpoints */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -1284,7 +1277,7 @@ if (serial) { /* let the last holder of this object * cause it to be cleaned up */ - kobject_put (&serial->kobj); + kref_put(&serial->kref); } dev_info(dev, "device disconnected\n"); } diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h --- a/drivers/usb/serial/usb-serial.h Sat Apr 3 19:38:57 2004 +++ b/drivers/usb/serial/usb-serial.h Sat Apr 3 19:38:57 2004 @@ -55,6 +55,7 @@ #define __LINUX_USB_SERIAL_H #include +#include #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 255 /* loads of devices :) */ @@ -163,10 +164,10 @@ __u16 vendor; __u16 product; struct usb_serial_port * port[MAX_NUM_PORTS]; - struct kobject kobj; + struct kref kref; void * private; }; -#define to_usb_serial(d) container_of(d, struct usb_serial, kobj) +#define to_usb_serial(d) container_of(d, struct usb_serial, kref) #define NUM_DONT_CARE (-1) diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/serial/visor.c Sat Apr 3 19:38:42 2004 @@ -239,6 +239,8 @@ .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), + .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID), @@ -275,6 +277,7 @@ { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { }, /* optional parameter entry */ diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h --- a/drivers/usb/serial/visor.h Sat Apr 3 19:38:55 2004 +++ b/drivers/usb/serial/visor.h Sat Apr 3 19:38:55 2004 @@ -46,6 +46,7 @@ #define SAMSUNG_VENDOR_ID 0x04E8 #define SAMSUNG_SCH_I330_ID 0x8001 +#define SAMSUNG_SPH_I500_ID 0x6601 #define GARMIN_VENDOR_ID 0x091E #define GARMIN_IQUE_3600_ID 0x0004 diff -Nru a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig --- a/drivers/usb/storage/Kconfig Sat Apr 3 19:38:56 2004 +++ b/drivers/usb/storage/Kconfig Sat Apr 3 19:38:56 2004 @@ -1,8 +1,6 @@ # # USB Storage driver configuration # -comment "SCSI support is needed for USB Storage" - depends on USB && SCSI=n config USB_STORAGE tristate "USB Mass Storage support" diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Sat Apr 3 19:38:43 2004 +++ b/drivers/usb/storage/scsiglue.c Sat Apr 3 19:38:43 2004 @@ -64,8 +64,10 @@ return "SCSI emulation for USB Mass Storage devices"; } -static int slave_configure (struct scsi_device *sdev) +static int slave_configure(struct scsi_device *sdev) { + struct us_data *us = (struct us_data *) sdev->host->hostdata[0]; + /* Scatter-gather buffers (all but the last) must have a length * divisible by the bulk maxpacket size. Otherwise a data packet * would end up being short, causing a premature end to the data @@ -75,6 +77,16 @@ * have the desired effect because, except at the beginning and * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); + + /* Devices using Genesys Logic chips cause a lot of trouble for + * high-speed transfers; they die unpredictably when given more + * than 64 KB of data at a time. If we detect such a device, + * reduce the maximum transfer size to 64 KB = 128 sectors. */ + +#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location + if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS && + us->pusb_dev->speed == USB_SPEED_HIGH) + blk_queue_max_sectors(sdev->request_queue, 128); /* this is to satisify the compiler, tho I don't think the * return code is ever checked anywhere. */ diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/storage/transport.c Sat Apr 3 19:38:42 2004 @@ -563,9 +563,9 @@ /* * If we're running the CB transport, which is incapable - * of determining status on its own, we need to auto-sense + * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices - * can signal data-in errors by stalling the bulk-in pipe. + * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && srb->sc_data_direction != SCSI_DATA_READ) { @@ -698,7 +698,11 @@ * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && - (srb->sense_buffer[2] & 0xf) == 0x0) { + /* Filemark 0, ignore EOM, ILI 0, no sense */ + (srb->sense_buffer[2] & 0xaf) == 0 && + /* No ASC or ASCQ */ + srb->sense_buffer[12] == 0 && + srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } @@ -809,15 +813,19 @@ } /* If not UFI, we interpret the data as a result code - * The first byte should always be a 0x0 - * The second byte & 0x0F should be 0x0 for good, otherwise error + * The first byte should always be a 0x0. + * + * Some bogus devices don't follow that rule. They stuff the ASC + * into the first byte -- so if it's non-zero, call it a failure. */ if (us->iobuf[0]) { - US_DEBUGP("CBI IRQ data showed reserved bType %d\n", + US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n", us->iobuf[0]); - return USB_STOR_TRANSPORT_ERROR; + goto Failed; + } + /* The second byte & 0x0F should be 0x0 for good, otherwise error */ switch (us->iobuf[1] & 0x0F) { case 0x00: return USB_STOR_TRANSPORT_GOOD; diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Sat Apr 3 19:38:54 2004 +++ b/drivers/usb/storage/unusual_devs.h Sat Apr 3 19:38:54 2004 @@ -261,6 +261,14 @@ US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), +/* This entry is needed because the device reports Sub=ff */ +UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500, + "Sony", + "DSC-T1", + US_SC_8070, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), + + /* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", @@ -368,7 +376,7 @@ UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, "Lexar", "Jumpshot USB CF Reader", - US_SC_SCSI, US_PR_JUMPSHOT, NULL, + US_SC_DEVICE, US_PR_JUMPSHOT, NULL, US_FL_MODE_XLATE ), #endif @@ -409,6 +417,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Henning Schild */ +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0113, 0x0113, + "EagleTec", + "External Hard Disk", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY ), + /* Reported by Hanno Boeck * Taken from the Lycoris Kernel */ UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, @@ -440,12 +455,6 @@ US_SC_SCSI, US_PR_DEVICE, NULL, 0 ), -UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001, - "Minolta", - "DiMAGE 7i", - US_SC_SCSI, US_PR_DEVICE, NULL, - 0 ), - UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001, "Minolta", "DiMAGE 7Hi", @@ -619,6 +628,9 @@ * are using transport protocol CB. * - They don't like the INQUIRY command. So we must handle this command * of the SCSI layer ourselves. + * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have + * bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB). + * So don't remove the US_PR_CB override! */ UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, "Casio", @@ -649,6 +661,17 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), +/* Entry needed for flags. Moreover, all devices with this ID use + * bulk-only transport, but _some_ falsely report Control/Bulk instead. + * One example is "Trumpion Digital Research MYMP3". + * Submitted by Bjoern Brill + */ +UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, + "Trumpion", + "t33520 USB Flash Card Controller", + US_SC_DEVICE, US_PR_BULK, NULL, + US_FL_MODE_XLATE), + /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, "Trumpion", @@ -688,15 +711,9 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* This entry from in the Debian mailing list */ -UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff, - "Pentax", - "Optio 330GS", - US_SC_8070, US_PR_CB, NULL, - US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ), /* Submitted by Per Winkvist */ -UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, +UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, "Pentax", "Optio S/S4", US_SC_DEVICE, US_PR_DEVICE, NULL, diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Sat Apr 3 19:38:42 2004 +++ b/drivers/usb/storage/usb.c Sat Apr 3 19:38:42 2004 @@ -423,7 +423,7 @@ /* Fill in the device-related fields */ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; - us->ifnum = intf->altsetting->desc.bInterfaceNumber; + us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; /* Store our private data in the interface and increment the * device's reference count */ @@ -452,7 +452,7 @@ { struct usb_device *dev = us->pusb_dev; struct usb_interface_descriptor *idesc = - &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting].desc; + &us->pusb_intf->cur_altsetting->desc; struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; struct usb_device_id *id = &storage_usb_ids[id_index]; @@ -686,7 +686,7 @@ static int get_pipes(struct us_data *us) { struct usb_host_interface *altsetting = - &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting]; + us->pusb_intf->cur_altsetting; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; @@ -877,8 +877,9 @@ int result; US_DEBUGP("USB Mass Storage device detected\n"); - US_DEBUGP("act_altsetting is %d, id_index is %d\n", - intf->act_altsetting, id_index); + US_DEBUGP("altsetting is %d, id_index is %d\n", + intf->cur_altsetting->desc.bAlternateSetting, + id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); @@ -953,8 +954,6 @@ scsi_scan_host(us->host); - printk(KERN_DEBUG - "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_DEBUG "USB Mass Storage device found at %d\n", us->pusb_dev->devnum); return 0; diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Sat Apr 3 19:38:45 2004 +++ b/drivers/usb/storage/usb.h Sat Apr 3 19:38:45 2004 @@ -176,6 +176,5 @@ * single queue element srb for write access */ #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) -#define sg_address(psg) (page_address((psg).page) + (psg).offset) #endif diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig --- a/drivers/video/Kconfig Sat Apr 3 19:38:40 2004 +++ b/drivers/video/Kconfig Sat Apr 3 19:38:40 2004 @@ -76,10 +76,6 @@ hardware found in Acorn RISC PCs and other ARM-based machines. If unsure, say N. -config FB_ANAKIN - bool "Anakin LCD support" - depends on FB && ARM && ARCH_ANAKIN - config FB_CLPS711X bool "CLPS711X LCD support" depends on FB && ARM && ARCH_CLPS711X diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile Sat Apr 3 19:38:41 2004 +++ b/drivers/video/Makefile Sat Apr 3 19:38:41 2004 @@ -28,7 +28,6 @@ obj-$(CONFIG_FB_PLATINUM) += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c --- a/drivers/video/acornfb.c Sat Apr 3 19:38:56 2004 +++ b/drivers/video/acornfb.c Sat Apr 3 19:38:56 2004 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -1254,6 +1256,11 @@ printk("acornfb: freed %dK memory\n", mb_freed); } +static struct device acornfb_device = { + .bus_id = "acornfb", + .coherent_dma_mask = 0xffffffff, +}; + int __init acornfb_init(void) { @@ -1263,6 +1270,8 @@ acornfb_init_fbinfo(); + current_par.dev = &acornfb_device; + if (current_par.montype == -1) current_par.montype = acornfb_detect_monitortype(); @@ -1323,37 +1332,30 @@ #if defined(HAS_VIDC20) if (!current_par.using_vram) { + dma_addr_t handle; + void *base; + /* * RiscPC needs to allocate the DRAM memory * for the framebuffer if we are not using - * VRAM. Archimedes/A5000 machines use a - * fixed address for their framebuffers. + * VRAM. */ - unsigned long page, top, base; - int order = get_order(size); - - base = __get_free_pages(GFP_KERNEL, order); - if (base == 0) { + base = dma_alloc_writecombine(current_par.dev, size, &handle, + GFP_KERNEL); + if (base == NULL) { printk(KERN_ERR "acornfb: unable to allocate screen " "memory\n"); return -ENOMEM; } - top = base + (PAGE_SIZE << order); - - /* Mark the framebuffer pages as reserved so mmap will work. */ - for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE) - SetPageReserved(virt_to_page(page)); - /* Hand back any excess pages that we allocated. */ - for (page = base + size; page < top; page += PAGE_SIZE) - free_page(page); - fb_info.screen_base = (char *)base; - fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base); + fb_info.screen_base = base; + fb_info.fix.smem_start = handle; } #endif #if defined(HAS_VIDC) /* - * Free unused pages + * Archimedes/A5000 machines use a fixed address for their + * framebuffers. Free unused pages */ free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); #endif diff -Nru a/drivers/video/acornfb.h b/drivers/video/acornfb.h --- a/drivers/video/acornfb.h Sat Apr 3 19:38:44 2004 +++ b/drivers/video/acornfb.h Sat Apr 3 19:38:45 2004 @@ -47,6 +47,7 @@ }; struct acornfb_par { + struct device *dev; unsigned long screen_end; unsigned int dram_size; unsigned int vram_half_sam; diff -Nru a/drivers/video/anakinfb.c b/drivers/video/anakinfb.c --- a/drivers/video/anakinfb.c Sat Apr 3 19:38:44 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,102 +0,0 @@ -/* - * linux/drivers/video/anakinfb.c - * - * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 23-Apr-2001 TTC Created - */ - -#include -#include -#include -#include -#include -#include - -#include - -static u32 colreg[17]; -static struct fb_info fb_info; - -static struct fb_var_screeninfo anakinfb_var = { - .xres = 400, - .yres = 234, - .xres_virtual = 400, - .yres_virtual = 234, - .bits_per_pixel = 16, - .red = { 11, 5, 0 }, - .green = { 5, 6, 0 }, - .blue = { 0, 5, 0 }, - .activate = FB_ACTIVATE_NOW, - .height = -1, - .width = -1, - .vmode = FB_VMODE_NONINTERLACED, -}; - -static struct fb_fix_screeninfo anakinfb_fix = { - .id = "AnakinFB", - .smem_start = VGA_START, - .smem_len = VGA_SIZE, - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .line_length = 400*2, - .accel = FB_ACCEL_NONE, -}; - -static int -anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 15) - return 1; - - ((u16 *)(info->pseudo_palette))[regno] = (red & 0xf800) | (green & 0xfc00 >> 5) | (blue & 0xf800 >> 11); - return 0; -} - -static struct fb_ops anakinfb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = anakinfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, -}; - -int __init -anakinfb_init(void) -{ - memset(&fb_info, 0, sizeof(struct fb_info)); - - fb_info.flags = FBINFO_FLAG_DEFAULT; - fb_info.fbops = &anakinfb_ops; - fb_info.var = anakinfb_var; - fb_info.fix = anakinfb_fix; - fb_info.psuedo_palette = colreg; - if (!(request_mem_region(VGA_START, VGA_SIZE, "vga"))) - return -ENOMEM; - if (fb_info.screen_base = ioremap(VGA_START, VGA_SIZE)) { - release_mem_region(VGA_START, VGA_SIZE); - return -EIO; - } - - fb_alloc_cmap(&fb_info.cmap, 16, 0); - - if (register_framebuffer(&fb_info) < 0) { - iounmap(fb_info.screen_base); - release_mem_region(VGA_START, VGA_SIZE); - return -EINVAL; - } - - MOD_INC_USE_COUNT; - return 0; -} - -MODULE_AUTHOR("Tak-Shing Chan "); -MODULE_DESCRIPTION("Anakin framebuffer driver"); -MODULE_SUPPORTED_DEVICE("fb"); diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c --- a/drivers/video/aty/radeon_monitor.c Sat Apr 3 19:38:40 2004 +++ b/drivers/video/aty/radeon_monitor.c Sat Apr 3 19:38:40 2004 @@ -640,21 +640,21 @@ #ifdef CONFIG_PPC_OF /* iBook2's */ if (machine_is_compatible("PowerBook4,3")) { - rinfo->panel_info.ref_divider = rinfo->pll.ref_div;; + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x6; rinfo->panel_info.fbk_divider = 0xad; rinfo->panel_info.use_bios_dividers = 1; } /* Aluminium PowerBook 17" */ if (machine_is_compatible("PowerBook5,3")) { - rinfo->panel_info.ref_divider = rinfo->pll.ref_div;; + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x4; rinfo->panel_info.fbk_divider = 0x80; rinfo->panel_info.use_bios_dividers = 1; } /* iBook G4 */ if (machine_is_compatible("PowerBook6,3")) { - rinfo->panel_info.ref_divider = rinfo->pll.ref_div;; + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; rinfo->panel_info.post_divider = 0x6; rinfo->panel_info.fbk_divider = 0xad; rinfo->panel_info.use_bios_dividers = 1; @@ -757,7 +757,7 @@ && rinfo->mon1_EDID) { struct fb_var_screeninfo var; RTRACE("Parsing EDID data for panel info\n"); - if (parse_edid(rinfo->mon1_EDID, &var) == 0) { + if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { if (var.xres >= rinfo->panel_info.xres && var.yres >= rinfo->panel_info.yres) radeon_var_to_panel_info(rinfo, &var); diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c --- a/drivers/video/console/fbcon.c Sat Apr 3 19:38:45 2004 +++ b/drivers/video/console/fbcon.c Sat Apr 3 19:38:45 2004 @@ -309,94 +309,6 @@ } /* - * drawing helpers - */ -static void putcs_unaligned(struct vc_data *vc, struct fb_info *info, - struct fb_image *image, int count, - const unsigned short *s) -{ - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int width = (vc->vc_font.width + 7) >> 3; - unsigned int cellsize = vc->vc_font.height * width; - unsigned int maxcnt = info->pixmap.size/cellsize; - unsigned int shift_low = 0, mod = vc->vc_font.width % 8; - unsigned int shift_high = 8, size, pitch, cnt, k; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int idx = vc->vc_font.width >> 3; - u8 *src, *dst, *dst0; - - while (count) { - if (count > maxcnt) - cnt = k = maxcnt; - else - cnt = k = count; - - image->width = vc->vc_font.width * cnt; - pitch = ((image->width + 7) >> 3) + scan_align; - pitch &= ~scan_align; - size = pitch * vc->vc_font.height + buf_align; - size &= ~buf_align; - dst0 = fb_get_buffer_offset(info, &info->pixmap, size); - image->data = dst0; - while (k--) { - src = vc->vc_font.data + (scr_readw(s++) & charmask)* - cellsize; - dst = dst0; - fb_move_buf_unaligned(info, &info->pixmap, dst, pitch, src, - idx, image->height, shift_high, - shift_low, mod); - shift_low += mod; - dst0 += (shift_low >= 8) ? width : width - 1; - shift_low &= 7; - shift_high = 8 - shift_low; - } - info->fbops->fb_imageblit(info, image); - image->dx += cnt * vc->vc_font.width; - count -= cnt; - } -} - -static void putcs_aligned(struct vc_data *vc, struct fb_info *info, - struct fb_image *image, int count, - const unsigned short *s) -{ - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int width = vc->vc_font.width >> 3; - unsigned int cellsize = vc->vc_font.height * width; - unsigned int maxcnt = info->pixmap.size/cellsize; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int pitch, cnt, size, k; - u8 *src, *dst, *dst0; - - while (count) { - if (count > maxcnt) - cnt = k = maxcnt; - else - cnt = k = count; - - pitch = width * cnt + scan_align; - pitch &= ~scan_align; - size = pitch * vc->vc_font.height + buf_align; - size &= ~buf_align; - image->width = vc->vc_font.width * cnt; - dst0 = fb_get_buffer_offset(info, &info->pixmap, size); - image->data = dst0; - while (k--) { - src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize; - dst = dst0; - fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, - width, image->height); - dst0 += width; - } - info->fbops->fb_imageblit(info, image); - image->dx += cnt * vc->vc_font.width; - count -= cnt; - } -} - -/* * Accelerated handlers. */ void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, @@ -430,48 +342,23 @@ info->fbops->fb_fillrect(info, ®ion); } -static void accel_putc(struct vc_data *vc, struct fb_info *info, - int c, int ypos, int xpos) +void accel_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx) { unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; unsigned int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; unsigned int scan_align = info->pixmap.scan_align - 1; unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int shift_low = 0, mod = vc->vc_font.width % 8; + unsigned int shift_high = 8, pitch, cnt, size, k; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; - unsigned int size, pitch; - struct fb_image image; - u8 *src, *dst; - - image.dx = xpos * vc->vc_font.width; - image.dy = ypos * vc->vc_font.height; - image.width = vc->vc_font.width; - image.height = vc->vc_font.height; - image.fg_color = attr_fgcol(fgshift, c); - image.bg_color = attr_bgcol(bgshift, c); - image.depth = 1; - - pitch = width + scan_align; - pitch &= ~scan_align; - size = pitch * vc->vc_font.height; - size += buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); - image.data = dst; - src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width; - - fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); - - info->fbops->fb_imageblit(info, &image); -} - -void accel_putcs(struct vc_data *vc, struct fb_info *info, - const unsigned short *s, int count, int yy, int xx) -{ - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + unsigned int idx = vc->vc_font.width >> 3; struct fb_image image; u16 c = scr_readw(s); + u8 *src, *dst, *dst0; image.fg_color = attr_fgcol(fgshift, c); image.bg_color = attr_bgcol(bgshift, c); @@ -480,10 +367,41 @@ image.height = vc->vc_font.height; image.depth = 1; - if (!(vc->vc_font.width & 7)) - putcs_aligned(vc, info, &image, count, s); - else - putcs_unaligned(vc, info, &image, count, s); + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + + image.width = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst0 = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst0; + while (k--) { + src = vc->vc_font.data + (scr_readw(s++) & charmask)*cellsize; + dst = dst0; + + if (mod) { + fb_move_buf_unaligned(info, &info->pixmap, dst, pitch, + src, idx, image.height, shift_high, + shift_low, mod); + shift_low += mod; + dst0 += (shift_low >= 8) ? width : width - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } else { + fb_move_buf_aligned(info, &info->pixmap, dst, pitch, + src, idx, image.height); + dst0 += width; + } + } + info->fbops->fb_imageblit(info, &image); + image.dx += cnt * vc->vc_font.width; + count -= cnt; + } } void accel_clear_margins(struct vc_data *vc, struct fb_info *info, @@ -724,15 +642,13 @@ static void fbcon_set_display(struct vc_data *vc, int init, int logo) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + int nr_rows, nr_cols, old_rows, old_cols, i, charcnt = 256; struct display *p = &fb_display[vc->vc_num]; - int nr_rows, nr_cols; - int old_rows, old_cols; unsigned short *save = NULL, *r, *q; - int i, charcnt = 256; struct font_desc *font; if (vc->vc_num != fg_console || (info->flags & FBINFO_FLAG_MODULE) || - info->fix.type == FB_TYPE_TEXT) + (info->fix.type == FB_TYPE_TEXT)) logo = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ @@ -746,19 +662,17 @@ struct display *q = &fb_display[i]; struct vc_data *tmp = vc_cons[i].d; - if (vc->vc_font.width > 32) { - /* If we are not the first console on this - fb, copy the font from that console */ - vc->vc_font.width = tmp->vc_font.width; - vc->vc_font.height = tmp->vc_font.height; - vc->vc_font.data = p->fontdata = q->fontdata; - p->userfont = q->userfont; - if (p->userfont) { - REFCOUNT(p->fontdata)++; - charcnt = FNTCHARCNT(p->fontdata); - } - con_copy_unimap(vc->vc_num, i); + /* If we are not the first console on this + fb, copy the font from that console */ + vc->vc_font.width = tmp->vc_font.width; + vc->vc_font.height = tmp->vc_font.height; + vc->vc_font.data = p->fontdata = q->fontdata; + p->userfont = q->userfont; + if (p->userfont) { + REFCOUNT(p->fontdata)++; + charcnt = FNTCHARCNT(p->fontdata); } + con_copy_unimap(vc->vc_num, i); } if (!p->fontdata) { @@ -958,11 +872,19 @@ accel_clear(vc, info, real_y(p, sy), sx, height, width); } - static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int width = (vc->vc_font.width + 7) >> 3; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; struct display *p = &fb_display[vc->vc_num]; + unsigned int size, pitch; + struct fb_image image; + u8 *src, *dst; if (!info->fbops->fb_blank && console_blanked) return; @@ -972,7 +894,28 @@ if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; - accel_putc(vc, info, c, real_y(p, ypos), xpos); + image.dx = xpos * vc->vc_font.width; + image.dy = real_y(p, ypos) * vc->vc_font.height; + image.width = vc->vc_font.width; + image.height = vc->vc_font.height; + image.fg_color = attr_fgcol(fgshift, c); + image.bg_color = attr_bgcol(bgshift, c); + image.depth = 1; + + src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width; + + pitch = width + scan_align; + pitch &= ~scan_align; + size = pitch * vc->vc_font.height; + size += buf_align; + size &= ~buf_align; + + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + + fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height); + + info->fbops->fb_imageblit(info, &image); } static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, @@ -2345,6 +2288,7 @@ { if (!num_registered_fb) return -ENODEV; + take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); acquire_console_sem(); if (!fbcon_event_notifier_registered) { @@ -2352,10 +2296,11 @@ fbcon_event_notifier_registered = 1; } release_console_sem(); - return 0; } +#ifdef MODULE + void __exit fb_console_exit(void) { acquire_console_sem(); @@ -2369,6 +2314,8 @@ module_init(fb_console_init); module_exit(fb_console_exit); + +#endif /* * Visible symbols for modules diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c --- a/drivers/video/dnfb.c Sat Apr 3 19:38:55 2004 +++ b/drivers/video/dnfb.c Sat Apr 3 19:38:55 2004 @@ -103,8 +103,6 @@ #define SWAP(A) ((A>>8) | ((A&0xff) <<8)) -static struct fb_info fb_info; - /* frame buffer operations */ static int dnfb_blank(int blank, struct fb_info *info); @@ -119,7 +117,7 @@ .fb_cursor = soft_cursor, }; -struct fb_var_screeninfo dnfb_var __initdata = { +struct fb_var_screeninfo dnfb_var __devinitdata = { .xres 1280, .yres 1024, .xres_virtual 2048, @@ -130,7 +128,7 @@ .vmode FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo dnfb_fix __initdata = { +static struct fb_fix_screeninfo dnfb_fix __devinitdata = { .id "Apollo Mono", .smem_start (FRAME_BUFFER_START + IO_BASE), .smem_len FRAME_BUFFER_LEN, @@ -148,7 +146,7 @@ return 0; } -static +static void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { @@ -224,21 +222,38 @@ out_8(AP_CONTROL_0, NORMAL_MODE); } +/* + * Initialization + */ -unsigned long __init dnfb_init(unsigned long mem_start) +static int __devinit dnfb_probe(struct device *device) { - int err; + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int err = 0; + + info = framebuffer_alloc(0, &dev->dev); + if (!info) + return -ENOMEM; + + info->fbops = &dn_fb_ops; + info->fix = dnfb_fix; + info->var = dnfb_var; + info->screen_base = (u_char *) info->fix.smem_start; + + err = fb_alloc_cmap(&info->cmap, 2, 0); + if (err < 0) { + framebuffer_release(info); + return err; + } - fb_info.fbops = &dn_fb_ops; - fb_info.fix = dnfb_fix; - fb_info.var = dnfb_var; - fb_info.screen_base = (u_char *) fb_info.fix.smem_start; - - fb_alloc_cmap(&fb_info.cmap, 2, 0); - - err = register_framebuffer(&fb_info); - if (err < 0) - panic("unable to register apollo frame buffer\n"); + err = register_framebuffer(info); + if (err < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + return err; + } + dev_set_drvdata(&dev->dev, info); /* now we have registered we can safely setup the hardware */ out_8(AP_CONTROL_3A, RESET_CREG); @@ -249,7 +264,31 @@ out_be16(AP_ROP_1, SWAP(0x3)); printk("apollo frame buffer alive and kicking !\n"); - return mem_start; + return err; +} + +static struct device_driver dnfb_driver = { + .name = "dnfb", + .bus = &platform_bus_type, + .probe = dnfb_probe, +}; + +static struct platform_device dnfb_device = { + .name = "dnfb", +}; + +int __init dnfb_init(void) +{ + int ret; + + ret = driver_register(&dnfb_driver); + + if (!ret) { + ret = platform_device_register(&dnfb_device); + if (ret) + driver_unregister(&dnfb_driver); + } + return ret; } MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c --- a/drivers/video/fbmem.c Sat Apr 3 19:38:31 2004 +++ b/drivers/video/fbmem.c Sat Apr 3 19:38:31 2004 @@ -55,7 +55,6 @@ extern int acornfb_setup(char*); extern int amifb_init(void); extern int amifb_setup(char*); -extern int anakinfb_init(void); extern int atafb_init(void); extern int atafb_setup(char*); extern int macfb_init(void); @@ -180,9 +179,6 @@ #ifdef CONFIG_FB_AMIGA { "amifb", amifb_init, amifb_setup }, #endif -#ifdef CONFIG_FB_ANAKIN - { "anakinfb", anakinfb_init, NULL }, -#endif #ifdef CONFIG_FB_CLPS711X { "clps711xfb", clps711xfb_init, NULL }, #endif @@ -1181,11 +1177,9 @@ #elif defined(__mips__) pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; -#elif defined(__sh__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; #elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; -#elif defined(__ia64__) || defined(__arm__) +#elif defined(__ia64__) || defined(__arm__) || defined(__sh__) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #else #warning What do we have to do here?? diff -Nru a/drivers/video/fbmon.c b/drivers/video/fbmon.c --- a/drivers/video/fbmon.c Sat Apr 3 19:38:55 2004 +++ b/drivers/video/fbmon.c Sat Apr 3 19:38:55 2004 @@ -41,6 +41,15 @@ * EDID parser */ +#undef DEBUG /* define this for verbose EDID parsing output */ + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(fmt,## args) +#else +#define DPRINTK(fmt, args...) +#endif + + const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; @@ -84,203 +93,93 @@ return 1; } -static void parse_vendor_block(unsigned char *block) +static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs) { - unsigned char c[4]; - - c[0] = ((block[0] & 0x7c) >> 2) + '@'; - c[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@'; - c[2] = (block[1] & 0x1f) + '@'; - c[3] = 0; - printk(" Manufacturer: %s ", c); - printk("Model: %x ", block[2] + (block[3] << 8)); - printk("Serial#: %u\n", block[4] + (block[5] << 8) + - (block[6] << 16) + (block[7] << 24)); - printk(" Year: %u Week %u\n", block[9] + 1990, block[8]); -} - -static void parse_dpms_capabilities(unsigned char flags) -{ - printk(" DPMS: Active %s, Suspend %s, Standby %s\n", + specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; + specs->manufacturer[1] = ((block[0] & 0x03) << 3) + + ((block[1] & 0xe0) >> 5) + '@'; + specs->manufacturer[2] = (block[1] & 0x1f) + '@'; + specs->manufacturer[3] = 0; + specs->model = block[2] + (block[3] << 8); + specs->serial = block[4] + (block[5] << 8) + + (block[6] << 16) + (block[7] << 24); + specs->year = block[9] + 1990; + specs->week = block[8]; + DPRINTK(" Manufacturer: %s\n", specs->manufacturer); + DPRINTK(" Model: %x\n", specs->model); + DPRINTK(" Serial#: %u\n", specs->serial); + DPRINTK(" Year: %u Week %u\n", specs->year, specs->week); +} + +static void get_dpms_capabilities(unsigned char flags, + struct fb_monspecs *specs) +{ + specs->dpms = 0; + if (flags & DPMS_ACTIVE_OFF) + specs->dpms |= FB_DPMS_ACTIVE_OFF; + if (flags & DPMS_SUSPEND) + specs->dpms |= FB_DPMS_SUSPEND; + if (flags & DPMS_STANDBY) + specs->dpms |= FB_DPMS_STANDBY; + DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n", (flags & DPMS_ACTIVE_OFF) ? "yes" : "no", (flags & DPMS_SUSPEND) ? "yes" : "no", (flags & DPMS_STANDBY) ? "yes" : "no"); } -static void print_chroma(unsigned char *block) +static void get_chroma(unsigned char *block, struct fb_monspecs *specs) { int tmp; + DPRINTK(" Chroma\n"); /* Chromaticity data */ - printk(" Chromaticity: "); tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2); tmp *= 1000; tmp += 512; - printk("RedX: 0.%03d ", tmp/1024); + specs->chroma.redx = tmp/1024; + DPRINTK(" RedX: 0.%03d ", specs->chroma.redx); tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2); tmp *= 1000; tmp += 512; - printk("RedY: 0.%03d\n", tmp/1024); + specs->chroma.redy = tmp/1024; + DPRINTK("RedY: 0.%03d\n", specs->chroma.redy); tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2); tmp *= 1000; tmp += 512; - printk(" GreenX: 0.%03d ", tmp/1024); + specs->chroma.greenx = tmp/1024; + DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx); tmp = (block[5] & 3) | (block[0xa] << 2); tmp *= 1000; tmp += 512; - printk("GreenY: 0.%03d\n", tmp/1024); + specs->chroma.greeny = tmp/1024; + DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny); tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2); tmp *= 1000; tmp += 512; - printk(" BlueX: 0.%03d ", tmp/1024); + specs->chroma.bluex = tmp/1024; + DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex); tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2); tmp *= 1000; tmp += 512; - printk("BlueY: 0.%03d\n", tmp/1024); + specs->chroma.bluey = tmp/1024; + DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); tmp *= 1000; tmp += 512; - printk(" WhiteX: 0.%03d ", tmp/1024); + specs->chroma.whitex = tmp/1024; + DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex); tmp = (block[6] & 3) | (block[0xe] << 2); tmp *= 1000; tmp += 512; - printk("WhiteY: 0.%03d\n", tmp/1024); -} - -static void parse_display_block(unsigned char *block) -{ - unsigned char c; - - c = (block[0] & 0x80) >> 7; - if (c) - printk(" Digital Display Input"); - else { - printk(" Analog Display Input: Input Voltage - "); - switch ((block[0] & 0x60) >> 5) { - case 0: - printk("0.700V/0.300V"); - break; - case 1: - printk("0.714V/0.286V"); - break; - case 2: - printk("1.000V/0.400V"); - break; - case 3: - printk("0.700V/0.000V"); - break; - default: - printk("unknown"); - } - printk("\n"); - } - c = (block[0] & 0x10) >> 4; - if (c) - printk(" Configurable signal level\n"); - printk(" Sync: "); - c = block[0] & 0x0f; - if (c & 0x10) - printk("Blank to Blank "); - if (c & 0x08) - printk("Separate "); - if (c & 0x04) - printk("Composite "); - if (c & 0x02) - printk("Sync on Green "); - if (c & 0x01) - printk("Serration on "); - printk("\n"); - - printk(" Max H-size in cm: "); - c = block[1]; - if (c) - printk("%d\n", c); - else - printk("variable\n"); - - printk(" Max V-size in cm: "); - c = block[2]; - if (c) - printk("%d\n", c); - else - printk("variable\n"); - - c = block[3]; - printk(" Gamma: "); - printk("%d.%d\n", (c + 100)/100, (c+100) % 100); - - parse_dpms_capabilities(block[4]); - - switch ((block[4] & 0x18) >> 3) { - case 0: - printk(" Monochrome/Grayscale\n"); - break; - case 1: - printk(" RGB Color Display\n"); - break; - case 2: - printk(" Non-RGB Multicolor Display\n"); - break; - default: - printk(" Unknown\n"); - break; - } - - print_chroma(block); - - c = block[4] & 0x7; - if (c & 0x04) - printk(" Default color format is primary\n"); - if (c & 0x02) - printk(" First DETAILED Timing is preferred\n"); - if (c & 0x01) - printk(" Display is GTF capable\n"); -} - -static void parse_std_md_block(unsigned char *block) -{ - unsigned char c; - - c = block[0]; - if (c&0x80) printk(" 720x400@70Hz\n"); - if (c&0x40) printk(" 720x400@88Hz\n"); - if (c&0x20) printk(" 640x480@60Hz\n"); - if (c&0x10) printk(" 640x480@67Hz\n"); - if (c&0x08) printk(" 640x480@72Hz\n"); - if (c&0x04) printk(" 640x480@75Hz\n"); - if (c&0x02) printk(" 800x600@56Hz\n"); - if (c&0x01) printk(" 800x600@60Hz\n"); - - c = block[1]; - if (c&0x80) printk(" 800x600@72Hz\n"); - if (c&0x40) printk(" 800x600@75Hz\n"); - if (c&0x20) printk(" 832x624@75Hz\n"); - if (c&0x10) printk(" 1024x768@87Hz (interlaced)\n"); - if (c&0x08) printk(" 1024x768@60Hz\n"); - if (c&0x04) printk(" 1024x768@70Hz\n"); - if (c&0x02) printk(" 1024x768@75Hz\n"); - if (c&0x01) printk(" 1280x1024@75Hz\n"); - - c = block[2]; - if (c&0x80) printk(" 1152x870@75Hz\n"); - printk(" Manufacturer's mask: %x\n",c&0x7F); -} - - -static int edid_is_timing_block(unsigned char *block) -{ - if ((block[0] != 0x00) || (block[1] != 0x00) || - (block[2] != 0x00) || (block[4] != 0x00)) - return 1; - else - return 0; + specs->chroma.whitey = tmp/1024; + DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); } static int edid_is_serial_block(unsigned char *block) @@ -323,154 +222,6 @@ return 0; } -static int edid_is_color_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfb) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static int edid_is_std_timings_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfa) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static void parse_serial_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" Serial No : %s\n", c); -} - -static void parse_ascii_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" %s\n", c); -} - -static void parse_limits_block(unsigned char *block) -{ - printk(" HorizSync : %d-%d KHz\n", H_MIN_RATE, H_MAX_RATE); - printk(" VertRefresh : %d-%d Hz\n", V_MIN_RATE, V_MAX_RATE); - if (MAX_PIXEL_CLOCK != 10*0xff) - printk(" Max Pixelclock: %d MHz\n", (int) MAX_PIXEL_CLOCK); -} - -static void parse_monitor_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" Monitor Name : %s\n", c); -} - -static void parse_color_block(unsigned char *block) -{ - printk(" Color Point : unimplemented\n"); -} - -static void parse_std_timing_block(unsigned char *block) -{ - int xres, yres = 0, refresh, ratio, err = 1; - - xres = (block[0] + 31) * 8; - if (xres <= 256) - return; - - ratio = (block[1] & 0xc0) >> 6; - switch (ratio) { - case 0: - yres = xres; - break; - case 1: - yres = (xres * 3)/4; - break; - case 2: - yres = (xres * 4)/5; - break; - case 3: - yres = (xres * 9)/16; - break; - } - refresh = (block[1] & 0x3f) + 60; - printk(" %dx%d@%dHz\n", xres, yres, refresh); - err = 0; -} - -static void parse_dst_timing_block(unsigned char *block) -{ - int i; - - block += 5; - for (i = 0; i < 5; i++, block += STD_TIMING_DESCRIPTION_SIZE) - parse_std_timing_block(block); -} - -static void parse_detailed_timing_block(unsigned char *block) -{ - printk(" %d MHz ", PIXEL_CLOCK/1000000); - printk("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, - H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); - printk("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, - V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); - printk("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", - (VSYNC_POSITIVE) ? "+" : "-"); -} - -int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) -{ - int i; - unsigned char *block; - - if (edid == NULL || var == NULL) - return 1; - - if (!(edid_checksum(edid))) - return 1; - - if (!(edid_check_header(edid))) - return 1; - - block = edid + DETAILED_TIMING_DESCRIPTIONS_START; - - for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { - if (edid_is_timing_block(block)) { - var->xres = var->xres_virtual = H_ACTIVE; - var->yres = var->yres_virtual = V_ACTIVE; - var->height = var->width = -1; - var->right_margin = H_SYNC_OFFSET; - var->left_margin = (H_ACTIVE + H_BLANKING) - - (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); - var->upper_margin = V_BLANKING - V_SYNC_OFFSET - - V_SYNC_WIDTH; - var->lower_margin = V_SYNC_OFFSET; - var->hsync_len = H_SYNC_WIDTH; - var->vsync_len = V_SYNC_WIDTH; - var->pixclock = PIXEL_CLOCK; - var->pixclock /= 1000; - var->pixclock = KHZ2PICOS(var->pixclock); - - if (HSYNC_POSITIVE) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (VSYNC_POSITIVE) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - return 0; - } - } - return 1; -} - static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { struct fb_var_screeninfo var; @@ -500,45 +251,82 @@ unsigned char c; c = block[0]; - if (c&0x80) - calc_mode_timings(720, 400, 70, &mode[num++]); - if (c&0x40) - calc_mode_timings(720, 400, 88, &mode[num++]); - if (c&0x20) + if (c&0x80) { + calc_mode_timings(720, 400, 70, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@70Hz\n"); + } + if (c&0x40) { + calc_mode_timings(720, 400, 88, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@88Hz\n"); + } + if (c&0x20) { mode[num++] = vesa_modes[3]; - if (c&0x10) - calc_mode_timings(640, 480, 67, &mode[num++]); - if (c&0x08) + DPRINTK(" 640x480@60Hz\n"); + } + if (c&0x10) { + calc_mode_timings(640, 480, 67, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 640x480@67Hz\n"); + } + if (c&0x08) { mode[num++] = vesa_modes[4]; - if (c&0x04) + DPRINTK(" 640x480@72Hz\n"); + } + if (c&0x04) { mode[num++] = vesa_modes[5]; - if (c&0x02) + DPRINTK(" 640x480@75Hz\n"); + } + if (c&0x02) { mode[num++] = vesa_modes[7]; - if (c&0x01) + DPRINTK(" 800x600@56Hz\n"); + } + if (c&0x01) { mode[num++] = vesa_modes[8]; + DPRINTK(" 800x600@60Hz\n"); + } c = block[1]; - if (c&0x80) + if (c&0x80) { mode[num++] = vesa_modes[9]; - if (c&0x40) + DPRINTK(" 800x600@72Hz\n"); + } + if (c&0x40) { mode[num++] = vesa_modes[10]; - if (c&0x20) - calc_mode_timings(832, 624, 75, &mode[num++]); - if (c&0x10) + DPRINTK(" 800x600@75Hz\n"); + } + if (c&0x20) { + calc_mode_timings(832, 624, 75, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 832x624@75Hz\n"); + } + if (c&0x10) { mode[num++] = vesa_modes[12]; - if (c&0x08) + DPRINTK(" 1024x768@87Hz Interlaced\n"); + } + if (c&0x08) { mode[num++] = vesa_modes[13]; - if (c&0x04) + DPRINTK(" 1024x768@60Hz\n"); + } + if (c&0x04) { mode[num++] = vesa_modes[14]; - if (c&0x02) + DPRINTK(" 1024x768@70Hz\n"); + } + if (c&0x02) { mode[num++] = vesa_modes[15]; - if (c&0x01) + DPRINTK(" 1024x768@75Hz\n"); + } + if (c&0x01) { mode[num++] = vesa_modes[21]; - + DPRINTK(" 1280x1024@75Hz\n"); + } c = block[2]; - if (c&0x80) + if (c&0x80) { mode[num++] = vesa_modes[17]; - + DPRINTK(" 1152x870@75Hz\n"); + } + DPRINTK(" Manufacturer's mask: %x\n",c&0x7F); return num; } @@ -567,17 +355,17 @@ } refresh = (block[1] & 0x3f) + 60; + DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); for (i = 0; i < VESA_MODEDB_SIZE; i++) { if (vesa_modes[i].xres == xres && vesa_modes[i].yres == yres && vesa_modes[i].refresh == refresh) { *mode = vesa_modes[i]; - break; - } else { - calc_mode_timings(xres, yres, refresh, mode); - break; + mode->flag |= FB_MODE_IS_STANDARD; + return 1; } } + calc_mode_timings(xres, yres, refresh, mode); return 1; } @@ -615,6 +403,15 @@ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * (V_ACTIVE + V_BLANKING)); mode->vmode = 0; + mode->flag = FB_MODE_IS_DETAILED; + + DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); + DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, + H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); + DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, + V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); + DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", + (VSYNC_POSITIVE) ? "+" : "-"); } /** @@ -647,21 +444,30 @@ *dbsize = 0; + DPRINTK(" Supported VESA Modes\n"); block = edid + ESTABLISHED_TIMING_1; num += get_est_timing(block, &mode[num]); + DPRINTK(" Standard Timings\n"); block = edid + STD_TIMING_DESCRIPTIONS_START; for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) num += get_std_timing(block, &mode[num]); + DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + int first = 1; + if (block[0] == 0x00 && block[1] == 0x00) { if (block[3] == 0xfa) { num += get_dst_timing(block + 5, &mode[num]); } } else { get_detailed_timing(block, &mode[num]); + if (first) { + mode[num].flag |= FB_MODE_IS_FIRST; + first = 0; + } num++; } } @@ -694,45 +500,24 @@ kfree(modedb); } -/** - * fb_get_monitor_limits - get monitor operating limits - * @edid: EDID data - * @specs: fb_monspecs structure pointer - * - * DESCRIPTION: - * Gets monitor operating limits from EDID data and places them in - * @specs - */ int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) { int i, retval = 1; unsigned char *block; - if (edid == NULL || specs == NULL) - return 1; - - if (!(edid_checksum(edid))) - return 1; - - if (!(edid_check_header(edid))) - return 1; - - memset(specs, 0, sizeof(struct fb_monspecs)); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; - printk("Monitor Operating Limits: "); + DPRINTK(" Monitor Operating Limits: "); for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { if (edid_is_limits_block(block)) { specs->hfmin = H_MIN_RATE * 1000; specs->hfmax = H_MAX_RATE * 1000; specs->vfmin = V_MIN_RATE; specs->vfmax = V_MAX_RATE; - specs->dclkmax = (MAX_PIXEL_CLOCK != 10*0xff) ? - MAX_PIXEL_CLOCK * 1000000 : 0; + specs->dclkmax = MAX_PIXEL_CLOCK * 1000000; specs->gtf = (GTF_SUPPORT) ? 1 : 0; - specs->dpms = edid[DPMS_FLAGS]; retval = 0; - printk("From EDID\n"); + DPRINTK("From EDID\n"); break; } } @@ -744,7 +529,7 @@ modes = fb_create_modedb(edid, &num_modes); if (!modes) { - printk("None Available\n"); + DPRINTK("None Available\n"); return 1; } @@ -767,15 +552,189 @@ if (specs->vfmin == 0 || specs->vfmin > hz) specs->vfmin = hz; } - printk("Extrapolated\n"); + DPRINTK("Extrapolated\n"); fb_destroy_modedb(modes); } - printk(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", specs->hfmin/1000, specs->hfmax/1000, - specs->vfmin, specs->vfmax, specs->dclkmax/1000000); + DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", + specs->hfmin/1000, specs->hfmax/1000, specs->vfmin, + specs->vfmax, specs->dclkmax/1000000); return retval; } -void show_edid(unsigned char *edid) +static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + unsigned char c, *block; + + block = edid + EDID_STRUCT_DISPLAY; + + fb_get_monitor_limits(edid, specs); + + c = (block[0] & 0x80) >> 7; + specs->input = 0; + if (c) { + specs->input |= FB_DISP_DDI; + DPRINTK(" Digital Display Input"); + } else { + DPRINTK(" Analog Display Input: Input Voltage - "); + switch ((block[0] & 0x60) >> 5) { + case 0: + DPRINTK("0.700V/0.300V"); + specs->input |= FB_DISP_ANA_700_300; + break; + case 1: + DPRINTK("0.714V/0.286V"); + specs->input |= FB_DISP_ANA_714_286; + break; + case 2: + DPRINTK("1.000V/0.400V"); + specs->input |= FB_DISP_ANA_1000_400; + break; + case 3: + DPRINTK("0.700V/0.000V"); + specs->input |= FB_DISP_ANA_700_000; + break; + default: + DPRINTK("unknown"); + specs->input |= FB_DISP_UNKNOWN; + } + } + DPRINTK("\n Sync: "); + c = (block[0] & 0x10) >> 4; + if (c) + DPRINTK(" Configurable signal level\n"); + c = block[0] & 0x0f; + specs->signal = 0; + if (c & 0x10) { + DPRINTK("Blank to Blank "); + specs->signal |= FB_SIGNAL_BLANK_BLANK; + } + if (c & 0x08) { + DPRINTK("Separate "); + specs->signal |= FB_SIGNAL_SEPARATE; + } + if (c & 0x04) { + DPRINTK("Composite "); + specs->signal |= FB_SIGNAL_COMPOSITE; + } + if (c & 0x02) { + DPRINTK("Sync on Green "); + specs->signal |= FB_SIGNAL_SYNC_ON_GREEN; + } + if (c & 0x01) { + DPRINTK("Serration on "); + specs->signal |= FB_SIGNAL_SERRATION_ON; + } + DPRINTK("\n"); + specs->max_x = block[1]; + specs->max_y = block[2]; + DPRINTK(" Max H-size in cm: "); + if (specs->max_x) + DPRINTK("%d\n", specs->max_x); + else + DPRINTK("variable\n"); + DPRINTK(" Max V-size in cm: "); + if (specs->max_y) + DPRINTK("%d\n", specs->max_y); + else + DPRINTK("variable\n"); + + c = block[3]; + specs->gamma = c+100; + DPRINTK(" Gamma: "); + DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100); + + get_dpms_capabilities(block[4], specs); + + switch ((block[4] & 0x18) >> 3) { + case 0: + DPRINTK(" Monochrome/Grayscale\n"); + specs->input |= FB_DISP_MONO; + break; + case 1: + DPRINTK(" RGB Color Display\n"); + specs->input |= FB_DISP_RGB; + break; + case 2: + DPRINTK(" Non-RGB Multicolor Display\n"); + specs->input |= FB_DISP_MULTI; + break; + default: + DPRINTK(" Unknown\n"); + specs->input |= FB_DISP_UNKNOWN; + break; + } + + get_chroma(block, specs); + + specs->misc = 0; + c = block[4] & 0x7; + if (c & 0x04) { + DPRINTK(" Default color format is primary\n"); + specs->misc |= FB_MISC_PRIM_COLOR; + } + if (c & 0x02) { + DPRINTK(" First DETAILED Timing is preferred\n"); + specs->misc |= FB_MISC_1ST_DETAIL; + } + if (c & 0x01) { + printk(" Display is GTF capable\n"); + specs->gtf = 1; + } +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] != 0x00) || (block[1] != 0x00) || + (block[2] != 0x00) || (block[4] != 0x00)) + return 1; + else + return 0; +} + +int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) +{ + int i; + unsigned char *block; + + if (edid == NULL || var == NULL) + return 1; + + if (!(edid_checksum(edid))) + return 1; + + if (!(edid_check_header(edid))) + return 1; + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_timing_block(block)) { + var->xres = var->xres_virtual = H_ACTIVE; + var->yres = var->yres_virtual = V_ACTIVE; + var->height = var->width = -1; + var->right_margin = H_SYNC_OFFSET; + var->left_margin = (H_ACTIVE + H_BLANKING) - + (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); + var->upper_margin = V_BLANKING - V_SYNC_OFFSET - + V_SYNC_WIDTH; + var->lower_margin = V_SYNC_OFFSET; + var->hsync_len = H_SYNC_WIDTH; + var->vsync_len = V_SYNC_WIDTH; + var->pixclock = PIXEL_CLOCK; + var->pixclock /= 1000; + var->pixclock = KHZ2PICOS(var->pixclock); + + if (HSYNC_POSITIVE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (VSYNC_POSITIVE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + return 0; + } + } + return 1; +} + +void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { unsigned char *block; int i; @@ -788,83 +747,52 @@ if (!(edid_check_header(edid))) return; - printk("========================================\n"); - printk("Display Information (EDID)\n"); - printk("========================================\n"); - printk(" EDID Version %d.%d\n", (int) edid[EDID_STRUCT_VERSION], - (int) edid[EDID_STRUCT_REVISION]); - parse_vendor_block(edid + ID_MANUFACTURER_NAME); + memset(specs, 0, sizeof(struct fb_monspecs)); - printk(" Display Characteristics:\n"); - parse_display_block(edid + EDID_STRUCT_DISPLAY); + specs->version = edid[EDID_STRUCT_VERSION]; + specs->revision = edid[EDID_STRUCT_REVISION]; - printk(" Standard Timings\n"); - block = edid + STD_TIMING_DESCRIPTIONS_START; - for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) - parse_std_timing_block(block); + DPRINTK("========================================\n"); + DPRINTK("Display Information (EDID)\n"); + DPRINTK("========================================\n"); + DPRINTK(" EDID Version %d.%d\n", (int) specs->version, + (int) specs->revision); - printk(" Supported VESA Modes\n"); - parse_std_md_block(edid + ESTABLISHED_TIMING_1); + parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs); - printk(" Detailed Monitor Information\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { if (edid_is_serial_block(block)) { - parse_serial_block(block); + copy_string(block, specs->serial_no); + DPRINTK(" Serial Number: %s\n", specs->serial_no); } else if (edid_is_ascii_block(block)) { - parse_ascii_block(block); - } else if (edid_is_limits_block(block)) { - parse_limits_block(block); + copy_string(block, specs->ascii); + DPRINTK(" ASCII Block: %s\n", specs->ascii); } else if (edid_is_monitor_block(block)) { - parse_monitor_block(block); - } else if (edid_is_color_block(block)) { - parse_color_block(block); - } else if (edid_is_std_timings_block(block)) { - parse_dst_timing_block(block); - } else if (edid_is_timing_block(block)) { - parse_detailed_timing_block(block); + copy_string(block, specs->monitor); + DPRINTK(" Monitor Name: %s\n", specs->monitor); } } - printk("========================================\n"); -} -#ifdef CONFIG_PPC_OF -char *get_EDID_from_OF(struct pci_dev *pdev) -{ - static char *propnames[] = - { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL }; - unsigned char *pedid = NULL; - struct device_node *dp; - int i; + DPRINTK(" Display Characteristics:\n"); + get_monspecs(edid, specs); - if (pdev == NULL) - return NULL; - dp = pci_device_to_OF_node(pdev); - while (dp != NULL) { - for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) get_property(dp, propnames[i], NULL); - if (pedid != NULL) - return pedid; - } - dp = dp->child; - } - show_edid(pedid); - return pedid; + specs->modedb = fb_create_modedb(edid, &specs->modedb_len); + DPRINTK("========================================\n"); } -#endif -#ifdef CONFIG_X86 -char *get_EDID_from_BIOS(void *dummy) +char *get_EDID_from_firmware(struct device *dev) { - unsigned char *pedid = edid_info.dummy; - + unsigned char *pedid = NULL; + +#if defined(CONFIG_EDID_FIRMWARE) && defined(CONFIG_X86) + pedid = edid_info.dummy; if (!pedid) return NULL; - show_edid(pedid); - return pedid; -} #endif + return pedid; +} /* * VESA Generalized Timing Formula (GTF) @@ -971,7 +899,7 @@ */ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) { - u32 duty_cycle, h_period, hblank;; + u32 duty_cycle, h_period, hblank; dclk /= 1000; h_period = 100 - C_VAL; @@ -1179,7 +1107,7 @@ * REQUIRES: * A valid info->monspecs. */ -int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info) +int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) { u32 hfreq, vfreq, htotal, vtotal, pixclock; u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; @@ -1228,16 +1156,12 @@ -EINVAL : 0; } -EXPORT_SYMBOL(parse_edid); -EXPORT_SYMBOL(show_edid); -#ifdef CONFIG_X86 -EXPORT_SYMBOL(get_EDID_from_BIOS); -#endif -#ifdef CONFIG_PPC_OF -EXPORT_SYMBOL(get_EDID_from_OF); -#endif -EXPORT_SYMBOL(fb_get_monitor_limits); +EXPORT_SYMBOL(fb_parse_edid); +EXPORT_SYMBOL(fb_edid_to_monspecs); +EXPORT_SYMBOL(get_EDID_from_firmware); + EXPORT_SYMBOL(fb_get_mode); EXPORT_SYMBOL(fb_validate_mode); EXPORT_SYMBOL(fb_create_modedb); EXPORT_SYMBOL(fb_destroy_modedb); +EXPORT_SYMBOL(fb_get_monitor_limits); diff -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c --- a/drivers/video/fm2fb.c Sat Apr 3 19:38:43 2004 +++ b/drivers/video/fm2fb.c Sat Apr 3 19:38:43 2004 @@ -49,7 +49,7 @@ * not assembled with memory for the alpha channel. In this * case it could be possible to add the frame buffer into the * normal memory pool. - * + * * At relative address 0x1ffff8 of the frame buffers base address * there exists a control register with the number of * four control bits. They have the following meaning: @@ -64,7 +64,7 @@ * is not very much information about the FrameMaster II in * the world so I add these information for completeness. * - * JP1 interlace selection (1-2 non interlaced/2-3 interlaced) + * JP1 interlace selection (1-2 non interlaced/2-3 interlaced) * JP2 wait state creation (leave as is!) * JP3 wait state creation (leave as is!) * JP4 modulate composite sync on green output (1-2 composite @@ -127,12 +127,7 @@ static volatile unsigned char *fm2fb_reg; -#define arraysize(x) (sizeof(x)/sizeof(*(x))) - -static struct fb_info fb_info; -static u32 pseudo_palette[17]; - -static struct fb_fix_screeninfo fb_fix __initdata = { +static struct fb_fix_screeninfo fb_fix __devinitdata = { .smem_len = FRAMEMASTER_REG, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, @@ -141,12 +136,12 @@ .accel = FB_ACCEL_NONE, }; -static int fm2fb_mode __initdata = -1; +static int fm2fb_mode __devinitdata = -1; #define FM2FB_MODE_PAL 0 #define FM2FB_MODE_NTSC 1 -static struct fb_var_screeninfo fb_var_modes[] __initdata = { +static struct fb_var_screeninfo fb_var_modes[] __devinitdata = { { /* 768 x 576, 32 bpp (PAL) */ 768, 576, 768, 576, 0, 0, 32, 0, @@ -161,11 +156,10 @@ 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0 } }; - + /* * Interface used by the world */ -int fm2fb_init(void); static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); @@ -174,7 +168,7 @@ static struct fb_ops fm2fb_ops = { .owner = THIS_MODULE, .fb_setcolreg = fm2fb_setcolreg, - .fb_blank = fm2fb_blank, + .fb_blank = fm2fb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -202,7 +196,7 @@ static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { - if (regno > 15) + if (regno > info->cmap.len) return 1; red >>= 8; green >>= 8; @@ -216,66 +210,91 @@ * Initialisation */ -int __init fm2fb_init(void) +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id); + +static struct zorro_device_id fm2fb_devices[] __devinitdata = { + { ZORRO_PROD_BSC_FRAMEMASTER_II }, + { ZORRO_PROD_HELFRICH_RAINBOW_II }, + { 0 } +}; + +static struct zorro_driver fm2fb_driver = { + .name = "fm2fb", + .id_table = fm2fb_devices, + .probe = fm2fb_probe, +}; + +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id) { - struct zorro_dev *z = NULL; + struct fb_info *info; unsigned long *ptr; int is_fm; int x, y; - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II) - is_fm = 1; - else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II) - is_fm = 0; - else - continue; - - if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb")) - continue; - - /* assigning memory to kernel space */ - fb_fix.smem_start = z->resource.start; - fb_info.screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE); - fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG; - fm2fb_reg = (unsigned char *)(fb_info.screen_base+FRAMEMASTER_REG); - - strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); - - /* make EBU color bars on display */ - ptr = (unsigned long *)fb_fix.smem_start; - for (y = 0; y < 576; y++) { - for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */ - for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */ - for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */ - for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */ - for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */ - for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */ - for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */ - for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */ - } - fm2fb_blank(0, NULL); - - if (fm2fb_mode == -1) - fm2fb_mode = FM2FB_MODE_PAL; - - fb_info.fbops = &fm2fb_ops; - fb_info.var = fb_var_modes[fm2fb_mode]; - fb_info.screen_base = (char *)fb_fix.smem_start; - fb_info.pseudo_palette = pseudo_palette; - fb_info.fix = fb_fix; - fb_info.flags = FBINFO_FLAG_DEFAULT; + is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II; + + if (!zorro_request_device(z,"fm2fb")) + return -ENXIO; - /* The below fields will go away !!!! */ - fb_alloc_cmap(&fb_info.cmap, 16, 0); + info = framebuffer_alloc(256 * sizeof(u32), &z->dev); + if (!info) { + zorro_release_device(z); + return -ENOMEM; + } - if (register_framebuffer(&fb_info) < 0) - return -EINVAL; + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + framebuffer_release(info); + zorro_release_device(z); + return -ENOMEM; + } - printk("fb%d: %s frame buffer device\n", fb_info.node, fb_fix.id); - return 0; + /* assigning memory to kernel space */ + fb_fix.smem_start = zorro_resource_start(z); + info->screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE); + fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG; + fm2fb_reg = (unsigned char *)(info->screen_base+FRAMEMASTER_REG); + + strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); + + /* make EBU color bars on display */ + ptr = (unsigned long *)fb_fix.smem_start; + for (y = 0; y < 576; y++) { + for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */ + for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */ + for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */ + for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */ + for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */ + for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */ + } + fm2fb_blank(0, info); + + if (fm2fb_mode == -1) + fm2fb_mode = FM2FB_MODE_PAL; + + info->fbops = &fm2fb_ops; + info->var = fb_var_modes[fm2fb_mode]; + info->pseudo_palette = info->par; + info->par = NULL; + info->fix = fb_fix; + info->flags = FBINFO_FLAG_DEFAULT; + + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + zorro_release_device(z); + return -EINVAL; } - return -ENXIO; + printk("fb%d: %s frame buffer device\n", info->node, fb_fix.id); + return 0; +} + +int __init fm2fb_init(void) +{ + return zorro_register_driver(&fm2fb_driver); } int __init fm2fb_setup(char *options) @@ -285,7 +304,7 @@ if (!options || !*options) return 0; - while ((this_opt = strsep(&options, ",")) != NULL) { + while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "pal", 3)) fm2fb_mode = FM2FB_MODE_PAL; else if (!strncmp(this_opt, "ntsc", 4)) diff -Nru a/drivers/video/hitfb.c b/drivers/video/hitfb.c --- a/drivers/video/hitfb.c Sat Apr 3 19:38:41 2004 +++ b/drivers/video/hitfb.c Sat Apr 3 19:38:41 2004 @@ -1,16 +1,16 @@ /* - * $Id: hitfb.c,v 1.10 2004/02/01 19:46:04 lethal Exp $ + * $Id: hitfb.c,v 1.12 2004/03/16 00:07:51 lethal Exp $ * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device * (C) 1999 Mihai Spatar * (C) 2000 YAEGASHI Takeshi * (C) 2003, 2004 Paul Mundt - * (C) 2003 Andriy Skulysh + * (C) 2003, 2004 Andriy Skulysh * * 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 @@ -30,139 +30,137 @@ #include #include +#ifdef MACH_HP600 +#include +#include +#endif + +#define WIDTH 640 + static struct fb_var_screeninfo hitfb_var __initdata = { .activate = FB_ACTIVATE_NOW, .height = -1, - .width = -1, - .vmode = FB_VMODE_NONINTERLACED, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, }; static struct fb_fix_screeninfo hitfb_fix __initdata = { - .id = "Hitachi HD64461", - .type = FB_TYPE_PACKED_PIXELS, - .ypanstep = 8, - .accel = FB_ACCEL_NONE, + .id = "Hitachi HD64461", + .type = FB_TYPE_PACKED_PIXELS, + .ypanstep = 8, + .accel = FB_ACCEL_NONE, }; static u32 pseudo_palette[16]; static struct fb_info fb_info; - -#define WIDTH 640 - -static void hitfb_set_base(u32 offset) +static inline void hitfb_accel_wait(void) { - fb_writew(offset>>10,HD64461_LCDCBAR); -} - -static inline void hitfb_accel_wait() -{ - while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) - ; + while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ; } static inline void hitfb_accel_start(int truecolor) { if (truecolor) { - fb_writew(6,HD64461_GRCFGR); + fb_writew(6, HD64461_GRCFGR); } else { - fb_writew(7,HD64461_GRCFGR); + fb_writew(7, HD64461_GRCFGR); } } -static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, - u16 width, u16 height) +static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, + u16 width, u16 height) { - u32 saddr=WIDTH*dy+dx; + u32 saddr = WIDTH * dy + dx; if (truecolor) saddr <<= 1; - - fb_writew(width,HD64461_BBTDWR); - fb_writew(height,HD64461_BBTDHR); - - fb_writew(saddr&0xffff,HD64461_BBTDSARL); - fb_writew(saddr>>16,HD64461_BBTDSARH); -} - -static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, - u16 width, u16 height, u16 color) -{ - hitfb_accel_set_dest(truecolor,dx,dy,width,height); - - fb_writew(0x00f0,HD64461_BBTROPR); - fb_writew(16,HD64461_BBTMDR); - fb_writew(color,HD64461_GRSCR); - hitfb_accel_start(truecolor); + fb_writew(width, HD64461_BBTDWR); + fb_writew(height, HD64461_BBTDHR); + + fb_writew(saddr & 0xffff, HD64461_BBTDSARL); + fb_writew(saddr >> 16, HD64461_BBTDSARH); + } -static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u16 dy, - u16 width, u16 height, u16 rop, u32 mask_addr) +static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, + u16 width, u16 height, u16 color) { - u32 saddr,daddr; - u32 maddr=0; - fb_writew(rop,HD64461_BBTROPR); - - if((sy>3)+1)*(height+1)-1; - } else { - maddr=(((width>>4)+1)*(height+1)-1)*2; - } + fb_writew(0x00f0, HD64461_BBTROPR); + fb_writew(16, HD64461_BBTMDR); + fb_writew(color, HD64461_GRSCR); - fb_writew((1<<5)|1,HD64461_BBTMDR); - } else { - fb_writew(1,HD64461_BBTMDR); - } + hitfb_accel_start(truecolor); +} + +static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, + u16 dy, u16 width, u16 height, u16 rop, + u32 mask_addr) +{ + u32 saddr, daddr; + u32 maddr = 0; + + fb_writew(rop, HD64461_BBTROPR); + if ((sy < dy) || ((sy == dy) && (sx <= dx))) { + saddr = WIDTH * (sy + height) + sx + width; + daddr = WIDTH * (dy + height) + dx + width; + if (mask_addr) { + if (truecolor) + maddr = ((width >> 3) + 1) * (height + 1) - 1; + else + maddr = + (((width >> 4) + 1) * (height + 1) - 1) * 2; + + fb_writew((1 << 5) | 1, HD64461_BBTMDR); + } else + fb_writew(1, HD64461_BBTMDR); } else { - saddr=WIDTH*sy+sx; - daddr=WIDTH*dy+dx; + saddr = WIDTH * sy + sx; + daddr = WIDTH * dy + dx; if (mask_addr) { - fb_writew((1<<5),HD64461_BBTMDR); + fb_writew((1 << 5), HD64461_BBTMDR); } else { - outw(0,HD64461_BBTMDR); + fb_writew(0, HD64461_BBTMDR); } } - if (truecolor) { - saddr<<=1; - daddr<<=1; + saddr <<= 1; + daddr <<= 1; } - - fb_writew(width,HD64461_BBTDWR); - fb_writew(height,HD64461_BBTDHR); - fb_writew(saddr&0xffff,HD64461_BBTSSARL); - fb_writew(saddr>>16,HD64461_BBTSSARH); - fb_writew(daddr&0xffff,HD64461_BBTDSARL); - fb_writew(daddr>>16,HD64461_BBTDSARH); - + fb_writew(width, HD64461_BBTDWR); + fb_writew(height, HD64461_BBTDHR); + fb_writew(saddr & 0xffff, HD64461_BBTSSARL); + fb_writew(saddr >> 16, HD64461_BBTSSARH); + fb_writew(daddr & 0xffff, HD64461_BBTDSARL); + fb_writew(daddr >> 16, HD64461_BBTDSARH); if (mask_addr) { - maddr+=mask_addr; - fb_writew(maddr&0xffff,HD64461_BBTMARL); - fb_writew(maddr>>16,HD64461_BBTMARH); + maddr += mask_addr; + fb_writew(maddr & 0xffff, HD64461_BBTMARL); + fb_writew(maddr >> 16, HD64461_BBTMARH); } hitfb_accel_start(truecolor); } static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { - if (rect->rop != ROP_COPY) { - cfb_fillrect(p,rect); - } else { - fb_writew(0x00f0,HD64461_BBTROPR); - fb_writew(16,HD64461_BBTMDR); - - if (p->var.bits_per_pixel==16) { - fb_writew( ((u32*)(p->pseudo_palette))[rect->color] , HD64461_GRSCR ); - hitfb_accel_set_dest(1,rect->dx,rect->dy,rect->width,rect->height); + if (rect->rop != ROP_COPY) + cfb_fillrect(p, rect); + else { + fb_writew(0x00f0, HD64461_BBTROPR); + fb_writew(16, HD64461_BBTMDR); + + if (p->var.bits_per_pixel == 16) { + fb_writew(((u32 *) (p->pseudo_palette))[rect->color], + HD64461_GRSCR); + hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width, + rect->height); hitfb_accel_start(1); } else { fb_writew(rect->color, HD64461_GRSCR); - hitfb_accel_set_dest(0,rect->dx,rect->dy,rect->width,rect->height); + hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width, + rect->height); hitfb_accel_start(0); } hitfb_accel_wait(); @@ -171,23 +169,24 @@ static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { - hitfb_accel_bitblt(p->var.bits_per_pixel==16,area->sx,area->sy, - area->dx,area->dy,area->width,area->height,0x00cc,0); + hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, + area->dx, area->dy, area->width, area->height, + 0x00cc, 0); hitfb_accel_wait(); } static int hitfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - int xoffset = var->xoffset; - int yoffset = var->yoffset; + int xoffset = var->xoffset; + int yoffset = var->yoffset; - if (xoffset!=0) + if (xoffset != 0) return -EINVAL; - hitfb_set_base(yoffset*2*640); + fb_writew(yoffset, HD64461_LCDCBAR); - return 0; + return 0; } int hitfb_blank(int blank_mode, struct fb_info *info) @@ -195,6 +194,12 @@ unsigned short v; if (blank_mode) { +#ifdef MACH_HP600 + sh_dac_disable(DAC_LCD_BRIGHTNESS); + v = fb_readw(HD64461_GPBDR); + v |= HD64461_GPBDR_LCDOFF; + fb_writew(v, HD64461_GPBDR); +#endif v = fb_readw(HD64461_LDR1); v &= ~HD64461_LDR1_DON; fb_writew(v, HD64461_LDR1); @@ -210,7 +215,12 @@ v = fb_readw(HD64461_STBCR); v &= ~HD64461_STBCR_SLCDST; fb_writew(v, HD64461_STBCR); - +#ifdef MACH_HP600 + sh_dac_enable(DAC_LCD_BRIGHTNESS); + v = fb_readw(HD64461_GPBDR); + v &= ~HD64461_GPBDR_LCDOFF; + fb_writew(v, HD64461_GPBDR); +#endif v = fb_readw(HD64461_LDR1); v |= HD64461_LDR1_DON; fb_writew(v, HD64461_LDR1); @@ -219,36 +229,71 @@ v &= ~HD64461_LCDCCR_MOFF; fb_writew(v, HD64461_LCDCCR); } - return 0; } static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) + unsigned blue, unsigned transp, struct fb_info *info) { if (regno >= info->cmap.len) return 1; - + switch (info->var.bits_per_pixel) { - case 8: - fb_writew(regno << 8, HD64461_CPTWAR); - fb_writew(red >> 10, HD64461_CPTWDR); - fb_writew(green >> 10, HD64461_CPTWDR); - fb_writew(blue >> 10, HD64461_CPTWDR); - break; - case 16: - ((u32*)(info->pseudo_palette))[regno] = - ((red & 0xf800) ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; + case 8: + fb_writew(regno << 8, HD64461_CPTWAR); + fb_writew(red >> 10, HD64461_CPTWDR); + fb_writew(green >> 10, HD64461_CPTWDR); + fb_writew(blue >> 10, HD64461_CPTWDR); + break; + case 16: + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; } return 0; } -static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static struct fb_ops hitfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = hitfb_setcolreg, + .fb_blank = hitfb_blank, + .fb_pan_display = hitfb_pan_display, + .fb_fillrect = hitfb_fillrect, + .fb_copyarea = hitfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +int __init hitfb_init(void) { + unsigned short lcdclor, ldr3, ldvndr; + int size; + + hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; + hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024; + + lcdclor = fb_readw(HD64461_LCDCLOR); + ldvndr = fb_readw(HD64461_LDVNDR); + ldr3 = fb_readw(HD64461_LDR3); + + switch (ldr3 & 15) { + default: + case 4: + hitfb_var.bits_per_pixel = 8; + hitfb_var.xres = lcdclor; + break; + case 8: + hitfb_var.bits_per_pixel = 16; + hitfb_var.xres = lcdclor / 2; + break; + } + hitfb_fix.line_length = lcdclor; + hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + hitfb_var.yres = ldvndr + 1; + hitfb_var.xres_virtual = hitfb_var.xres; + hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor; switch (hitfb_var.bits_per_pixel) { case 8: hitfb_var.red.offset = 0; @@ -260,7 +305,7 @@ hitfb_var.transp.offset = 0; hitfb_var.transp.length = 0; break; - case 16: /* RGB 565 */ + case 16: /* RGB 565 */ hitfb_var.red.offset = 11; hitfb_var.red.length = 5; hitfb_var.green.offset = 5; @@ -272,70 +317,22 @@ break; } - return 0; -} + fb_info.fbops = &hitfb_ops; + fb_info.var = hitfb_var; + fb_info.fix = hitfb_fix; + fb_info.pseudo_palette = pseudo_palette; + fb_info.flags = FBINFO_FLAG_DEFAULT; -static struct fb_ops hitfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = hitfb_check_var, - .fb_set_par = hitfb_set_par, - .fb_setcolreg = hitfb_setcolreg, - .fb_pan_display = hitfb_pan_display, - .fb_blank = hitfb_blank, - .fb_fillrect = hitfb_fillrect, - .fb_copyarea = hitfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, -}; - -int __init hitfb_init(void) -{ - unsigned short lcdclor, ldr3, ldvndr; - int size; - - hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; - hitfb_fix.smem_len = (MACH_HP690) ? 1024*1024 : 512*1024; - - lcdclor = inw(HD64461_LCDCLOR); - ldvndr = inw(HD64461_LDVNDR); - ldr3 = inw(HD64461_LDR3); - - switch (ldr3&15) { - default: - case 4: - hitfb_var.bits_per_pixel = 8; - hitfb_var.xres = lcdclor; - break; - case 8: - hitfb_var.bits_per_pixel = 16; - hitfb_var.xres = lcdclor/2; - break; - } - - /* XXX: Most of this should go into hitfb_set_par().. --PFM. */ - hitfb_fix.line_length = lcdclor; - hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - hitfb_var.yres = ldvndr+1; - hitfb_var.xres_virtual = hitfb_var.xres; - hitfb_var.yres_virtual = hitfb_fix.smem_len/lcdclor; - - fb_info.fbops = &hitfb_ops; - fb_info.var = hitfb_var; - fb_info.fix = hitfb_fix; - fb_info.pseudo_palette = pseudo_palette; - fb_info.flags = FBINFO_FLAG_DEFAULT; - - fb_info.screen_base = (void *) hitfb_fix.smem_start; + fb_info.screen_base = (void *)hitfb_fix.smem_start; size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16; - fb_alloc_cmap(&fb_info.cmap, size, 0); + fb_alloc_cmap(&fb_info.cmap, size, 0); if (register_framebuffer(&fb_info) < 0) return -EINVAL; - + printk(KERN_INFO "fb%d: %s frame buffer device\n", - fb_info.node, fb_info.fix.id); + fb_info.node, fb_info.fix.id); return 0; } @@ -350,4 +347,3 @@ #endif MODULE_LICENSE("GPL"); - diff -Nru a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c --- a/drivers/video/i810/i810_main.c Sat Apr 3 19:38:42 2004 +++ b/drivers/video/i810/i810_main.c Sat Apr 3 19:38:42 2004 @@ -281,7 +281,7 @@ static void i810_load_2d(struct i810fb_par *par) { u32 tmp; - u8 tmp8, *mmio = par->mmio_start_virtual;; + u8 tmp8, *mmio = par->mmio_start_virtual; i810_writel(FW_BLC, mmio, par->watermark); tmp = i810_readl(PIXCONF, mmio); diff -Nru a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h --- a/drivers/video/i810/i810_main.h Sat Apr 3 19:38:44 2004 +++ b/drivers/video/i810/i810_main.h Sat Apr 3 19:38:44 2004 @@ -84,7 +84,7 @@ extern void i810fb_load_front (u32 offset, struct fb_info *info); /* Conditionals */ -#if defined(__i386__) +#ifdef CONFIG_X86 inline void flush_cache(void) { asm volatile ("wbinvd":::"memory"); diff -Nru a/drivers/video/modedb.c b/drivers/video/modedb.c --- a/drivers/video/modedb.c Sat Apr 3 19:38:43 2004 +++ b/drivers/video/modedb.c Sat Apr 3 19:38:43 2004 @@ -39,7 +39,7 @@ #define DEFAULT_MODEDB_INDEX 0 -static const struct fb_videomode modedb[] __initdata = { +static const struct fb_videomode modedb[] = { { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, @@ -130,11 +130,11 @@ 0, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ - "LCD_XGA_75", 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, + NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ - "LCD_XGA_60", 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, + NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ @@ -254,109 +254,128 @@ const struct fb_videomode vesa_modes[] = { /* 0 640x350-85 VESA */ { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, - FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA}, /* 1 640x400-85 VESA */ { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 2 720x400-85 VESA */ { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 3 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 4 640x480-72 VESA */ { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 5 640x480-75 VESA */ { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 6 640x480-85 VESA */ { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 7 800x600-56 VESA */ { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 8 800x600-60 VESA */ { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 9 800x600-72 VESA */ { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 10 800x600-75 VESA */ { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 11 800x600-85 VESA */ { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 12 1024x768i-43 VESA */ { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, /* 13 1024x768-60 VESA */ { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 14 1024x768-70 VESA */ { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 15 1024x768-75 VESA */ { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 16 1024x768-85 VESA */ { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 17 1152x864-75 VESA */ { NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 18 1280x960-60 VESA */ { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 19 1280x960-85 VESA */ { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 20 1280x1024-60 VESA */ { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 21 1280x1024-75 VESA */ { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 22 1280x1024-85 VESA */ { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 23 1600x1200-60 VESA */ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 24 1600x1200-65 VESA */ { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 25 1600x1200-70 VESA */ { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 26 1600x1200-75 VESA */ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 27 1600x1200-85 VESA */ { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 28 1792x1344-60 VESA */ { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 29 1792x1344-75 VESA */ { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 30 1856x1392-60 VESA */ { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 31 1856x1392-75 VESA */ { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 32 1920x1440-60 VESA */ { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 33 1920x1440-75 VESA */ { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; -static int __init my_atoi(const char *name) +static int my_atoi(const char *name) { int val = 0; @@ -447,11 +466,11 @@ * */ -int __init fb_find_mode(struct fb_var_screeninfo *var, - struct fb_info *info, const char *mode_option, - const struct fb_videomode *db, unsigned int dbsize, - const struct fb_videomode *default_mode, - unsigned int default_bpp) +int fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp) { int i, j; @@ -535,5 +554,5 @@ return 0; } -EXPORT_SYMBOL(__fb_try_mode); EXPORT_SYMBOL(vesa_modes); +EXPORT_SYMBOL(fb_find_mode); diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c --- a/drivers/video/pm2fb.c Sat Apr 3 19:38:56 2004 +++ b/drivers/video/pm2fb.c Sat Apr 3 19:38:57 2004 @@ -434,14 +434,14 @@ pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); } -static void set_aperture(struct pm2fb_par* p) +static void set_aperture(struct pm2fb_par* p, u32 depth) { WAIT_FIFO(p, 4); #ifdef __LITTLE_ENDIAN pm2_WR(p, PM2R_APERTURE_ONE, 0); pm2_WR(p, PM2R_APERTURE_TWO, 0); #else - switch (p->depth) { + switch (depth) { case 8: case 24: pm2_WR(p, PM2R_APERTURE_ONE, 0); @@ -744,7 +744,7 @@ pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); } - set_aperture(par); + set_aperture(par, depth); DEFRW(); WAIT_FIFO(par, 19); diff -Nru a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c --- a/drivers/video/pvr2fb.c Sat Apr 3 19:38:41 2004 +++ b/drivers/video/pvr2fb.c Sat Apr 3 19:38:41 2004 @@ -338,6 +338,7 @@ ((blue & 0xf800) >> 11); pvr2fb_set_pal_entry(par, regno, tmp); + ((u16*)(info->pseudo_palette))[regno] = tmp; break; case 24: /* RGB 888 */ red >>= 8; green >>= 8; blue >>= 8; @@ -348,6 +349,7 @@ tmp = (transp << 24) | (red << 16) | (green << 8) | blue; pvr2fb_set_pal_entry(par, regno, tmp); + ((u32*)(info->pseudo_palette))[regno] = tmp; break; default: pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); diff -Nru a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c --- a/drivers/video/sa1100fb.c Sat Apr 3 19:38:42 2004 +++ b/drivers/video/sa1100fb.c Sat Apr 3 19:38:42 2004 @@ -1595,12 +1595,18 @@ * of the framebuffer. */ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); - fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, - &fbi->map_dma, PTE_BUFFERABLE); + fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); if (fbi->map_cpu) { fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; fbi->screen_dma = fbi->map_dma + PAGE_SIZE; + /* + * FIXME: this is actually the wrong thing to place in + * smem_start. But fbdev suffers from the problem that + * it needs an API which doesn't exist (in this case, + * dma_writecombine_mmap) + */ fbi->fb.fix.smem_start = fbi->screen_dma; } @@ -1613,7 +1619,7 @@ }; -static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) +static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) { struct sa1100fb_mach_info *inf; struct sa1100fb_info *fbi; @@ -1624,6 +1630,7 @@ return NULL; memset(fbi, 0, sizeof(struct sa1100fb_info)); + fbi->dev = dev; strcpy(fbi->fb.fix.id, SA1100_NAME); @@ -1703,7 +1710,7 @@ if (!request_mem_region(0xb0100000, 0x10000, "LCD")) return -EBUSY; - fbi = sa1100fb_init_fbinfo(); + fbi = sa1100fb_init_fbinfo(dev); ret = -ENOMEM; if (!fbi) goto failed; diff -Nru a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h --- a/drivers/video/sa1100fb.h Sat Apr 3 19:38:45 2004 +++ b/drivers/video/sa1100fb.h Sat Apr 3 19:38:45 2004 @@ -63,6 +63,7 @@ struct sa1100fb_info { struct fb_info fb; + struct device *dev; struct sa1100fb_rgb *rgb[NR_RGB]; u_int max_bpp; diff -Nru a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c --- a/drivers/video/sis/init301.c Sat Apr 3 19:38:41 2004 +++ b/drivers/video/sis/init301.c Sat Apr 3 19:38:41 2004 @@ -2313,7 +2313,7 @@ #ifdef SIS315H - unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);; + unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); /* The following is nearly unpreditable and varies from machine * to machine. Especially the 301DH seems to be a real trouble diff -Nru a/drivers/video/tgafb.c b/drivers/video/tgafb.c --- a/drivers/video/tgafb.c Sat Apr 3 19:38:54 2004 +++ b/drivers/video/tgafb.c Sat Apr 3 19:38:54 2004 @@ -25,6 +25,7 @@ #include #include #include