From 20046205f06c05e08f9399d17648ed52e0121f91 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:26:46 -0500 Subject: [PATCH] Import 2.3.13pre7 --- CREDITS | 14 +- Documentation/Configure.help | 417 ++-- Documentation/devices.tex | 20 + Documentation/devices.txt | 14 + Documentation/modules.txt | 2 +- Documentation/mtrr.txt | 4 +- Documentation/nbd.txt | 4 +- Documentation/networking/00-INDEX | 8 +- Documentation/networking/Configurable | 8 +- Documentation/networking/DLINK.txt | 10 +- Documentation/networking/dgrs.txt | 2 +- Documentation/scsi-generic.txt | 495 ++-- Documentation/sx.txt | 289 +++ arch/i386/defconfig | 6 +- arch/i386/kernel/bios32.c | 2 +- arch/i386/kernel/process.c | 31 + drivers/block/Config.in | 5 +- drivers/block/MAKEDEV-IDE45 | 99 - drivers/block/MAKEDEV-IDE67 | 99 - drivers/block/Makefile | 120 +- drivers/block/aec6210.c | 11 +- drivers/block/cpqarray.c | 4 +- drivers/block/genhd.c | 4 + drivers/block/hpt34x.c | 75 +- drivers/block/hpt366.c | 493 ++++ drivers/block/ide-cd.c | 247 +- drivers/block/ide-cd.h | 78 +- drivers/block/ide-dma.c | 37 +- drivers/block/ide-floppy.c | 27 +- drivers/block/ide-pci.c | 170 +- drivers/block/ide-probe.c | 8 +- drivers/block/ide-tape.c | 4 +- drivers/block/ide.c | 96 +- drivers/block/ll_rw_blk.c | 2 + drivers/block/pdc202xx.c | 27 +- drivers/block/piix.c | 34 +- drivers/block/sis5513.c | 418 ++++ drivers/block/sl82c105.c | 111 + drivers/block/trm290.c | 2 +- drivers/block/via82c586.c | 144 +- drivers/cdrom/cdrom.c | 973 ++++++-- drivers/char/Config.in | 1 + drivers/char/Makefile | 8 + drivers/char/bttv.c | 5 +- drivers/char/buz.c | 4 +- drivers/char/epca.c | 42 +- drivers/char/generic_serial.c | 1074 +++++++++ drivers/char/generic_serial.h | 101 + drivers/char/isicom.c | 268 ++- drivers/char/keyboard.c | 3 +- drivers/char/lp.c | 17 +- drivers/char/mem.c | 2 +- drivers/char/nvram.c | 2 +- drivers/char/pcxx.c | 4 +- drivers/char/planb.c | 2 +- drivers/char/pty.c | 2 +- drivers/char/riscom8.c | 8 +- drivers/char/rocket.c | 18 +- drivers/char/rtc.c | 2 +- drivers/char/softdog.c | 2 +- drivers/char/stallion.c | 8 +- drivers/char/sx.c | 2684 ++++++++++++++++++++++ drivers/char/sx.h | 180 ++ drivers/char/sxboards.h | 181 ++ drivers/char/sxwindow.h | 393 ++++ drivers/char/tty_io.c | 9 +- drivers/char/vc_screen.c | 2 +- drivers/dio/dio.c | 4 +- drivers/fc4/soc.c | 2 +- drivers/fc4/socal.c | 2 +- drivers/i2o/Makefile | 2 +- drivers/i2o/i2o_block.c | 73 +- drivers/i2o/i2o_config.c | 3 +- drivers/i2o/i2o_core.c | 211 +- drivers/i2o/i2o_lan.c | 273 ++- drivers/i2o/i2o_lan.h | 4 +- drivers/i2o/i2o_pci.c | 131 +- drivers/i2o/i2o_proc.c | 8 +- drivers/i2o/i2o_scsi.c | 3 +- drivers/net/3c59x.c | 13 +- drivers/net/Space.c | 8 + drivers/net/acenic.c | 4 +- drivers/net/de4x5.c | 4 +- drivers/net/dgrs.c | 20 +- drivers/net/epic100.c | 2 +- drivers/net/hamradio/Config.in | 2 + drivers/net/hamradio/Makefile | 8 + drivers/net/hamradio/yam.c | 1297 +++++++++++ drivers/net/hamradio/yam1200.h | 343 +++ drivers/net/hamradio/yam9600.h | 343 +++ drivers/net/hp100.c | 2 +- drivers/net/irda/toshoboe.c | 4 +- drivers/net/lance.c | 2 +- drivers/net/ne.c | 2 +- drivers/net/ne2k-pci.c | 2 +- drivers/net/net_init.c | 6 + drivers/net/ni5010.c | 6 +- drivers/net/ni52.c | 4 +- drivers/net/ni65.c | 4 +- drivers/net/pcnet32.c | 5 +- drivers/net/plip.c | 8 +- drivers/net/ptifddi.c | 2 +- drivers/net/rcpci45.c | 3 +- drivers/net/rrunner.c | 4 +- drivers/net/rtl8139.c | 2 +- drivers/net/sdla.c | 4 +- drivers/net/shaper.c | 49 +- drivers/net/sk_g16.c | 6 +- drivers/net/skeleton.c | 6 +- drivers/net/sktr.c | 12 +- drivers/net/slhc.c | 3 +- drivers/net/slip.c | 2 +- drivers/net/smc-mca.c | 3 +- drivers/net/smc-ultra.c | 4 +- drivers/net/smc-ultra32.c | 4 +- drivers/net/smc9194.c | 8 +- drivers/net/sunbmac.c | 4 +- drivers/net/sunhme.c | 4 +- drivers/net/sunlance.c | 8 +- drivers/net/sunqe.c | 2 +- drivers/net/tlan.c | 2 +- drivers/net/tulip.c | 19 +- drivers/net/via-rhine.c | 4 +- drivers/net/wd.c | 4 +- drivers/net/x25_asy.c | 2 +- drivers/net/yellowfin.c | 15 +- drivers/net/znet.c | 2 +- drivers/parport/parport_amiga.c | 2 - drivers/parport/parport_arc.c | 2 - drivers/parport/parport_atari.c | 2 - drivers/parport/parport_mfc3.c | 2 - drivers/parport/parport_pc.c | 9 +- drivers/parport/share.c | 2 - drivers/pci/names.c | 262 +-- drivers/pci/pci.c | 9 +- drivers/pci/proc.c | 275 ++- drivers/pci/quirks.c | 8 +- drivers/scsi/advansys.c | 4 +- drivers/scsi/eata_dma.c | 4 +- drivers/scsi/eata_pio.c | 4 +- drivers/scsi/pci2000.c | 8 +- drivers/scsi/pci2220i.c | 14 +- drivers/scsi/qlogicfc.c | 2 +- drivers/scsi/qlogicisp.c | 2 +- drivers/scsi/scsi.c | 233 +- drivers/scsi/sr.c | 101 +- drivers/scsi/sr_ioctl.c | 179 +- drivers/scsi/wd7000.c | 11 +- drivers/sound/cmpci.c | 2 +- drivers/sound/es1370.c | 6 +- drivers/sound/es1371.c | 6 +- drivers/sound/lowlevel/awe_compat-fbsd.h | 1 + drivers/sound/sonicvibes.c | 22 +- drivers/usb/ohci-hcd.c | 4 +- drivers/usb/ohci.c | 4 +- drivers/usb/uhci.c | 11 +- drivers/video/atyfb.c | 248 +- include/asm-alpha/ide.h | 4 +- include/asm-i386/ide.h | 6 +- include/asm-mips/ide.h | 4 +- include/asm-ppc/ide.h | 4 +- include/asm-sparc64/ide.h | 4 +- include/linux/capability.h | 6 +- include/linux/cdrom.h | 194 ++ include/linux/i2o.h | 61 +- include/linux/ide.h | 11 +- include/linux/if_shaper.h | 3 +- include/linux/isicom.h | 22 +- include/linux/major.h | 2 + include/linux/parport.h | 6 +- include/linux/parport_pc.h | 6 +- include/linux/pci.h | 23 +- include/linux/sysctl.h | 16 +- include/linux/sysrq.h | 2 + include/linux/yam.h | 82 + init/main.c | 4 + kernel/capability.c | 2 + kernel/ksyms.c | 3 + kernel/sysctl.c | 43 +- scripts/MAKEDEV.ide | 12 + scripts/mkdep.c | 2 +- 181 files changed, 12072 insertions(+), 2508 deletions(-) create mode 100644 Documentation/sx.txt delete mode 100644 drivers/block/MAKEDEV-IDE45 delete mode 100644 drivers/block/MAKEDEV-IDE67 create mode 100644 drivers/block/hpt366.c create mode 100644 drivers/block/sis5513.c create mode 100644 drivers/char/generic_serial.c create mode 100644 drivers/char/generic_serial.h create mode 100644 drivers/char/sx.c create mode 100644 drivers/char/sx.h create mode 100644 drivers/char/sxboards.h create mode 100644 drivers/char/sxwindow.h create mode 100644 drivers/net/hamradio/yam.c create mode 100644 drivers/net/hamradio/yam1200.h create mode 100644 drivers/net/hamradio/yam9600.h create mode 100644 include/linux/yam.h diff --git a/CREDITS b/CREDITS index f39a8b956f79..5d64bac7c68f 100644 --- a/CREDITS +++ b/CREDITS @@ -814,12 +814,15 @@ D: Selection mechanism N: Andre Hedrick E: hedrick@astro.dyer.vanderbilt.edu +D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver -D: Aladdin 1533/1543(C) chipset IDE -D: HighPoint HPT343/5 chipset IDE -D: PIIX chipset IDE -D: Promise Ultra/33 chipset IDE -D: Promise Ultra/66 chipset IDE +D: Aladdin 1533/1543(C) chipset +D: Active-Chipset maddness.......... +D: HighPoint HPT343/5 Ultra/33 & HPT366 Ultra/66 chipsets +D: Intel PIIX chipset +D: Promise PDC20246/20247 & PDC20262 chipsets +D: SiS5513 Ultra/66/33 chipsets +D: VIA 82C586/596/686 chipsets S: Nashville, TN S: USA @@ -2287,6 +2290,7 @@ N: Roger E. Wolff E: R.E.Wolff@BitWizard.nl D: Written kmalloc/kfree D: Written Specialix IO8+ driver +D: Written Specialix SX driver S: van Bronckhorststraat 12 S: 2612 XV Delft S: The Netherlands diff --git a/Documentation/Configure.help b/Documentation/Configure.help index e8aaa312d80d..baafb60292f4 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -546,6 +546,20 @@ CONFIG_BLK_DEV_IDEDMA_PCI It is safe to say Y to this question. +Use DMA by default when available +CONFIG_IDEDMA_PCI_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! + + It is normally safe to answer Y to this question unless your + motherboard uses a VIA VP2 chipset, in which case you should say N. + Good-Bad DMA Model-Firmware (EXPERIMENTAL) IDEDMA_NEW_DRIVE_LISTINGS This test compares both the model and firmware revision for buggy drives @@ -555,23 +569,6 @@ IDEDMA_NEW_DRIVE_LISTINGS If in doubt, say N. -Generic ATA-66 support (DANGEROUS) -CONFIG_IDEDMA_ULTRA_66 - This allows for your Generic IDE control to attempt support for - using ATA-66 or UDMA-66 transfer modes 3/4. If you are not sure what you - are attempting, "DO NOT" even think about this option, unless your - mainboard's chipset is verified. Do not complain to anyone if you - do not know what you are doing and are just playing around. - This option has no known success cases to date. - - Say N, or beware......... - -Winbond SL82c105 support -CONFIG_BLK_DEV_SL82C105 - If you have a Winbond SL82c105 IDE controller, say Y here to enable - special configuration for this chip. This is common on various CHRP - motherboards, but could be used elsewhere. If in doubt, say Y. - Boot off-board chipsets first support CONFIG_BLK_DEV_OFFBOARD Normally, IDE controllers built into the motherboard (on-board @@ -590,96 +587,31 @@ CONFIG_BLK_DEV_OFFBOARD If in doubt, say N. -Use DMA by default when available -CONFIG_IDEDMA_PCI_AUTO - Prior to kernel version 2.1.112, Linux used to automatically use - DMA for IDE drives and chipsets which support it. Due to concerns - about a couple of cases where buggy hardware may have caused damage, - the default is now to NOT use DMA automatically. To revert to the - previous behaviour, say Y to this question. - - If you suspect your hardware is at all flakey, say N here. - Do NOT email the IDE kernel people regarding this issue! - - It is normally safe to answer Y to this question unless your - motherboard uses a VIA VP2 chipset, in which case you should say N. - -Other IDE chipset support -CONFIG_IDE_CHIPSETS - Say Y here if you want to include enhanced support for various IDE - interface chipsets used on motherboards and add-on cards. You can - then pick your particular IDE chip from among the following options. - This enhanced support may be necessary for Linux to be able to - access the 3rd/4th drives in some systems. It may also enable - setting of higher speed I/O rates to improve system performance with - these chipsets. Most of these also require special kernel boot - parameters to actually turn on the support at runtime; you can find - a list of these in the file Documentation/ide.txt. - - People with SCSI-only systems can say N here. - -Generic 4 drives/port support -CONFIG_BLK_DEV_4DRIVES - Certain older chipsets, including the Tekram 690CD, use a single set - of I/O ports at 0x1f0 to control up to four drives, instead of the - customary two drives per port. Support for this can be enabled at - runtime using the "ide0=four" kernel boot parameter if you say Y - here. - -DTC-2278 support -CONFIG_BLK_DEV_DTC2278 - This driver is enabled at runtime using the "ide0=dtc2278" kernel - boot parameter. It enables support for the secondary IDE interface - of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the Documentation/ide.txt and drivers/block/dtc2278.c - files for more info. +AEC6210 chipset support +CONFIG_BLK_DEV_AEC6210 + This driver adds up to 4 more eide devices sharing a single interrupt. + This add-on card is a bootable PCI UDMA controller. In order to get this + card to initialize correctly in some cases, you should include this driver. -Holtek HT6560B support -CONFIG_BLK_DEV_HT6560B - This driver is enabled at runtime using the "ide0=ht6560b" kernel - boot parameter. It enables support for the secondary IDE interface - of the Holtek card, and permits faster I/O speeds to be set as well. - See the Documentation/ide.txt and drivers/block/ht6560b.c files for - more info. + This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless. -PROMISE DC4030 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC4030 - This driver provides support for the secondary IDE interface and - cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver - is known to incur timeouts/retries during heavy I/O to drives - attached to the secondary interface. CDROM and TAPE devices are not - supported yet. This driver is enabled at runtime using the - "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt - and drivers/block/pdc4030.c files for more info. + Please read the comments at the top of drivers/block/aec6210.c -PS/2 ESDI hard disk support -CONFIG_BLK_DEV_PS2 - Say Y here if you have a PS/2 machine with a MCA bus and an ESDI - hard disk. - - 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 Documentation/modules.txt. The module will be - called ps2esdi.o. +ALI M15x3 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_ALI15X3 + This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C + onboard chipsets. It also tests for Simplex mode and enables + normal dual channel support. -Tekram TRM290 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_TRM290 - This driver adds support for bus master DMA transfers - using the Tekram TRM290 PCI IDE chip. Volunteers are - needed for further tweaking and development. - Please read the comments at the top of drivers/block/trm290.c. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. -OPTi 82C621 enhanced support (EXPERIMENTAL) -CONFIG_BLK_DEV_OPTI621 - This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of drivers/block/opti621.c. + Please read the comments at the top of drivers/block/alim15x3.c -NS87415 support (EXPERIMENTAL) -CONFIG_BLK_DEV_NS87415 - This driver adds detection and support for the NS87415 chip - (used in SPARC64, among others). + If unsure, say N. - Please read the comments at the top of drivers/block/ns87415.c. +CMD646 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_CMD646 + Say Y here if you have an IDE controller like this. CY82C693 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_CY82C693 @@ -691,37 +623,67 @@ CONFIG_BLK_DEV_CY82C693 Please read the comments at the top of drivers/block/cy82c693.c -VIA82C586 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_VIA82C586 - This allows you to to configure your chipset for a better use while - running (U)DMA: it will allow you to enable efficiently the second - channel dma usage, as it is may not be set by BIOS. It allows you to - run a kernel command line at boot time in order to set fifo config. - If no command line is provided, it will try to set fifo configuration - at its best. It will allow you to get a proc/ide/via display - (while running a "cat") provided you enabled "proc" support and - set DISPLAY_APOLLO_TIMINGS in via82c586.c +HPT34X chipset support +CONFIG_BLK_DEV_HPT34X + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT343 chipset in its current form is a non-bootable or + HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers. + This driver requires dynamic tuning of the chipset during the ide-probe + at boot. It is reported to support DVD II drives, by the manufacturer. + + Please read the comments at the top of drivers/block/hpt34x.c +HPT34X DMA support (DANGEROUS) +CONFIG_BLK_DEV_HPT34X_DMA This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. - If unsure, say N. + Please read the comments at the top of drivers/block/hpt34x.c -CMD646 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_CMD646 - Say Y here if you have an IDE controller like this. +HPT366 chipset support +CONFIG_BLK_DEV_HPT366 + This is an Ultra DMA chipset for ATA-66. + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT366 chipset in its current form is a non-bootable. + This driver requires dynamic tuning of the chipset during the ide-probe + at boot. It is reported to support DVD II drives, by the manufacturer. -ALI M15x3 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_ALI15X3 - This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C - onboard chipsets. It also tests for Simplex mode and enables - normal dual channel support. + Please read the comments at the top of drivers/block/hpt366.c - This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. +Intel PIIXn chipsets support +CONFIG_BLK_DEV_PIIX + This driver adds PIO mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly tune + PIO 0-4 mode settings, this allows dynamic tuning of the chipset + via the standard end-user tool 'hdparm'. - Please read the comments at the top of drivers/block/alim15x3.c + Please read the comments at the top of drivers/block/piix.c If unsure, say N. +PIIXn Tuning support (EXPERIMENTAL) +CONFIG_BLK_DEV_PIIX_TUNING + This driver extension adds DMA mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly setup + the device/adapter combination and speed limits, It has become a necessity + to back/forward speed devices as needed. + + Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2 + if the BIOS can to perform this task at INIT. + + If unsure, say N. + +NS87415 support (EXPERIMENTAL) +CONFIG_BLK_DEV_NS87415 + This driver adds detection and support for the NS87415 chip + (used in SPARC64, among others). + + Please read the comments at the top of drivers/block/ns87415.c. + +OPTi 82C621 enhanced support (EXPERIMENTAL) +CONFIG_BLK_DEV_OPTI621 + This is a driver for the OPTi 82C621 EIDE controller. + Please read the comments at the top of drivers/block/opti621.c. + PROMISE PDC20246/PDC20262 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246. @@ -764,54 +726,127 @@ PDC202XX_FORCE_MASTER_MODE Say N. -AEC6210 chipset support -CONFIG_BLK_DEV_AEC6210 - This driver adds up to 4 more eide devices sharing a single interrupt. - This add-on card is a bootable PCI UDMA controller. In order to get this - card to initialize correctly in some cases, you should include this driver. +SiS5513 chipset support +CONFIG_BLK_DEV_SIS5513 + This driver ensures (U)DMA support for SIS5513 chipset based mainboards. + SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all other DMA mode 2 + limited chipsets are unsupported to date. - This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. - Please read the comments at the top of drivers/block/aec6210.c + Please read the comments at the top of drivers/block/sis5513.c -Intel PIIXn chipsets support -CONFIG_BLK_DEV_PIIX - This driver adds PIO mode setting and tuning for all PIIX IDE - controllers by Intel. Since the BIOS can sometimes improperly tune - PIO 0-4 mode settings, this allows dynamic tuning of the chipset - via the standard end-user tool 'hdparm'. +Winbond SL82c105 support +CONFIG_BLK_DEV_SL82C105 + If you have a Winbond SL82c105 IDE controller, say Y here to enable + special configuration for this chip. This is common on various CHRP + motherboards, but could be used elsewhere. If in doubt, say Y. - Please read the comments at the top of drivers/block/piix.c +Tekram TRM290 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_TRM290 + This driver adds support for bus master DMA transfers + using the Tekram TRM290 PCI IDE chip. Volunteers are + needed for further tweaking and development. + Please read the comments at the top of drivers/block/trm290.c. + +VIA82C586 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_VIA82C586 + This allows you to to configure your chipset for a better use while + running (U)DMA: it will allow you to enable efficiently the second + channel dma usage, as it is may not be set by BIOS. It allows you to + run a kernel command line at boot time in order to set fifo config. + If no command line is provided, it will try to set fifo configuration + at its best. It will allow you to get a proc/ide/via display + (while running a "cat") provided you enabled "proc" support and + set DISPLAY_APOLLO_TIMINGS in via82c586.c + + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. If unsure, say N. -PIIXn Tuning support (EXPERIMENTAL) -CONFIG_BLK_DEV_PIIX_TUNING - This driver extension adds DMA mode setting and tuning for all PIIX IDE - controllers by Intel. Since the BIOS can sometimes improperly setup - the device/adapter combination and speed limits, It has become a necessity - to back/forward speed devices as needed. +Support for PowerMac IDE devices (must also enable IDE) +CONFIG_BLK_DEV_IDE_PMAC + No help for CONFIG_BLK_DEV_IDE_PMAC - Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2 - if the BIOS can to perform this task at INIT. +PowerMac IDE DMA support +CONFIG_BLK_DEV_IDEDMA_PMAC + No help for CONFIG_BLK_DEV_IDEDMA_PMAC - If unsure, say N. +Use DMA by default +CONFIG_IDEDMA_PMAC_AUTO + No help for CONFIG_IDEDMA_PMAC_AUTO -HPT34X chipset support -CONFIG_BLK_DEV_HPT34X - This driver adds up to 4 more EIDE devices sharing a single - interrupt. The HPT343 chipset in its current form is a non-bootable or - HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers. - This driver requires dynamic tuning of the chipset during the ide-probe - at boot. It is reported to support DVD II drives, by the manufacturer. +ICS IDE interface support +CONFIG_BLK_DEV_IDE_ICSIDE + No help for CONFIG_BLK_DEV_IDE_ICSIDE - Please read the comments at the top of drivers/block/hpt343.c +ICS DMA support +CONFIG_BLK_DEV_IDEDMA_ICS + No help for CONFIG_BLK_DEV_IDEDMA_ICS -HPT34X DMA support (DANGEROUS) -CONFIG_BLK_DEV_HPT34X_DMA - This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. +Use ICS DMA by default +CONFIG_IDEDMA_ICS_AUTO + No help for CONFIG_IDEDMA_ICS_AUTO + +RapIDE interface support +CONFIG_BLK_DEV_IDE_RAPIDE + No help for CONFIG_BLK_DEV_IDE_RAPIDE + +Other IDE chipset support +CONFIG_IDE_CHIPSETS + Say Y here if you want to include enhanced support for various IDE + interface chipsets used on motherboards and add-on cards. You can + then pick your particular IDE chip from among the following options. + This enhanced support may be necessary for Linux to be able to + access the 3rd/4th drives in some systems. It may also enable + setting of higher speed I/O rates to improve system performance with + these chipsets. Most of these also require special kernel boot + parameters to actually turn on the support at runtime; you can find + a list of these in the file Documentation/ide.txt. + + People with SCSI-only systems can say N here. + +Generic 4 drives/port support +CONFIG_BLK_DEV_4DRIVES + Certain older chipsets, including the Tekram 690CD, use a single set + of I/O ports at 0x1f0 to control up to four drives, instead of the + customary two drives per port. Support for this can be enabled at + runtime using the "ide0=four" kernel boot parameter if you say Y + here. + +ALI M14xx support +CONFIG_BLK_DEV_ALI14XX + This driver is enabled at runtime using the "ide0=ali14xx" kernel + boot parameter. It enables support for the secondary IDE interface + of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster + I/O speeds to be set as well. See the files Documentation/ide.txt + and drivers/block/ali14xx.c for more info. - Please read the comments at the top of drivers/block/hpt343.c +DTC-2278 support +CONFIG_BLK_DEV_DTC2278 + This driver is enabled at runtime using the "ide0=dtc2278" kernel + boot parameter. It enables support for the secondary IDE interface + of the DTC-2278 card, and permits faster I/O speeds to be set as + well. See the Documentation/ide.txt and drivers/block/dtc2278.c + files for more info. + +Holtek HT6560B support +CONFIG_BLK_DEV_HT6560B + This driver is enabled at runtime using the "ide0=ht6560b" kernel + boot parameter. It enables support for the secondary IDE interface + of the Holtek card, and permits faster I/O speeds to be set as well. + See the Documentation/ide.txt and drivers/block/ht6560b.c files for + more info. + +PROMISE DC4030 support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC4030 + This driver provides support for the secondary IDE interface and + cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver + is known to incur timeouts/retries during heavy I/O to drives + attached to the secondary interface. CDROM and TAPE devices are not + supported yet. This driver is enabled at runtime using the + "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt + and drivers/block/pdc4030.c files for more info. QDI QD6580 support CONFIG_BLK_DEV_QD6580 @@ -828,14 +863,6 @@ CONFIG_BLK_DEV_UMC8672 See the files Documentation/ide.txt and drivers/block/umc8672.c for more info. -ALI M14xx support -CONFIG_BLK_DEV_ALI14XX - This driver is enabled at runtime using the "ide0=ali14xx" kernel - boot parameter. It enables support for the secondary IDE interface - of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster - I/O speeds to be set as well. See the files Documentation/ide.txt - and drivers/block/ali14xx.c for more info. - Amiga builtin Gayle IDE interface support CONFIG_BLK_DEV_GAYLE This is the IDE driver for the builtin IDE interface on some Amiga @@ -845,21 +872,6 @@ CONFIG_BLK_DEV_GAYLE (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. -Falcon IDE interface support -CONFIG_BLK_DEV_FALCON_IDE - This is the IDE driver for the builtin IDE interface on the Atari Falcon. - Say Y if you have a Falcon and want to use IDE devices (hard disks, - CD-ROM drives, etc.) that are connected to the builtin IDE interface. - -Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) -CONFIG_BLK_DEV_BUDDHA - This is the IDE driver for the IDE interfaces on the Buddha and - Catweasel expansion boards. It supports up to two interfaces on the - Buddha and three on the Catweasel. - Say Y if you have a Buddha or Catweasel expansion board and want to - use IDE devices (hard disks, CD-ROM drives, etc.) that are connected - to one of its IDE interfaces. - Amiga IDE Doubler support (EXPERIMENTAL) CONFIG_BLK_DEV_IDEDOUBLER This driver provides support for the so called `IDE doublers' (made by @@ -872,17 +884,20 @@ CONFIG_BLK_DEV_IDEDOUBLER Say Y if you have an IDE doubler. The driver is enabled at kernel runtime using the "ide=doubler" kernel boot parameter. -Support for PowerMac IDE devices (must also enable IDE) -CONFIG_BLK_DEV_IDE_PMAC - No help for CONFIG_BLK_DEV_IDE_PMAC - -PowerMac IDE DMA support -CONFIG_BLK_DEV_IDEDMA_PMAC - No help for CONFIG_BLK_DEV_IDEDMA_PMAC +Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) +CONFIG_BLK_DEV_BUDDHA + This is the IDE driver for the IDE interfaces on the Buddha and + Catweasel expansion boards. It supports up to two interfaces on the + Buddha and three on the Catweasel. + Say Y if you have a Buddha or Catweasel expansion board and want to + use IDE devices (hard disks, CD-ROM drives, etc.) that are connected + to one of its IDE interfaces. -Use DMA by default -CONFIG_IDEDMA_PMAC_AUTO - No help for CONFIG_IDEDMA_PMAC_AUTO +Falcon IDE interface support +CONFIG_BLK_DEV_FALCON_IDE + This is the IDE driver for the builtin IDE interface on the Atari Falcon. + Say Y if you have a Falcon and want to use IDE devices (hard disks, + CD-ROM drives, etc.) that are connected to the builtin IDE interface. Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -894,21 +909,15 @@ CONFIG_BLK_DEV_MAC_IDE (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. -ICS IDE interface support -CONFIG_BLK_DEV_IDE_ICSIDE - No help for CONFIG_BLK_DEV_IDE_ICSIDE - -ICS DMA support -CONFIG_BLK_DEV_IDEDMA_ICS - No help for CONFIG_BLK_DEV_IDEDMA_ICS - -Use ICS DMA by default -CONFIG_IDEDMA_ICS_AUTO - No help for CONFIG_IDEDMA_ICS_AUTO - -RapIDE interface support -CONFIG_BLK_DEV_IDE_RAPIDE - No help for CONFIG_BLK_DEV_IDE_RAPIDE +PS/2 ESDI hard disk support +CONFIG_BLK_DEV_PS2 + Say Y here if you have a PS/2 machine with a MCA bus and an ESDI + hard disk. + + 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 Documentation/modules.txt. The module will be + called ps2esdi.o. XT hard disk support CONFIG_BLK_DEV_XD diff --git a/Documentation/devices.tex b/Documentation/devices.tex index 5bd758c0d6b1..d4e10e7f7b59 100644 --- a/Documentation/devices.tex +++ b/Documentation/devices.tex @@ -1783,6 +1783,16 @@ major number 3). \minor{31}{/dev/mtdr15}{16th MTD (ro)} \end{devicelist} +\begin{devicelist} +\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} + \minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)} + \minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)} +\end{devicelist} + +\noindent +Partitions are handled the same way as for the first interface (see +major number 3). + \begin{devicelist} \major{91}{}{char }{CAN-Bus controller} \minor{0}{/dev/can0}{First CAN-Bus controller} @@ -1790,6 +1800,16 @@ major number 3). \minordots \end{devicelist} +\begin{devicelist} +\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} + \minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)} + \minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)} +\end{devicelist} + +\noindent +Partitions are handled the same way as for the first interface (see +major number 3). + \begin{devicelist} \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card} \end{devicelist} diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 92b2d621d6e7..9f911d1fc174 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -1241,11 +1241,25 @@ Your cooperation is appreciated. 30 = /dev/mtd15 16th MTD (rw) 31 = /dev/mtdr15 16th MTD (ro) + block Eighth IDE hard disk/CD-ROM interface + 0 = /dev/hdq Master: whole disk (or CD-ROM) + 64 = /dev/hdr Slave: whole disk (or CD-ROM) + + Partitions are handled the same way as for the first + interface (see major number 3). + 91 char CAN-Bus devices 0 = /dev/can0 First CAN-Bus controller 1 = /dev/can1 Second CAN-Bus controller ... + block Ninth IDE hard disk/CD-ROM interface + 0 = /dev/hds Master: whole disk (or CD-ROM) + 64 = /dev/hdt Slave: whole disk (or CD-ROM) + + Partitions are handled the same way as for the first + interface (see major number 3). + 92 char Reserved for ith Kommunikationstechnik MIC ISDN card 93 char IBM Smart Capture Card frame grabber diff --git a/Documentation/modules.txt b/Documentation/modules.txt index ca9c434f716e..cf8b422140e4 100644 --- a/Documentation/modules.txt +++ b/Documentation/modules.txt @@ -59,7 +59,7 @@ Here is a sample of the available modules included in the kernel sources: Most low-level SCSI drivers: (i.e. aha1542, in2000) All SCSI high-level drivers: disk, tape, cdrom, generic. - Most ethernet drivers: (too many to list, please see the file + Most Ethernet drivers: (too many to list, please see the file ./Documentation/networking/net-modules.txt) Most CDROM drivers: diff --git a/Documentation/mtrr.txt b/Documentation/mtrr.txt index f047b7a2873a..941da7e91421 100644 --- a/Documentation/mtrr.txt +++ b/Documentation/mtrr.txt @@ -52,7 +52,7 @@ reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1 -This is for videoram at base address 0xf8000000 and size 4 MBytes. To +This is for video RAM at base address 0xf8000000 and size 4 megabytes. To find out your base address, you need to look at the output of your X server, which tells you where the linear framebuffer address is. A typical line that you may get is: @@ -68,7 +68,7 @@ know?), the following line will tell you: (--) S3: videoram: 4096k -That's 4 MBytes, which is 0x400000 bytes (in hexadecimal). +That's 4 megabytes, which is 0x400000 bytes (in hexadecimal). A patch is being written for XFree86 which will make this automatic: in other words the X server will manipulate /proc/mtrr using the ioctl() interface, so users won't have to do anything. If you use a diff --git a/Documentation/nbd.txt b/Documentation/nbd.txt index fc488449e192..7b7899740480 100644 --- a/Documentation/nbd.txt +++ b/Documentation/nbd.txt @@ -4,11 +4,11 @@ means, that it works on my computer, and it worked on one of school computers. - What is it: With this compiled in the kernel, linux can use a remote + What is it: With this compiled in the kernel, Linux can use a remote server as one of its block devices. So every time the client computer wants to read /dev/nd0, it sends a request over TCP to the server, which will reply with the data read. This can be used for stations with - low-disk space (or even diskless - if you boot from floppy) to + low disk space (or even diskless - if you boot from floppy) to borrow disk space from another computer. Unlike NFS, it is possible to put any filesystem on it etc. It is impossible to use NBD as a root filesystem, since it requires a user-level program to start. It also diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index e3981efff11a..be39d93e40b8 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -13,9 +13,9 @@ PLIP.txt alias.txt - info on using alias network devices arcnet-hardware.txt - - tons of info on arcnet, hubs, arcnet card jumper settings, etc. + - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt - - info on the using the arcnet driver itself. + - info on the using the ARCnet driver itself. ax25.txt - info on using AX.25 and NET/ROM code for Linux baycom.txt @@ -69,13 +69,13 @@ shaper.txt smc9.txt - the driver for SMC's 9000 series of Ethernet cards soundmodem.txt - - Linux driver for soundcards as AX.25 modems + - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. tulip.txt - info on using DEC 21040/21041/21140 based PCI Ethernet cards. vortex.txt - - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards. + - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt - Wan router documentation wanpipe.txt diff --git a/Documentation/networking/Configurable b/Documentation/networking/Configurable index 62c27457e1d0..a941ca30f665 100644 --- a/Documentation/networking/Configurable +++ b/Documentation/networking/Configurable @@ -20,11 +20,11 @@ to Address Resolution Protocol (ARP) are very easily viewed and altered. 7000 Others are already accessible via the related user space programs. -For example, MAX_WINDOW has a default of 32k which is a good choice for -modern hardware, but if you have a slow (8 bit) ethercard and/or a slow +For example, MAX_WINDOW has a default of 32 k which is a good choice for +modern hardware, but if you have a slow (8 bit) Ethernet card and/or a slow machine, then this will be far too big for the card to keep up with fast -Tx'ing machines on the same net, resulting in overruns and receive errors. -A value of about 4k would be more appropriate, which can be set via: +machines transmitting on the same net, resulting in overruns and receive errors. +A value of about 4 k would be more appropriate, which can be set via: # route add -net 192.168.3.0 window 4096 diff --git a/Documentation/networking/DLINK.txt b/Documentation/networking/DLINK.txt index 9dafab262886..efbf441bae40 100644 --- a/Documentation/networking/DLINK.txt +++ b/Documentation/networking/DLINK.txt @@ -18,8 +18,8 @@ Released 1994-06-13 pocket adapters, for the parallel port on a Linux based machine. Some adapter "clones" will also work. Xircom is _not_ a clone... These drivers _can_ be used as loadable modules, - and were developed for use on Linux v1.1.13 and above. - For use on Linux v1.0.X, or earlier releases, see below. + and were developed for use on Linux 1.1.13 and above. + For use on Linux 1.0.X, or earlier releases, see below. I have used these drivers for NFS, ftp, telnet and X-clients on remote machines. Transmissions with ftp seems to work as @@ -57,7 +57,7 @@ Released 1994-06-13 de620.h Macros for de620.c If you are upgrading from the d-link tar release, there will - also be a "dlink-patches" file that will patch Linux v1.1.18: + also be a "dlink-patches" file that will patch Linux 1.1.18: linux/drivers/net/Makefile linux/drivers/net/CONFIG linux/drivers/net/MODULES @@ -162,10 +162,10 @@ Released 1994-06-13 6. USING THE DRIVERS WITH EARLIER RELEASES. - The later v1.1.X releases of the Linux kernel include some + The later 1.1.X releases of the Linux kernel include some changes in the networking layer (a.k.a. NET3). This affects these drivers in a few places. The hints that follow are - _not_ tested by me, since I don't have the diskspace to keep + _not_ tested by me, since I don't have the disk space to keep all releases on-line. Known needed changes to date: - release patchfile: some patches will fail, but they should diff --git a/Documentation/networking/dgrs.txt b/Documentation/networking/dgrs.txt index d37d1c41ad72..1aa1bb3f94ab 100644 --- a/Documentation/networking/dgrs.txt +++ b/Documentation/networking/dgrs.txt @@ -1,4 +1,4 @@ - The Digi Intl. RightSwitch SE-X (dgrs) Device Driver + The Digi International RightSwitch SE-X (dgrs) Device Driver This is a Linux driver for the Digi International RightSwitch SE-X EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet diff --git a/Documentation/scsi-generic.txt b/Documentation/scsi-generic.txt index 17822c4ad70f..2d26dec9d2e8 100644 --- a/Documentation/scsi-generic.txt +++ b/Documentation/scsi-generic.txt @@ -1,34 +1,38 @@ - Notes on Linux's SG driver version 2.1.30 + Notes on Linux's SG driver version 2.1.34 ----------------------------------------- - 990328 + 990606 Introduction ============ +Sg is one of the four "high level" SCSI device drivers along with +sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized +(but lower level) than its siblings and tends to be used on SCSI devices +that don't fit into the already serviced categories. Thus sg is used for +scanners, cd writers and reading audio cds digitally amongst other things. + These are notes on the Linux SCSI generic packet device driver (sg) -describing version 2.1.30 . The original driver was written by Lawrence -Foard and has remained in place with minimal changes since circa 1992. +describing version 2.1.34 . The original driver was written by Lawrence +Foard and remained in place with minimal changes since circa 1992. Version 2 of this driver remains backward compatible (binary and source **) with the original. It adds scatter gather, command queuing, per file descriptor sequencing, asynchronous notification and better error reporting. -Sg is one of the four "high level" SCSI device drivers along with -sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized -(but lower level) than its sibling and tends to be used on SCSI devices -that don't fit into the already serviced categories. Thus sg is used for -scanners, cd writers and reading audio cds amongst other things. +This is an abridged version of the sg documentation that is targeted +at the linux/Documentation directory. The full document can be found +at http://www.torque.net/sg/p/scsi-generic_long.txt . -The interface and usage of the original sg driver has been documented +The interface and usage of the original sg driver have been documented by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy of the document is version 1.5 dated 7th May 1996. It can found at -ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO . -Amongst other things it has a lot of tables from the SCSI-2 standard -that are very useful for programming this interface. +ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO . +A copy of this document can be found at: +http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO . ** It is possible to write applications that perform differently depending on whether they are using the original or this version of -the sg device driver. The author is not aware of any useful applications -that have problems with version 2 (yet). +the sg device driver. The author is not aware of any useful +pre-existing applications that have problems with version 2 (yet). Architecture @@ -38,9 +42,11 @@ It is one of the four high level device driver in the SCSI sub-system; the others are sd (for direct-access devices - disks), st (for tapes) and sr (for data cdroms). The other three devices are block devices. -The unifying layer of the SCSI sub-system in the so-called mid-level. -Below that are all the drivers for the various adapters supported by -Linux. +The unifying layer of the SCSI sub-system is the so-called mid-level. +Below that are the "low level" drivers which are the drivers for the +various adapters supported by Linux. Also at this level are pseudo +adapter drivers such as ide-scsi which converts the SCSI protocol to +ATAPI (which are similar to one another) for use by IDE devices. Since sg is a character device it supports the traditional Unix system calls of open(), close(), read(), write() and ioctl(). Two other @@ -85,8 +91,9 @@ struct sg_header { unsigned char sense_buffer[16]; }; /* this structure is 36 bytes long */ -The 'pack_len' is bizzare and ends up having the 'reply_len' put in it -(perhaps it had a use at some stage). +The 'pack_len' is bizarre and ends up having the 'reply_len' put in it +(perhaps it had a use at some stage). Even though it looks like an +input variable, it is not read by sg internally (only written). The 'reply_len' is the length of the data the corresponding read() will/should request (including the sg_header). @@ -95,14 +102,14 @@ The 'pack_id' is not acted upon by the sg device driver but is conveyed back to the corresponding read() so it can be used for sequencing by an application. -The 'result' is also bizzare, turning certain types of host codes it 0 (no +The 'result' is also bizarre, turning certain types of host codes to 0 (no error), EBUSY or EIO. With better error reporting now available, the 'result' is best ignored. -The 'twelve_byte' field overrides the internal SCSI command length "guessing" +The 'twelve_byte' field overrides the internal SCSI command length detection algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces -a command lenth of 12 bytes. -The command length "guessing" algorithm is as follows: +a command length of 12 bytes. +The command length detection algorithm is as follows: Group: 0 1 2 3 4 5 6 7 Length: 6 10 10 12 12 12 10 10 @@ -115,6 +122,7 @@ or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately this is unlikely to happen in the 2.2.x series of kernels. + The new sg_header offered in this driver is: #define SG_MAX_SENSE 16 struct sg_header @@ -122,15 +130,17 @@ struct sg_header int pack_len; /* [o] reply_len (ie useless) ignored as input */ int reply_len; /* [i] max length of expected reply (inc. sg_header) */ int pack_id; /* [io] id number of packet (use ints >= 0) */ - int result; /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */ + int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */ unsigned int twelve_byte:1; /* [i] Force 12 byte command length for group 6 & 7 commands */ unsigned int target_status:5; /* [o] scsi status from target */ unsigned int host_status:8; /* [o] host status (see "DID" codes) */ unsigned int driver_status:8; /* [o] driver status+suggestion */ unsigned int other_flags:10; /* unused */ - unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is - CHECK_CONDITION or COMMAND_TERMINATED this is output. */ + unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases: + when target_status is CHECK_CONDITION or + when target_status is COMMAND_TERMINATED or + when (driver_status & DRIVER_SENSE) is true. */ }; /* This structure is 36 bytes long on i386 */ Firstly the new header is binary compatible with the original. This is @@ -146,6 +156,9 @@ EAGAIN) until a packet with that 'pack_id' becomes available. In all cases the value of 'pack_id' available after a read() is the value given to that variable in the prior, corresponding write(). +The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN +ioctl(). + The 'target_status' field is always output and is the (masked and shifted 1 bit right) SCSI status code from the target device. The allowable values are (found in ): @@ -162,28 +175,28 @@ values are (found in ): When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the 'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE) is true then the 'sense_buffer' is also output (this seems to occur when -the scsi ide emulation is used). When the 'sense_buffer' is output the +the ide-scsi emulation is used). When the 'sense_buffer' is output the SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) . The 'host_status' field is always output and has the following values -whose "defines" are not visible outside the kernel (unfortunately): +whose "defines" are not visible outside the kernel. A copy of these +defines can be found in sg_err.h (see the utilities section): #define DID_OK 0x00 /* NO error */ #define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ #define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ #define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_BAD_TARGET 0x04 /* BAD target, device not responding? */ #define DID_ABORT 0x05 /* Told to abort for some other reason */ #define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ +#define DID_ERROR 0x07 /* Internal error [DMA underrun on aic7xxx]*/ #define DID_RESET 0x08 /* Reset by somebody. */ #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DID_SOFT_ERROR 0x0b /* The low level driver wants a retry */ The 'driver_status' field is always output. When ('driver_status' & -DRIVER_SENSE) is true the 'sense_buffer' is also output. The following -values whose "defines" are not visible outside the kernel (unfortunately) -can occur: +DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these +defines can be found in sg_err.h (see the utilities section): #define DRIVER_OK 0x00 /* Typically no suggestion */ #define DRIVER_BUSY 0x01 #define DRIVER_SOFT 0x02 @@ -192,7 +205,7 @@ can occur: #define DRIVER_INVALID 0x05 #define DRIVER_TIMEOUT 0x06 #define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 +#define DRIVER_SENSE 0x08 /* Implies sense_buffer output */ /* above status 'or'ed with one of the following suggestions */ #define SUGGEST_RETRY 0x10 #define SUGGEST_ABORT 0x20 @@ -200,55 +213,8 @@ can occur: #define SUGGEST_DIE 0x40 #define SUGGEST_SENSE 0x80 -'other_flags' still remains as a 10 bit field, so code that places 0 in it -will still be happy. It is not used. - - -memory -====== -Memory is a scarce resource in any computer. Sg needs to reserve memory -suitable for DMA roughly equal in size to the maximum of the write and -read data buffers for each packet. This DMA memory is obtained at the time -of a write() and released when the corresponding read() is called (although -if memory is tight it may be using the buffer reserved by the open() ). - -Linux obtaining memory a challenge for several reasons. The memory pool -that sg uses is in common with all other device drivers and all user -processes. In this environment the only way to 99.9% guarantee a driver -will have memory in Linux is to build it into the kernel (ie not as a -module) and then reserve it on initialization before user processes get -a chance. [Of course, another driver initialized before sg could take -all available memory ...] Another problem is the biggest contiguous -chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE -(which is 128KBytes on i386). As memory gets "splintered" there is a good -chance that buffers won't be available (my machine has 64 MBytes of RAM -and has 3 available at the moment). - -The original sg driver used the following technique: grab a SG_BIG_BUFF -sized buffer at driver initialization and use it for all requests greater -than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to -32 KBytes in the origianl driver but many applications suggest that the -user increases this number. Linux limits the biggest single buffer of -this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the -sg driver is a module then there is a high chance a contiguous block of -that large size will not be available at module initialization. - -The author has found no "silver bullet" solution but uses multiple -techniques hoping that at least one is able provide memory at the critical -time. Listed below are some of these techniques: - - use scatter gather: then instead of one large buffer needing to - be found, multiple smaller buffer can be used - - use memory above the 16MByte level: the original driver limited - itself to obtaining memory below the 16MByte level (on the i386) - due to the shortcomings of DMA on ISA adapters. Yet more and more - people use PCI adapters that don't have this problem. So make - the decision based on the capabilities of the host adpater - associated with the current SCSI device - - reserve some memory at open() for emergencies but otherwise - fetch and release it on a per packet basis - - if the kernel is short of memory then dip into the SCSI DMA - pool (maintained by the mid-level driver) to a limited amount - +'other_flags' still remains as a 10 bit field (reduced from 31 bits), so +code that places 0 in it will still be happy. It is not used. System Calls @@ -257,16 +223,16 @@ What follows are descriptions of the characteristics of the standard Unix operating system calls when applied to a SCSI generic device using this version of the device driver. -open ----- +open(const char * filename, int flags) +-------------------------------------- The filename should be an 'sg' device such as /dev/sg[a-z] /dev/sg[0,1,2,...] or a symbolic link to one of these. [Devfs has its own sub-directory for -sg devices.] It seems as though SCSI devices are allocated to sg minor -numbers in the same order as they appear in 'cat /proc/scsi/scsi'. -Sg is a "character" based Linux device driver. This means it has an -open/close/read/write/ioctl type interface. +sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI +devices are allocated to sg minor numbers in the same order as they appear +in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver. +This means it has an open/close/read/write/ioctl type interface. Flags can be either O_RDONLY or O_RDWR or-ed with either O_EXCL waits for other opens on sg device to be closed before @@ -279,7 +245,7 @@ O_NONBLOCK Sets non-blocking mode. Calls that would otherwise block The original version of sg did not allow the O_RDONLY (yielding a EACCES error). This version allows it for accessing ioctls (e.g. doing an sg device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be -allowed. +allowed. These flags are found in . By default, sequencing is per file descriptor in this version of sg. This means, for example that 2 processes can independently manipulate the same @@ -290,32 +256,38 @@ on the same device at the same time probably wouldn't be a good idea. The previous version of sg supported only per device sequencing and this can still be selected with the SG_SET_MERGE_FD,1 ioctl(). -The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the -current sg.h) on open() for "emergency" situations. If this is unavailable -it will halve its request and try again. It gives up if PAGE_SIZE bytes -(4096 bytes on i386) cannot be obtained so no memory is reserved. In this -case open() will still return successfully. The actual amount of memory -reserved can be found with the SG_GET_RESERVED_SIZE ioctl(). +The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in +the current sg.h) on open(). The size of this reserved buffer can +subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both +cases these are requests subject to various dynamic constraints. The actual +amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl(). +The reserved buffer will be used if: + - it is not already in use (eg when command queuing is in use) + - a write() does not call for a buffer size larger than the + reserved size. Returns a file descriptor if >= 0 , otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): -ENODEV sg not compiled into kernel or the kernel cannot find the - sg module (or it can't initialize itself (low memory??)) -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted +EACCES Either the user doesn't have appropriate permissions on + 'filename' or attempted to use both O_RDONLY and O_EXCL EBUSY O_NONBLOCK set and some user of this sg device has O_EXCL set while someone is already using this device EINTR while waiting for an "exclusive" lock to clear, a signal is received, just try again ... +ENODEV sg not compiled into kernel or the kernel cannot find the + sg module (or it can't initialize itself (low memory??)) +ENOENT given filename not found ENOMEM An attempt to get memory to store this open's context failed (this was _not_ a request to reserve DMA memory) -EACCES An attempt to use both O_RDONLY and O_EXCL +ENXIO either there is no attached device corresponding to given + filename or scsi sub-system is currently processing some + error (eg doing a device reset) or the sg driver/module + removed or corrupted -write ------ +write(int sg_fd, const void * buffer, size_t count) +--------------------------------------------------- Even though sg is a character-based device driver it sends and receives packets to/from the associated scsi device. Write() is used to send a packet containing 2 mandatory parts and 1 optional part. The mandatory @@ -343,32 +315,33 @@ In this sg driver a write() should return more or less immediately. Returns number of bytes written if > 0 , otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted EACCES opened with RD_ONLY flag -EIO incoming buffer too short. It should be at least (6 + - sizeof(struct sg_header))==42 bytes long -EDOM a) command queuing off: a packet is already queued - b) command queuing on: too many packets queued - (SG_MAX_QUEUE exceeded) EAGAIN SCSI mid-level out of command blocks (rare), try again. This is more likely to happen when queuing commands, so wait a bit (eg usleep(10000) ) before trying again +EDOM a) command queuing off: a packet is already queued + b) command queuing on: too many packets queued + (SG_MAX_QUEUE exceeded) + c) SCSI command length given in SG_NEXT_CMD_LEN too long +EFAULT 'buffer' for 'count' bytes is an invalid memory range +EIO incoming buffer too short. It should be at least (6 + + sizeof(struct sg_header))==42 bytes long ENOMEM can't get memory for DMA. Take evasive action ... - (see section on memory) +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted -read ----- +read(int sg_fd, void * buffer, size_t count) +-------------------------------------------- Read() is used to receive a packet containing 1 mandatory part and 1 optional part. The mandatory part is: - a control block (an instance of struct sg_header) The optional part is: - incoming data (eg if a SCSI read command was sent by earlier write() ) The buffer given to a read() and its corresponding count should be -sufficient to accommodate this packet to avoid truncation. Truncation has -occurred if count < sg_header::replylen . +sufficient to accommodate this packet to avoid truncation. Truncation occurs +if count < sg_header::replylen . By default, read() will return the oldest packet queued up. If the SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to @@ -377,7 +350,6 @@ sg_header::pack_id given to this read(). If not available it will either wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given to read() will match the oldest packet. - Returns number of bytes read if > 0 , otherwise -1 implies an error. Unfortunately the return value in the non-error case is simply the same as the count argument. It is not the actual number of bytes @@ -385,25 +357,26 @@ DMA-ed by the SCSI device. This driver is currently unable to provide such an underrun indication. Error codes (value in 'errno' after -1 returned): -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted EAGAIN either no waiting packet or requested packet is not available while O_NONBLOCK flag was set +EFAULT 'buffer' for 'count' bytes is an invalid memory range EINTR while waiting for a packet, a signal is received, just try again ... EIO if the 'count' given to read() is < sizeof(struct sg_header) and the 'result' element in sg_header is non-zero. Not a recommended error reporting technique +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted -close ------ +close(int sg_fd) +---------------- Preferably a close() should be done after all issued write()s have had their corresponding read() calls completed. Unfortunately this is not always possible. The semantics of close() in Unix are to return more or less immediately (ie not wait on any event) so the driver needs to -arrange to an orderly cleanup of those packets that are still "in +arrange for an orderly cleanup of those packets that are still "in flight". A process that has an open file descriptor to an sg device may be aborted @@ -411,22 +384,22 @@ A process that has an open file descriptor to an sg device may be aborted (which is called 'sg_release()' in the version 2 driver) to facilitate the cleanup mentioned above. -A problem persists in version 2.1.8 if the sg driver is a module and is -removed while packets are still "in flight". Hopefully this will be soon -fixed. +A problem persists in version 2.1.34 if the sg driver is a module and is +removed while packets are still "in flight". Returns 0 if successful, otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): ENXIO sg driver/module removed or corrupted -ioctl (sg specific) -------------------- +ioctl(int sg_fd, int command, ...) [sg specific] +------------------------------------------------- Ken Thompson (or perhaps some other Unix luminary) described ioctl() as the "garbage bin of Unix". This driver compounds the situation by adding -around 18 more commands. These commands either yield state information (10 -of them), change the driver's characteristics (8 of them) or allow direct -communication with the common SCSI mid-level driver. +more ... +If a ioctl command is not recognized by sg (and the various lower levels +that it may pass the command on to) then the error EINVAL occurs. If an +invalid address is given (in the 3rd argument) then the error EFAULT occurs. Those commands with an appended "+" are new in version 2. @@ -442,15 +415,38 @@ a manifest constant HZ which is the number of "jiffies" in 1 second. SG_SET_TIMEOUT: Assumes 3rd argument points to an int containing the new timeout value for this file descriptor. The unit is a "jiffy". Packets that are -already "in flight" will not be effected. The default value is set -on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). +already "in flight" will not be affected. The default value is set +on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is +currently 1 minute and may not be long enough for formats. SG_EMULATED_HOST: Assumes 3rd argument points to an int and outputs a flag indicating -whether the host (adapter) is connected to a real SCSI bus or is +whether the host (adapter) is connected to a real SCSI bus or is an emulated one (eg ide-scsi device driver). A value of 1 means emulated while 0 is not. +SG_SET_TRANSFORM W: +Third argument is ignored. Only is meaningful when SG_EMULATED host has +yielded 1 (ie the low-level is the ide-scsi device driver); otherwise +an EINVAL error occurs. The default state is to _not_ transform SCSI +commands to the corresponding ATAPI commands but pass them straight +through as is. [Only certain classes of SCSI commands need to be +transformed to their ATAPI equivalents.] Making this ioctl command causes +transforms to occur thereafter. Subsequent calls to this ioctl command +have no additional effect. Beware, this state will affect all devices +(and hence all related sg file descriptors) associated with this ide-scsi +"bus". +The author of ide-scsi has pointed out that this is not the intended +behaviour which is a 3rd argument of 0 to disable transforms and 1 to +enable transforms. Note the 3rd argument is an 'int' not a 'int *'. +Perhaps the intended behaviour will be implemented soon. + +SG_GET_TRANSFORM: +Third argument is ignored. Only is meaningful when SG_EMULATED host has +yielded 1 (ie the low-level is the ide-scsi device driver); otherwise +an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI +to ATAPI commands (default). Returns 1 when it is transforming. + SG_SET_FORCE_LOW_DMA +: Assumes 3rd argument points to an int containing 0 or 1. 0 (default) means sg decides whether to use memory above 16 Mbyte level (on i386) @@ -459,10 +455,10 @@ PCI SCSI adapters will indicate they can DMA to the whole 32 bit address space. If 1 is given then the host adapter is overridden and only memory below the 16MB level is used for DMA. A requirement for this should be -extremely rare. If the "reserve" buffer allocated on open() is not in +extremely rare. If the "reserved" buffer allocated on open() is not in use then it will be de-allocated and re-allocated under the 16MB level (and the latter operation could fail yielding ENOMEM). -Only the current file descriptor is effected. +Only the current file descriptor is affected. SG_GET_LOW_DMA +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 @@ -472,11 +468,11 @@ on this file descriptor. 1 indicates the memory below the 16MB level adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 . SG_GET_SCSI_ID +: -Assumes 3rd argument is pointing to an object of type Sg_scsi_id and -populates it. That structure contains ints for host_no, channel, -scsi_id, lun and scsi_type. Most of this information is available from -other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) -but tends to be awkward to collect. +Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see +sg.h) and populates it. That structure contains ints for host_no, +channel, scsi_id, lun and scsi_type. Most of this information is +available from other sources (eg SCSI_IOCTL_GET_IDLUN and +SCSI_IOCTL_GET_BUS_NUMBER) but tends to be awkward to collect. SG_SET_FORCE_PACK_ID +: Assumes 3rd argument is pointing to an int. 0 (default) instructs read() @@ -486,9 +482,9 @@ waiting to be read (when command queuing is being used). oldest packet matching that pack_id or wait until it arrives (or yield EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1 given to read() in the mode will match the oldest packet. -Only the current file descriptor is effected by this command. +Only the current file descriptor is affected by this command. -SG_GET_LOW_DMA +: +SG_GET_PACK_ID +: Assumes 3rd argument points to an int and places the pack_id of the oldest (written) packet in it. If no packet is waiting to be read then yields -1. @@ -503,30 +499,33 @@ scatter gather elements supported by the host adapter. 0 indicates that the adapter does support scatter gather. SG_SET_RESERVED_SIZE +W: -This is not currently implemented. It is intended for reserving either a -large buffer or scatter gather list that will be available until the -current file descriptor is closed. The requested amount of memory may -not be available so SG_GET_RESERVED_SIZE should be used after this call -to see how much was reserved. (EBUSY error possible) +Assumes 3rd argument is pointing to an int. That value will be used to +request a new reserved buffer of that size. The previous reserved buffer +is freed (if it is not in use; if it was in use -EBUSY is returned). +A new reserved buffer is then allocated and its actual size can be found by +calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used +for DMA purposes by subsequent write() commands if it is not already in +use and if the write() is not calling for a buffer size larger than that +reserved. The reserved buffer may well be a series of kernel buffers if the +adapter supports scatter-gather. Large buffers can be requested (eg 1 MB). SG_GET_RESERVED_SIZE +: Assumes 3rd argument points to an int and places the size in bytes of -the DMA buffer reserved on open() for emergencies. If this is 0 then it -is probably not wise to attempt on operation like burning a CD on this -file descriptor. +the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE +ioctl() call on this fd. The result can be 0 if memory is very tight. In +this case it may not be wise to attempt something like burning a CD on +this file descriptor. SG_SET_MERGE_FD +W: Assumes 3rd argument is pointing to an int. 0 (the default) causes all subsequent sequencing to be per file descriptor. 1 causes all subsequent sequencing to be per device. If this command tries to change the current -state and the is one or more _other_ file descriptors using this sg -device then an EBUSY error occurs. Also if this file descriptor was not -open()ed with the O_RDWR flag then an EACCES error occurs. -Per device sequencing was the original semantics and allowed, for example -different processes to "share" the device, one perhaps write()ing with -the other one read()ing. This command is supplied if anyone needs those -semantics. Per file descriptor sequencing, perhaps with the usage of -the O_EXCL flag, seems more sensible. +state and there is one or more _other_ file descriptors using this sg +device then an EBUSY error occurs. Per device sequencing was the original +semantics and allowed, for example different processes to "share" the +device, one perhaps write()ing with the other one read()ing. This command +is supplied if anyone needs those semantics. Per file descriptor +sequencing, perhaps with the use of the O_EXCL flag, seems more sensible. SG_GET_MERGE_FD +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies @@ -538,14 +537,42 @@ Assumes 3rd argument is pointing to an int. 0 (current default, set by SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write() a packet while one is already queued will result in a EDOM error. 1 turns command queuing on. -Changing the queuing state only effects write()s done after the change. -Only the current file descriptor is effected by this command. +Changing the queuing state only affects write()s done after the change. +Only the current file descriptor is affected by this command. SG_GET_COMMAND_Q +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies that command queuing is off on this file descriptor. 1 implies command queuing is on. +SG_SET_UNDERRUN_FLAG +: +Assumes 3rd argument is pointing to an int. 0 (current default, set by +SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests +that underruns be flagged. [The only low level driver that acts on this +at the moment is the aic7xxx which yields a DID_ERROR error on underrun.] +Only the current file descriptor is affected by this command (unless +"per device" sequencing has been selected). + +SG_GET_UNDERRUN_FLAG +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +that underruns are not being reported. 1 implies that underruns are being +reported (see SG_SET_UNDERRUN_FLAG for more details). + +SG_NEXT_CMD_LEN +: +Assumes 3rd argument is pointing to an int. The value of the int (if > 0) +will be used as the SCSI command length of the next SCSI command sent to +a write() on this fd. After that write() the SCSI command length logic is +reset to use automatic length detection (ie depending on SCSI command group +and the 'twelve_byte' field). If the current SCSI command length maximum of +12 is exceeded then the affected write() will yield an EDOM error. +Giving this ioctl() a value of 0 will set automatic length detection for +the next write(). N.B. Only the following write() on this fd is affected by +this ioctl(). + +SG_GET_VERSION_NUM +: +Assumes 3rd argument points to an int. The version number is then placed +in that int. A sg version such as 2.1.34 will yield "20134" from this ioctl. + SG_SET_DEBUG +: Assumes 3rd argument is pointing to an int. 0 (default) turns debugging off. Values > 0 cause the SCSI sense buffer to be decoded and output @@ -556,73 +583,53 @@ If you need a _lot_ of the SCSI sub-system debug information (mainly from the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of debug will appear in your console/log. -ioctl (in common with sd, st + sr) ----------------------------------- -The following ioctl()s can be called from any high-level scsi device -driver (ie sd, st, sr + sg). Access permissions may differ a bit from -one device to another, the access information given below is specific to -the sg device driver. - -SCSI_IOCTL_GET_IDLUN: -SCSI_IOCTL_GET_BUS_NUMBER: - -SCSI_IOCTL_SEND_COMMAND: W -If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto -the SCSI mid-level driver for processing. -Don't know much about this one but it looks pretty powerful and -dangerous. Some comments says it is also deprecated. -: W -If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto -the SCSI mid-level driver for processing. - - -poll ----- +poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms) +-------------------------------------------------------------- This is a native call in Linux 2.2 but most of its capabilities are available through the older select() call. Given a choice poll() should probably be used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK -for polling; or alternatively with asynchronous notification using the -fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. +for polling; and optionally with asynchronous notification as well using +the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. Only if something drastically is wrong (eg file handle gone stale) will POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set. POLLIN is set when there is one or more packets waiting to be read. -When POLLIN is set it implies that a read() will not block (or yield +When POLLIN is set it implies that a read() will not block (nor yield EAGAIN in non-blocking mode) but return a packet immediately. POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet -(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected +(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain set until the number of queued packets reaches SG_MAX_QUEUE, if the state is off then POLLOUT is only set when no packets are queued. Note that a packet can be queued after write()ing but not available to be read(); this typically happens when a SCSI read command is issued while -the data is being retreaved. +the data is being retrieved. Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case it is per device. -fcntl ------ +fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg) +---------------------------------------------------------------- There are several uses for this system call in association with a sg -file descriptor. The first pseudo code shows code that is useful for +file descriptor. The following pseudo code shows code that is useful for scanning the sg devices, taking care not to be caught in a wait for an O_EXCL lock by another process, and when the appropriate device is -found switching to normal blocked io. A working example of this logic -is in the sg_scan.c utility program. +found, switching to normal blocked io. A working example of this logic +is in the sg_scan utility program. open("/dev/sga", O_RDONLY | O_NONBLOCK) /* check device, EBUSY means some other process has O_EXCL lock on it */ -/* one the device you want is found then ... */ +/* when the device you want is found then ... */ flags = fcntl(sg_fd, F_GETFL) fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK)) -/* for simple apps is is easier to use normal blocked io */ +/* since, for simple apps, it is easier to use normal blocked io */ Some work has to be done in Linux to set up for asynchronous notification. -This is a non-blocking mode of operation in which when the driver receives +This is a non-blocking mode of operation in which, when the driver receives data back from a device so that a read() can be done, it sends a SIGPOLL (aka SIGIO) signal to the owning process. A working example of this logic -is in the sg_poll.c test program. +is in the sg_poll test program. sigemptyset(&sig_set) sigaddset(&sig_set, SIGPOLL) @@ -634,3 +641,91 @@ fcntl(sg_fd, F_SETFL, flags | O_ASYNC) Utility and Test Programs ========================= +See the README file in the sg_utils.tgz tarball. At the time of +writing this was sg_utils990527.tgz . + +Briefly, that tarball contains the following utilities: +sg_dd512 'dd' like program that assumes 512 byte blocks size +sg_dd2048 'dd' like program that assumes 2048 byte blocks size +sgq_dd512 like 'sg_dd512' but does command queuing on "if" +sg_scan outputs information (optionally Inquiry) on SCSI devices +sg_rbuf tests SCSI bus transfer speed (without physical IO) +sg_whoami outputs info (optionally capacity) of given SCSI device +sginfo outputs "mode" information about SCSI devices (it is a + re-port of the scsiinfo program onto the sg interface) + +It also contains the following test programs: +sg_debug outputs sg driver state to console/log file +sg_poll tests asynchronous notification +sg_inquiry does a SCSI Inquiry command (from original HOWTO) +sg_tst_med checks presence of media (from original HOWTO) + +There are also 2 source files (sg_err.[hc]) for outputting and categorizing +SCSI 2 errors and warnings. This code is used by most of the above +utility and test programs. + +The following programs: sg_dd512, sg_dd2048, sg_scan, sg_rbuf, sg_tst_med, +sg_inquiry and sginfo, can be compiled either for this new sg driver _or_ +the original sg driver. + + +Header files +============ +User applications need to find the correct "sg.h" header file matching +their kernel in order to write code using the sg device driver. This is +sometimes more difficult than it should be. The correct "sg.h" will usually +be found at /usr/src/linux/include/scsi/sg.h . Another important header +file is "scsi.h" which will be in the same directory. + +Several distributions have taken their own copies of these files and placed +them in /usr/include/scsi which is where "#include " would go +looking. The directory /usr/include/scsi _should_ be a symbolic link to +/usr/src/linux/include/scsi/ . It was is Redhat 5.1 and 5.2 but it is +not is Redhat 6.0 . Some other distributions have the same problem. To +solve this (as root) do the following: + +# cd /usr/include +# mv scsi scsi_orig +# ln -s ../src/linux/include/scsi scsi + +This doesn't seem to be a problem with /usr/include/linux (at least in +Redhat where it is a symbolic link) so it is hard to understand why +/usr/include/scsi is defined the way it is. The fact the +/usr/include/linux is a symbolic link opens up the following solution +proposed by the author of cdparanoia (Monty): +#include + + +Extra information in scsi-generic_long.txt +========================================== +This document is an abridged form of a more comprehensive document called +scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt). + +The longer document contains additional sections on: + - memory issues + - ioctl()s in common with sd, st + sr + - distinguishing the original from the new driver + - SG_BIG_BUFF and friends + - shortcomings + - future directions + - an appendix with some SCSI 2 information in it + + +Conclusion +========== +The SCSI generic packet device driver attempts to make as few assumptions +as possible about the device it is connected to while giving applications +using it as much flexibility as possible on the SCSI command level. Sg +needs to hide the "messy" kernel related details while protecting +the integrity of the kernel against sg "abuse". Some of these aims are +contradictory and some compromises need to be made. For example: should +a sg based application be able to reset a SCSI bus when that could cause +collateral damage to a disk holding the root file system? There is no +easy answer to this and many other related questions. + +If you have any suggestion about sg (or improving (the accuracy of) this +document) please contact me. + + +Douglas Gilbert +dgilbert@interlog.com diff --git a/Documentation/sx.txt b/Documentation/sx.txt new file mode 100644 index 000000000000..f924f39bd34b --- /dev/null +++ b/Documentation/sx.txt @@ -0,0 +1,289 @@ + + sx.txt -- specialix SX/SI multiport serial driver readme. + + + + Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) + + Specialix pays for the development and support of this driver. + Please DO contact support@specialix.co.uk if you require + support. + + This driver was developed in the BitWizard linux device + driver service. If you require a linux device driver for your + product, please contact devices@BitWizard.nl for a quote. + + (History) + There used to be an SI driver by Simon Allan. This is a complete + rewrite from scratch. Just a few lines-of-code have been snatched. + + (Sources) + Specialix document number 6210028: SX Host Card and Download Code + Software Functional Specification. + + (Copying) + 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. + + (Addendum) + I'd appreciate it that if you have fixes, that you send them + to me first. + + +Introduction +============ + +This file contains some random information, that I like to have online +instead of in a manual that can get lost. Ever misplace your Linux +kernel sources? And the manual of one of the boards in your computer? + + +Theory of operation +=================== + +An important thing to know is that the driver itself doesn't have the +firmware for the card. This means that you need the separate package +"sx_firmware". For now you can get the source at + + ftp://ftp.bitwizard.nl/specialix/sx_firmware_.tgz + +The firmware load needs a "misc" device, so you'll need to enable the +"Support for user misc device modules" in your kernel configuration. +The misc device needs to be called "/dev/specialix_sxctl". It needs +misc major 10, and minor number 167 (assigned by HPA). The section +on creating device files below also creates this device. + +After loading the sx.o module into your kernel, the driver will report +the number of cards detected, but because it doesn't have any +firmware, it will not be able to determine the number of ports. Only +when you then run "sx_firmware" will the firmware be downloaded and +the rest of the driver initialized. At that time the sx_firmware +program will report the number of ports installed. + +In contrast with many other multi port serial cards, some of the data +structures are only allocated when the card knows the number of ports +that are connected. This means we won't waste memory for 120 port +descriptor structures when you only have 8 ports. If you experience +problems due to this, please report them: I haven't seen any. + + +Interrupts +========== + +A multi port serial card, would generate a horrendous amount of +interrupts if it would interrupt the CPU for every received +character. Even more than 10 years ago, the trick not to use +interrupts but to poll the serial cards was invented. + +The SX card allow us to do this two ways. First the card limits its +own interrupt rate to a rate that won't overwhelm the CPU. Secondly, +we could forget about the cards interrupt completely and use the +internal timer for this purpose. + +Polling the card can take up to a few percent of your CPU. Using the +interrupts would be better if you have most of the ports idle. Using +timer-based polling is better if your card almost always has work to +do. You save the separate interrupt in that case. + +In any case, it doesn't really matter all that much. + +The most common problem with interrupts is that for ISA cards in a PCI +system the BIOS has to be told to configure that interrupt as "legacy +ISA". Otherwise the card can pull on the interrupt line all it wants +but the CPU won't see this. + +If you can't get the interrupt to work, remember that polling mode is +more efficient (provided you actually use the card intensively). + + +Allowed Configurations +====================== + +Some configurations are disallowed. Even though at a glance they might +seem to work, they are known to lockup the bus between the host card +and the device concentrators. You should respect the drivers decision +not to support certain configurations. It's there for a reason. + +Warning: Seriously technical stuff ahead. Executive summary: Don't use +SX cards except configured at a 64k boundary. Skip the next paragraph. + +The SX cards can theoretically be placed at a 32k boundary. So for +instance you can put an SX card at 0xc8000-0xd7fff. This is not a +"recommended configuration". ISA cards have to tell the bus controller +how they like their timing. Due to timing issues they have to do this +based on which 64k window the address falls into. This means that the +32k window below and above the SX card have to use exactly the same +timing as the SX card. That reportedly works for other SX cards. But +you're still left with two useless 32k windows that should not be used +by anybody else. + + +Configuring the driver +====================== + +PCI cards are always detected. The driver auto-probes for ISA cards at +some sensible addresses. Please report if the auto-probe causes trouble +in your system, or when a card isn't detected. + +I'm afraid I haven't implemented "kernel command line parameters" yet. +This means that if the default doesn't work for you, you shouldn't use +the compiled-into-the-kernel version of the driver. Use a module +instead. If you convince me that you need this, I'll make it for +you. Deal? + +I'm afraid that the module parameters are a bit clumsy. If you have a +better idea, please tell me. + +You can specify several parameters: + + sx_poll: number of jiffies between timer-based polls. + + Set this to "0" to disable timer based polls. + Initialization of cards without a working interrupt + will fail. + + Set this to "1" if you want a polling driver. + (on Intel: 100 polls per second). If you don't use + fast baud rates, you might consider a value like "5". + (If you don't know how to do the math, use 1). + + sx_slowpoll: Number of jiffies between timer-based polls. + Set this to "100" to poll once a second. + This should get the card out of a stall if the driver + ever misses an interrupt. I've never seen this happen, + and if it does, that's a bug. Tell me. + + sx_maxints: Number of interrupts to request from the card. + The card normally limits interrupts to about 100 per + second to offload the host CPU. You can increase this + number to reduce latency on the card a little. + Note that if you give a very high number you can overload + your CPU as well as the CPU on the host card. This setting + is inaccurate and not recommended for SI cards (But it + works). + + sx_irqmask: The mask of allowable IRQs to use. I suggest you set + this to 0 (disable IRQs all together) and use polling if + the assignment of IRQs becomes problematic. + + sx_debug: You can enable different sorts of debug traces with this. + At "-1" all debugging traces are active. You'll get several + times more debugging output than you'll get characters + transmitted. + + +Baud rates +========== + +Theoretically new SXDCs should be capable of more than 460k +baud. However the line drivers usually give up before that. Also the +CPU on the card may not be able to handle 8 channels going at full +blast at that speed. Moreover, the buffers are not large enough to +allow operation with 100 interrupts per second. You'll have to realize +that the card has a 256 byte buffer, so you'll have to increase the +number of interrupts per second if you have more than 256*100 bytes +per second to transmit. If you do any performance testing in this +area, I'd be glad to hear from you... + +(Psst Linux users..... I think the Linux driver is more efficient than +the driver for other OSes. If you can and want to benchmark them +against each other, be my guest, and report your findings...... :-) + + +Ports and devices +================= + +Port 0 is the top connector on the module closest to the host +card. Oh, the ports on the SXDCs and TAs are labelled from 1 to 8 +instead of from 0 to 7, as they are numbered by linux. I'm stubborn in +this: I know for sure that I wouldn't be able to calculate which port +is which anymore if I would change that.... + + +Devices: + +You should make the device files as follows: + +#!/bin/sh +# (I recommend that you cut-and-paste this into a file and run that) +cd /dev +t=0 +mknod specialix_sxctl c 10 167 +while [ $t -lt 64 ] + do + echo -n "$t " + mknod ttyX$t c 32 $t + mknod cux$t c 33 $t + t=`expr $t + 1` +done +echo "" +rm /etc/psdevtab +ps > /dev/null + + +This creates 64 devices. If you have more, increase the constant on +the line with "while". The devices start at 0, as is customary on +Linux. Specialix seems to like starting the numbering at 1. + +If your system doesn't come with these devices pre-installed, bug your +linux-vendor about this. They should have these devices +"pre-installed" before the new millennium. The "ps" stuff at the end +is to "tell" ps that the new devices exist. + +Officially the maximum number of cards per computer is 4. This driver +however supports as many cards in one machine as you want. You'll run +out of interrupts after a few, but you can switch to polled operation +then. At about 256 ports (More than 8 cards), we run out of minor +device numbers. Sorry. I suggest you buy a second computer.... (Or +switch to RIO). + +------------------------------------------------------------------------ + + + Fixed bugs and restrictions: + - Hangup processing. + -- Done. + + - the write path in generic_serial (lockup / oops). + -- Done (Ugly: not the way I want it. Copied from serial.c). + + - write buffer isn't flushed at close. + -- Done. I still seem to loose a few chars at close. + Sorry. I think that this is a firmware issue. (-> Specialix) + + - drain hardware before changing termios + - Change debug on the fly. + - ISA free irq -1. (no firmware loaded). + - adding c8000 as a probe address. Added warning. + - Add a RAMtest for the RAM on the card.c + - Crash when opening a port "way" of the number of allowed ports. + (for example opening port 60 when there are only 24 ports attached) + - Sometimes the use-count strays a bit. After a few hours of + testing the use count is sometimes "3". If you are not like + me and can remember what you did to get it that way, I'd + appreciate an Email. Possibly fixed. Tell me if anyone still + sees this. + - TAs don't work right if you don't connect all the modem control + signals. SXDCs do. T225 firmware problem -> Specialix. + (Mostly fixed now, I think. Tell me if you encounter this!) + + Bugs & restrictions: + + - Arbitrary baud rates. Requires firmware update. (-> Specialix) + + - Low latency (mostly firmware, -> Specialix) + + + diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 3ff204313e5a..16161e449483 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -94,7 +94,9 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set # CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set @@ -293,14 +295,12 @@ CONFIG_SERIAL=y # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y # # Mice # -# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y CONFIG_PSMOUSE=y CONFIG_82C710_MOUSE=y # CONFIG_PC110_PAD is not set diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index bcc5b259edb9..d6459ba704ed 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -1240,7 +1240,7 @@ __initfunc(void pcibios_init(void)) access_pci = bios; } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { if (!strcmp(str, "off")) { pci_probe = 0; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 36c7ca2de845..62e97b3bef62 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -80,6 +80,37 @@ static void default_idle(void) void (*idle)(void) = default_idle; +#if 1 + +#include + +static int __init piix4_idle_init(void) +{ + /* This is the PIIX4 ACPI device */ + struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + + if (dev) { + u32 base; + + printk("Found PIIX4 ACPI device\n"); + pci_read_config_dword(dev, 0x40, &base); + printk(" Base address %04x\n", base); +#ifdef __SMP__ + /* + * We can't really do idle things with multiple CPU's, I'm + * afraid. We'd need a per-CPU ACPI device. + */ + if (smp_num_cpus > 1) + return 0; +#endif + } + return 0; +} + +__initcall(piix4_idle_init); + +#endif + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 6fba7d5fc57a..4b898f66722c 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -43,7 +43,6 @@ else bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS - bool ' Generic ATA-66 support (DANGEROUS)' CONFIG_IDEDMA_ULTRA_66 define_bool IDEDMA_PCI_EXPERIMENTAL y else define_bool IDEDMA_PCI_EXPERIMENTAL n @@ -61,6 +60,7 @@ else "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA fi + bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then @@ -80,6 +80,7 @@ else bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE fi fi + bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 @@ -206,9 +207,11 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ + "$CONFIG_BLK_DEV_HPT366" = "y" -o \ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ + "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff --git a/drivers/block/MAKEDEV-IDE45 b/drivers/block/MAKEDEV-IDE45 deleted file mode 100644 index c55a9b3cf1c2..000000000000 --- a/drivers/block/MAKEDEV-IDE45 +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -# -# Andre Hedrick -# -# The song goes, "I did it the hard way..........." -# - -if [ ! -f /dev/hdi ]; then \ - echo "Making IDE4 Primary Devices hdi's"; \ - mknod /dev/hdi b 56 0; \ - mknod /dev/hdi1 b 56 1; \ - mknod /dev/hdi2 b 56 2; \ - mknod /dev/hdi3 b 56 3; \ - mknod /dev/hdi4 b 56 4; \ - mknod /dev/hdi5 b 56 5; \ - mknod /dev/hdi6 b 56 6; \ - mknod /dev/hdi7 b 56 7; \ - mknod /dev/hdi8 b 56 8; \ - mknod /dev/hdi9 b 56 9; \ - mknod /dev/hdi10 b 56 10; \ - mknod /dev/hdi11 b 56 11; \ - mknod /dev/hdi12 b 56 12; \ - mknod /dev/hdi13 b 56 13; \ - mknod /dev/hdi14 b 56 14; \ - mknod /dev/hdi15 b 56 15; \ - mknod /dev/hdi16 b 56 16; \ - chown root.disk /dev/hdi*; \ - chmod 660 /dev/hdi*; \ -fi - -if [ ! -f /dev/hdj ]; then \ - echo "Making IDE4 Secondary Devices hdj's"; \ - mknod /dev/hdj b 56 64; \ - mknod /dev/hdj1 b 56 65; \ - mknod /dev/hdj2 b 56 66; \ - mknod /dev/hdj3 b 56 67; \ - mknod /dev/hdj4 b 56 68; \ - mknod /dev/hdj5 b 56 69; \ - mknod /dev/hdj6 b 56 70; \ - mknod /dev/hdj7 b 56 71; \ - mknod /dev/hdj8 b 56 72; \ - mknod /dev/hdj9 b 56 73; \ - mknod /dev/hdj10 b 56 74; \ - mknod /dev/hdj11 b 56 75; \ - mknod /dev/hdj12 b 56 76; \ - mknod /dev/hdj13 b 56 77; \ - mknod /dev/hdj14 b 56 78; \ - mknod /dev/hdj15 b 56 79; \ - mknod /dev/hdj16 b 56 80; \ - chown root.disk /dev/hdj*; \ - chmod 660 /dev/hdj*; \ -fi - -if [ ! -f /dev/hdk ]; then \ - echo "Making IDE5 Primary Devices hdk's"; \ - mknod /dev/hdk b 57 0; \ - mknod /dev/hdk1 b 57 1; \ - mknod /dev/hdk2 b 57 2; \ - mknod /dev/hdk3 b 57 3; \ - mknod /dev/hdk4 b 57 4; \ - mknod /dev/hdk5 b 57 5; \ - mknod /dev/hdk6 b 57 6; \ - mknod /dev/hdk7 b 57 7; \ - mknod /dev/hdk8 b 57 8; \ - mknod /dev/hdk9 b 57 9; \ - mknod /dev/hdk10 b 57 10; \ - mknod /dev/hdk11 b 57 11; \ - mknod /dev/hdk12 b 57 12; \ - mknod /dev/hdk13 b 57 13; \ - mknod /dev/hdk14 b 57 14; \ - mknod /dev/hdk15 b 57 15; \ - mknod /dev/hdk16 b 57 16; \ - chown root.disk /dev/hdk*; \ - chmod 660 /dev/hdk*; \ -fi - -if [ ! -f /dev/hdl ]; then \ - echo "Making IDE5 Secondary Devices hdl's"; \ - mknod /dev/hdl b 57 64; \ - mknod /dev/hdl1 b 57 65; \ - mknod /dev/hdl2 b 57 66; \ - mknod /dev/hdl3 b 57 67; \ - mknod /dev/hdl4 b 57 68; \ - mknod /dev/hdl5 b 57 69; \ - mknod /dev/hdl6 b 57 70; \ - mknod /dev/hdl7 b 57 71; \ - mknod /dev/hdl8 b 57 72; \ - mknod /dev/hdl9 b 57 73; \ - mknod /dev/hdl10 b 57 74; \ - mknod /dev/hdl11 b 57 75; \ - mknod /dev/hdl12 b 57 76; \ - mknod /dev/hdl13 b 57 77; \ - mknod /dev/hdl14 b 57 78; \ - mknod /dev/hdl15 b 57 79; \ - mknod /dev/hdl16 b 57 80; \ - chown root.disk /dev/hdl*; \ - chmod 660 /dev/hdl*; \ -fi - diff --git a/drivers/block/MAKEDEV-IDE67 b/drivers/block/MAKEDEV-IDE67 deleted file mode 100644 index 27728be28e65..000000000000 --- a/drivers/block/MAKEDEV-IDE67 +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -# -# Andre Hedrick -# -# The song goes, "I did it the hard way..........." -# - -if [ ! -f /dev/hdm ]; then \ - echo "Making IDE6 Primary Devices hdm's"; \ - mknod /dev/hdm b 88 0; \ - mknod /dev/hdm1 b 88 1; \ - mknod /dev/hdm2 b 88 2; \ - mknod /dev/hdm3 b 88 3; \ - mknod /dev/hdm4 b 88 4; \ - mknod /dev/hdm5 b 88 5; \ - mknod /dev/hdm6 b 88 6; \ - mknod /dev/hdm7 b 88 7; \ - mknod /dev/hdm8 b 88 8; \ - mknod /dev/hdm9 b 88 9; \ - mknod /dev/hdm10 b 88 10; \ - mknod /dev/hdm11 b 88 11; \ - mknod /dev/hdm12 b 88 12; \ - mknod /dev/hdm13 b 88 13; \ - mknod /dev/hdm14 b 88 14; \ - mknod /dev/hdm15 b 88 15; \ - mknod /dev/hdm16 b 88 16; \ - chown root.disk /dev/hdm*; \ - chmod 660 /dev/hdm*; \ -fi - -if [ ! -f /dev/hdn ]; then \ - echo "Making IDE6 Secondary Devices hdn's"; \ - mknod /dev/hdn b 88 64; \ - mknod /dev/hdn1 b 88 65; \ - mknod /dev/hdn2 b 88 66; \ - mknod /dev/hdn3 b 88 67; \ - mknod /dev/hdn4 b 88 68; \ - mknod /dev/hdn5 b 88 69; \ - mknod /dev/hdn6 b 88 70; \ - mknod /dev/hdn7 b 88 71; \ - mknod /dev/hdn8 b 88 72; \ - mknod /dev/hdn9 b 88 73; \ - mknod /dev/hdn10 b 88 74; \ - mknod /dev/hdn11 b 88 75; \ - mknod /dev/hdn12 b 88 76; \ - mknod /dev/hdn13 b 88 77; \ - mknod /dev/hdn14 b 88 78; \ - mknod /dev/hdn15 b 88 79; \ - mknod /dev/hdn16 b 88 80; \ - chown root.disk /dev/hdn*; \ - chmod 660 /dev/hdn*; \ -fi - -if [ ! -f /dev/hdo ]; then \ - echo "Making IDE7 Primary Devices hdo's"; \ - mknod /dev/hdo b 89 0; \ - mknod /dev/hdo1 b 89 1; \ - mknod /dev/hdo2 b 89 2; \ - mknod /dev/hdo3 b 89 3; \ - mknod /dev/hdo4 b 89 4; \ - mknod /dev/hdo5 b 89 5; \ - mknod /dev/hdo6 b 89 6; \ - mknod /dev/hdo7 b 89 7; \ - mknod /dev/hdo8 b 89 8; \ - mknod /dev/hdo9 b 89 9; \ - mknod /dev/hdo10 b 89 10; \ - mknod /dev/hdo11 b 89 11; \ - mknod /dev/hdo12 b 89 12; \ - mknod /dev/hdo13 b 89 13; \ - mknod /dev/hdo14 b 89 14; \ - mknod /dev/hdo15 b 89 15; \ - mknod /dev/hdo16 b 89 16; \ - chown root.disk /dev/hdo*; \ - chmod 660 /dev/hdo*; \ -fi - -if [ ! -f /dev/hdp ]; then \ - echo "Making IDE7 Secondary Devices hdp's"; \ - mknod /dev/hdp b 89 64; \ - mknod /dev/hdp1 b 89 65; \ - mknod /dev/hdp2 b 89 66; \ - mknod /dev/hdp3 b 89 67; \ - mknod /dev/hdp4 b 89 68; \ - mknod /dev/hdp5 b 89 69; \ - mknod /dev/hdp6 b 89 70; \ - mknod /dev/hdp7 b 89 71; \ - mknod /dev/hdp8 b 89 72; \ - mknod /dev/hdp9 b 89 73; \ - mknod /dev/hdp10 b 89 74; \ - mknod /dev/hdp11 b 89 75; \ - mknod /dev/hdp12 b 89 76; \ - mknod /dev/hdp13 b 89 77; \ - mknod /dev/hdp14 b 89 78; \ - mknod /dev/hdp15 b 89 79; \ - mknod /dev/hdp16 b 89 80; \ - chown root.disk /dev/hdp*; \ - chmod 660 /dev/hdp*; \ -fi - diff --git a/drivers/block/Makefile b/drivers/block/Makefile index cf5c12227d0a..0cc01bc45c3c 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -94,116 +94,128 @@ else endif endif -ifeq ($(CONFIG_BLK_DEV_HD),y) -L_OBJS += hd.o +# +# IDE-STUFF +# + +ifeq ($(CONFIG_BLK_DEV_AEC6210),y) +IDE_OBJS += aec6210.o endif -ifeq ($(CONFIG_BLK_DEV_RZ1000),y) -IDE_OBJS += rz1000.o +ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) +IDE_OBJS += ali14xx.o endif -ifeq ($(CONFIG_BLK_DEV_CMD640),y) -IDE_OBJS += cmd640.o +ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) +IDE_OBJS += alim15x3.o endif -ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y) -IDE_OBJS += ide-pmac.o +ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) +IDE_OBJS += buddha.o endif -ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) -IDE_OBJS += ide-pci.o +ifeq ($(CONFIG_BLK_DEV_CMD640),y) +IDE_OBJS += cmd640.o endif -ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) -IDE_OBJS += ide-dma.o +ifeq ($(CONFIG_BLK_DEV_CMD646),y) +IDE_OBJS += cmd646.o +endif + +ifeq ($(CONFIG_BLK_DEV_CY82C693),y) +IDE_OBJS += cy82c693.o endif ifeq ($(CONFIG_BLK_DEV_DTC2278),y) IDE_OBJS += dtc2278.o endif -ifeq ($(CONFIG_BLK_DEV_HT6560B),y) -IDE_OBJS += ht6560b.o +ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y) +IDE_OBJS += falconide.o endif -ifeq ($(CONFIG_BLK_DEV_QD6580),y) -IDE_OBJS += qd6580.o +ifeq ($(CONFIG_BLK_DEV_GAYLE),y) +IDE_OBJS += gayle.o endif -ifeq ($(CONFIG_BLK_DEV_UMC8672),y) -IDE_OBJS += umc8672.o +ifeq ($(CONFIG_BLK_DEV_HD),y) +L_OBJS += hd.o endif -ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) -IDE_OBJS += ali14xx.o +ifeq ($(CONFIG_BLK_DEV_HPT34X),y) +IDE_OBJS += hpt34x.o endif -ifeq ($(CONFIG_BLK_DEV_PDC4030),y) -IDE_OBJS += pdc4030.o +ifeq ($(CONFIG_BLK_DEV_HPT366),y) +IDE_OBJS += hpt366.o endif -ifeq ($(CONFIG_BLK_DEV_TRM290),y) -IDE_OBJS += trm290.o +ifeq ($(CONFIG_BLK_DEV_HT6560B),y) +IDE_OBJS += ht6560b.o endif -ifeq ($(CONFIG_BLK_DEV_OPTI621),y) -IDE_OBJS += opti621.o +ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) +IDE_OBJS += ide-dma.o endif -ifeq ($(CONFIG_BLK_DEV_NS87415),y) -IDE_OBJS += ns87415.o +ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) +IDE_OBJS += ide-pci.o endif -ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) -IDE_OBJS += via82c586.o +ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y) +IDE_OBJS += ide-pmac.o endif -ifeq ($(CONFIG_BLK_DEV_GAYLE),y) -IDE_OBJS += gayle.o +ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y) +IDE_OBJS += macide.o endif -ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y) -IDE_OBJS += falconide.o +ifeq ($(CONFIG_BLK_DEV_NS87415),y) +IDE_OBJS += ns87415.o endif -ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y) -IDE_OBJS += macide.o +ifeq ($(CONFIG_BLK_DEV_OPTI621),y) +IDE_OBJS += opti621.o endif -ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) -IDE_OBJS += buddha.o +ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) +IDE_OBJS += pdc202xx.o endif -ifeq ($(CONFIG_BLK_DEV_CMD646),y) -IDE_OBJS += cmd646.o +ifeq ($(CONFIG_BLK_DEV_PDC4030),y) +IDE_OBJS += pdc4030.o endif -ifeq ($(CONFIG_BLK_DEV_SL82C105),y) -IDE_OBJS += sl82c105.o +ifeq ($(CONFIG_BLK_DEV_PIIX),y) +IDE_OBJS += piix.o endif -ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) -IDE_OBJS += alim15x3.o +ifeq ($(CONFIG_BLK_DEV_QD6580),y) +IDE_OBJS += qd6580.o endif -ifeq ($(CONFIG_BLK_DEV_CY82C693),y) -IDE_OBJS += cy82c693.o +ifeq ($(CONFIG_BLK_DEV_RZ1000),y) +IDE_OBJS += rz1000.o endif -ifeq ($(CONFIG_BLK_DEV_PIIX),y) -IDE_OBJS += piix.o +ifeq ($(CONFIG_BLK_DEV_SIS5513),y) +IDE_OBJS += sis5513.o endif -ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) -IDE_OBJS += pdc202xx.o +ifeq ($(CONFIG_BLK_DEV_SL82C105),y) +IDE_OBJS += sl82c105.o endif -ifeq ($(CONFIG_BLK_DEV_AEC6210),y) -IDE_OBJS += aec6210.o +ifeq ($(CONFIG_BLK_DEV_TRM290),y) +IDE_OBJS += trm290.o endif -ifeq ($(CONFIG_BLK_DEV_HPT34X),y) -IDE_OBJS += hpt34x.o +ifeq ($(CONFIG_BLK_DEV_UMC8672),y) +IDE_OBJS += umc8672.o +endif + +ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) +IDE_OBJS += via82c586.o endif ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c index 03ef37c90934..ba8d508530a3 100644 --- a/drivers/block/aec6210.c +++ b/drivers/block/aec6210.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 + * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 * - * Copyright (C) 1998 Andre Hedrick (hedrick@astro.dyer.vanderbilt.edu) + * Copyright (C) 1998-99 Andre Hedrick * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 * pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 @@ -31,7 +31,6 @@ * NO-Devices * 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02 * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 - */ #include @@ -54,10 +53,8 @@ __initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name)) { if (dev->rom_address) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", - name, dev->rom_address); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); } return dev->irq; } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 7aeff3bfb4a3..544a2958358f 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -631,7 +631,7 @@ static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) irq = pdev->irq; for(i=0; i<6; i++) - addr[i] = pdev->base_address[i]; + addr[i] = pdev->resource[i].flags; (void) pcibios_read_config_word(bus, device_fn, PCI_COMMAND,&command); @@ -665,7 +665,7 @@ DBGINFO( */ for(i=0; i<6; i++) if (!(addr[i] & 0x1)) { - c->paddr = addr[i]; + c->paddr = pdev->resource[i].start; break; } c->vaddr = remap_pci_mem(c->paddr, 128); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 934ddd06e692..801e239025cd 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -85,6 +85,10 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) * This requires special handling here. */ switch (hd->major) { + case IDE9_MAJOR: + unit += 2; + case IDE8_MAJOR: + unit += 2; case IDE7_MAJOR: unit += 2; case IDE6_MAJOR: diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c index 79df61b1fbd2..45e2bddcf56a 100644 --- a/drivers/block/hpt34x.c +++ b/drivers/block/hpt34x.c @@ -1,8 +1,7 @@ /* - * linux/drivers/block/hpt34x.c Version 0.24 July 3, 1999 + * linux/drivers/block/hpt34x.c Version 0.25 July 11, 1999 * * Copyright (C) 1998-99 Andre Hedrick - * (hedrick@astro.dyer.vanderbilt.edu) * * 00:12.0 Unknown mass storage controller: * Triones Technologies, Inc. @@ -118,9 +117,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ((int) ide_dma_off_quietly); #endif /* HPT343_DISABLE_ALL_DMAING */ - if (id->dma_ultra & 0x0004) { + if (id->dma_ultra & 0x0010) { + goto backspeed; + } else if (id->dma_ultra & 0x0008) { + goto backspeed; + } else if (id->dma_ultra & 0x0004) { +backspeed: if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0404; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -128,7 +132,7 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_UDMA_2; } else if (id->dma_ultra & 0x0002) { if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0202; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -136,7 +140,7 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_UDMA_1; } else if (id->dma_ultra & 0x0001) { if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0101; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -190,7 +194,8 @@ static int config_chipset_for_dma (ide_drive_t *drive) (void) hpt34x_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); @@ -337,47 +342,10 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) __initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) { - int i; unsigned short cmd; - unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; -#if 0 - unsigned char misc10 = inb(hpt34xIoBase + 0x0010); - unsigned char misc11 = inb(hpt34xIoBase + 0x0011); -#endif pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - - dev->base_address[0] = (hpt34xIoBase + 0x20); - dev->base_address[1] = (hpt34xIoBase + 0x34); - dev->base_address[2] = (hpt34xIoBase + 0x28); - dev->base_address[3] = (hpt34xIoBase + 0x3c); - - for(i=0; i<4; i++) - dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; - - /* - * Since 20-23 can be assigned and are R/W, we correct them. - */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]); - pci_write_config_word(dev, PCI_COMMAND, cmd); - -#if 0 - outb(misc10|0x78, (hpt34xIoBase + 0x0010)); - outb(misc11, (hpt34xIoBase + 0x0011)); -#endif - -#ifdef DEBUG - printk("%s: 0x%02x 0x%02x\n", - (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name, - inb(hpt34xIoBase + 0x0010), - inb(hpt34xIoBase + 0x0011)); -#endif - if (cmd & PCI_COMMAND_MEMORY) { if (dev->rom_address) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); @@ -385,6 +353,25 @@ __initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) } pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } else { + int i = 0; + unsigned long hpt34xIoBase = dev->resource[4].start; + + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; + /* + * Since 20-23 can be assigned and are R/W, we correct them. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); + + pci_write_config_word(dev, PCI_COMMAND, cmd); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } return dev->irq; diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c new file mode 100644 index 000000000000..20b1c8c1191c --- /dev/null +++ b/drivers/block/hpt366.c @@ -0,0 +1,493 @@ +/* + * linux/drivers/block/hpt366.c Version 0.11 August 04, 1999 + * + * Copyright (C) 1999 Andre Hedrick + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +const char *bad_ata66_4[] = { + "WDC AC310200R", + "QUANTUM FIREBALLP KA13.6", + NULL +}; + +const char *bad_ata66_3[] = { + "WDC AC310200R", + NULL +}; + +const char *bad_ata33[] = { + "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", + "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", + "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", + "Maxtor 90510D4", + "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", + "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", + "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", + NULL +}; + +struct chipset_bus_clock_list_entry { + byte xfer_speed; + unsigned int chipset_settings; +}; + +struct chipset_bus_clock_list_entry forty_base [] = { + + { XFER_UDMA_4 , 0x900fd943 }, + { XFER_UDMA_3 , 0x900ad943 }, + { XFER_UDMA_2 , 0x900bd943 }, + { XFER_UDMA_1 , 0x9008d943 }, + { XFER_UDMA_0 , 0x9008d943 }, + + { XFER_MW_DMA_2 , 0xa008d943 }, + { XFER_MW_DMA_1 , 0xa010d955 }, + { XFER_MW_DMA_0 , 0xa010d9fc }, + + { XFER_PIO_4 , 0xc008d963 }, + { XFER_PIO_3 , 0xc010d974 }, + { XFER_PIO_2 , 0xc010d997 }, + { XFER_PIO_1 , 0xc010d9c7 }, + { XFER_PIO_0 , 0xc018d9d9 }, + { 0 , 0x0120d9d9 } +}; + +struct chipset_bus_clock_list_entry thirty_three_base [] = { + + { XFER_UDMA_4 , 0x90c9a731 }, + { XFER_UDMA_3 , 0x90cfa731 }, + { XFER_UDMA_2 , 0x90caa731 }, + { XFER_UDMA_1 , 0x90cba731 }, + { XFER_UDMA_0 , 0x90c8a731 }, + + { XFER_MW_DMA_2 , 0xa0c8a731 }, + { XFER_MW_DMA_1 , 0xa0c8a732 }, /* 0xa0c8a733 */ + { XFER_MW_DMA_0 , 0xa0c8a797 }, + + { XFER_PIO_4 , 0xc0c8a731 }, + { XFER_PIO_3 , 0xc0c8a742 }, + { XFER_PIO_2 , 0xc0d0a753 }, + { XFER_PIO_1 , 0xc0d0a7a3 }, /* 0xc0d0a793 */ + { XFER_PIO_0 , 0xc0d0a7aa }, /* 0xc0d0a7a7 */ + { 0 , 0x0120a7a7 } +}; + +struct chipset_bus_clock_list_entry twenty_five_base [] = { + + { XFER_UDMA_4 , 0x90c98521 }, + { XFER_UDMA_3 , 0x90cf8521 }, + { XFER_UDMA_2 , 0x90cf8521 }, + { XFER_UDMA_1 , 0x90cb8521 }, + { XFER_UDMA_0 , 0x90cb8521 }, + + { XFER_MW_DMA_2 , 0xa0ca8521 }, + { XFER_MW_DMA_1 , 0xa0ca8532 }, + { XFER_MW_DMA_0 , 0xa0ca8575 }, + + { XFER_PIO_4 , 0xc0ca8521 }, + { XFER_PIO_3 , 0xc0ca8532 }, + { XFER_PIO_2 , 0xc0ca8542 }, + { XFER_PIO_1 , 0xc0d08572 }, + { XFER_PIO_0 , 0xc0d08585 }, + { 0 , 0x01208585 } +}; + +#define HPT366_DEBUG_DRIVE_INFO 0 +#define HPT366_ALLOW_ATA66_4 1 +#define HPT366_ALLOW_ATA66_3 1 +#define HPT366_ALLOW_ATA33_2 1 +#define HPT366_ALLOW_ATA33_1 1 +#define HPT366_ALLOW_ATA33_0 1 + +extern char *ide_xfer_verbose (byte xfer_rate); + +static int check_in_drive_lists (ide_drive_t *drive, const char **list) +{ + struct hd_driveid *id = drive->id; + + while (*list) { + if (!strcmp(*list++,id->model)) { +#ifdef DEBUG + printk("%s: Broken ASIC, BackSpeeding (U)DMA for %s\n", drive->name, id->model); +#endif /* DEBUG */ + return 1; + } + } + return 0; +} + +static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) + return chipset_table->chipset_settings; + return 0x01208585; +} + +static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) +{ + int err; + byte busclock; + +#if HPT366_DEBUG_DRIVE_INFO + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + byte regtime = (drive->select.b.unit & 0x01) ? 0x43 : 0x40; + unsigned int reg1 = 0; + unsigned int reg2 = 0; + + pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1); + pci_read_config_byte(HWIF(drive)->pci_dev, regtime|0x01, &busclock); + switch(busclock) { + case 0xd9: + reg2 = pci_bus_clock_list(speed, forty_base); + break; + case 0x85: + reg2 = pci_bus_clock_list(speed, twenty_five_base); + break; + case 0xa7: + default: + reg2 = pci_bus_clock_list(speed, thirty_three_base); + break; + } + + if (drive->id->dword_io & 1) + reg2 |= 0x80000000; + else + reg2 &= ~0x80000000; + + pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); + err = ide_config_drive_speed(drive, speed); + +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: %s drive%d (0x%08x 0x%08x) 0x%04x\n", + drive->name, ide_xfer_verbose(speed), + drive_number, reg1, reg2, err); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + return(err); +} + +/* + * This allows the configuration of ide_pci chipset registers + * for cards that learn about the drive's UDMA, DMA, PIO capabilities + * after the drive is reported by the OS. Initally for designed for + * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc. + * + * check_in_drive_lists(drive, bad_ata66_4) + * check_in_drive_lists(drive, bad_ata66_3) + * check_in_drive_lists(drive, bad_ata33) + * + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed = 0x00; + + if ((id->dma_ultra & 0x0010) && + (!check_in_drive_lists(drive, bad_ata66_4)) && + (HPT366_ALLOW_ATA66_4) && + (HWIF(drive)->udma_four)) { + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && + (!check_in_drive_lists(drive, bad_ata66_3)) && + (HPT366_ALLOW_ATA66_3) && + (HWIF(drive)->udma_four)) { + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && + (HPT366_ALLOW_ATA33_2) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && + (HPT366_ALLOW_ATA33_1) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && + (HPT366_ALLOW_ATA33_0) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) hpt366_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_chipset_for_pio (ide_drive_t *drive) +{ + unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + + byte timing, speed, pio; + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : + (drive->id->tPIO & 2) ? 0x02 : + (drive->id->tPIO & 1) ? 0x01 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + + switch(timing) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + (void) hpt366_tune_chipset(drive, speed); +} + +static void hpt366_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + switch(pio) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: speed = XFER_PIO_0;break; + } + (void) hpt366_tune_chipset(drive, speed); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + + config_chipset_for_pio(drive); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + * + * This is specific to the HPT343 UDMA bios-less chipset + * and HPT345 UDMA bios chipset (stamped HPT363) + * by HighPoint|Triones Technologies, Inc. + */ + +int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + byte reg50h = 0, reg52h = 0; + + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); +#if 0 + case ide_dma_lostirq: + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_lostirq) reg52h=0x%02x\n", drive->name, reg52h); + break; + case ide_dma_timeout: + (void) ide_dmaproc(ide_dma_off_quietly, drive); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h); + if (reg52h & 0x04) { + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h); + } + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h); + (void) ide_dmaproc(ide_dma_on, drive); + if (reg52h & 0x04) + (void) ide_dmaproc(ide_dma_off, drive); + return 1; +#endif + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +__initfunc(unsigned int pci_init_hpt366 (struct pci_dev *dev, const char *name)) +{ + byte ata66 = 0; + + pci_read_config_byte(dev, 0x5a, &ata66); + if (dev->rom_address) + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn)); + return dev->irq; +} + +__initfunc(void ide_init_hpt366 (ide_hwif_t *hwif)) +{ + hwif->tuneproc = &hpt366_tune_drive; + if (hwif->dma_base) { + byte ata66 = 0; + + hwif->dmaproc = &hpt366_dmaproc; + pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); + hwif->udma_four = (ata66 & 0x02) ? 0 : 1; + } else { + hwif->udma_four = 0; + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +} diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 5b11d33101f8..c40a5b2f6721 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -2,7 +2,7 @@ * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1998, 1999 Jens Axboe * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -243,11 +243,23 @@ * Useful when using ide-cd in conjunction with * ide-scsi. TODO: non-modular way of doing the * same. + * + * 4.54 Aug 5, 1999 - Support for MMC2 class commands through the generic + * packet interface to cdrom.c. + * - Unified audio ioctl support, most of it. + * - cleaned up various deprecated verify_area(). + * - Added ide_cdrom_packet() as the interface for + * the Uniform generic_packet(). + * - bunch of other stuff, will fill in logs later. + * - report 1 slot for non-changers, like the other + * cd-rom drivers. don't report select disc for + * non-changers as well. + * - mask out audio playing, if the device can't do it. * * *************************************************************************/ - -#define IDECD_VERSION "4.53" + +#define IDECD_VERSION "4.54" #include #include @@ -517,8 +529,8 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - int stat, err, sense_key, cmd; - + int stat, cmd, err, sense_key; + /* Check for errors. */ stat = GET_STAT(); *stat_ret = stat; @@ -526,8 +538,8 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, if (OK_STAT (stat, good_stat, BAD_R_STAT)) return 0; - /* Got an error. */ - err = IN_BYTE (IDE_ERROR_REG); + /* Get the IDE error register. */ + err = GET_ERR(); sense_key = err >> 4; if (rq == NULL) @@ -1170,8 +1182,6 @@ static int cdrom_lockdoor (ide_drive_t *drive, int lockflag, struct atapi_request_sense *reqbuf); - - /* Interrupt routine for packet command completion. */ static void cdrom_pc_intr (ide_drive_t *drive) { @@ -1385,14 +1395,15 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage && (pc->c[0] != REQUEST_SENSE && pc->c[0] != ALLOW_MEDIUM_REMOVAL && - pc->c[0] != START_STOP)) { + pc->c[0] != START_STOP && + pc->c[0] != MODE_SENSE_10 && + pc->c[0] != MODE_SELECT_10)) { (void) cdrom_lockdoor (drive, 1, NULL); } return 0; } } - /**************************************************************************** * cdrom driver request routine. */ @@ -1518,7 +1529,7 @@ cdrom_lockdoor (ide_drive_t *drive, int lockflag, struct atapi_request_sense my_reqbuf; int stat; struct packet_command pc; - + if (reqbuf == NULL) reqbuf = &my_reqbuf; @@ -1564,45 +1575,18 @@ cdrom_eject (ide_drive_t *drive, int ejectflag, { struct packet_command pc; - if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0) + if (CDROM_CONFIG_FLAGS (drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; + + /* reload fails on some drives, if the tray is locked */ + if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag) + return 0; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = START_STOP; - pc.c[4] = 2 + (ejectflag != 0); - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_pause (ide_drive_t *drive, int pauseflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PAUSE_RESUME; - pc.c[8] = !pauseflag; - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_startstop (ide_drive_t *drive, int startflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = START_STOP; - pc.c[1] = 1; - pc.c[4] = startflag; + pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } @@ -1611,8 +1595,8 @@ cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, struct atapi_request_sense *reqbuf) { struct { - unsigned lba; - unsigned blocklen; + __u32 lba; + __u32 blocklen; } capbuf; int stat; @@ -1892,7 +1876,7 @@ static int cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end, struct atapi_request_sense *reqbuf) { - int i, stat; + int i, stat = 0; struct atapi_request_sense my_reqbuf; if (reqbuf == NULL) @@ -2048,7 +2032,6 @@ cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen, return cdrom_queue_packet_command (drive, &pc); } - /* Read the drive mechanism status and slot table into our internal buffer. If the buffer does not yet exist, allocate it. */ static int @@ -2090,6 +2073,21 @@ cdrom_read_changer_info (ide_drive_t *drive) NULL); } +/* the generic packet interface to cdrom.c */ +static int ide_cdrom_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + struct packet_command pc; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + + memset(&pc, 0, sizeof(pc)); + memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); + pc.buffer = cgc->buffer; + pc.buflen = cgc->buflen; + cgc->stat = cdrom_queue_packet_command(drive, &pc); + return cgc->stat; +} + static int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, @@ -2168,19 +2166,16 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, toc = info->toc; - stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra)); - if (stat) return stat; - - copy_from_user (&ra, (void *)arg, sizeof (ra)); + if (copy_from_user(&ra, (void *)arg, sizeof (ra))) + return -EFAULT; if (ra.nframes < 0 || ra.nframes > toc->capacity) return -EINVAL; else if (ra.nframes == 0) return 0; - stat = verify_area (VERIFY_WRITE, (char *)ra.buf, - ra.nframes * CD_FRAMESIZE_RAW); - if (stat) return stat; + if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes * CD_FRAMESIZE_RAW)) + return -EFAULT; if (ra.addr_format == CDROM_MSF) lba = msf_to_lba (ra.addr.msf.minute, @@ -2208,8 +2203,7 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, buf, this_nblocks * CD_FRAMESIZE_RAW, NULL); if (stat) break; - copy_to_user (ra.buf, buf, - this_nblocks * CD_FRAMESIZE_RAW); + __copy_to_user(ra.buf, buf,this_nblocks * CD_FRAMESIZE_RAW); ra.buf += this_nblocks * CD_FRAMESIZE_RAW; ra.nframes -= this_nblocks; lba += this_nblocks; @@ -2224,11 +2218,8 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, char buffer[16]; int stat; - stat = verify_area (VERIFY_READ, (void *) arg, - sizeof (char)); - if (stat) return stat; - - copy_from_user (&spindown, (void *) arg, sizeof(char)); + if (copy_from_user(&spindown, (void *) arg, sizeof(char))) + return -EFAULT; stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, sizeof (buffer), NULL); @@ -2245,17 +2236,14 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, char buffer[16]; int stat; - stat = verify_area (VERIFY_WRITE, (void *) arg, - sizeof (char)); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, sizeof (buffer), NULL); if (stat) return stat; spindown = buffer[11] & 0x0f; - copy_to_user ((void *) arg, &spindown, sizeof (char)); + if (copy_to_user((void *) arg, &spindown, sizeof (char))) + return -EFAULT; return 0; } @@ -2268,14 +2256,14 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, memset (&pc, 0, sizeof (pc)); - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c)); - if (stat) return stat; - copy_from_user (&pc.c, (void *) arg, sizeof (pc.c)); + if (copy_from_user(&pc.c, (void *) arg, sizeof (pc.c))) + return -EFAULT; + arg += sizeof (pc.c); - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len)); - if (stat) return stat; - copy_from_user (&len, (void *) arg , sizeof (len)); + if (copy_from_user (&len, (void *) arg , sizeof (len))) + return -EFAULT; + arg += sizeof (len); lena = len; @@ -2438,70 +2426,6 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); } - case CDROMVOLCTRL: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24], mask[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 1, mask, - sizeof (buffer), NULL); - if (stat) return stat; - - buffer[1] = buffer[2] = 0; - - buffer[17] = volctrl->channel0 & mask[17]; - buffer[19] = volctrl->channel1 & mask[19]; - buffer[21] = volctrl->channel2 & mask[21]; - buffer[23] = volctrl->channel3 & mask[23]; - - return cdrom_mode_select (drive, PAGE_AUDIO, buffer, - sizeof (buffer), NULL); - } - - case CDROMVOLREAD: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; - - volctrl->channel0 = buffer[17]; - volctrl->channel1 = buffer[19]; - volctrl->channel2 = buffer[21]; - volctrl->channel3 = buffer[23]; - - return 0; - } - - case CDROMSTART: - return cdrom_startstop (drive, 1, NULL); - - case CDROMSTOP: { -#ifdef IHAVEADOLPHIN - /* Certain Drives require this. Most don't - and will produce errors upon CDROMSTOP - pit says the Dolphin needs this. If you - own a dolphin, just define IHAVEADOLPHIN somewhere */ - int stat; - stat = cdrom_startstop (drive, 0, NULL); - if (stat) return stat; - return cdrom_eject (drive, 1, NULL); -#endif /* end of IHAVEADOLPHIN */ - return cdrom_startstop (drive, 0, NULL); - } - - case CDROMPAUSE: - return cdrom_pause (drive, 1, NULL); - - case CDROMRESUME: - return cdrom_pause (drive, 0, NULL); - - default: return -EINVAL; } @@ -2534,7 +2458,6 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) return cdrom_eject (drive, !position, NULL); } - static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { @@ -2835,9 +2758,11 @@ struct cdrom_device_ops ide_cdrom_dops = { ide_cdrom_dev_ioctl, /* dev_ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN - | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET - | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ - 0 /* n_minors */ + | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS + | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD + | CDC_DVD_R| CDC_DVD_RAM | CDC_GENERIC_PACKET, /* capability */ + 0, /* n_minors */ + ide_cdrom_packet }; static int ide_cdrom_register (ide_drive_t *drive, int nslots) @@ -2853,6 +2778,25 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) *(int *)&devinfo->capacity = nslots; devinfo->handle = (void *) drive; strcpy(devinfo->name, drive->name); + + /* set capability mask to match the probe. */ + if (!CDROM_CONFIG_FLAGS (drive)->cd_r) + devinfo->mask |= CDC_CD_R; + if (!CDROM_CONFIG_FLAGS (drive)->cd_rw) + devinfo->mask |= CDC_CD_RW; + if (!CDROM_CONFIG_FLAGS (drive)->dvd) + devinfo->mask |= CDC_DVD; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_r) + devinfo->mask |= CDC_DVD_R; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram) + devinfo->mask |= CDC_DVD_RAM; + if (!CDROM_CONFIG_FLAGS (drive)->is_changer) + devinfo->mask |= CDC_SELECT_DISC; + if (!CDROM_CONFIG_FLAGS (drive)->audio_play) + devinfo->mask |= CDC_PLAY_AUDIO; + if (!CDROM_CONFIG_FLAGS (drive)->close_tray) + devinfo->mask |= CDC_CLOSE_TRAY; + return register_cdrom (devinfo); } @@ -2860,7 +2804,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - int stat, nslots = 0, attempts = 3; + int stat, nslots = 1, attempts = 3; struct { char pad[8]; struct atapi_capabilities_page cap; @@ -2891,7 +2835,11 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (buf.cap.dvd_ram_write) CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; if (buf.cap.dvd_r_write) - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 1; + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; + if (buf.cap.audio_play) + CDROM_CONFIG_FLAGS (drive)->audio_play = 1; + if (buf.cap.mechtype == 0) + CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { @@ -2931,10 +2879,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed, (CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM"); - if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_rw) + if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram) printk (" DVD%s%s", - (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-RAM" : "", - (CDROM_CONFIG_FLAGS (drive)->dvd_rw)? "/RW" : ""); + (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", + (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) printk (" CD%s%s", @@ -3060,9 +3008,11 @@ int ide_cdrom_setup (ide_drive_t *drive) CDROM_CONFIG_FLAGS (drive)->test_write = 0; CDROM_CONFIG_FLAGS (drive)->dvd = 0; CDROM_CONFIG_FLAGS (drive)->dvd_r = 0; - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 0; + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0; CDROM_CONFIG_FLAGS (drive)->no_eject = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0; + CDROM_CONFIG_FLAGS (drive)->audio_play = 0; + CDROM_CONFIG_FLAGS (drive)->close_tray = 1; /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; @@ -3196,7 +3146,6 @@ int ide_cdrom_check_media_change (ide_drive_t *drive) (drive->select.b.unit)<driver_data))->config_flags)) @@ -518,9 +520,11 @@ struct atapi_mechstat_header { #if defined(__BIG_ENDIAN_BITFIELD) __u8 mech_state : 3; - __u8 reserved1 : 5; + __u8 door_open : 1; + __u8 reserved1 : 4; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved1 : 5; + __u8 reserved1 : 4; + __u8 door_open : 1; __u8 mech_state : 3; #else #error "Please fix " @@ -653,13 +657,13 @@ const struct { { MODE_SENSE_10, "Mode Sense" }, { LOAD_UNLOAD, "Load/Unload CD" }, { READ_12, "Read(12)" }, + { GET_PERFORMANCE, "Get Performance" }, { READ_CD_MSF, "Read CD MSF" }, { SCAN, "Scan" }, { SET_CD_SPEED, "Set CD Speed" }, { PLAY_CD, "Play CD" }, { MECHANISM_STATUS, "Mechanism Status" }, { READ_CD, "Read CD" }, - { DVD_GET_PERFORMANCE, "Get Performance" }, }; diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 0cda4398cadd..008756dc7224 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -357,12 +357,11 @@ static int config_drive_for_dma (ide_drive_t *drive) /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); -#ifdef CONFIG_IDEDMA_ULTRA_66 + /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ - if ((id->field_valid & 4) && (id->word93 & 0x2000)) + if ((id->field_valid & 4) && (hwif->udma_four) && (id->word93 & 0x2000)) if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) return hwif->dmaproc(ide_dma_on, drive); -#endif /* CONFIG_IDEDMA_ULTRA_66 */ /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) @@ -443,6 +442,12 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); + case ide_dma_lostirq: + case ide_dma_timeout: + /* + * printk("ide_dmaproc: chipset supported func only: %d\n", func); + */ + return 1; default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -510,7 +515,7 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p /* * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: */ -__initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)) +unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) { unsigned long dma_base = 0; struct pci_dev *dev = hwif->pci_dev; @@ -518,7 +523,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); } else { - dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + dma_base = dev->resource[4].start; if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) { printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base); dma_base = 0; @@ -532,10 +537,6 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c switch(dev->device) { case PCI_DEVICE_ID_CMD_643: - /* - * Lets attempt to use the same Ali tricks - * to fix CMD643..... - */ #ifdef CONFIG_BLK_DEV_ALI15X3 case PCI_DEVICE_ID_AL_M5219: case PCI_DEVICE_ID_AL_M5229: @@ -550,9 +551,19 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c } break; default: - if (inb(dma_base+2) & 0x80) { - printk("%s: simplex device: DMA disabled\n", name); - dma_base = 0; + /* + * If the device claims "simplex" DMA, + * this means only one of the two interfaces + * can be trusted with DMA at any point in time. + * So we should enable DMA only on one of the + * two interfaces. + */ + if ((inb(dma_base+2) & 0x80)) { /* simplex device? */ + if ((!hwif->drives[0].present && !hwif->drives[1].present) || + (hwif->mate && hwif->mate->dma_base)) { + printk("%s: simplex device: DMA disabled\n", name); + dma_base = 0; + } } } } diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 49ccb66cedbe..66b71b3a23d0 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.8 Dec 7, 1997 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * - * Copyright (C) 1996, 1997 Gadi Oxman + * Copyright (C) 1996 - 1999 Gadi Oxman */ /* @@ -26,9 +26,12 @@ * Issue START command only if TEST UNIT READY fails. * Add work-around for IOMEGA ZIP revision 21.D. * Remove idefloppy_get_capabilities(). + * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of + * bytes requested on each interrupt to be zero. + * Thanks to for pointing this out. */ -#define IDEFLOPPY_VERSION "0.8" +#define IDEFLOPPY_VERSION "0.9" #include #include @@ -997,7 +1000,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) pc->retries++; pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ + bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { @@ -1521,9 +1524,19 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) floppy->pc = floppy->pc_stack; if (gcw.drq_type == 1) set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags); - if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 && - ((strcmp(drive->id->fw_rev, "21.D") == 0) || - (strcmp(drive->id->fw_rev, "23.D") == 0))) { + /* + * We used to check revisions here. At this point however + * I'm giving up. Just assume they are all broken, its easier. + * + * The actual reason for the workarounds was likely + * a driver bug after all rather than a firmware bug, + * and the workaround below used to hide it. It should + * be fixed as of version 1.9, but to be on the safe side + * we'll leave the limitation below for the 2.2.x tree. + */ + + if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) + { for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; } diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index f4c7733a3bce..1dc68faeef75 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pci.c Version 1.03 May 1, 1999 + * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 * * Copyright (c) 1998-1999 Andre Hedrick * @@ -52,6 +52,7 @@ #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) #define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) +#define DEVID_HPT366 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366}) #define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) @@ -106,11 +107,14 @@ extern void ide_init_rz1000(ide_hwif_t *); #endif #ifdef CONFIG_BLK_DEV_VIA82C586 +extern unsigned int pci_init_via82c568(struct pci_dev *, const char *); extern void ide_init_via82c586(ide_hwif_t *); extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase); +#define PCI_VIA82C586 &pci_init_via82c568 #define INIT_VIA82C586 &ide_init_via82c586 #define DMA_VIA82C586 &ide_dmacapable_via82c586 #else +#define PCI_VIA82C586 NULL #define INIT_VIA82C586 NULL #define DMA_VIA82C586 NULL #endif @@ -166,6 +170,26 @@ extern void ide_init_hpt34x(ide_hwif_t *); #define INIT_HPT34X NULL #endif +#ifdef CONFIG_BLK_DEV_HPT366 +extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); +extern void ide_init_hpt366(ide_hwif_t *); +#define PCI_HPT366 &pci_init_hpt366 +#define INIT_HPT366 &ide_init_hpt366 +#else +#define PCI_HPT366 NULL +#define INIT_HPT366 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_SIS5513 +extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); +extern void ide_init_sis5513(ide_hwif_t *); +#define PCI_SIS5513 &pci_init_sis5513 +#define INIT_SIS5513 &ide_init_sis5513 +#else +#define PCI_SIS5513 NULL +#define INIT_SIS5513 NULL +#endif + #define INIT_SAMURAI NULL #define INIT_CX5530 NULL @@ -183,41 +207,45 @@ typedef struct ide_pci_device_s { void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); ide_pci_enablebit_t enablebits[2]; byte bootable; + byte sixtysix; unsigned int extra; } ide_pci_device_t; static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_VP_IDE, "VP_IDE", NULL, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, - {DEVID_SIS5513, "SIS5513", NULL, NULL, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; + {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_VP_IDE, "VP_IDE", PCI_VIA82C586, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, 0 }, + {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 0, 16 }, + {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 1, 48 }, + {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 }, + {DEVID_SIS5513, "SIS5513", PCI_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 1, 0 }, + {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, 0 }, + {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 }, + {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, 16 }, + {DEVID_HPT366, "HPT366", PCI_HPT366, INIT_HPT366, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 1, 256 }, + {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0, 0 }, + {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }}; + +static byte hpt363_shared_irq = 0; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt @@ -229,27 +257,35 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT343: { - int i; unsigned short pcicmd = 0; - unsigned long hpt34xIoBase = dev->resource[4].start; pci_write_config_byte(dev, 0x80, 0x00); - - /* FIXME - this is too ugly, and looks senseless. Why not just use resource[4]? */ - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); if (!(pcicmd & PCI_COMMAND_MEMORY)) { + /* + * FIXME - this is too ugly, and looks senseless. + * Why not just use resource[4]? + * + * This was a cleaner/quicker way to get the ioports + * that the are not decode do to a flaw in the chipset + * design. + */ + + int i; + unsigned long hpt34xIoBase = dev->resource[4].start; + + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } else { pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } } + case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: case PCI_DEVICE_ID_ARTOP_ATP850UF: @@ -452,6 +488,8 @@ check_if_enabled: ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port)) + return; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { /* FIXME! This really should check that it really gets the IO/MEM part right! */ ctl = dev->resource[(2*port)+1].start; @@ -491,13 +529,12 @@ check_if_enabled: hwif->irq = hwif->channel ? 15 : 14; goto bypass_umc_dma; } - + if ((!d->sixtysix) && (hwif->udma_four)) + hwif->udma_four = 0; #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) autodma = 0; - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) - hwif->udma_four = 1; if (autodma) hwif->autodma = 1; if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || @@ -506,6 +543,7 @@ check_if_enabled: #ifdef CONFIG_BLK_DEV_HPT34X IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || #endif /* CONFIG_BLK_DEV_HPT34X */ + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); @@ -541,6 +579,44 @@ bypass_umc_dma: printk("%s: neither IDE port enabled (BIOS)\n", d->name); } +__initfunc(static void hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)) +{ + struct pci_dev *dev2; + ide_pci_device_t *d2; + unsigned char pin1 = 0, pin2 = 0; + + d2 = d; + if (PCI_FUNC(dev->devfn) & 1) + return; + + for (dev2=pci_devices; dev2; dev2=dev2->next) { + if ((dev2->vendor == dev->vendor) && + (dev2->device == dev->device) && + (PCI_FUNC(dev2->devfn) & 1)) + break; + } + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + if (dev2) { + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + hpt363_shared_irq = (pin1 != pin2) ? 1 : 0; + } + + if (hpt363_shared_irq) { + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", + d->name, pin1, pin2); + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + + if (dev2) { + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); + } +} + /* * ide_scan_pcibus() gets invoked at boot time from ide.c. * It finds all PCI IDE controllers and calls ide_setup_pci_device for them. @@ -565,6 +641,8 @@ __initfunc(void ide_scan_pcibus (void)) continue; /* CY82C693 is more than only a IDE controller */ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) continue; /* UM8886A/BF pair */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) + hpt366_device_order_fixup(dev, d); else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 76dc905dd3ce..07cc72965493 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -20,7 +20,7 @@ * Version 1.04 fixed buggy treatments of known flash memory cards * * Version 1.05 fix for (hwif->chipset == ide_pdc4030) - * added ide6/7 + * added ide6/7/8/9 * allowed for secondary flash card to be detectable * with new flag : drive->ata_flash : 1; */ @@ -762,6 +762,12 @@ static int hwif_init (ide_hwif_t *hwif) #endif #if MAX_HWIFS > 7 case IDE7_MAJOR: rfn = &do_ide7_request; break; +#endif +#if MAX_HWIFS > 8 + case IDE8_MAJOR: rfn = &do_ide8_request; break; +#endif +#if MAX_HWIFS > 9 + case IDE9_MAJOR: rfn = &do_ide9_request; break; #endif default: printk("%s: request_fn NOT DEFINED\n", hwif->name); diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index ed278655ea90..a9b6941b48d7 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -3583,8 +3583,8 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) /* * These two ide-pci host adapters appear to need this disabled. */ - if ((hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || - (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { + if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || + (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { drive->dsc_overlap = 0; } else #endif /* CONFIG_BLK_DEV_IDEPCI */ diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 9a09e7ec37bc..650594771b46 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.19 January 29, 1999 + * linux/drivers/block/ide.c Version 6.20 July 10, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -93,19 +93,28 @@ * Version 6.17 fix for newest EZ-Drive problem * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" * Version 6.19 Re-design for a UNIFORM driver for all platforms, - * model based on suggestions from Russell King and - * Geert Uytterhoeven + * model based on suggestions from Russell King and + * Geert Uytterhoeven * Promise DC4030VL now supported. + * add support for ide6/ide7 * delay_50ms() changed to ide_delay_50ms() and exported. + * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection. + * Added hdx=flash to allow for second flash disk + * detection w/o the hang loop. + * Added support for ide8/ide9 + * Added idex=ata66 for the quirky chipsets that are + * ATA-66 compliant, but have yet to determine a method + * of verification of the 80c cable presence. + * Specifically Promise's PDC20262 chipset. * - * Some additional driver compile-time options are in ide.h + * Some additional driver compile-time options are in ./include/linux/ide.h * * To do, in likely order of completion: * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f */ -#define REVISION "Revision: 6.19" -#define VERSION "Id: ide.c 6.19 1999/01/29" +#define REVISION "Revision: 6.20" +#define VERSION "Id: ide.c 6.20 1999/07/10" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -144,7 +153,11 @@ extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/ #endif -static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR }; +static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, + IDE2_MAJOR, IDE3_MAJOR, + IDE4_MAJOR, IDE5_MAJOR, + IDE6_MAJOR, IDE7_MAJOR, + IDE8_MAJOR, IDE9_MAJOR }; static int idebus_parameter; /* holds the "idebus=" parameter */ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ @@ -1308,6 +1321,20 @@ void do_ide7_request (void) } #endif /* MAX_HWIFS > 7 */ +#if MAX_HWIFS > 8 +void do_ide8_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[8].hwgroup); +} +#endif /* MAX_HWIFS > 8 */ + +#if MAX_HWIFS > 9 +void do_ide9_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[9].hwgroup); +} +#endif /* MAX_HWIFS > 9 */ + static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) { unsigned long flags; @@ -1347,6 +1374,7 @@ void ide_timer_expiry (unsigned long data) handler(drive); } else if (drive_is_ready(drive)) { printk("%s: lost interrupt\n", drive->name); + (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive); spin_unlock_irqrestore(&hwgroup->spinlock, flags); handler(drive); } else { @@ -1357,6 +1385,7 @@ void ide_timer_expiry (unsigned long data) * need something here for HPT34X.......AMH * irq timeout: status=0x58 { DriveReady SeekComplete DataRequest } */ + (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); } spin_unlock_irqrestore(&hwgroup->spinlock, flags); ide_error(drive, "irq timeout", GET_STAT()); @@ -1957,7 +1986,7 @@ int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) } for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; - if ((!hwif->present && !initializing) || + if ((!hwif->present && !hwif->mate && !initializing) || (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } @@ -2641,6 +2670,10 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * "idex=four" : four drives on idex and ide(x^1) share same ports * "idex=reset" : reset interface before first use * "idex=dma" : enable DMA by default on both drives if possible + * "idex=ata66" : informs the interface that it has an 80c cable + * for chipsets that are ATA-66 capable, but + * the ablity to bit test for detection is + * currently unknown. * * "splitfifo=betweenChan" * : FIFO Configuration of VIA 82c586(,"A"or"B"). @@ -2828,9 +2861,12 @@ __initfunc(void ide_setup (char *s)) if (s[3] >= '0' && s[3] <= max_hwif) { /* * Be VERY CAREFUL changing this: note hardcoded indexes below + * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding. */ - const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "four", - "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL}; + const char *ide_words[] = { + "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", + "minus8", "minus9", "minus10", + "four", "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -2838,19 +2874,19 @@ __initfunc(void ide_setup (char *s)) /* * Cryptic check to ensure chipset not already set for hwif: */ - if (i > 0 || i <= -7) { /* is parameter a chipset name? */ + if (i > 0 || i <= -11) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i <= -7 && i != -14 && hw != 0) + if (i <= -11 && i != -18 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ - if (i <= -7 && i != -14 && ide_hwifs[hw+1].chipset != ide_unknown) + if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } switch (i) { #ifdef CONFIG_BLK_DEV_PDC4030 - case -14: /* "dc4030" */ + case -18: /* "dc4030" */ { extern void init_pdc4030(void); init_pdc4030(); @@ -2858,7 +2894,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_PDC4030 */ #ifdef CONFIG_BLK_DEV_ALI14XX - case -13: /* "ali14xx" */ + case -17: /* "ali14xx" */ { extern void init_ali14xx (void); init_ali14xx(); @@ -2866,7 +2902,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_ALI14XX */ #ifdef CONFIG_BLK_DEV_UMC8672 - case -12: /* "umc8672" */ + case -16: /* "umc8672" */ { extern void init_umc8672 (void); init_umc8672(); @@ -2874,7 +2910,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_UMC8672 */ #ifdef CONFIG_BLK_DEV_DTC2278 - case -11: /* "dtc2278" */ + case -15: /* "dtc2278" */ { extern void init_dtc2278 (void); init_dtc2278(); @@ -2882,7 +2918,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_DTC2278 */ #ifdef CONFIG_BLK_DEV_CMD640 - case -10: /* "cmd640_vlb" */ + case -14: /* "cmd640_vlb" */ { extern int cmd640_vlb; /* flag for cmd640.c */ cmd640_vlb = 1; @@ -2890,7 +2926,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_CMD640 */ #ifdef CONFIG_BLK_DEV_HT6560B - case -9: /* "ht6560b" */ + case -13: /* "ht6560b" */ { extern void init_ht6560b (void); init_ht6560b(); @@ -2898,7 +2934,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_HT6560B */ #if CONFIG_BLK_DEV_QD6580 - case -8: /* "qd6580" */ + case -12: /* "qd6580" */ { extern void init_qd6580 (void); init_qd6580(); @@ -2906,7 +2942,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_QD6580 */ #ifdef CONFIG_BLK_DEV_4DRIVES - case -7: /* "four" drives on one set of ports */ + case -11: /* "four" drives on one set of ports */ { ide_hwif_t *mate = &ide_hwifs[hw^1]; mate->drives[0].select.all ^= 0x20; @@ -2917,6 +2953,18 @@ __initfunc(void ide_setup (char *s)) goto do_serialize; } #endif /* CONFIG_BLK_DEV_4DRIVES */ + case -10: /* minus10 */ + case -9: /* minus9 */ + case -8: /* minus8 */ + goto bad_option; + case -7: /* ata66 */ +#ifdef CONFIG_BLK_DEV_IDEPCI + hwif->udma_four = 1; + goto done; +#else /* !CONFIG_BLK_DEV_IDEPCI */ + hwif->udma_four = 0; + goto bad_hwif; +#endif /* CONFIG_BLK_DEV_IDEPCI */ case -6: /* dma */ hwif->autodma = 1; goto done; @@ -3425,6 +3473,12 @@ EXPORT_SYMBOL(do_ide6_request); #if MAX_HWIFS > 7 EXPORT_SYMBOL(do_ide7_request); #endif /* MAX_HWIFS > 7 */ +#if MAX_HWIFS > 8 +EXPORT_SYMBOL(do_ide8_request); +#endif /* MAX_HWIFS > 8 */ +#if MAX_HWIFS > 9 +EXPORT_SYMBOL(do_ide9_request); +#endif /* MAX_HWIFS > 9 */ /* * Driver module diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 6d48504e870f..be51cd8da001 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -486,6 +486,8 @@ void make_request(int major,int rw, struct buffer_head * bh) case IDE5_MAJOR: case IDE6_MAJOR: case IDE7_MAJOR: + case IDE8_MAJOR: + case IDE9_MAJOR: case ACSI_MAJOR: case MFM_ACORN_MAJOR: /* diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index 08f87655e81a..abd49660f7a1 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -215,8 +215,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) byte test1, test2, speed; byte AP, BP, CP, DP, EP; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - byte udma_66 = ((id->word93 & 0x2000) && (dev->device == PCI_DEVICE_ID_PROMISE_20262)) ? 1 : 0; - byte udma_33 = ultra ? (inb((dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; + byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_33 = ultra ? (inb((dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; pci_read_config_byte(dev, 0x50, &EP); @@ -308,7 +308,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_3; } else if ((id->dma_ultra & 0x0004) && (udma_33)) { if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0404; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -319,7 +319,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_2; } else if ((id->dma_ultra & 0x0002) && (udma_33)) { if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0202; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -330,7 +330,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_1; } else if ((id->dma_ultra & 0x0001) && (udma_33)) { if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0101; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -493,7 +493,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name)) { - unsigned long high_16 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; byte udma_speed_flag = inb(high_16 + 0x001f); byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); @@ -551,5 +551,20 @@ __initfunc(void ide_init_pdc202xx (ide_hwif_t *hwif)) { if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; + + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20262: +#if 0 + { + unsigned long high_16 = hwif->pci_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + hwif->udma_four = 1; + } +#endif + break; + case PCI_DEVICE_ID_PROMISE_20246: + default: + hwif->udma_four = 0; + break; + } } } diff --git a/drivers/block/piix.c b/drivers/block/piix.c index 384712603e35..b1fd76014baa 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.24 June 28, 1999 + * linux/drivers/block/piix.c Version 0.25 July 11, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer @@ -149,18 +149,19 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) #ifdef CONFIG_BLK_DEV_PIIX_TUNING -static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) +static int piix_config_drive_for_dma(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long flags; int sitre; short reg4042, reg44, reg48, reg4a; byte speed; int u_speed; - byte maslave = hwif->channel ? 0x42 : 0x40; + + byte maslave = hwif->channel ? 0x42 : 0x40; + int ultra = (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; @@ -171,9 +172,6 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - save_flags(flags); - cli(); - if (id->dma_ultra && (ultra)) { if (!(reg48 & u_flag)) { pci_write_config_word(dev, 0x48, reg48|u_flag); @@ -184,7 +182,12 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) } } - if ((id->dma_ultra & 0x0004) && (ultra)) { + if ((id->dma_ultra & 0x0010) && (ultra)) { + goto backspeed; + } else if ((id->dma_ultra & 0x0008) && (ultra)) { + goto backspeed; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { +backspeed: drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; if (!((id->dma_ultra >> 8) & 4)) { @@ -256,7 +259,6 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); } - restore_flags(flags); piix_tune_drive(drive, piix_dma_2_pio(speed)); (void) ide_config_drive_speed(drive, speed); @@ -269,7 +271,8 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) printk("\n"); #endif /* PIIX_DEBUG_DRIVE_INFO */ - return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); @@ -277,10 +280,9 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; switch (func) { case ide_dma_check: - return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive, ultra), drive); + return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive), drive); default : break; } @@ -292,12 +294,14 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) void ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; -#ifdef CONFIG_BLK_DEV_PIIX_TUNING + if (hwif->dma_base) { +#ifdef CONFIG_BLK_DEV_PIIX_TUNING hwif->dmaproc = &piix_dmaproc; - } else #endif /* CONFIG_BLK_DEV_PIIX_TUNING */ - { + hwif->drives[0].autotune = 0; + hwif->drives[1].autotune = 0; + } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c new file mode 100644 index 000000000000..948fb2d5fd1f --- /dev/null +++ b/drivers/block/sis5513.c @@ -0,0 +1,418 @@ +/* + * linux/drivers/block/sis5513.c Version 0.06 July 11, 1999 + * + * Copyright (C) 1999 Andre Hedrick + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +static struct pci_dev *host_dev; + +#define SIS5513_DEBUG_DRIVE_INFO 0 + +extern char *ide_xfer_verbose (byte xfer_rate); + +/* + * ((id->word93 & 0x2000) && (HWIF(drive)->udma_four)) + */ +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + byte drive_pci, test1, test2, mask; + int err; + + byte speed = 0x00; + byte unmask = 0xE0; + byte four_two = 0x00; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_620: + unmask = 0xF0; + four_two = 0x01; + default: + break; + } + } + + switch(drive_number) { + case 0: drive_pci = 0x40;break; + case 1: drive_pci = 0x42;break; + case 2: drive_pci = 0x44;break; + case 3: drive_pci = 0x46;break; + default: return ide_dma_off; + } + + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + + if ((!ultra) && (test2 & 0x80)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + } + + if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & 0x90)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); + } + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & 0xA0)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); + } + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + mask = (four_two) ? 0xB0 : 0xA0; + if (!(test2 & mask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|mask); + } + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + mask = (four_two) ? 0xD0 : 0xC0; + if (!(test2 & mask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|mask); + } + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & unmask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|unmask); + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + err = ide_config_drive_speed(drive, speed); + +#if SIS5513_DEBUG_DRIVE_INFO + printk("%s: %s drive%d\n", + drive->name, + ide_xfer_verbose(speed), + drive_number); +#endif /* SIS5513_DEBUG_DRIVE_INFO */ + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_drive_art_rwp (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + byte timing, pio, drive_pci, test1, test2; + + unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + + if (drive->media == ide_disk) { + struct pci_dev *dev = hwif->pci_dev; + byte reg4bh = 0; + byte rw_prefetch = (0x11 << drive_number); + + pci_read_config_byte(dev, 0x4b, ®4bh); + if ((reg4bh & rw_prefetch) != rw_prefetch) + pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); + } + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + +/* + * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4 + * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns) + * 0x41 2:0 bits 000 110 100 011 011 + * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns) + * 0x40 3:0 bits 0000 0111 0100 0011 0001 + * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) + */ + + switch(drive_number) { + case 0: drive_pci = 0x40;break; + case 1: drive_pci = 0x42;break; + case 2: drive_pci = 0x44;break; + case 3: drive_pci = 0x46;break; + default: return; + } + + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + + /* + * Do a blanket clear of active and recovery timings. + */ + + test1 &= ~0x07; + test2 &= ~0x0F; + + switch(timing) { + case 4: test1 |= 0x01;test2 |= 0x03;break; + case 3: test1 |= 0x03;test2 |= 0x03;break; + case 2: test1 |= 0x04;test2 |= 0x04;break; + case 1: test1 |= 0x07;test2 |= 0x06;break; + default: break; + } + + pci_write_config_byte(dev, drive_pci, test1); + pci_write_config_byte(dev, drive_pci|0x01, test2); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_off_quietly; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + return HWIF(drive)->dmaproc(ide_dma_off, drive); + } + + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, 1); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, 0); + } + } else if ((ide_dmaproc(ide_dma_good_drive, drive)) && + (id->eide_dma_time > 150)) { + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, 0); + } + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ +int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + config_drive_art_rwp(drive); + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +__initfunc(unsigned int pci_init_sis5513 (struct pci_dev *dev, const char *name)) +{ + struct pci_dev *host; + byte latency = 0, reg48h = 0; + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); + pci_read_config_byte(dev, 0x48, ®48h); + + for (host = pci_devices; host; host=host->next) { + if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_620) { + if (latency != 0x10) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + host_dev = host; + printk("%s: Chipset Core ATA-66, SiS620\n", name); + printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", + name, + (reg48h & 0x10) ? "33" : "66", + (reg48h & 0x20) ? "33" : "66"); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_530) { + host_dev = host; + printk("%s: Chipset Core ATA-66, SiS530\n", name); + printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", + name, + (reg48h & 0x10) ? "33" : "66", + (reg48h & 0x20) ? "33" : "66"); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_5600) { + host_dev = host; + printk("SIS5600:%s Chipset Core ATA-33\n", name); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_5597) { + host_dev = host; + printk("SIS5597:%s Chipset Core ATA-33\n", name); + break; + } + } + + if (host_dev) { + byte reg52h = 0; + + pci_read_config_byte(dev, 0x52, ®52h); + if (!(reg52h & 0x04)) + pci_write_config_byte(dev, 0x52, reg52h|0x04); + } + + return 0; +} + +__initfunc(void ide_init_sis5513 (ide_hwif_t *hwif)) +{ + byte reg48h = 0; + byte mask = hwif->channel ? 0x20 : 0x10; + + pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); + hwif->irq = hwif->channel ? 15 : 14; + + if (!(hwif->dma_base)) + return; + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_620: + hwif->autodma = 1; + hwif->udma_four = (reg48h & mask) ? 0 : 1; + hwif->dmaproc = &sis5513_dmaproc; + return; + case PCI_DEVICE_ID_SI_5600: + case PCI_DEVICE_ID_SI_5597: + hwif->autodma = 1; + hwif->udma_four = 0; + hwif->dmaproc = &sis5513_dmaproc; + return; + default: + hwif->autodma = 0; + hwif->udma_four = 0; + return; + } + } +} diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 2f08740eadfe..75e18c17aeda 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -1,3 +1,14 @@ +/* + * drivers/block/sl82c105.c + * + * SL82C105/Winbond 553 IDE driver + * + * Maintainer unknown. + * + * Drive tuning added from Corel Computer's kernel sources + * -- Russell King (15/11/98) linux@arm.linux.org.uk + */ + #include #include #include @@ -15,9 +26,108 @@ #include "ide_modes.h" +#ifdef CONFIG_ARCH_NETWINDER +/* + * Convert a PIO mode and cycle time to the required on/off + * times for the interface. This has protection against run-away + * timings. + */ +static unsigned int get_timing_sl82c105(ide_pio_data_t *p) +{ + unsigned int cmd_on; + unsigned int cmd_off; + + cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; + cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30; + + if (cmd_on > 32) + cmd_on = 32; + if (cmd_on == 0) + cmd_on = 1; + + if (cmd_off > 32) + cmd_off = 32; + if (cmd_off == 0) + cmd_off = 1; + + return (cmd_on - 1) << 8 | (cmd_off - 1); +} + +/* + * Tell the drive to enable the specified PIO mode. + * This should be in ide.c, maybe as a special command + * (see do_special). + */ +static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + + if (pio > 2) { + /* FIXME: I don't believe that this SELECT_DRIVE is required, + * since ide.c only calls tuneproc from do_special, after + * the correct drive has been selected. + */ + SELECT_DRIVE(hwif, drive); + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(0x08 | pio, IDE_NSECTOR_REG); + OUT_BYTE(0x03, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + + if (ide_wait_stat(drive, DRIVE_READY, + BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) { + printk("%s: drive not ready for command\n", + drive->name); + return 1; + } + + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); + } + + return 0; +} + +/* + * We only deal with PIO mode here - DMA mode 'using_dma' is not + * initialised at the point that this function is called. + */ +static void tune_sl82c105(ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + ide_pio_data_t p; + unsigned int drv_ctrl = 0x909; + + pio = ide_get_best_pio_mode(drive, pio, 5, &p); + + if (!ide_set_drive_pio_mode(drive, pio)) { + drv_ctrl = get_timing_sl82c105(&p); + + if (p.use_iordy) + drv_ctrl |= 0x40; + } + + pci_write_config_word(dev, + (hwif->channel ? 0x4c : 0x44) + + (drive->select.b.unit ? 4 : 0), + drv_ctrl); + + printk("%s: selected PIO mode %d (%dns)\n", + drive->name, p.pio_mode, p.cycle_time); +} +#endif + void ide_init_sl82c105(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; + +#ifdef CONFIG_ARCH_NETWINDER + unsigned char ctrl_stat; + + pci_read_config_byte(dev, 0x40, &ctrl_stat); + pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33); + + hwif->tuneproc = tune_sl82c105; +#else unsigned short t16; unsigned int t32; pci_read_config_word(dev, PCI_COMMAND, &t16); @@ -33,4 +143,5 @@ void ide_init_sl82c105(ide_hwif_t *hwif) printk("IDE control/status register: %08x\n",t32); pci_write_config_dword(dev, 0x40, 0x10ff08a1); #endif /* CONFIG_MBX */ +#endif } diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index c4f96d49206b..8476a8088d9a 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -220,7 +220,7 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) struct pci_dev *dev = hwif->pci_dev; hwif->chipset = ide_trm290; - cfgbase = dev->base_address[4]; + cfgbase = dev->resource[4].start; if ((dev->class & 5) && cfgbase) { hwif->config_data = cfgbase & PCI_BASE_ADDRESS_IO_MASK; diff --git a/drivers/block/via82c586.c b/drivers/block/via82c586.c index 7dd6eb321cf1..85084fd6f34e 100644 --- a/drivers/block/via82c586.c +++ b/drivers/block/via82c586.c @@ -1,8 +1,8 @@ /* - * linux/drivers/block/via82c586.c Version 0.03 Nov. 19, 1998 + * linux/drivers/block/via82c586.c Version 0.04 July 11, 1999 * * Copyright (C) 1998 Michel Aubry, Maintainer - * Copyright (C) 1998 Andre Hedrick, Integrater + * Copyright (C) 1998 Andre Hedrick, Maintainer * * The VIA MVP-3 is reported OK with UDMA. * The TX Pro III is also reported OK with UDMA. @@ -57,6 +57,9 @@ #include +static struct pci_dev *host_dev; +static struct pci_dev *isa_dev; + #define DISPLAY_VIA_TIMINGS #if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) @@ -438,6 +441,137 @@ static int via_set_fifoconfig(ide_hwif_t *hwif) return 0; } +__initfunc(unsigned int pci_init_via82c568 (struct pci_dev *dev, const char *name)) +{ + struct pci_dev *host; + struct pci_dev *isa; + + byte revision = 0; + + for (host = pci_devices; host; host=host->next) { + if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C585) { + host_dev = host; + printk("VT 82C585 Apollo VP1/VPX"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C595) { + host_dev = host; + printk("VT 82C595 Apollo VP2"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C597_0) { + host_dev = host; + printk("VT 82C597 Apollo VP3"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C598_0) { + host_dev = host; + printk("VT 82C598 Apollo MVP3"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } else if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C680) { + host_dev = host; + printk("VT 82C680 Apollo P6"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C691) { + host_dev = host; + printk("VT 82C691 Apollo Pro"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C693) { + host_dev = host; + printk("VT 82C693 Apollo Pro Plus"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } + } + return 0; +} + +__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif)) +{ + set_via_timings(hwif); +} + /* * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) * checks if channel "channel" of if hwif is dma @@ -464,9 +598,3 @@ void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } } - -__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif)) -{ - set_via_timings(hwif); -} - diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2e68d007b1da..be5fea015d7e 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1,7 +1,7 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. Copyright (c) 1997, 1998 Erik Andersen - Copyright (c) 1998, 1999 Jens Axboe + Copyright (c) 1998, 1999 Jens Axboe May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -125,11 +125,29 @@ -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of CDC_CLOSE_TRAY. -- proc info didn't mask against capabilities mask. + + 3.00 Aug 5, 1999 - Jens Axboe + -- Unified audio ioctl handling across CD-ROM drivers. A lot of the + code was duplicated before. Drives that support the generic packet + interface are now being fed packets from here instead. + -- First attempt at adding support for MMC2 commands - for DVD and + CD-R(W) drives. Only the DVD parts are in now - the interface used is + the same as for the audio ioctls. + -- ioctl cleanups. if a drive couldn't play audio, it didn't get + a change to perform device specific ioctls as well. + -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities. + -- Put in sysctl files for autoclose, autoeject, check_media, debug, + and lock. + -- /proc/sys/dev/cdrom/info has been updated to also contain info about + CD-Rx and DVD capabilities. + -- Now default to checking media type. + -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for + doing this anyway, with the generic_packet addition. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 2.55" -#define VERSION "Id: cdrom.c 2.55 1999/04/25" +#define REVISION "Revision: 3.00" +#define VERSION "Id: cdrom.c 3.00 1999/08/05" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -172,7 +190,7 @@ static int keeplocked = 0; static int autoclose=1; static int autoeject=0; static int lockdoor = 1; -static int check_media_type = 0; +static int check_media_type = 1; MODULE_PARM(debug, "i"); MODULE_PARM(autoclose, "i"); MODULE_PARM(autoeject, "i"); @@ -194,8 +212,12 @@ MODULE_PARM(check_media_type, "i"); #define IOCTL_OUT(arg, type, out) \ copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT) +/* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in + a lot of places. This macro makes the code more clear. */ +#define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & type) -#define FM_WRITE 0x2 /* file mode write bit */ +/* used in the audio ioctls */ +#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret /* Not-exported routines. */ static int cdrom_open(struct inode *ip, struct file *fp); @@ -208,6 +230,8 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi, struct cdrom_device_ops * cdo); static void sanitize_format(union cdrom_addr *addr, u_char * curr, u_char requested); +static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg); #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ @@ -269,13 +293,14 @@ int register_cdrom(struct cdrom_device_info *cdi) ENSURE(reset, CDC_RESET); ENSURE(audio_ioctl, CDC_PLAY_AUDIO); ENSURE(dev_ioctl, CDC_IOCTLS); + ENSURE(generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; cdo->n_minors = 0; cdi->options = CDO_USE_FFLAGS; - if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY) + if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) cdi->options |= (int) CDO_AUTO_CLOSE; - if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) + if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY)) cdi->options |= (int) CDO_AUTO_EJECT; if (lockdoor==1) cdi->options |= (int) CDO_LOCK; @@ -347,7 +372,7 @@ int cdrom_open(struct inode *ip, struct file *fp) cdinfo(CD_OPEN, "entering cdrom_open\n"); if (cdi == NULL) return -ENODEV; - if (fp->f_mode & FM_WRITE) + if (fp->f_mode & FMODE_WRITE) return -EROFS; purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); if (purpose) @@ -377,7 +402,7 @@ int open_for_data(struct cdrom_device_info * cdi) if (ret == CDS_TRAY_OPEN) { cdinfo(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ - if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY && + if (CDROM_CAN(CDC_CLOSE_TRAY) && cdi->options & CDO_AUTO_CLOSE) { cdinfo(CD_OPEN, "trying to close the tray.\n"); ret=cdo->tray_move(cdi,0); @@ -442,8 +467,7 @@ int open_for_data(struct cdrom_device_info * cdi) cdinfo(CD_OPEN, "open device failed.\n"); goto clean_up_and_return; } - if (cdo->capability & ~cdi->mask & CDC_LOCK && - cdi->options & CDO_LOCK) { + if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); } @@ -457,8 +481,7 @@ int open_for_data(struct cdrom_device_info * cdi) is a goto to avoid bloating the driver with redundant code. */ clean_up_and_return: cdinfo(CD_WARNING, "open failed.\n"); - if (cdo->capability & ~cdi->mask & CDC_LOCK && - cdi->options & CDO_LOCK) { + if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 0); cdinfo(CD_OPEN, "door unlocked.\n"); } @@ -482,7 +505,7 @@ int check_for_audio_disc(struct cdrom_device_info * cdi, if (ret == CDS_TRAY_OPEN) { cdinfo(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ - if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY && + if (CDROM_CAN(CDC_CLOSE_TRAY) && cdi->options & CDO_AUTO_CLOSE) { cdinfo(CD_OPEN, "trying to close the tray.\n"); ret=cdo->tray_move(cdi,0); @@ -553,8 +576,7 @@ int cdrom_release(struct inode *ip, struct file *fp) if (sb) invalidate_inodes(sb); invalidate_buffers(dev); if (opened_for_data && - cdi->options & CDO_AUTO_EJECT && - cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) + cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) cdo->tray_move(cdi, 1); } return 0; @@ -572,7 +594,7 @@ int media_changed(struct cdrom_device_info *cdi, int queue) unsigned int mask = (1 << (queue & 1)); int ret = !!(cdi->mc_flags & mask); - if (!(cdi->ops->capability & ~cdi->mask & CDC_MEDIA_CHANGED)) + if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return ret; /* changed since last call? */ if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { @@ -594,7 +616,7 @@ int cdrom_media_changed(kdev_t dev) return 0; if (cdi->ops->media_changed == NULL) return 0; - if (!(cdi->ops->capability & ~cdi->mask & CDC_MEDIA_CHANGED)) + if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return 0; return (media_changed(cdi, 0)); } @@ -610,7 +632,7 @@ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) tracks->xa=0; tracks->error=0; cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); - if (!(cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)) { + if (!CDROM_CAN(CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; } @@ -684,6 +706,375 @@ void sanitize_format(union cdrom_addr *addr, *curr = requested; } +/* DVD handling */ + +#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) +#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge)) + +static void setup_report_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type) +{ + cgc->cmd[0] = DVD_REPORT_KEY; + cgc->cmd[10] = type | (agid << 6); +} + +static void setup_send_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type) +{ + cgc->cmd[0] = DVD_SEND_KEY; + cgc->cmd[10] = type | (agid << 6); +} + +static int dvd_do_auth (struct cdrom_device_info *cdi, dvd_authinfo *ai) +{ + int rv; + u_char buf[20]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(&cgc, 0, sizeof(cgc)); + memset(buf, 0x93, sizeof(buf)); + cgc.buffer = buf; + + switch (ai->type) { + /* LU data send */ + case DVD_LU_SEND_AGID: + cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_AGID\n"); + setup_report_key (&cgc, 0, 0); + cgc.buflen = cgc.cmd[9] = 8; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + ai->lsa.agid = buf[7] >> 6; + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_KEY1: + cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_KEY1\n"); + setup_report_key (&cgc, ai->lsk.agid, 2); + cgc.buflen = cgc.cmd[9] = 12; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + copy_key(ai->lsk.key, &buf[4]); + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_CHALLENGE: + cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_CHALLENGE\n"); + setup_report_key (&cgc, ai->lsc.agid, 1); + cgc.buflen = cgc.cmd[9] = 16; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + copy_chal(ai->lsc.chal, &buf[4]); + /* Returning data, let host change state */ + break; + + /* Post-auth key */ + case DVD_LU_SEND_TITLE_KEY: + cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_TITLE_KEY\n"); + setup_report_key (&cgc, ai->lstk.agid, 4); + cgc.cmd[5] = ai->lstk.lba; + cgc.cmd[4] = ai->lstk.lba >> 8; + cgc.cmd[3] = ai->lstk.lba >> 16; + cgc.cmd[2] = ai->lstk.lba >> 24; + cgc.buflen = cgc.cmd[9] = 12; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + ai->lstk.cpm = (buf[4] >> 7) & 1; + ai->lstk.cp_sec = (buf[4] >> 6) & 1; + ai->lstk.cgms = (buf[4] >> 4) & 3; + copy_key (ai->lstk.title_key, &buf[5]); + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_ASF: + cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_ASF\n"); + setup_report_key (&cgc, ai->lsasf.agid, 5); + cgc.buflen = cgc.cmd[9] = 8; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + ai->lsasf.asf = buf[7] & 1; + break; + + /* LU data receive (LU changes state) */ + case DVD_HOST_SEND_CHALLENGE: + cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n"); + setup_send_key (&cgc, ai->hsc.agid, 1); + cgc.buflen = -(cgc.cmd[9] = 16); + buf[1] = 14; + copy_chal (&buf[4], ai->hsc.chal); + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + ai->type = DVD_LU_SEND_KEY1; + break; + + case DVD_HOST_SEND_KEY2: + cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n"); + setup_send_key (&cgc, ai->hsk.agid, 3); + cgc.buflen = -(cgc.cmd[9] = 12); + buf[1] = 10; + copy_key (&buf[4], ai->hsk.key); + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) { + ai->type = DVD_AUTH_FAILURE; + return rv; + } + ai->type = DVD_AUTH_ESTABLISHED; + break; + + /* Misc */ + case DVD_INVALIDATE_AGID: + cdinfo(CD_DO_IOCTL, "entering DVD_INVALIDATE_AGID\n"); + setup_report_key (&cgc, ai->lsasf.agid, 0x3f); + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + break; + + default: + cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); + return -ENOTTY; + } + + return 0; +} + +static int dvd_read_physical (struct cdrom_device_info *cdi, dvd_struct *s) +{ + int rv, i; + u_char buf[4 + 4 * 20], *base; + struct dvd_layer *layer; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(buf, 0, sizeof(buf)); + memset(&cgc, 0, sizeof(cgc)); + cgc.buffer = buf; + cgc.buflen = sizeof(buf); + cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[6] = s->physical.layer_num; + cgc.cmd[7] = s->type; + cgc.cmd[9] = cgc.buflen & 0xff; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + base = &buf[4]; + layer = &s->physical.layer[0]; + + /* place the data... really ugly, but at least we won't have to + worry about endianess in userspace or here. */ + for (i = 0; i < 4; ++i, base += 20, ++layer) { + memset (layer, 0, sizeof (*layer)); + layer->book_version = base[0] & 0xf; + layer->book_type = base[0] >> 4; + layer->min_rate = base[1] & 0xf; + layer->disc_size = base[1] >> 4; + layer->layer_type = base[2] & 0xf; + layer->track_path = (base[2] >> 4) & 1; + layer->nlayers = (base[2] >> 5) & 3; + layer->track_density = base[3] & 0xf; + layer->linear_density = base[3] >> 4; + layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; + layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; + layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; + layer->bca = base[16] >> 7; + } + + return 0; +} + +static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int rv; + u_char buf[8]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(buf, 0, sizeof(buf)); + memset(&cgc, 0, sizeof(cgc)); + cgc.buffer = buf; + cgc.buflen = sizeof(buf); + cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[6] = s->copyright.layer_num; + cgc.cmd[7] = s->type; + cgc.cmd[8] = cgc.buflen >> 8; + cgc.cmd[9] = cgc.buflen & 0xff; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + s->copyright.cpst = buf[4]; + s->copyright.rmi = buf[5]; + + return 0; +} + +static int dvd_read_disckey (struct cdrom_device_info *cdi, dvd_struct *s) +{ + int rv; + u_char buf[4 + 2048]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(buf, 0, sizeof (buf)); + memset(&cgc, 0, sizeof (cgc)); + + cgc.buffer = buf; + cgc.buflen = sizeof(buf); + cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.cmd[8] = sizeof(buf) >> 8; + cgc.cmd[9] = cgc.buflen & 0xff; + cgc.cmd[10] = s->disckey.agid << 6; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + memcpy (s->disckey.value, &buf[4], 2048); + + return 0; +} + +static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int rv; + u_char buf[4 + 188]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(buf, 0, sizeof (buf)); + memset(&cgc, 0, sizeof (cgc)); + cgc.buffer = buf; + cgc.buflen = sizeof(buf); + cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.cmd[9] = cgc.buflen = 0xff; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + s->bca.len = buf[0] << 8 | buf[1]; + if (s->bca.len < 12 || s->bca.len > 188) { + cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); + return -EIO; + } + memcpy(s->bca.value, &buf[4], s->bca.len); + + return 0; +} + +static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int rv; + u_char buf[4 + 2048]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + memset(buf, 0, sizeof(buf)); + memset(&cgc, 0, sizeof(cgc)); + cgc.buffer = buf; + cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.buflen = sizeof(buf); + cgc.cmd[8] = sizeof(buf) >> 8; + cgc.cmd[9] = cgc.buflen & 0xff; + + rv = cdo->generic_packet(cdi, &cgc); + if (rv) + return rv; + + s->manufact.len = buf[0] << 8 | buf[1]; + if (s->manufact.len < 0 || s->manufact.len > 2048) { + cdinfo(CD_WARNING, "Recieved invalid manufacture info length (%d)\n", s->bca.len); + return -EIO; + } + memcpy(s->manufact.value, &buf[4], s->manufact.len); + + return 0; +} + +static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s) +{ + switch (s->type) { + case DVD_STRUCT_PHYSICAL: + return dvd_read_physical(cdi, s); + + case DVD_STRUCT_COPYRIGHT: + return dvd_read_copyright(cdi, s); + + case DVD_STRUCT_DISCKEY: + return dvd_read_disckey(cdi, s); + + case DVD_STRUCT_BCA: + return dvd_read_bca(cdi, s); + + case DVD_STRUCT_MANUFACT: + return dvd_read_manufact(cdi, s); + + default: + cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", + s->type); + return -EINVAL; + } +} + +static int cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = 0x5a; /* MODE_SENSE_10 */ + cgc->cmd[2] = page_code | (page_control << 6); + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + return cdo->generic_packet(cdi, cgc); +} + +static int cdrom_mode_select(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = 0x55; /* MODE_SELECT_10 */ + cgc->cmd[1] = 0x10; /* PF */ + cgc->cmd[2] = 0x0e; /* PF */ + + /* generic_packet() wants the length as seen from the drive, i.e. + it will transfer data _to_ us. The CD-ROM wants the absolute + value, however. */ + cgc->cmd[7] = (-cgc->buflen) >> 8; + cgc->cmd[8] = (-cgc->buflen) & 0xff; + + return cdo->generic_packet(cdi, cgc); +} + /* Some of the cdrom ioctls are not implemented here, because these * appear to be either too device-specific, or it is not clear to me * what use they are. These are (number of drivers that support them @@ -704,6 +1095,7 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, kdev_t dev = ip->i_rdev; struct cdrom_device_info *cdi = cdrom_find_device (dev); struct cdrom_device_ops *cdo; + int ret; if (cdi == NULL) return -ENODEV; @@ -715,7 +1107,6 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, /* maybe we should order cases after statistics of use? */ case CDROMMULTISESSION: { - int ret; struct cdrom_multisession ms_info; u_char requested_format; cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); @@ -737,28 +1128,28 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, } case CDROMEJECT: { - int ret; cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); - if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) + if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; if (cdi->use_count != 1 || keeplocked) return -EBUSY; - if (cdo->capability & ~cdi->mask & CDC_LOCK) + if (CDROM_CAN(CDC_LOCK)) if ((ret=cdo->lock_door(cdi, 0))) return ret; return cdo->tray_move(cdi, 1); } - case CDROMCLOSETRAY: + case CDROMCLOSETRAY: { cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); - if (!(cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)) + if (!CDROM_CAN(CDC_CLOSE_TRAY)) return -ENOSYS; return cdo->tray_move(cdi, 0); + } - case CDROMEJECT_SW: + case CDROMEJECT_SW: { cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); - if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) + if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; if (keeplocked) return -EBUSY; @@ -766,13 +1157,13 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, if (arg) cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; return 0; + } case CDROM_MEDIA_CHANGED: { cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); - if (!(cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED)) + if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS; - if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC) - || arg == CDSL_CURRENT) + if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) /* cannot select disc or select current disc */ return media_changed(cdi, 1); if ((unsigned int)arg >= cdi->capacity) @@ -780,7 +1171,7 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, return cdo->media_changed (cdi, arg); } - case CDROM_SET_OPTIONS: + case CDROM_SET_OPTIONS: { cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); /* options need to be in sync with capability. too late for that, so we have to check each one separately... */ @@ -789,34 +1180,36 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, case CDO_CHECK_TYPE: break; case CDO_LOCK: - if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) + if (!CDROM_CAN(CDC_LOCK)) return -ENOSYS; break; case 0: return cdi->options; /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */ default: - if (!(cdo->capability & ~cdi->mask & arg)) + if (!CDROM_CAN(arg)) return -ENOSYS; } cdi->options |= (int) arg; return cdi->options; + } - case CDROM_CLEAR_OPTIONS: + case CDROM_CLEAR_OPTIONS: { cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); cdi->options &= ~(int) arg; return cdi->options; + } case CDROM_SELECT_SPEED: { cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); - if (!(cdo->capability & ~cdi->mask & CDC_SELECT_SPEED)) + if (!CDROM_CAN(CDC_SELECT_SPEED)) return -ENOSYS; return cdo->select_speed(cdi, arg); } case CDROM_SELECT_DISC: { cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); - if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC)) + if (!CDROM_CAN(CDC_SELECT_DISC)) return -ENOSYS; if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) return cdo->select_disc(cdi, arg); @@ -826,15 +1219,17 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, } case CDROMRESET: { + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); - if (!(cdo->capability & ~cdi->mask & CDC_RESET)) + if (!CDROM_CAN(CDC_RESET)) return -ENOSYS; return cdo->reset(cdi); } case CDROM_LOCKDOOR: { - cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl"); - if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) { + cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); + if (!CDROM_CAN(CDC_LOCK)) { return -EDRIVE_CANT_DO_THIS; } else { keeplocked = arg ? 1 : 0; @@ -845,7 +1240,7 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, case CDROM_DEBUG: { if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis"); + cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); debug = arg ? 1 : 0; return debug; } @@ -861,7 +1256,6 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, * is written on the CD is /not/ uniform across all discs! */ case CDROM_GET_MCN: { - int ret; struct cdrom_mcn mcn; cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); if (!(cdo->capability & CDC_MCN)) @@ -923,144 +1317,236 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, return CDS_NO_INFO; } - case CDROM_CHANGER_NSLOTS: + case CDROM_CHANGER_NSLOTS: { cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); - return cdi->capacity; - -/* The following is not implemented, because there are too many - * different data types. We could support /1/ raw mode, that is large - * enough to hold everything. - */ + return cdi->capacity; + } + } -#if 0 - case CDROMREADMODE1: { - int ret; + /* use the ioctls that are implemented through the generic_packet() + interface. this may look at bit funny, but if -ENOTTY is + returned that particular ioctl is not implemented and we + let it go through the device specific ones. */ + if (CDROM_CAN(CDC_GENERIC_PACKET)) { + ret = mmc_ioctl(cdi, cmd, arg); + if (ret != -ENOTTY) + return ret; + } + + /* Now all the audio-ioctls follow, they are all routed through the + same call audio_ioctl(). */ + if (!CDROM_CAN(CDC_PLAY_AUDIO)) { + if (CDROM_CAN(CDC_IOCTLS)) + return cdo->dev_ioctl(cdi, cmd, arg); + return -ENOSYS; + } + + /* note: most of the cdinfo() calls are commented out here, + because they fill up the sys log when CD players poll + the drive. */ + switch (cmd) { + case CDROMSUBCHNL: { + struct cdrom_subchnl q; + u_char requested, back; + /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ + IOCTL_IN(arg, struct cdrom_subchnl, q); + requested = q.cdsc_format; + if (!((requested == CDROM_MSF) || + (requested == CDROM_LBA))) + return -EINVAL; + q.cdsc_format = CDROM_MSF; + if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) + return ret; + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, requested); + sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); + IOCTL_OUT(arg, struct cdrom_subchnl, q); + /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + return 0; + } + case CDROMREADTOCHDR: { + struct cdrom_tochdr header; + /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ + IOCTL_IN(arg, struct cdrom_tochdr, header); + if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) + return ret; + IOCTL_OUT(arg, struct cdrom_tochdr, header); + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ + return 0; + } + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + u_char requested_format; + /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ + IOCTL_IN(arg, struct cdrom_tocentry, entry); + requested_format = entry.cdte_format; + if (!((requested_format == CDROM_MSF) || + (requested_format == CDROM_LBA))) + return -EINVAL; + /* make interface to low-level uniform */ + entry.cdte_format = CDROM_MSF; + if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) + return ret; + sanitize_format(&entry.cdte_addr, + &entry.cdte_format, requested_format); + IOCTL_OUT(arg, struct cdrom_tocentry, entry); + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ + return 0; + } + case CDROMPLAYMSF: { struct cdrom_msf msf; - char buf[CD_FRAMESIZE]; - cdinfo(CD_DO_IOCTL, "entering CDROMREADMODE1\n"); + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); IOCTL_IN(arg, struct cdrom_msf, msf); - if (ret=cdo->read_audio(dev, cmd, &msf, &buf, cdi)) + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, &msf); + } + case CDROMPLAYTRKIND: { + struct cdrom_ti ti; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); + IOCTL_IN(arg, struct cdrom_ti, ti); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, &ti); + } + case CDROMVOLCTRL: { + struct cdrom_volctrl volume; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); + IOCTL_IN(arg, struct cdrom_volctrl, volume); + return cdo->audio_ioctl(cdi, cmd, &volume); + } + case CDROMVOLREAD: { + struct cdrom_volctrl volume; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); + if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) return ret; - IOCTL_OUT(arg, __typeof__(buf), buf); + IOCTL_OUT(arg, struct cdrom_volctrl, volume); return 0; } -#endif + case CDROMSTART: + case CDROMSTOP: + case CDROMPAUSE: + case CDROMRESUME: { + cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, NULL); + } } /* switch */ -/* Now all the audio-ioctls follow, they are all routed through the - same call audio_ioctl(). */ + return -ENOSYS; +} -#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret +static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + int rv; - if (!(cdo->capability & CDC_PLAY_AUDIO)) - return -ENOSYS; - else { - switch (cmd) { - case CDROMSUBCHNL: { - int ret; - struct cdrom_subchnl q; - u_char requested, back; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ - IOCTL_IN(arg, struct cdrom_subchnl, q); - requested = q.cdsc_format; - if (!((requested == CDROM_MSF) || - (requested == CDROM_LBA))) - return -EINVAL; - q.cdsc_format = CDROM_MSF; - if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) - return ret; - back = q.cdsc_format; /* local copy */ - sanitize_format(&q.cdsc_absaddr, &back, requested); - sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - IOCTL_OUT(arg, struct cdrom_subchnl, q); - /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ - return 0; - } - case CDROMREADTOCHDR: { - int ret; - struct cdrom_tochdr header; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ - IOCTL_IN(arg, struct cdrom_tochdr, header); - if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) - return ret; - IOCTL_OUT(arg, struct cdrom_tochdr, header); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ - return 0; - } - case CDROMREADTOCENTRY: { - int ret; - struct cdrom_tocentry entry; - u_char requested_format; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ - IOCTL_IN(arg, struct cdrom_tocentry, entry); - requested_format = entry.cdte_format; - if (!((requested_format == CDROM_MSF) || - (requested_format == CDROM_LBA))) - return -EINVAL; - /* make interface to low-level uniform */ - entry.cdte_format = CDROM_MSF; - if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) - return ret; - sanitize_format(&entry.cdte_addr, - &entry.cdte_format, requested_format); - IOCTL_OUT(arg, struct cdrom_tocentry, entry); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ + memset(&cgc, 0, sizeof(cgc)); + + /* build a unified command and queue it through + cdo->generic_packet() */ + switch (cmd) { + case CDROMVOLCTRL: + case CDROMVOLREAD: { + struct cdrom_volctrl volctrl; + char buffer[32], mask[32]; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); + + IOCTL_IN(arg, struct cdrom_volctrl, volctrl); + + cgc.buffer = buffer; + cgc.buflen = 24; + rv = cdrom_mode_sense(cdi, &cgc, 0x0e, 0); + if (rv) return rv; + + /* now we have the current volume settings. if it was only + a CDROMVOLREAD, return these values */ + if (cmd == CDROMVOLREAD) { + volctrl.channel0 = buffer[17]; + volctrl.channel1 = buffer[19]; + volctrl.channel2 = buffer[21]; + volctrl.channel3 = buffer[23]; + IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); return 0; - } - case CDROMPLAYMSF: { - int ret; - struct cdrom_msf msf; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - IOCTL_IN(arg, struct cdrom_msf, msf); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, &msf); - } - case CDROMPLAYTRKIND: { - int ret; - struct cdrom_ti ti; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, &ti); - } - case CDROMVOLCTRL: { - struct cdrom_volctrl volume; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); - IOCTL_IN(arg, struct cdrom_volctrl, volume); - return cdo->audio_ioctl(cdi, cmd, &volume); - } - case CDROMVOLREAD: { - int ret; - struct cdrom_volctrl volume; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); - if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) - return ret; - IOCTL_OUT(arg, struct cdrom_volctrl, volume); + } + + /* get the volume mask */ + cgc.buffer = mask; + rv = cdrom_mode_sense(cdi, &cgc, 0x0e, 1); + if (rv) return rv; + + buffer[17] = volctrl.channel0 & mask[17]; + buffer[19] = volctrl.channel1 & mask[19]; + buffer[21] = volctrl.channel2 & mask[21]; + buffer[23] = volctrl.channel3 & mask[23]; + + /* clear the first three */ + memset(buffer, 0, 3); + + /* set volume */ + cgc.buflen = -24; + cgc.buffer = buffer; + return cdrom_mode_select(cdi, &cgc); + } + + case CDROMSTART: + case CDROMSTOP: { + cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n"); + cgc.cmd[0] = 0x1b; + cgc.cmd[1] = 1; + cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; + return cdo->generic_packet(cdi, &cgc); + } + + case CDROMPAUSE: + case CDROMRESUME: { + cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n"); + cgc.cmd[0] = 0x4b; + cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; + return cdo->generic_packet(cdi, &cgc); + } + + case DVD_READ_STRUCT: { + dvd_struct s; + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n"); + IOCTL_IN(arg, dvd_struct, s); + if ((rv = dvd_read_struct(cdi, &s)) == 0) { + IOCTL_OUT(arg, dvd_struct, s); return 0; - } - case CDROMSTART: - case CDROMSTOP: - case CDROMPAUSE: - case CDROMRESUME: { - int ret; - cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, NULL); - } - } /* switch */ - } + } + return rv; + } - /* device specific ioctls? */ - if (!(cdo->capability & CDC_IOCTLS)) - return -ENOSYS; - else - return cdo->dev_ioctl(cdi, cmd, arg); + case DVD_AUTH: { + dvd_authinfo ai; + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering dvd_auth\n"); + IOCTL_IN(arg, dvd_authinfo, ai); + if ((rv = dvd_do_auth (cdi, &ai))) + return rv; + IOCTL_OUT(arg, dvd_authinfo, ai); + return 0; + } + + case CDROM_SEND_PACKET: { + cdinfo(CD_DO_IOCTL, "entering send_packet\n"); + IOCTL_IN(arg, struct cdrom_generic_command, cgc); + cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); + rv = cdo->generic_packet(cdi, &cgc); + if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen)) { + kfree(cgc.buffer); + return -EFAULT; + } + kfree(cgc.buffer); + return rv; + } + + } /* switch */ + + return -ENOTTY; } EXPORT_SYMBOL(cdrom_count_tracks); @@ -1072,90 +1558,160 @@ EXPORT_SYMBOL(cdrom_fops); #define CDROM_STR_SIZE 1000 -static char cdrom_drive_info[CDROM_STR_SIZE]="info\n"; +struct cdrom_sysctl_settings { + char info[CDROM_STR_SIZE]; /* general info */ + int autoclose; /* close tray upon mount, etc */ + int autoeject; /* eject on umount */ + int debug; /* turn on debugging messages */ + int lock; /* lock the door on device open */ + int check; /* check media type */ +} cdrom_sysctl_settings; int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) { int pos; struct cdrom_device_info *cdi; + char *info = cdrom_sysctl_settings.info; if (!*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } - pos = sprintf(cdrom_drive_info, "CD-ROM information, " VERSION "\n"); + pos = sprintf(info, "CD-ROM information, " VERSION "\n"); - pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t"); + pos += sprintf(info+pos, "\ndrive name:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%s", cdi->name); + + pos += sprintf(info+pos, "\ndrive speed:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", cdi->speed); + + pos += sprintf(info+pos, "\ndrive # of slots:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", cdi->capacity); + + pos += sprintf(info+pos, "\nCan close tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); + + pos += sprintf(info+pos, "\nCan open tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%s", cdi->name); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); - pos += sprintf(cdrom_drive_info+pos, "\ndrive speed:\t"); + pos += sprintf(info+pos, "\nCan lock tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->speed); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); - pos += sprintf(cdrom_drive_info+pos, "\ndrive # of slots:"); + pos += sprintf(info+pos, "\nCan change speed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->capacity); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t"); + pos += sprintf(info+pos, "\nCan select disk:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_CLOSE_TRAY)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t"); + pos += sprintf(info+pos, "\nCan read multisession:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_OPEN_TRAY)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t"); + pos += sprintf(info+pos, "\nCan read MCN:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_LOCK)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:"); + pos += sprintf(info+pos, "\nReports media changed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_SPEED)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:"); + pos += sprintf(info+pos, "\nCan play audio:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_DISC)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:"); + pos += sprintf(info+pos, "\nCan write CD-R:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_MULTI_SESSION)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan read MCN:\t"); + pos += sprintf(info+pos, "\nCan write CD-RW:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_MCN)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nReports media changed:"); + pos += sprintf(info+pos, "\nCan read DVD:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_MEDIA_CHANGED)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t"); + pos += sprintf(info+pos, "\nCan write DVD-R:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0)); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); - strcpy(cdrom_drive_info+pos,"\n\n"); - pos += 3; - if (*lenp > pos) - *lenp = pos; + pos += sprintf(info+pos, "\nCan write DVD-RAM:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); + strcpy(info+pos,"\n\n"); + return proc_dostring(ctl, write, filp, buffer, lenp); } +static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int *valp = ctl->data; + int val = *valp; + int ret; + + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + /* FIXME: only 1's and 0's should be accepted */ + if (write && *valp != val) { + + switch (ctl->ctl_name) { + case DEV_CDROM_AUTOCLOSE: { + if (valp == &cdrom_sysctl_settings.autoclose) + autoclose = cdrom_sysctl_settings.autoclose; + break; + } + case DEV_CDROM_AUTOEJECT: { + if (valp == &cdrom_sysctl_settings.autoeject) + autoeject = cdrom_sysctl_settings.autoeject; + break; + } + case DEV_CDROM_DEBUG: { + if (valp == &cdrom_sysctl_settings.debug) + debug = cdrom_sysctl_settings.debug; + break; + } + case DEV_CDROM_LOCK: { + if (valp == &cdrom_sysctl_settings.lock) + lockdoor = cdrom_sysctl_settings.lock; + break; + } + case DEV_CDROM_CHECK_MEDIA: { + if (valp == &cdrom_sysctl_settings.check) + check_media_type = cdrom_sysctl_settings.check; + break; + } + } + } + + return ret; +} + /* Place files in /proc/sys/dev/cdrom */ ctl_table cdrom_table[] = { - {DEV_CDROM_INFO, "info", &cdrom_drive_info, + {DEV_CDROM_INFO, "info", &cdrom_sysctl_settings.info, CDROM_STR_SIZE, 0444, NULL, &cdrom_sysctl_info}, + {DEV_CDROM_AUTOCLOSE, "autoclose", &cdrom_sysctl_settings.autoclose, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_AUTOEJECT, "autoeject", &cdrom_sysctl_settings.autoeject, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_DEBUG, "debug", &cdrom_sysctl_settings.debug, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_LOCK, "lock", &cdrom_sysctl_settings.lock, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_CHECK_MEDIA, "check_media", &cdrom_sysctl_settings.check, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, {0} }; @@ -1198,6 +1754,13 @@ static void cdrom_sysctl_register(void) cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; + + /* set the defaults */ + cdrom_sysctl_settings.autoclose = autoclose; + cdrom_sysctl_settings.autoeject = autoeject; + cdrom_sysctl_settings.debug = debug; + cdrom_sysctl_settings.lock = lockdoor; + cdrom_sysctl_settings.check = check_media_type; initialized = 1; } diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 0d7b843c464e..1ac3001861ee 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -41,6 +41,7 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then if [ "$CONFIG_SPECIALIX" != "n" ]; then bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS fi + tristate 'Specialix SX (and SI) card support' CONFIG_SX tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 6197a497b10f..a0e632bbb619 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -156,6 +156,14 @@ else endif endif +ifeq ($(CONFIG_SX),y) +L_OBJS += sx.o generic_serial.o +else + ifeq ($(CONFIG_SX),m) + M_OBJS += sx.o + endif +endif + ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) O_OBJS += atixlmouse.o else diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index c24d96b27187..83109a492e05 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -3538,12 +3538,13 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) btv->id=dev->device; btv->irq=dev->irq; - btv->bt848_adr=dev->base_address[0]; + btv->bt848_adr=dev->resource[0].start; if (btv->id >= 878) btv->i2c_command = 0x83; else btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); +#if 0 if (remap[bttv_num]) { unsigned int dw = btv->bt848_adr; @@ -3558,7 +3559,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw); btv->dev->base_address[0] = btv->bt848_adr; } - btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; +#endif pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", bttv_num,btv->id, btv->revision); diff --git a/drivers/char/buz.c b/drivers/char/buz.c index 1a37e2944812..aef057a584eb 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -3219,7 +3219,7 @@ static int zr36057_init(int i) } /* i2c */ memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); - sprintf(zr->i2c.name, "zoran%u%u", zr->id); + sprintf(zr->i2c.name, "zoran%u", zr->id); zr->i2c.data = zr; if (i2c_register_bus(&zr->i2c) < 0) { kfree((void *) zr->stat_com); @@ -3327,7 +3327,7 @@ static int find_zr36057(void) spin_lock_init(&zr->lock); - zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; + zr->zr36057_adr = zr->pci_dev->resource[0].start; pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); if (zr->revision < 2) { printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", diff --git a/drivers/char/epca.c b/drivers/char/epca.c index abb8c5f35290..c67586baabd0 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -4049,12 +4049,12 @@ int get_PCI_configuration(unsigned char bus, unsigned char device_fn, if (!dev) return(0); - *base_addr0 = dev->base_address[0]; - *base_addr1 = dev->base_address[1]; - *base_addr2 = dev->base_address[2]; - *base_addr3 = dev->base_address[3]; - *base_addr4 = dev->base_address[4]; - *base_addr5 = dev->base_address[5]; + *base_addr0 = dev->resource[0].start; + *base_addr1 = dev->resource[1].start; + *base_addr2 = dev->resource[2].start; + *base_addr3 = dev->resource[3].start; + *base_addr4 = dev->resource[4].start; + *base_addr5 = dev->resource[5].start; /* ------------------------------------------------------------------------ NOTE - The code below mask out either the 2 or 4 bits dependent on the @@ -4064,36 +4064,6 @@ int get_PCI_configuration(unsigned char bus, unsigned char device_fn, be 0 when used as an address. ---------------------------------------------------------------------------- */ - if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK; - - if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK; - - if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK; - - if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK; - - if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK; - - if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ - (*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK; - else - (*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK; - return(1); } /* End get_PCI_configuration */ diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c new file mode 100644 index 000000000000..15b4fcd96d9c --- /dev/null +++ b/drivers/char/generic_serial.c @@ -0,0 +1,1074 @@ +/* + * generic_serial.c + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Credit for the idea to do it this way might go to Alan Cox. + * + * + * Version 0.1 -- December, 1998. Initial version. + * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc. + * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus. + */ + +#include +#include +#include +#include +#include + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.2.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +/* Some 200 days (on intel) */ +#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL>>1)) + + +#ifndef MODULE + +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + + +/* Should be in a header somewhere. */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ +#endif + +#endif + +#ifndef TWO_ZERO +/* This include is new with 2.2 (and required!) */ +#include +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define waitq_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + +#include "generic_serial.h" + + +#ifndef MODULE +extern void my_hd (unsigned char *ptr, int n); +#endif + +static char * tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +int gs_debug = 0; + + +#ifdef DEBUG +#define gs_dprintk(f, str...) if (gs_debug & f) printk (str) +#else +#define gs_dprintk(f, str...) /* nothing */ +#endif + +#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n") +#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n") + + + +#if NEW_WRITE_LOCKING +#define DECL /* Nothing */ +#define LOCKIT down (& port->port_write_sem); +#define RELEASEIT up (&port->port_write_sem); +#else +#define DECL unsigned long flags; +#define LOCKIT save_flags (flags);cli () +#define RELEASEIT restore_flags (flags) +#endif + + + +void gs_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct gs_port *port = tty->driver_data; + DECL + + /* func_enter (); */ + + /* Take a lock on the serial tranmit buffer! */ + LOCKIT; + + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + /* Sorry, buffer is full, drop character. Update statistics???? -- REW */ + RELEASEIT; + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= SERIAL_XMIT_SIZE - 1; + port->xmit_cnt++; /* Characters in buffer */ + + RELEASEIT; + /* func_exit ();*/ +} + + +#ifdef NEW_WRITE_LOCKING + +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port = tty->driver_data; + int c, total = 0; + int t; + + /* func_enter (); */ + + if (! (port->flags & ASYNC_INITIALIZED)) + return 0; + + /* get exclusive "write" access to this port (problem 3) */ + /* This is not a spinlock because we can have a disk access (page + fault) in copy_from_user */ + down (& port->port_write_sem); + + while (1) { + + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + if (from_user) + copy_from_user (port->xmit_buf + port->xmit_head, buf, c); + else + memcpy (port->xmit_buf + port->xmit_head, buf, c); + + port -> xmit_cnt += c; + port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1); + buf += c; + count -= c; + total += c; + } + up (& port->port_write_sem); + + gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", + (port->flags & GS_TX_INTEN)?"enabled": "disabled"); + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + /* func_exit (); */ + return total; +} +#else +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port; + int c, total = 0; + int t; + unsigned long flags; + + func_enter (); + + /* The standard serial driver returns 0 in this case. + That sounds to me as "No error, I just didn't get to writing any + bytes. Feel free to try again." + The "official" way to write n bytes from buf is: + + for (nwritten = 0;nwritten < n;nwritten += rv) { + rv = write (fd, buf+nwritten, n-nwritten); + if (rv < 0) break; // Error: bail out. // + } + + which will loop endlessly in this case. The manual page for write + agrees with me. In practise almost everybody writes + "write (fd, buf,n);" but some people might have had to deal with + incomplete writes in the past and correctly implemented it by now... + */ + + if (!tty) return -EIO; + + port = tty->driver_data; + if (!port || !port->xmit_buf || !tmp_buf) + return -EIO; + + /* printk ("from_user = %d.\n", from_user); */ + save_flags(flags); + if (from_user) { + /* printk ("Going into the semaphore\n"); */ + down(&tmp_buf_sem); + /* printk ("got out of the semaphore\n"); */ + while (1) { + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + cli(); + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(port->xmit_buf + port->xmit_head, buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + } + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); + return total; +} + +#endif + + + +int gs_write_room(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + int ret; + + /* func_enter (); */ + ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (ret < 0) + ret = 0; + /* func_exit (); */ + return ret; +} + + +int gs_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + func_exit (); + return port->xmit_cnt; +} + + +int gs_real_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + if (!tty) return 0; + port = tty->driver_data; + + func_exit (); + return port->xmit_cnt + port->rd->chars_in_buffer (port); +} + + +static void gs_wait_tx_flushed (void * ptr, int timeout) +{ + struct gs_port *port = ptr; + long end_jiffies; + int jiffies_to_transmit, charsleft; + int to, rcib; + + func_enter(); + + gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port); + if (port) { + gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", + port->xmit_cnt, port->xmit_buf, port->tty); + } + + if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { + gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n"); + func_exit(); + return; /* This is an error which we don't know how to handle. */ + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n"); + + rcib = gs_real_chars_in_buffer(port->tty); + + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 2\n"); + + if(rcib <= 0) { + gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n"); + func_exit(); + return; + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n"); + + /* stop trying: now + twice the time it would normally take + seconds */ + end_jiffies = jiffies; + if (timeout != MAX_SCHEDULE_TIMEOUT) + end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0; + end_jiffies += timeout; + + gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", + jiffies, end_jiffies, end_jiffies-jiffies); + + to = 100; + /* the expression is actually jiffies < end_jiffies, but that won't + work around the wraparound. Tricky eh? */ + while (to-- && + (charsleft = gs_real_chars_in_buffer (port->tty)) && + time_after (end_jiffies, jiffies)) { + /* Units check: + chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! + check! */ + + charsleft += 16; /* Allow 16 chars more to be transmitted ... */ + jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0; + /* ^^^ Round up.... */ + if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1; + + gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies " + "(%d chars).\n", jiffies_to_transmit, charsleft); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(jiffies_to_transmit); + if (signal_pending (current)) + break; + } + + gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); + current->state = TASK_RUNNING; + + func_exit(); +} + + + +void gs_flush_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + + func_enter (); + /* XXX Would the write semaphore do? */ + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + func_exit (); +} + + +void gs_flush_chars(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) { + func_exit (); + return; + } + + /* Beats me -- REW */ + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + func_exit (); +} + + +void gs_stop(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt && + port->xmit_buf && + (port->flags & GS_TX_INTEN) ) { + port->flags &= ~GS_TX_INTEN; + port->rd->disable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_start(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + if (port->xmit_cnt && + port->xmit_buf && + !(port->flags & GS_TX_INTEN) ) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_shutdown_port (struct gs_port *port) +{ + long flags; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + + save_flags (flags); + cli (); + + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = 0; + } + + if (port->tty) + set_bit(TTY_IO_ERROR, &port->tty->flags); + + port->rd->shutdown_port (port); + + port->flags &= ~ASYNC_INITIALIZED; + restore_flags (flags); +} + + +void gs_hangup(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + + tty = port->tty; + if (!tty) return; + + gs_shutdown_port (port); + + /* gs_flush_buffer (tty); */ + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE); + port->tty = NULL; + port->count = 0; + + wake_up_interruptible(&port->open_wait); + func_exit (); +} + + +void gs_do_softint(void *private_) +{ + struct gs_port *port = private_; + struct tty_struct *tty; + + tty = port->tty; + if(!tty) return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + func_exit (); +} + + +int block_til_ready(void *port_, struct file * filp) +{ + struct gs_port *port = port_; + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + int CD; + struct tty_struct *tty; + + func_enter (); + tty = port->tty; + + gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == GS_TYPE_CALLOUT) { + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } + + gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + + gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; + while (1) { + CD = port->rd->get_CD (port); + gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || CD)) + break; + gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", + (int)signal_pending (current), *(long*)(¤t->blocked)); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", + port->blocked_open); + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + + port->flags |= ASYNC_NORMAL_ACTIVE; + func_exit (); + return 0; +} + + +void gs_close(struct tty_struct * tty, struct file * filp) +{ + unsigned long flags; + struct gs_port *port; + + func_enter (); + port = (struct gs_port *) tty->driver_data; + + gs_dprintk (GS_DEBUG_CLOSE, "tty=%p, port=%p port->tty=%p\n", + tty, port, port->tty); + + if(! port) { + func_exit(); + return; + } + if (!port->tty) { + printk (KERN_WARNING "gs: Odd: port->tty is NULL\n"); + port->tty = tty; + } + + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + port->rd->hungup (port); + func_exit (); + return; + } + + if ((tty->count == 1) && (port->count != 1)) { + printk(KERN_ERR "gs: gs_close: bad port count;" + " tty->count is 1, port count is %d\n", port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count); + port->count = 0; + } + if (port->count) { + restore_flags(flags); + func_exit (); + return; + } + port->flags |= ASYNC_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + /* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); */ + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + port->rd->disable_rx_interrupts (port); + + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + gs_wait_tx_flushed (port, port->closing_wait); + + port->flags &= ~GS_ACTIVE; + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING | ASYNC_INITIALIZED); + wake_up_interruptible(&port->close_wait); + + port->rd->close (port); + port->rd->shutdown_port (port); + restore_flags(flags); + func_exit (); +} + + +static unsigned int gs_baudrates[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; + + +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios) +{ + struct gs_port *port = tty->driver_data; + int baudrate, tmp; + struct termios *tiosp; + + func_enter(); + + tiosp = tty->termios; + + + if (gs_debug & GS_DEBUG_TERMIOS) { + gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); + my_hd ((unsigned char *)tiosp, sizeof (struct termios)); + } + +#if 0 + /* This is an optimization that is only allowed for dumb cards */ + /* Smart cards require knowledge of iflags and oflags too: that + might change hardware cooking mode.... */ +#endif + if (old_termios) { + if( (tiosp->c_iflag == old_termios->c_iflag) + && (tiosp->c_oflag == old_termios->c_oflag) + && (tiosp->c_cflag == old_termios->c_cflag) + && (tiosp->c_lflag == old_termios->c_lflag) + && (tiosp->c_line == old_termios->c_line) + && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) { + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n"); + return; + } + } else + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: " + "no optimization\n"); + + if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) { + if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n"); + if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n"); + if(tiosp->c_cflag != old_termios->c_cflag) printk("c_cflag changed\n"); + if(tiosp->c_lflag != old_termios->c_lflag) printk("c_lflag changed\n"); + if(tiosp->c_line != old_termios->c_line) printk("c_line changed\n"); + if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); + } + + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + + baudrate = gs_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (port->baud_base / port->custom_divisor); + } + + /* I recommend using THIS instead of the mess in termios (and + duplicating the above code). Next we should create a clean + interface towards this variable. If your card supports arbitrary + baud rates, (e.g. CD1400 or 16550 based cards) then everything + will be very easy..... */ + port->baud = baudrate; + + /* Two timer ticks seems enough to wakeup something like SLIP driver */ + /* Baudrate/10 is cps. Divide by HZ to get chars per tick. */ + tmp = (baudrate / 10 / HZ) * 2; + + if (tmp < 0) tmp = 0; + if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1; + + port->wakeup_chars = tmp; + + /* We should really wait for the characters to be all sent before + changing the settings. -- CAL */ + gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT); + + port->rd->set_real_termios(port); + + if ((!old_termios || + (old_termios->c_cflag & CRTSCTS)) && + !( tiosp->c_cflag & CRTSCTS)) { + tty->stopped = 0; + gs_start(tty); + } + +#ifdef tytso_patch_94Nov25_1726 + /* This "makes sense", Why is it commented out? */ + + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif + + func_exit(); + return; +} + + + +/* Must be called with interrupts enabled */ +int gs_init_port(struct gs_port *port) +{ + unsigned long flags; + unsigned long page; + + save_flags (flags); + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + + cli (); /* Don't expect this to make a difference. */ + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + restore_flags (flags); + + if (!tmp_buf) { + return -ENOMEM; + } + } + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + if (!port->xmit_buf) { + /* We may sleep in get_free_page() */ + unsigned long tmp; + + tmp = get_free_page(GFP_KERNEL); + + /* Spinlock? */ + cli (); + if (port->xmit_buf) + free_page (tmp); + else + port->xmit_buf = (unsigned char *) tmp; + restore_flags (flags); + + if (!port->xmit_buf) + return -ENOMEM; + } + + cli(); + + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + gs_set_termios(port->tty, NULL); + + port->flags |= ASYNC_INITIALIZED; + port->flags &= ~GS_TX_INTEN; + + restore_flags(flags); + return 0; +} + + +int gs_setserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + copy_from_user(&sio, sp, sizeof(struct serial_struct)); + + if (!capable(CAP_SYS_ADMIN)) { + if ((sio.baud_base != port->baud_base) || + (sio.close_delay != port->close_delay) || + ((sio.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return(-EPERM); + } + + port->flags = (port->flags & ~ASYNC_USR_MASK) | + (sio.flags & ASYNC_USR_MASK); + + port->baud_base = sio.baud_base; + port->close_delay = sio.close_delay; + port->closing_wait = sio.closing_wait; + port->custom_divisor = sio.custom_divisor; + + gs_set_termios (port->tty, NULL); + + return 0; +} + + +/*****************************************************************************/ + +/* + * Generate the serial struct info. + */ + +void gs_getserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + memset(&sio, 0, sizeof(struct serial_struct)); + sio.flags = port->flags; + sio.baud_base = port->baud_base; + sio.close_delay = port->close_delay; + sio.closing_wait = port->closing_wait; + sio.custom_divisor = port->custom_divisor; + sio.hub6 = 0; + + /* If you want you can override these. */ + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = -1; + sio.line = -1; + sio.port = -1; + sio.irq = -1; + + if (port->rd->getserial) + port->rd->getserial (port, &sio); + + copy_to_user(sp, &sio, sizeof(struct serial_struct)); +} + diff --git a/drivers/char/generic_serial.h b/drivers/char/generic_serial.h new file mode 100644 index 000000000000..ca321af9b0bf --- /dev/null +++ b/drivers/char/generic_serial.h @@ -0,0 +1,101 @@ +/* + * generic_serial.h + * + * Copyright (C) 1998 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Version 0.1 -- December, 1998. + */ + +#ifndef GENERIC_SERIAL_H +#define GENERIC_SERIAL_H + +struct real_driver { + void (*disable_tx_interrupts) (void *); + void (*enable_tx_interrupts) (void *); + void (*disable_rx_interrupts) (void *); + void (*enable_rx_interrupts) (void *); + int (*get_CD) (void *); + void (*shutdown_port) (void*); + void (*set_real_termios) (void*); + int (*chars_in_buffer) (void*); + void (*close) (void*); + void (*hungup) (void*); + void (*getserial) (void*, struct serial_struct *sp); +}; + + + +struct gs_port { + int magic; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + /* struct semaphore port_write_sem; */ + int flags; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + long session; + long pgrp; + int count; + int blocked_open; + struct tty_struct *tty; + int event; + unsigned short closing_wait; + int close_delay; + struct real_driver *rd; + int wakeup_chars; + int baud_base; + int baud; + int custom_divisor; +}; + + +/* Flags */ +/* Warning: serial.h defines some ASYNC_ flags, they say they are "only" + used in serial.c, but they are also used in all other serial drivers. + Make sure they don't clash with these here... */ +#define GS_TX_INTEN 0x00800000 +#define GS_RX_INTEN 0x00400000 +#define GS_ACTIVE 0x00200000 + + + +#define GS_TYPE_NORMAL 1 +#define GS_TYPE_CALLOUT 2 + + +#define GS_DEBUG_FLUSH 0x00000001 +#define GS_DEBUG_BTR 0x00000002 +#define GS_DEBUG_TERMIOS 0x00000004 +#define GS_DEBUG_STUFF 0x00000008 +#define GS_DEBUG_CLOSE 0x00000010 + + +void gs_put_char(struct tty_struct *tty, unsigned char ch); +int gs_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count); +int gs_write_room(struct tty_struct *tty); +int gs_chars_in_buffer(struct tty_struct *tty); +void gs_flush_buffer(struct tty_struct *tty); +void gs_flush_chars(struct tty_struct *tty); +void gs_stop(struct tty_struct *tty); +void gs_start(struct tty_struct *tty); +void gs_hangup(struct tty_struct *tty); +void gs_do_softint(void *private_); +int block_til_ready(void *port, struct file *filp); +void gs_close(struct tty_struct *tty, struct file *filp); +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios); +int gs_init_port(struct gs_port *port); +int gs_setserial(struct gs_port *port, struct serial_struct *sp); +void gs_getserial(struct gs_port *port, struct serial_struct *sp); + +extern int gs_debug; + +#endif diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e99decb6235a..16cba83417a8 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -14,7 +14,8 @@ * Printk clean up * 9/12/98 alan@redhat.com Rough port to 2.1.x * - * + * 10/6/99 sameer Merged the ISA and PCI drivers to + * a new unified driver. * *********************************************************** * * To use this driver you also need the support package. You @@ -51,8 +52,21 @@ #include #include +#include + #include +static int device_id[] = { 0x2028, + 0x2051, + 0x2052, + 0x2053, + 0x2054, + 0x2055, + 0x2056, + 0x2057, + 0x2058 + }; + static int isicom_refcount = 0; static int prev_card = 3; /* start servicing isi_card[0] */ static struct isi_board * irq_to_board[16] = { NULL, }; @@ -147,7 +161,7 @@ static int ISILoad_release(struct inode *inode, struct file *filp) static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - unsigned int card, i, j, signature, status; + unsigned int card, i, j, signature, status, portcount = 0; unsigned short word_count, base; bin_frame frame; /* exec_record exec_rec; */ @@ -180,19 +194,38 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp, printk("."); } signature=(inw(base+0x4)) & 0xff; - - if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { + if (isi_card[card].isa) { + + if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { #ifdef ISICOM_DEBUG - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); #endif - printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); - return -EIO; - } - + printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + } + else { + portcount = inw(base+0x2); + if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) { +#ifdef ISICOM_DEBUG + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); +#endif + printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + } switch(signature) { case 0xa5: case 0xbb: - case 0xdd: isi_card[card].port_count = 8; + case 0xdd: + if (isi_card[card].isa) + isi_card[card].port_count = 8; + else { + if (portcount == 4) + isi_card[card].port_count = 4; + else + isi_card[card].port_count = 8; + } isi_card[card].shift_count = 12; break; @@ -310,7 +343,8 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp, outw(0x0, base); outw(0x0, base); InterruptTheCard(base); - + outw(0x0, base+0x4); /* for ISI4608 cards */ + isi_card[card].status |= FIRMWARE_LOADED; return 0; @@ -455,28 +489,7 @@ static void isicom_tx(unsigned long _data) txcount--; } } -/* - * Replaced the code below with hopefully a faster loop - sameer - */ -/* - while (1) { - wrd = port->xmit_buf[port->xmit_tail++]; - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - if (--txcount > 0) { - wrd |= (port->xmit_buf[port->xmit_tail++] << 8); - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - outw(wrd, base); - if (--txcount <= 0) break; - } - else { - outw(wrd, base); - break; - } - } -*/ InterruptTheCard(base); if (port->xmit_cnt <= 0) port->status &= ~ISI_TXOK; @@ -531,12 +544,34 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) unsigned char channel; short byte_count; - card = irq_to_board[irq]; + /* + * find the source of interrupt + */ + + for(count = 0; count < BOARD_COUNT; count++) { + card = &isi_card[count]; + if (card->base != 0) { + if (((card->isa == YES) && (card->irq == irq)) || + ((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02))) + break; + } + card = NULL; + } + if (!card || !(card->status & FIRMWARE_LOADED)) { - printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq); +/* printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/ return; } + base = card->base; + if (card->isa == NO) { + /* + * disable any interrupts from the PCI card and lower the + * interrupt line + */ + outw(0x8000, base+0x04); + ClearInterrupt(base); + } inw(base); /* get the dummy word out */ header = inw(base); @@ -548,12 +583,18 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) if ((channel+1) > card->port_count) { printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", base, channel+1); - ClearInterrupt(base); + if (card->isa) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } port = card->ports + channel; if (!(port->flags & ASYNC_INITIALIZED)) { - ClearInterrupt(base); + if (card->isa) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } @@ -681,7 +722,10 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) } queue_task(&tty->flip.tqueue, &tq_timer); } - ClearInterrupt(base); + if (card->isa == YES) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } @@ -1023,12 +1067,11 @@ static int isicom_open(struct tty_struct * tty, struct file * filp) return -ENODEV; } - /* open on higher 8 dev files on a 8 port card !!! */ - if (card->port_count == 8) - if (line > ((board * 16)+7)) { - printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n"); - return -ENODEV; - } + /* open on a port greater than the port count for the card !!! */ + if (line > ((board * 16) + card->port_count - 1)) { + printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n"); + return -ENODEV; + } port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->device, "isicom_open")) return -ENODEV; @@ -1764,21 +1807,42 @@ static void unregister_drivers(void) static int register_isr(void) { - int count, done=0; + int count, done=0, card; + unsigned char request; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { - if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { - printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", - isi_card[count].irq, count+1); + /* + * verify if the required irq has already been requested for + * another ISI Card, if so we already have it, else request it + */ + request = YES; + for(card = 0; card < count; card++) + if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + request = NO; + if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO)) + break; + /* + * ISA cards cannot share interrupts with other + * PCI or ISA devices hence disable this card. + */ release_region(isi_card[count].base,16); - isi_card[count].base=0; + isi_card[count].base = 0; + break; } - else { - printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", - count+1, isi_card[count].base, isi_card[count].irq); - - irq_to_board[isi_card[count].irq]=&isi_card[count]; - done++; + if (request == YES) { + if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { + printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); + isi_card[count].base=0; + } + else { + printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", + count+1, isi_card[count].base, isi_card[count].irq); + + irq_to_board[isi_card[count].irq]=&isi_card[count]; + done++; + } } } } @@ -1787,14 +1851,24 @@ static int register_isr(void) static void unregister_isr(void) { - int count; - for (count=0; count < BOARD_COUNT; count++ ) + int count, card; + unsigned char freeirq; + for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { - free_irq(isi_card[count].irq, NULL); + freeirq = YES; + for(card = 0; card < count; card++) + if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + freeirq = NO; + break; + } + if (freeirq == YES) { + free_irq(isi_card[count].irq, NULL); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); -#endif + printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); +#endif + } } + } } static int isicom_init(void) @@ -1883,29 +1957,75 @@ MODULE_PARM_DESC(irq, "Interrupts for the cards"); int init_module(void) { - int retval, card; - - for(card=0; card < BOARD_COUNT; card++) - { - isi_card[card].base=io[card]; - isi_card[card].irq=irq[card]; + struct pci_dev *dev = NULL; + int retval, card, idx, count; + unsigned char pciirq; + unsigned int ioaddr; + + card = 0; + for(idx=0; idx < BOARD_COUNT; idx++) { + if (io[idx]) { + isi_card[idx].base=io[idx]; + isi_card[idx].irq=irq[idx]; + isi_card[idx].isa=YES; + card++; + } + else { + isi_card[idx].base = 0; + isi_card[idx].irq = 0; + } } - for (card=0 ;card < BOARD_COUNT; card++) { - if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)|| - (isi_card[card].irq==4)||(isi_card[card].irq==5)|| - (isi_card[card].irq==7)||(isi_card[card].irq==10)|| - (isi_card[card].irq==11)||(isi_card[card].irq==12)|| - (isi_card[card].irq==15))) { + for (idx=0 ;idx < card; idx++) { + if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)|| + (isi_card[idx].irq==4)||(isi_card[idx].irq==5)|| + (isi_card[idx].irq==7)||(isi_card[idx].irq==10)|| + (isi_card[idx].irq==11)||(isi_card[idx].irq==12)|| + (isi_card[idx].irq==15))) { - if (isi_card[card].base) { + if (isi_card[idx].base) { printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", - isi_card[card].irq, card+1); - isi_card[card].base=0; + isi_card[idx].irq, idx+1); + isi_card[idx].base=0; + card--; } } } + if (pci_present() && (card < BOARD_COUNT)) { + for (idx=0; idx < DEVID_COUNT; idx++) { + dev = NULL; + for (;;){ + if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) + break; + if (card >= BOARD_COUNT) + break; + + /* found a PCI ISI card! */ + ioaddr = dev->base_address[3]; /* i.e at offset 0x1c in the + * PCI configuration register + * space. + */ + ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + pciirq = dev->irq; + printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); + /* + * allot the first empty slot in the array + */ + for (count=0; count < BOARD_COUNT; count++) { + if (isi_card[count].base == 0) { + isi_card[count].base = ioaddr; + isi_card[count].irq = pciirq; + isi_card[count].isa = NO; + card++; + break; + } + } + } + if (card >= BOARD_COUNT) break; + } + } + if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); return -EIO; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index bd215a6370f8..58888cfadabb 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -155,6 +155,7 @@ struct pt_regs * kbd_pt_regs; #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; +int sysrq_enabled = 1; #endif /* @@ -247,7 +248,7 @@ void handle_scancode(unsigned char scancode, int down) sysrq_pressed = !up_flag; return; } else if (sysrq_pressed) { - if (!up_flag) { + if (!up_flag && sysrq_enabled) { handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); return; } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index f6b033924406..bc69e26058b0 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -755,6 +755,17 @@ static int lp_register(int nr, struct parport *port) printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); +#ifdef CONFIG_LP_CONSOLE + if (!nr) { + if (port->modes & PARPORT_MODE_SAFEININT) { + register_console (&lpcons); + printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP); + } else + printk (KERN_ERR "lp%d: cannot run console on %s\n", + CONSOLE_LP, port->name); + } +#endif + return 0; } @@ -842,12 +853,6 @@ int __init lp_init (void) printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n"); #endif } -#ifdef CONFIG_LP_CONSOLE - else { - register_console (&lpcons); - printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP); - } -#endif return 0; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 986f9007bd84..fd123de44e72 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -598,7 +598,7 @@ static struct file_operations memory_fops = { NULL /* fsync */ }; -__initfunc(int chr_dev_init(void)) +int __init chr_dev_init(void) { if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 9eda26551fb7..dde61fe778bd 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -413,7 +413,7 @@ static struct miscdevice nvram_dev = { }; -__initfunc(int nvram_init(void)) +int __init nvram_init(void) { /* First test whether the driver should init at all */ if (!CHECK_DRIVER_INIT()) diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index dda54324e5b4..a20a87447e79 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -894,7 +894,7 @@ static void pcxe_flush_chars(struct tty_struct *tty) * Driver setup function when linked into the kernel to optionally parse multible * "digi="-lines and initialize the driver at boot time. No probing. */ -__initfunc(void pcxx_setup(char *str, int *ints)) +void __init pcxx_setup(char *str, int *ints) { struct board_info board; @@ -1085,7 +1085,7 @@ __initfunc(void pcxx_setup(char *str, int *ints)) * function to initialize the driver with the given parameters, which are either * the default values from this file or the parameters given at boot. */ -__initfunc(int pcxe_init(void)) +int __init pcxe_init(void) { ulong memory_seg=0, memory_size=0; int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; diff --git a/drivers/char/planb.c b/drivers/char/planb.c index 1c6bf655be58..33ce793cfba7 100644 --- a/drivers/char/planb.c +++ b/drivers/char/planb.c @@ -2359,7 +2359,7 @@ static void release_planb(void) int init_module(void) { #else -__initfunc(int init_planbs(struct video_init *unused)) +int __init init_planbs(struct video_init *unused) { #endif int i; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 1e67c604e836..5f35b24ad66c 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -334,7 +334,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) tty->termios->c_cflag |= (CS8 | CREAD); } -__initfunc(int pty_init(void)) +int __init pty_init(void) { int i; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index adfa0a165634..b14d84f28e67 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -232,7 +232,7 @@ extern inline void rc_long_delay(unsigned long delay) } /* Reset and setup CD180 chip */ -__initfunc(static void rc_init_CD180(struct riscom_board const * bp)) +static void __init rc_init_CD180(struct riscom_board const * bp) { unsigned long flags; @@ -257,7 +257,7 @@ __initfunc(static void rc_init_CD180(struct riscom_board const * bp)) } /* Main probing routine, also sets irq. */ -__initfunc(static int rc_probe(struct riscom_board *bp)) +static int __init rc_probe(struct riscom_board *bp) { unsigned char val1, val2; int irqs = 0; @@ -1820,7 +1820,7 @@ static void rc_release_drivers(void) * addresses in this case. * */ -__initfunc(void riscom8_setup(char *str, int * ints)) +void __init riscom8_setup(char *str, int * ints) { int i; @@ -1836,7 +1836,7 @@ __initfunc(void riscom8_setup(char *str, int * ints)) /* * This routine must be called by kernel at boot time */ -__initfunc(int riscom8_init(void)) +int __init riscom8_init(void) { int i; int found = 0; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index cc0027ebe0ff..0c68943cd117 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1958,7 +1958,7 @@ static struct pci_dev *pci_find_slot(unsigned char bus, } #endif -__initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn)) +int __init register_PCI(int i, unsigned int bus, unsigned int device_fn) { int num_aiops, aiop, max_num_aiops, num_chan, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; @@ -1973,15 +1973,7 @@ __initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn)) if (!dev) return 0; -#if (LINUX_VERSION_CODE >= 0x020163) /* 2.1.99 */ - rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; -#else - ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, - &port); - if (ret) - return 0; - rcktpt_io_addr[i] = port & PCI_BASE_ADDRESS_IO_MASK; -#endif + rcktpt_io_addr[i] = dev->resource[0].start; switch(dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; @@ -2047,7 +2039,7 @@ __initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn)) return(1); } -__initfunc(static int init_PCI(int boards_found)) +static int __init init_PCI(int boards_found) { unsigned char bus, device_fn; int i, count = 0; @@ -2102,7 +2094,7 @@ __initfunc(static int init_PCI(int boards_found)) } #endif -__initfunc(static int init_ISA(int i, int *reserved_controller)) +static int __init init_ISA(int i, int *reserved_controller) { int num_aiops, num_chan; int aiop, chan; @@ -2154,7 +2146,7 @@ __initfunc(static int init_ISA(int i, int *reserved_controller)) /* * The module "startup" routine; it's run when the module is loaded. */ -__initfunc(int rp_init(void)) +int __init rp_init(void) { int i, retval, pci_boards_found, isa_boards_found; int reserved_controller = 0; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 7a744d37860e..0d87326a2954 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -524,7 +524,7 @@ static struct miscdevice rtc_dev= &rtc_fops }; -__initfunc(int rtc_init(void)) +int __init rtc_init(void) { unsigned long flags; #ifdef __alpha__ diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c index c8f21a184c64..a9a7a18db6fa 100644 --- a/drivers/char/softdog.c +++ b/drivers/char/softdog.c @@ -178,7 +178,7 @@ static struct miscdevice softdog_miscdev= &softdog_fops }; -__initfunc(void watchdog_init(void)) +void __init watchdog_init(void) { misc_register(&softdog_miscdev); init_timer(&watchdog_ticktock); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 23b8df504441..3a60b522e2b1 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -2280,7 +2280,7 @@ static void stl_offintr(void *private) * interrupt across multiple boards. */ -__initfunc(static int stl_mapirq(int irq, char *name)) +static int __init stl_mapirq(int irq, char *name) { int rc, i; @@ -2311,7 +2311,7 @@ __initfunc(static int stl_mapirq(int irq, char *name)) * Initialize all the ports on a panel. */ -__initfunc(static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)) +static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) { stlport_t *portp; int chipmask, i; @@ -2700,7 +2700,7 @@ static int inline stl_initech(stlbrd_t *brdp) * since the initial search and setup is very different. */ -__initfunc(static int stl_brdinit(stlbrd_t *brdp)) +static int __init stl_brdinit(stlbrd_t *brdp) { int i; @@ -3204,7 +3204,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns /*****************************************************************************/ -__initfunc(int stl_init(void)) +int __init stl_init(void) { printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); diff --git a/drivers/char/sx.c b/drivers/char/sx.c new file mode 100644 index 000000000000..7e5ff946523f --- /dev/null +++ b/drivers/char/sx.c @@ -0,0 +1,2684 @@ + +/* sx.c -- driver for the Specialix SX series cards. + * + * This driver will also support the older SI, and XIO cards. + * + * + * (C) 1998 R.E.Wolff@BitWizard.nl + * + * Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous + * version of this driver. Some fragments may have been copied. (none + * yet :-) + * + * Specialix pays for the development and support of this driver. + * Please DO contact support@specialix.co.uk if you require + * support. But please read the documentation (sx.txt) first. + * + * + * + * 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. + * + * Revision history: + * $Log: sx.c,v $ + * Revision 1.26 1999/08/05 15:22:14 wolff + * - Port to 2.3.x + * - Reformatted to Linus' liking. + * + * Revision 1.25 1999/07/30 14:24:08 wolff + * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0). + * + * Revision 1.24 1999/07/28 09:41:52 wolff + * - I noticed the remark about use-count straying in sx.txt. I checked + * sx_open, and found a few places where that could happen. I hope it's + * fixed now. + * + * Revision 1.23 1999/07/28 08:56:06 wolff + * - Fixed crash when sx_firmware run twice. + * - Added sx_slowpoll as a module parameter (I guess nobody really wanted + * to change it from the default... ) + * - Fixed a stupid editing problem I introduced in 1.22. + * - Fixed dropping characters on a termios change. + * + * Revision 1.22 1999/07/26 21:01:43 wolff + * Russell Brown noticed that I had overlooked 4 out of six modem control + * signals in sx_getsignals. Ooops. + * + * Revision 1.21 1999/07/23 09:11:33 wolff + * I forgot to free dynamically allocated memory when the driver is unloaded. + * + * Revision 1.20 1999/07/20 06:25:26 wolff + * The "closing wait" wasn't honoured. Thanks to James Griffiths for + * reporting this. + * + * Revision 1.19 1999/07/11 08:59:59 wolff + * Fixed an oops in close, when an open was pending. Changed the memtest + * a bit. Should also test the board in word-mode, however my card fails the + * memtest then. I still have to figure out what is wrong... + * + * Revision 1.18 1999/06/10 09:38:42 wolff + * Changed the format of the firmware revision from %04x to %x.%02x . + * + * Revision 1.17 1999/06/04 09:44:35 wolff + * fixed problem: reference to pci stuff when config_pci was off... + * Thanks to Jorge Novo for noticing this. + * + * Revision 1.16 1999/06/02 08:30:15 wolff + * added/removed the workaround for the DCD bug in the Firmware. + * A bit more debugging code to locate that... + * + * Revision 1.15 1999/06/01 11:35:30 wolff + * when DCD is left low (floating?), on TA's the firmware first tells us + * that DCD is high, but after a short while suddenly comes to the + * conclusion that it is low. All this would be fine, if it weren't that + * Unix requires us to send a "hangup" signal in that case. This usually + * all happens BEFORE the program has had a chance to ioctl the device + * into clocal mode.. + * + * Revision 1.14 1999/05/25 11:18:59 wolff + * Added PCI-fix. + * Added checks for return code of sx_sendcommand. + * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...) + * + * Revision 1.13 1999/04/29 15:18:01 wolff + * Fixed an "oops" that showed on SuSE 6.0 systems. + * Activate DTR again after stty 0. + * + * Revision 1.12 1999/04/29 07:49:52 wolff + * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming + * the connection would be dropped anyway. That is not always the case, + * and confuses people). + * Told the card to always monitor the modem signals. + * Added support for dynamic gs_debug adjustments. + * Now tells the rest of the system the number of ports. + * + * Revision 1.11 1999/04/24 11:11:30 wolff + * Fixed two stupid typos in the memory test. + * + * Revision 1.10 1999/04/24 10:53:39 wolff + * Added some of Christian's suggestions. + * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the + * card to send the signal to the process.....) + * + * Revision 1.9 1999/04/23 07:26:38 wolff + * Included Christian Lademann's 2.0 compile-warning fixes and interrupt + * assignment redesign. + * Cleanup of some other stuff. + * + * Revision 1.8 1999/04/16 13:05:30 wolff + * fixed a DCD change unnoticed bug. + * + * Revision 1.7 1999/04/14 22:19:51 wolff + * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!) + * + * Revision 1.6 1999/04/13 18:40:20 wolff + * changed misc-minor to 161, as assigned by HPA. + * + * Revision 1.5 1999/04/13 15:12:25 wolff + * Fixed use-count leak when "hangup" occurred. + * Added workaround for a stupid-PCIBIOS bug. + * + * + * Revision 1.4 1999/04/01 22:47:40 wolff + * Fixed < 1M linux-2.0 problem. + * (vremap isn't compatible with ioremap in that case) + * + * Revision 1.3 1999/03/31 13:45:45 wolff + * Firmware loading is now done through a separate IOCTL. + * + * Revision 1.2 1999/03/28 12:22:29 wolff + * rcs cleanup + * + * Revision 1.1 1999/03/28 12:10:34 wolff + * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). + * + * Revision 0.12 1999/03/28 09:20:10 wolff + * Fixed problem in 0.11, continueing cleanup. + * + * Revision 0.11 1999/03/28 08:46:44 wolff + * cleanup. Not good. + * + * Revision 0.10 1999/03/28 08:09:43 wolff + * Fixed loosing characters on close. + * + * Revision 0.9 1999/03/21 22:52:01 wolff + * Ported back to 2.2.... (minor things) + * + * Revision 0.8 1999/03/21 22:40:33 wolff + * Port to 2.0 + * + * Revision 0.7 1999/03/21 19:06:34 wolff + * Fixed hangup processing. + * + * Revision 0.6 1999/02/05 08:45:14 wolff + * fixed real_raw problems. Inclusion into kernel imminent. + * + * Revision 0.5 1998/12/21 23:51:06 wolff + * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it + * shouldn't have. THATs why I want to have transmit interrupts even when + * the buffer is empty. + * + * Revision 0.4 1998/12/17 09:34:46 wolff + * PPP works. ioctl works. Basically works! + * + * Revision 0.3 1998/12/15 13:05:18 wolff + * It works! Wow! Gotta start implementing IOCTL and stuff.... + * + * Revision 0.2 1998/12/01 08:33:53 wolff + * moved over to 2.1.130 + * + * Revision 0.1 1998/11/03 21:23:51 wolff + * Initial revision. Detects SX card. + * + * */ + + +#define RCS_ID "$Id: sx.c,v 1.26 1999/08/05 15:22:14 wolff Exp $" +#define RCS_REV "$Revision: 1.26 $" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */ +#define BYTE u8 +#define WORD u16 + +/* .... but the 3.0.4 version uses _u8 and _u16. */ +#define _u8 u8 +#define _u16 u16 + +#include "sxboards.h" +#include "sxwindow.h" + + +/* I don't think that this driver can handle more than 256 ports on + one machine. You'll have to increase the number of boards in sx.h + if you want more than 4 boards. */ + + +/* ************************************************************** */ +/* * This section can be removed when 2.0 becomes outdated.... * */ +/* ************************************************************** */ + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.3.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +#include + +#define Get_user(a,b) a = get_user(b) +#define Put_user(a,b) 0,put_user(a,b) +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + +#define pci_present pcibios_present +#define pci_read_config_word pcibios_read_config_word +#define pci_read_config_dword pcibios_read_config_dword + +static inline unsigned char get_irq (unsigned char bus, unsigned char fn) +{ + unsigned char t; + pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t); + return t; +} + +static inline void *ioremap(unsigned long base, long length) +{ + if (base < 0x100000) return (void *)base; + return vremap (base, length); +} + +#define my_iounmap(x, b) (((long)x<0x100000)?0:vfree ((void*)x)) + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + +/* Should be in a header somewhere. They are in tty.h on 2.2 */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ + +/* The return type of a "close" routine. */ +#define INT void +#define NO_ERROR /* Nothing */ + +#else + +/* The 2.2.x compatibility section. */ +#include + + +#define Get_user(a,b) get_user(a,b) +#define Put_user(a,b) put_user(a,b) +#define get_irq(pdev) pdev->irq + +#define INT int +#define NO_ERROR 0 + +#define my_iounmap(x,b) (iounmap((char *)(b))) + +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define wait_queue_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + + + +#include "generic_serial.h" +#include "sx.h" + + +/* ************************************************************** */ +/* * End of compatibility section.. * */ +/* ************************************************************** */ + + + +/* Why the hell am I defining these here? */ +#define SX_TYPE_NORMAL 1 +#define SX_TYPE_CALLOUT 2 + +#ifndef SX_NORMAL_MAJOR +/* This allows overriding on the compiler commandline, or in a "major.h" + include or something like that */ +#define SX_NORMAL_MAJOR 32 +#define SX_CALLOUT_MAJOR 33 +#endif + +#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 +#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 +#endif + + + +/* Configurable options: + (Don't be too sure that it'll work if you toggle them) */ + +/* Am I paranoid or not ? ;-) */ +#undef SX_PARANOIA_CHECK + + +/* 20 -> 2000 per second. The card should rate-limit interrupts at 100 + Hz, but it is user configurable. I don't recommend going above 1000 + Hz. The interrupt ratelimit might trigger if the interrupt is + shared with a very active other device. */ +#define IRQ_RATE_LIMIT 20 + +/* Sharing interrupts is possible now. If the other device wants more + than 2000 interrupts per second, we'd gracefully decline further + interrupts. That's not what we want. On the other hand, if the + other device interrupts 2000 times a second, don't use the SX + interrupt. Use polling. */ +#undef IRQ_RATE_LIMIT + + +#if 0 +/* Not implemented */ +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#define SX_REPORT_FIFO +#define SX_REPORT_OVERRUN +#endif + + +/* Function prototypes */ +static void sx_disable_tx_interrupts (void * ptr); +static void sx_enable_tx_interrupts (void * ptr); +static void sx_disable_rx_interrupts (void * ptr); +static void sx_enable_rx_interrupts (void * ptr); +static int sx_get_CD (void * ptr); +static void sx_shutdown_port (void * ptr); +static void sx_set_real_termios (void *ptr); +static void sx_hungup (void *ptr); +static void sx_close (void *ptr); +static int sx_chars_in_buffer (void * ptr); +static int sx_init_board (struct sx_board *board); +static int sx_init_portstructs (int nboards, int nports); +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int sx_fw_open(struct inode *inode, struct file *filp); +static INT sx_fw_release(struct inode *inode, struct file *filp); +static int sx_init_drivers(void); +void my_hd (unsigned char *addr, int len); + + + +static struct tty_driver sx_driver, sx_callout_driver; + +static struct tty_struct * sx_table[SX_NPORTS] = { NULL, }; +static struct termios ** sx_termios; +static struct termios ** sx_termios_locked; + +struct sx_board boards[SX_NBOARDS]; +struct sx_port *sx_ports; +int sx_refcount; +int sx_initialized = 0; +int sx_nports = 0; +int sx_debug = 0; + + +/* You can have the driver poll your card. + - Set sx_poll to 1 to poll every timer tick (10ms on Intel). + This is used when the card cannot use an interrupt for some reason. + + - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If + the driver misses an interrupt (report this if it DOES happen to you!) + everything will continue to work.... + */ +int sx_poll = 1; +int sx_slowpoll = 0; + +/* The card limits the number of interrupts per second. + At 115k2 "100" should be sufficient. + If you're using higher baudrates, you can increase this... + */ + +int sx_maxints = 100; + +/* These are the only open spaces in my computer. Yours may have more + or less.... */ +int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; +int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; + +#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int)) +#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int)) + + +/* Set the mask to all-ones. This alas, only supports 32 interrupts. + Some architectures may need more. */ +int sx_irqmask = -1; + +#ifndef TWO_ZERO +#ifdef MODULE +MODULE_PARM(sx_poll, "i"); +MODULE_PARM(sx_slowpoll, "i"); +MODULE_PARM(sx_maxints, "i"); +MODULE_PARM(sx_debug, "i"); +MODULE_PARM(sx_irqmask, "i"); +#endif +#endif + +static struct real_driver sx_real_driver = { + sx_disable_tx_interrupts, + sx_enable_tx_interrupts, + sx_disable_rx_interrupts, + sx_enable_rx_interrupts, + sx_get_CD, + sx_shutdown_port, + sx_set_real_termios, + sx_chars_in_buffer, + sx_close, + sx_hungup, + NULL +}; + + +/* + This driver can spew a whole lot of debugging output at you. If you + need maximum performance, you should disable the DEBUG define. To + aid in debugging in the field, I'm leaving the compile-time debug + features enabled, and disable them "runtime". That allows me to + instruct people with problems to enable debugging without requiring + them to recompile... +*/ +#define DEBUG + + +#ifdef DEBUG +#define sx_dprintk(f, str...) if (sx_debug & f) printk (str) +#else +#define sx_dprintk(f, str...) /* nothing */ +#endif + + + +#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n") +#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit " __FUNCTION__ "\n") + +#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \ + "(port %d)\n", port->line) + + + + +/* + * Firmware loader driver specific routines + * + */ + +static struct file_operations sx_fw_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + sx_fw_ioctl, + NULL, /* mmap */ + sx_fw_open, +#ifndef TWO_ZERO + NULL, /* flush */ +#endif + sx_fw_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct miscdevice sx_fw_device = { + SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops +}; + + + + + +#ifdef SX_PARANOIA_CHECK + +/* This doesn't work. Who's paranoid around here? Not me! */ + +static inline int sx_paranoia_check(struct sx_port const * port, + kdev_t device, const char *routine) +{ + + static const char *badmagic = + KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n"; + static const char *badinfo = + KERN_ERR "sx: Warning: null sx port for device %s in %s\n"; + + if (!port) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != SX_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } + + return 0; +} +#else +#define sx_paranoia_check(a,b,c) 0 +#endif + +/* The timeouts. First try 30 times as fast as possible. Then give + the card some time to breathe between accesses. (Otherwise the + processor on the card might not be able to access its OWN bus... */ + +#define TIMEOUT_1 30 +#define TIMEOUT_2 1000000 + + +/* This needs redoing for Alpha -- REW -- Done. */ + +inline void write_sx_byte (struct sx_board *board, int offset, u8 byte) +{ + writeb (byte, board->base+offset); +} + +inline u8 read_sx_byte (struct sx_board *board, int offset) +{ + return readb (board->base+offset); +} + + +inline void write_sx_word (struct sx_board *board, int offset, u16 word) +{ + writew (word, board->base+offset); +} + +inline u16 read_sx_word (struct sx_board *board, int offset) +{ + return readw (board->base + offset); +} + + +int sx_busy_wait_eq (struct sx_board *board, + int offset, + int mask, + int correctval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + +int sx_busy_wait_neq (struct sx_board *board, + int offset, + int mask, + int badval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + + +/* 5.6.4 of 6210028 r2.3 */ +int sx_reset (struct sx_board *board) +{ + func_enter (); + + if (IS_SX_BOARD (board)) { + + write_sx_byte (board, SX_CONFIG, 0); + write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */ + + if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) { + printk (KERN_INFO "sx: Card doesn't respond to reset....\n"); + return 0; + } + } else { + /* Gory details of the SI/ISA board */ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET); + write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR); + } + + func_exit (); + return 1; +} + + +/* This doesn't work on machines where "NULL" isn't 0 */ +/* If you have one of those, someone will need to write + the equivalent of this, which will amount to about 3 lines. I don't + want to complicate this right now. -- REW + (See, I do write comments every now and then :-) */ +#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem)) + + +#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem)) +#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem)) +#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem)) + + +#define sx_write_channel_byte(port, elem, val) \ + write_sx_byte (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_byte(port, elem) \ + read_sx_byte (port->board, CHAN_OFFSET (port, elem)) + +#define sx_write_channel_word(port, elem, val) \ + write_sx_word (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_word(port, elem) \ + read_sx_word (port->board, CHAN_OFFSET (port, elem)) + + +#define sx_write_module_byte(board, addr, elem, val) \ + write_sx_byte (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_byte(board, addr, elem) \ + read_sx_byte (board, MODU_OFFSET (board, addr, elem)) + +#define sx_write_module_word(board, addr, elem, val) \ + write_sx_word (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_word(board, addr, elem) \ + read_sx_word (board, MODU_OFFSET (board, addr, elem)) + + +#define sx_write_board_byte(board, elem, val) \ + write_sx_byte (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_byte(board, elem) \ + read_sx_byte (board, BRD_OFFSET (board, elem)) + +#define sx_write_board_word(board, elem, val) \ + write_sx_word (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_word(board, elem) \ + read_sx_word (board, BRD_OFFSET (board, elem)) + + +int sx_start_board (struct sx_board *board) +{ + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN); + } else { + /* Don't bug me about the clear_set. + I haven't the foggiest idea what it's about -- REW*/ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + return 1; +} + +#define SX_IRQ_REG_VAL(board) \ + ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0) + +/* Note. The SX register is write-only. Therefore, we have to enable the + bus too. This is a no-op, if you don't mess with this driver... */ +int sx_start_interrupts (struct sx_board *board) +{ + + /* Don't call this with board->irq == 0 */ + + if (IS_SX_BOARD(board)) { + write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) | + SX_CONF_BUSEN | + SX_CONF_HOSTIRQ); + } else { + switch (board->irq) { + case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break; + case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break; + case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break; + default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n", + board->irq); + return 0; + } + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + + return 1; +} + + +int sx_send_command (struct sx_port *port, + int command, + int mask, + int newstat) +{ + func_enter2 (); + write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command); + func_exit (); + return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat); +} + + +char *mod_type_s (int module_type) +{ + switch (module_type) { + case TA4: return "TA4"; + case TA8: return "TA8"; + case TA4_ASIC: return "TA4_ASIC"; + case TA8_ASIC: return "TA8_ASIC"; + case MTA_CD1400:return "MTA_CD1400"; + case SXDC: return "SXDC"; + default:return "Unknown/invalid"; + } +} + + +char *pan_type_s (int pan_type) +{ + switch (pan_type) { + case MOD_RS232DB25: return "MOD_RS232DB25"; + case MOD_RS232RJ45: return "MOD_RS232RJ45"; + case MOD_RS422DB25: return "MOD_RS422DB25"; + case MOD_PARALLEL: return "MOD_PARALLEL"; + case MOD_2_RS232DB25: return "MOD_2_RS232DB25"; + case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45"; + case MOD_2_RS422DB25: return "MOD_2_RS422DB25"; + case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE"; + case MOD_2_PARALLEL: return "MOD_2_PARALLEL"; + case MOD_BLANK: return "empty"; + default:return "invalid"; + } +} + + +int mod_compat_type (int module_type) +{ + return module_type >> 4; +} + + +static void sx_setsignals (struct sx_port *port, int dtr, int rts) +{ + int t; + func_enter2 (); + + t = sx_read_channel_byte (port, hi_op); + if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR); + if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS); + sx_write_channel_byte (port, hi_op, t); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts); + func_exit (); +} + + + +static int sx_getsignals (struct sx_port *port) +{ + int i_stat,o_stat; + + o_stat = sx_read_channel_byte (port, hi_op); + i_stat = sx_read_channel_byte (port, hi_ip); + + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n", + (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0, + port->c_dcd, sx_get_CD (port), + sx_read_channel_byte (port, hi_ip), + sx_read_channel_byte (port, hi_state)); + + return (((o_stat & OP_DTR)?TIOCM_DTR:0) | + ((o_stat & OP_RTS)?TIOCM_RTS:0) | + ((i_stat & IP_CTS)?TIOCM_CTS:0) | + ((i_stat & IP_DCD)?TIOCM_CAR:0) | + ((i_stat & IP_DSR)?TIOCM_DSR:0) | + ((i_stat & IP_RI)?TIOCM_RNG:0) + ); +} + + +static void sx_set_baud (struct sx_port *port) +{ + int t; + + if (port->board->ta_type == MOD_SXDC) { + switch (port->gs.baud) { + /* Save some typing work... */ +#define e(x) case x:t= BAUD_ ## x ; break + e(50);e(75);e(110);e(150);e(200);e(300);e(600); + e(1200);e(1800);e(2000);e(2400);e(4800);e(7200); + e(9600);e(14400);e(19200);e(28800);e(38400); + e(56000);e(57600);e(64000);e(76800);e(115200); + e(128000);e(150000);e(230400);e(256000);e(460800); + e(921600); + case 134 :t = BAUD_134_5; break; + case 0 :t = -1; + break; + default: + /* Can I return "invalid"? */ + t = BAUD_9600; + printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t > 0) { + /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */ + sx_setsignals (port, 1, -1); + /* XXX This is not TA & MTA compatible */ + sx_write_channel_byte (port, hi_csr, 0xff); + + sx_write_channel_byte (port, hi_txbaud, t); + sx_write_channel_byte (port, hi_rxbaud, t); + } else { + sx_setsignals (port, 0, -1); + } + } else { + switch (port->gs.baud) { +#define e(x) case x:t= CSR_ ## x ; break + e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800); + e(1800);e(9600); + e(19200);e(57600);e(38400); + /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */ + case 110: + if (port->board->ta_type == MOD_TA) { + t = CSR_110; + break; + } else { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } + case 115200: + if (port->board->ta_type == MOD_TA) { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } else { + t = CSR_110; + break; + } + case 0 :t = -1; + break; + default: + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t >= 0) { + sx_setsignals (port, 1, -1); + sx_write_channel_byte (port, hi_csr, t * 0x11); + } else { + sx_setsignals (port, 0, -1); + } + } +} + + +/* Simon Allen's version of this routine was 225 lines long. 85 is a lot + better. -- REW */ + +static void sx_set_real_termios (void *ptr) +{ + struct sx_port *port = ptr; + + func_enter2(); + + /* What is this doing here? -- REW + Ha! figured it out. It is to allow you to get DTR active again + if you've dropped it with stty 0. Moved to set_baud, where it + belongs (next to the drop dtr if baud == 0) -- REW */ + /* sx_setsignals (port, 1, -1); */ + + sx_set_baud (port); + +#define CFLAG port->gs.tty->termios->c_cflag + sx_write_channel_byte (port, hi_mr1, + (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) | + (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) | + (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) | + (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) | + (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) | + (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) | + (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) ); + + sx_write_channel_byte (port, hi_mr2, + (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) | + (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP)); + + switch (CFLAG & CSIZE) { + case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break; + case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break; + case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break; + case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break; + default: + printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE); + break; + } + + sx_write_channel_byte (port, hi_prtcl, + (I_IXON (port->gs.tty)?SP_TXEN:0) | + (I_IXOFF (port->gs.tty)?SP_RXEN:0) | + (I_IXANY (port->gs.tty)?SP_TANY:0) | + SP_DCEN); + + sx_write_channel_byte (port, hi_break, + I_OTHER(port->gs.tty) ? 0: + (I_IGNBRK(port->gs.tty)?BR_IGN:0 | + I_BRKINT(port->gs.tty)?BR_INT:0)); + + sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty)); + + if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) { + if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n"); + } + } else { + sx_dprintk (SX_DEBUG_TERMIOS, + "sx: Not sending reconfigure: port isn't open (%02x).\n", + sx_read_channel_byte (port, hi_hstat)); + } + + + /* Tell line discipline whether we will do input cooking */ + if(I_OTHER(port->gs.tty)) { + clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } else { + set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", + port->gs.tty->termios->c_iflag, + I_OTHER(port->gs.tty)); + + +/* Tell line discipline whether we will do output cooking. + * If OPOST is set and no other output flags are set then we can do output + * processing. Even if only *one* other flag in the O_OTHER group is set + * we do cooking in software. + */ + if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) { + set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } else { + clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", + port->gs.tty->termios->c_oflag, + O_OTHER(port->gs.tty)); + /* port->c_dcd = sx_get_CD (port); */ + func_exit (); +} + + + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +/* Note: + Other drivers use the macro "MIN" to calculate how much to copy. + This has the disadvantage that it will evaluate parts twice. That's + expensive when it's IO (and the compiler cannot optimize those away!). + Moreover, I'm not sure that you're race-free. + + I assign a value, and then only allow the value to decrease. This + is always safe. This makes the code a few lines longer, and you + know I'm dead against that, but I think it is required in this + case. */ + + +void sx_transmit_chars (struct sx_port *port) +{ + int c; + int tx_ip; + int txroom; + + func_enter2 (); + sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n", + port, port->gs.xmit_cnt); + + if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) { + return; + } + + while (1) { + c = port->gs.xmit_cnt; + + sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c); + tx_ip = sx_read_channel_byte (port, hi_txipos); + + /* Took me 5 minutes to deduce this formula. + Luckily it is literally in the manual in section 6.5.4.3.5 */ + txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff; + + /* Don't copy more bytes than there is room for in the buffer */ + if (c > txroom) + c = txroom; + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom ); + + /* Don't copy past the end of the hardware transmit buffer */ + if (c > 0x100 - tx_ip) + c = 0x100 - tx_ip; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip ); + + /* Don't copy pas the end of the source buffer */ + if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) + c = SERIAL_XMIT_SIZE - port->gs.xmit_tail; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", + c, SERIAL_XMIT_SIZE- port->gs.xmit_tail); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + + memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip, + port->gs.xmit_buf + port->gs.xmit_tail, c); + + /* Update the pointer in the card */ + sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff); + + /* Update the kernel buffer end */ + port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1); + + /* This one last. (this is essential) + It would allow others to start putting more data into the buffer! */ + port->gs.xmit_cnt -= c; + } + + if (port->gs.xmit_cnt == 0) { + sx_disable_tx_interrupts (port); + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + port->gs.wakeup_chars); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); + func_exit (); +} + + +/* Note the symmetry between receiving chars and transmitting them! + Note: The kernel should have implemented both a receive buffer and + a transmit buffer. */ + +/* Inlined: Called only once. Remove the inline when you add another call */ +inline void sx_receive_chars (struct sx_port *port) +{ + int c; + int rx_op; + struct tty_struct *tty; + int copied=0; + + /* func_enter2 (); */ + tty = port->gs.tty; + while (1) { + rx_op = sx_read_channel_byte (port, hi_rxopos); + c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff; + + sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + c > TTY_FLIPBUF_SIZE) + c = TTY_FLIPBUF_SIZE - tty->flip.count; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* Don't copy past the end of the hardware receive buffer */ + if (rx_op + c > 0x100) c = 0x100 - rx_op; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, + read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op), + CHAN_OFFSET(port, hi_rxbuf)); + memcpy_fromio (tty->flip.char_buf_ptr, + port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c); + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c); + + /* Update the kernel buffer end */ + tty->flip.count += c; + tty->flip.char_buf_ptr += c; + tty->flip.flag_buf_ptr += c; + + /* This one last. ( Not essential.) + It allows the card to start putting more data into the buffer! + Update the pointer in the card */ + sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff); + + copied += c; + } + if (copied) { + struct timeval tv; + + do_gettimeofday (&tv); + sx_dprintk (SX_DEBUG_RECEIVE, + "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n", + port->line, copied, + (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw); + + /* Tell the rest of the system the news. Great news. New characters! */ + tty_flip_buffer_push (tty); + /* tty_schedule_flip (tty); */ + } + + /* func_exit (); */ +} + +/* Inlined: it is called only once. Remove the inline if you add another + call */ +inline void sx_check_modem_signals (struct sx_port *port) +{ + int hi_state; + int c_dcd; + + hi_state = sx_read_channel_byte (port, hi_state); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n", + port->c_dcd, sx_get_CD (port)); + + if (hi_state & ST_BREAK) { + hi_state &= ~ST_BREAK; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n"); + + sx_write_channel_byte (port, hi_state, hi_state); + if (port->gs.flags & ASYNC_SAK) { + do_SAK (port->gs.tty); + } + } + if (hi_state & ST_DCD) { + hi_state &= ~ST_DCD; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n"); + sx_write_channel_byte (port, hi_state, hi_state); + c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd); + if (c_dcd != port->c_dcd) { + port->c_dcd = c_dcd; + if (sx_get_CD (port)) { + /* DCD went UP */ + if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || + ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) && + (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) { + /* Are we blocking in open?*/ + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n"); + wake_up_interruptible(&port->gs.open_wait); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n"); + } + } else { + /* DCD went down! */ + if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && + (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n"); + tty_hangup (port->gs.tty); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n"); + } + } + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n"); + } + } +} + + +/* This is what an interrupt routine should look like. + * Small, elegant, clear. + */ + +static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs) +{ + struct sx_board *board = ptr; + struct sx_port *port; + int i; + + /* func_enter (); */ + sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); + + /* AAargh! The order in which to do these things is essential and + not trivial. + + - Rate limit goes before "recursive". Otherwise a series of + recursive calls will hang the machine in the interrupt routine. + + - hardware twiddling goes before "recursive". Otherwise when we + poll the card, and a recursive interrupt happens, we wont + ack the card, so it might keep on interrupting us. (especially + level sensitive interrupt systems like PCI). + + - Rate limit goes before hardware twiddling. Otherwise we won't + catch a card that has gone bonkers. + + - The "initialized" test goes after the hardware twiddling. Otherwise + the card will stick us in the interrupt routine again. + + - The initialized test goes before recursive. + */ + + + +#ifdef IRQ_RATE_LIMIT + /* Aaargh! I'm ashamed. This costs more lines-of-code than the + actual interrupt routine!. (Well, used to when I wrote that comment) */ + { + static int lastjif; + static int nintr=0; + + if (lastjif == jiffies) { + if (++nintr > IRQ_RATE_LIMIT) { + free_irq (board->irq, board); + printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n", + board->irq); + } + } else { + lastjif = jiffies; + nintr = 0; + } + } +#endif + + + if (board->irq == irq) { + /* Tell the card we've noticed the interrupt. */ + + sx_write_board_word (board, cc_int_pending, 0); + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_RESET_IRQ, 1); + } else { + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + } + + if (!sx_initialized) return; + if (!(board->flags & SX_BOARD_INITIALIZED)) return; + + if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) { + printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq); + return; + } + + for (i=0;inports;i++) { + port = &board->ports[i]; + if (port->gs.flags & GS_ACTIVE) { + if (sx_read_channel_byte (port, hi_state)) { + sx_dprintk (SX_DEBUG_INTERRUPTS, + "Port %d: modem signal change?... \n", i); + sx_check_modem_signals (port); + } + if (port->gs.xmit_cnt) { + sx_transmit_chars (port); + } + if (!(port->gs.flags & SX_RX_THROTTLE)) { + sx_receive_chars (port); + } + } + } + + clear_bit (SX_BOARD_INTR_LOCK, &board->locks); + + sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); + /* func_exit (); */ +} + + +static void sx_pollfunc (unsigned long data) +{ + struct sx_board *board = (struct sx_board *) data; + + func_enter (); + + sx_interrupt (0, board, NULL); + + board->timer.expires = jiffies + sx_poll; + add_timer (&board->timer); + func_exit (); +} + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the generic_serial driver * + * ********************************************************************** */ + +/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */ +/* Hmm. Ok I figured it out. You don't. */ + +static void sx_disable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_enable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + int data_in_buffer; + func_enter2(); + + /* First transmit the characters that we're supposed to */ + sx_transmit_chars (port); + + /* The sx card will never interrupt us if we don't fill the buffer + past 25%. So we keep considering interrupts off if that's the case. */ + data_in_buffer = (sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff; + + /* XXX Must be "HIGH_WATER" for SI card according to doc. */ + if (data_in_buffer < LOW_WATER) + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_disable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + +static void sx_enable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + + +/* Jeez. Isn't this simple? */ +static int sx_get_CD (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0); +} + + +/* Jeez. Isn't this simple? */ +static int sx_chars_in_buffer (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff); +} + + +static void sx_shutdown_port (void * ptr) +{ + struct sx_port *port = ptr; + + func_enter(); + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + sx_setsignals (port, 0, 0); + } + + func_exit(); +} + + + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the rest of the system * + * ********************************************************************** */ + + +static int sx_fw_open(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_INC_USE_COUNT; + func_exit (); + return 0; +} + + +static INT sx_fw_release(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); + return NO_ERROR; +} + + +static int sx_open (struct tty_struct * tty, struct file * filp) +{ + struct sx_port *port; + int retval, line; + + func_enter(); + + if (!sx_initialized) { + return -EIO; + } + + line = MINOR(tty->device); + sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", + current->pid, line, tty, current->tty, sx_nports); + + if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports)) + return -ENODEV; + + port = & sx_ports[line]; + port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a + 1 -> 0 transition. */ + + + sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd); + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + + sx_dprintk (SX_DEBUG_OPEN, "starting port\n"); + + /* + * Start up serial port + */ + retval = gs_init_port(&port->gs); + sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n"); + if (retval) { + port->gs.count--; + return retval; + } + + port->gs.flags |= GS_ACTIVE; + sx_setsignals (port, 1,1); + + sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", + port->gs.count); + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n"); + +#if 0 + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port, sizeof (*port)); +#else + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port->board->base + port->ch_base, + sizeof (*port)); +#endif + + if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n"); + MOD_DEC_USE_COUNT; + port->gs.count--; + return -EIO; + } + + retval = block_til_ready(port, filp); + sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", + retval, port->gs.count); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + /* tty->low_latency = 1; */ + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + sx_set_real_termios (port); + } + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + port->c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); + func_exit(); + return 0; + +} + + +/* I haven't the foggiest why the decrement use count has to happen + here. The whole linux serial drivers stuff needs to be redesigned. + My guess is that this is a hack to minimize the impact of a bug + elsewhere. Thinking about it some more. (try it sometime) Try + running minicom on a serial port that is driven by a modularized + driver. Have the modem hangup. Then remove the driver module. Then + exit minicom. I expect an "oops". -- REW */ +static void sx_hungup (void *ptr) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); +} + + +static void sx_close (void *ptr) +{ + struct sx_port *port = ptr; + /* Give the port 5 seconds to close down. */ + int to = 5 * HZ; + + func_enter (); + sx_send_command (port, HS_CLOSE, 0, 0); + + while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (1); + if (signal_pending (current)) + break; + } + current->state = TASK_RUNNING; + if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { + if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { + printk (KERN_ERR + "sx: sent the force_close command, but card didn't react\n"); + } else + sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); + } + + sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", + 5 * HZ - to - 1, port->gs.count); + + MOD_DEC_USE_COUNT; + func_exit (); +} + + + +/* This is relatively thorough. But then again it is only 20 lines. */ +#define MARCHUP for (i=min;i=min;i--) +#define W0 write_sx_byte (board, i, 0x55) +#define W1 write_sx_byte (board, i, 0xaa) +#define R0 if (read_sx_byte (board, i) != 0x55) return 1 +#define R1 if (read_sx_byte (board, i) != 0xaa) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest (struct sx_board *board, int min, int max) +{ + int i; + + /* This is a marchb. Theoretically, marchb catches much more than + simpler tests. In practise, the longer test just catches more + intermittent errors. -- REW + (For the theory behind memory testing see: + Testing Semiconductor Memories by A.J. van de Goor.) */ + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +#undef MARCHUP +#undef MARCHDOWN +#undef W0 +#undef W1 +#undef R0 +#undef R1 + +#define MARCHUP for (i=min;i=min;i-=2) +#define W0 write_sx_word (board, i, 0x55aa) +#define W1 write_sx_word (board, i, 0xaa55) +#define R0 if (read_sx_word (board, i) != 0x55aa) return 1 +#define R1 if (read_sx_word (board, i) != 0xaa55) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest_w (struct sx_board *board, int min, int max) +{ + int i; + + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + int *descr = (int *)arg, i; + static struct sx_board *board = NULL; + int nbytes, offset, data; + char *tmp; + + func_enter(); + +#if 0 + /* Removed superuser check: Sysops can use the permissions on the device + file to restrict access. Recommendation: Root only. (root.root 600) */ + if (!suser ()) { + return -EPERM; + } +#endif + + sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg); + + if (!board) board = &boards[0]; + if (board->flags & SX_BOARD_PRESENT) { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n", + board->flags); + } else { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:", + board->flags); + for (i=0;i< SX_NBOARDS;i++) + sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags); + sx_dprintk (SX_DEBUG_FIRMWARE, "\n"); + return -EIO; + } + + switch (cmd) { + case SXIO_SET_BOARD: + sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg); + if (arg > SX_NBOARDS) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n"); + if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n"); + board = &boards[arg]; + break; + case SXIO_GET_TYPE: + rc = IS_SX_BOARD (board)? SX_TYPE_SX:SX_TYPE_SI; + sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); + break; + case SXIO_DO_RAMTEST: + if (sx_initialized) /* Already initialized: better not ramtest the board. */ + return -EPERM; + if (IS_SX_BOARD (board)) { + rc = do_memtest (board, 0, 0x7000); + if (!rc) rc = do_memtest (board, 0, 0x7000); + /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/ + } else { + rc = do_memtest (board, 0, 0x7ff8); + /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */ + } + sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc); + break; + case SXIO_DOWNLOAD: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + if (!sx_reset (board)) + return -EIO; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER); + if (!tmp) return -ENOMEM; + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + while (nbytes && data) { + for (i=0;inbytes)?nbytes-i:SX_CHUNK_SIZE); + memcpy_toio ((char *) (board->base + offset + i), tmp, + (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE); + } + + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + } + kfree (tmp); + sx_nports += sx_init_board (board); + rc = sx_nports; + break; + case SXIO_INIT: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + /* This is not allowed until all boards are initialized... */ + for (i=0;i= 0) + sx_initialized++; + break; + case SXIO_SETDEBUG: + sx_debug = arg; + break; + case SXIO_GETDEBUG: + rc = sx_debug; + break; + case SXIO_SETGSDEBUG: + gs_debug = arg; + break; + case SXIO_GETGSDEBUG: + rc = gs_debug; + break; + default: + printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd); + break; + } + func_exit (); + return rc; +} + + +static int sx_ioctl (struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int rc; + struct sx_port *port = tty->driver_data; + int ival; + + /* func_enter2(); */ + + rc = 0; + switch (cmd) { + case TIOCGSOFTCAR: + rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + Get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + gs_getserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = sx_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + + default: + rc = -ENOIOCTLCMD; + break; + } + + /* func_exit(); */ + return rc; +} + + +/* The throttle/unthrottle scheme for the Specialix card is different + * from other drivers and deserves some explanation. + * The Specialix hardware takes care of XON/XOFF + * and CTS/RTS flow control itself. This means that all we have to + * do when signalled by the upper tty layer to throttle/unthrottle is + * to make a note of it here. When we come to read characters from the + * rx buffers on the card (sx_receive_chars()) we look to see if the + * upper layer can accept more (as noted here in sx_rx_throt[]). + * If it can't we simply don't remove chars from the cards buffer. + * When the tty layer can accept chars, we again note that here and when + * sx_receive_chars() is called it will remove them from the cards buffer. + * The card will notice that a ports buffer has drained below some low + * water mark and will unflow control the line itself, using whatever + * flow control scheme is in use for that port. -- Simon Allen + */ + +static void sx_throttle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* If the port is using any type of input flow + * control then throttle the port. + */ + if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) { + port->gs.flags |= SX_RX_THROTTLE; + } + func_exit(); +} + + +static void sx_unthrottle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* Always unthrottle even if flow control is not enabled on + * this port in case we disabled flow control while the port + * was throttled + */ + port->gs.flags &= ~SX_RX_THROTTLE; + func_exit(); + return; +} + + +/* ********************************************************************** * + * Here are the initialization routines. * + * ********************************************************************** */ + + + + +static int sx_init_board (struct sx_board *board) +{ + int addr; + int chans; + int type; + + func_enter(); + + /* This is preceded by downloading the download code. */ + + board->flags |= SX_BOARD_INITIALIZED; + + /* This resets the processor again, to make sure it didn't do any + foolish things while we were downloading the image */ + if (!sx_reset (board)) + return 0; + + sx_start_board (board); + + if (!sx_busy_wait_neq (board, 0, 0xff, 0)) { + printk (KERN_ERR "sx: Ooops. Board won't initialize.\n"); + return 0; + } + + /* Ok. So now the processor on the card is running. It gathered + some info for us... */ + sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10); + sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30); + + sx_dprintk (SX_DEBUG_INIT, + "init_status: %x, %dk memory, firmware V%x.%02x,\n", + read_sx_byte (board, 0), read_sx_byte(board, 1), + read_sx_byte (board, 5), read_sx_byte(board, 4)); + + if (read_sx_byte (board, 0) == 0xff) { + printk (KERN_INFO "sx: No modules found. Sorry.\n"); + board->nports = 0; + return 0; + } + + chans = 0; + + if (IS_SX_BOARD(board)) { + sx_write_board_word (board, cc_int_count, sx_maxints); + } else { + if (sx_maxints) + sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints); + } + + /* grab the first module type... */ + /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */ + board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip)); + + /* XXX byteorder */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + type = sx_read_module_byte (board, addr, mc_chip); + sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n", + addr, read_sx_byte (board, addr + 2)); + + chans += sx_read_module_byte (board, addr, mc_type); + + sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n", + mod_type_s (type), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4)); + + sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n", + sx_read_module_byte (board, addr, mc_rev1), + sx_read_module_byte (board, addr, mc_rev2), + sx_read_module_byte (board, addr, mc_mtaasic_rev)); + + /* The following combinations are illegal: It should theoretically + work, but timing problems make the bus HANG. */ + + if (mod_compat_type (type) != board->ta_type) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't mix TA/MTA/SXDC on the same hostadapter.\n"); + chans=0; + break; + } + if (IS_SI_BOARD(board) && (mod_compat_type(type) == 4)) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't use SXDCs on an SI/XIO adapter.\n"); + chans=0; + break; + } +#if 0 /* Problem fixed: firmware 3.05 */ + if (IS_SX_BOARD(board) && (type == TA8)) { + /* There are some issues with the firmware and the DCD/RTS + lines. It might work if you tie them together or something. + It might also work if you get a newer sx_firmware. Therefore + this is just a warning. */ + printk (KERN_WARNING "sx: The SX host doesn't work too well " + "with the TA8 adapters.\nSpecialix is working on it.\n"); + } +#endif + } + + if (chans) { + /* board->flags |= SX_BOARD_PRESENT; */ + if(board->irq > 0) { + /* fixed irq, probably PCI */ + if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */ + if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) { + printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq); + board->irq = 0; + } + } else + board->irq = 0; + } else if(board->irq < 0 && sx_irqmask) { + /* auto-allocate irq */ + int irqnr; + int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK); + for(irqnr = 15; irqnr > 0; irqnr--) + if(irqmask & (1 << irqnr)) + if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) + break; + if(! irqnr) + printk(KERN_ERR "sx: Cannot allocate IRQ.\n"); + board->irq = irqnr; + } else + board->irq = 0; + + if (board->irq) { + /* Found a valid interrupt, start up interrupts! */ + sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq); + sx_start_interrupts (board); + board->poll = sx_slowpoll; + board->flags |= SX_IRQ_ALLOCATED; + } else { + /* no irq: setup board for polled operation */ + board->poll = sx_poll; + sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll); + } + + /* The timer should be initialized anyway: That way we can safely + del_timer it when the module is unloaded. */ + init_timer (&board->timer); + + if (board->poll) { + board->timer.data = (unsigned long) board; + board->timer.function = sx_pollfunc; + board->timer.expires = jiffies + board->poll; + add_timer (&board->timer); + } + } else { + board->irq = 0; + } + + board->nports = chans; + sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports); + + func_exit(); + return chans; +} + + +void printheader(void) +{ + static int header_printed = 0; + + if (!header_printed) { + printk (KERN_INFO "Specialix SX driver " + "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n"); + printk (KERN_INFO "sx: version %s\n", RCS_ID); + header_printed = 1; + } +} + + +int probe_sx (struct sx_board *board) +{ + struct vpd_prom vpdp; + char *p; + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", + board->base + SX_VPD_ROM); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SX_VPD_ROM), 0x40); + + p = (char *) &vpdp; + for (i=0;i< sizeof (struct vpd_prom);i++) + *p++ = read_sx_byte (board, SX_VPD_ROM + i*2); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)&vpdp, 0x20); + + sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n"); + + if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) { + sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n", + vpdp.identifier); + return 0; + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base); + printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", + vpdp.hwrev, vpdp.hwass, vpdp.uniqid); + printk ( "Manufactured: %d/%d\n", + 1970 + vpdp.myear, vpdp.mweek); + + + if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) && + (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) { + /* This might be a bit harsh. This was the primary reason the + SX/ISA card didn't work at first... */ + printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n"); + return (0); + } + + if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) { + if (board->base & 0x8000) { + printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base); + printk (KERN_WARNING "sx: Read sx.txt for more info.\n"); + } + } + + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + + +/* Specialix probes for this card at 32k increments from 640k to 16M. + I consider machines with less than 16M unlikely nowadays, so I'm + not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA + card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves + 0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */ + +int probe_si (struct sx_board *board) +{ + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", + board->base + SI2_ISA_ID_BASE); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8); + + for (i=0;i<8;i++) { + if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) { + return 0; + } + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base); + /* Compared to the SX boards, it is a complete guess as to what + this card is up to... */ + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + +static int sx_init_drivers(void) +{ + int error; + + func_enter(); + + memset(&sx_driver, 0, sizeof(sx_driver)); + sx_driver.magic = TTY_DRIVER_MAGIC; + sx_driver.driver_name = "specialix_sx"; + sx_driver.name = "ttyX"; + sx_driver.major = SX_NORMAL_MAJOR; + sx_driver.num = sx_nports; + sx_driver.type = TTY_DRIVER_TYPE_SERIAL; + sx_driver.subtype = SX_TYPE_NORMAL; + sx_driver.init_termios = tty_std_termios; + sx_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + sx_driver.flags = TTY_DRIVER_REAL_RAW; + sx_driver.refcount = &sx_refcount; + sx_driver.table = sx_table; + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + sx_driver.open = sx_open; + sx_driver.close = gs_close; + sx_driver.write = gs_write; + sx_driver.put_char = gs_put_char; + sx_driver.flush_chars = gs_flush_chars; + sx_driver.write_room = gs_write_room; + sx_driver.chars_in_buffer = gs_chars_in_buffer; + sx_driver.flush_buffer = gs_flush_buffer; + sx_driver.ioctl = sx_ioctl; + sx_driver.throttle = sx_throttle; + sx_driver.unthrottle = sx_unthrottle; + sx_driver.set_termios = gs_set_termios; + sx_driver.stop = gs_stop; + sx_driver.start = gs_start; + sx_driver.hangup = gs_hangup; + + sx_callout_driver = sx_driver; + sx_callout_driver.name = "cux"; + sx_callout_driver.major = SX_CALLOUT_MAJOR; + sx_callout_driver.subtype = SX_TYPE_CALLOUT; + + if ((error = tty_register_driver(&sx_driver))) { + printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&sx_callout_driver))) { + tty_unregister_driver(&sx_driver); + printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n", + error); + return 1; + } + + func_exit(); + return 0; +} + + +void * ckmalloc (int size) +{ + void *p; + + p = kmalloc(size, GFP_KERNEL); + if (p) + memset(p, 0, size); + return p; +} + + +static int sx_init_portstructs (int nboards, int nports) +{ + struct sx_board *board; + struct sx_port *port; + int i, j; + int addr, chans; + int portno; + + func_enter(); + + /* Many drivers statically allocate the maximum number of ports + There is no reason not to allocate them dynamically. Is there? -- REW */ + sx_ports = ckmalloc(nports * sizeof (struct sx_port)); + if (!sx_ports) + return -ENOMEM; + + sx_termios = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios) { + kfree (sx_ports); + return -ENOMEM; + } + + sx_termios_locked = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios_locked) { + kfree (sx_ports); + kfree (sx_termios); + return -ENOMEM; + } + + /* Adjust the values in the "driver" */ + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + port = sx_ports; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->ports = port; + for (j=0; j < boards[i].nports;j++) { + sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j); + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SX_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->board = board; + port->gs.rd = &sx_real_driver; +#ifdef NEW_WRITE_LOCKING + port->gs.port_write_sem = MUTEX; +#endif + port++; + } + } + + port = sx_ports; + portno = 0; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->port_base = portno; + /* Possibly the configuration was rejected. */ + sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports); + if (board->nports <= 0) continue; + /* XXX byteorder ?? */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + chans = sx_read_module_byte (board, addr, mc_type); + sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans); + sx_dprintk (SX_DEBUG_PROBE, "Port at"); + for (j=0;jch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer); + else + port->ch_base = addr + 0x100 + 0x300*j; + + sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base); + port->line = portno++; + port++; + } + sx_dprintk (SX_DEBUG_PROBE, "\n"); + } + /* This has to be done earlier. */ + /* board->flags |= SX_BOARD_INITIALIZED; */ + } + + func_exit(); + return 0; +} + + +static void sx_release_drivers(void) +{ + func_enter(); + tty_unregister_driver(&sx_driver); + tty_unregister_driver(&sx_callout_driver); + func_exit(); +} + +#ifdef TWO_ZERO +#define PDEV unsigned char pci_bus, unsigned pci_fun +#define pdev pci_bus, pci_fun +#else +#define PDEV struct pci_dev *pdev +#endif + + +#ifdef CONFIG_PCI + /******************************************************** + * Setting bit 17 in the CNTRL register of the PLX 9050 * + * chip forces a retry on writes while a read is pending.* + * This is to prevent the card locking up on Intel Xeon * + * multiprocessor systems with the NX chipset. -- NV * + ********************************************************/ + +/* Newer cards are produced with this bit set from the configuration + EEprom. As the bit is read/write for the CPU, we can fix it here, + if we detect that it isn't set correctly. -- REW */ + +void fix_sx_pci (PDEV, struct sx_board *board) +{ + unsigned int hwbase; + unsigned long rebase; + int t; + +#define CNTRL_REG_OFFSET 0x14 + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase); + hwbase &= PCI_BASE_ADDRESS_MEM_MASK; + rebase = (ulong) ioremap(hwbase, 0x80); + t = readb (rebase + CNTRL_REG_OFFSET*4 + 2); + if (t != 0x06) { + printk (KERN_DEBUG "sx: performing cntrl reg fix: %02x -> 06\n", t); + writeb (0x06, rebase + CNTRL_REG_OFFSET*4+2); + } + my_iounmap (hwbase, rebase); + +} +#endif + + +#ifdef MODULE +#define sx_init init_module +#endif + +int sx_init(void) +{ + int i; + int found = 0; + struct sx_board *board; + +#ifdef CONFIG_PCI +#ifndef TWO_ZERO + struct pci_dev *pdev = NULL; +#else + unsigned char pci_bus, pci_fun; + /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */ +#endif + unsigned int tint; + unsigned short tshort; +#endif + + func_enter(); + sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug); + if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) { + printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. " + "Assuming -1.\n"); + printk ("(%p)\n", &sx_debug); + sx_debug=-1; + } + +#ifdef CONFIG_PCI + if (pci_present ()) { +#ifndef TWO_ZERO + while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, + pdev))) { +#else + for (i=0;i< SX_NBOARDS;i++) { + if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i, + &pci_bus, &pci_fun)) break; +#endif + /* Specialix has a whole bunch of cards with + 0x2000 as the device ID. They say its because + the standard requires it. Stupid standard. */ + /* It seems that reading a word doesn't work reliably on 2.0. + Also, reading a non-aligned dword doesn't work. So we read the + whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID) + ourselves */ + /* I don't know why the define doesn't work, constant 0x2c does --REW */ + pci_read_config_dword (pdev, 0x2c, &tint); + tshort = (tint >> 16) & 0xffff; + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint); + /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */ + if (tshort != 0x0200) { + sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n", + tshort); + continue; + } + board = &boards[found]; + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->irq = get_irq (pdev); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_PCI_BOARD; + + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n", + tint, boards[found].base, board->irq); + + if (probe_sx (board)) { + found++; + fix_sx_pci (pdev, board); + } else + my_iounmap (board->hw_base, board->base); + } + } +#endif + + for (i=0;ihw_base = sx_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_ISA_BOARD; + board->irq = sx_irqmask?-1:0; + + if (probe_sx (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + for (i=0;ihw_base = si_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SI_ISA_BOARD; + board->irq = sx_irqmask ?-1:0; + + if (probe_si (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + if (found) { + printk (KERN_INFO "sx: total of %d boards detected.\n", found); + + if (misc_register(&sx_fw_device) < 0) { + printk(KERN_ERR "SX: Unable to register firmware loader driver.\n"); + return -EIO; + } + } + + func_exit(); + return found?0:-EIO; +} + + + +void cleanup_module(void) +{ + int i; + struct sx_board *board; + + func_enter(); + for (i = 0; i < SX_NBOARDS; i++) { + board = &boards[i]; + if (board->flags & SX_BOARD_INITIALIZED) { + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base); + /* The board should stop messing with us. + (actually I mean the interrupt) */ + sx_reset (board); + if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED)) + free_irq (board->irq, board); + + /* It is safe/allowed to del_timer a non-active timer */ + del_timer (& board->timer); + my_iounmap (board->hw_base, board->base); + } + } + if (misc_deregister(&sx_fw_device) < 0) { + printk (KERN_INFO "sx: couldn't deregister firmware loader device\n"); + } + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized); + if (sx_initialized) + sx_release_drivers (); + + kfree (sx_ports); + kfree (sx_termios); + kfree (sx_termios_locked); + func_exit(); +} + + +#ifdef DEBUG +void my_hd (unsigned char *addr, int len) +{ + int i, j, ch; + + for (i=0;i 0x7f)?'.':ch)); + } + printk ("\n"); + } +} +#endif + +#ifdef MODULE +#undef func_enter +#undef func_exit + +#include "generic_serial.c" +#endif + + +/* + * Anybody who knows why this doesn't work for me, please tell me -- REW. + * Snatched from scsi.c (fixed one spelling error): + * Overrides for Emacs so that we follow Linus' tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff --git a/drivers/char/sx.h b/drivers/char/sx.h new file mode 100644 index 000000000000..e046482e4730 --- /dev/null +++ b/drivers/char/sx.h @@ -0,0 +1,180 @@ + +/* + * sx.h + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * SX serial driver. + * -- Supports SI, XIO and SX host cards. + * -- Supports TAs, MTAs and SXDCs. + * + * Version 1.3 -- March, 1999. + * + */ + +#define SX_NBOARDS 4 +#define SX_PORTSPERBOARD 32 +#define SX_NPORTS (SX_NBOARDS * SX_PORTSPERBOARD) + +#ifdef __KERNEL__ + +#define SX_MAGIC 0x12345678 + +struct sx_port { + struct gs_port gs; + /* + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + */ + struct wait_queue *shutdown_wait; + int ch_base; + int c_dcd; + struct sx_board *board; + int line; + int locks; +}; + +struct sx_board { + int magic; + unsigned int base; + unsigned int hw_base; + int port_base; /* Number of the first port */ + struct sx_port *ports; + int nports; + int flags; + int irq; + int poll; + int ta_type; + struct timer_list timer; + int locks; +}; + +struct vpd_prom { + unsigned short id; + char hwrev; + char hwass; + int uniqid; + char myear; + char mweek; + char hw_feature[5]; + char oem_id; + char identifier[16]; +}; + +#ifndef MOD_RS232DB25MALE +#define MOD_RS232DB25MALE 0x0a +#endif + + +#define SX_BOARD_PRESENT 0x00000001 +#define SX_ISA_BOARD 0x00000002 +#define SX_PCI_BOARD 0x00000004 +#define SI_ISA_BOARD 0x00000008 +#define SX_BOARD_INITIALIZED 0x00000010 +#define SX_IRQ_ALLOCATED 0x00000020 + +#define SX_BOARD_TYPE (SX_ISA_BOARD|SX_PCI_BOARD|SI_ISA_BOARD) + +#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_ISA_BOARD)) +#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD) + + +#define SERIAL_TYPE_NORMAL 1 + +/* The SI processor clock is required to calculate the cc_int_count register + value for the SI cards. */ +#define SI_PROCESSOR_CLOCK 25000000 + + +/* port flags */ +/* Make sure these don't clash with gs flags or async flags */ +#define SX_RX_THROTTLE 0x0000001 + + + +#define SX_PORT_TRANSMIT_LOCK 0 +#define SX_BOARD_INTR_LOCK 0 + + + +/* Debug flags. Add these together to get more debug info. */ + +#define SX_DEBUG_OPEN 0x00000001 +#define SX_DEBUG_SETTING 0x00000002 +#define SX_DEBUG_FLOW 0x00000004 +#define SX_DEBUG_MODEMSIGNALS 0x00000008 +#define SX_DEBUG_TERMIOS 0x00000010 +#define SX_DEBUG_TRANSMIT 0x00000020 +#define SX_DEBUG_RECEIVE 0x00000040 +#define SX_DEBUG_INTERRUPTS 0x00000080 +#define SX_DEBUG_PROBE 0x00000100 +#define SX_DEBUG_INIT 0x00000200 +#define SX_DEBUG_CLEANUP 0x00000400 +#define SX_DEBUG_CLOSE 0x00000800 +#define SX_DEBUG_FIRMWARE 0x00001000 +#define SX_DEBUG_MEMTEST 0x00002000 + +#define SX_DEBUG_ALL 0xffffffff + + +#define O_OTHER(tty) \ + ((O_OLCUC(tty)) ||\ + (O_ONLCR(tty)) ||\ + (O_OCRNL(tty)) ||\ + (O_ONOCR(tty)) ||\ + (O_ONLRET(tty)) ||\ + (O_OFILL(tty)) ||\ + (O_OFDEL(tty)) ||\ + (O_NLDLY(tty)) ||\ + (O_CRDLY(tty)) ||\ + (O_TABDLY(tty)) ||\ + (O_BSDLY(tty)) ||\ + (O_VTDLY(tty)) ||\ + (O_FFDLY(tty))) + +/* Same for input. */ +#define I_OTHER(tty) \ + ((I_INLCR(tty)) ||\ + (I_IGNCR(tty)) ||\ + (I_ICRNL(tty)) ||\ + (I_IUCLC(tty)) ||\ + (L_ISIG(tty))) + +#define MOD_TA ( TA>>4) +#define MOD_MTA (MTA_CD1400>>4) +#define MOD_SXDC ( SXDC>>4) + + +/* We copy the download code over to the card in chunks of ... bytes */ +#define SX_CHUNK_SIZE 128 + +#endif /* __KERNEL__ */ + + + +/* Specialix document 6210046-11 page 3 */ +#define SPX(X) (('S'<<24) | ('P' << 16) | (X)) + +/* Specialix-Linux specific IOCTLS. */ +#define SPXL(X) (SPX(('L' << 8) | (X))) + + +#define SXIO_SET_BOARD SPXL(0x01) +#define SXIO_GET_TYPE SPXL(0x02) +#define SXIO_DOWNLOAD SPXL(0x03) +#define SXIO_INIT SPXL(0x04) +#define SXIO_SETDEBUG SPXL(0x05) +#define SXIO_GETDEBUG SPXL(0x06) +#define SXIO_DO_RAMTEST SPXL(0x07) +#define SXIO_SETGSDEBUG SPXL(0x08) +#define SXIO_GETGSDEBUG SPXL(0x09) + + +#ifndef SXCTL_MISC_MINOR +/* Allow others to gather this into "major.h" or something like that */ +#define SXCTL_MISC_MINOR 167 +#endif + +#define SX_TYPE_SX 0x01 +#define SX_TYPE_SI 0x02 + diff --git a/drivers/char/sxboards.h b/drivers/char/sxboards.h new file mode 100644 index 000000000000..45636c9e9058 --- /dev/null +++ b/drivers/char/sxboards.h @@ -0,0 +1,181 @@ +/************************************************************************/ +/* */ +/* Title : SX/SI/XIO Board Hardware Definitions */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO board hardware */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. + +*/ + +#ifndef _sxboards_h /* If SXBOARDS.H not already defined */ +#define _sxboards_h 1 + +/***************************************************************************** +******************************* ****************************** +******************************* Board Types ****************************** +******************************* ****************************** +*****************************************************************************/ + +/* BUS types... */ +#define BUS_ISA 0 +#define BUS_MCA 1 +#define BUS_EISA 2 +#define BUS_PCI 3 + +/* Board phases... */ +#define SI1_Z280 1 +#define SI2_Z280 2 +#define SI3_T225 3 + +/* Board types... */ +#define CARD_TYPE(bus,phase) (bus<<4|phase) +#define CARD_BUS(type) ((type>>4)&0xF) +#define CARD_PHASE(type) (type&0xF) + +#define TYPE_SI2_ISA CARD_TYPE(BUS_ISA,SI2_Z280) +#define TYPE_SI2_EISA CARD_TYPE(BUS_EISA,SI2_Z280) +#define TYPE_SI2_PCI CARD_TYPE(BUS_PCI,SI2_Z280) + +#define TYPE_SX_ISA CARD_TYPE(BUS_ISA,SI3_T225) +#define TYPE_SX_PCI CARD_TYPE(BUS_PCI,SI3_T225) + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 2 Z280 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* ISA board details... */ +#define SI2_ISA_WINDOW_LEN 0x8000 /* 32 Kbyte shared memory window */ +#define SI2_ISA_MEMORY_LEN 0x7FF8 /* Usable memory */ +#define SI2_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SI2_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SI2_ISA_ADDR_STEP SI2_ISA_WINDOW_LEN/* ISA board address step */ +#define SI2_ISA_IRQ_MASK 0x9800 /* IRQs 15,12,11 */ + +/* ISA board, register definitions... */ +#define SI2_ISA_ID_BASE 0x7FF8 /* READ: Board ID string */ +#define SI2_ISA_RESET SI2_ISA_ID_BASE /* WRITE: Host Reset */ +#define SI2_ISA_IRQ11 (SI2_ISA_ID_BASE+1) /* WRITE: Set IRQ11 */ +#define SI2_ISA_IRQ12 (SI2_ISA_ID_BASE+2) /* WRITE: Set IRQ12 */ +#define SI2_ISA_IRQ15 (SI2_ISA_ID_BASE+3) /* WRITE: Set IRQ15 */ +#define SI2_ISA_IRQSET (SI2_ISA_ID_BASE+4) /* WRITE: Set Host Interrupt */ +#define SI2_ISA_INTCLEAR (SI2_ISA_ID_BASE+5) /* WRITE: Enable Host Interrupt */ + +#define SI2_ISA_IRQ11_SET 0x10 +#define SI2_ISA_IRQ11_CLEAR 0x00 +#define SI2_ISA_IRQ12_SET 0x10 +#define SI2_ISA_IRQ12_CLEAR 0x00 +#define SI2_ISA_IRQ15_SET 0x10 +#define SI2_ISA_IRQ15_CLEAR 0x00 +#define SI2_ISA_INTCLEAR_SET 0x10 +#define SI2_ISA_INTCLEAR_CLEAR 0x00 +#define SI2_ISA_IRQSET_CLEAR 0x10 +#define SI2_ISA_IRQSET_SET 0x00 +#define SI2_ISA_RESET_SET 0x00 +#define SI2_ISA_RESET_CLEAR 0x10 + +/* PCI board details... */ +#define SI2_PCI_WINDOW_LEN 0x100000 /* 1 Mbyte memory window */ + +/* PCI board register definitions... */ +#define SI2_PCI_SET_IRQ 0x40001 /* Set Host Interrupt */ +#define SI2_PCI_RESET 0xC0001 /* Host Reset */ + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 3 T225 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* General board details... */ +#define SX_WINDOW_LEN 64*1024 /* 64 Kbyte memory window */ + +/* ISA board details... */ +#define SX_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SX_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SX_ISA_ADDR_STEP SX_WINDOW_LEN /* ISA board address step */ +#define SX_ISA_IRQ_MASK 0x9E00 /* IRQs 15,12,11,10,9 */ + +/* Hardware register definitions... */ +#define SX_EVENT_STATUS 0x7800 /* READ: T225 Event Status */ +#define SX_EVENT_STROBE 0x7800 /* WRITE: T225 Event Strobe */ +#define SX_EVENT_ENABLE 0x7880 /* WRITE: T225 Event Enable */ +#define SX_VPD_ROM 0x7C00 /* READ: Vital Product Data ROM */ +#define SX_CONFIG 0x7C00 /* WRITE: Host Configuration Register */ +#define SX_IRQ_STATUS 0x7C80 /* READ: Host Interrupt Status */ +#define SX_SET_IRQ 0x7C80 /* WRITE: Set Host Interrupt */ +#define SX_RESET_STATUS 0x7D00 /* READ: Host Reset Status */ +#define SX_RESET 0x7D00 /* WRITE: Host Reset */ +#define SX_RESET_IRQ 0x7D80 /* WRITE: Reset Host Interrupt */ + +/* SX_VPD_ROM definitions... */ +#define SX_VPD_SLX_ID1 0x00 +#define SX_VPD_SLX_ID2 0x01 +#define SX_VPD_HW_REV 0x02 +#define SX_VPD_HW_ASSEM 0x03 +#define SX_VPD_UNIQUEID4 0x04 +#define SX_VPD_UNIQUEID3 0x05 +#define SX_VPD_UNIQUEID2 0x06 +#define SX_VPD_UNIQUEID1 0x07 +#define SX_VPD_MANU_YEAR 0x08 +#define SX_VPD_MANU_WEEK 0x09 +#define SX_VPD_IDENT 0x10 +#define SX_VPD_IDENT_STRING "JET HOST BY KEV#" + +/* SX unique identifiers... */ +#define SX_UNIQUEID_MASK 0xF0 +#define SX_ISA_UNIQUEID1 0x20 +#define SX_PCI_UNIQUEID1 0x50 + +/* SX_CONFIG definitions... */ +#define SX_CONF_BUSEN 0x02 /* Enable T225 memory and I/O */ +#define SX_CONF_HOSTIRQ 0x04 /* Enable board to host interrupt */ + +/* SX bootstrap... */ +#define SX_BOOTSTRAP "\x28\x20\x21\x02\x60\x0a" +#define SX_BOOTSTRAP_SIZE 6 +#define SX_BOOTSTRAP_ADDR (0x8000-SX_BOOTSTRAP_SIZE) + +/***************************************************************************** +********************************** ********************************** +********************************** EISA ********************************** +********************************** ********************************** +*****************************************************************************/ + +#define SI2_EISA_OFF 0x42 +#define SI2_EISA_VAL 0x01 + +/***************************************************************************** +*********************************** ********************************** +*********************************** PCI ********************************** +*********************************** ********************************** +*****************************************************************************/ + +/* General definitions... */ + +#define SPX_VENDOR_ID 0x11CB /* Assigned by the PCI SIG */ +#define SPX_DEVICE_ID 0x4000 /* SI/XIO boards */ +#define SPX_PLXDEVICE_ID 0x2000 /* SX boards */ + +#define SPX_SUB_VENDOR_ID SPX_VENDOR_ID /* Same as vendor id */ +#define SI2_SUB_SYS_ID 0x400 /* Phase 2 (Z280) board */ +#define SX_SUB_SYS_ID 0x200 /* Phase 3 (t225) board */ + +#endif /*_sxboards_h */ + +/* End of SXBOARDS.H */ diff --git a/drivers/char/sxwindow.h b/drivers/char/sxwindow.h new file mode 100644 index 000000000000..cf01b662aefc --- /dev/null +++ b/drivers/char/sxwindow.h @@ -0,0 +1,393 @@ +/************************************************************************/ +/* */ +/* Title : SX Shared Memory Window Structure */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO cards shared */ +/* memory window structure: */ +/* SXCARD */ +/* SXMODULE */ +/* SXCHANNEL */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. (based on STRUCT.H) + +*/ + +#ifndef _sxwindow_h /* If SXWINDOW.H not already defined */ +#define _sxwindow_h 1 + +/***************************************************************************** +*************************** *************************** +*************************** Common Definitions *************************** +*************************** *************************** +*****************************************************************************/ + +typedef struct _SXCARD *PSXCARD; /* SXCARD structure pointer */ +typedef struct _SXMODULE *PMOD; /* SXMODULE structure pointer */ +typedef struct _SXCHANNEL *PCHAN; /* SXCHANNEL structure pointer */ + +/***************************************************************************** +********************************* ********************************* +********************************* SXCARD ********************************* +********************************* ********************************* +*****************************************************************************/ + +typedef struct _SXCARD +{ + BYTE cc_init_status; /* 0x00 Initialisation status */ + BYTE cc_mem_size; /* 0x01 Size of memory on card */ + WORD cc_int_count; /* 0x02 Interrupt count */ + WORD cc_revision; /* 0x04 Download code revision */ + BYTE cc_isr_count; /* 0x06 Count when ISR is run */ + BYTE cc_main_count; /* 0x07 Count when main loop is run */ + WORD cc_int_pending; /* 0x08 Interrupt pending */ + WORD cc_poll_count; /* 0x0A Count when poll is run */ + BYTE cc_int_set_count; /* 0x0C Count when host interrupt is set */ + BYTE cc_rfu[0x80 - 0x0D]; /* 0x0D Pad structure to 128 bytes (0x80) */ + +} SXCARD; + +/* SXCARD.cc_init_status definitions... */ +#define ADAPTERS_FOUND (BYTE)0x01 +#define NO_ADAPTERS_FOUND (BYTE)0xFF + +/* SXCARD.cc_mem_size definitions... */ +#define SX_MEMORY_SIZE (BYTE)0x40 + +/* SXCARD.cc_int_count definitions... */ +#define INT_COUNT_DEFAULT 100 /* Hz */ + +/***************************************************************************** +******************************** ******************************** +******************************** SXMODULE ******************************** +******************************** ******************************** +*****************************************************************************/ + +#define TOP_POINTER(a) ((a)|0x8000) /* Sets top bit of word */ +#define UNTOP_POINTER(a) ((a)&~0x8000) /* Clears top bit of word */ + +typedef struct _SXMODULE +{ + WORD mc_next; /* 0x00 Next module "pointer" (ORed with 0x8000) */ + BYTE mc_type; /* 0x02 Type of TA in terms of number of channels */ + BYTE mc_mod_no; /* 0x03 Module number on SI bus cable (0 closest to card) */ + BYTE mc_dtr; /* 0x04 Private DTR copy (TA only) */ + BYTE mc_rfu1; /* 0x05 Reserved */ + WORD mc_uart; /* 0x06 UART base address for this module */ + BYTE mc_chip; /* 0x08 Chip type / number of ports */ + BYTE mc_current_uart; /* 0x09 Current uart selected for this module */ +#ifdef DOWNLOAD + PCHAN mc_chan_pointer[8]; /* 0x0A Pointer to each channel structure */ +#else + WORD mc_chan_pointer[8]; /* 0x0A Define as WORD if not compiling into download */ +#endif + WORD mc_rfu2; /* 0x1A Reserved */ + BYTE mc_opens1; /* 0x1C Number of open ports on first four ports on MTA/SXDC */ + BYTE mc_opens2; /* 0x1D Number of open ports on second four ports on MTA/SXDC */ + BYTE mc_mods; /* 0x1E Types of connector module attached to MTA/SXDC */ + BYTE mc_rev1; /* 0x1F Revision of first CD1400 on MTA/SXDC */ + BYTE mc_rev2; /* 0x20 Revision of second CD1400 on MTA/SXDC */ + BYTE mc_mtaasic_rev; /* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */ + BYTE mc_rfu3[0x100 - 0x22]; /* 0x22 Pad structure to 256 bytes (0x100) */ + +} SXMODULE; + +/* SXMODULE.mc_type definitions... */ +#define FOUR_PORTS (BYTE)4 +#define EIGHT_PORTS (BYTE)8 + +/* SXMODULE.mc_chip definitions... */ +#define CHIP_MASK 0xF0 +#define TA (BYTE)0 +#define TA4 (TA | FOUR_PORTS) +#define TA8 (TA | EIGHT_PORTS) +#define TA4_ASIC (BYTE)0x0A +#define TA8_ASIC (BYTE)0x0B +#define MTA_CD1400 (BYTE)0x28 +#define SXDC (BYTE)0x48 + +/* SXMODULE.mc_mods definitions... */ +#define MOD_RS232DB25 0x00 /* RS232 DB25 (socket/plug) */ +#define MOD_RS232RJ45 0x01 /* RS232 RJ45 (shielded/opto-isolated) */ +#define MOD_RESERVED_2 0x02 /* Reserved (RS485) */ +#define MOD_RS422DB25 0x03 /* RS422 DB25 Socket */ +#define MOD_RESERVED_4 0x04 /* Reserved */ +#define MOD_PARALLEL 0x05 /* Parallel */ +#define MOD_RESERVED_6 0x06 /* Reserved (RS423) */ +#define MOD_RESERVED_7 0x07 /* Reserved */ +#define MOD_2_RS232DB25 0x08 /* Rev 2.0 RS232 DB25 (socket/plug) */ +#define MOD_2_RS232RJ45 0x09 /* Rev 2.0 RS232 RJ45 */ +#define MOD_RESERVED_A 0x0A /* Rev 2.0 Reserved */ +#define MOD_2_RS422DB25 0x0B /* Rev 2.0 RS422 DB25 */ +#define MOD_RESERVED_C 0x0C /* Rev 2.0 Reserved */ +#define MOD_2_PARALLEL 0x0D /* Rev 2.0 Parallel */ +#define MOD_RESERVED_E 0x0E /* Rev 2.0 Reserved */ +#define MOD_BLANK 0x0F /* Blank Panel */ + +/***************************************************************************** +******************************** ******************************* +******************************** SXCHANNEL ******************************* +******************************** ******************************* +*****************************************************************************/ + +#define TX_BUFF_OFFSET 0x60 /* Transmit buffer offset in channel structure */ +#define BUFF_POINTER(a) (((a)+TX_BUFF_OFFSET)|0x8000) +#define UNBUFF_POINTER(a) (jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET) +#define BUFFER_SIZE 256 +#define HIGH_WATER ((BUFFER_SIZE / 4) * 3) +#define LOW_WATER (BUFFER_SIZE / 4) + +typedef struct _SXCHANNEL +{ + WORD next_item; /* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */ + WORD addr_uart; /* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */ + WORD module; /* 0x04 Offset from window base of parent SXMODULE structure */ + BYTE type; /* 0x06 Chip type / number of ports (copy of mc_chip) */ + BYTE chan_number; /* 0x07 Channel number on the TA/MTA/SXDC */ + WORD xc_status; /* 0x08 Flow control and I/O status */ + BYTE hi_rxipos; /* 0x0A Receive buffer input index */ + BYTE hi_rxopos; /* 0x0B Receive buffer output index */ + BYTE hi_txopos; /* 0x0C Transmit buffer output index */ + BYTE hi_txipos; /* 0x0D Transmit buffer input index */ + BYTE hi_hstat; /* 0x0E Command register */ + BYTE dtr_bit; /* 0x0F INTERNAL DTR control byte (TA only) */ + BYTE txon; /* 0x10 INTERNAL copy of hi_txon */ + BYTE txoff; /* 0x11 INTERNAL copy of hi_txoff */ + BYTE rxon; /* 0x12 INTERNAL copy of hi_rxon */ + BYTE rxoff; /* 0x13 INTERNAL copy of hi_rxoff */ + BYTE hi_mr1; /* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/ + BYTE hi_mr2; /* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/ + BYTE hi_csr; /* 0x16 Clock Select Register (baud rate) */ + BYTE hi_op; /* 0x17 Modem Output Signal */ + BYTE hi_ip; /* 0x18 Modem Input Signal */ + BYTE hi_state; /* 0x19 Channel status */ + BYTE hi_prtcl; /* 0x1A Channel protocol (flow control) */ + BYTE hi_txon; /* 0x1B Transmit XON character */ + BYTE hi_txoff; /* 0x1C Transmit XOFF character */ + BYTE hi_rxon; /* 0x1D Receive XON character */ + BYTE hi_rxoff; /* 0x1E Receive XOFF character */ + BYTE close_prev; /* 0x1F INTERNAL channel previously closed flag */ + BYTE hi_break; /* 0x20 Break and error control */ + BYTE break_state; /* 0x21 INTERNAL copy of hi_break */ + BYTE hi_mask; /* 0x22 Mask for received data */ + BYTE mask; /* 0x23 INTERNAL copy of hi_mask */ + BYTE mod_type; /* 0x24 MTA/SXDC hardware module type */ + BYTE ccr_state; /* 0x25 INTERNAL MTA/SXDC state of CCR register */ + BYTE ip_mask; /* 0x26 Input handshake mask */ + BYTE hi_parallel; /* 0x27 Parallel port flag */ + BYTE par_error; /* 0x28 Error code for parallel loopback test */ + BYTE any_sent; /* 0x29 INTERNAL data sent flag */ + BYTE asic_txfifo_size; /* 0x2A INTERNAL SXDC transmit FIFO size */ + BYTE rfu1[2]; /* 0x2B Reserved */ + BYTE csr; /* 0x2D INTERNAL copy of hi_csr */ +#ifdef DOWNLOAD + PCHAN nextp; /* 0x2E Offset from window base of next channel structure */ +#else + WORD nextp; /* 0x2E Define as WORD if not compiling into download */ +#endif + BYTE prtcl; /* 0x30 INTERNAL copy of hi_prtcl */ + BYTE mr1; /* 0x31 INTERNAL copy of hi_mr1 */ + BYTE mr2; /* 0x32 INTERNAL copy of hi_mr2 */ + BYTE hi_txbaud; /* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */ + BYTE hi_rxbaud; /* 0x34 Extended receive baud rate (SXDC only if((hi_csr&0xF0)==0xF0) */ + BYTE txbreak_state; /* 0x35 INTERNAL MTA/SXDC transmit break state */ + BYTE txbaud; /* 0x36 INTERNAL copy of hi_txbaud */ + BYTE rxbaud; /* 0x37 INTERNAL copy of hi_rxbaud */ + WORD err_framing; /* 0x38 Count of receive framing errors */ + WORD err_parity; /* 0x3A Count of receive parity errors */ + WORD err_overrun; /* 0x3C Count of receive overrun errors */ + WORD err_overflow; /* 0x3E Count of receive buffer overflow errors */ + BYTE rfu2[TX_BUFF_OFFSET - 0x40]; /* 0x40 Reserved until hi_txbuf */ + BYTE hi_txbuf[BUFFER_SIZE]; /* 0x060 Transmit buffer */ + BYTE hi_rxbuf[BUFFER_SIZE]; /* 0x160 Receive buffer */ + BYTE rfu3[0x300 - 0x260]; /* 0x260 Reserved until 768 bytes (0x300) */ + +} SXCHANNEL; + +/* SXCHANNEL.addr_uart definitions... */ +#define FASTPATH 0x1000 /* Set to indicate fast rx/tx processing (TA only) */ + +/* SXCHANNEL.xc_status definitions... */ +#define X_TANY 0x0001 /* XON is any character (TA only) */ +#define X_TION 0x0001 /* Tx interrupts on (MTA only) */ +#define X_TXEN 0x0002 /* Tx XON/XOFF enabled (TA only) */ +#define X_RTSEN 0x0002 /* RTS FLOW enabled (MTA only) */ +#define X_TXRC 0x0004 /* XOFF received (TA only) */ +#define X_RTSLOW 0x0004 /* RTS dropped (MTA only) */ +#define X_RXEN 0x0008 /* Rx XON/XOFF enabled */ +#define X_ANYXO 0x0010 /* XOFF pending/sent or RTS dropped */ +#define X_RXSE 0x0020 /* Rx XOFF sent */ +#define X_NPEND 0x0040 /* Rx XON pending or XOFF pending */ +#define X_FPEND 0x0080 /* Rx XOFF pending */ +#define C_CRSE 0x0100 /* Carriage return sent (TA only) */ +#define C_TEMR 0x0100 /* Tx empty requested (MTA only) */ +#define C_TEMA 0x0200 /* Tx empty acked (MTA only) */ +#define C_ANYP 0x0200 /* Any protocol bar tx XON/XOFF (TA only) */ +#define C_EN 0x0400 /* Cooking enabled (on MTA means port is also || */ +#define C_HIGH 0x0800 /* Buffer previously hit high water */ +#define C_CTSEN 0x1000 /* CTS automatic flow-control enabled */ +#define C_DCDEN 0x2000 /* DCD/DTR checking enabled */ +#define C_BREAK 0x4000 /* Break detected */ +#define C_RTSEN 0x8000 /* RTS automatic flow control enabled (MTA only) */ +#define C_PARITY 0x8000 /* Parity checking enabled (TA only) */ + +/* SXCHANNEL.hi_hstat definitions... */ +#define HS_IDLE_OPEN 0x00 /* Channel open state */ +#define HS_LOPEN 0x02 /* Local open command (no modem monitoring) */ +#define HS_MOPEN 0x04 /* Modem open command (wait for DCD signal) */ +#define HS_IDLE_MPEND 0x06 /* Waiting for DCD signal state */ +#define HS_CONFIG 0x08 /* Configuration command */ +#define HS_CLOSE 0x0A /* Close command */ +#define HS_START 0x0C /* Start transmit break command */ +#define HS_STOP 0x0E /* Stop transmit break command */ +#define HS_IDLE_CLOSED 0x10 /* Closed channel state */ +#define HS_IDLE_BREAK 0x12 /* Transmit break state */ +#define HS_FORCE_CLOSED 0x14 /* Force close command */ +#define HS_RESUME 0x16 /* Clear pending XOFF command */ +#define HS_WFLUSH 0x18 /* Flush transmit buffer command */ +#define HS_RFLUSH 0x1A /* Flush receive buffer command */ +#define HS_SUSPEND 0x1C /* Suspend output command (like XOFF received) */ +#define PARALLEL 0x1E /* Parallel port loopback test command (Diagnostics Only) */ +#define ENABLE_RX_INTS 0x20 /* Enable receive interrupts command (Diagnostics Only) */ +#define ENABLE_TX_INTS 0x22 /* Enable transmit interrupts command (Diagnostics Only) */ +#define ENABLE_MDM_INTS 0x24 /* Enable modem interrupts command (Diagnostics Only) */ +#define DISABLE_INTS 0x26 /* Disable interrupts command (Diagnostics Only) */ + +/* SXCHANNEL.hi_mr1 definitions... */ +#define MR1_BITS 0x03 /* Data bits mask */ +#define MR1_5_BITS 0x00 /* 5 data bits */ +#define MR1_6_BITS 0x01 /* 6 data bits */ +#define MR1_7_BITS 0x02 /* 7 data bits */ +#define MR1_8_BITS 0x03 /* 8 data bits */ +#define MR1_PARITY 0x1C /* Parity mask */ +#define MR1_ODD 0x04 /* Odd parity */ +#define MR1_EVEN 0x00 /* Even parity */ +#define MR1_WITH 0x00 /* Parity enabled */ +#define MR1_FORCE 0x08 /* Force parity */ +#define MR1_NONE 0x10 /* No parity */ +#define MR1_NOPARITY MR1_NONE /* No parity */ +#define MR1_ODDPARITY (MR1_WITH|MR1_ODD) /* Odd parity */ +#define MR1_EVENPARITY (MR1_WITH|MR1_EVEN) /* Even parity */ +#define MR1_MARKPARITY (MR1_FORCE|MR1_ODD) /* Mark parity */ +#define MR1_SPACEPARITY (MR1_FORCE|MR1_EVEN) /* Space parity */ +#define MR1_RTS_RXFLOW 0x80 /* RTS receive flow control */ + +/* SXCHANNEL.hi_mr2 definitions... */ +#define MR2_STOP 0x0F /* Stop bits mask */ +#define MR2_1_STOP 0x07 /* 1 stop bit */ +#define MR2_2_STOP 0x0F /* 2 stop bits */ +#define MR2_CTS_TXFLOW 0x10 /* CTS transmit flow control */ +#define MR2_RTS_TOGGLE 0x20 /* RTS toggle on transmit */ +#define MR2_NORMAL 0x00 /* Normal mode */ +#define MR2_AUTO 0x40 /* Auto-echo mode (TA only) */ +#define MR2_LOCAL 0x80 /* Local echo mode */ +#define MR2_REMOTE 0xC0 /* Remote echo mode (TA only) */ + +/* SXCHANNEL.hi_csr definitions... */ +#define CSR_75 0x0 /* 75 baud */ +#define CSR_110 0x1 /* 110 baud (TA), 115200 (MTA/SXDC) */ +#define CSR_38400 0x2 /* 38400 baud */ +#define CSR_150 0x3 /* 150 baud */ +#define CSR_300 0x4 /* 300 baud */ +#define CSR_600 0x5 /* 600 baud */ +#define CSR_1200 0x6 /* 1200 baud */ +#define CSR_2000 0x7 /* 2000 baud */ +#define CSR_2400 0x8 /* 2400 baud */ +#define CSR_4800 0x9 /* 4800 baud */ +#define CSR_1800 0xA /* 1800 baud */ +#define CSR_9600 0xB /* 9600 baud */ +#define CSR_19200 0xC /* 19200 baud */ +#define CSR_57600 0xD /* 57600 baud */ +#define CSR_EXTBAUD 0xF /* Extended baud rate (hi_txbaud/hi_rxbaud) */ + +/* SXCHANNEL.hi_op definitions... */ +#define OP_RTS 0x01 /* RTS modem output signal */ +#define OP_DTR 0x02 /* DTR modem output signal */ + +/* SXCHANNEL.hi_ip definitions... */ +#define IP_CTS 0x02 /* CTS modem input signal */ +#define IP_DCD 0x04 /* DCD modem input signal */ +#define IP_DSR 0x20 /* DTR modem input signal */ +#define IP_RI 0x40 /* RI modem input signal */ + +/* SXCHANNEL.hi_state definitions... */ +#define ST_BREAK 0x01 /* Break received (clear with config) */ +#define ST_DCD 0x02 /* DCD signal changed state */ + +/* SXCHANNEL.hi_prtcl definitions... */ +#define SP_TANY 0x01 /* Transmit XON/XANY (if SP_TXEN enabled) */ +#define SP_TXEN 0x02 /* Transmit XON/XOFF flow control */ +#define SP_CEN 0x04 /* Cooking enabled */ +#define SP_RXEN 0x08 /* Rx XON/XOFF enabled */ +#define SP_DCEN 0x20 /* DCD / DTR check */ +#define SP_DTR_RXFLOW 0x40 /* DTR receive flow control */ +#define SP_PAEN 0x80 /* Parity checking enabled */ + +/* SXCHANNEL.hi_break definitions... */ +#define BR_IGN 0x01 /* Ignore any received breaks */ +#define BR_INT 0x02 /* Interrupt on received break */ +#define BR_PARMRK 0x04 /* Enable parmrk parity error processing */ +#define BR_PARIGN 0x08 /* Ignore chars with parity errors */ +#define BR_ERRINT 0x80 /* Treat parity/framing/overrun errors as exceptions */ + +/* SXCHANNEL.par_error definitions.. */ +#define DIAG_IRQ_RX 0x01 /* Indicate serial receive interrupt (diags only) */ +#define DIAG_IRQ_TX 0x02 /* Indicate serial transmit interrupt (diags only) */ +#define DIAG_IRQ_MD 0x04 /* Indicate serial modem interrupt (diags only) */ + +/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */ +#define BAUD_75 0x00 /* 75 baud */ +#define BAUD_115200 0x01 /* 115200 baud */ +#define BAUD_38400 0x02 /* 38400 baud */ +#define BAUD_150 0x03 /* 150 baud */ +#define BAUD_300 0x04 /* 300 baud */ +#define BAUD_600 0x05 /* 600 baud */ +#define BAUD_1200 0x06 /* 1200 baud */ +#define BAUD_2000 0x07 /* 2000 baud */ +#define BAUD_2400 0x08 /* 2400 baud */ +#define BAUD_4800 0x09 /* 4800 baud */ +#define BAUD_1800 0x0A /* 1800 baud */ +#define BAUD_9600 0x0B /* 9600 baud */ +#define BAUD_19200 0x0C /* 19200 baud */ +#define BAUD_57600 0x0D /* 57600 baud */ +#define BAUD_230400 0x0E /* 230400 baud */ +#define BAUD_460800 0x0F /* 460800 baud */ +#define BAUD_921600 0x10 /* 921600 baud */ +#define BAUD_50 0x11 /* 50 baud */ +#define BAUD_110 0x12 /* 110 baud */ +#define BAUD_134_5 0x13 /* 134.5 baud */ +#define BAUD_200 0x14 /* 200 baud */ +#define BAUD_7200 0x15 /* 7200 baud */ +#define BAUD_56000 0x16 /* 56000 baud */ +#define BAUD_64000 0x17 /* 64000 baud */ +#define BAUD_76800 0x18 /* 76800 baud */ +#define BAUD_128000 0x19 /* 128000 baud */ +#define BAUD_150000 0x1A /* 150000 baud */ +#define BAUD_14400 0x1B /* 14400 baud */ +#define BAUD_256000 0x1C /* 256000 baud */ +#define BAUD_28800 0x1D /* 28800 baud */ + +/* SXCHANNEL.txbreak_state definiions... */ +#define TXBREAK_OFF 0 /* Not sending break */ +#define TXBREAK_START 1 /* Begin sending break */ +#define TXBREAK_START1 2 /* Begin sending break, part 1 */ +#define TXBREAK_ON 3 /* Sending break */ +#define TXBREAK_STOP 4 /* Stop sending break */ +#define TXBREAK_STOP1 5 /* Stop sending break, part 1 */ + +#endif /* _sxwindow_h */ + +/* End of SXWINDOW.H */ + diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 62ec86628bc4..4d44c31f371d 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -125,11 +125,15 @@ static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); +#ifdef CONFIG_SX +extern int sx_init (void); +#endif #ifdef CONFIG_8xx extern long console_8xx_init(long, long); extern int rs_8xx_init(void); #endif /* CONFIG_8xx */ + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -2080,7 +2084,7 @@ static struct tty_driver dev_console_driver; * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ -__initfunc(int tty_init(void)) +int __init tty_init(void) { if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); @@ -2178,6 +2182,9 @@ __initfunc(int tty_init(void)) #ifdef CONFIG_SPECIALIX specialix_init(); #endif +#ifdef CONFIG_SX + sx_init(); +#endif #ifdef CONFIG_8xx rs_8xx_init(); #endif /* CONFIG_8xx */ diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 4db4e6efb0f4..a25013fea525 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -310,7 +310,7 @@ static struct file_operations vcs_fops = { NULL /* fsync */ }; -__initfunc(int vcs_init(void)) +int __init vcs_init(void) { int error; diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c index eaab1ab1f657..ad4cc754460f 100644 --- a/drivers/dio/dio.c +++ b/drivers/dio/dio.c @@ -112,7 +112,7 @@ struct dioboard static struct dioboard *blist = NULL; -__initfunc(static int dio_find_slow(int deviceid)) +static int __init dio_find_slow(int deviceid) { /* Called to find a DIO device before the full bus scan has run. Basically only used by the console driver. */ @@ -151,7 +151,7 @@ int dio_find(int deviceid) /* This is the function that scans the DIO space and works out what * hardware is actually present. */ -__initfunc(void dio_init(void)) +void __init dio_init(void) { int scode; struct dioboard *b, *bprev = NULL; diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index f0ddd38d1e5c..caa11c33e6f7 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -672,7 +672,7 @@ static inline void soc_init(struct linux_sbus_device *sdev, int no) } #ifndef MODULE -__initfunc(int soc_probe(void)) +int __init soc_probe(void) #else int init_module(void) #endif diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index 60a5f15e1708..6bcfbeacde03 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -798,7 +798,7 @@ static inline void socal_init(struct linux_sbus_device *sdev, int no) } #ifndef MODULE -__initfunc(int socal_probe(void)) +int __init socal_probe(void) #else int init_module(void) #endif diff --git a/drivers/i2o/Makefile b/drivers/i2o/Makefile index d70b423107dd..95207337f363 100644 --- a/drivers/i2o/Makefile +++ b/drivers/i2o/Makefile @@ -27,7 +27,7 @@ ifeq ($(CONFIG_I2O_PCI),y) L_OBJS += i2o_pci.o else ifeq ($(CONFIG_I2O_PCI),m) - M_OBJS += i2o_pci.o + MX_OBJS += i2o_pci.o endif endif diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c index 83634d676868..8ed8fb00f366 100644 --- a/drivers/i2o/i2o_block.c +++ b/drivers/i2o/i2o_block.c @@ -323,7 +323,8 @@ static struct i2o_handler i2o_block_handler = { i2o_block_reply, "I2O Block OSM", - 0 + 0, + I2O_CLASS_RANDOM_BLOCK_STORAGE }; @@ -575,15 +576,6 @@ static int i2ob_ioctl(struct inode *inode, struct file *file, } } -/* - * Issue UTIL_CLAIM messages - */ - -static int i2ob_claim_device(struct i2ob_device *dev, int onoff) -{ - return i2o_issue_claim(dev->controller, dev->tid, i2ob_context, onoff, &dev->done_flag); -} - /* * Close the block device down */ @@ -625,10 +617,10 @@ static int i2ob_release(struct inode *inode, struct file *file) i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); /* - * Now unclaim the device. - */ - if (i2ob_claim_device(dev, 0)<0) - printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); + * Now unclaim the device. + */ + if (i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0) + printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); } MOD_DEC_USE_COUNT; @@ -657,7 +649,7 @@ static int i2ob_open(struct inode *inode, struct file *file) int *query_done; - if(i2ob_claim_device(dev, 1)<0) + if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0) { dev->refcnt--; return -EBUSY; @@ -809,36 +801,35 @@ static void i2ob_probe(void) if(uniti2odev = d; + * Get the device and fill in the + * Tid and controller. + */ + struct i2ob_device *dev=&i2ob_dev[unit]; + dev->i2odev = d; dev->controller = c; - dev->tid = d->id; + dev->tid = d->id; - /* - * Insure the device can be claimed - * before installing it. - */ - if(i2ob_claim_device(dev, 1)==0) - { - printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit); - i2ob_install_device(c,d,unit); + /* + * Insure the device can be claimed + * before installing it. + */ + if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY )==0) + { + printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit); + i2ob_install_device(c,d,unit); unit+=16; - /* - * Now that the device has been - * installed, unclaim it so that - * it can be claimed by either - * the block or scsi driver. - */ - if (i2ob_claim_device(dev, 0)<0) - printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid); - - } - else - printk(KERN_INFO "TID %d not claimed\n",dev->tid); + /* + * Now that the device has been + * installed, unclaim it so that + * it can be claimed by either + * the block or scsi driver. + */ + if(i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)) + printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid); + } + else + printk(KERN_INFO "TID %d not claimed\n",dev->tid); } else { diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c index 486376c1011c..e872450f01a9 100644 --- a/drivers/i2o/i2o_config.c +++ b/drivers/i2o/i2o_config.c @@ -75,7 +75,8 @@ struct i2o_handler cfg_handler= { i2o_cfg_reply, "Configuration", - 0 + 0, + 0xffffffff // All classes }; static long long cfg_llseek(struct file *file, long long offset, int origin) diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index a851b5bf34d4..45e79bb744c7 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -14,15 +14,20 @@ * Red Creek RCPCI45 adapter driver by Red Creek Communications * * Fixes by Philipp Rumpf - * Juha Sievänen + * Juha Sievänen * Auvo Häkkinen + * Deepak Saxena */ - + #include #include #include #include + +#if defined(CONFIG_I2O_PCI) || defined (CONFIG_I2O_PCI_MODULE) #include +#endif + #include #include #include @@ -32,6 +37,7 @@ #include "i2o_lan.h" +#define DRIVERDEBUG /* * Size of the I2O module table @@ -46,6 +52,32 @@ static int reply_flag = 0; extern int i2o_online_controller(struct i2o_controller *c); static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *); +static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *); +static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *); +static void i2o_dump_message(u32 *); + +#ifdef MODULE +/* + * Function table to send to bus specific layers + * See for explanation of this + */ +static struct i2o_core_func_table i2o_core_functions = +{ + i2o_install_controller, + i2o_activate_controller, + i2o_find_controller, + i2o_unlock_controller, + i2o_run_queue, + i2o_delete_controller +}; + +#ifdef CONFIG_I2O_PCI_MODULE +extern int i2o_pci_core_attach(struct i2o_core_func_table *); +extern void i2o_pci_core_detach(void); +#endif /* CONFIG_I2O_PCI_MODULE */ + +#endif /* MODULE */ + /* Message handler */ static struct i2o_handler i2o_core_handler = @@ -133,12 +165,19 @@ int i2o_remove_handler(struct i2o_handler *h) int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) { + int i; + spin_lock(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; c->devices=d; *d->dev_name = 0; + d->owner = NULL; + + for(i = 0; i < I2O_MAX_MANAGERS; i++) + d->managers[i] = NULL; + spin_unlock(&i2o_configuration_lock); return 0; } @@ -247,9 +286,12 @@ int i2o_delete_controller(struct i2o_controller *c) while(*p) { if(*p!=c) + { + printk("Quiescing controller %p != %p\n", c, *p); if(i2o_quiesce_controller(*p)<0) printk(KERN_INFO "Unable to quiesce iop%d\n", (*p)->unit); + } p=&((*p)->next); } @@ -308,11 +350,23 @@ struct i2o_controller *i2o_find_controller(int n) /* - * Track if a device is being used by a driver + * Claim a device for use as either the primary user or just + * as a management/secondary user */ - -int i2o_claim_device(struct i2o_device *d, struct i2o_driver *r) +int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type) { + /* Device already has a primary user or too many managers */ + if((type == I2O_CLAIM_PRIMARY && d->owner) || + (d->num_managers == I2O_MAX_MANAGERS)) + { + return -EBUSY; + } + + if(i2o_issue_claim(d->controller,d->id, h->context, 1, &reply_flag, type) < 0) + { + return -EBUSY; + } + spin_lock(&i2o_configuration_lock); if(d->owner) { @@ -320,25 +374,92 @@ int i2o_claim_device(struct i2o_device *d, struct i2o_driver *r) return -EBUSY; } atomic_inc(&d->controller->users); - d->owner=r; + + if(type == I2O_CLAIM_PRIMARY) + d->owner=h; + else + i2o_add_management_user(d, h); + spin_unlock(&i2o_configuration_lock); return 0; } -int i2o_release_device(struct i2o_device *d) +int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type) { + int err = 0; + spin_lock(&i2o_configuration_lock); - if(d->owner==NULL) + + /* Primary user */ + if(type == I2O_CLAIM_PRIMARY) { + if(d->owner != h) + err = -ENOENT; + else + { + if(i2o_issue_claim(d->controller,d->id, h->context, 0, &reply_flag, type) < 0) + { + err = -ENXIO; + } + else + { + d->owner = NULL; + atomic_dec(&d->controller->users); + } + } + spin_unlock(&i2o_configuration_lock); - return -EINVAL; + return err; } - atomic_dec(&d->controller->users); - d->owner=NULL; + + /* Management or other user */ + if(i2o_remove_management_user(d, h)) + err = -ENOENT; + else + { + atomic_dec(&d->controller->users); + + if(i2o_issue_claim(d->controller,d->id, h->context, 0, + &reply_flag, type) < 0) + err = -ENXIO; + } + spin_unlock(&i2o_configuration_lock); + return err; +} + +int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h) +{ + int i; + + if(d->num_managers == I2O_MAX_MANAGERS) + return 1; + + for(i = 0; i < I2O_MAX_MANAGERS; i++) + if(!d->managers[i]) + d->managers[i] = h; + + d->num_managers++; + return 0; } +int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h) +{ + int i; + + for(i=0; i < I2O_MAX_MANAGERS; i++) + { + if(d->managers[i] == h) + { + d->managers[i] = NULL; + return 0; + } + } + + return -ENOENT; +} + /* * This is called by the bus specific driver layer when an interrupt * or poll of this card interface is desired. @@ -363,7 +484,11 @@ void i2o_run_queue(struct i2o_controller *c) if(i) i->reply(i,c,m); else - printk("Spurious reply\n"); + { + printk("Spurious reply to handler %d\n", + m->initiator_context&(MAX_I2O_MODULES-1)); + i2o_dump_message((u32*)m); + } i2o_flush_reply(c,mv); mb(); } @@ -803,7 +928,8 @@ int i2o_quiesce_controller(struct i2o_controller *c) msg[2]=core_context; msg[3]=(u32)&reply_flag; - return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10); + /* Long timeout needed for quiesce if lots of devices */ + return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 120); } @@ -839,11 +965,15 @@ static int i2o_reset_controller(struct i2o_controller *c) /* First stop external operations */ for(iop=i2o_controller_chain; iop != NULL; iop=iop->next) { - if(i2o_quiesce_controller(iop)<0) - printk(KERN_INFO "Unable to quiesce iop%d\n", - iop->unit); - else - printk(KERN_DEBUG "%s quiesced\n", iop->name); + /* Quiesce is rejected on hold state */ + if(iop->status != ADAPTER_STATE_HOLD) + { + if(i2o_quiesce_controller(iop)<0) + printk(KERN_INFO "Unable to quiesce iop%d\n", + iop->unit); + else + printk(KERN_DEBUG "%s quiesced\n", iop->name); + } } /* Then reset the IOP */ @@ -1398,7 +1528,7 @@ int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *fl * Issue UTIL_CLAIM messages */ -int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag) +int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag, u32 type) { u32 msg[6]; @@ -1412,7 +1542,7 @@ int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, i msg[2] = 0x80000000|context; msg[3] = (u32)flag; - msg[4] = 0x01<<24; /* Primary user */ + msg[4] = type; return i2o_post_wait(c, tid, msg, 20, flag,2); } @@ -1999,8 +2129,19 @@ void i2o_report_status(const char *severity, const char *module, u32 *msg) return; } +/* Used to dump a message to syslog during debugging */ +static void i2o_dump_message(u32 *msg) +{ +#ifdef DRIVERDEBUG + int i; + + printk(KERN_INFO "Dumping I2O message @ %p\n", msg); + for(i = 0; i < ((msg[0]>>16)&0xffff); i++) + printk(KERN_INFO "\tmsg[%d] = %#10x\n", i, msg[i]); +#endif +} -#ifdef CONFIG_MODULE +#ifdef MODULE EXPORT_SYMBOL(i2o_install_handler); EXPORT_SYMBOL(i2o_remove_handler); @@ -2040,19 +2181,31 @@ MODULE_DESCRIPTION("I2O Core"); int init_module(void) { - if (i2o_install_handler(&i2o_core_handler) < 0) - { - printk(KERN_ERR "i2o_core: Unable to install core handler.\n"); - return 0; - } + if (i2o_install_handler(&i2o_core_handler) < 0) + { + printk(KERN_ERR "i2o_core: Unable to install core handler.\n"); + return 0; + } - core_context = i2o_core_handler.context; + core_context = i2o_core_handler.context; - return 0; + /* + * Attach core to I2O PCI subsystem + */ +#ifdef CONFIG_I2O_PCI_MODULE + if(i2o_pci_core_attach(&i2o_core_functions) < 0) + printk(KERN_INFO "No PCI I2O controllers found\n"); +#endif + + return 0; } void cleanup_module(void) { +#ifdef CONFIG_I2O_PCI_MODULE + i2o_pci_core_detach(); +#endif + i2o_remove_handler(&i2o_core_handler); } @@ -2093,4 +2246,4 @@ __init int i2o_init(void) return 0; } -#endif \ No newline at end of file +#endif diff --git a/drivers/i2o/i2o_lan.c b/drivers/i2o/i2o_lan.c index 930c36b7657e..0f16f5d2cbc5 100644 --- a/drivers/i2o/i2o_lan.c +++ b/drivers/i2o/i2o_lan.c @@ -1,7 +1,7 @@ /* * linux/drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM Prototyping, June 4th 1999 + * I2O LAN CLASS OSM Prototyping, July 16th 1999 * * (C) Copyright 1999 University of Helsinki, * Department of Computer Science @@ -15,17 +15,16 @@ * * Authors: Auvo Häkkinen * Juha Sievänen + * Deepak Saxena * * Tested: in FDDI environment (using SysKonnect's DDM) * in Ethernet environment (using Intel 82558 DDM proto) * * TODO: batch mode networking - * - this one assumes that we always get one packet - * in a bucket * - we've not been able to test batch replies and * batch receives - * - error checking / timeouts - * - code / test for other LAN classes + * error checking / timeouts + * code / test for other LAN classes */ #include @@ -39,6 +38,7 @@ #include #include #include +#include #include #include @@ -48,7 +48,7 @@ //#define DRIVERDEBUG #ifdef DRIVERDEBUG -#define dprintk(s, args...) printk(s, ## args) +#define dprintk(s, args...) printk(s, ## args) #else #define dprintk(s, args...) #endif @@ -64,17 +64,25 @@ struct i2o_lan_local { u32 packet_tresh; /* treshold for incoming skb's */ struct fddi_statistics stats; /* see also struct net_device_stats */ unsigned short (*type_trans)(struct sk_buff *, struct device *); + /* + * Due to way that interrupts can pile up, we need to keep track + * of buckets ourselves. Otherwise we'll end up flooding + * the DDM with buckets. + */ + u32 bucket_count; }; /* function prototypes */ static int i2o_lan_receive_post(struct device *dev); static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m); +static void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv); /* * Module params */ -static u32 bucketpost = 64; -static u32 bucketthresh = 8; +static u32 bucketpost = I2O_BUCKET_COUNT; +static u32 bucketthresh = I2O_BUCKET_THRESH; +static u32 rx_copybreak = 200; static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m) @@ -82,6 +90,15 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, u32 *msg = (u32 *)m; u8 unit = (u8)(msg[2]>>16); // InitiatorContext struct device *dev = i2o_landevs[unit]; + struct i2o_lan_local *priv; + + if(dev) + priv = (struct i2o_lan_local *)dev->priv; + else + priv = NULL; + + dprintk("Unit: %d Function: %#x\n", + unit, msg[1]>>24); if (msg[0] & (1<<13)) // Fail bit is set { @@ -97,36 +114,41 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, return; } -#ifdef DRIVERDEBUG -// if (msg[4] >> 24) /* ReqStatus != SUCCESS */ - i2o_report_status(KERN_INFO, "i2o_lan", msg); +#ifndef DRIVERDEBUG + if (msg[4] >> 24) /* ReqStatus != SUCCESS */ #endif + i2o_report_status(KERN_INFO, dev->name, msg); switch (msg[1] >> 24) { case LAN_RECEIVE_POST: - if (dev->start) - i2o_lan_receive_post_reply(dev,m); - else { - // we are getting unused buckets back - u8 trl_count = msg[3] & 0x000000FF; - struct i2o_bucket_descriptor *bucket = - (struct i2o_bucket_descriptor *)&msg[6]; - do { - dprintk("%s: Releasing unused bucket\n",dev->name); - dev_kfree_skb((struct sk_buff *)bucket->context); - bucket++; - } while (--trl_count); - } - break; + { + if (dev->start) + { + if(!(msg[4]>>24)) + { + i2o_lan_receive_post_reply(dev,m); + break; + } + else + { + // Something VERY wrong if this is happening + printk( KERN_WARNING "i2olan: Device %s rejected bucket post\n", dev->name); + i2o_lan_release_buckets(msg,priv); + } + } + else + { + i2o_lan_release_buckets(msg,priv); + } + + break; + } case LAN_PACKET_SEND: case LAN_SDU_SEND: { u8 trl_count = msg[3] & 0x000000FF; - if (msg[4] >> 24) // ReqStatus != SUCCESS - i2o_report_status(KERN_WARNING, dev->name, msg); - do { // The HDM has handled the outgoing packet dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", @@ -135,29 +157,47 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, dev->tbusy = 0; mark_bh(NET_BH); /* inform upper layers */ + + break; } - break; default: if (msg[2] & 0x80000000) // reply to a UtilParamsGet/Set { - int *flag = (int *)msg[3]; // flag for i2o_post_wait + int *flag = (int *)msg[3]; // flag for i2o_post_wait if (msg[4] >> 24) // ReqStatus != SUCCESS { - i2o_report_status(KERN_WARNING, dev->name, msg); - *flag = -(msg[4] & 0xFFFF); // DetailedStatus - } - else - *flag = I2O_POST_WAIT_OK; + *flag = -(msg[4] & 0xFFFF); // DetailedStatus + } + else + *flag = I2O_POST_WAIT_OK; } } } +void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv) +{ + u8 trl_count = (u8)(msg[3] & 0x000000FF); + u32 *pskb = &msg[6]; + + while (trl_count) + { + dprintk("%s: Releasing unused sk_buff %p\n",dev->name, + (struct sk_buff*)(*pskb)); + dev_kfree_skb((struct sk_buff*)(*pskb)); + pskb++; + if(priv) + priv->bucket_count--; + trl_count--; + } +} + static struct i2o_handler i2o_lan_handler = { i2o_lan_reply, "I2O Lan OSM", - 0 // context + 0, // context + I2O_CLASS_LAN }; static int lan_context; @@ -177,22 +217,25 @@ static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m) "msgsize = %d, buckets_remaining = %d\n", msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]); #endif - dprintk(KERN_INFO "Buckets_remaining = %d\n",msg[5]); + + dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d\n", + msg[5], priv->bucket_count); do { skb = (struct sk_buff *)(bucket->context); packet = (struct i2o_packet_info *)bucket->packet_info; + priv->bucket_count--; #if 0 - dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n", + dprintk(KERN)INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n", packet->flags, packet->offset, packet->status, packet->len); #endif - if (packet->len < priv->packet_tresh) { + if (packet->len < rx_copybreak) { newskb = (struct sk_buff *) dev_alloc_skb(packet->len+2); if (newskb) { skb_reserve(newskb,2); memcpy(skb_put(newskb,packet->len), - skb->data, packet->len); + skb->data, packet->len); newskb->dev = dev; newskb->protocol = priv->type_trans(newskb, dev); @@ -200,10 +243,11 @@ static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m) dev_kfree_skb(skb); // FIXME: reuse this skb? } else { - printk("Can't allocate skb.\n"); + printk("I2OLAN-%s: Can't allocate skb.\n", dev->name); return -ENOMEM; } } else { + skb_put(skb,packet->len); skb->dev = dev; skb->protocol = priv->type_trans(skb, dev); @@ -216,9 +260,18 @@ static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m) bucket++; // to next Packet Descriptor Block } while (--trl_count); - - if (msg[5] <= bucketthresh) // BucketsRemaining + if (priv->bucket_count <= bucketthresh) // BucketsRemaining + { + dprintk("Bucket_count = %d, ",priv->bucket_count); i2o_lan_receive_post(dev); + } + + + if((msg[4]& 0x0000ffff) == 0x05) // I2O_LAN_RECEIVE_OVERRUN + { + printk("Bucket overrun! priv->bucketcount = %d\n", + priv->bucket_count); + } return 0; } @@ -267,6 +320,9 @@ static int i2o_lan_receive_post(struct device *dev) if (skb == NULL) return -ENOMEM; skb_reserve(skb, 2); + + priv->bucket_count++; + msg[4 + 3*i] = 0x51000000 | bucket_len; msg[5 + 3*i] = (u32)skb; msg[6 + 3*i] = virt_to_bus(skb->data); @@ -279,6 +335,7 @@ static int i2o_lan_receive_post(struct device *dev) total += bucket_count; } + return 0; } @@ -317,6 +374,7 @@ static int i2o_lan_suspend(struct device *dev) struct i2o_controller *iop = i2o_dev->controller; u32 msg[5]; + dprintk( "%s: LAN SUSPEND MESSAGE\n", dev->name ); msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext @@ -350,7 +408,7 @@ static void i2o_set_batch_mode(struct device *dev) // enable batch mode, toggle automatically val = 0x00000000; // val = 0x00000001; // turn off batch mode - if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0003, 0, + if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0003, 0, &val, 4, &priv->reply_flag) <0) printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n"); else @@ -364,7 +422,7 @@ static void i2o_set_batch_mode(struct device *dev) /* set LAN_OPERATION attributes */ val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit - if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0004, 2, + if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0004, 2, &val, 4, &priv->reply_flag) < 0) printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n"); else @@ -384,8 +442,10 @@ static int i2o_lan_open(struct device *dev) struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, +/* if (i2o_issue_claim(iop, i2o_dev->id, priv->unit << 16 | lan_context, 1, &priv->reply_flag) < 0) +*/ + if(i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) { printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); return -EAGAIN; @@ -424,8 +484,12 @@ static int i2o_lan_close(struct device *dev) i2o_lan_suspend(dev); - if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, +/* + if (i2o_issue_claim(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0, &priv->reply_flag) < 0) +*/ + + if(i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " "(tid=%d)\n", dev->name, i2o_dev->id); @@ -513,7 +577,6 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct device *dev) msg[6] = virt_to_bus(skb->data); i2o_post_message(iop,m); - dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", dev->name, skb->len); @@ -528,7 +591,7 @@ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) u64 val64[16]; u64 supported_group[4] = { 0, 0, 0, 0 }; - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0100, -1, val64, sizeof(val64), &priv->reply_flag) < 0) dprintk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name); else { @@ -542,11 +605,11 @@ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) priv->stats.rx_dropped = val64[6]; } - i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0180, -1, + i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0180, -1, &supported_group, sizeof(supported_group), &priv->reply_flag); if (supported_group[2]) { - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0183, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0183, -1, val64, sizeof(val64), &priv->reply_flag) < 0) dprintk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name); else { @@ -561,23 +624,24 @@ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) { u64 supported_stats = 0; - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0200, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0200, -1, val64, sizeof(val64), &priv->reply_flag) < 0) dprintk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name); else { - dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name); +// dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name); priv->stats.transmit_collision = val64[1] + val64[2]; priv->stats.rx_frame_errors = val64[0]; priv->stats.tx_carrier_errors = val64[6]; } - - i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0280, -1, - &supported_stats, 8, &priv->reply_flag); - + + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0280, -1, + &supported_stats, 8, &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS\n", dev->name); + if (supported_stats != 0) { - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0281, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0281, -1, val64, sizeof(val64), &priv->reply_flag) < 0) - dprintk("%s: Unable to query LAN_OPTIONLA_802_3_HISTORICAL_STATS.\n",dev->name); + dprintk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name); else { dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name); if (supported_stats & 0x1) @@ -586,18 +650,19 @@ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) priv->stats.tx_heartbeat_errors = val64[2]; } } + } #ifdef CONFIG_TR if (i2o_dev->subclass == I2O_LAN_TR) { - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0300, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0300, -1, val64, sizeof(val64), &priv->reply_flag) < 0) dprintk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name); else { struct tr_statistics *stats = (struct tr_statistics *)&priv->stats; - dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); +// dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); stats->line_errors = val64[0]; stats->internal_errors = val64[7]; @@ -617,11 +682,11 @@ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) #ifdef CONFIG_FDDI if (i2o_dev->subclass == I2O_LAN_FDDI) { - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0400, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0400, -1, val64, sizeof(val64), &priv->reply_flag) < 0) dprintk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name); else { - dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); +// dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); priv->stats.smt_cf_state = val64[0]; memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); @@ -654,15 +719,29 @@ static void i2o_lan_set_multicast_list(struct device *dev) dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name); +if (dev==NULL) + printk("dev is NULL\n"); +else if (dev->priv==NULL) + printk("dev->priv is NULL\n"); +else if (priv->i2o_dev==NULL) + printk("i2o_dev is NULL\n"); +else if (i2o_dev->controller==NULL) + printk("iop is NULL\n"); +else { + printk("Everything seems to be OK in i2o_lan_set_multicast_list().\n"); + printk("id = %d, unit = %d, lan_context = %d\n", + i2o_dev->id, priv->unit, lan_context); +} + return; /* FIXME: Why does the next call kill the interrupt handler? - * The same works fine in function lan_open(), and in i2o_proc.c + * The same piece of code works fine in function lan_open(), and in i2o_proc.c * - * *because its trying to sleep in an irq - this must be async - Alan + * *because its trying to sleep in an irq - this must be async - Alan */ - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, -1, + if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0001, -1, &work32, sizeof(work32), &priv->reply_flag) < 0 ) { printk(KERN_WARNING "i2o_lan: Unable to query " @@ -705,11 +784,11 @@ return; mclist = mclist->next; } - if (i2o_clear_table(iop, i2o_dev->id, lan_context, 0x0002, + if (i2o_clear_table(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0002, &priv->reply_flag) < 0 ) dprintk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); - if (i2o_row_add_table(iop, i2o_dev->id, lan_context, 0x0002, -1, + if (i2o_row_add_table(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0002, -1, work32, dev->mc_count*8, &priv->reply_flag) < 0) dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); } @@ -719,7 +798,7 @@ return; dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n"); } - if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, + if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0001, 3, &filter_mask, 4, &priv->reply_flag) <0) printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n"); @@ -744,12 +823,14 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev) unregister_dev = unregister_netdev; break; + #ifdef CONFIG_ANYLAN case I2O_LAN_100VG: printk(KERN_ERR "i2o_lan: 100base VG not yet supported\n"); break; #endif + #ifdef CONFIG_TR case I2O_LAN_TR: dev = init_trdev(NULL, sizeof(struct i2o_lan_local)); @@ -802,11 +883,18 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev) priv = (struct i2o_lan_local *)dev->priv; priv->i2o_dev = i2o_dev; priv->type_trans = type_trans; - - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, lan_context, - 0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0) + priv->bucket_count = 0; + + unit++; + i2o_landevs[unit] = dev; + priv->unit = unit; + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, + priv->unit << 16 | lan_context, + 0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0) { printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); + unit--; unregister_dev(dev); kfree(dev); return NULL; @@ -835,29 +923,33 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev) __init int i2o_lan_init(void) { struct device *dev; - struct i2o_lan_local *priv; - int i; + int i; - if (i2o_install_handler(&i2o_lan_handler) < 0) + bucketpost = bucketpost - bucketthresh; + + if (i2o_install_handler(&i2o_lan_handler) < 0) { printk(KERN_ERR "Unable to register I2O LAN OSM.\n"); return -EINVAL; - } + } + + for(i=0; i <= MAX_LAN_CARDS; i++) + i2o_landevs[i] = NULL; lan_context = i2o_lan_handler.context; - for (i=0; i < MAX_I2O_CONTROLLERS; i++) + for (i=0; i < MAX_I2O_CONTROLLERS; i++) { - struct i2o_controller *iop = i2o_find_controller(i); - struct i2o_device *i2o_dev; + struct i2o_controller *iop = i2o_find_controller(i); + struct i2o_device *i2o_dev; - if (iop==NULL) + if (iop==NULL) continue; - for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) + for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { - if (i2o_dev->class != I2O_CLASS_LAN) - continue; + if (i2o_dev->class != I2O_CLASS_LAN) + continue; if (unit == MAX_LAN_CARDS) { @@ -872,19 +964,15 @@ __init int i2o_lan_init(void) printk(KERN_ERR "Unable to register I2O LAN device\n"); continue; // try next one } - priv = (struct i2o_lan_local *)dev->priv; - - unit++; - i2o_landevs[unit] = dev; - priv->unit = unit; printk(KERN_INFO "%s: I2O LAN device registered, tid = %d," " subclass = 0x%08X, unit = %d.\n", - dev->name, i2o_dev->id, i2o_dev->subclass, - priv->unit); - } + dev->name, i2o_dev->id, i2o_dev->subclass, + ((struct i2o_lan_local *)dev->priv)->unit); + } + i2o_unlock_controller(iop); - } + } dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1); @@ -940,5 +1028,6 @@ MODULE_DESCRIPTION("I2O Lan OSM"); MODULE_PARM(bucketpost, "i"); // Number of buckets to post MODULE_PARM(bucketthresh, "i"); // Bucket post threshold +MODULE_PARM(rx_copybreak, "i"); #endif diff --git a/drivers/i2o/i2o_lan.h b/drivers/i2o/i2o_lan.h index 0f05cd96d297..d54022a9389c 100644 --- a/drivers/i2o/i2o_lan.h +++ b/drivers/i2o/i2o_lan.h @@ -17,8 +17,8 @@ /* Tunable parameters first */ -#define I2O_BUCKET_COUNT 16 -#define I2O_BUCKET_THRESH 0 +#define I2O_BUCKET_COUNT 64 +#define I2O_BUCKET_THRESH 16 /* LAN types */ #define I2O_LAN_ETHERNET 0x0030 diff --git a/drivers/i2o/i2o_pci.c b/drivers/i2o/i2o_pci.c index d0bcaaa18331..44fe37a15d11 100644 --- a/drivers/i2o/i2o_pci.c +++ b/drivers/i2o/i2o_pci.c @@ -5,16 +5,18 @@ * (C) Copyright 1999 Red Hat Software * * Written by Alan Cox, Building Number Three Ltd + * Modified by Deepak Saxena * * 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 + * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * TODO: * Support polled I2O PCI controllers. */ - + +#include #include #include #include @@ -24,10 +26,21 @@ #include #include +#ifdef MODULE +/* + * Core function table + * See for an explanation + */ +static struct i2o_core_func_table *core; + +/* Core attach function */ +extern int i2o_pci_core_attach(struct i2o_core_func_table *); +extern void i2o_pci_core_detach(void); +#endif /* MODULE */ + /* * Free bus specific resources */ - static void i2o_pci_dispose(struct i2o_controller *c) { I2O_IRQ_WRITE32(c,0xFFFFFFFF); @@ -60,7 +73,11 @@ static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) { struct i2o_controller *c = dev_id; +#ifdef MODULE + core->run_queue(c); +#else i2o_run_queue(c); +#endif /* MODULE */ } /* @@ -76,20 +93,20 @@ int __init i2o_pci_install(struct pci_dev *dev) u32 size; int i; - + if(c==NULL) { printk(KERN_ERR "i2o_pci: insufficient memory to add controller.\n"); return -ENOMEM; } memset(c, 0, sizeof(*c)); - + for(i=0; i<6; i++) { /* Skip I/O spaces */ - if(!(dev->base_address[i]&PCI_BASE_ADDRESS_SPACE)) + if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE)) { - memptr=PCI_BASE_ADDRESS_MEM_MASK&dev->base_address[i]; + memptr=dev->resource[i].flags; break; } } @@ -100,10 +117,7 @@ int __init i2o_pci_install(struct pci_dev *dev) return -ENOMEM; } - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, 0xFFFFFFFF); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, &size); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, dev->base_address[i]); - + size = dev->resource[i].end-dev->resource[i].start+1; /* Map the I2O controller */ printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size); @@ -125,8 +139,12 @@ int __init i2o_pci_install(struct pci_dev *dev) c->type = I2O_TYPE_PCI; I2O_IRQ_WRITE32(c,0xFFFFFFFF); - + +#ifdef MODULE + i = core->install(c); +#else i = i2o_install_controller(c); +#endif /* MODULE */ if(i<0) { @@ -144,7 +162,11 @@ int __init i2o_pci_install(struct pci_dev *dev) printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", c->name, dev->irq); c->bus.pci.irq = -1; +#ifdef MODULE + core->delete(c); +#else i2o_delete_controller(c); +#endif /* MODULE */ return -EBUSY; } } @@ -187,12 +209,27 @@ static void i2o_pci_unload(void) for(i = 0; i < MAX_I2O_CONTROLLERS; i++) { +#ifdef MODULE + c=core->find(i); +#else c=i2o_find_controller(i); +#endif /* MODULE */ + if(c==NULL) continue; + +#ifdef MODULE + core->unlock(c); +#else i2o_unlock_controller(c); +#endif /* MODULE */ + if(c->type == I2O_TYPE_PCI) +#ifdef MODULE + core->delete(c); +#else i2o_delete_controller(c); +#endif /* MODULE */ } } @@ -203,50 +240,102 @@ static void i2o_pci_activate(void) for(i = 0; i < MAX_I2O_CONTROLLERS; i++) { +#ifdef MODULE + c=core->find(i); +#else c=i2o_find_controller(i); +#endif /* MODULE */ + if(c==NULL) continue; if(c->type == I2O_TYPE_PCI) { +#ifdef MODULE + if(core->activate(c)) +#else if(i2o_activate_controller(c)) +#endif /* MODULE */ { printk("I2O: Failed to initialize iop%d\n", c->unit); +#ifdef MODULE + core->unlock(c); + core->delete(c); +#else i2o_unlock_controller(c); i2o_delete_controller(c); +#endif continue; } I2O_IRQ_WRITE32(c,0); } +#ifdef MODULE + core->unlock(c); +#else i2o_unlock_controller(c); +#endif } } + #ifdef MODULE -EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Red Hat Software"); -MODULE_DESCRIPTION("I2O PCI Interface"); +int i2o_pci_core_attach(struct i2o_core_func_table *table) +{ + int i; + + MOD_INC_USE_COUNT; + + core = table; + + if((i = i2o_pci_scan())<0) + return -ENODEV; + i2o_pci_activate(); + + return i; +} + +void i2o_pci_core_detach(void) +{ + i2o_pci_unload(); + + MOD_DEC_USE_COUNT; +} int init_module(void) { - if(i2o_pci_scan()<0) - return -ENODEV; - i2o_pci_activate(); - return 0; + printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); + +/* + * Let the core call the scan function for module dependency + * reasons. See include/linux/i2o.h for the reason why this + * is done. + * + * if(i2o_pci_scan()<0) + * return -ENODEV; + * i2o_pci_activate(); + */ + + return 0; + } void cleanup_module(void) { - i2o_pci_unload(); } +EXPORT_SYMBOL(i2o_pci_core_attach); +EXPORT_SYMBOL(i2o_pci_core_detach); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O PCI Interface"); + #else __init void i2o_pci_init(void) { + printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); if(i2o_pci_scan()>=0) { - printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); i2o_pci_activate(); } } diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c index 2bb9fcfc4b03..f0d8afe39e0d 100644 --- a/drivers/i2o/i2o_proc.c +++ b/drivers/i2o/i2o_proc.c @@ -3,7 +3,7 @@ * * Copyright (c) 1999 Intel Corporation * - * Originally written by Deepak Saxena(deepak.saxena@intel.com) + * Originally written by Deepak Saxena(deepak@plexity.net) * * This program is free software. You can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,6 +38,7 @@ #define FMT_U64_HEX "0x%08x%08x" #define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) +#include #include #include #include @@ -143,7 +144,8 @@ static struct i2o_handler i2o_proc_handler = { (void *)i2o_proc_reply, "I2O procfs Layer", - 0 + 0, + 0xffffffff // All classes }; /* @@ -3089,7 +3091,7 @@ __init int i2o_proc_init(void) #ifdef MODULE -MODULE_AUTHOR("Intel Corporation"); +MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); void cleanup_module(void) diff --git a/drivers/i2o/i2o_scsi.c b/drivers/i2o/i2o_scsi.c index 45ed85973152..1f437b6acf22 100644 --- a/drivers/i2o/i2o_scsi.c +++ b/drivers/i2o/i2o_scsi.c @@ -293,7 +293,8 @@ struct i2o_handler i2o_scsi_handler= { i2o_scsi_reply, "I2O SCSI OSM", - 0 + 0, + I2O_CLASS_SCSI_PERIPHERAL }; static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 62f73cd711a3..2e00a2ca3153 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -655,20 +655,9 @@ static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) continue; { -#if LINUX_VERSION_CODE >= 0x20155 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0] & ~3; + ioaddr = pdev->resource[0].start; irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr & ~3;; - irq = pci_irq_line; -#endif } /* Power-up the card. */ diff --git a/drivers/net/Space.c b/drivers/net/Space.c index fd660f2ab912..7400b2eb3ea0 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -680,6 +680,14 @@ static struct device mkiss_bootstrap = { #define NEXT_DEV (&mkiss_bootstrap) #endif /* MKISS */ +#if defined(CONFIG_YAM) +extern int yam_init(struct device *); +static struct device yam_bootstrap = { + "yam", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, yam_init, }; +#undef NEXT_DEV +#define NEXT_DEV (&yam_bootstrap) +#endif /* CONFIG_YAM */ + #if defined(CONFIG_STRIP) extern int strip_init_ctrl_dev(struct device *); static struct device strip_bootstrap = { diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 38fa4b98f54c..01de0f99f2ce 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -288,13 +288,13 @@ int __init acenic_probe (struct device *dev) break; } printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i " - "clks\n", pdev->base_address[0], dev->irq, pci_latency); + "clks\n", pdev->resource[0].start, dev->irq, pci_latency); /* * Remap the regs into kernel space. */ - ap->regs = (struct ace_regs *)ioremap(pdev->base_address[0], + ap->regs = (struct ace_regs *)ioremap(pdev->resource[0].start, 0x4000); if (!ap->regs){ printk(KERN_ERR "%s: Unable to map I/O register, " diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index ccd35038e020..9952aaccc661 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -2192,7 +2192,7 @@ pci_probe(struct device *dev, u_long ioaddr) lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = pdev->base_address[0] & CBIO_MASK; + iobase = pdev->resource[0].start; /* Fetch the IRQ to be used */ irq = pdev->irq; @@ -2278,7 +2278,7 @@ srom_search(struct pci_dev *dev) lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = dev->base_address[0] & CBIO_MASK; + iobase = dev->resource[0].start; /* Fetch the IRQ to be used */ irq = dev->irq; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 8588a8b4aacd..e74501b4a3fb 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1395,28 +1395,14 @@ dgrs_scan(struct device *dev) &pci_device_fn)) break; -#if LINUX_VERSION_CODE < 0x20100 - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &plxreg); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &io); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_2, &mem); -#else pdev = pci_find_slot(pci_bus, pci_device_fn); pci_irq = pdev->irq; - plxreg = pdev->base_address[0]; - io = pdev->base_address[1]; - mem = pdev->base_address[2]; -#endif + plxreg = pdev->resource[0].start; + io = pdev->resource[1].start; + mem = pdev->resource[2].start; pcibios_read_config_dword(pci_bus, pci_device_fn, 0x30, &plxdma); irq = pci_irq; - plxreg &= ~15; - io &= ~3; - mem &= ~15; plxdma &= ~15; /* diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 1c5d85721f1e..7574db8d4d56 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -285,7 +285,7 @@ int epic100_probe(struct device *dev) struct pci_dev *pcidev = NULL; while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev)) != NULL) { - long pci_ioaddr = pcidev->base_address[0] & ~3; + long pci_ioaddr = pcidev->resource[0].start; int vendor = pcidev->vendor; int device = pcidev->device; diff --git a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in index c2da88f1f4bb..9ded63d1c918 100644 --- a/drivers/net/hamradio/Config.in +++ b/drivers/net/hamradio/Config.in @@ -28,3 +28,5 @@ if [ "$CONFIG_SOUNDMODEM" != "n" ]; then bool ' soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800 bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 fi + +tristate 'YAM driver for AX.25' CONFIG_YAM diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index aeb14f32c1f4..962dbaa7fee4 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -53,6 +53,14 @@ else endif endif +ifeq ($(CONFIG_YAM),y) +L_OBJS += yam.o +else + ifeq ($(CONFIG_YAM),m) + M_OBJS += yam.o + endif +endif + ifeq ($(CONFIG_PI),y) L_OBJS += pi2.o else diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c new file mode 100644 index 000000000000..4fb1dc983d5d --- /dev/null +++ b/drivers/net/hamradio/yam.c @@ -0,0 +1,1297 @@ +/*****************************************************************************/ + +/* + * yam.c -- YAM radio modem driver. + * + * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr) + * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3 + * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration + * 0.2 F6FBB 08.06.98 Added delay after FPGA programming + * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 + * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance + * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics + * 0.6 F6FBB 25.08.98 Added 1200Bds format + * 0.7 F6FBB 12.09.98 Added to the kernel configuration + * 0.8 F6FBB 14.10.98 Fixed slottime/persistance timing bug + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +/* prototypes for ax25_encapsulate and ax25_rebuild_header */ +#include +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + +/* make genksyms happy */ +#include +#include +#include + +#include +#include + +#include +#include "yam9600.h" +#include "yam1200.h" + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +#if LINUX_VERSION_CODE < 0x20115 +extern __inline__ void dev_init_buffers(struct device *dev) +{ + int i; + for (i = 0; i < DEV_NUMBUFFS; i++) { + skb_queue_head_init(&dev->buffs[i]); + } +} +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +static const char yam_drvname[] = "yam"; +static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n"; + +/* --------------------------------------------------------------------- */ + +#define YAM_9600 1 +#define YAM_1200 2 + +#define NR_PORTS 4 +#define YAM_MAGIC 0xF10A7654 + +/* Transmitter states */ + +#define TX_OFF 0 +#define TX_HEAD 1 +#define TX_DATA 2 +#define TX_CRC1 3 +#define TX_CRC2 4 +#define TX_TAIL 5 + +#define YAM_MAX_FRAME 1024 + +#define DEFAULT_BITRATE 9600 /* bps */ +#define DEFAULT_HOLDD 10 /* sec */ +#define DEFAULT_TXD 300 /* ms */ +#define DEFAULT_TXTAIL 10 /* ms */ +#define DEFAULT_SLOT 100 /* ms */ +#define DEFAULT_PERS 64 /* 0->255 */ + +struct yam_port { + int magic; + int bitrate; + int baudrate; + int iobase; + int irq; + int dupmode; + char name[16]; + + struct device dev; + + /* Stats section */ + +#if LINUX_VERSION_CODE < 0x20119 + struct enet_statistics stats; +#else + struct net_device_stats stats; +#endif + int nb_rxint; + int nb_mdint; + + /* Parameters section */ + + int txd; /* tx delay */ + int holdd; /* duplex ptt delay */ + int txtail; /* txtail delay */ + int slot; /* slottime */ + int pers; /* persistence */ + + /* Tx section */ + + int tx_state; + int tx_count; + int slotcnt; + unsigned char tx_buf[YAM_MAX_FRAME]; + int tx_len; + int tx_crcl, tx_crch; + struct sk_buff_head send_queue; /* Packets awaiting transmission */ + + /* Rx section */ + + int dcd; + unsigned char rx_buf[YAM_MAX_FRAME]; + int rx_len; + int rx_crcl, rx_crch; +}; + +struct yam_mcs { + unsigned char bits[YAM_FPGA_SIZE]; + int bitrate; + struct yam_mcs *next; +}; + +static struct yam_port yam_ports[NR_PORTS]; + +static struct yam_mcs *yam_data = NULL; + +static unsigned irqs[16]; + +static char ax25_bcast[7] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static char ax25_test[7] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +static struct timer_list yam_timer; + +/* --------------------------------------------------------------------- */ + +#define RBR(iobase) (iobase+0) +#define THR(iobase) (iobase+0) +#define IER(iobase) (iobase+1) +#define IIR(iobase) (iobase+2) +#define FCR(iobase) (iobase+2) +#define LCR(iobase) (iobase+3) +#define MCR(iobase) (iobase+4) +#define LSR(iobase) (iobase+5) +#define MSR(iobase) (iobase+6) +#define SCR(iobase) (iobase+7) +#define DLL(iobase) (iobase+0) +#define DLM(iobase) (iobase+1) + +#define YAM_EXTENT 8 + +/* Interrupt Identification Register Bit Masks */ +#define IIR_NOPEND 1 +#define IIR_MSR 0 +#define IIR_TX 2 +#define IIR_RX 4 +#define IIR_LSR 6 +#define IIR_TIMEOUT 12 /* Fifo mode only */ + +#define IIR_MASK 0x0F + +/* Interrupt Enable Register Bit Masks */ +#define IER_RX 1 /* enable rx interrupt */ +#define IER_TX 2 /* enable tx interrupt */ +#define IER_LSR 4 /* enable line status interrupts */ +#define IER_MSR 8 /* enable modem status interrupts */ + +/* Modem Control Register Bit Masks */ +#define MCR_DTR 0x01 /* DTR output */ +#define MCR_RTS 0x02 /* RTS output */ +#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */ +#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */ +#define MCR_LOOP 0x10 /* Loopback enable */ + +/* Modem Status Register Bit Masks */ +#define MSR_DCTS 0x01 /* Delta CTS input */ +#define MSR_DDSR 0x02 /* Delta DSR */ +#define MSR_DRIN 0x04 /* Delta RI */ +#define MSR_DDCD 0x08 /* Delta DCD */ +#define MSR_CTS 0x10 /* CTS input */ +#define MSR_DSR 0x20 /* DSR input */ +#define MSR_RING 0x40 /* RI input */ +#define MSR_DCD 0x80 /* DCD input */ + +/* line status register bit mask */ +#define LSR_RXC 0x01 +#define LSR_OE 0x02 +#define LSR_PE 0x04 +#define LSR_FE 0x08 +#define LSR_BREAK 0x10 +#define LSR_THRE 0x20 +#define LSR_TSRE 0x40 + +/* Line Control Register Bit Masks */ +#define LCR_DLAB 0x80 +#define LCR_BREAK 0x40 +#define LCR_PZERO 0x28 +#define LCR_PEVEN 0x18 +#define LCR_PODD 0x08 +#define LCR_STOP1 0x00 +#define LCR_STOP2 0x04 +#define LCR_BIT5 0x00 +#define LCR_BIT6 0x02 +#define LCR_BIT7 0x01 +#define LCR_BIT8 0x03 + +/* YAM Modem <-> UART Port mapping */ + +#define TX_RDY MSR_DCTS /* transmitter ready to send */ +#define RX_DCD MSR_DCD /* carrier detect */ +#define RX_FLAG MSR_RING /* hdlc flag received */ +#define FPGA_DONE MSR_DSR /* FPGA is configured */ +#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */ +#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */ + +#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */ +#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */ +#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */ + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/************************************************************************* +* CRC Tables +************************************************************************/ + +static const unsigned char chktabl[256] = +{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e, + 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64, + 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e, + 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50, + 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e, + 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44, + 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e, + 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38, + 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e, + 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24, + 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e, + 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10, + 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e, + 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04, + 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e, + 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9, + 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1, + 0x78}; +static const unsigned char chktabh[256] = +{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9, + 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb, + 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb, + 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f, + 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed, + 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf, + 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef, + 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07, + 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1, + 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3, + 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3, + 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87, + 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5, + 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7, + 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7, + 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f, + 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e, + 0x0f}; + +/************************************************************************* +* FPGA functions +************************************************************************/ + +static void delay(int ms) +{ + unsigned long timeout = jiffies + ((ms * HZ) / 1000); + while (jiffies < timeout); +} + +/* + * reset FPGA + */ + +static void fpga_reset(int iobase) +{ + outb(0, IER(iobase)); + outb(LCR_DLAB | LCR_BIT5, LCR(iobase)); + outb(1, DLL(iobase)); + outb(0, DLM(iobase)); + + outb(LCR_BIT5, LCR(iobase)); + inb(LSR(iobase)); + inb(MSR(iobase)); + /* turn off FPGA supply voltage */ + outb(MCR_OUT1 | MCR_OUT2, MCR(iobase)); + delay(100); + /* turn on FPGA supply voltage again */ + outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase)); + delay(100); +} + +/* + * send one byte to FPGA + */ + +static int fpga_write(int iobase, unsigned char wrd) +{ + unsigned char bit; + int k; + unsigned long timeout = jiffies + HZ / 10; + + for (k = 0; k < 8; k++) { + bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR; + outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase)); + wrd <<= 1; + outb(0xfc, THR(iobase)); + while ((inb(LSR(iobase)) & LSR_TSRE) == 0) + if (jiffies > timeout) + return -1; + } + + return 0; +} + +#ifdef MODULE +static void free_mcs(void) +{ + struct yam_mcs *p; + + while (yam_data) { + p = yam_data; + yam_data = yam_data->next; + kfree(p); + } +} +#endif + +static unsigned char * + add_mcs(unsigned char *bits, int bitrate) +{ + struct yam_mcs *p; + + /* If it already exists, replace the bit data */ + p = yam_data; + while (p) { + if (p->bitrate == bitrate) { + memcpy(p->bits, bits, YAM_FPGA_SIZE); + return p->bits; + } + p = p->next; + } + + /* Allocate a new mcs */ + p = kmalloc(sizeof(struct yam_mcs), GFP_ATOMIC); + if (p == NULL) { + printk(KERN_WARNING "YAM: no memory to allocate mcs\n"); + return NULL; + } + memcpy(p->bits, bits, YAM_FPGA_SIZE); + p->bitrate = bitrate; + p->next = yam_data; + yam_data = p; + + return p->bits; +} + +static unsigned char *get_mcs(int bitrate) +{ + struct yam_mcs *p; + + p = yam_data; + while (p) { + if (p->bitrate == bitrate) + return p->bits; + p = p->next; + } + + /* Load predefined mcs data */ + switch (bitrate) { + case 1200: + return add_mcs(bits_1200, bitrate); + default: + return add_mcs(bits_9600, bitrate); + } +} + +/* + * download bitstream to FPGA + * data is contained in bits[] array in fpgaconf.h + */ + +static int fpga_download(int iobase, int bitrate) +{ + int i, rc; + unsigned char *pbits; + + pbits = get_mcs(bitrate); + if (pbits == NULL) + return -1; + + fpga_reset(iobase); + for (i = 0; i < YAM_FPGA_SIZE; i++) { + if (fpga_write(iobase, pbits[i])) { + printk("yam: error in write cycle\n"); + return -1; /* write... */ + } + } + + fpga_write(iobase, 0xFF); + rc = inb(MSR(iobase)); /* check DONE signal */ + + /* Needed for some hardwares */ + delay(50); + + return (rc & MSR_DSR) ? 0 : -1; +} + + +/************************************************************************ +* Serial port init +************************************************************************/ + +static void yam_set_uart(struct device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + int divisor = 115200 / yp->baudrate; + + outb(0, IER(dev->base_addr)); + outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr)); + outb(divisor, DLL(dev->base_addr)); + outb(0, DLM(dev->base_addr)); + outb(LCR_BIT8, LCR(dev->base_addr)); + outb(PTT_OFF, MCR(dev->base_addr)); + outb(0x00, FCR(dev->base_addr)); + + /* Flush pending irq */ + + inb(RBR(dev->base_addr)); + inb(MSR(dev->base_addr)); + + /* Enable rx irq */ + + outb(ENABLE_RTXINT, IER(dev->base_addr)); +} + + +/* --------------------------------------------------------------------- */ + +enum uart { + c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A +}; + +static const char *uart_str[] = +{"unknown", "8250", "16450", "16550", "16550A"}; + +static enum uart yam_check_uart(unsigned int iobase) +{ + unsigned char b1, b2, b3; + enum uart u; + enum uart uart_tab[] = + {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A}; + + b1 = inb(MCR(iobase)); + outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ + b2 = inb(MSR(iobase)); + outb(0x1a, MCR(iobase)); + b3 = inb(MSR(iobase)) & 0xf0; + outb(b1, MCR(iobase)); /* restore old values */ + outb(b2, MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(RBR(iobase)); + inb(RBR(iobase)); + outb(0x01, FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, SCR(iobase)); + b1 = inb(SCR(iobase)); + outb(0xa5, SCR(iobase)); + b2 = inb(SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/****************************************************************************** +* Rx Section +******************************************************************************/ +static void inline + yam_rx_flag(struct device *dev, struct yam_port *yp) +{ + if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) { + int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */ + struct sk_buff *skb; + + if ((yp->rx_crch & yp->rx_crcl) != 0xFF) { + /* Bad crc */ + } else { + if (!(skb = dev_alloc_skb(pkt_len))) { + printk("%s: memory squeeze, dropping packet\n", dev->name); + ++yp->stats.rx_dropped; + } else { + unsigned char *cp; + skb->dev = dev; + cp = skb_put(skb, pkt_len); + *cp++ = 0; /* KISS kludge */ + memcpy(cp, yp->rx_buf, pkt_len - 1); + skb->protocol = htons(ETH_P_AX25); + skb->mac.raw = skb->data; + netif_rx(skb); + ++yp->stats.rx_packets; + } + } + } + yp->rx_len = 0; + yp->rx_crcl = 0x21; + yp->rx_crch = 0xf3; +} + +static void inline + yam_rx_byte(struct device *dev, struct yam_port *yp, unsigned char rxb) +{ + if (yp->rx_len < YAM_MAX_FRAME) { + unsigned char c = yp->rx_crcl; + yp->rx_crcl = (chktabl[c] ^ yp->rx_crch); + yp->rx_crch = (chktabh[c] ^ rxb); + yp->rx_buf[yp->rx_len++] = rxb; + } +} + +/******************************************************************************** +* TX Section +********************************************************************************/ + +static void ptt_on(struct device *dev) +{ + outb(PTT_ON, MCR(dev->base_addr)); +} + +static void ptt_off(struct device *dev) +{ + outb(PTT_OFF, MCR(dev->base_addr)); +} + +static int yam_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct yam_port *yp = dev->priv; + + if (skb == NULL) { + return 0; + } + skb_queue_tail(&yp->send_queue, skb); + dev->trans_start = jiffies; + return 0; +} + +static void yam_start_tx(struct device *dev, struct yam_port *yp) +{ + if ((yp->tx_state == TX_TAIL) || (yp->txd == 0)) + yp->tx_count = 1; + else + yp->tx_count = (yp->bitrate * yp->txd) / 8000; + yp->tx_state = TX_HEAD; + ptt_on(dev); +} + +static unsigned short random_seed; + +static inline unsigned short random_num(void) +{ + random_seed = 28629 * random_seed + 157; + return random_seed; +} + +static void yam_arbitrate(struct device *dev) +{ + struct yam_port *yp = dev->priv; + + if (!yp || yp->magic != YAM_MAGIC + || yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) { + return; + } + /* tx_state is TX_OFF and there is data to send */ + + if (yp->dupmode) { + /* Full duplex mode, don't wait */ + yam_start_tx(dev, yp); + return; + } + if (yp->dcd) { + /* DCD on, wait slotime ... */ + yp->slotcnt = yp->slot / 10; + return; + } + /* Is slottime passed ? */ + if ((--yp->slotcnt) > 0) + return; + + yp->slotcnt = yp->slot / 10; + + /* is random > persist ? */ + if ((random_num() % 256) > yp->pers) + return; + + yam_start_tx(dev, yp); +} + +static void yam_dotimer(unsigned long dummy) +{ + int i; + + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = &yam_ports[i].dev; + if (dev->start) + yam_arbitrate(dev); + } + yam_timer.expires = jiffies + HZ / 100; + add_timer(&yam_timer); +} + +static void yam_tx_byte(struct device *dev, struct yam_port *yp) +{ + struct sk_buff *skb; + unsigned char b, temp; + + switch (yp->tx_state) { + case TX_OFF: + break; + case TX_HEAD: + if (--yp->tx_count <= 0) { + if (!(skb = skb_dequeue(&yp->send_queue))) { + ptt_off(dev); + yp->tx_state = TX_OFF; + break; + } + yp->tx_state = TX_DATA; + if (skb->data[0] != 0) { +/* do_kiss_params(s, skb->data, skb->len); */ + dev_kfree_skb(skb); + break; + } + yp->tx_len = skb->len - 1; /* strip KISS byte */ + if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) { + dev_kfree_skb(skb); + break; + } + memcpy(yp->tx_buf, skb->data + 1, yp->tx_len); + dev_kfree_skb(skb); + yp->tx_count = 0; + yp->tx_crcl = 0x21; + yp->tx_crch = 0xf3; + yp->tx_state = TX_DATA; + } + break; + case TX_DATA: + b = yp->tx_buf[yp->tx_count++]; + outb(b, THR(dev->base_addr)); + temp = yp->tx_crcl; + yp->tx_crcl = chktabl[temp] ^ yp->tx_crch; + yp->tx_crch = chktabh[temp] ^ b; + if (yp->tx_count >= yp->tx_len) { + yp->tx_state = TX_CRC1; + } + break; + case TX_CRC1: + yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch; + yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff; + outb(yp->tx_crcl, THR(dev->base_addr)); + yp->tx_state = TX_CRC2; + break; + case TX_CRC2: + outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr)); + if (skb_queue_empty(&yp->send_queue)) { + yp->tx_count = (yp->bitrate * yp->txtail) / 8000; + if (yp->dupmode == 2) + yp->tx_count += (yp->bitrate * yp->holdd) / 8; + if (yp->tx_count == 0) + yp->tx_count = 1; + yp->tx_state = TX_TAIL; + } else { + yp->tx_count = 1; + yp->tx_state = TX_HEAD; + } + ++yp->stats.tx_packets; + break; + case TX_TAIL: + if (--yp->tx_count <= 0) { + yp->tx_state = TX_OFF; + ptt_off(dev); + } + break; + } +} + +/*********************************************************************************** +* ISR routine +************************************************************************************/ + +static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev; + struct yam_port *yp; + unsigned char iir; + int counter = 100; + int i; + + sti(); + + for (i = 0; i < NR_PORTS; i++) { + yp = &yam_ports[i]; + dev = &yp->dev; + + if (!dev->start) + continue; + + while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) { + unsigned char msr = inb(MSR(dev->base_addr)); + unsigned char lsr = inb(LSR(dev->base_addr)); + unsigned char rxb; + + if (lsr & LSR_OE) + ++yp->stats.rx_fifo_errors; + + yp->dcd = (msr & RX_DCD) ? 1 : 0; + + if (--counter <= 0) { + printk("%s: too many irq iir=%d\n", dev->name, iir); + return; + } + if (msr & TX_RDY) { + ++yp->nb_mdint; + yam_tx_byte(dev, yp); + } + if (lsr & LSR_RXC) { + ++yp->nb_rxint; + rxb = inb(RBR(dev->base_addr)); + if (msr & RX_FLAG) + yam_rx_flag(dev, yp); + else + yam_rx_byte(dev, yp, rxb); + } + } + } +} + +static int yam_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + int len = 0; + int i; + off_t pos = 0; + off_t begin = 0; + + cli(); + + for (i = 0; i < NR_PORTS; i++) { + if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0) + continue; + len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name); + len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start); + len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate); + len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase); + len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate); + len += sprintf(buffer + len, " IRQ %u\n", yam_ports[i].irq); + len += sprintf(buffer + len, " TxState %u\n", yam_ports[i].tx_state); + len += sprintf(buffer + len, " Duplex %u\n", yam_ports[i].dupmode); + len += sprintf(buffer + len, " HoldDly %u\n", yam_ports[i].holdd); + len += sprintf(buffer + len, " TxDelay %u\n", yam_ports[i].txd); + len += sprintf(buffer + len, " TxTail %u\n", yam_ports[i].txtail); + len += sprintf(buffer + len, " SlotTime %u\n", yam_ports[i].slot); + len += sprintf(buffer + len, " Persist %u\n", yam_ports[i].pers); + len += sprintf(buffer + len, " TxFrames %lu\n", yam_ports[i].stats.tx_packets); + len += sprintf(buffer + len, " RxFrames %lu\n", yam_ports[i].stats.rx_packets); + len += sprintf(buffer + len, " TxInt %u\n", yam_ports[i].nb_mdint); + len += sprintf(buffer + len, " RxInt %u\n", yam_ports[i].nb_rxint); + len += sprintf(buffer + len, " RxOver %lu\n", yam_ports[i].stats.rx_fifo_errors); + len += sprintf(buffer + len, "\n"); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + break; + } + + sti(); + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) + len = length; + + return len; +} + +#ifdef CONFIG_INET +#ifndef PROC_NET_YAM +#define PROC_NET_YAM (PROC_NET_LAST+10) /* Sorry again... */ +#endif + +struct proc_dir_entry yam_proc_dir_entry = +{ + PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, yam_net_get_info +}; + +#define yam_net_procfs_init() proc_net_register(&yam_proc_dir_entry); +#define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM); +#else +#define yam_net_procfs_init() +#define yam_net_procfs_remove() +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE >= 0x20119 +static struct net_device_stats * + yam_get_stats(struct device *dev) +#else +static struct enet_statistics * + yam_get_stats(struct device *dev) +#endif +{ + struct yam_port *yp; + + if (!dev || !dev->priv) + return NULL; + + yp = (struct yam_port *) dev->priv; + if (yp->magic != YAM_MAGIC) + return NULL; + + /* + * Get the current statistics. This may be called with the + * card open or closed. + */ + return &yp->stats; +} + +/* --------------------------------------------------------------------- */ + +static int yam_open(struct device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + enum uart u; + int i; + + printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); + + if (!dev || !yp || !yp->bitrate) + return -ENXIO; + if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || + dev->irq < 2 || dev->irq > 15) { + return -ENXIO; + } + if (check_region(dev->base_addr, YAM_EXTENT)) { + printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); + return -EACCES; + } + if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) { + printk("%s: cannot find uart type\n", dev->name); + return -EIO; + } + if (fpga_download(dev->base_addr, yp->bitrate)) { + printk("%s: cannot init FPGA\n", dev->name); + return -EIO; + } + outb(0, IER(dev->base_addr)); + if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) { + printk("%s: irq %d busy\n", dev->name, dev->irq); + return -EBUSY; + } + request_region(dev->base_addr, YAM_EXTENT, dev->name); + + yam_set_uart(dev); + dev->start = 1; + yp->slotcnt = yp->slot / 10; + + /* Reset overruns for all ports - FPGA programming makes overruns */ + for (i = 0; i < NR_PORTS; i++) { + inb(LSR(yam_ports[i].dev.base_addr)); + yam_ports[i].stats.rx_fifo_errors = 0; + } + + printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq, + uart_str[u]); + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_close(struct device *dev) +{ + struct sk_buff *skb; + struct yam_port *yp = (struct yam_port *) dev->priv; + + if (!dev || !yp) + return -EINVAL; + /* + * disable interrupts + */ + outb(0, IER(dev->base_addr)); + outb(1, MCR(dev->base_addr)); + /* Remove IRQ handler if last */ + free_irq(dev->irq, NULL); + release_region(dev->base_addr, YAM_EXTENT); + dev->start = 0; + dev->tbusy = 1; + while ((skb = skb_dequeue(&yp->send_queue))) + dev_kfree_skb(skb); + + printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n", + yam_drvname, dev->base_addr, dev->irq); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + struct yamdrv_ioctl_cfg yi; + struct yamdrv_ioctl_mcs *ym; + int ioctl_cmd; + + if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int))) + return -EFAULT; + + if (yp == NULL || yp->magic != YAM_MAGIC) + return -EINVAL; + + if (!suser()) + return -EPERM; + + if (cmd != SIOCDEVPRIVATE) + return -EINVAL; + + switch (ioctl_cmd) { + + case SIOCYAMRESERVED: + return -EINVAL; /* unused */ + + case SIOCYAMSMCS: + if (dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC); + ym->bitrate = 9600; + if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) + return -EFAULT; + if (ym->bitrate > YAM_MAXBITRATE) + return -EINVAL; + add_mcs(ym->bits, ym->bitrate); + kfree(ym); + break; + + case SIOCYAMSCFG: + if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg))) + return -EFAULT; + + if ((yi.cfg.mask & YAM_IOBASE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_IRQ) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_BITRATE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + + if (yi.cfg.mask & YAM_IOBASE) { + yp->iobase = yi.cfg.iobase; + dev->base_addr = yi.cfg.iobase; + } + if (yi.cfg.mask & YAM_IRQ) { + if (yi.cfg.irq > 15) + return -EINVAL; + yp->irq = yi.cfg.irq; + dev->irq = yi.cfg.irq; + } + if (yi.cfg.mask & YAM_BITRATE) { + if (yi.cfg.bitrate > YAM_MAXBITRATE) + return -EINVAL; + yp->bitrate = yi.cfg.bitrate; + } + if (yi.cfg.mask & YAM_BAUDRATE) { + if (yi.cfg.baudrate > YAM_MAXBAUDRATE) + return -EINVAL; + yp->baudrate = yi.cfg.baudrate; + } + if (yi.cfg.mask & YAM_MODE) { + if (yi.cfg.mode > YAM_MAXMODE) + return -EINVAL; + yp->dupmode = yi.cfg.mode; + } + if (yi.cfg.mask & YAM_HOLDDLY) { + if (yi.cfg.holddly > YAM_MAXHOLDDLY) + return -EINVAL; + yp->holdd = yi.cfg.holddly; + } + if (yi.cfg.mask & YAM_TXDELAY) { + if (yi.cfg.txdelay > YAM_MAXTXDELAY) + return -EINVAL; + yp->txd = yi.cfg.txdelay; + } + if (yi.cfg.mask & YAM_TXTAIL) { + if (yi.cfg.txtail > YAM_MAXTXTAIL) + return -EINVAL; + yp->txtail = yi.cfg.txtail; + } + if (yi.cfg.mask & YAM_PERSIST) { + if (yi.cfg.persist > YAM_MAXPERSIST) + return -EINVAL; + yp->pers = yi.cfg.persist; + } + if (yi.cfg.mask & YAM_SLOTTIME) { + if (yi.cfg.slottime > YAM_MAXSLOTTIME) + return -EINVAL; + yp->slot = yi.cfg.slottime; + yp->slotcnt = yp->slot / 10; + } + break; + + case SIOCYAMGCFG: + yi.cfg.mask = 0xffffffff; + yi.cfg.iobase = yp->iobase; + yi.cfg.irq = yp->irq; + yi.cfg.bitrate = yp->bitrate; + yi.cfg.baudrate = yp->baudrate; + yi.cfg.mode = yp->dupmode; + yi.cfg.txdelay = yp->txd; + yi.cfg.holddly = yp->holdd; + yi.cfg.txtail = yp->txtail; + yi.cfg.persist = yp->pers; + yi.cfg.slottime = yp->slot; + if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg))) + return -EFAULT; + break; + + default: + return -EINVAL; + + } + + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *) addr; + + /* addr is an AX.25 shifted ASCII mac address */ + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_probe(struct device *dev) +{ + struct yam_port *yp; + + if (!dev) + return -ENXIO; + + yp = (struct yam_port *) dev->priv; + + dev->open = yam_open; + dev->stop = yam_close; + dev->do_ioctl = yam_ioctl; + dev->hard_start_xmit = yam_send_packet; + dev->get_stats = yam_get_stats; + + dev_init_buffers(dev); + skb_queue_head_init(&yp->send_queue); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + dev->hard_header = NULL; + dev->rebuild_header = NULL; +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + + dev->set_mac_address = yam_set_mac_address; + + dev->type = ARPHRD_AX25; /* AF_AX25 device */ + dev->hard_header_len = 73; /* We do digipeaters now */ + dev->mtu = 256; /* AX25 is the default */ + dev->addr_len = 7; /* sizeof an ax.25 address */ + memcpy(dev->broadcast, ax25_bcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); + + /* New style flags */ + dev->flags = 0; + + return 0; +} + +/* --------------------------------------------------------------------- */ + +__initfunc(int yam_init(struct device *dev)) +{ + int i; + + printk(yam_drvinfo); + + /* Clears the IRQ table */ + memset(irqs, 0, sizeof(irqs)); + memset(yam_ports, 0, sizeof(yam_ports)); + + for (i = 0; i < NR_PORTS; i++) { + sprintf(yam_ports[i].name, "yam%d", i); + yam_ports[i].magic = YAM_MAGIC; + yam_ports[i].bitrate = DEFAULT_BITRATE; + yam_ports[i].baudrate = DEFAULT_BITRATE * 2; + yam_ports[i].iobase = 0; + yam_ports[i].irq = 0; + yam_ports[i].dupmode = 0; + yam_ports[i].holdd = DEFAULT_HOLDD; + yam_ports[i].txd = DEFAULT_TXD; + yam_ports[i].txtail = DEFAULT_TXTAIL; + yam_ports[i].slot = DEFAULT_SLOT; + yam_ports[i].pers = DEFAULT_PERS; + + dev = &yam_ports[i].dev; + + dev->priv = &yam_ports[i]; + dev->name = yam_ports[i].name; + dev->base_addr = yam_ports[i].iobase; + dev->irq = yam_ports[i].irq; + dev->init = yam_probe; + dev->if_port = 0; + dev->start = 0; + dev->tbusy = 1; + + if (register_netdev(dev)) { + printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name); + return -ENXIO; + } + } + + yam_timer.function = yam_dotimer; + yam_timer.expires = jiffies + HZ / 100; + add_timer(&yam_timer); + + yam_net_procfs_init(); + + /* do not keep this device */ + return 1; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); +MODULE_DESCRIPTION("Yam amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + int ret = yam_init(NULL); + + return (ret == 1) ? 0 : ret; +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + del_timer(&yam_timer); + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = &yam_ports[i].dev; + if (!dev->priv) + continue; + if (dev->start) + yam_close(dev); + unregister_netdev(dev); + } + free_mcs(); + yam_net_procfs_remove(); +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/yam1200.h b/drivers/net/hamradio/yam1200.h new file mode 100644 index 000000000000..53ca8a3903a7 --- /dev/null +++ b/drivers/net/hamradio/yam1200.h @@ -0,0 +1,343 @@ +/* + * + * File yam1k2b5.mcs converted to h format by mcs2h + * + * (C) F6FBB 1998 + * + * Tue Aug 25 20:24:08 1998 + * + */ + +static unsigned char bits_1200[]= { +0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2, +0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf, +0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff, +0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf, +0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0, +0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f, +0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff, +0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, +0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb, +0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb, +0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe, +0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed, +0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef, +0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f, +0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff, +0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0, +0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f, +0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0, +0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f, +0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff, +0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e, +0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1, +0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea, +0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff, +0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff, +0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02, +0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, +0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff, +0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff, +0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf, +0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff, +0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff, +0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0, +0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08, +0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01, +0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f, +0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe, +0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33, +0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd, +0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff, +0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad, +0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc, +0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff, +0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff, +0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b, +0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf, +0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e, +0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f, +0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff, +0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff, +0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff, +0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40, +0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, +0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10, +0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00, +0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff, +0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7, +0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f, +0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff, +0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1, +0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd, +0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00, +0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00, +0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00, +0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff, +0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff, +0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef, +0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf, +0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7, +0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc, +0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff, +0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0, +0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7, +0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59, +0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f, +0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff, +0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5, +0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f, +0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc, +0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff, +0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab, +0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d, +0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff, +0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00, +0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00, +0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe, +0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff, +0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0, +0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff, +0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f, +0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34, +0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00, +0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03, +0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde, +0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef, +0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd, +0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1, +0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b, +0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, +0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd, +0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab, +0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff, +0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff, +0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff, +0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff, +0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff, +0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff, +0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1, +0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff, +0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff, +0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d, +0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7, +0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0, +0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20, +0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f, +0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf, +0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7, +0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff, +0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff, +0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d, +0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff, +0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02, +0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01, +0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe, +0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee, +0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f, +0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, +0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff, +0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2, +0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f, +0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff, +0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32, +0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4, +0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3, +0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97, +0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78, +0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1, +0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3, +0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff, +0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff, +0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe, +0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff, +0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed, +0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00, +0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00, +0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f, +0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff, +0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3, +0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff, +0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf, +0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0, +0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00, +0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10, +0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f, +0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd, +0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe, +0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a, +0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5, +0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff, +0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff, +0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb, +0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe, +0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf, +0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd, +0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8, +0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57, +0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73, +0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff, +0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, +0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b, +0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95, +0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00, +0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08, +0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81, +0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff, +0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe, +0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff, +0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed, +0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7, +0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01, +0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14, +0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10, +0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3, +0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf, +0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf, +0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73, +0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee, +0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0, +0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7, +0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f, +0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f, +0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0, +0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff, +0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff, +0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef, +0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff, +0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff, +0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff, +0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d, +0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8, +0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe, +0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00, +0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00, +0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd, +0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff, +0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff, +0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff, +0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54, +0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff, +0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00, +0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24, +0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24, +0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff, +0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf, +0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff, +0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb, +0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf, +0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6, +0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3, +0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe, +0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff, +0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe, +0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff, +0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b, +0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff, +0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff, +0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f, +0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9, +0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f, +0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff, +0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f, +0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff, +0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff, +0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff, +0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff, +0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff, +0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff, +0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02, +0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00, +0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf, +0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe, +0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff, +0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff, +0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd, +0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1, +0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff, +0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff, +0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, +0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc, +0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, +0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/drivers/net/hamradio/yam9600.h b/drivers/net/hamradio/yam9600.h new file mode 100644 index 000000000000..5ed1fe6ff43e --- /dev/null +++ b/drivers/net/hamradio/yam9600.h @@ -0,0 +1,343 @@ +/* + * + * File yam111.mcs converted to h format by mcs2h + * + * (C) F6FBB 1998 + * + * Tue Aug 25 20:23:03 1998 + * + */ + +static unsigned char bits_9600[]= { +0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2, +0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf, +0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, +0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff, +0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf, +0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0, +0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7, +0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff, +0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef, +0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6, +0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef, +0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef, +0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f, +0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff, +0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff, +0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f, +0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff, +0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff, +0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1, +0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f, +0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff, +0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, +0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff, +0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2, +0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00, +0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0, +0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a, +0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad, +0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff, +0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5, +0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb, +0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff, +0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe, +0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3, +0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86, +0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff, +0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9, +0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd, +0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff, +0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc, +0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33, +0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04, +0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00, +0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd, +0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb, +0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff, +0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1, +0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff, +0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22, +0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00, +0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, +0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff, +0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff, +0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f, +0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7, +0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe, +0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5, +0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69, +0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0, +0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a, +0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3, +0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f, +0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5, +0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4, +0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14, +0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, +0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff, +0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf, +0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff, +0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00, +0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00, +0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe, +0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff, +0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0, +0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7, +0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf, +0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30, +0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06, +0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20, +0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f, +0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe, +0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5, +0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1, +0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba, +0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, +0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd, +0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf, +0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff, +0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff, +0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb, +0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd, +0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff, +0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, +0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1, +0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff, +0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff, +0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79, +0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed, +0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0, +0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20, +0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f, +0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff, +0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, +0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff, +0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff, +0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe, +0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff, +0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10, +0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, +0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff, +0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf, +0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff, +0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff, +0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2, +0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f, +0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff, +0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2, +0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5, +0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff, +0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf, +0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30, +0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1, +0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0, +0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff, +0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff, +0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f, +0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff, +0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef, +0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff, +0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90, +0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01, +0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3, +0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff, +0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff, +0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0, +0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03, +0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00, +0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f, +0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc, +0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f, +0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc, +0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5, +0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff, +0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef, +0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb, +0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff, +0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff, +0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3, +0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7, +0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff, +0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, +0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb, +0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff, +0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00, +0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff, +0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1, +0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, +0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f, +0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff, +0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff, +0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00, +0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00, +0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00, +0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff, +0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79, +0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff, +0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77, +0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe, +0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf, +0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff, +0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff, +0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf, +0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff, +0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5, +0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff, +0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff, +0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef, +0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, +0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef, +0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9, +0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe, +0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00, +0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff, +0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff, +0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff, +0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, +0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11, +0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00, +0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00, +0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6, +0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff, +0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf, +0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda, +0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda, +0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6, +0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd, +0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe, +0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff, +0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff, +0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff, +0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0, +0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff, +0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f, +0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff, +0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, +0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf, +0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f, +0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff, +0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff, +0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb, +0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff, +0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff, +0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80, +0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff, +0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7, +0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf, +0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff, +0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff, +0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd, +0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef, +0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff, +0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, +0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd, +0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, +0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index fb90def137ef..228b145df8a0 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -419,7 +419,7 @@ int __init hp100_probe( struct device *dev ) continue; } /* found... */ - ioaddr = pci_dev -> base_address[ 0 ] & ~3; + ioaddr = pci_dev ->resource[ 0 ].start; if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; pci_read_config_word( pci_dev, PCI_COMMAND, &pci_command ); if ( !( pci_command & PCI_COMMAND_IO ) ) { diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c index 0986211f11d8..0121f55eef37 100644 --- a/drivers/net/irda/toshoboe.c +++ b/drivers/net/irda/toshoboe.c @@ -713,7 +713,7 @@ toshoboe_open (struct pci_dev *pci_dev) dev_self[i] = self; self->pdev = pci_dev; - self->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + self->base = pci_dev->resource[0].start; idev = &self->idev; @@ -850,7 +850,7 @@ int __init toshoboe_init (void) if (pci_dev) { printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", - pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK, + pci_dev->resource[0], pci_dev->irq); if (!toshoboe_open (pci_dev)) diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 9054744fc566..09f47960cc77 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -382,7 +382,7 @@ int lance_probe(struct device *dev) unsigned short pci_command; pci_irq_line = pdev->irq; - pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr = pdev->resource[0].start; /* PCI Spec 2.1 states that it is either the driver or PCI card's * responsibility to set the PCI Master Enable Bit if needed. * (From Mark Stockton ) diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 36a841c08d49..b20292ca86a4 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -218,7 +218,7 @@ static int __init ne_probe_pci(struct device *dev) unsigned int pci_ioaddr; while ((pdev = pci_find_device(pci_clone_list[i].vendor, pci_clone_list[i].dev_id, pdev))) { - pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr = pdev->resource[0].start; /* Avoid already found cards from previous calls */ if (check_region(pci_ioaddr, NE_IO_EXTENT)) continue; diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index cd809d56251b..00578322c602 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -208,7 +208,7 @@ int __init ne2k_pci_probe(struct device *dev) if (pci_clone_list[i].vendor == 0) continue; - pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr = pdev->resource[0].start; pci_irq_line = pdev->irq; pci_read_config_word(pdev, PCI_COMMAND, &pci_command); diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index 3aa066f1d9db..d75995a2fda3 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -111,6 +111,8 @@ init_etherdev(struct device *dev, int sizeof_priv) alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); @@ -233,6 +235,8 @@ struct device *init_hippi_dev(struct device *dev, int sizeof_priv) alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); @@ -563,6 +567,8 @@ struct device *init_trdev(struct device *dev, int sizeof_priv) alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index b5e959dddeda..f1fbdd0398cf 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -119,7 +119,7 @@ static void dump_packet(void *buf, int len); static void show_registers(struct device *dev); -__initfunc(int ni5010_probe(struct device *dev)) +int __init ni5010_probe(struct device *dev) { int *port; @@ -157,7 +157,7 @@ static inline int rd_port(int ioaddr) return inb(IE_SAPROM); } -__initfunc(void trigger_irq(int ioaddr)) +void __init trigger_irq(int ioaddr) { outb(0x00, EDLC_RESET); /* Clear EDLC hold RESET state */ outb(0x00, IE_RESET); /* Board reset */ @@ -182,7 +182,7 @@ __initfunc(void trigger_irq(int ioaddr)) * verifies that the correct device exists and functions. */ -__initfunc(static int ni5010_probe1(struct device *dev, int ioaddr)) +static int __init ni5010_probe1(struct device *dev, int ioaddr) { static unsigned version_printed = 0; int i; diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index cc7a9976e5d5..e63355d7a515 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -358,7 +358,7 @@ void alloc586(struct device *dev) /********************************************** * probe the ni5210-card */ -__initfunc(int ni52_probe(struct device *dev)) +int __init ni52_probe(struct device *dev) { #ifndef MODULE int *port; @@ -409,7 +409,7 @@ __initfunc(int ni52_probe(struct device *dev)) return ENODEV; } -__initfunc(static int ni52_probe1(struct device *dev,int ioaddr)) +static int __init ni52_probe1(struct device *dev,int ioaddr) { int i,size; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 9e22ce1a412d..a38715099c0d 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -326,7 +326,7 @@ static int ni65_close(struct device *dev) #ifdef MODULE static #endif -__initfunc(int ni65_probe(struct device *dev)) +int __init ni65_probe(struct device *dev) { int *port; static int ports[] = {0x360,0x300,0x320,0x340, 0}; @@ -348,7 +348,7 @@ __initfunc(int ni65_probe(struct device *dev)) /* * this is the real card probe .. */ -__initfunc(static int ni65_probe1(struct device *dev,int ioaddr)) +static int __init ni65_probe1(struct device *dev,int ioaddr) { int i,j; struct priv *p; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 62be203af456..2af9cbeb8046 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -461,10 +461,7 @@ int __init pcnet32_probe (struct device *dev) if (pcnet32_tbl[chip_idx].vendor_id == 0) continue; - ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; -#if defined(ADDR_64BITS) && defined(__alpha__) - ioaddr |= ((long)pdev->base_address[1]) << 32; -#endif + ioaddr = pdev->resource[0].start; irq_line = pdev->irq; /* Avoid already found cards from previous pcnet32_probe() calls */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 4bf73f81e225..77f7d0592c89 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -233,8 +233,8 @@ struct net_local { then calls us here. */ -__initfunc(int -plip_init_dev(struct device *dev, struct parport *pb)) +int __init +plip_init_dev(struct device *dev, struct parport *pb) { struct net_local *nl; struct pardevice *pardev; @@ -1223,8 +1223,8 @@ plip_searchfor(int list[], int a) return 0; } -__initfunc(int -plip_init(void)) +int __init +plip_init(void) { struct parport *pb = parport_enumerate(); int i=0; diff --git a/drivers/net/ptifddi.c b/drivers/net/ptifddi.c index 978ee37ef892..ed768da54da4 100644 --- a/drivers/net/ptifddi.c +++ b/drivers/net/ptifddi.c @@ -213,7 +213,7 @@ static inline int pti_fddi_init(struct device *dev, struct linux_sbus_device *sd pti_load_main_firmware(pp); } -__initfunc(int ptifddi_sbus_probe(struct device *dev)) +int __init ptifddi_sbus_probe(struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index da7f1667f829..ff5560c197ca 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -226,8 +226,7 @@ static int RCscan(struct device *dev) !((pdev = pci_find_slot(pci_bus, pci_device_fn)))) break; pci_irq_line = pdev->irq; - pci_ioaddr = pdev->base_address[0]; - pci_ioaddr &= PCI_BASE_ADDRESS_MEM_MASK; + pci_ioaddr = pdev->resource[0].start; #ifdef RCDEBUG printk("rc: Found RedCreek PCI adapter\n"); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 4016cf60fdd5..eaf8b66e36d4 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -72,7 +72,7 @@ extern __u32 sysctl_rmem_max; static int probed __initdata = 0; -__initfunc(int rr_hippi_probe (struct device *dev)) +int __init rr_hippi_probe (struct device *dev) { int boards_found = 0; int version_disp; /* was version info already displayed? */ @@ -502,7 +502,7 @@ static unsigned int write_eeprom(struct rr_private *rrpriv, } -__initfunc(static int rr_init(struct device *dev)) +static int __init rr_init(struct device *dev) { struct rr_private *rrpriv; struct rr_regs *regs; diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index dea2d1e9952c..73b7bf8530b3 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -353,7 +353,7 @@ int rtl8139_probe(struct device *dev) { #if defined(PCI_SUPPORT_VER2) struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0] & ~3; + ioaddr = pdev->resource[0].start; irq = pdev->irq; #else u32 pci_ioaddr; diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c index 32f22e14d9f1..f3f9e6705509 100644 --- a/drivers/net/sdla.c +++ b/drivers/net/sdla.c @@ -1624,7 +1624,7 @@ static struct net_device_stats *sdla_stats(struct device *dev) return(&flp->stats); } -__initfunc(int sdla_init(struct device *dev)) +int __init sdla_init(struct device *dev) { struct frad_local *flp; @@ -1666,7 +1666,7 @@ __initfunc(int sdla_init(struct device *dev)) return(0); } -__initfunc(void sdla_setup(void)) +void __init sdla_setup(void) { printk("%s.\n", version); register_frad(devname); diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 318f4c19a9f8..825a287d066f 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -51,14 +51,19 @@ * will render your machine defunct. Don't for now shape over * PPP or SLIP therefore! * This will be fixed in BETA4 - */ - -/* - * bh_atomic() SMP races fixes and rewritten the locking code to be SMP safe - * and irq-mask friendly. NOTE: we can't use start_bh_atomic() in kick_shaper() - * because it's going to be recalled from an irq handler, and synchronize_bh() - * is a nono if called from irq context. + * + * Update History : + * + * bh_atomic() SMP races fixes and rewritten the locking code to + * be SMP safe and irq-mask friendly. + * NOTE: we can't use start_bh_atomic() in kick_shaper() + * because it's going to be recalled from an irq handler, + * and synchronize_bh() is a nono if called from irq context. * 1999 Andrea Arcangeli + * + * Device statistics (tx_pakets, tx_bytes, + * tx_drops: queue_over_time and collisions: max_queue_exceded) + * 1999/06/18 Jordi Murgo */ #include @@ -228,18 +233,20 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) /* * Queue over time. Spill packet. */ - if(skb->shapeclock-jiffies > SHAPER_LATENCY) + if(skb->shapeclock-jiffies > SHAPER_LATENCY) { dev_kfree_skb(skb); - else + shaper->stats.tx_dropped++; + } else skb_queue_tail(&shaper->sendq, skb); } #endif - if(sh_debug) + if(sh_debug) printk("Frame queued.\n"); if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) { ptr=skb_dequeue(&shaper->sendq); - dev_kfree_skb(ptr); + dev_kfree_skb(ptr); + shaper->stats.collisions++; } shaper_unlock(shaper); return 0; @@ -262,7 +269,11 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) printk("Kick new frame to %s, %d\n", shaper->dev->name,newskb->priority); dev_queue_xmit(newskb); - if(sh_debug) + + shaper->stats.tx_bytes+=newskb->len; + shaper->stats.tx_packets++; + + if(sh_debug) printk("Kicked new frame out.\n"); dev_kfree_skb(skb); } @@ -415,7 +426,8 @@ static int shaper_start_xmit(struct sk_buff *skb, struct device *dev) static struct net_device_stats *shaper_get_stats(struct device *dev) { - return NULL; + struct shaper *sh=dev->priv; + return &sh->stats; } static int shaper_header(struct sk_buff *skb, struct device *dev, @@ -590,7 +602,7 @@ static struct shaper *shaper_alloc(struct device *dev) * Add a shaper device to the system */ -__initfunc(int shaper_probe(struct device *dev)) +int __init shaper_probe(struct device *dev) { /* * Set up the shaper. @@ -665,7 +677,9 @@ int init_module(void) void cleanup_module(void) { - /* + struct shaper *sh=dev_shape.priv; + + /* * No need to check MOD_IN_USE, as sys_delete_module() checks. * To be unloadable we must be closed and detached so we don't * need to flush things. @@ -674,10 +688,9 @@ void cleanup_module(void) unregister_netdev(&dev_shape); /* - * Free up the private structure, or leak memory :-) + * Free up the private structure, or leak memory :-) */ - - kfree(dev_shape.priv); + kfree(sh); dev_shape.priv = NULL; } diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 244df754479c..d62c75c44a6b 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -531,7 +531,7 @@ void SK_print_ram(struct device *dev); * (detachable devices only). */ -__initfunc(int SK_init(struct device *dev)) +int __init SK_init(struct device *dev) { int ioaddr = 0; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ @@ -614,7 +614,7 @@ __initfunc(int SK_init(struct device *dev)) * 94/06/30 pwe SK_ADDR now checked and at the correct place -*/ -__initfunc(int SK_probe(struct device *dev, short ioaddr)) +int __init SK_probe(struct device *dev, short ioaddr) { int i,j; /* Counters */ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ @@ -1737,7 +1737,7 @@ static void set_multicast_list(struct device *dev) * YY/MM/DD uid Description -*/ -__initfunc(unsigned int SK_rom_addr(void)) +unsigned int __init SK_rom_addr(void) { int i,j; int rom_found = 0; diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index 1ba46069128b..73b1a6bff062 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -127,8 +127,8 @@ extern void chipset_init(struct device *dev, int startp); struct netdev_entry netcard_drv = {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else -__initfunc(int -netcard_probe(struct device *dev)) +int __init +netcard_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -155,7 +155,7 @@ netcard_probe(struct device *dev)) * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -__initfunc(static int netcard_probe1(struct device *dev, int ioaddr)) +static int __init netcard_probe1(struct device *dev, int ioaddr) { static unsigned version_printed = 0; int i; diff --git a/drivers/net/sktr.c b/drivers/net/sktr.c index a5e64eae9aad..3de5624354dd 100644 --- a/drivers/net/sktr.c +++ b/drivers/net/sktr.c @@ -186,7 +186,7 @@ static void sktr_write_tpl_status(TPL *tpl, unsigned int Status); * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. */ -__initfunc(int sktr_probe(struct device *dev)) +int __init sktr_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -217,7 +217,7 @@ __initfunc(int sktr_probe(struct device *dev)) /* * Detect and setup the PCI SysKonnect TR cards in slot order. */ -__initfunc(static int sktr_pci_chk_card(struct device *dev)) +static int __init sktr_pci_chk_card(struct device *dev) { static int pci_index = 0; unsigned char pci_bus, pci_device_fn; @@ -295,7 +295,7 @@ __initfunc(static int sktr_pci_chk_card(struct device *dev)) /* * Detect and setup the ISA SysKonnect TR cards. */ -__initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr)) +static int __init sktr_isa_chk_card(struct device *dev, int ioaddr) { int i, err; unsigned long flags; @@ -386,7 +386,7 @@ __initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr)) return (0); } -__initfunc(static int sktr_probe1(struct device *dev, int ioaddr)) +static int __init sktr_probe1(struct device *dev, int ioaddr) { static unsigned version_printed = 0; struct net_local *tp; @@ -428,7 +428,7 @@ __initfunc(static int sktr_probe1(struct device *dev, int ioaddr)) } /* Dummy function */ -__initfunc(static int sktr_init_card(struct device *dev)) +static int __init sktr_init_card(struct device *dev) { if(sktr_debug > 3) printk("%s: sktr_init_card\n", dev->name); @@ -440,7 +440,7 @@ __initfunc(static int sktr_init_card(struct device *dev)) * This function tests if an adapter is really installed at the * given I/O address. Return negative if no adapter at IO addr. */ -__initfunc(static int sktr_isa_chk_ioaddr(int ioaddr)) +static int __init sktr_isa_chk_ioaddr(int ioaddr) { unsigned char old, chk1, chk2; diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 690c75e84fa9..7dc3fbf39a5d 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -752,8 +752,7 @@ void cleanup_module(void) } #else /* MODULE */ - -__initfunc(void slhc_install(void)) +void __init slhc_install(void) { } diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 7187a3d8f03e..67611cea6adf 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1318,7 +1318,7 @@ static int sl_ioctl(struct device *dev,struct ifreq *rq,int cmd) #ifdef MODULE static int slip_init_ctrl_dev(void) #else /* !MODULE */ -__initfunc(int slip_init_ctrl_dev(struct device *dummy)) +int __init slip_init_ctrl_dev(struct device *dummy) #endif /* !MODULE */ { int status; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index a588a1b9a4fb..54643ce4975c 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -66,8 +66,7 @@ static int ultramca_close_card(struct device *dev); #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ - -__initfunc(int ultramca_probe(struct device *dev)) +int __init ultramca_probe(struct device *dev) { unsigned short ioaddr; unsigned char reg4, num_pages; diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index ea3712c7e9da..d67b478d5c2c 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -106,7 +106,7 @@ struct netdev_entry ultra_drv = {"ultra", ultra_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else -__initfunc(int ultra_probe(struct device *dev)) +int __init ultra_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -128,7 +128,7 @@ __initfunc(int ultra_probe(struct device *dev)) } #endif -__initfunc(int ultra_probe1(struct device *dev, int ioaddr)) +int __init ultra_probe1(struct device *dev, int ioaddr) { int i; int checksum = 0; diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index f78f02a6e03c..3cf124ac3ab0 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -103,7 +103,7 @@ static int ultra32_close(struct device *dev); following. */ -__initfunc(int ultra32_probe(struct device *dev)) +int __init ultra32_probe(struct device *dev) { const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; int ioaddr, edge, media; @@ -126,7 +126,7 @@ __initfunc(int ultra32_probe(struct device *dev)) return ENODEV; } -__initfunc(int ultra32_probe1(struct device *dev, int ioaddr)) +int __init ultra32_probe1(struct device *dev, int ioaddr) { int i; int checksum = 0; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 7f7a99ab7e7b..08cf98c7ef2e 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -750,7 +750,7 @@ static void smc_hardware_send_packet( struct device * dev ) | --------------------------------------------------------------------------- */ -__initfunc(int smc_init(struct device *dev)) +int __init smc_init(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -795,7 +795,7 @@ __initfunc(int smc_init(struct device *dev)) . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ -__initfunc(int smc_findirq( int ioaddr )) +int __init smc_findirq( int ioaddr ) { int timeout = 20; @@ -877,7 +877,7 @@ __initfunc(int smc_findirq( int ioaddr )) .--------------------------------------------------------------------- */ -__initfunc(static int smc_probe( int ioaddr )) +static int __init smc_probe( int ioaddr ) { unsigned int bank; word revision_register; @@ -942,7 +942,7 @@ __initfunc(static int smc_probe( int ioaddr )) . o GRAB the region .----------------------------------------------------------------- */ -__initfunc(static int smc_initcard(struct device *dev, int ioaddr)) +static int __init smc_initcard(struct device *dev, int ioaddr) { int i; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index b9f773e5db09..86110af8c5ae 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1253,7 +1253,7 @@ static void bigmac_set_multicast(struct device *dev) bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE; } -__initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev)) +static int __init bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev) { static unsigned version_printed = 0; struct bigmac *bp = 0; @@ -1492,7 +1492,7 @@ fail_and_cleanup: return res; /* Return error code. */ } -__initfunc(int bigmac_probe(struct device *dev)) +int __init bigmac_probe(struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 86ce459515ce..827a716b59ae 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3324,8 +3324,8 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev) qp->happy_meals[qfe_slot] = dev; } - hpreg_base = pdev->base_address[0]; - if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { + hpreg_base = pdev->resource[0].start; + if((pdev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { printk("happymeal(PCI): Cannot find proper PCI device base address.\n"); return ENODEV; } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 4b3918353f5f..4d710fd517aa 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -965,10 +965,10 @@ static void lance_set_multicast (struct device *dev) mark_bh(NET_BH); } -__initfunc(static int +static int __init sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, struct Linux_SBus_DMA *ledma, - struct linux_sbus_device *lebuffer)) + struct linux_sbus_device *lebuffer) { static unsigned version_printed = 0; int i; @@ -1157,7 +1157,7 @@ find_ledma (struct linux_sbus_device *dev) #include /* Find all the lance cards on the system and initialize them */ -__initfunc(int sparc_lance_probe (struct device *dev)) +int __init sparc_lance_probe (struct device *dev) { static struct linux_sbus_device sdev; static int called = 0; @@ -1179,7 +1179,7 @@ __initfunc(int sparc_lance_probe (struct device *dev)) #else /* !CONFIG_SUN4 */ /* Find all the lance cards on the system and initialize them */ -__initfunc(int sparc_lance_probe (struct device *dev)) +int __init sparc_lance_probe (struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 4b126e3c6985..a326aa855f99 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1173,7 +1173,7 @@ qec_free_devs: return res; } -__initfunc(int qec_probe(struct device *dev)) +int __init qec_probe(struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index f476b62596e6..0508eec9989c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -554,7 +554,7 @@ int TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 * ); *pci_irq = pdev->irq; - *pci_io_base = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + *pci_io_base = pdev->resource[0].start; *pci_dfn = pdev->devfn; pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c index c8c3297310bf..ced27073a7c1 100644 --- a/drivers/net/tulip.c +++ b/drivers/net/tulip.c @@ -497,7 +497,7 @@ int tulip_probe(struct device *dev) continue; } #if LINUX_VERSION_CODE >= 0x20155 - pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0]; + pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start; #else pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); @@ -572,23 +572,8 @@ static struct device *tulip_probe1(int pci_bus, int pci_device_fn, dev = init_etherdev(dev, 0); -#if LINUX_VERSION_CODE >= 0x20155 irq = pci_find_slot(pci_bus, pci_device_fn)->irq; - ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0]; -#else - { - u8 pci_irq_line; - u32 pci_ioaddr; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, - &pci_ioaddr); - irq = pci_irq_line; - ioaddr = pci_ioaddr; - } -#endif - /* Remove I/O space marker in bit 0. */ - ioaddr &= ~3; + ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start; printk(KERN_INFO "%s: %s at %#3lx,", dev->name, tulip_tbl[chip_id].chip_name, ioaddr); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index be7646b6564e..d242e6bf1393 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -431,9 +431,9 @@ static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[]) #if defined(PCI_SUPPORT_VER2) struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); #ifdef VIA_USE_IO - pciaddr = pdev->base_address[0]; + pciaddr = pdev->resource[0].start; #else - pciaddr = pdev->base_address[1]; + pciaddr = pdev->resource[1].start; #endif irq = pdev->irq; #else diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 99d2318d0ce0..5bcaa0e44125 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -86,7 +86,7 @@ struct netdev_entry wd_drv = {"wd", wd_probe1, WD_IO_EXTENT, wd_portlist}; #else -__initfunc(int wd_probe(struct device *dev)) +int __init wd_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -108,7 +108,7 @@ __initfunc(int wd_probe(struct device *dev)) } #endif -__initfunc(int wd_probe1(struct device *dev, int ioaddr)) +int __init wd_probe1(struct device *dev, int ioaddr) { int i; int checksum = 0; diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c index 9f20bf6cd56d..e6e723604680 100644 --- a/drivers/net/x25_asy.c +++ b/drivers/net/x25_asy.c @@ -818,7 +818,7 @@ static int x25_asy_open_dev(struct device *dev) #ifdef MODULE static int x25_asy_init_ctrl_dev(void) #else /* !MODULE */ -__initfunc(int x25_asy_init_ctrl_dev(struct device *dummy)) +int __init x25_asy_init_ctrl_dev(struct device *dummy) #endif /* !MODULE */ { int status; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 8d5b232ecbf6..5ef28210a24b 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -377,23 +377,10 @@ int yellowfin_probe(struct device *dev) continue; { -#if LINUX_VERSION_CODE >= 0x20155 || PCI_SUPPORT_1 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0]; + ioaddr = pdev->resource[0].start; irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr; - irq = pci_irq_line; -#endif } - /* Remove I/O space marker in bit 0. */ - ioaddr &= ~3; if (yellowfin_debug > 2) printk(KERN_INFO "Found %s at I/O %#lx, IRQ %d.\n", diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 0884cb0d8440..be66a0897b5d 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -200,7 +200,7 @@ static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, }; BIOS area. We just scan for the signature, and pull the vital parameters out of the structure. */ -__initfunc(int znet_probe(struct device *dev)) +int __init znet_probe(struct device *dev) { int i; struct netidblk *netinfo; diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c index 8151f0bb3140..4d716e7fb91d 100644 --- a/drivers/parport/parport_amiga.c +++ b/drivers/parport/parport_amiga.c @@ -199,8 +199,6 @@ static struct parport_operations pp_amiga_ops = { NULL, /* data_forward */ NULL, /* data_reverse */ - amiga_interrupt, - amiga_init_state, amiga_save_state, amiga_restore_state, diff --git a/drivers/parport/parport_arc.c b/drivers/parport/parport_arc.c index 48e5c5cddfc7..69509dc63058 100644 --- a/drivers/parport/parport_arc.c +++ b/drivers/parport/parport_arc.c @@ -96,8 +96,6 @@ static struct parport_operations parport_arc_ops = arc_data_forward, arc_data_reverse, - arc_interrupt, - arc_init_state, arc_save_state, arc_restore_state, diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c index 56d31951f84c..ddfd740681ac 100644 --- a/drivers/parport/parport_atari.c +++ b/drivers/parport/parport_atari.c @@ -140,8 +140,6 @@ static struct parport_operations parport_atari_ops = { NULL, /* data_forward - FIXME */ NULL, /* data_reverse - FIXME */ - parport_atari_interrupt, - parport_atari_init_state, parport_atari_save_state, parport_atari_restore_state, diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c index 6300607c1245..351585bc8d08 100644 --- a/drivers/parport/parport_mfc3.c +++ b/drivers/parport/parport_mfc3.c @@ -290,8 +290,6 @@ static struct parport_operations pp_mfc3_ops = { NULL, /* data_forward - FIXME */ NULL, /* data_reverse - FIXME */ - mfc3_interrupt, - mfc3_init_state, mfc3_save_state, mfc3_restore_state, diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 83ba8d4f3d98..30c8a7867781 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -229,12 +229,16 @@ unsigned char parport_pc_read_data(struct parport *p) unsigned char __frob_control (struct parport *p, unsigned char mask, unsigned char val) { + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); struct parport_pc_private *priv = p->physport->private_data; unsigned char ctr = priv->ctr; ctr = (ctr & ~mask) ^ val; ctr &= priv->ctr_writable; /* only write writable bits. */ outb (ctr, CONTROL (p)); - return priv->ctr = ctr; /* update soft copy */ + return priv->ctr = ctr & wm; /* update soft copy */ } void parport_pc_write_control(struct parport *p, unsigned char d) @@ -939,7 +943,6 @@ struct parport_operations parport_pc_ops = parport_pc_data_forward, parport_pc_data_reverse, - parport_pc_interrupt, parport_pc_init_state, parport_pc_save_state, parport_pc_restore_state, @@ -1531,7 +1534,7 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, p->base_hi = base_hi; p->irq = irq; p->dma = dma; - p->modes = PARPORT_MODE_PCSPP; + p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; p->ops = ops; p->private_data = priv; p->physport = p; diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 7a098ca23f1b..e438bb3cc117 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -48,7 +48,6 @@ static unsigned char dead_read_lines (struct parport *p) { return 0; } static unsigned char dead_frob_lines (struct parport *p, unsigned char b, unsigned char c) { return 0; } static void dead_onearg (struct parport *p){} -static void dead_irq (int i, void *p, struct pt_regs *r) { } static void dead_initstate (struct pardevice *d, struct parport_state *s) { } static void dead_state (struct parport *p, struct parport_state *s) { } static void dead_noargs (void) { } @@ -67,7 +66,6 @@ static struct parport_operations dead_ops = { dead_onearg, /* disable_irq */ dead_onearg, /* data_forward */ dead_onearg, /* data_reverse */ - dead_irq, dead_initstate, /* init_state */ dead_state, dead_state, diff --git a/drivers/pci/names.c b/drivers/pci/names.c index 1a1a9aac5a81..b64d1d705a27 100644 --- a/drivers/pci/names.c +++ b/drivers/pci/names.c @@ -49,7 +49,7 @@ struct pci_vendor_info { #include "devlist.h" static const struct pci_vendor_info __initdata pci_vendor_list[] = { -#define VENDOR( vendor, name ) { PCI_VENDOR_ID_##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), name, __devices_##vendor }, +#define VENDOR( vendor, name ) { PCI_VENDOR_ID_##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor }, #define ENDVENDOR() #define DEVICE( vendor, device, name ) #include "devlist.h" @@ -97,263 +97,3 @@ void __init pci_namedevice(struct pci_dev *dev) } } } - -#ifdef CONFIG_PROC_FS - -static const char *pci_strclass (unsigned int class) -{ - switch (class >> 8) { - case PCI_CLASS_NOT_DEFINED: return "Non-VGA device"; - case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device"; - - case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller"; - case PCI_CLASS_STORAGE_IDE: return "IDE interface"; - case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; - case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; - case PCI_CLASS_STORAGE_RAID: return "RAID bus controller"; - case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller"; - - case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller"; - case PCI_CLASS_NETWORK_TOKEN_RING: return "Token ring network controller"; - case PCI_CLASS_NETWORK_FDDI: return "FDDI network controller"; - case PCI_CLASS_NETWORK_ATM: return "ATM network controller"; - case PCI_CLASS_NETWORK_OTHER: return "Network controller"; - - case PCI_CLASS_DISPLAY_VGA: return "VGA compatible controller"; - case PCI_CLASS_DISPLAY_XGA: return "XGA compatible controller"; - case PCI_CLASS_DISPLAY_OTHER: return "Display controller"; - - case PCI_CLASS_MULTIMEDIA_VIDEO: return "Multimedia video controller"; - case PCI_CLASS_MULTIMEDIA_AUDIO: return "Multimedia audio controller"; - case PCI_CLASS_MULTIMEDIA_OTHER: return "Multimedia controller"; - - case PCI_CLASS_MEMORY_RAM: return "RAM memory"; - case PCI_CLASS_MEMORY_FLASH: return "FLASH memory"; - case PCI_CLASS_MEMORY_OTHER: return "Memory"; - - case PCI_CLASS_BRIDGE_HOST: return "Host bridge"; - case PCI_CLASS_BRIDGE_ISA: return "ISA bridge"; - case PCI_CLASS_BRIDGE_EISA: return "EISA bridge"; - case PCI_CLASS_BRIDGE_MC: return "MicroChannel bridge"; - case PCI_CLASS_BRIDGE_PCI: return "PCI bridge"; - case PCI_CLASS_BRIDGE_PCMCIA: return "PCMCIA bridge"; - case PCI_CLASS_BRIDGE_NUBUS: return "NuBus bridge"; - case PCI_CLASS_BRIDGE_CARDBUS: return "CardBus bridge"; - case PCI_CLASS_BRIDGE_OTHER: return "Bridge"; - - case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial controller"; - case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel controller"; - case PCI_CLASS_COMMUNICATION_OTHER: return "Communication controller"; - - case PCI_CLASS_SYSTEM_PIC: return "PIC"; - case PCI_CLASS_SYSTEM_DMA: return "DMA controller"; - case PCI_CLASS_SYSTEM_TIMER: return "Timer"; - case PCI_CLASS_SYSTEM_RTC: return "RTC"; - case PCI_CLASS_SYSTEM_OTHER: return "System peripheral"; - - case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard controller"; - case PCI_CLASS_INPUT_PEN: return "Digitizer Pen"; - case PCI_CLASS_INPUT_MOUSE: return "Mouse controller"; - case PCI_CLASS_INPUT_OTHER: return "Input device controller"; - - case PCI_CLASS_DOCKING_GENERIC: return "Generic Docking Station"; - case PCI_CLASS_DOCKING_OTHER: return "Docking Station"; - - case PCI_CLASS_PROCESSOR_386: return "386"; - case PCI_CLASS_PROCESSOR_486: return "486"; - case PCI_CLASS_PROCESSOR_PENTIUM: return "Pentium"; - case PCI_CLASS_PROCESSOR_ALPHA: return "Alpha"; - case PCI_CLASS_PROCESSOR_POWERPC: return "Power PC"; - case PCI_CLASS_PROCESSOR_CO: return "Co-processor"; - - case PCI_CLASS_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)"; - case PCI_CLASS_SERIAL_ACCESS: return "ACCESS Bus"; - case PCI_CLASS_SERIAL_SSA: return "SSA"; - case PCI_CLASS_SERIAL_USB: return "USB Controller"; - case PCI_CLASS_SERIAL_FIBER: return "Fiber Channel"; - - case PCI_CLASS_HOT_SWAP_CONTROLLER: return "Hot Swap Controller"; - - default: return "Unknown class"; - } -} - -/* - * Convert some of the configuration space registers of the device at - * address (bus,devfn) into a string (possibly several lines each). - * The configuration string is stored starting at buf[len]. If the - * string would exceed the size of the buffer (SIZE), 0 is returned. - */ -static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) -{ - unsigned int class_rev, bus, devfn; - unsigned short vendor, device, status; - unsigned char bist, latency, min_gnt, max_lat; - int reg, len = 0; - const char *str; - - bus = dev->bus->number; - devfn = dev->devfn; - - pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); - pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); - pcibios_read_config_word (bus, devfn, PCI_STATUS, &status); - pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist); - pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency); - pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt); - pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat); - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, " %s: %s (rev %d).\n ", - pci_strclass(class_rev >> 8), - dev->name, - class_rev & 0xff); - - switch (status & PCI_STATUS_DEVSEL_MASK) { - case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break; - case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break; - case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break; - default: str = "Unknown devsel. "; - } - if (len + strlen(str) > size) { - return -1; - } - len += sprintf(buf + len, str); - - if (status & PCI_STATUS_FAST_BACK) { -# define fast_b2b_capable "Fast back-to-back capable. " - if (len + strlen(fast_b2b_capable) > size) { - return -1; - } - len += sprintf(buf + len, fast_b2b_capable); -# undef fast_b2b_capable - } - - if (bist & PCI_BIST_CAPABLE) { -# define BIST_capable "BIST capable. " - if (len + strlen(BIST_capable) > size) { - return -1; - } - len += sprintf(buf + len, BIST_capable); -# undef BIST_capable - } - - if (dev->irq) { - if (len + 40 > size) { - return -1; - } - len += sprintf(buf + len, "IRQ %d. ", dev->irq); - } - - if (dev->master) { - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, "Master Capable. "); - if (latency) - len += sprintf(buf + len, "Latency=%d. ", latency); - else - len += sprintf(buf + len, "No bursts. "); - if (min_gnt) - len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); - if (max_lat) - len += sprintf(buf + len, "Max Lat=%d.", max_lat); - } - - for (reg = 0; reg < 6; reg++) { - struct resource *res = dev->resource + reg; - unsigned long base, end, flags; - - if (len + 40 > size) { - return -1; - } - base = res->start; - end = res->end; - flags = res->flags; - if (!flags) - continue; - - if (flags & PCI_BASE_ADDRESS_SPACE_IO) { - len += sprintf(buf + len, - "\n I/O at 0x%lx [0x%lx].", - base, end); - } else { - const char *pref, *type = "unknown"; - - if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) { - pref = "P"; - } else { - pref = "Non-p"; - } - switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - type = "32 bit"; break; - case PCI_BASE_ADDRESS_MEM_TYPE_1M: - type = "20 bit"; break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - type = "64 bit"; break; - } - len += sprintf(buf + len, - "\n %srefetchable %s memory at " - "0x%lx [0x%lx].", pref, type, - base, - end); - } - } - - len += sprintf(buf + len, "\n"); - return len; -} - - -/* - * Return list of PCI devices as a character string for /proc/pci. - * BUF is a buffer that is PAGE_SIZE bytes long. - */ -int get_pci_list(char *buf) -{ - int nprinted, len, size; - struct pci_dev *dev; - static int complained = 0; -# define MSG "\nwarning: page-size limit reached!\n" - - if (!complained) { - complained++; - printk(KERN_INFO "%s uses obsolete /proc/pci interface\n", - current->comm); - } - - /* reserve same for truncation warning message: */ - size = PAGE_SIZE - (strlen(MSG) + 1); - len = sprintf(buf, "PCI devices found:\n"); - - for (dev = pci_devices; dev; dev = dev->next) { - nprinted = sprint_dev_config(dev, buf + len, size - len); - if (nprinted < 0) { - return len + sprintf(buf + len, MSG); - } - len += nprinted; - } - return len; -} - -static struct proc_dir_entry proc_old_pci = { - PROC_PCI, 3, "pci", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations -}; - -void __init proc_old_pci_init(void) -{ - proc_register(&proc_root, &proc_old_pci); -} - -#endif /* CONFIG_PROC_FS */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b66baa972d42..308f9944e767 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -451,13 +451,9 @@ void __init pci_init(void) #ifdef CONFIG_PCI_QUIRKS pci_quirks_init(); #endif - -#ifdef CONFIG_PROC_FS - pci_proc_init(); -#endif } -void __init pci_setup (char *str, int *ints) +static int __init pci_setup(char *str) { while (str) { char *k = strchr(str, ','); @@ -470,4 +466,7 @@ void __init pci_setup (char *str, int *ints) } str = k; } + return 1; } + +__setup("pci=", pci_setup); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index a4acf26ecaeb..63104929b270 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -6,12 +6,12 @@ * Copyright (c) 1997, 1998 Martin Mares */ -#include #include #include #include #include #include + #include #include @@ -322,7 +322,7 @@ int pci_proc_detach_device(struct pci_dev *dev) return 0; } -__initfunc(void proc_bus_pci_add(struct pci_bus *bus)) +void __init proc_bus_pci_add(struct pci_bus *bus) { while (bus) { struct pci_dev *dev; @@ -335,15 +335,266 @@ __initfunc(void proc_bus_pci_add(struct pci_bus *bus)) } } -__initfunc(void pci_proc_init(void)) +static const char *pci_strclass (unsigned int class) { - if (!pci_present()) - return; - proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus); - proc_register(proc_bus_pci_dir, &proc_pci_devices); - proc_bus_pci_add(&pci_root); - -#ifdef CONFIG_PCI_OLD_PROC - proc_old_pci_init(); -#endif + switch (class >> 8) { + case PCI_CLASS_NOT_DEFINED: return "Non-VGA device"; + case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device"; + + case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller"; + case PCI_CLASS_STORAGE_IDE: return "IDE interface"; + case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; + case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; + case PCI_CLASS_STORAGE_RAID: return "RAID bus controller"; + case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller"; + + case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller"; + case PCI_CLASS_NETWORK_TOKEN_RING: return "Token ring network controller"; + case PCI_CLASS_NETWORK_FDDI: return "FDDI network controller"; + case PCI_CLASS_NETWORK_ATM: return "ATM network controller"; + case PCI_CLASS_NETWORK_OTHER: return "Network controller"; + + case PCI_CLASS_DISPLAY_VGA: return "VGA compatible controller"; + case PCI_CLASS_DISPLAY_XGA: return "XGA compatible controller"; + case PCI_CLASS_DISPLAY_OTHER: return "Display controller"; + + case PCI_CLASS_MULTIMEDIA_VIDEO: return "Multimedia video controller"; + case PCI_CLASS_MULTIMEDIA_AUDIO: return "Multimedia audio controller"; + case PCI_CLASS_MULTIMEDIA_OTHER: return "Multimedia controller"; + + case PCI_CLASS_MEMORY_RAM: return "RAM memory"; + case PCI_CLASS_MEMORY_FLASH: return "FLASH memory"; + case PCI_CLASS_MEMORY_OTHER: return "Memory"; + + case PCI_CLASS_BRIDGE_HOST: return "Host bridge"; + case PCI_CLASS_BRIDGE_ISA: return "ISA bridge"; + case PCI_CLASS_BRIDGE_EISA: return "EISA bridge"; + case PCI_CLASS_BRIDGE_MC: return "MicroChannel bridge"; + case PCI_CLASS_BRIDGE_PCI: return "PCI bridge"; + case PCI_CLASS_BRIDGE_PCMCIA: return "PCMCIA bridge"; + case PCI_CLASS_BRIDGE_NUBUS: return "NuBus bridge"; + case PCI_CLASS_BRIDGE_CARDBUS: return "CardBus bridge"; + case PCI_CLASS_BRIDGE_OTHER: return "Bridge"; + + case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial controller"; + case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel controller"; + case PCI_CLASS_COMMUNICATION_OTHER: return "Communication controller"; + + case PCI_CLASS_SYSTEM_PIC: return "PIC"; + case PCI_CLASS_SYSTEM_DMA: return "DMA controller"; + case PCI_CLASS_SYSTEM_TIMER: return "Timer"; + case PCI_CLASS_SYSTEM_RTC: return "RTC"; + case PCI_CLASS_SYSTEM_OTHER: return "System peripheral"; + + case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard controller"; + case PCI_CLASS_INPUT_PEN: return "Digitizer Pen"; + case PCI_CLASS_INPUT_MOUSE: return "Mouse controller"; + case PCI_CLASS_INPUT_OTHER: return "Input device controller"; + + case PCI_CLASS_DOCKING_GENERIC: return "Generic Docking Station"; + case PCI_CLASS_DOCKING_OTHER: return "Docking Station"; + + case PCI_CLASS_PROCESSOR_386: return "386"; + case PCI_CLASS_PROCESSOR_486: return "486"; + case PCI_CLASS_PROCESSOR_PENTIUM: return "Pentium"; + case PCI_CLASS_PROCESSOR_ALPHA: return "Alpha"; + case PCI_CLASS_PROCESSOR_POWERPC: return "Power PC"; + case PCI_CLASS_PROCESSOR_CO: return "Co-processor"; + + case PCI_CLASS_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)"; + case PCI_CLASS_SERIAL_ACCESS: return "ACCESS Bus"; + case PCI_CLASS_SERIAL_SSA: return "SSA"; + case PCI_CLASS_SERIAL_USB: return "USB Controller"; + case PCI_CLASS_SERIAL_FIBER: return "Fiber Channel"; + + case PCI_CLASS_HOT_SWAP_CONTROLLER: return "Hot Swap Controller"; + + default: return "Unknown class"; + } } + +/* + * Convert some of the configuration space registers of the device at + * address (bus,devfn) into a string (possibly several lines each). + * The configuration string is stored starting at buf[len]. If the + * string would exceed the size of the buffer (SIZE), 0 is returned. + */ +static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) +{ + unsigned int class_rev, bus, devfn; + unsigned short vendor, device, status; + unsigned char bist, latency, min_gnt, max_lat; + int reg, len = 0; + const char *str; + + bus = dev->bus->number; + devfn = dev->devfn; + + pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); + pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); + pcibios_read_config_word (bus, devfn, PCI_STATUS, &status); + pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist); + pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency); + pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt); + pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat); + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, " %s: %s (rev %d).\n ", + pci_strclass(class_rev >> 8), + dev->name, + class_rev & 0xff); + + switch (status & PCI_STATUS_DEVSEL_MASK) { + case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break; + case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break; + case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break; + default: str = "Unknown devsel. "; + } + if (len + strlen(str) > size) { + return -1; + } + len += sprintf(buf + len, str); + + if (status & PCI_STATUS_FAST_BACK) { +# define fast_b2b_capable "Fast back-to-back capable. " + if (len + strlen(fast_b2b_capable) > size) { + return -1; + } + len += sprintf(buf + len, fast_b2b_capable); +# undef fast_b2b_capable + } + + if (bist & PCI_BIST_CAPABLE) { +# define BIST_capable "BIST capable. " + if (len + strlen(BIST_capable) > size) { + return -1; + } + len += sprintf(buf + len, BIST_capable); +# undef BIST_capable + } + + if (dev->irq) { + if (len + 40 > size) { + return -1; + } + len += sprintf(buf + len, "IRQ %d. ", dev->irq); + } + + if (dev->master) { + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, "Master Capable. "); + if (latency) + len += sprintf(buf + len, "Latency=%d. ", latency); + else + len += sprintf(buf + len, "No bursts. "); + if (min_gnt) + len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); + if (max_lat) + len += sprintf(buf + len, "Max Lat=%d.", max_lat); + } + + for (reg = 0; reg < 6; reg++) { + struct resource *res = dev->resource + reg; + unsigned long base, end, flags; + + if (len + 40 > size) { + return -1; + } + base = res->start; + end = res->end; + flags = res->flags; + if (!flags) + continue; + + if (flags & PCI_BASE_ADDRESS_SPACE_IO) { + len += sprintf(buf + len, + "\n I/O at 0x%lx [0x%lx].", + base, end); + } else { + const char *pref, *type = "unknown"; + + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) { + pref = "P"; + } else { + pref = "Non-p"; + } + switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + type = "32 bit"; break; + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + type = "20 bit"; break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + type = "64 bit"; break; + } + len += sprintf(buf + len, + "\n %srefetchable %s memory at " + "0x%lx [0x%lx].", pref, type, + base, + end); + } + } + + len += sprintf(buf + len, "\n"); + return len; +} + + +/* + * Return list of PCI devices as a character string for /proc/pci. + * BUF is a buffer that is PAGE_SIZE bytes long. + */ +int get_pci_list(char *buf) +{ + int nprinted, len, size; + struct pci_dev *dev; + static int complained = 0; +# define MSG "\nwarning: page-size limit reached!\n" + + if (!complained) { + complained++; + printk(KERN_INFO "%s uses obsolete /proc/pci interface\n", + current->comm); + } + + /* reserve same for truncation warning message: */ + size = PAGE_SIZE - (strlen(MSG) + 1); + len = sprintf(buf, "PCI devices found:\n"); + + for (dev = pci_devices; dev; dev = dev->next) { + nprinted = sprint_dev_config(dev, buf + len, size - len); + if (nprinted < 0) { + return len + sprintf(buf + len, MSG); + } + len += nprinted; + } + return len; +} + +static struct proc_dir_entry proc_old_pci = { + PROC_PCI, 3, "pci", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; + +static int __init pci_proc_init(void) +{ + if (pci_present()) { + proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus); + proc_register(proc_bus_pci_dir, &proc_pci_devices); + proc_bus_pci_add(&pci_root); + proc_register(&proc_root, &proc_old_pci); + } + return 0; +} + +__initcall(pci_proc_init); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3fe63303089c..0b20c0da33d1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -76,7 +76,7 @@ struct bridge_mapping_type { {0x0 ,0x0 ,0x0 }, }; -__initfunc(static void quirk_bridge(struct pci_dev *dev, int pos)) +static void __init quirk_bridge(struct pci_dev *dev, int pos) { struct bridge_mapping_type *bmap; unsigned char val; @@ -108,7 +108,7 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos)) /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ -__initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg)) +static void __init quirk_passive_release(struct pci_dev *dev, int arg) { struct pci_dev *d = NULL; unsigned char dlc; @@ -135,7 +135,7 @@ __initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg)) int isa_dma_bridge_buggy = 0; /* Exported */ -__initfunc(static void quirk_isa_dma_hangs(struct pci_dev *dev, int arg)) +static void __init quirk_isa_dma_hangs(struct pci_dev *dev, int arg) { if(!isa_dma_bridge_buggy) { @@ -204,7 +204,7 @@ static struct quirk_info quirk_list[] __initdata = { { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs, 0x00 }, }; -__initfunc(void pci_quirks_init(void)) +void __init pci_quirks_init(void) { struct pci_dev *d; int i; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index dc46aa27e9b0..d835b6cae06b 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -4370,7 +4370,7 @@ advansys_detect(Scsi_Host_Template *tpnt) ASC_DBG2(2, "advansys_detect: devfn %d, bus number %d\n", pci_devp->devfn, pci_devp->bus->number); - iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; + iop = pci_devp->resource[0].start; ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", pci_devp->vendor, pci_devp->device); @@ -4484,7 +4484,7 @@ advansys_detect(Scsi_Host_Template *tpnt) #endif /* ASC_CONFIG_PCI */ #else /* version >= v2.1.93 */ #ifdef CONFIG_PCI - pci_memory_address = pci_devp->base_address[1]; + pci_memory_address = pci_devp->resource[1].start; if ((boardp->ioremap_addr = ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index e11609336c67..1b791497bafa 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -1414,12 +1414,12 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt) DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: find_PCI, HBA at %s\n", dev->name)); pci_set_master(dev); - base = dev->base_address[0]; + base = dev->resource[0].flags; if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) { printk("eata_dma: invalid base address of device %s\n", dev->name); continue; } - base &= PCI_BASE_ADDRESS_IO_MASK; + base = dev->resource[0].start; /* EISA tag there ? */ pal1 = inb(base); pal2 = inb(base + 1); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 8c691c8ad953..4c52133f3a44 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -890,12 +890,12 @@ void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt) DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", dev->name)); pci_set_master(dev); - base = dev->base_address[0]; + base = dev->resource[0].flags; if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) { printk("eata_pio: invalid base address of device %s\n", dev->name); continue; } - base &= PCI_BASE_ADDRESS_IO_MASK; + base = dev->resource[0].start; /* EISA tag there ? */ if ((inb(base) == 0x12) && (inb(base + 1) == 0x14)) continue; /* Jep, it's forced, so move on */ diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index 0662010944ed..c83f856d20b4 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -640,12 +640,8 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); padapter = HOSTDATA(pshost); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) - padapter->basePort = pdev->base_address[1] & 0xFFFE; -#else - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); - padapter->basePort &= 0xFFFE; -#endif + padapter->basePort = pdev->resource[1].start; + DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index bcbd30913b1e..cf2f09f91f6b 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -1822,12 +1822,7 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt) padapter = HOSTDATA(pshost); memset (padapter, 0, sizeof (ADAPTER2220I)); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) - zs = pdev->base_address[1] & 0xFFFE; -#else - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zs); - zs &= 0xFFFE; -#endif + zs = pdev->resource[1].start; padapter->basePort = zs; padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor @@ -1835,12 +1830,7 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt) padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) - zs = pdev->base_address[2] & 0xFFFE; -#else - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zs); - zs &= 0xFFFE; -#endif + zs = pdev->resource[2].start; padapter->regBase = zs; padapter->regData = zs + REG_DATA; // data register I/O address padapter->regError = zs + REG_ERROR; // error register I/O address diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 8d8cb22ca67c..906d4f1969b9 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -1828,7 +1828,7 @@ static int isp2100_init(struct Scsi_Host *sh) printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id); return 1; } - io_base = pdev->base_address[0]; + io_base = pdev->resource[0].start; irq = pdev->irq; diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index 46f1f253c76f..f07f5a526064 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -1188,7 +1188,7 @@ static int isp1020_init(struct Scsi_Host *sh) printk("qlogicisp : error reading PCI configuration\n"); return 1; } - io_base = pdev->base_address[0]; + io_base = pdev->resource[0].start; irq = pdev->irq; if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 799fd7fb6997..63120824d6de 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -32,6 +32,8 @@ * Converted cli() code to spinlocks, Ingo Molnar * * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * out_of_space hacks, D. Gilbert (dpg) 990608 */ #include @@ -180,6 +182,7 @@ static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, struct Scsi_Host *shpnt, char * scsi_result); void scsi_build_commandblocks(Scsi_Device * SDpnt); +static int scsi_unregister_device(struct Scsi_Device_Template * tpnt); /* * These are the interface to the old error handling code. It should go away @@ -403,7 +406,7 @@ static void scan_scsis_done (Scsi_Cmnd * SCpnt) up(SCpnt->request.sem); } -__initfunc(void scsi_logging_setup(char *str, int *ints)) +void __init scsi_logging_setup(char *str, int *ints) { if (ints[0] != 1) { printk("scsi_logging_setup : usage scsi_logging_level=n " @@ -419,7 +422,7 @@ static int max_scsi_luns = 8; static int max_scsi_luns = 1; #endif -__initfunc(void scsi_luns_setup(char *str, int *ints)) +void __init scsi_luns_setup(char *str, int *ints) { if (ints[0] != 1) printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n"); @@ -451,16 +454,18 @@ static void scan_scsis (struct Scsi_Host *shpnt, Scsi_Device * SDtail; int sparse_lun; - SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); - memset (SCpnt, 0, sizeof (Scsi_Cmnd)); - - SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); - memset (SDpnt, 0, sizeof (Scsi_Device)); - - - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ( ( !shpnt->unchecked_isa_dma ) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + scsi_result = NULL; + SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); + if (SCpnt) { + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), + GFP_ATOMIC); + if (SDpnt) { + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ( ( !shpnt->unchecked_isa_dma ) + ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + } + } if (scsi_result == NULL) { @@ -517,15 +522,23 @@ static void scan_scsis (struct Scsi_Host *shpnt, if(SDpnt!=oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - oldSDpnt->scsi_request_fn = NULL; - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) { - (*sdtpnt->attach)(oldSDpnt); - if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);} - resize_dma_pool(); + oldSDpnt->scsi_request_fn = NULL; + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if(sdtpnt->attach) { + (*sdtpnt->attach)(oldSDpnt); + if(oldSDpnt->attached) { + scsi_build_commandblocks(oldSDpnt); + if (0 == oldSDpnt->has_cmdblocks) { + printk("scan_scsis: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } + } + } + resize_dma_pool(); for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) @@ -886,8 +899,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, return 0; } - memset (SDpnt, 0, sizeof (Scsi_Device)); - /* * And hook up our command block to the new device we will be testing * for. @@ -1903,9 +1914,9 @@ void * scsi_init_malloc(unsigned int size, int gfp_mask) for (order = 0, a_size = PAGE_SIZE; a_size < size; order++, a_size <<= 1) ; - retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); + retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); } else - retval = kmalloc(size, gfp_mask); + retval = kmalloc(size, gfp_mask); if (retval) memset(retval, 0, size); @@ -1974,9 +1985,10 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n", SDpnt->queue_depth, j); SDpnt->queue_depth = j; - /* Still problem if 0==j , continue anyway ... */ + SDpnt->has_cmdblocks = (0 != j); } - SDpnt->has_cmdblocks = 1; + else + SDpnt->has_cmdblocks = 1; } #ifndef MODULE /* { */ @@ -1985,7 +1997,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) * initialization, bus scanning, and sd/st initialization routines. * This is only used at boot time. */ -__initfunc(int scsi_dev_init(void)) +int __init scsi_dev_init(void) { Scsi_Device * SDpnt; struct Scsi_Host * shpnt; @@ -2040,7 +2052,13 @@ __initfunc(int scsi_dev_init(void)) /* SDpnt->scsi_request_fn = NULL; */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) { + printk("scsi_dev_init: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } } } @@ -2433,7 +2451,7 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, */ static void resize_dma_pool(void) { - int i; + int i, k; unsigned long size; struct Scsi_Host * shpnt; struct Scsi_Host * host = NULL; @@ -2442,6 +2460,7 @@ static void resize_dma_pool(void) unsigned int new_dma_sectors = 0; unsigned int new_need_isa_buffer = 0; unsigned char ** new_dma_malloc_pages = NULL; + int out_of_space = 0; if( !scsi_hostlist ) { @@ -2533,27 +2552,67 @@ static void resize_dma_pool(void) * race conditions that I would rather not even think * about right now. */ - if( new_dma_sectors < dma_sectors ) +#if 0 /* Why do this? No gain and risks out_of_space */ + if( new_dma_sectors < dma_sectors ) new_dma_sectors = dma_sectors; +#endif + if( new_dma_sectors <= dma_sectors ) + return; /* best to quit while we are in front */ + + for (k = 0; k < 20; ++k) { /* just in case */ + out_of_space = 0; + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + new_dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (new_dma_malloc_freelist) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(*new_dma_malloc_pages); + new_dma_malloc_pages = (unsigned char **) + scsi_init_malloc(size, GFP_ATOMIC); + if (! new_dma_malloc_pages) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + scsi_init_free((char *)new_dma_malloc_freelist, size); + out_of_space = 1; + } + } + else + out_of_space = 1; + + if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { + for(i = dma_sectors / SECTORS_PER_PAGE; + i < new_dma_sectors / SECTORS_PER_PAGE; i++) { + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (! new_dma_malloc_pages[i]) + break; + } + if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */ + int k = i; - if (new_dma_sectors) - { - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - new_dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_freelist, 0, size); - - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(*new_dma_malloc_pages); - new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_pages, 0, size); - } - - /* - * If we need more buffers, expand the list. - */ - if( new_dma_sectors > dma_sectors ) { - for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++) - new_dma_malloc_pages[i] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + out_of_space = 1; + for (i = 0; i < k; ++i) + scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE); + } + } + if (out_of_space) { /* try scaling down new_dma_sectors request */ + printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, " + "wanted=%u, scaling\n", dma_sectors, new_dma_sectors); + if (new_dma_sectors < (8 * SECTORS_PER_PAGE)) + break; /* pretty well hopeless ... */ + new_dma_sectors = (new_dma_sectors * 3) / 4; + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + if (new_dma_sectors <= dma_sectors) + break; /* stick with what we have got */ + } + else + break; /* found space ... */ + } /* end of for loop */ + if (out_of_space) { + scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */ + printk(" WARNING, not enough memory, pool not expanded\n"); + return; } /* When we dick with the actual DMA list, we need to @@ -2600,6 +2659,7 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) struct Scsi_Device_Template * sdtpnt; const char * name; unsigned long flags; + int out_of_space = 0; if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or * no detect routine available @@ -2699,11 +2759,11 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) { if(shpnt->hostt == tpnt) { - scan_scsis(shpnt,0,0,0,0); - if (shpnt->select_queue_depths != NULL) - { - (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); - } + scan_scsis(shpnt,0,0,0,0); + if (shpnt->select_queue_depths != NULL) + { + (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + } } } @@ -2722,14 +2782,19 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) { for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } } } /* * Now that we have all of the devices, resize the DMA pool, * as required. */ - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); /* This does any final handling that is required. */ @@ -2750,7 +2815,13 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) #endif MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_host(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } /* @@ -3011,6 +3082,7 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) { Scsi_Device * SDpnt; struct Scsi_Host * shpnt; + int out_of_space = 0; if (tpnt->next) return 1; @@ -3052,6 +3124,8 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) { SDpnt->online = TRUE; scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; } } } @@ -3060,9 +3134,16 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) * This does any final handling that is required. */ if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)(); - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_device(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) @@ -3298,6 +3379,7 @@ scsi_dump_status(int level) int init_module(void) { unsigned long size; + int has_space = 0; /* * This makes /proc/scsi visible. @@ -3313,7 +3395,6 @@ int init_module(void) proc_scsi_register(0, &proc_scsi_scsi); #endif - dma_sectors = PAGE_SIZE / SECTOR_SIZE; scsi_dma_free_sectors= dma_sectors; /* @@ -3322,15 +3403,31 @@ int init_module(void) */ /* One bit per sector to indicate free/busy */ - size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(dma_malloc_freelist, 0, size); - - /* One pointer per page for the page list */ - dma_malloc_pages = (unsigned char **) - scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC); - dma_malloc_pages[0] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); + dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (dma_malloc_freelist) { + /* One pointer per page for the page list */ + dma_malloc_pages = (unsigned char **)scsi_init_malloc( + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages), + GFP_ATOMIC); + if (dma_malloc_pages) { + dma_malloc_pages[0] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (dma_malloc_pages[0]) + has_space = 1; + } + } + if (! has_space) { + if (dma_malloc_freelist) { + scsi_init_free((char *)dma_malloc_freelist, size); + if (dma_malloc_pages) + scsi_init_free((char *)dma_malloc_pages, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + } + printk("scsi::init_module: failed, out of memory\n"); + return 1; + } /* * This is where the processing takes place for most everything diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b15966334e63..72a9dfc7c89b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -34,6 +34,7 @@ #include #include #include +#include #define MAJOR_NR SCSI_CDROM_MAJOR #include @@ -70,6 +71,7 @@ void get_capabilities(int); void requeue_sr_request (Scsi_Cmnd * SCpnt); static int sr_media_change(struct cdrom_device_info*, int); +static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); static void sr_release(struct cdrom_device_info *cdi) { @@ -99,8 +101,10 @@ static struct cdrom_device_ops sr_dops = { sr_dev_ioctl, /* device-specific ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | - CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, - 0 + CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | + CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET, + 0, + sr_packet }; /* @@ -988,27 +992,86 @@ void get_capabilities(int i){ scsi_CDs[i].cdi.speed = 1; /* disable speed select, drive probably can't do this either */ scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; - } else { - n = buffer[3]+4; - scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176; - scsi_CDs[i].readcd_known = 1; - scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01; - /* print some capability bits */ - printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i, - ((buffer[n+14] << 8) + buffer[n+15])/176, - scsi_CDs[i].cdi.speed, - buffer[n+3]&0x01 ? "writer " : "", /* CD Writer */ - buffer[n+2]&0x02 ? "cd/rw " : "", /* can read rewriteable */ - buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */ - buffer[n+5]&0x01 ? "cdda " : "", /* can read audio data */ - loadmech[buffer[n+6]>>5]); - if ((buffer[n+6] >> 5) == 0) - /* caddy drives can't close tray... */ - scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; + scsi_free(buffer, 512); + return; } + + n = buffer[3]+4; + scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176; + scsi_CDs[i].readcd_known = 1; + scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01; + /* print some capability bits */ + printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i, + ((buffer[n+14] << 8) + buffer[n+15])/176, + scsi_CDs[i].cdi.speed, + buffer[n+3]&0x01 ? "writer " : "", /* CD Writer */ + buffer[n+2]&0x02 ? "cd/rw " : "", /* can read rewriteable */ + buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */ + buffer[n+5]&0x01 ? "cdda " : "", /* can read audio data */ + loadmech[buffer[n+6]>>5]); + if ((buffer[n+6] >> 5) == 0) + /* caddy drives can't close tray... */ + scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; + if ((buffer[n+2] & 0x8) == 0) + /* not a DVD drive */ + scsi_CDs[i].cdi.mask |= CDC_DVD; + if ((buffer[n+3] & 0x20) == 0) + /* can't write DVD-RAM media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; + if ((buffer[n+3] & 0x10) == 0) + /* can't write DVD-R media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_R; + if ((buffer[n+3] & 0x2) == 0) + /* can't write CD-RW media */ + scsi_CDs[i].cdi.mask |= CDC_CD_RW; + if ((buffer[n+3] & 0x1) == 0) + /* can't write CD-R media */ + scsi_CDs[i].cdi.mask |= CDC_CD_R; + scsi_free(buffer, 512); } +/* + * sr_packet() is the entry point for the generic commands generated + * by the Uniform CD-ROM layer. +*/ +static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) +{ + Scsi_Cmnd *SCpnt; + Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; + DECLARE_MUTEX_LOCKED(sem); + unsigned long flags; + int stat; + + /* get the device */ + SCpnt = scsi_allocate_device(NULL, device, 1); + if (SCpnt == NULL) + return -ENODEV; /* this just doesn't seem right /axboe */ + + /* set the LUN */ + cgc->cmd[1] |= device->lun << 5; + + /* do the locking and issue the command */ + SCpnt->request.rq_dev = cdi->dev; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->cmd_len = 0; + SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); + scsi_do_cmd (SCpnt, (void *)cgc->cmd, (void *)cgc->buffer, cgc->buflen, + sr_init_done, SR_TIMEOUT, MAX_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + + stat = SCpnt->result; + + /* release */ + SCpnt->request.rq_dev = MKDEV(0,0); + scsi_release_command(SCpnt); + SCpnt = NULL; + + return stat; +} + static int sr_registered = 0; static int sr_init() diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 59d4b53cf661..32f3b49fb357 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -240,9 +240,8 @@ int sr_get_last_session(struct cdrom_device_info *cdi, int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn) { u_char sr_cmd[10]; - char * buffer; + char buffer[32]; int result; - unsigned long flags; sr_cmd[0] = SCMD_READ_SUBCHANNEL; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); @@ -254,20 +253,11 @@ int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn) sr_cmd[8] = 24; sr_cmd[9] = 0; - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char*) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0); memcpy (mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - return result; } @@ -395,8 +385,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) case CDROMREADTOCHDR: { struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; - char * buffer; - unsigned long flags; + char buffer[32]; sr_cmd[0] = SCMD_READ_TOC; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); @@ -406,27 +395,18 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); break; } case CDROMREADTOCENTRY: { struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; - unsigned char * buffer; - unsigned long flags; + unsigned char buffer[32]; sr_cmd[0] = SCMD_READ_TOC; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | @@ -437,11 +417,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0); tocentry->cdte_ctrl = buffer[5] & 0xf; @@ -455,151 +430,13 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - case CDROMSTOP: - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMSTART: - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 1; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMVOLCTRL: - { - char * buffer, * mask; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - unsigned long flags; - - /* First we get the current params so we can just twiddle the volume */ - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - - if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) { - printk ("Hosed while obtaining audio mode page\n"); - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - spin_lock_irqsave(&io_request_lock, flags); - mask = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!mask) { - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - result = -ENOMEM; - break; - }; - - if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) { - printk ("Hosed while obtaining mask for audio mode page\n"); - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - scsi_free(mask, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - /* Now mask and substitute our own volume and reuse the rest */ - buffer[0] = 0; /* Clear reserved field */ - - buffer[21] = volctrl->channel0 & mask[21]; - buffer[23] = volctrl->channel1 & mask[23]; - buffer[25] = volctrl->channel2 & mask[25]; - buffer[27] = volctrl->channel3 & mask[27]; - - sr_cmd[0] = MODE_SELECT; - sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */ - sr_cmd[2] = sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0); - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - scsi_free(mask, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - case CDROMVOLREAD: - { - char * buffer; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - unsigned long flags; - - /* Get the current params */ - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - - if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) { - printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n"); - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); - break; - } - - volctrl->channel0 = buffer[21]; - volctrl->channel1 = buffer[23]; - volctrl->channel2 = buffer[25]; - volctrl->channel3 = buffer[27]; - - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); break; } case CDROMSUBCHNL: { struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; - char * buffer; - unsigned long flags; + char buffer[32]; sr_cmd[0] = SCMD_READ_SUBCHANNEL; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ @@ -611,11 +448,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) sr_cmd[8] = 16; sr_cmd[9] = 0; - spin_lock_irqsave(&io_request_lock, flags); - buffer = (unsigned char *) scsi_malloc(512); - spin_unlock_irqrestore(&io_request_lock, flags); - if(!buffer) return -ENOMEM; - result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0); subchnl->cdsc_audiostatus = buffer[1]; @@ -631,9 +463,6 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) subchnl->cdsc_absaddr.msf.second = buffer[10]; subchnl->cdsc_absaddr.msf.frame = buffer[11]; - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(buffer, 512); - spin_unlock_irqrestore(&io_request_lock, flags); break; } default: diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 7338feeecf73..6bdfc0a023a7 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1561,19 +1561,16 @@ int wd7000_detect (Scsi_Host_Template *tpnt) break; if (i == pass) { -#if (LINUX_VERSION_CODE < 0x020100) -#else void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs, signatures[sig_ptr].len); -#endif - short bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig, + short bios_match=0; + + if(biosaddr) + bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len); -#if (LINUX_VERSION_CODE < 0x020100) -#else iounmap (biosaddr); -#endif if (! bios_match) goto bios_matched; diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index d85429745d76..4e8d7262596a 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -2232,7 +2232,7 @@ __initfunc(int init_cmpci(void)) init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); s->magic = CM_MAGIC; - s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + s->iobase = pcidev->resource[0].start; #ifdef CONFIG_SOUND_CMPCI_FM s->iosynth = 0x388; #endif diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 2012cf7a6b33..207c5424c830 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -2334,8 +2334,8 @@ int __init init_module(void) printk(KERN_INFO "es1370: version v0.26 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { - if (pcidev->base_address[0] == 0 || - (pcidev->base_address[0] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pcidev->resource[0].flags == 0 || + (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; if (pcidev->irq == 0) continue; @@ -2352,7 +2352,7 @@ int __init init_module(void) init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); s->magic = ES1370_MAGIC; - s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + s->io = pcidev->resource[0].start; s->irq = pcidev->irq; if (check_region(s->io, ES1370_EXTENT)) { printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index ec3abf274a0b..4e0f8c04e767 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -2735,8 +2735,8 @@ int __init init_module(void) printk(KERN_INFO "es1371: version v0.14 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { - if (pcidev->base_address[0] == 0 || - (pcidev->base_address[0] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pcidev->resource[0].flags == 0 || + (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; if (pcidev->irq == 0) continue; @@ -2753,7 +2753,7 @@ int __init init_module(void) init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); s->magic = ES1371_MAGIC; - s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + s->io = pcidev->resource[0].start; s->irq = pcidev->irq; if (check_region(s->io, ES1371_EXTENT)) { printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); diff --git a/drivers/sound/lowlevel/awe_compat-fbsd.h b/drivers/sound/lowlevel/awe_compat-fbsd.h index 9b00cc6f9612..cbb01dc5c56c 100644 --- a/drivers/sound/lowlevel/awe_compat-fbsd.h +++ b/drivers/sound/lowlevel/awe_compat-fbsd.h @@ -51,6 +51,7 @@ #ifdef AWE_OBSOLETE_VOXWARE +#include #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) #define CONFIG_AWE32_SYNTH #endif diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index c04a2c9a4ad6..ff3a859ee063 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -2333,14 +2333,14 @@ int __init init_module(void) #endif while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) { - if (pcidev->base_address[1] == 0 || - (pcidev->base_address[1] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pcidev->resource[1].flags == 0 || + (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; - if (pcidev->base_address[2] == 0 || - (pcidev->base_address[2] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pcidev->resource[2].flags == 0 || + (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; - if (pcidev->base_address[3] == 0 || - (pcidev->base_address[3] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pcidev->resource[3].flags == 0 || + (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; if (pcidev->irq == 0) continue; @@ -2356,11 +2356,11 @@ int __init init_module(void) init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); s->magic = SV_MAGIC; - s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - s->iosynth = pcidev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; - s->iomidi = pcidev->base_address[3] & PCI_BASE_ADDRESS_IO_MASK; - s->iogame = pcidev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + s->iosb = pcidev->resource[0].start; + s->ioenh = pcidev->resource[1].start; + s->iosynth = pcidev->resource[2].start; + s->iomidi = pcidev->resource[3].start; + s->iogame = pcidev->resource[4].start; pci_read_config_dword(pcidev, 0x40, &s->iodmaa); pci_read_config_dword(pcidev, 0x48, &s->iodmac); dmaio &= ~(SV_EXTENT_DMA-1); diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c index b839ba884138..2c45778aa642 100644 --- a/drivers/usb/ohci-hcd.c +++ b/drivers/usb/ohci-hcd.c @@ -1449,14 +1449,14 @@ static int found_ohci(int irq, void* mem_base) static int start_ohci(struct pci_dev *dev) { - unsigned int mem_base = dev->base_address[0]; + unsigned int mem_base = dev->resource[0].flags; /* If its OHCI, its memory */ if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV; /* Get the memory address and map it for IO */ - mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + mem_base = dev->resource[0].start; /* * FIXME ioremap_nocache isn't implemented on all CPUs (such diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c index 65798e6d21de..9e5b966094f5 100644 --- a/drivers/usb/ohci.c +++ b/drivers/usb/ohci.c @@ -2607,14 +2607,14 @@ static int found_ohci(int irq, void* mem_base) */ static int init_ohci(struct pci_dev *dev) { - unsigned long mem_base = dev->base_address[0]; + unsigned long mem_base = dev->resource[0].flags; /* If its OHCI, its memory */ if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV; /* Get the memory address and map it for IO */ - mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + mem_base = dev->resource[0].start; /* no interrupt won't work... */ if (dev->irq == 0) { diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index cb53710d121e..e4f493b4784f 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -1847,18 +1847,11 @@ static int start_uhci(struct pci_dev *dev) /* Search for the IO base address.. */ for (i = 0; i < 6; i++) { - unsigned int io_addr = dev->base_address[i]; + unsigned int io_addr = dev->resource[i].start; /* IO address? */ - if (!(io_addr & 1)) + if (!(dev->resource[i].flags & 1)) continue; - - io_addr &= PCI_BASE_ADDRESS_IO_MASK; - - /* Is it already in use? */ - if (check_region(io_addr, 32)) - break; - return found_uhci(dev->irq, io_addr); } return -1; diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 522b790edc59..f0f2e7a1ed17 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -72,8 +72,8 @@ #ifdef __sparc__ #include #include -#include #endif +#include #include