From ac5579c68db87bc21630676c167ee8224267f32c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:25:57 -0500 Subject: [PATCH] Import 2.3.10pre1 --- Documentation/Changes | 6 - Documentation/Configure.help | 193 +++-- Documentation/SMP.txt | 2 +- Documentation/fb/tgafb.txt | 51 ++ Documentation/java.txt | 329 +++++++- Documentation/oops-tracing.txt | 20 +- Documentation/parport.txt | 119 ++- Makefile | 6 +- README | 8 +- arch/alpha/config.in | 8 +- arch/alpha/kernel/smp.c | 2 +- arch/i386/config.in | 8 +- arch/i386/defconfig | 7 +- arch/i386/kernel/irq.h | 2 +- arch/i386/kernel/process.c | 1 - arch/i386/kernel/ptrace.c | 47 +- arch/i386/kernel/smp.c | 2 +- arch/i386/mm/fault.c | 4 +- arch/mips/sgi/kernel/indy_sc.c | 1 - arch/ppc/config.in | 8 +- arch/ppc/kernel/process.c | 1 - arch/ppc/kernel/smp.c | 2 +- arch/sparc/kernel/sun4d_smp.c | 2 +- arch/sparc/kernel/sun4m_smp.c | 2 +- arch/sparc64/config.in | 16 +- arch/sparc64/kernel/binfmt_aout32.c | 5 +- arch/sparc64/kernel/smp.c | 2 +- drivers/block/Config.in | 74 +- drivers/block/Makefile | 4 +- drivers/block/alim15x3.c | 71 +- drivers/block/cmd646.c | 4 + drivers/block/{hpt343.c => hpt34x.c} | 70 +- drivers/block/icside.c | 4 + drivers/block/ide-dma.c | 26 +- drivers/block/ide-pci.c | 36 +- drivers/block/ide.c | 22 + drivers/block/pdc202xx.c | 18 +- drivers/block/piix.c | 30 +- drivers/char/Config.in | 2 +- drivers/char/c-qcam.c | 59 +- drivers/char/cyclades.c | 2 - drivers/char/esp.c | 1 - drivers/char/i2c-parport.c | 2 - drivers/char/joystick/joy-db9.c | 2 +- drivers/char/lp.c | 857 ++++++++----------- drivers/char/rocket.c | 1 - drivers/char/serial.c | 1 - drivers/macintosh/macserial.c | 1 - drivers/misc/Config.in | 37 + drivers/misc/Makefile | 13 +- drivers/misc/parport_arc.c | 56 +- drivers/misc/parport_atari.c | 3 - drivers/misc/parport_ax.c | 135 ++- drivers/misc/parport_daisy.c | 474 +++++++++++ drivers/misc/parport_ieee1284.c | 596 +++++++++++-- drivers/misc/parport_ieee1284_ops.c | 736 +++++++++++++++++ drivers/misc/parport_init.c | 40 +- drivers/misc/parport_pc.c | 1516 ++++++++++++++++++++++++++-------- drivers/misc/parport_probe.c | 212 +++++ drivers/misc/parport_procfs.c | 20 +- drivers/misc/parport_share.c | 167 ++-- drivers/pnp/Config.in | 13 - drivers/pnp/Makefile | 12 - drivers/pnp/parport_probe.c | 288 ------- drivers/sbus/char/sab82532.c | 1 - drivers/sbus/char/su.c | 1 - drivers/scsi/ppa.c | 6 +- drivers/sgi/char/graphics.c | 3 +- drivers/sgi/char/shmiq.c | 3 +- drivers/usb/CREDITS | 2 +- drivers/video/Makefile | 2 + drivers/video/fbmem.c | 3 +- drivers/video/tgafb.c | 1296 ++++++++++++++++------------- drivers/video/tgafb.h | 190 +++++ fs/binfmt_aout.c | 3 +- fs/buffer.c | 4 +- fs/ext2/ioctl.c | 38 +- fs/fat/mmap.c | 3 +- fs/locks.c | 62 +- fs/ncpfs/mmap.c | 3 +- fs/proc/array.c | 12 +- fs/proc/mem.c | 4 +- fs/ufs/super.c | 3 +- include/asm-sparc/page.h | 1 - include/linux/fs.h | 33 +- include/linux/ide.h | 1 + include/linux/isdn.h | 3 - include/linux/lp.h | 19 +- include/linux/mm.h | 5 +- include/linux/parport.h | 390 +++++---- include/linux/parport_pc.h | 301 ++++--- include/linux/sched.h | 13 +- include/linux/swap.h | 3 - ipc/shm.c | 11 +- kernel/exit.c | 3 +- kernel/fork.c | 8 +- kernel/sched.c | 4 +- kernel/sys.c | 20 +- mm/filemap.c | 22 +- mm/memory.c | 227 +++-- mm/mmap.c | 4 +- mm/page_alloc.c | 87 -- mm/vmscan.c | 21 +- net/appletalk/ddp.c | 2 + net/socket.c | 2 +- net/sunrpc/xprt.c | 39 +- scripts/ksymoops/Makefile | 79 -- scripts/ksymoops/README | 406 +-------- scripts/ksymoops/io.c | 139 ---- scripts/ksymoops/ksymoops.c | 678 --------------- scripts/ksymoops/ksymoops.h | 146 ---- scripts/ksymoops/ksyms.c | 294 ------- scripts/ksymoops/map.c | 251 ------ scripts/ksymoops/misc.c | 108 --- scripts/ksymoops/object.c | 230 ------ scripts/ksymoops/oops.c | 1377 ------------------------------ scripts/ksymoops/re.c | 145 ---- scripts/ksymoops/symbol.c | 444 ---------- 118 files changed, 6227 insertions(+), 7387 deletions(-) create mode 100644 Documentation/fb/tgafb.txt rename drivers/block/{hpt343.c => hpt34x.c} (85%) create mode 100644 drivers/misc/Config.in create mode 100644 drivers/misc/parport_daisy.c rewrite drivers/misc/parport_ieee1284.c (60%) create mode 100644 drivers/misc/parport_ieee1284_ops.c create mode 100644 drivers/misc/parport_probe.c delete mode 100644 drivers/pnp/parport_probe.c create mode 100644 drivers/video/tgafb.h rewrite include/linux/parport_pc.h (72%) delete mode 100644 scripts/ksymoops/Makefile rewrite scripts/ksymoops/README (99%) delete mode 100644 scripts/ksymoops/io.c delete mode 100644 scripts/ksymoops/ksymoops.c delete mode 100644 scripts/ksymoops/ksymoops.h delete mode 100644 scripts/ksymoops/ksyms.c delete mode 100644 scripts/ksymoops/map.c delete mode 100644 scripts/ksymoops/misc.c delete mode 100644 scripts/ksymoops/object.c delete mode 100644 scripts/ksymoops/oops.c delete mode 100644 scripts/ksymoops/re.c delete mode 100644 scripts/ksymoops/symbol.c diff --git a/Documentation/Changes b/Documentation/Changes index 633479eb9..ce50723e9 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -191,12 +191,6 @@ Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.7 or later. Glibc2 users should especially try to use the 2.9.1.0.x releases, as they resolve known issues with glibc2 and binutils-2.8.x releases. - libbfd, libiberty, and /usr/include/bfd.h, which are part of recent -binutils packages, are also required to compile ksymoops. Depending -upon your distribution, this may require you to install both binutils -and binutils-development packages (Debian puts bfd.h in binutils-dev, -for example). - Gnu C ===== diff --git a/Documentation/Configure.help b/Documentation/Configure.help index da39d21ef..ace1522fe 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -530,7 +530,7 @@ CONFIG_BLK_DEV_IDEPCI People with SCSI-only systems should say N here; if unsure say Y. Generic PCI bus-master DMA support -CONFIG_BLK_DEV_IDEDMA +CONFIG_BLK_DEV_IDEDMA_PCI If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and is capable of bus-master DMA operation (most Pentium PCI systems), you will want to say Y here to reduce CPU overhead. You can then use @@ -546,6 +546,26 @@ CONFIG_BLK_DEV_IDEDMA It is safe to say Y to this question. +Good-Bad DMA Model-Firmware (EXPERIMENTAL) +IDEDMA_NEW_DRIVE_LISTINGS + This test compares both the model and firmware revision for buggy drives + that claim to (U)DMA capable. This is a blanket on/off test with no speed + limit options. Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe; + whereas, many versions of EGCS have a problem and miscompile. + + 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 @@ -562,13 +582,16 @@ CONFIG_BLK_DEV_OFFBOARD improve the usability of some boot managers such as LILO when booting from a drive on an off-board controller. + Requires that all onboard ide controllers be disabled or calling + "pci=reverse" to invert the device scan order. + Note that, if you say Y here, the order of the hd* devices will be rearranged which may require modification of fstab and other files. If in doubt, say N. Use DMA by default when available -CONFIG_IDEDMA_AUTO +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, @@ -664,7 +687,7 @@ CONFIG_BLK_DEV_CY82C693 This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/cy82c693.c @@ -679,7 +702,7 @@ CONFIG_BLK_DEV_VIA82C586 (while running a "cat") provided you enabled "proc" support and set DISPLAY_APOLLO_TIMINGS in via82c586.c - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. If unsure, say N. @@ -693,14 +716,15 @@ CONFIG_BLK_DEV_ALI15X3 onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/alim15x3.c If unsure, say N. -PROMISE PDC20246 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC20246 +PROMISE PDC20246/PDC20262 support +CONFIG_BLK_DEV_PDC202XX + Promise Ultra33 or PDC20246. This driver adds up to 4 more eide devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. Since multiple cards can be installed and there are BIOS ROM problems @@ -708,38 +732,49 @@ CONFIG_BLK_DEV_PDC20246 do not match. Should you be unable to make new BIOS chips with a burner, the driver attempts to dynamic tuning of the chipset at boot-time for max-speed. Ultra33 BIOS 1.25 or new required for more than one card. + This card may require "PDC202XX Special UDMA Feature (EXPERIMENTAL)". - This requires CONFIG_IDEDMA_AUTO to be enabled. - - Please read the comments at the top of drivers/block/pdc202xx.c - - If unsure, say N. - -PROMISE PDC20262 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC20262 + Promise Ultra66 or PDC20262. This driver adds up to 4 more eide devices sharing a single interrupt. This add-on card is a bootable PCI UDMA ATA-66 controller. The driver attempts to dynamic tuning of the chipset at boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS 1.11 or newer required. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +Special UDMA Feature (EXPERIMENTAL) +PDC202XX_FORCE_BURST_BIT + For PDC20246 and PDC20262 Ultra DMA chipsets. + Designed originally for PDC20246/Ultra33 that has BIOS setup failures + when using 3 or more cards. Please read the comments at the top of drivers/block/pdc202xx.c If unsure, say N. +Special Mode Feature (DANGEROUS) +PDC202XX_FORCE_MASTER_MODE + For PDC20246 and PDC20262 Ultra DMA chipsets. + This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. + + 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. - This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless. + This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless. Please read the comments at the top of drivers/block/aec6210.c -Intel PIIXn chipsets support (EXPERIMENTAL) +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 @@ -750,15 +785,31 @@ CONFIG_BLK_DEV_PIIX If unsure, say N. -HPT343 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_HPT343 +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. + +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 - PCI UDMA controller. 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. + 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. - This requires CONFIG_IDEDMA_AUTO to be enabled. + Please read the comments at the top of drivers/block/hpt343.c + +HPT34X DMA support (DANGEROUS) +CONFIG_BLK_DEV_HPT34X_DMA + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/hpt343.c @@ -821,17 +872,17 @@ 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 +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 +PowerMac IDE DMA support +CONFIG_BLK_DEV_IDEDMA_PMAC + No help for CONFIG_BLK_DEV_IDEDMA_PMAC - Use DMA by default - CONFIG_PMAC_IDEDMA_AUTO - No help for CONFIG_PMAC_IDEDMA_AUTO +Use DMA by default +CONFIG_IDEDMA_PMAC_AUTO + No help for CONFIG_IDEDMA_PMAC_AUTO Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -843,9 +894,21 @@ CONFIG_BLK_DEV_MAC_IDE (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. - RapIDE interface support - CONFIG_BLK_DEV_IDE_RAPIDE - No help for CONFIG_BLK_DEV_IDE_RAPIDE +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 XT hard disk support CONFIG_BLK_DEV_XD @@ -2218,12 +2281,12 @@ CONFIG_PARPORT whenever you want), say M here and read Documentation/modules.txt. The module will be called parport.o. If you have more than one parallel port and want to specify which port and IRQ to be used by - this driver at module load time, read - Documentation/networking/net-modules.txt. + this driver at module load time, take a look at + Documentation/networking/parport.txt. If unsure, say Y. -PC-style hardware +PC-style hardware CONFIG_PARPORT_PC You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style parallel @@ -2236,28 +2299,36 @@ CONFIG_PARPORT_PC If unsure, say Y. +Use FIFO/DMA if available +CONFIG_PARPORT_PC_FIFO + Many parallel port chipsets provide hardware that can speed up + printing. Say Y here if you want to take advantage of that. + + As well as actually having a FIFO, or DMA capability, the kernel + will need to know which IRQ the parallel port has. By default, + parallel port interrupts will not be used, and so neither will the + FIFO. See Documentation/parport.txt to find out how to specify + which IRQ/DMA to use. + Support foreign hardware CONFIG_PARPORT_OTHER Say Y here if you want to be able to load driver modules to support other non-standard types of parallel ports. This causes a performance loss, so most people say N. -Sun Ultra/AX-style hardware +Sun Ultra/AX-style hardware CONFIG_PARPORT_AX Say Y here if you need support for the parallel port hardware on Sun Ultra/AX machines. This code is also available as a module (say M), called parport_ax.o. If in doubt, saying N is the safe plan. -Plug and Play support -CONFIG_PNP - Plug and Play support allows the kernel to automatically configure - some peripheral devices. Say Y to enable PnP. - -Auto-probe for parallel devices -CONFIG_PNP_PARPORT - Some IEEE-1284 conforming parallel-port devices can identify - themselves when requested. Say Y to enable this feature, or M to - compile it as a module (parport_probe.o). If in doubt, say N. +IEEE1284 transfer modes +CONFIG_PARPORT_1284 + If you have a printer that supports status readback or device ID, or + want to use a device that uses enhanced parallel port transfer modes + such as EPP and ECP, say Y here to enable advanced IEEE 1284 + transfer modes. Also say Y if you want device ID information to + appear in /proc/parport/*/autoprobe*. It is safe to say N. Enable loadable module support CONFIG_MODULES @@ -8440,7 +8511,8 @@ CONFIG_PRINTER corresponding drivers into the kernel. If you want to compile this driver as a module however ( = 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 lp.o. + read Documentation/modules.txt and Documentation/parport.txt. The + module will be called lp.o. If you have several parallel ports, you can specify which ports to use with the "lp" kernel command line option. (Try "man bootparam" @@ -8454,11 +8526,18 @@ CONFIG_PRINTER If you have more than 3 printers, you need to increase the LP_NO variable in lp.c. -Support IEEE1284 status readback -CONFIG_PRINTER_READBACK - If your printer conforms to IEEE 1284, it may be able to provide a - status indication when you read from it (for example, with `cat - /dev/lp1'). To use this feature, say Y here. +Support for console on line printer +CONFIG_LP_CONSOLE + If you want kernel messages to be printed out as they occur, you + can have a console on the printer. This option adds support for + doing that; to actually get it to happen you need to pass the + option "console=lp" to the kernel at boot time. + + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + + If unsure, say N. Mouse Support (not serial mice) CONFIG_MOUSE diff --git a/Documentation/SMP.txt b/Documentation/SMP.txt index deac933c8..99832ca96 100644 --- a/Documentation/SMP.txt +++ b/Documentation/SMP.txt @@ -1,7 +1,7 @@ SMP on x86/Linux is now an official feature and is not experimental. Experimental SMP support for other architectures is underway. -Please view linux/Documentation/smp for more information about enabling SMP. +Please view linux/Documentation/smp.txt for more information about enabling SMP. SMP support for Linux with up to 16 processors using the Intel MP specification. diff --git a/Documentation/fb/tgafb.txt b/Documentation/fb/tgafb.txt new file mode 100644 index 000000000..36fe07821 --- /dev/null +++ b/Documentation/fb/tgafb.txt @@ -0,0 +1,51 @@ +[Also cloned from vesafb.txt, thanks to Gerd] + +What is tgafb? +=============== + +This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA +cards, specifically the following models + +ZLxP-E1 (8bpp, 4 MB VRAM) +ZLxP-E2 (32bpp, 8 MB VRAM) +ZLxP-E3 (32bpp, 16 MB VRAM, Zbuffer) + +This version, tgafb-1.12, is almost a complete rewrite of the code written +by Geert Uytterhoeven, which was based on the original TGA console code +written by Jay Estabrook. + +Major new features: + + * Support for multiple resolutions, including setting the resolution at + boot time, allowing the use of a fixed-frequency monitor. + * Complete code rewrite to follow Geert's skeletonfb spec which will allow + future implementation of hardware acceleration and other features. + + +Configuration +============= + +You can pass kernel command line options to tgafb with +`video=tga:option1,option2:value2,option3' (multiple options should be +separated by comma, values are separated from options by `:'). +Accepted options: + +font:X - default font to use. All fonts are supported, including the + SUN12x22 font which is very nice at high resolutions. +mode:X - default video mode. See drivers/video/tgafb.c for a list. + +X11 +=== + +XF68_FBDev should work just fine, but I haven't tested it. Running +the XF86_TGA server (reasonably recent versions of which support all TGA +cards) works fine for me. + +One minor problem with XF86_TGA is when running tgafb in resolutions higher +than 640x480, on switching VCs from tgafb to X, the entire screen is not +re-drawn and must be manually refreshed. This is an X server problem, not a +tgafb problem. + +Enjoy! + +Martin Lucina diff --git a/Documentation/java.txt b/Documentation/java.txt index 1b30c1183..be7203d3b 100644 --- a/Documentation/java.txt +++ b/Documentation/java.txt @@ -21,7 +21,7 @@ other program after you have done the following: 2) You have to compile BINFMT_MISC either as a module or into the kernel (CONFIG_BINFMT_MISC) and set it up properly. If you choose to compile it as a module, you will have - to insert it manually with modprobe/insmod, as kerneld + to insert it manually with modprobe/insmod, as kmod can not easy be supported with binfmt_misc. Read the file 'binfmt_misc.txt' in this directory to know more about the configuration process. @@ -29,14 +29,15 @@ other program after you have done the following: 3) Add the following configuration items to binfmt_misc (you should really have read binfmt_misc.txt now): support for Java applications: - ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' + ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:' support for Java Applets: - ':Applet:E::html::/usr/local/java/bin/appletviewer:' + ':Applet:E::html::/usr/bin/appletviewer:' or the following, if you want to be more selective: - ':Applet:M:: in the first line @@ -45,42 +46,300 @@ other program after you have done the following: For the compiled Java programs you need a wrapper script like the following (this is because Java is broken in case of the filename handling), again fix the path names, both in the script and in the - above given configuration string: + above given configuration string. + + You, too, need the little program after the script. Compile like + gcc -O2 -o javaclassname javaclassname.c + and stick it to /usr/local/bin. + + Both the javawrapper shellscript and the javaclassname program + were supplied by Colin J. Watson . ====================== Cut here =================== #!/bin/bash -# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java +# /usr/local/bin/javawrapper - the wrapper for binfmt_misc/java + +if [ -z "$1" ]; then + exec 1>&2 + echo Usage: $0 class-file + exit 1 +fi + CLASS=$1 +FQCLASS=`/usr/local/bin/javaclassname $1` +FQCLASSN=`echo $FQCLASS | sed -e 's/^.*\.\([^.]*\)$/\1/'` +FQCLASSP=`echo $FQCLASS | sed -e 's-\.-/-g' -e 's-^[^/]*$--' -e 's-/[^/]*$--'` -# if classname is a link, we follow it (this could be done easier - how?) -if [ -L "$1" ] ; then - CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` +# for example: +# CLASS=Test.class +# FQCLASS=foo.bar.Test +# FQCLASSN=Test +# FQCLASSP=foo/bar + +unset CLASSBASE + +declare -i LINKLEVEL=0 + +while :; do + if [ "`basename $CLASS .class`" == "$FQCLASSN" ]; then + # See if this directory works straight off + cd -L `dirname $CLASS` + CLASSDIR=$PWD + cd $OLDPWD + if echo $CLASSDIR | grep -q "$FQCLASSP$"; then + CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` + break; + fi + # Try dereferencing the directory name + cd -P `dirname $CLASS` + CLASSDIR=$PWD + cd $OLDPWD + if echo $CLASSDIR | grep -q "$FQCLASSP$"; then + CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` + break; + fi + # If no other possible filename exists + if [ ! -L $CLASS ]; then + exec 1>&2 + echo $0: + echo " $CLASS should be in a" \ + "directory tree called $FQCLASSP" + exit 1 + fi + fi + if [ ! -L $CLASS ]; then break; fi + # Go down one more level of symbolic links + let LINKLEVEL+=1 + if [ $LINKLEVEL -gt 5 ]; then + exec 1>&2 + echo $0: + echo " Too many symbolic links encountered" + exit 1 + fi + CLASS=`ls --color=no -l $CLASS | sed -e 's/^.* \([^ ]*\)$/\1/'` +done + +if [ -z "$CLASSBASE" ]; then + if [ -z "$FQCLASSP" ]; then + GOODNAME=$FQCLASSN.class + else + GOODNAME=$FQCLASSP/$FQCLASSN.class + fi + exec 1>&2 + echo $0: + echo " $FQCLASS should be in a file called $GOODNAME" + exit 1 fi -CLASSN=`basename $CLASS .class` -CLASSP=`dirname $CLASS` - -FOO=$PATH -PATH=$CLASSPATH -if [ -z "`type -p -a $CLASSN.class`" ] ; then - # class is not in CLASSPATH - if [ -e "$CLASSP/$CLASSN.class" ] ; then - # append dir of class to CLASSPATH - if [ -z "${CLASSPATH}" ] ; then - export CLASSPATH=$CLASSP - else - export CLASSPATH=$CLASSP:$CLASSPATH - fi - else - # uh! now we would have to create a symbolic link - really - # ugly, i.e. print a message that one has to change the setup - echo "Hey! This is not a good setup to run $1 !" - exit 1 - fi + +if ! echo $CLASSPATH | grep -q "^\(.*:\)*$CLASSBASE\(:.*\)*"; then + # class is not in CLASSPATH, so prepend dir of class to CLASSPATH + if [ -z "${CLASSPATH}" ] ; then + export CLASSPATH=$CLASSBASE + else + export CLASSPATH=$CLASSBASE:$CLASSPATH + fi fi -PATH=$FOO shift -/usr/local/java/bin/java $CLASSN "$@" +/usr/bin/java $FQCLASS "$@" +====================== Cut here =================== + + +====================== Cut here =================== +/* javaclassname.c + * + * Extracts the class name from a Java class file; intended for use in a Java + * wrapper of the type supported by the binfmt_misc option in the Linux kernel. + * + * Copyright (C) 1999 Colin J. Watson . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +/* From Sun's Java VM Specification, as tag entries in the constant pool. */ + +#define CP_UTF8 1 +#define CP_INTEGER 3 +#define CP_FLOAT 4 +#define CP_LONG 5 +#define CP_DOUBLE 6 +#define CP_CLASS 7 +#define CP_STRING 8 +#define CP_FIELDREF 9 +#define CP_METHODREF 10 +#define CP_INTERFACEMETHODREF 11 +#define CP_NAMEANDTYPE 12 + +/* Define some commonly used error messages */ + +#define seek_error() error("%s: Cannot seek\n", program) +#define corrupt_error() error("%s: Class file corrupt\n", program) +#define eof_error() error("%s: Unexpected end of file\n", program) +#define utf8_error() error("%s: Only ASCII 1-255 supported\n", program); + +char *program; + +long *pool; + +u_int8_t read_8(FILE *classfile); +u_int16_t read_16(FILE *classfile); +void skip_constant(FILE *classfile, u_int16_t *cur); +void error(const char *format, ...); +int main(int argc, char **argv); + +/* Reads in an unsigned 8-bit integer. */ +u_int8_t read_8(FILE *classfile) +{ + int b = fgetc(classfile); + if(b == EOF) + eof_error(); + return (u_int8_t)b; +} + +/* Reads in an unsigned 16-bit integer. */ +u_int16_t read_16(FILE *classfile) +{ + int b1, b2; + b1 = fgetc(classfile); + if(b1 == EOF) + eof_error(); + b2 = fgetc(classfile); + if(b2 == EOF) + eof_error(); + return (u_int16_t)((b1 << 8) | b2); +} + +/* Reads in a value from the constant pool. */ +void skip_constant(FILE *classfile, u_int16_t *cur) +{ + u_int16_t len; + int seekerr = 1; + pool[*cur] = ftell(classfile); + switch(read_8(classfile)) + { + case CP_UTF8: + len = read_16(classfile); + seekerr = fseek(classfile, len, SEEK_CUR); + break; + case CP_CLASS: + case CP_STRING: + seekerr = fseek(classfile, 2, SEEK_CUR); + break; + case CP_INTEGER: + case CP_FLOAT: + case CP_FIELDREF: + case CP_METHODREF: + case CP_INTERFACEMETHODREF: + case CP_NAMEANDTYPE: + seekerr = fseek(classfile, 4, SEEK_CUR); + break; + case CP_LONG: + case CP_DOUBLE: + seekerr = fseek(classfile, 8, SEEK_CUR); + ++(*cur); + break; + default: + corrupt_error(); + } + if(seekerr) + seek_error(); +} + +void error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *classfile; + u_int16_t cp_count, i, this_class, classinfo_ptr; + u_int8_t length; + + program = argv[0]; + + if(!argv[1]) + error("%s: Missing input file\n", program); + classfile = fopen(argv[1], "rb"); + if(!classfile) + error("%s: Error opening %s\n", program, argv[1]); + + if(fseek(classfile, 8, SEEK_SET)) /* skip magic and version numbers */ + seek_error(); + cp_count = read_16(classfile); + pool = calloc(cp_count, sizeof(long)); + if(!pool) + error("%s: Out of memory for constant pool\n", program); + + for(i = 1; i < cp_count; ++i) + skip_constant(classfile, &i); + if(fseek(classfile, 2, SEEK_CUR)) /* skip access flags */ + seek_error(); + + this_class = read_16(classfile); + if(this_class < 1 || this_class >= cp_count) + corrupt_error(); + if(!pool[this_class] || pool[this_class] == -1) + corrupt_error(); + if(fseek(classfile, pool[this_class] + 1, SEEK_SET)) + seek_error(); + + classinfo_ptr = read_16(classfile); + if(classinfo_ptr < 1 || classinfo_ptr >= cp_count) + corrupt_error(); + if(!pool[classinfo_ptr] || pool[classinfo_ptr] == -1) + corrupt_error(); + if(fseek(classfile, pool[classinfo_ptr] + 1, SEEK_SET)) + seek_error(); + + length = read_16(classfile); + for(i = 0; i < length; ++i) + { + u_int8_t x = read_8(classfile); + if((x & 0x80) || !x) + { + if((x & 0xE0) == 0xC0) + { + u_int8_t y = read_8(classfile); + if((y & 0xC0) == 0x80) + { + int c = ((x & 0x1f) << 6) + (y & 0x3f); + if(c) putchar(c); + else utf8_error(); + } + else utf8_error(); + } + else utf8_error(); + } + else if(x == '/') putchar('.'); + else putchar(x); + } + putchar('\n'); + free(pool); + fclose(classfile); + return 0; +} ====================== Cut here =================== @@ -116,4 +375,6 @@ the execution bit, then just do originally by Brian A. Lantz, brian@lantz.com -heavily edited for binfmt_misc by Richard Günther. +heavily edited for binfmt_misc by Richard Günther +new scripts by Colin J. Watson . + diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index 108c3b645..ebdef0873 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -1,15 +1,16 @@ Quick Summary ------------- -cd /usr/src/linux/scripts/ksymoops -make ksymoops -./ksymoops < the_oops.txt +Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops +Read the ksymoops man page. +ksymoops < the_oops.txt and send the output the maintainer of the kernel area that seems to be -involved with the problem. Don't worry too much about getting the wrong -person. If you are unsure send it to the person responsible for the code -relevant to what you were doing. If it occurs repeatably try and describe -how to recreate it. Thats worth even more than the oops +involved with the problem, not to the ksymoops maintainer. Don't worry +too much about getting the wrong person. If you are unsure send it to +the person responsible for the code relevant to what you were doing. +If it occurs repeatably try and describe how to recreate it. Thats +worth even more than the oops If you are totally stumped as to whom to send the report, send it to linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as @@ -41,9 +42,8 @@ Oh, it helps if the report happens on a kernel that is compiled with the same compiler and similar setups. The other thing to do is disassemble the "Code:" part of the bug report: -ksymoops will do this too with the correct tools (and new version of -ksymoops), but if you don't have the tools you can just do a silly -program: +ksymoops will do this too with the correct tools, but if you don't have +the tools you can just do a silly program: char str[] = "\xXX\xXX\xXX..."; main(){} diff --git a/Documentation/parport.txt b/Documentation/parport.txt index 6cf09e631..15e3303c9 100644 --- a/Documentation/parport.txt +++ b/Documentation/parport.txt @@ -28,17 +28,20 @@ architecture-dependent code with (for example): to tell the parport code that you want three PC-style ports, one at 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an -auto-detected IRQ. Currently, PC-style (parport_pc) and Sun Ultra/AX -(parport_ax) hardware is supported; more is in the works. +auto-detected IRQ. Currently, PC-style (parport_pc), Sun Ultra/AX +(parport_ax), Amiga, Atari, and MFC3 hardware is supported. KMod ---- If you use kmod, you will find it useful to edit /etc/conf.modules. -Here is an example of the lines that need to be added: +When a driver needs to use the parport subsystem for the first time, a +module by the name of parport_lowlevel will be automatically loaded +via kmod. No module actually exists with that name; it's just an +alias. Here is an example of the lines that need to be added: - alias parport_lowlevel parport_pc + post-install parport modprobe -k parport_pc options parport_pc io=0x378,0x278 irq=7,auto KMod will then automatically load parport_pc (with the options @@ -49,20 +52,15 @@ KMod will then automatically load parport_pc (with the options Parport probe [optional] ------------- -Once the architecture-dependent part of the parport code is loaded -into the kernel, you can insert the parport_probe module with: - - # insmod parport_probe.o - -This will perform an IEEE1284 probe of any attached devices and log a -message similar to: +In 2.2 kernels there was a module called parport_probe, which was used +for collecting IEEE 1284 device ID information. This has now been +enhanced and now lives with the IEEE 1284 support. When a parallel +port is detected, the devices that are connected to it are analysed, +and information is logged like this: parport0: Printer, BJC-210 (Canon) -(If you are using kmod and have configured parport_probe as a module, -this will just happen.) - -The probe information is available in /proc/parport/?/autoprobe. +The probe information is available from files in /proc/sys/dev/parport/. Parport linked into the kernel statically @@ -85,29 +83,74 @@ Files in /proc ============== If you have configured the /proc filesystem into your kernel, you will -see a new directory entry: /proc/parport. In there will be a +see a new directory entry: /proc/sys/dev/parport. In there will be a directory entry for each parallel port for which parport is -configured. In each of those directories are four files describing -that parallel port. For example: - -File: Contents: - -/proc/parport/0/devices A list of the device drivers using - that port. A "+" will appear by the - name of the device currently using the - port (it might not appear against any). - -/proc/parport/0/hardware Parallel port's base address, IRQ line - and DMA channel. - -/proc/parport/0/irq The IRQ that parport is using for that - port. This is in a separate file to - allow you to alter it by writing a new - value in (IRQ number or "none"). - -/proc/parport/0/autoprobe Any IEEE-1284 device ID information - that has been acquired. - +configured. In each of those directories are a collection of files +describing that parallel port. + +The /proc/sys/dev/parport directory tree looks like: + +parport +|-- default +| |-- spintime +| `-- timeslice +|-- parport0 +| |-- autoprobe +| |-- autoprobe0 +| |-- autoprobe1 +| |-- autoprobe2 +| |-- autoprobe3 +| |-- devices +| | |-- active +| | `-- lp +| | `-- timeslice +| |-- hardware +| `-- spintime +`-- parport1 + |-- autoprobe + |-- autoprobe0 + |-- autoprobe1 + |-- autoprobe2 + |-- autoprobe3 + |-- devices + | |-- active + | `-- ppa + | `-- timeslice + |-- hardware + `-- spintime + + +File: Contents: + +devices/active A list of the device drivers using that port. A "+" + will appear by the name of the device currently using + the port (it might not appear against any). The + string "none" means that there are no device drivers + using that port. + +hardware Parallel port's base address, IRQ line and DMA channel. + +autoprobe Any IEEE-1284 device ID information that has been + acquired from the (non-IEEE 1284.3) device. + +autoprobe[0-3] IEEE 1284 device ID information retrieved from + daisy-chain devices that conform to IEEE 1284.3. + +spintime The number of microseconds to busy-loop while waiting + for the peripheral to respond. You might find that + adjusting this improves performance, depending on your + peripherals. This is a port-wide setting, i.e. it + applies to all devices on a particular port. + +timeslice The number of jiffies (FIXME: this should be in + milliseconds or something) that a device driver is + allowed to keep a port claimed for. This is advisory, + and driver can ignore it if it must. + +default/* The defaults for spintime and timeslice. When a new + port is registered, it picks up the default spintime. + When a new device is registered, it picks up the + default timeslice. Device drivers ============== @@ -135,7 +178,7 @@ regardless of base address. Also: - * If you selected the IEEE-1284 autoprobe at compile time, you can say + * If you selected the IEEE 1284 support at compile time, you can say `lp=auto' on the kernel command line, and lp will create devices only for those ports that seem to have printers attached. diff --git a/Makefile b/Makefile index ec74c4044..5a6f76204 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 9 +SUBLEVEL = 10 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -351,8 +351,7 @@ endif clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \ - ! -regex '.*ksymoops/.*' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -376,7 +375,6 @@ mrproper: clean archmrproper rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog - rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops rm -f .menuconfig.log rm -f include/asm rm -rf include/config diff --git a/README b/README index dd95240e6..a1f137898 100644 --- a/README +++ b/README @@ -9,9 +9,9 @@ public use. Different releases may have various and sometimes severe bugs. It is *strongly* recommended that you back up the previous kernel before installing any new 2.3.xx release. -If you need to use a proven and stable Linux kernel, please use 1.2.13, -2.0.36 or 2.2.xx. All features which will be in the 2.3.xx releases will -be contained in 2.4.xx when the code base has stabilized again. +If you need to use a proven and stable Linux kernel, please use 2.0.37 +or 2.2.xx. All features which will be in the 2.3.xx releases will be +contained in 2.4.xx when the code base has stabilized again. If you decide to use 2.3, it is recommended that you join the kernel mailing list. To do this, e-mail majordomo@vger.rutgers.edu, and put in the body @@ -105,7 +105,7 @@ INSTALLING the kernel: SOFTWARE REQUIREMENTS - Compiling and running the 2.3.x kernels requires up-to-date + Compiling and running the 2.3.xx kernels requires up-to-date versions of various software packages. Consult ./Documentation/Changes for the minimum version numbers required and how to get updates for these packages. Beware that using diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 75b3e9563..eb9752970 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -188,13 +188,7 @@ tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in endmenu source drivers/pnp/Config.in diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index e97021869..eef452e57 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -603,7 +603,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs) update_one_process(current, 1, user, !user, cpu); if (current->pid) { - if (--current->counter < 0) { + if (--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff --git a/arch/i386/config.in b/arch/i386/config.in index f0ac5e2c0..56b3fd802 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -92,13 +92,7 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in bool 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" = "y" ]; then diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 856ceecf3..80656a997 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -70,11 +70,6 @@ CONFIG_BINFMT_MISC=y # CONFIG_I2O_PROC is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -98,6 +93,8 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_HPT34X is not set +CONFIG_BLK_DEV_PIIX=y # CONFIG_IDE_CHIPSETS is not set # diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index 6a19d9884..1023cd4da 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -238,7 +238,7 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ */ static inline void x86_do_profile (unsigned long eip) { - if (prof_buffer && current->pid) { + if (prof_buffer) { eip -= (unsigned long) &_stext; eip >>= prof_shift; /* diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index ad745f58a..ad522c6c7 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 09664ba81..28aea16a8 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -73,8 +73,7 @@ static inline int put_stack_long(struct task_struct *task, int offset, * and that it is in the task area before calling this: this routine does * no checking. */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) +static unsigned long get_long(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr) { pgd_t * pgdir; pmd_t * pgmiddle; @@ -84,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(mm, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -94,7 +93,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(mm, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -104,7 +103,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(mm, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -124,7 +123,7 @@ repeat: * Now keeps R/W state of page so that a text page stays readonly * even if a debugger scribbles breakpoints into it. -M.U- */ -static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, +static void put_long(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, unsigned long data) { pgd_t *pgdir; @@ -135,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(mm, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -145,7 +144,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(mm, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -155,12 +154,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(mm, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(mm, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -176,10 +175,10 @@ repeat: * This routine checks the page boundaries, and that the offset is * within the task area. It then calls get_long() to read a long. */ -static int read_long(struct task_struct * tsk, unsigned long addr, +static int read_long(struct mm_struct * mm, unsigned long addr, unsigned long * result) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); + struct vm_area_struct * vma = find_extend_vma(mm, addr); if (!vma) return -EIO; @@ -192,8 +191,8 @@ static int read_long(struct task_struct * tsk, unsigned long addr, if (!vma_high || vma_high->vm_start != vma->vm_end) return -EIO; } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + low = get_long(mm, vma, addr & ~(sizeof(long)-1)); + high = get_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); switch (addr & (sizeof(long)-1)) { case 1: low >>= 8; @@ -210,7 +209,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr, } *result = low; } else - *result = get_long(tsk, vma, addr); + *result = get_long(mm, vma, addr); return 0; } @@ -218,10 +217,10 @@ static int read_long(struct task_struct * tsk, unsigned long addr, * This routine checks the page boundaries, and that the offset is * within the task area. It then calls put_long() to write a long. */ -static int write_long(struct task_struct * tsk, unsigned long addr, +static int write_long(struct mm_struct * mm, unsigned long addr, unsigned long data) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); + struct vm_area_struct * vma = find_extend_vma(mm, addr); if (!vma) return -EIO; @@ -234,8 +233,8 @@ static int write_long(struct task_struct * tsk, unsigned long addr, if (!vma_high || vma_high->vm_start != vma->vm_end) return -EIO; } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + low = get_long(mm, vma, addr & ~(sizeof(long)-1)); + high = get_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); switch (addr & (sizeof(long)-1)) { case 0: /* shouldn't happen, but safety first */ low = data; @@ -259,10 +258,10 @@ static int write_long(struct task_struct * tsk, unsigned long addr, high |= data >> 8; break; } - put_long(tsk, vma, addr & ~(sizeof(long)-1),low); - put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); + put_long(mm, vma, addr & ~(sizeof(long)-1),low); + put_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); } else - put_long(tsk, vma, addr, data); + put_long(mm, vma, addr, data); return 0; } @@ -404,7 +403,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) unsigned long tmp; down(&child->mm->mmap_sem); - ret = read_long(child, addr, &tmp); + ret = read_long(child->mm, addr, &tmp); up(&child->mm->mmap_sem); if (ret >= 0) ret = put_user(tmp,(unsigned long *) data); @@ -437,7 +436,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: down(&child->mm->mmap_sem); - ret = write_long(child,addr,data); + ret = write_long(child->mm,addr,data); up(&child->mm->mmap_sem); goto out; diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 9d3a8b4b5..f092d0905 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -1792,7 +1792,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) update_one_process(p, 1, user, system, cpu); if (p->pid) { p->counter -= 1; - if (p->counter < 0) { + if (p->counter <= 0) { p->counter = 0; p->need_resched = 1; } diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 5a1f363bd..bb808c300 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -50,7 +50,7 @@ good_area: start &= PAGE_MASK; for (;;) { - handle_mm_fault(current,vma, start, 1); + handle_mm_fault(current->mm, vma, start, 1); if (!size) break; size--; @@ -162,7 +162,7 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - if (!handle_mm_fault(tsk, vma, address, write)) + if (!handle_mm_fault(mm, vma, address, write)) goto do_sigbus; /* diff --git a/arch/mips/sgi/kernel/indy_sc.c b/arch/mips/sgi/kernel/indy_sc.c index cc5d844e4..1fecee23f 100644 --- a/arch/mips/sgi/kernel/indy_sc.c +++ b/arch/mips/sgi/kernel/indy_sc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 2881decd7..e7a649a32 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -66,13 +66,7 @@ define_bool CONFIG_BINFMT_ELF y define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 2cb23188a..523a1945f 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index fc2613ddf..5c26da8cc 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -85,7 +85,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) update_one_process(p, 1, user, system, cpu); p->counter -= 1; - if (p->counter < 0) { + if (p->counter <= 0) { p->counter = 0; current->need_resched = 1; } diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index edd736b41..64ef31bbb 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -473,7 +473,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) if(current->pid) { update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index c9acf609c..3fb1044f4 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -454,7 +454,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) if(current->pid) { update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index c501884ed..eb192c584 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -68,20 +68,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then fi if [ "$CONFIG_PCI" = "y" ]; then - tristate 'Parallel port support' CONFIG_PARPORT - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_AX" = "m" ]; then - define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y - fi - if [ "$CONFIG_PARPORT_AX" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi - dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT - if [ "$CONFIG_PRINTER" != "n" ]; then - bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK - fi - fi + source drivers/misc/Config.in + dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi endmenu diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 7d638c5da..bc77266f9 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -311,9 +311,10 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm, fd = open_dentry(bprm->dentry, O_RDONLY); if (fd < 0) return fd; - file = fcheck(fd); + file = fget(fd); if (!file->f_op || !file->f_op->mmap) { + fput(fd); sys_close(fd); do_brk(0, ex.a_text+ex.a_data); read_exec(bprm->dentry, fd_offset, @@ -327,6 +328,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm, fd_offset); if (error != N_TXTADDR(ex)) { + fput(file); sys_close(fd); send_sig(SIGKILL, current, 0); return error; @@ -336,6 +338,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); + fput(file); sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index b0e92d50b..a0e8f7e69 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -615,7 +615,7 @@ do { hardirq_enter(cpu); \ unsigned int *inc, *inc2; update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 0e73f0c65..d0b4a5d07 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -41,30 +41,49 @@ else bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then 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 + fi fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 + bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 + fi + bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA + fi + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + fi + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 - bool ' Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then - bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 - bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 - bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 - bool ' PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246 - bool ' PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262 - if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \ - "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then - define_bool CONFIG_BLK_DEV_PDC202XX y - else - define_bool CONFIG_BLK_DEV_PDC202XX n - fi - bool ' HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343 + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX + if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then + bool ' Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT + bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE fi fi + 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 + fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 @@ -106,13 +125,12 @@ else bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \ + "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + fi bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 - fi - fi fi if [ "$CONFIG_AMIGA" = "y" ]; then bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE @@ -182,13 +200,13 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then source drivers/block/paride/Config.in fi - -if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ - "$CONFIG_IDE_CHIPSETS" = "y" -o \ - "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ - "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ +if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ + "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ + "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ - "$CONFIG_BLK_DEV_HPT343" = "y" -o \ + "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ + "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ + "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 7d553f9b2..61909b033 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -202,8 +202,8 @@ ifeq ($(CONFIG_BLK_DEV_AEC6210),y) IDE_OBJS += aec6210.o endif -ifeq ($(CONFIG_BLK_DEV_HPT343),y) -IDE_OBJS += hpt343.o +ifeq ($(CONFIG_BLK_DEV_HPT34X),y) +IDE_OBJS += hpt34x.o endif ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c index ce5d0cb63..4ea590fa2 100644 --- a/drivers/block/alim15x3.c +++ b/drivers/block/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.04 Feb. 8, 1999 + * linux/drivers/block/alim15x3.c Version 0.05 Jun. 29, 1999 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer @@ -20,6 +20,8 @@ #include +#include "ide_modes.h" + #define DISPLAY_ALI_TIMINGS #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) @@ -59,6 +61,55 @@ char *channel_status[8] = { }; #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ +static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int s_time, a_time, c_time; + byte s_clc, a_clc, r_clc; + unsigned long flags; + int bus_speed = ide_system_bus_speed(); + int port = hwif->index ? 0x5c : 0x58; + + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + s_time = ide_pio_timings[pio].setup_time; + a_time = ide_pio_timings[pio].active_time; + if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) + s_clc = 0; + if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) + a_clc = 0; + c_time = ide_pio_timings[pio].cycle_time; + +#if 0 + if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) + r_clc = 0; +#endif + + if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { + r_clc = 1; + } else { + if (r_clc >= 16) + r_clc = 0; + } + save_flags(flags); + cli(); + pci_write_config_byte(dev, port, s_clc); + pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); + restore_flags(flags); + + /* + * setup active rec + * { 70, 165, 365 }, PIO Mode 0 + * { 50, 125, 208 }, PIO Mode 1 + * { 30, 100, 110 }, PIO Mode 2 + * { 30, 80, 70 }, PIO Mode 3 with IORDY + * { 25, 70, 25 }, PIO Mode 4 with IORDY ns + * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) + */ + +} + __initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name)) { byte confreg0 = 0, confreg1 =0, progif = 0; @@ -146,19 +197,22 @@ int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) { struct pci_dev *dev; - byte ideic, inmir; + byte ideic, inmir, iderev; byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; + + pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev); + hwif->irq = hwif->channel ? 15 : 14; for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */ if (dev->vendor==PCI_VENDOR_ID_AL && - dev->device==PCI_DEVICE_ID_AL_M1533) + dev->device==PCI_DEVICE_ID_AL_M1533) break; if (dev) { pci_read_config_byte(dev, 0x58, &ideic); ideic = ideic & 0x03; if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { + (!hwif->channel && !ideic)) { pci_read_config_byte(dev, 0x44, &inmir); inmir = inmir & 0x0f; hwif->irq = irq_routing_table[inmir]; @@ -174,8 +228,15 @@ __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) ali_display_info = &ali_get_info; #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - if (hwif->dma_base) + hwif->tuneproc = &ali15x3_tune_drive; + if ((hwif->dma_base) && (iderev >= 0xC1)) { + /* M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; + } else { + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } return; } diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c index 63b4bbc09..4775093fb 100644 --- a/drivers/block/cmd646.c +++ b/drivers/block/cmd646.c @@ -94,6 +94,9 @@ static __inline__ int wait_for_ready(ide_drive_t *drive) static void cmd646_do_setfeature(ide_drive_t *drive, byte command) { +#if 0 + (void) ide_config_drive_speed(drive, command); +#else unsigned long flags; byte old_select; @@ -116,6 +119,7 @@ static void cmd646_do_setfeature(ide_drive_t *drive, byte command) out: OUT_BYTE(old_select, IDE_SELECT_REG); restore_flags(flags); +#endif } static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base) diff --git a/drivers/block/hpt343.c b/drivers/block/hpt34x.c similarity index 85% rename from drivers/block/hpt343.c rename to drivers/block/hpt34x.c index f759cbf8a..e853ee438 100644 --- a/drivers/block/hpt343.c +++ b/drivers/block/hpt34x.c @@ -49,7 +49,7 @@ extern char *ide_xfer_verbose (byte xfer_rate); -static void hpt343_clear_chipset (ide_drive_t *drive) +static void hpt34x_clear_chipset (ide_drive_t *drive) { int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); unsigned int reg1 = 0, tmp1 = 0; @@ -63,7 +63,7 @@ static void hpt343_clear_chipset (ide_drive_t *drive) pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); } -static int hpt343_tune_chipset (ide_drive_t *drive, byte speed) +static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed) { int err; byte hi_speed, lo_speed; @@ -84,7 +84,7 @@ static int hpt343_tune_chipset (ide_drive_t *drive, byte speed) pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); tmp2 = ((hi_speed << drive_number) | reg2); - err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + err = ide_config_drive_speed(drive, speed); pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); @@ -187,7 +187,7 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ((int) ide_dma_off_quietly); } - (void) hpt343_tune_chipset(drive, speed); + (void) hpt34x_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -229,15 +229,23 @@ static void config_chipset_for_pio (ide_drive_t *drive) speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; break; } - - (void) hpt343_tune_chipset(drive, speed); + (void) hpt34x_tune_chipset(drive, speed); } -#if 0 -static void hpt343_tune_drive (ide_drive_t *drive, byte pio) +static void hpt34x_tune_drive (ide_drive_t *drive, byte pio) { + byte speed; + + hpt34x_clear_chipset(drive); + 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) hpt34x_tune_chipset(drive, speed); } -#endif static int config_drive_xfer_rate (ide_drive_t *drive) { @@ -290,18 +298,18 @@ no_dma_set: } /* - * hpt343_dmaproc() initiates/aborts (U)DMA read/write operations on a 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 hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { switch (func) { case ide_dma_check: - hpt343_clear_chipset(drive); + hpt34x_clear_chipset(drive); return config_drive_xfer_rate(drive); #if 0 case ide_dma_off: @@ -324,26 +332,26 @@ int hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive) /* * If the BIOS does not set the IO base addaress to XX00, 343 will fail. */ -#define HPT343_PCI_INIT_REG 0x80 +#define HPT34X_PCI_INIT_REG 0x80 -__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name)) +__initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) { int i; unsigned short cmd; - unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; #if 0 - unsigned char misc10 = inb(hpt343IoBase + 0x0010); - unsigned char misc11 = inb(hpt343IoBase + 0x0011); + unsigned char misc10 = inb(hpt34xIoBase + 0x0010); + unsigned char misc11 = inb(hpt34xIoBase + 0x0011); #endif - pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x00); + 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] = (hpt343IoBase + 0x20); - dev->base_address[1] = (hpt343IoBase + 0x34); - dev->base_address[2] = (hpt343IoBase + 0x28); - dev->base_address[3] = (hpt343IoBase + 0x3c); + 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; @@ -358,15 +366,15 @@ __initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name)) pci_write_config_word(dev, PCI_COMMAND, cmd); #if 0 - outb(misc10|0x78, (hpt343IoBase + 0x0010)); - outb(misc11, (hpt343IoBase + 0x0011)); + 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(hpt343IoBase + 0x0010), - inb(hpt343IoBase + 0x0011)); + inb(hpt34xIoBase + 0x0010), + inb(hpt34xIoBase + 0x0011)); #endif if (cmd & PCI_COMMAND_MEMORY) { @@ -380,13 +388,19 @@ __initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name)) return dev->irq; } -__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif)) +__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif)) { + hwif->tuneproc = &hpt34x_tune_drive; if (hwif->dma_base) { unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); +#ifdef CONFIG_BLK_DEV_HPT34X_DMA hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; - hwif->dmaproc = &hpt343_dmaproc; +#endif /* CONFIG_BLK_DEV_HPT34X_DMA */ + hwif->dmaproc = &hpt34x_dmaproc; + } else { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; } } diff --git a/drivers/block/icside.c b/drivers/block/icside.c index 0d29761ee..edffa0cf1 100644 --- a/drivers/block/icside.c +++ b/drivers/block/icside.c @@ -299,6 +299,9 @@ icside_config_drive(ide_drive_t *drive, int mode) drive->drive_data = 250; } +#if 1 + err = ide_config_drive_speed(drive, (byte) speed); +#else /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -313,6 +316,7 @@ icside_config_drive(ide_drive_t *drive, int mode) err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); +#endif if (err == 0) { drive->id->dma_mword &= 0x00ff; diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 9f26ea6bc..0cda4398c 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -91,9 +91,8 @@ #include #include -#define IDE_DMA_NEW_LISTINGS 0 +#ifdef IDEDMA_NEW_DRIVE_LISTINGS -#if IDE_DMA_NEW_LISTINGS struct drive_list_entry { char * id_model; char * id_firmware; @@ -130,7 +129,8 @@ int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) return 1; return 0; } -#else /* !IDE_DMA_NEW_LISTINGS */ + +#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ /* * good_dma_drives() lists the model names (from "hdparm -i") @@ -162,7 +162,7 @@ const char *bad_dma_drives[] = {"WDC AC11000H", "WDC AC31600H", NULL}; -#endif /* IDE_DMA_NEW_LISTINGS */ +#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ /* * Our Physical Region Descriptor (PRD) table should be large enough @@ -314,8 +314,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad) { struct hd_driveid *id = drive->id; -#if IDE_DMA_NEW_LISTINGS - +#ifdef IDEDMA_NEW_DRIVE_LISTINGS if (good_bad) { return in_drive_list(id, drive_whitelist); } else { @@ -324,8 +323,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad) printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return(blacklist); } -#else /* !IDE_DMA_NEW_LISTINGS */ - +#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ const char **list; if (good_bad) { @@ -346,7 +344,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad) } } } -#endif /* IDE_DMA_NEW_LISTINGS */ +#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ return 0; } @@ -359,12 +357,12 @@ 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); -#if 0 +#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->dma_ultra & (id->dma_ultra >> 11) & 3)) return hwif->dmaproc(ide_dma_on, drive); -#endif +#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)) @@ -527,7 +525,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c } } if (dma_base) { - if (extra) /* PDC20246 & HPT343 */ + if (extra) /* PDC20246, PDC20262, & HPT343 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; @@ -538,13 +536,15 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c * 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: - outb(inb(dma_base+2) & 0x60, dma_base+2); /* * Ali 15x3 chipsets know as ALI IV and V report * this as simplex, skip this test for them. */ +#endif /* CONFIG_BLK_DEV_ALI15X3 */ + outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); } diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index 8b4c5fe2c..df3100d37 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -51,7 +51,7 @@ #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #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_HPT343 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) +#define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) #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}) @@ -156,14 +156,14 @@ extern unsigned int pci_init_aec6210(struct pci_dev *, const char *); #define PCI_AEC6210 NULL #endif -#ifdef CONFIG_BLK_DEV_HPT343 -extern unsigned int pci_init_hpt343(struct pci_dev *, const char *); -extern void ide_init_hpt343(ide_hwif_t *); -#define PCI_HPT343 &pci_init_hpt343 -#define INIT_HPT343 &ide_init_hpt343 +#ifdef CONFIG_BLK_DEV_HPT34X +extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); +extern void ide_init_hpt34x(ide_hwif_t *); +#define PCI_HPT34X &pci_init_hpt34x +#define INIT_HPT34X &ide_init_hpt34x #else -#define PCI_HPT343 NULL -#define INIT_HPT343 NULL +#define PCI_HPT34X NULL +#define INIT_HPT34X NULL #endif #define INIT_SAMURAI NULL @@ -212,7 +212,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {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_HPT343, "HPT343", PCI_HPT343, INIT_HPT343, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, + {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 }, @@ -231,13 +231,13 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const { int i; unsigned short pcicmd = 0; - unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; pci_write_config_byte(dev, 0x80, 0x00); - dev->base_address[0] = (hpt343IoBase + 0x20); - dev->base_address[1] = (hpt343IoBase + 0x34); - dev->base_address[2] = (hpt343IoBase + 0x28); - dev->base_address[3] = (hpt343IoBase + 0x3c); + 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; @@ -422,7 +422,7 @@ check_if_enabled: printk("%s: 100%% native mode on irq %d\n", d->name, pciirq); #endif } - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) { + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { /* * Since there are two cards that report almost identically, * the only discernable difference is the values @@ -490,9 +490,9 @@ check_if_enabled: if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || -#ifdef CONFIG_BLK_DEV_HPT343 - IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) || -#endif +#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_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); diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 17b10593d..6d324bea8 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -2235,6 +2235,27 @@ void ide_delay_50ms (void) while (0 < (signed long)(timeout - jiffies)); } +int ide_config_drive_speed (ide_drive_t *drive, byte speed) +{ + int err; + + /* + * Don't use ide_wait_cmd here - it will + * attempt to set_geometry and recalibrate, + * but for some reason these don't work at + * this point (lost interrupt). + */ + SELECT_DRIVE(HWIF(drive), drive); + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(speed, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + + err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); + + return(err); +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -3416,6 +3437,7 @@ EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); EXPORT_SYMBOL(ide_delay_50ms); +EXPORT_SYMBOL(ide_config_drive_speed); EXPORT_SYMBOL(ide_stall_queue); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(ide_add_proc_entries); diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index f0591397c..08f87655e 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -90,8 +90,6 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 -#define PDC202XX_FORCE_BURST_BIT 0 -#define PDC202XX_FORCE_MASTER_MODE 0 extern char *ide_xfer_verbose (byte xfer_rate); @@ -225,16 +223,12 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) switch(drive_number) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -242,16 +236,12 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -415,7 +405,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) return ide_dma_off_quietly; } - err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + err = ide_config_drive_speed(drive, speed); #if PDC202XX_DECODE_REGISTER_INFO pci_read_config_byte(dev, (drive_pci), &AP); @@ -436,8 +426,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) printk("0x%08x\n", drive_conf); #endif /* PDC202XX_DEBUG_DRIVE_INFO */ -chipset_is_set: - 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 : @@ -533,7 +521,7 @@ __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#if PDC202XX_FORCE_BURST_BIT +#ifdef PDC202XX_FORCE_BURST_BIT if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); @@ -541,7 +529,7 @@ __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name } #endif /* PDC202XX_FORCE_BURST_BIT */ -#if PDC202XX_FORCE_MASTER_MODE +#ifdef PDC202XX_FORCE_MASTER_MODE if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); diff --git a/drivers/block/piix.c b/drivers/block/piix.c index e89e5dfb6..79a0e873f 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.23 May 29, 1999 + * linux/drivers/block/piix.c Version 0.24 June 28, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer @@ -44,6 +44,12 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); * + * #if 0 + * int err; + * err = ide_config_drive_speed(drive, speed); + * (void) ide_config_drive_speed(drive, speed); + * #else + * #endif */ #include @@ -62,6 +68,7 @@ extern char *ide_xfer_verbose (byte xfer_rate); +#ifdef CONFIG_BLK_DEV_PIIX_TUNING /* * */ @@ -91,6 +98,7 @@ static byte piix_dma_2_pio (byte xfer_rate) { return 0; } } +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ /* * Based on settings done by AMI BIOS @@ -111,11 +119,7 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) { 2, 1 }, { 2, 3 }, }; -#if 1 pio = ide_get_best_pio_mode(drive, pio, 5, NULL); -#else - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); -#endif pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); if (is_slave) { master_data = master_data | 0x4000; @@ -142,6 +146,8 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) restore_flags(flags); } +#ifdef CONFIG_BLK_DEV_PIIX_TUNING + static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) { struct hd_driveid *id = drive->id; @@ -246,17 +252,13 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) } speed = XFER_SW_DMA_2; } else { -#if 0 - speed = XFER_PIO_0; -#else speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); -#endif } restore_flags(flags); piix_tune_drive(drive, piix_dma_2_pio(speed)); - (void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO printk("%s: %s drive%d ", @@ -284,11 +286,19 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ void ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; +#ifdef CONFIG_BLK_DEV_PIIX_TUNING if (hwif->dma_base) { hwif->dmaproc = &piix_dmaproc; + } else +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ + { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; } + } diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 6c9f0a651..8bc1b4feb 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -52,7 +52,7 @@ fi if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PRINTER" != "n" ]; then - bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK + bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi fi diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c index 5f9341eac..41586b58f 100644 --- a/drivers/char/c-qcam.c +++ b/drivers/char/c-qcam.c @@ -1,6 +1,6 @@ /* * Video4Linux Colour QuickCam driver - * Copyright 1997-1998 Philip Blundell + * Copyright 1997-1999 Philip Blundell * */ @@ -294,7 +294,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) if (is_bi_dir) { /* Turn the port around */ - parport_frob_control(q->pport, 0x20, 0x20); + parport_data_reverse(q->pport); mdelay(3); qcam_set_ack(q, 0); if (qcam_await_ready1(q, 1)) { @@ -336,7 +336,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) { printk("qcam: short read.\n"); if (is_bi_dir) - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); qc_setup(q); return len; } @@ -355,11 +355,11 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) if (qcam_await_ready1(q, 1)) { printk("qcam: no ack after EOF\n"); - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); qc_setup(q); return len; } - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); mdelay(3); qcam_set_ack(q, 1); if (qcam_await_ready1(q, 0)) @@ -646,7 +646,7 @@ static struct qcam_device *qcam_init(struct parport *port) q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, NULL, 0, NULL); - q->bidirectional = (q->pport->modes & PARPORT_MODE_PCPS2)?1:0; + q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0; if (q->pdev == NULL) { @@ -678,10 +678,7 @@ int init_cqcam(struct parport *port) struct qcam_device *qcam; if (num_cams == MAX_CAMS) - { - printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); return -ENOSPC; - } qcam = qcam_init(port); if (qcam==NULL) @@ -725,19 +722,40 @@ void close_cqcam(struct qcam_device *qcam) kfree(qcam); } -#define BANNER "Connectix Colour Quickcam driver v0.02\n" +#define BANNER "Connectix Colour Quickcam driver v0.03" -#ifdef MODULE -int init_module(void) +static void cq_attach(struct parport *port) { - struct parport *port; + init_cqcam(port); +} - printk(BANNER); +static void cq_detach(struct parport *port) +{ + /* Write this some day. */ +} - for (port = parport_enumerate(); port; port=port->next) - init_cqcam(port); +static struct parport_driver cqcam_driver = { + "cqcam", + cq_attach, + cq_detach, + NULL +}; - return (num_cams)?0:-ENODEV; +static void cqcam_init(void) +{ + printk(BANNER "\n"); + parport_register_driver(&cqcam_driver); +} + +#ifdef MODULE + +MODULE_AUTHOR("Philip Blundell "); +MODULE_DESCRIPTION(BANNER); + +int init_module(void) +{ + cqcam_init(); + return 0; } void cleanup_module(void) @@ -749,12 +767,7 @@ void cleanup_module(void) #else __initfunc(int init_colour_qcams(struct video_init *unused)) { - struct parport *port; - - printk(BANNER); - - for (port = parport_enumerate(); port; port=port->next) - init_cqcam(port); + cqcam_init(); return 0; } #endif diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index a5e8ff891..2d84f18c3 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -2640,7 +2640,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) printk("Not clean (jiff=%lu)...", jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -2653,7 +2652,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) } /* Run one more char cycle */ current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time * 5); current->state = TASK_RUNNING; #ifdef CY_DEBUG_WAIT_UNTIL_SENT diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 53d67f19e..e4d98cc0c 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2180,7 +2180,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) while ((serial_in(info, UART_ESI_STAT1) != 0x03) || (serial_in(info, UART_ESI_STAT2) != 0xff)) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(char_time); if (signal_pending(current)) diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c index cafe38f37..29b5e16c9 100644 --- a/drivers/char/i2c-parport.c +++ b/drivers/char/i2c-parport.c @@ -36,9 +36,7 @@ struct parport_i2c_bus static struct parport_i2c_bus *bus_list; -#ifdef __SMP__ static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED; -#endif /* software I2C functions */ diff --git a/drivers/char/joystick/joy-db9.c b/drivers/char/joystick/joy-db9.c index 82a5c6a0f..b459b91f5 100644 --- a/drivers/char/joystick/joy-db9.c +++ b/drivers/char/joystick/joy-db9.c @@ -337,7 +337,7 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port) return port; } - if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2))) { + if (!(pp->modes & PARPORT_MODE_TRISTATE)) { printk(KERN_ERR "js-db9: specified parport is not bidirectional\n"); return port; } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 4b005b96d..7aa14a886 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -27,6 +27,9 @@ * Obsoleted the CAREFUL flag since a printer that doesn' t work with * CAREFUL will block a bit after in lp_check_status(). * Andrea Arcangeli, 15 Oct 1998 + * Obsoleted and removed all the lowlevel stuff implemented in the last + * month to use the IEEE1284 functions (that handle the _new_ compatibilty + * mode fine). */ /* This driver should, in theory, work with any parallel port that has an @@ -58,74 +61,6 @@ * # insmod lp.o reset=1 */ -/* - * LP OPTIMIZATIONS - * - * - TRUST_IRQ flag - * - * Epson Stylus Color, HP and many other new printers want the TRUST_IRQ flag - * set when printing with interrupts. This is a long story. Such printers - * use a broken handshake (see the timing graph below) when printing with - * interrupts. The lp driver as default is just able to handle such bogus - * handshake, but setting such flag cause lp to go faster and probably do - * what such printers want (even if not documented). - * - * NOTE that setting the TRUST_IRQ flag in some printer can cause the irq - * printing to fail completly. You must try, to know if your printer - * will handle it. I suggest a graphics printing to force a major flow of - * characters to the printer for do the test. NOTE also that the TRUST_IRQ - * flag _should_ be fine everywhere but there is a lot of buggy hardware out - * there, so I am forced to implement it as a not-default thing. - * WARNING: before to do the test, be sure to have not played with the - * `-w' parameter of tunelp! - * - * Note also that lp automagically warn you (with a KERN_WARNING) if it - * detects that you could _try_ to set the TRUST_IRQ flag to speed up the - * printing and decrease the CPU load. - * - * To set the TRUST_IRQ flag you can use this command: - * - * tunelp /dev/lp? -T on - * - * If you have an old tunelp executable you can (hack and) use this simple - * C lazy proggy to set the flag in the lp driver: - --------------------------- cut here ------------------------------------- -#include -#include - -#define LPTRUSTIRQ 0x060f - -int main(int argc, char **argv) -{ - int fd = open("/dev/lp0", O_RDONLY); - ioctl(fd, LPTRUSTIRQ, argc - 1); - if (argc - 1) - printf("trusting the irq\n"); - else - printf("untrusting the irq\n"); - return 0; -} --------------------------- cut here ------------------------------------- - - * - LP_WAIT time - * - * You can use this setting if your printer is fast enough and/or your - * machine is slow enough ;-). - * - * tunelp /dev/lp? -w 0 - * - * - LP_CHAR tries - * - * If you print with irqs probably you can decrease the CPU load a lot using - * this setting. This is not the default because the printing is reported to - * be jerky somewhere... - * - * tunelp /dev/lp? -c 1 - * - * 11 Nov 1998, Andrea Arcangeli - */ - /* COMPATIBILITY WITH OLD KERNELS * * Under Linux 2.0 and previous versions, lp devices were bound to ports at @@ -162,6 +97,15 @@ int main(int argc, char **argv) * this case fine too. * * 15 Oct 1998, Andrea Arcangeli + * + * The so called `buggy' handshake is really the well documented + * compatibility mode IEEE1284 handshake. They changed the well known + * Centronics handshake acking in the middle of busy expecting to not + * break drivers or legacy application, while they broken linux lp + * until I fixed it reverse engineering the protocol by hand some + * month ago... + * + * 14 Dec 1998, Andrea Arcangeli */ #include @@ -175,6 +119,8 @@ int main(int argc, char **argv) #include #include #include +#include +#include #include #undef LP_STATS @@ -189,6 +135,8 @@ int main(int argc, char **argv) struct lp_struct lp_table[LP_NO]; +static unsigned int lp_count = 0; + /* Test if printer is ready */ #define LP_READY(status) ((status) & LP_PBUSY) /* Test if the printer is not acking the strobe */ @@ -197,7 +145,9 @@ struct lp_struct lp_table[LP_NO]; #define LP_NO_ERROR(status) ((status) & LP_PERRORP) #undef LP_DEBUG -#undef LP_READ_DEBUG + +/* If you want to see if you can get lp_poll working, define this. */ +#undef SUPPORT_POLL /* --- parport support ----------------------------------------- */ @@ -205,15 +155,62 @@ static int lp_preempt(void *handle) { struct lp_struct *lps = (struct lp_struct *)handle; - if (waitqueue_active (&lps->wait_q)) - wake_up_interruptible(&lps->wait_q); + if (!(lps->flags & LP_PORT_BUSY)) { + /* Let the port go. */ + clear_bit (LP_HAVE_PORT_BIT, &lps->flags); + return 0; + } + + if (!(lps->flags & LP_PORT_BUSY)) { + /* Let the port go. */ + clear_bit (LP_HAVE_PORT_BIT, &lps->flags); + return 0; + } /* Don't actually release the port now */ return 1; } -#define lp_parport_release(x) do { parport_release(lp_table[(x)].dev); } while (0); -#define lp_parport_claim(x) do { parport_claim_or_block(lp_table[(x)].dev); } while (0); +static void lp_check_data (struct lp_struct *lp) +{ +#if !defined(CONFIG_PARPORT_1284) || !defined (SUPPORT_POLL) + return; +#else + struct pardevice *dev = lp->dev; + if (!(lp->flags & LP_NO_REVERSE)) { + int err = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE); + if (err) + lp->flags |= LP_NO_REVERSE; + else { + unsigned char s = parport_read_status (dev->port); + if (s & PARPORT_STATUS_ERROR) + lp->flags &= ~LP_DATA_AVAIL; + else { + lp->flags |= LP_DATA_AVAIL; + if (waitqueue_active (&lp->dataq)) + wake_up_interruptible (&lp->dataq); + } + } + } +#endif /* IEEE 1284 support */ +} + +static void lp_parport_release (int minor) +{ + lp_check_data (&lp_table[minor]); + if (test_and_clear_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags)) + parport_release (lp_table[minor].dev); + + lp_table[minor].flags &= ~LP_PORT_BUSY; +} + +static void lp_parport_claim (int minor) +{ + if (!test_and_set_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags)) + parport_claim_or_block (lp_table[minor].dev); + + lp_table[minor].flags |= LP_PORT_BUSY; +} /* --- low-level port access ----------------------------------- */ @@ -222,29 +219,6 @@ static int lp_preempt(void *handle) #define w_ctr(x,y) do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0) #define w_dtr(x,y) do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0) -static __inline__ void lp_yield (int minor) -{ - if (!parport_yield_blocking (lp_table[minor].dev)) - { - if (current->need_resched) - schedule (); - } else - lp_table[minor].irq_missed = 1; -} - -static __inline__ void lp_schedule(int minor, long timeout) -{ - struct pardevice *dev = lp_table[minor].dev; - register unsigned long int timeslip = (jiffies - dev->time); - if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) { - lp_parport_release(minor); - lp_table[minor].irq_missed = 1; - schedule_timeout(timeout); - lp_parport_claim(minor); - } else - schedule_timeout(timeout); -} - static int lp_reset(int minor) { int retval; @@ -257,161 +231,51 @@ static int lp_reset(int minor) return retval; } -#define lp_wait(minor) udelay(LP_WAIT(minor)) - -static inline int lp_char(char lpchar, int minor) +static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long count = 0; -#ifdef LP_STATS - struct lp_stats *stats; -#endif - - if (signal_pending(current)) - return 0; - - for (;;) - { - unsigned char status; - int irq_ok = 0; - - /* - * Give a chance to other pardevice to run in the meantime. - */ - lp_yield(minor); - - status = r_str(minor); - if (LP_NO_ERROR(status)) - { - if (LP_READY(status)) - break; - - /* - * This is a crude hack that should be well known - * at least by Epson device driver developers. -arca - */ - irq_ok = (!LP_POLLED(minor) && - LP_NO_ACKING(status) && - lp_table[minor].irq_detected); - if ((LP_F(minor) & LP_TRUST_IRQ) && irq_ok) - break; - } - /* - * NOTE: if you run with irqs you _must_ use - * `tunelp /dev/lp? -c 1' to be rasonable efficient! - */ - if (++count == LP_CHAR(minor)) - { - if (irq_ok) - { - static int first_time = 1; - /* - * The printer is using a buggy handshake, so - * revert to polling to not overload the - * machine and warn the user that its printer - * could get optimized trusting the irq. -arca - */ - lp_table[minor].irq_missed = 1; - if (first_time) - { - first_time = 0; - printk(KERN_WARNING "lp%d: the " - "printing could be optimized " - "using the TRUST_IRQ flag, " - "see the top of " - "linux/drivers/char/lp.c\n", - minor); - } - } - return 0; - } - } - - w_dtr(minor, lpchar); - -#ifdef LP_STATS - stats = &LP_STAT(minor); - stats->chars++; -#endif - - /* must wait before taking strobe high, and after taking strobe - low, according spec. Some printers need it, others don't. */ - lp_wait(minor); + struct lp_struct *lp_dev = (struct lp_struct *) dev_id; + if (!(lp_dev->flags & LP_PORT_BUSY)) + /* We must have the port since we got an interrupt. */ + lp_check_data (lp_dev); + if (waitqueue_active (&lp_dev->waitq)) + wake_up_interruptible (&lp_dev->waitq); +} - /* control port takes strobe high */ - if (LP_POLLED(minor)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE); - lp_wait(minor); - w_ctr(minor, LP_PSELECP | LP_PINITP); - } else { - /* - * Epson Stylus Color generate the IRQ on the rising edge of - * strobe so clean the irq's information before playing with - * the strobe. -arca - */ - lp_table[minor].irq_detected = 0; - lp_table[minor].irq_missed = 0; - /* - * Be sure that the CPU doesn' t reorder instructions. -arca - */ - mb(); - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN); - lp_wait(minor); - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); - } +static void lp_wakeup (void *handle) +{ + struct lp_struct *lp_dev = handle; - /* - * Give to the printer a chance to put BUSY low. Really we could - * remove this because we could _guess_ that we are slower to reach - * again lp_char() than the printer to put BUSY low, but I' d like - * to remove this variable from the function I go solve - * when I read bug reports ;-). -arca - */ - lp_wait(minor); + if (lp_dev->flags & LP_PORT_BUSY) + return; -#ifdef LP_STATS - /* update waittime statistics */ - if (count > stats->maxwait) { -#ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d success after %d counts.\n", - minor, count); -#endif - stats->maxwait = count; + /* Grab the port if it can help (i.e. reverse mode is possible). */ + if (!(lp_dev->flags & LP_NO_REVERSE)) { + parport_claim (lp_dev->dev); + set_bit (LP_HAVE_PORT_BIT, &lp_dev->flags); + lp_check_data (lp_dev); + if (waitqueue_active (&lp_dev->waitq)) + wake_up_interruptible (&lp_dev->waitq); } - count *= 256; - wait = (count > stats->meanwait) ? count - stats->meanwait : - stats->meanwait - count; - stats->meanwait = (255 * stats->meanwait + count + 128) / 256; - stats->mdev = ((127 * stats->mdev) + wait + 64) / 128; -#endif - - return 1; } -static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void lp_error (int minor) { - struct lp_struct *lp_dev = (struct lp_struct *) dev_id; + int polling; - if (waitqueue_active (&lp_dev->wait_q)) - wake_up_interruptible(&lp_dev->wait_q); + if (LP_F(minor) & LP_ABORT) + return; - lp_dev->irq_detected = 1; - lp_dev->irq_missed = 0; -} - -static void lp_error(int minor) -{ - if (LP_POLLED(minor) || LP_PREEMPTED(minor)) { - current->state = TASK_INTERRUPTIBLE; - lp_parport_release(minor); - schedule_timeout(LP_TIMEOUT_POLLED); - lp_parport_claim(minor); - lp_table[minor].irq_missed = 1; - } + polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE; + if (polling) lp_parport_release (minor); + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + if (polling) lp_parport_claim (minor); + else parport_yield_blocking (lp_table[minor].dev); } static int lp_check_status(int minor) { + int error = 0; unsigned int last = lp_table[minor].last_error; unsigned char status = r_str(minor); if (status & LP_PERRORP) @@ -422,155 +286,112 @@ static int lp_check_status(int minor) last = LP_POUTPA; printk(KERN_INFO "lp%d out of paper\n", minor); } + error = -ENOSPC; } else if (!(status & LP_PSELECD)) { if (last != LP_PSELECD) { last = LP_PSELECD; printk(KERN_INFO "lp%d off-line\n", minor); } + error = -EIO; } else { if (last != LP_PERRORP) { last = LP_PERRORP; printk(KERN_INFO "lp%d on fire\n", minor); } + error = -EIO; } lp_table[minor].last_error = last; - if (last != 0) { - if (LP_F(minor) & LP_ABORT) - return 1; + if (last != 0) lp_error(minor); - } - return 0; + return error; } -static int lp_write_buf(unsigned int minor, const char *buf, int count) +static ssize_t lp_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) { - unsigned long copy_size; - unsigned long total_bytes_written = 0; - unsigned long bytes_written; - struct lp_struct *lp = &lp_table[minor]; - - if (minor >= LP_NO) - return -ENXIO; - if (lp->dev == NULL) - return -ENXIO; - - lp_table[minor].last_error = 0; - lp_table[minor].irq_detected = 0; - lp_table[minor].irq_missed = 1; - - if (LP_POLLED(minor)) - w_ctr(minor, LP_PSELECP | LP_PINITP); - else - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); - - do { - bytes_written = 0; - copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); - - if (copy_from_user(lp->lp_buffer, buf, copy_size)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - return -EFAULT; - } + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct parport *port = lp_table[minor].dev->port; + char *kbuf = lp_table[minor].lp_buffer; + ssize_t retv = 0; + ssize_t written; + size_t copy_size = count; - while (copy_size) { - if (lp_char(lp->lp_buffer[bytes_written], minor)) { - --copy_size; - ++bytes_written; #ifdef LP_STATS - lp->runchars++; -#endif - } else { - int rc = total_bytes_written + bytes_written; + if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) + lp_table[minor].runchars = 0; -#ifdef LP_STATS - if (lp->runchars > LP_STAT(minor).maxrun) - LP_STAT(minor).maxrun = lp->runchars; - LP_STAT(minor).sleeps++; + lp_table[minor].lastcall = jiffies; #endif - if (signal_pending(current)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - if (total_bytes_written + bytes_written) - return total_bytes_written + bytes_written; - else - return -EINTR; - } + /* Need to copy the data from user-space. */ + if (copy_size > LP_BUFFER_SIZE) + copy_size = LP_BUFFER_SIZE; -#ifdef LP_STATS - lp->runchars = 0; -#endif + if (copy_from_user (kbuf, buf, copy_size)) + return -EFAULT; - if (lp_check_status(minor)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - return rc ? rc : -EIO; - } + /* Claim Parport or sleep until it becomes available + */ + lp_parport_claim (minor); - if (LP_POLLED(minor) || - lp_table[minor].irq_missed) - { - lp_polling: -#if defined(LP_DEBUG) && defined(LP_STATS) - printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor)); -#endif - current->state = TASK_INTERRUPTIBLE; - lp_schedule(minor, LP_TIME(minor)); - } else { - cli(); - if (LP_PREEMPTED(minor)) - { - /* - * We can' t sleep on the interrupt - * since another pardevice need the port. - * We must check this in a cli() protected - * envinroment to avoid parport sharing - * starvation. - */ - sti(); - goto lp_polling; - } - if (!lp_table[minor].irq_detected) - interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); - sti(); - } - } + /* Go to compatibility mode. */ + parport_negotiate (port, IEEE1284_MODE_COMPAT); + + do { + /* Wait until lp_read has finished. */ + if (down_interruptible (&lp_table[minor].port_mutex)) + break; + + /* Write the data. */ + written = parport_write (port, kbuf, copy_size); + if (written >= 0) { + copy_size -= written; + count -= written; + buf += written; + retv += written; } - total_bytes_written += bytes_written; - buf += bytes_written; - count -= bytes_written; + up (&lp_table[minor].port_mutex); - } while (count > 0); + if (signal_pending (current)) { + if (retv == 0) + retv = -EINTR; - w_ctr(minor, LP_PSELECP | LP_PINITP); - return total_bytes_written; -} + break; + } -static ssize_t lp_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); - ssize_t retv; + if (copy_size > 0) { + /* incomplete write -> check error ! */ + int error = lp_check_status (minor); -#ifdef LP_STATS - if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) - lp_table[minor].runchars = 0; + if (LP_F(minor) & LP_ABORT) { + if (retv == 0) + retv = error; + break; + } - lp_table[minor].lastcall = jiffies; -#endif + parport_yield_blocking (lp_table[minor].dev); + } else if (current->need_resched) + schedule (); - /* Claim Parport or sleep until it becomes available - */ - lp_parport_claim (minor); + if (count) { + copy_size = count; + if (copy_size > LP_BUFFER_SIZE) + copy_size = LP_BUFFER_SIZE; - retv = lp_write_buf(minor, buf, count); + if (copy_from_user(kbuf, buf, copy_size)) { + if (retv == 0) + retv = -EFAULT; + break; + } + } + } while (count > 0); lp_parport_release (minor); + return retv; } @@ -579,109 +400,54 @@ static long long lp_lseek(struct file * file, long long offset, int origin) return -ESPIPE; } -#ifdef CONFIG_PRINTER_READBACK - -static int lp_read_nibble(int minor) -{ - unsigned char i; - i = r_str(minor)>>3; - i &= ~8; - if ((i & 0x10) == 0) i |= 8; - return (i & 0x0f); -} +#ifdef CONFIG_PARPORT_1284 -static void lp_read_terminate(struct parport *port) { - parport_write_control(port, (parport_read_control(port) & ~2) | 8); - /* SelectIN high, AutoFeed low */ - if (parport_wait_peripheral(port, 0x80, 0)) - /* timeout, SelectIN high, Autofeed low */ - return; - parport_write_control(port, parport_read_control(port) | 2); - /* AutoFeed high */ - parport_wait_peripheral(port, 0x80, 0x80); - /* no timeout possible, Autofeed low, SelectIN high */ - parport_write_control(port, (parport_read_control(port) & ~2) | 8); -} - -/* Status readback confirming to ieee1284 */ +/* Status readback conforming to ieee1284 */ static ssize_t lp_read(struct file * file, char * buf, - size_t length, loff_t *ppos) + size_t count, loff_t *ppos) { - int i; unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); - char *temp = buf; - ssize_t count = 0; - unsigned char z = 0; - unsigned char Byte = 0; struct parport *port = lp_table[minor].dev->port; + ssize_t retval = 0; + char *kbuf = lp_table[minor].lp_buffer; + + if (count > LP_BUFFER_SIZE) + count = LP_BUFFER_SIZE; lp_parport_claim (minor); - switch (parport_ieee1284_nibble_mode_ok(port, 0)) - { - case 0: - /* Handshake failed. */ - lp_read_terminate(port); - lp_parport_release (minor); - return -EIO; - case 1: - /* No data. */ - lp_read_terminate(port); - lp_parport_release (minor); - return 0; - default: - /* Data available. */ + if (!down_interruptible (&lp_table[minor].port_mutex)) { + for (;;) { + retval = parport_read (port, kbuf, count); - /* Hack: Wait 10ms (between events 6 and 7) */ - schedule_timeout((HZ+99)/100); - break; - } + if (retval) + break; - for (i=0; ; i++) { - parport_frob_control(port, 2, 2); /* AutoFeed high */ - if (parport_wait_peripheral(port, 0x40, 0)) { -#ifdef LP_READ_DEBUG - /* Some peripherals just time out when they've sent - all their data. */ - printk("%s: read1 timeout.\n", port->name); -#endif - parport_frob_control(port, 2, 0); /* AutoFeed low */ - break; - } - z = lp_read_nibble(minor); - parport_frob_control(port, 2, 0); /* AutoFeed low */ - if (parport_wait_peripheral(port, 0x40, 0x40)) { - printk("%s: read2 timeout.\n", port->name); - break; - } - if ((i & 1) != 0) { - Byte |= (z<<4); - if (__put_user (Byte, temp)) - { - count = -EFAULT; + if (file->f_flags & O_NONBLOCK) break; - } else { - temp++; - if (++count == length) - break; - } - /* Does the error line indicate end of data? */ - if ((parport_read_status(port) & LP_PERRORP) == - LP_PERRORP) + /* Wait for an interrupt. */ + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + + if (signal_pending (current)) { + retval = -EINTR; break; - } else - Byte=z; - } + } + } - lp_read_terminate(port); + up (&lp_table[minor].port_mutex); + } lp_parport_release (minor); - return count; + if (retval > 0 && copy_to_user (buf, kbuf, retval)) + retval = -EFAULT; + + return retval; } -#endif +#endif /* IEEE 1284 support */ static int lp_open(struct inode * inode, struct file * file) { @@ -729,7 +495,6 @@ static int lp_open(struct inode * inode, struct file * file) LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } - init_waitqueue_head(&(lp_table[minor].wait_q)); return 0; } @@ -752,7 +517,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, int retval = 0; #ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); + printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); #endif if (minor >= LP_NO) return -ENODEV; @@ -785,12 +550,6 @@ static int lp_ioctl(struct inode *inode, struct file *file, LP_F(minor) &= ~LP_CAREFUL; break; #endif - case LPTRUSTIRQ: - if (arg) - LP_F(minor) |= LP_TRUST_IRQ; - else - LP_F(minor) &= ~LP_TRUST_IRQ; - break; case LPWAIT: LP_WAIT(minor) = arg; break; @@ -834,16 +593,35 @@ static int lp_ioctl(struct inode *inode, struct file *file, return retval; } +#ifdef CONFIG_PARPORT_1284 +static unsigned int lp_poll (struct file *filp, struct poll_table_struct *wait) +{ + unsigned int minor = MINOR (filp->f_dentry->d_inode->i_rdev); + unsigned int mask = POLLOUT | POLLWRNORM; /* always writable */ + + poll_wait (filp, &lp_table[minor].dataq, wait); + + if (lp_table[minor].flags & LP_DATA_AVAIL) + mask |= POLLIN | POLLRDNORM; + + return mask; +} +#endif /* IEEE 1284 support */ + static struct file_operations lp_fops = { lp_lseek, -#ifdef CONFIG_PRINTER_READBACK +#ifdef CONFIG_PARPORT_1284 lp_read, #else NULL, #endif lp_write, NULL, /* lp_readdir */ - NULL, /* lp_poll */ +#ifdef CONFIG_PARPORT_1284 + lp_poll, +#else + NULL, +#endif lp_ioctl, NULL, /* lp_mmap */ lp_open, @@ -851,6 +629,70 @@ static struct file_operations lp_fops = { lp_release }; +/* --- support for console on the line printer ----------------- */ + +#ifdef CONFIG_LP_CONSOLE + +#define CONSOLE_LP 0 + +/* If the printer is out of paper, we can either lose the messages or + * stall until the printer is happy again. Define CONSOLE_LP_STRICT + * non-zero to get the latter behaviour. */ +#define CONSOLE_LP_STRICT 1 + +static void lp_console_write (struct console *co, const char *s, + unsigned count) +{ + struct pardevice *dev = lp_table[CONSOLE_LP].dev; + struct parport *port = dev->port; + ssize_t written; + signed long old_to; + + if (!(lp_table[CONSOLE_LP].flags & (1< 0) { + s += written; + count -= written; + } + } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); + + parport_set_timeout (dev, old_to); +} + +static kdev_t lp_console_device (struct console *c) +{ + return MKDEV(LP_MAJOR, CONSOLE_LP); +} + +static struct console lpcons = { + "lp", + lp_console_write, + NULL, + lp_console_device, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +#endif /* console on line printer */ + /* --- initialisation code ------------------------------------- */ #ifdef MODULE @@ -864,8 +706,8 @@ MODULE_PARM(reset, "i"); #else -static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; -static int reset __initdata = 0; +static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; +static int reset = 0; static int parport_ptr = 0; @@ -896,10 +738,10 @@ __initfunc(void lp_setup(char *str, int *ints)) #endif -int lp_register(int nr, struct parport *port) +static int lp_register(int nr, struct parport *port) { lp_table[nr].dev = parport_register_device(port, "lp", - lp_preempt, NULL, + lp_preempt, lp_wakeup, lp_interrupt, 0, (void *) &lp_table[nr]); @@ -916,13 +758,56 @@ int lp_register(int nr, struct parport *port) return 0; } -int lp_init(void) +static void lp_attach (struct parport *port) { - unsigned int count = 0; unsigned int i; - struct parport *port; - for(i = 0; i < LP_NO; i++) { + switch (parport_nr[0]) + { + case LP_PARPORT_UNSPEC: + case LP_PARPORT_AUTO: + if (parport_nr[0] == LP_PARPORT_AUTO && + port->probe_info[0].class != PARPORT_CLASS_PRINTER) + return; + + if (!lp_register(lp_count, port)) + if (++lp_count == LP_NO) + break; + + break; + + default: + for (i = 0; i < LP_NO; i++) { + if (port->number == parport_nr[i]) { + if (!lp_register(i, port)) + lp_count++; + break; + } + } + break; + } +} + +static void lp_detach (struct parport *port) +{ + /* Write this some day. */ +} + +static struct parport_driver lp_driver = { + "lp", + lp_attach, + lp_detach, + NULL +}; + +int __init lp_init (void) +{ + int i; + + if (parport_nr[0] == LP_PARPORT_OFF) + return 0; + + for (i = 0; i < LP_NO; i++) { lp_table[i].dev = NULL; lp_table[i].flags = 0; lp_table[i].chars = LP_INIT_CHAR; @@ -932,55 +817,37 @@ int lp_init(void) #ifdef LP_STATS lp_table[i].lastcall = 0; lp_table[i].runchars = 0; - memset(&lp_table[i].stats, 0, sizeof(struct lp_stats)); + memset (&lp_table[i].stats, 0, sizeof (struct lp_stats)); #endif - init_waitqueue_head(&lp_table[i].wait_q); lp_table[i].last_error = 0; - lp_table[i].irq_detected = 0; - lp_table[i].irq_missed = 0; + init_waitqueue_head (&lp_table[i].waitq); + init_waitqueue_head (&lp_table[i].dataq); + init_MUTEX (&lp_table[i].port_mutex); } - switch (parport_nr[0]) - { - case LP_PARPORT_OFF: - return 0; - - case LP_PARPORT_UNSPEC: - case LP_PARPORT_AUTO: - for (port = parport_enumerate(); port; port = port->next) { - - if (parport_nr[0] == LP_PARPORT_AUTO && - port->probe_info.class != PARPORT_CLASS_PRINTER) - continue; - - if (!lp_register(count, port)) - if (++count == LP_NO) - break; - } - break; + if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) { + printk ("lp: unable to get major %d\n", LP_MAJOR); + return -EIO; + } - default: - for (i = 0; i < LP_NO; i++) { - for (port = parport_enumerate(); port; - port = port->next) { - if (port->number == parport_nr[i]) { - if (!lp_register(i, port)) - count++; - break; - } - } - } - break; + if (parport_register_driver (&lp_driver)) { + printk ("lp: unable to register with parport\n"); + return -EIO; } - if (count) { - if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) { - printk("lp: unable to get major %d\n", LP_MAJOR); - return -EIO; - } - } else { - printk(KERN_INFO "lp: driver loaded but no devices found\n"); + if (!lp_count) { + printk (KERN_INFO "lp: driver loaded but no devices found\n"); +#ifndef CONFIG_PARPORT_12843 + if (parport_nr[0] == LP_PARPORT_AUTO) + 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; } @@ -1018,10 +885,18 @@ void cleanup_module(void) { unsigned int offset; + parport_unregister_driver (&lp_driver); + +#ifdef CONFIG_LP_CONSOLE + unregister_console (&lpcons); +#endif + unregister_chrdev(LP_MAJOR, "lp"); for (offset = 0; offset < LP_NO; offset++) { if (lp_table[offset].dev == NULL) continue; + if (lp_table[offset].flags & (1<state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(check_time); if (signal_pending(current)) break; diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 487c0cb39..e33a31ee2 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -2380,7 +2380,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 2ef67d1b0..9cf844c21 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -1558,7 +1558,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) char_time = MIN(char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; diff --git a/drivers/misc/Config.in b/drivers/misc/Config.in new file mode 100644 index 000000000..e2d96d0fa --- /dev/null +++ b/drivers/misc/Config.in @@ -0,0 +1,37 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +# Parport configuration. +# + +tristate 'Parallel port support' CONFIG_PARPORT +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" ]; then + bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO + fi + if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT + if [ "$CONFIG_ZORRO" != "n" ]; then + dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT + fi + else + define_bool CONFIG_PARPORT_AMIGA n + define_bool CONFIG_PARPORT_MFC3 n + fi + if [ "$CONFIG_ATARI" = "y" ]; then + dep_tristate ' Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT + else + define_bool CONFIG_PARPORT_ATARI n + fi + + # If exactly one hardware type is selected then parport will optimise away + # support for loading any others. Defeat this if the user is keen. + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + + bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 +fi diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4036ac94c..505a9d100 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -23,7 +23,13 @@ MI_OBJS := MIX_OBJS := ifeq ($(CONFIG_PARPORT),y) - L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o + L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \ + parport_procfs.o + + ifeq ($(CONFIG_PARPORT_1284),y) + L_OBJS += parport_daisy.o parport_probe.o + endif + ifeq ($(CONFIG_PARPORT_PC),y) LX_OBJS += parport_pc.o else @@ -62,7 +68,10 @@ ifeq ($(CONFIG_PARPORT),y) LX_OBJS += parport_init.o else ifeq ($(CONFIG_PARPORT),m) - MI_OBJS += parport_share.o parport_ieee1284.o + MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o + ifeq ($(CONFIG_PARPORT_1284),y) + MI_OBJS += parport_daisy.o parport_probe.o + endif ifneq ($(CONFIG_PROC_FS),n) MI_OBJS += parport_procfs.o endif diff --git a/drivers/misc/parport_arc.c b/drivers/misc/parport_arc.c index 26fca9c97..11581e253 100644 --- a/drivers/misc/parport_arc.c +++ b/drivers/misc/parport_arc.c @@ -98,41 +98,36 @@ static struct parport_operations parport_arc_ops = arc_read_control, arc_frob_control, - NULL, /* write_econtrol */ - NULL, /* read_econtrol */ - NULL, /* frob_econtrol */ - - arc_write_status, arc_read_status, - NULL, /* write_fifo */ - NULL, /* read_fifo */ - - NULL, /* change_mode */ - - NULL, /* epp_write_data */ - NULL, /* epp_read_data */ - NULL, /* epp_write_addr */ - NULL, /* epp_read_addr */ - NULL, /* epp_check_timeout */ + arc_enable_irq, + arc_disable_irq, - NULL, /* epp_write_block */ - NULL, /* epp_read_block */ + arc_data_forward, + arc_data_reverse, + + arc_interrupt, - NULL, /* ecp_write_block */ - NULL, /* epp_write_block */ - arc_init_state, arc_save_state, arc_restore_state, - arc_enable_irq, - arc_disable_irq, - arc_interrupt, - arc_inc_use_count, arc_dec_use_count, - arc_fill_inode + arc_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; /* --- Initialisation code -------------------------------- */ @@ -142,11 +137,11 @@ int parport_arc_init(void) /* Archimedes hardware provides only one port, at a fixed address */ struct parport *p; - if (check_region(PORT_BASE, 4)) + if (check_region(PORT_BASE, 1)) return 0; - - p = parport_register_port(base, IRQ_PRINTERACK, - PARPORT_DMA_NONE, &parport_arc_ops); + + p = parport_register_port (PORT_BASE, IRQ_PRINTERACK, + PARPORT_DMA_NONE, &parport_arc_ops); if (!p) return 0; @@ -158,9 +153,6 @@ int parport_arc_init(void) p->irq); parport_proc_register(p); - if (parport_probe_hook) - (*parport_probe_hook)(p); - /* Tell the high-level drivers about the port. */ parport_announce_port (p); diff --git a/drivers/misc/parport_atari.c b/drivers/misc/parport_atari.c index 5aed4994b..122213033 100644 --- a/drivers/misc/parport_atari.c +++ b/drivers/misc/parport_atari.c @@ -221,9 +221,6 @@ parport_atari_init(void) printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name); parport_proc_register(p); - if (parport_probe_hook) - (*parport_probe_hook)(p); - parport_announce_port (p); return 1; diff --git a/drivers/misc/parport_ax.c b/drivers/misc/parport_ax.c index 5baf7d25e..40ef8d0d9 100644 --- a/drivers/misc/parport_ax.c +++ b/drivers/misc/parport_ax.c @@ -164,6 +164,7 @@ parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char va void parport_ax_change_mode(struct parport *p, int m) { + /* FIXME */ parport_ax_frob_econtrol(p, 0xe0, m << 5); } @@ -201,58 +202,40 @@ parport_ax_enable_irq(struct parport *p) writel(dcsr, (unsigned long)&dma->dcsr); } -int -parport_ax_claim_resources(struct parport *p) -{ -} - void -parport_ax_init_state(struct parport_state *s) +parport_ax_init_state(struct pardevice *dev, struct parport_state *s) { - s->u.pc.ctr = 0xc; - s->u.pc.ecr = 0x0; + struct linux_ebus_dma *dma = dev->port->private_data; + + s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); + s->u.ax.ecr = 0x0; + + if (dev->irq_func) + s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr) + | EBUS_DCSR_INT_EN); + else + s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr) + & ~EBUS_DCSR_INT_EN); } void parport_ax_save_state(struct parport *p, struct parport_state *s) { - s->u.pc.ctr = parport_ax_read_control(p); - s->u.pc.ecr = parport_ax_read_econtrol(p); + struct linux_ebus_dma *dma = p->private_data; + + s->u.ax.ctr = parport_ax_read_control(p); + s->u.ax.ecr = parport_ax_read_econtrol(p); + s->u.ax.dcsr = readl((unsigned long)&dma->dcsr); } void parport_ax_restore_state(struct parport *p, struct parport_state *s) { - parport_ax_write_control(p, s->u.pc.ctr); - parport_ax_write_econtrol(p, s->u.pc.ecr); -} - -size_t -parport_ax_epp_read_block(struct parport *p, void *buf, size_t length) -{ - return 0; /* FIXME */ -} - -size_t -parport_ax_epp_write_block(struct parport *p, void *buf, size_t length) -{ - return 0; /* FIXME */ -} - -int -parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length, - void (*fn)(struct parport *, void *, size_t), - void *handle) -{ - return 0; /* FIXME */ -} + struct linux_ebus_dma *dma = p->private_data; -int -parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length, - void (*fn)(struct parport *, void *, size_t), - void *handle) -{ - return 0; /* FIXME */ + parport_ax_write_control(p, s->u.ax.ctr); + parport_ax_write_econtrol(p, s->u.ax.ecr); + writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr); } void @@ -290,41 +273,36 @@ static struct parport_operations parport_ax_ops = parport_ax_read_control, parport_ax_frob_control, - parport_ax_write_econtrol, - parport_ax_read_econtrol, - parport_ax_frob_econtrol, - - parport_ax_write_status, parport_ax_read_status, - parport_ax_write_fifo, - parport_ax_read_fifo, - - parport_ax_change_mode, - - parport_ax_write_epp, - parport_ax_read_epp, - parport_ax_write_epp_addr, - parport_ax_read_epp_addr, - parport_ax_check_epp_timeout, + parport_ax_enable_irq, + parport_ax_disable_irq, - parport_ax_epp_write_block, - parport_ax_epp_read_block, + parport_ax_data_forward, + parport_ax_data_reverse, + + parport_ax_interrupt, - parport_ax_ecp_write_block, - parport_ax_ecp_read_block, - parport_ax_init_state, parport_ax_save_state, parport_ax_restore_state, - parport_ax_enable_irq, - parport_ax_disable_irq, - parport_ax_interrupt, - parport_ax_inc_use_count, parport_ax_dec_use_count, - parport_ax_fill_inode + parport_ax_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; @@ -539,20 +517,6 @@ init_one_port(struct linux_ebus_device *dev) if (p->dma == PARPORT_DMA_AUTO) p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE; - if (p->irq != PARPORT_IRQ_NONE) { - int err; - if ((err = request_irq(p->irq, parport_ax_interrupt, - 0, p->name, p)) != 0) - return err; - else - parport_ax_enable_irq(p); - } - request_region(p->base, p->size, p->name); - if (p->modes & PARPORT_MODE_PCECR) - request_region(p->base+0x400, 3, p->name); - request_region((unsigned long)p->private_data, - sizeof(struct linux_ebus_dma), p->name); - printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->irq != PARPORT_IRQ_NONE) printk(", irq %s", __irq_itoa(p->irq)); @@ -569,12 +533,21 @@ init_one_port(struct linux_ebus_device *dev) printk("]\n"); parport_proc_register(p); + if (p->irq != PARPORT_IRQ_NONE) + if ((err = request_irq(p->irq, parport_ax_interrupt, + 0, p->name, p)) != 0) + return 0; /* @@@ FIXME */ + + request_region(p->base, p->size, p->name); + if (p->modes & PARPORT_MODE_PCECR) + request_region(p->base+0x400, 3, p->name); + request_region((unsigned long)p->private_data, + sizeof(struct linux_ebus_dma), p->name); + p->ops->write_control(p, 0x0c); p->ops->write_data(p, 0); - if (parport_probe_hook) - (*parport_probe_hook)(p); - + /* Tell the high-level drivers about the port. */ parport_announce_port (p); return 1; diff --git a/drivers/misc/parport_daisy.c b/drivers/misc/parport_daisy.c new file mode 100644 index 000000000..78b63cea2 --- /dev/null +++ b/drivers/misc/parport_daisy.c @@ -0,0 +1,474 @@ +/* + * IEEE 1284.3 Parallel port daisy chain and multiplexor code + * + * Copyright (C) 1999 Tim Waugh + * + * 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. + * + * ??-12-1998: Initial implementation. + * 31-01-1999: Make port-cloning transparent. + * 13-02-1999: Move DeviceID technique from parport_probe. + * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. + * + */ + +#include +#include +#include +#include + +#define DEBUG /* undef me for production */ + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +static struct daisydev { + struct daisydev *next; + struct parport *port; + int daisy; + int devnum; +} *topology = NULL; + +static int numdevs = 0; + +/* Forward-declaration of lower-level functions. */ +static int mux_present (struct parport *port); +static int num_mux_ports (struct parport *port); +static int select_port (struct parport *port); +static int assign_addrs (struct parport *port); + +/* Add a device to the discovered topology. */ +static void add_dev (int devnum, struct parport *port, int daisy) +{ + struct daisydev *newdev; + newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev)); + if (newdev) { + newdev->port = port; + newdev->daisy = daisy; + newdev->devnum = devnum; + newdev->next = topology; + if (!topology || topology->devnum >= devnum) + topology = newdev; + else { + struct daisydev *prev = topology; + while (prev->next && prev->next->devnum < devnum) + prev = prev->next; + newdev->next = prev->next; + prev->next = newdev; + } + } +} + +/* Clone a parport (actually, make an alias). */ +static struct parport *clone_parport (struct parport *real, int muxport) +{ + struct parport *extra = parport_register_port (real->base, + real->irq, + real->dma, + real->ops); + if (extra) { + extra->portnum = real->portnum; + extra->physport = real; + extra->muxport = muxport; + } + + return extra; +} + +/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */ +int parport_daisy_init (struct parport *port) +{ + char *deviceid; + static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; + int num_ports; + int i; + + /* Because this is called before any other devices exist, + * we don't have to claim exclusive access. */ + + /* If mux present on normal port, need to create new + * parports for each extra port. */ + if (port->muxport < 0 && mux_present (port) && + /* don't be fooled: a mux must have 2 or 4 ports. */ + ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) { + /* Leave original as port zero. */ + port->muxport = 0; + printk (KERN_INFO + "%s: 1st (default) port of %d-way multiplexor\n", + port->name, num_ports); + for (i = 1; i < num_ports; i++) { + /* Clone the port. */ + struct parport *extra = clone_parport (port, i); + if (!extra) { + if (signal_pending (current)) + break; + + schedule (); + continue; + } + + printk (KERN_INFO + "%s: %d%s port of %d-way multiplexor on %s\n", + extra->name, i + 1, th[i + 1], num_ports, + port->name); + + /* Analyse that port too. We won't recurse + forever because of the 'port->muxport < 0' + test above. */ + parport_announce_port (extra); + } + } + + if (port->muxport >= 0) + select_port (port); + + parport_daisy_deselect_all (port); + assign_addrs (port); + + /* Count the potential legacy device at the end. */ + add_dev (numdevs++, port, -1); + + /* Find out the legacy device's IEEE 1284 device ID. */ + deviceid = kmalloc (1000, GFP_KERNEL); + if (deviceid) { + parport_device_id (numdevs - 1, deviceid, 1000); + kfree (deviceid); + } + + return 0; +} + +/* Forget about devices on a physical port. */ +void parport_daisy_fini (struct parport *port) +{ + struct daisydev *dev, *prev = topology; + while (prev && prev->port == port) + prev = topology = topology->next; + + while (prev) { + dev = prev->next; + if (dev && dev->port == port) + prev->next = dev->next; + + prev = prev->next; + } + + /* Gaps in the numbering could be handled better. How should + someone enumerate through all IEEE1284.3 devices in the + topology?. */ + if (!topology) numdevs = 0; + return; } + +/* Find a device by canonical device number. */ +struct pardevice *parport_open (int devnum, const char *name, + int (*pf) (void *), void (*kf) (void *), + void (*irqf) (int, void *, struct pt_regs *), + int flags, void *handle) +{ + struct parport *port = parport_enumerate (); + struct pardevice *dev; + int portnum; + int muxnum; + int daisynum; + + if (parport_device_coords (devnum, &portnum, &muxnum, &daisynum)) + return NULL; + + while (port && ((port->portnum != portnum) || + (port->muxport != muxnum))) + port = port->next; + + if (!port) + /* No corresponding parport. */ + return NULL; + + dev = parport_register_device (port, name, pf, kf, + irqf, flags, handle); + if (dev) + dev->daisy = daisynum; + + /* Check that there really is a device to select. */ + if (daisynum >= 0) { + int selected; + parport_claim_or_block (dev); + selected = port->daisy; + parport_release (dev); + + if (selected != port->daisy) { + /* No corresponding device. */ + parport_unregister_device (dev); + return NULL; + } + } + + return dev; +} + +/* The converse of parport_open. */ +void parport_close (struct pardevice *dev) +{ + parport_unregister_device (dev); +} + +/* Convert device coordinates into a canonical device number. */ +int parport_device_num (int parport, int mux, int daisy) +{ + struct daisydev *dev = topology; + + while (dev && dev->port->portnum != parport && + dev->port->muxport != mux && dev->daisy != daisy) + dev = dev->next; + + if (!dev) + return -ENXIO; + + return dev->devnum; +} + +/* Convert a canonical device number into device coordinates. */ +int parport_device_coords (int devnum, int *parport, int *mux, int *daisy) +{ + struct daisydev *dev = topology; + + while (dev && dev->devnum != devnum) + dev = dev->next; + + if (!dev) + return -ENXIO; + + if (parport) *parport = dev->port->portnum; + if (mux) *mux = dev->port->muxport; + if (daisy) *daisy = dev->daisy; + return 0; +} + +/* Send a daisy-chain-style CPP command packet. */ +static int cpp_daisy (struct parport *port, int cmd) +{ + unsigned char s; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0x00); udelay (2); + parport_write_data (port, 0xff); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x87); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x78); udelay (2); + parport_write_data (port, cmd); udelay (2); + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (1); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + udelay (1); + s = parport_read_status (port); + parport_write_data (port, 0xff); udelay (2); + + return s; +} + +/* Send a mux-style CPP command packet. */ +static int cpp_mux (struct parport *port, int cmd) +{ + unsigned char s; + int rc; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0xf0); udelay (2); + parport_write_data (port, 0x0f); udelay (2); + parport_write_data (port, 0x52); udelay (2); + parport_write_data (port, 0xad); udelay (2); + parport_write_data (port, cmd); udelay (2); + + s = parport_read_status (port); + if (!(s & PARPORT_STATUS_ACK)) { + DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n", + port->name, cmd, s); + return -EIO; + } + + rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) | + ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) | + ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) | + ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3)); + + return rc; +} + +void parport_daisy_deselect_all (struct parport *port) +{ + cpp_daisy (port, 0x30); +} + +int parport_daisy_select (struct parport *port, int daisy, int mode) +{ + /* mode is currently ignored. FIXME? */ + return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR; +} + +static int mux_present (struct parport *port) +{ + return cpp_mux (port, 0x51) == 3; +} + +static int num_mux_ports (struct parport *port) +{ + return cpp_mux (port, 0x58); +} + +static int select_port (struct parport *port) +{ + int muxport = port->muxport; + return cpp_mux (port, 0x60 + muxport) == muxport; +} + +static int assign_addrs (struct parport *port) +{ + unsigned char s, last_dev; + unsigned char daisy; + int thisdev = numdevs; + char *deviceid; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0x00); udelay (2); + parport_write_data (port, 0xff); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x87); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x78); udelay (2); + last_dev = 0; /* We've just been speaking to a device, so we + know there must be at least _one_ out there. */ + + for (daisy = 0; daisy < 4; daisy++) { + parport_write_data (port, daisy); + udelay (2); + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (1); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + udelay (1); + + if (last_dev) + /* No more devices. */ + break; + + last_dev = !(parport_read_status (port) + & PARPORT_STATUS_BUSY); + + add_dev (numdevs++, port, daisy); + } + + parport_write_data (port, 0xff); udelay (2); + DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name, + numdevs - thisdev); + + /* Ask the new devices to introduce themselves. */ + deviceid = kmalloc (1000, GFP_KERNEL); + if (!deviceid) return 0; + + for (daisy = 0; thisdev < numdevs; thisdev++, daisy++) + parport_device_id (thisdev, deviceid, 1000); + + kfree (deviceid); + return 0; +} + +/* Find a device with a particular manufacturer and model string, + starting from a given device number. Like the PCI equivalent, + 'from' itself is skipped. */ +int parport_find_device (const char *mfg, const char *mdl, int from) +{ + struct daisydev *d = topology; /* sorted by devnum */ + + /* Find where to start. */ + while (d && d->devnum <= from) + d = d->next; + + /* Search. */ + while (d) { + struct parport_device_info *info; + info = &d->port->probe_info[1 + d->daisy]; + if ((!mfg || !strcmp (mfg, info->mfr)) && + (!mdl || !strcmp (mdl, info->model))) + break; + + d = d->next; + } + + if (d) + return d->devnum; + + return -1; +} + +/* Find a device in a particular class. Like the PCI equivalent, + 'from' itself is skipped. */ +int parport_find_class (parport_device_class cls, int from) +{ + struct daisydev *d = topology; /* sorted by devnum */ + + /* Find where to start. */ + while (d && d->devnum <= from) + d = d->next; + + /* Search. */ + while (d && d->port->probe_info[1 + d->daisy].class != cls) + d = d->next; + + if (d) + return d->devnum; + + return -1; +} diff --git a/drivers/misc/parport_ieee1284.c b/drivers/misc/parport_ieee1284.c dissimilarity index 60% index 91f6c262b..6cac030a1 100644 --- a/drivers/misc/parport_ieee1284.c +++ b/drivers/misc/parport_ieee1284.c @@ -1,71 +1,525 @@ -/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $ - * IEEE-1284 implementation for parport. - * - * Authors: Phil Blundell - * Carsten Gross - * Jose Renau - */ - -#include -#include -#include -#include - -/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to - * 25 for this. After this time we can create a timeout because the - * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are - * waiting a maximum time of 500 us busy (this is for speed). If there is - * not the right answer in this time, we call schedule and other processes - * are able to eat the time up to 40ms. - */ - -int parport_wait_peripheral(struct parport *port, unsigned char mask, - unsigned char result) -{ - int counter; - unsigned char status; - - for (counter = 0; counter < 20; counter++) { - status = parport_read_status(port); - if ((status & mask) == result) - return 0; - udelay(25); - if (current->need_resched) - schedule(); - } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); /* wait for 40ms */ - status = parport_read_status(port); - return ((status & mask) == result)?0:1; -} - -/* Test if the peripheral is IEEE 1284 compliant. - * return values are: - * 0 - handshake failed; peripheral is not compliant (or none present) - * 1 - handshake OK; IEEE1284 peripheral present but no data available - * 2 - handshake OK; IEEE1284 peripheral and data available - */ -int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) -{ - /* make sure it's a valid state, set nStrobe & nAutoFeed high */ - parport_frob_control (port, (1|2), 0); - udelay(1); - parport_write_data(port, mode); - udelay(400); - /* nSelectIn high, nAutoFd low */ - parport_frob_control(port, (2|8), 2); - if (parport_wait_peripheral(port, 0x78, 0x38)) { - parport_frob_control(port, (2|8), 8); - return 0; - } - /* nStrobe low */ - parport_frob_control (port, 1, 1); - udelay(1); /* Strobe wait */ - /* nStrobe high, nAutoFeed low, last step before transferring - * reverse data */ - parport_frob_control (port, (1|2), 0); - udelay(1); - /* Data available? */ - parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); - return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2; -} +/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $ + * IEEE-1284 implementation for parport. + * + * Authors: Phil Blundell + * Carsten Gross + * Jose Renau + * Tim Waugh (largely rewritten) + * + * This file is responsible for IEEE 1284 negotiation, and for handing + * read/write requests to low-level drivers. + */ + +#include +#include +#include +#include +#include +#include + +#define DEBUG /* undef me for production */ + +#ifdef CONFIG_LP_CONSOLE +#undef DEBUG /* Don't want a garbled console */ +#endif + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +/* Make parport_wait_peripheral wake up. + * It will be useful to call this from an interrupt handler. */ +void parport_ieee1284_wakeup (struct parport *port) +{ + up (&port->physport->ieee1284.irq); +} + +static struct parport *port_from_cookie[PARPORT_MAX]; +static void timeout_waiting_on_port (unsigned long cookie) +{ + parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]); +} + +/* Wait for a parport_ieee1284_wakeup. + * 0: success + * <0: error (exit as soon as possible) + * >0: timed out + */ +int parport_wait_event (struct parport *port, signed long timeout) +{ + int ret; + struct timer_list timer; + + if (!port->physport->cad->timeout) + /* Zero timeout is special, and we can't down() the + semaphore. */ + return 1; + + init_timer (&timer); + timer.expires = jiffies + timeout; + timer.function = timeout_waiting_on_port; + port_from_cookie[port->number % PARPORT_MAX] = port; + timer.data = port->number; + + add_timer (&timer); + ret = down_interruptible (&port->physport->ieee1284.irq); + if (!del_timer (&timer) && !ret) + /* Timed out. */ + ret = 1; + + return ret; +} + +/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to + * 25 for this. After this time we can create a timeout because the + * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are + * waiting a maximum time of 500 us busy (this is for speed). If there is + * not the right answer in this time, we call schedule and other processes + * are able to eat the time up to 40ms. + */ + +int parport_wait_peripheral(struct parport *port, + unsigned char mask, + unsigned char result) +{ + int counter; + long deadline; + unsigned char status; + + counter = port->physport->spintime; /* usecs of fast polling */ + if (!port->physport->cad->timeout) + /* A zero timeout is "special": busy wait for the + entire 35ms. */ + counter = 35000; + + /* Fast polling. + * + * This should be adjustable. + * How about making a note (in the device structure) of how long + * it takes, so we know for next time? + */ + for (counter /= 5; counter > 0; counter--) { + status = parport_read_status (port); + if ((status & mask) == result) + return 0; + if (signal_pending (current)) + return -EINTR; + if (current->need_resched) + break; + udelay(5); + } + + if (!port->physport->cad->timeout) + /* We may be in an interrupt handler, so we can't poll + * slowly anyway. */ + return 1; + + /* 40ms of slow polling. */ + deadline = jiffies + (HZ + 24) / 25; + while (time_before (jiffies, deadline)) { + int ret; + + if (signal_pending (current)) + return -EINTR; + + /* Wait for 10ms (or until an interrupt occurs if + * the handler is set) */ + if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0) + return ret; + + status = parport_read_status (port); + if ((status & mask) == result) + return 0; + + if (!ret) { + /* parport_wait_event didn't time out, but the + * peripheral wasn't actually ready either. + * Wait for another 10ms. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ+ 99) / 100); + } + } + + return 1; +} + +#ifdef CONFIG_PARPORT_1284 +/* Terminate a negotiated mode. */ +static void parport_ieee1284_terminate (struct parport *port) +{ + port = port->physport; + + port->ieee1284.phase = IEEE1284_PH_TERMINATE; + + /* EPP terminates differently. */ + switch (port->ieee1284.mode) { + case IEEE1284_MODE_EPP: + case IEEE1284_MODE_EPPSL: + case IEEE1284_MODE_EPPSWE: + /* Terminate from EPP mode. */ + + /* Event 68: Set nInit low */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + udelay (50); + + /* Event 69: Set nInit high, nSelectIn low */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + break; + + default: + /* Terminate from all other modes. */ + + /* Event 22: Set nSelectIn low, nAutoFd high */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_SELECT); + + /* Event 24: nAck goes low */ + parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); + + /* Event 25: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 27: nAck goes high */ + parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK); + + /* Event 29: Set nAutoFd high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + } + + port->ieee1284.mode = IEEE1284_MODE_COMPAT; + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n", + port->name); +} +#endif /* IEEE1284 support */ + +/* Negotiate an IEEE 1284 mode. + * return values are: + * 0 - handshake OK; IEEE1284 peripheral and mode available + * -1 - handshake failed; peripheral is not compliant (or none present) + * 1 - handshake OK; IEEE1284 peripheral present but mode not available + */ +int parport_negotiate (struct parport *port, int mode) +{ +#ifndef CONFIG_PARPORT_1284 + if (mode == IEEE1284_MODE_COMPAT) + return 0; + printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); + return -1; +#else + int m = mode; + unsigned char xflag; + + port = port->physport; + + /* Is there anything to do? */ + if (port->ieee1284.mode == mode) + return 0; + + /* Go to compability forward idle mode */ + if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) + parport_ieee1284_terminate (port); + + if (mode == IEEE1284_MODE_COMPAT) + /* Compatibility mode: no negotiation. */ + return 0; + + switch (mode) { + case IEEE1284_MODE_ECPSWE: + m = IEEE1284_MODE_ECP; + break; + case IEEE1284_MODE_EPPSL: + case IEEE1284_MODE_EPPSWE: + m = IEEE1284_MODE_EPP; + break; + case IEEE1284_MODE_BECP: + return -ENOSYS; /* FIXME (implement BECP) */ + } + + port->ieee1284.phase = IEEE1284_PH_NEGOTIATION; + + /* Start off with nStrobe and nAutoFd high, and nSelectIn low */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD + | PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + udelay(1); + + /* Event 0: Set data */ + parport_write_data (port, m); + udelay (400); /* Shouldn't need to wait this long. */ + + /* Event 1: Set nSelectIn high, nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 2: PError, Select, nFault go high, nAck goes low */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ERROR + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_ACK, + PARPORT_STATUS_ERROR + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_PAPEROUT)) { + /* Timeout */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_SELECT); + DPRINTK (KERN_DEBUG + "%s: Peripheral not IEEE1284 compliant (0x%02X)\n", + port->name, parport_read_status (port)); + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + return -1; /* Not IEEE1284 compliant */ + } + + /* Event 3: Set nStrobe low */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Event 4: Set nStrobe and nAutoFd high */ + udelay (5); + parport_frob_control (port, + PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD, + 0); + + /* Event 6: nAck goes high */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK + | PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_ACK)) { + if (parport_read_status (port) & PARPORT_STATUS_ACK) + printk (KERN_DEBUG + "%s: working around buggy peripheral: tell " + "Tim what make it is\n", port->name); + DPRINTK (KERN_DEBUG + "%s: Mode 0x%02x not supported? (0x%02x)\n", + port->name, mode, port->ops->read_status (port)); + parport_ieee1284_terminate (port); + return 1; + } + + xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; + + /* xflag should be high for all modes other than nibble (0). */ + if (mode && !xflag) { + /* Mode not supported. */ + DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n", + port->name, mode); + parport_ieee1284_terminate (port); + return 1; + } + + /* Mode is supported */ + DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode); + port->ieee1284.mode = mode; + + /* But ECP is special */ + if (mode & IEEE1284_MODE_ECP) { + port->ieee1284.phase = IEEE1284_PH_ECP_SETUP; + + /* Event 30: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 31: PError goes high. */ + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + /* (Should check that this works..) */ + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", + port->name); + } else switch (mode) { + case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + default: + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + } + + + return 0; +#endif /* IEEE1284 support */ +} + +/* Acknowledge that the peripheral has data available. + * Events 18-20, in order to get from Reverse Idle phase + * to Host Busy Data Available. + * This will most likely be called from an interrupt. + * Returns zero if data was available. + */ +#ifdef CONFIG_PARPORT_1284 +static int parport_ieee1284_ack_data_avail (struct parport *port) +{ + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + /* Event 18 didn't happen. */ + return -1; + + /* Event 20: nAutoFd goes high. */ + port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + return 0; +} +#endif /* IEEE1284 support */ + +/* Handle an interrupt. */ +void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs) +{ + struct parport *port = handle; + parport_ieee1284_wakeup (port); + +#ifdef CONFIG_PARPORT_1284 + if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) { + /* An interrupt in this phase means that data + * is now available. */ + DPRINTK (KERN_DEBUG "%s: Data available\n", port->name); + parport_ieee1284_ack_data_avail (port); + } +#endif /* IEEE1284 support */ +} + +/* Write a block of data. */ +ssize_t parport_write (struct parport *port, const void *buffer, size_t len) +{ +#ifndef CONFIG_PARPORT_1284 + return port->ops->compat_write_data (port, buffer, len, 0); +#else + ssize_t retval; + int mode = port->ieee1284.mode; + size_t (*fn) (struct parport *, const void *, size_t, int); + + /* Ignore the device-ID-request bit. */ + mode &= ~IEEE1284_DEVICEID; + + /* Use the mode we're in. */ + switch (mode) { + case IEEE1284_MODE_NIBBLE: + parport_negotiate (port, IEEE1284_MODE_COMPAT); + case IEEE1284_MODE_COMPAT: + DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n", + port->name); + fn = port->ops->compat_write_data; + break; + + case IEEE1284_MODE_EPP: + DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); + fn = port->ops->epp_write_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); + fn = port->ops->ecp_write_data; + break; + + case IEEE1284_MODE_ECPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n", + port->name); + /* The caller has specified that it must be emulated, + * even if we have ECP hardware! */ + fn = parport_ieee1284_ecp_write_data; + break; + + default: + DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name, + port->ieee1284.mode); + return -ENOSYS; + } + + retval = (*fn) (port, buffer, len, 0); + DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, + len); + return retval; +#endif /* IEEE1284 support */ +} + +/* Read a block of data. */ +ssize_t parport_read (struct parport *port, void *buffer, size_t len) +{ +#ifndef CONFIG_PARPORT_1284 + printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); + return -ENODEV; +#else + int mode = port->physport->ieee1284.mode; + size_t (*fn) (struct parport *, void *, size_t, int); + + /* Ignore the device-ID-request bit. */ + mode &= ~IEEE1284_DEVICEID; + + /* Use the mode we're in. */ + switch (mode) { + case IEEE1284_MODE_COMPAT: + if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) + return -EIO; + case IEEE1284_MODE_NIBBLE: + DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name); + fn = port->ops->nibble_read_data; + break; + + case IEEE1284_MODE_BYTE: + DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name); + fn = port->ops->byte_read_data; + break; + + case IEEE1284_MODE_EPP: + DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); + fn = port->ops->epp_read_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); + fn = port->ops->ecp_read_data; + break; + + case IEEE1284_MODE_ECPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n", + port->name); + fn = parport_ieee1284_ecp_read_data; + break; + + default: + DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name, + port->physport->ieee1284.mode); + return -ENOSYS; + } + + return (*fn) (port, buffer, len, 0); +#endif /* IEEE1284 support */ +} + +/* Set the amount of time we wait while nothing's happening. */ +long parport_set_timeout (struct pardevice *dev, long inactivity) +{ + long int old = dev->timeout; + + dev->timeout = inactivity; + + if (dev->port->physport->cad == dev) + parport_ieee1284_wakeup (dev->port); + + return old; +} diff --git a/drivers/misc/parport_ieee1284_ops.c b/drivers/misc/parport_ieee1284_ops.c new file mode 100644 index 000000000..7c4945f06 --- /dev/null +++ b/drivers/misc/parport_ieee1284_ops.c @@ -0,0 +1,736 @@ +/* IEEE-1284 operations for parport. + * + * This file is for generic IEEE 1284 operations. The idea is that + * they are used by the low-level drivers. If they have a special way + * of doing something, they can provide their own routines (and put + * the function pointers in port->ops); if not, they can just use these + * as a fallback. + * + * Note: Make no assumptions about hardware or architecture in this file! + * + * Author: Tim Waugh + */ + +#include +#include +#include +#include + +#define DEBUG /* undef me for production */ + +#ifdef CONFIG_LP_CONSOLE +#undef DEBUG /* Don't want a garbled console */ +#endif + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +/*** * + * One-way data transfer functions. * + * ***/ + +static inline +int polling (struct pardevice *dev) +{ + return dev->port->irq == PARPORT_IRQ_NONE; +} + +/* Compatibility mode. */ +size_t parport_ieee1284_write_compat (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + ssize_t count = 0; + const unsigned char *addr = buffer; + unsigned char byte; + struct pardevice *dev = port->physport->cad; + unsigned char ctl = (PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); + + if (port->irq != PARPORT_IRQ_NONE) + parport_enable_irq (port); + + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + while (count < len) { + long expire = jiffies + dev->timeout; + long wait = (HZ + 99) / 100; + unsigned char mask = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + unsigned char val = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + int i; + + /* Write the character to the data lines. */ + byte = *addr++; + parport_write_data (port, byte); + udelay (1); + + /* Wait until the peripheral's ready */ + do { + /* Is the peripheral ready yet? */ + if (!parport_wait_peripheral (port, mask, val)) + /* Skip the loop */ + goto ready; + + /* Is the peripheral upset? */ + if ((parport_read_status (port) & + (PARPORT_STATUS_PAPEROUT | + PARPORT_STATUS_SELECT | + PARPORT_STATUS_ERROR)) + != (PARPORT_STATUS_SELECT | + PARPORT_STATUS_ERROR)) + /* If nFault is asserted (i.e. no + * error) and PAPEROUT and SELECT are + * just red herrings, give the driver + * a chance to check it's happy with + * that before continuing. */ + goto stop; + + /* Have we run out of time? */ + if (!time_before (jiffies, expire)) + break; + + /* Yield the port for a while. If this is the + first time around the loop, don't let go of + the port. This way, we find out if we have + our interrupt handler called. */ + if (count && polling (dev)) { + parport_release (dev); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (wait); + parport_claim_or_block (dev); + } + else + /* We must have the device claimed here */ + parport_wait_event (port, wait); + + /* Is there a signal pending? */ + if (signal_pending (current)) + goto stop; + + /* Wait longer next time. */ + wait *= 2; + } while (time_before (jiffies, expire)); + + DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name); + break; + + ready: + /* Clear out previous irqs. */ + while (!down_trylock (&port->physport->ieee1284.irq)); + + /* Pulse strobe. */ + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (1); /* strobe */ + + parport_write_control (port, ctl); + udelay (1); /* hold */ + + /* Wait until it's received (up to 20us). */ + for (i = 0; i < 20; i++) { + if (!down_trylock (&port->physport->ieee1284.irq) || + !(parport_read_status (port) & PARPORT_STATUS_ACK)) + break; + udelay (1); + } + + count++; + + /* Let another process run if it needs to. */ + if (time_before (jiffies, expire)) + if (!parport_yield_blocking (dev) + && current->need_resched) + schedule (); + } + stop: + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return count; +} + +/* Nibble mode. */ +size_t parport_ieee1284_read_nibble (struct parport *port, + void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + unsigned char *buf = buffer; + int i; + unsigned char byte = 0; + + len *= 2; /* in nibbles */ + for (i=0; i < len; i++) { + unsigned char nibble; + + /* Does the error line indicate end of data? */ + if (((i & 1) == 0) && + (parport_read_status(port) & PARPORT_STATUS_ERROR)) { + port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + DPRINTK (KERN_DEBUG + "%s: No more nibble data (%d bytes)\n", + port->name, i/2); + + /* Go to reverse idle phase. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + } + + /* Event 7: Set nAutoFd low. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 9: nAck goes low. */ + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, 0)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG + "%s: Nibble timeout at event 9 (%d bytes)\n", + port->name, i/2); + break; + } + + + /* Read a nibble. */ + nibble = parport_read_status (port) >> 3; + nibble &= ~8; + if ((nibble & 0x10) == 0) + nibble |= 8; + nibble &= 0xf; + + /* Event 10: Set nAutoFd high. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 11: nAck goes high. */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG + "%s: Nibble timeout at event 11\n", + port->name); + break; + } + + if (i & 1) { + /* Second nibble */ + byte |= nibble << 4; + *buf++ = byte; + } else + byte = nibble; + } + + i /= 2; /* i is now in bytes */ + + if (i == len) { + /* Read the last nibble without checking data avail. */ + port = port->physport; + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + else + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + } + + return i; +#endif /* IEEE1284 support */ +} + +/* Byte mode. */ +size_t parport_ieee1284_read_byte (struct parport *port, + void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + unsigned char *buf = buffer; + ssize_t count = 0; + + for (count = 0; count < len; count++) { + unsigned char byte; + + /* Data available? */ + if (parport_read_status (port) & PARPORT_STATUS_ERROR) { + port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + DPRINTK (KERN_DEBUG + "%s: No more byte data (%d bytes)\n", + port->name, count); + + /* Go to reverse idle phase. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + } + + /* Event 7: Set nAutoFd low. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 9: nAck goes low. */ + port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA; + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + 0)) { + /* Timeout -- no more data? */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + 0); + DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n", + port->name); + break; + } + + byte = parport_read_data (port); + *buf++ = byte; + + /* Event 10: Set nAutoFd high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 11: nAck goes high. */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n", + port->name); + break; + } + + /* Event 16: Set nStrobe low. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (5); + + /* Event 17: Set nStrobe high. */ + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + } + + if (count == len) { + /* Read the last byte without checking data avail. */ + port = port->physport; + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + else + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + } + + return count; +#endif /* IEEE1284 support */ +} + +/*** * + * ECP Functions. * + * ***/ + +#ifdef CONFIG_PARPORT_1284 + +static inline +int ecp_forward_to_reverse (struct parport *port) +{ + int retval; + + /* Event 38: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + parport_data_reverse (port); + udelay (5); + + /* Event 39: Set nInit low to initiate bus reversal */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + + /* Event 40: PError goes low */ + retval = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, 0); + + if (!retval) { + DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n", + port->name); + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + } + + return retval; +} + +static inline +int ecp_reverse_to_forward (struct parport *port) +{ + int retval; + + /* Event 47: Set nInit high */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + parport_data_reverse (port); + + /* Event 49: PError goes high */ + retval = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + + if (!retval) { + parport_data_forward (port); + DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", + port->name); + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + } + + return retval; +} + +#endif /* IEEE1284 support */ + +/* ECP mode, forward channel, data. */ +size_t parport_ieee1284_ecp_write_data (struct parport *port, + const void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + const unsigned char *buf = buffer; + size_t written; + int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD; + int retry; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) + if (ecp_reverse_to_forward (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* HostAck high (data, not command) */ + parport_write_control (port, ctl); + for (written = 0; written < len; written++, buf++) { + long expire = jiffies + port->cad->timeout; + unsigned char byte; + + byte = *buf; + try_again: + parport_write_data (port, byte); + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (5); + for (retry = 0; retry < 100; retry++) { + if (!parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, 0)) + goto success; + + if (signal_pending (current)) { + parport_write_control (port, ctl); + break; + } + } + + /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ + DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); + + parport_write_control (port, ctl | PARPORT_CONTROL_INIT); + udelay (50); + if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { + /* It's buggered. */ + parport_write_control (port, ctl); + break; + } + + parport_write_control (port, ctl); + udelay (50); + if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) + break; + + DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", + port->name); + + if (time_after_eq (jiffies, expire)) break; + goto try_again; + success: + parport_write_control (port, ctl); + udelay (5); + if (parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + /* Peripheral hasn't accepted the data. */ + break; + } + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +#endif /* IEEE1284 support */ +} + +/* ECP mode, reverse channel, data. */ +size_t parport_ieee1284_ecp_read_data (struct parport *port, + void *buffer, size_t len, int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + struct pardevice *dev = port->cad; + unsigned char *buf = buffer; + int rle_count = 0; /* shut gcc up */ + int rle = 0; + ssize_t count = 0; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) + if (ecp_forward_to_reverse (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + + /* Set HostAck low to start accepting data. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + while (count < len) { + long expire = jiffies + dev->timeout; + unsigned char byte; + int command; + + /* Event 43: Peripheral sets nAck low. It can take as + long as it wants. */ + while (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* The peripheral hasn't given us data in + 35ms. If we have data to give back to the + caller, do it now. */ + if (count) + goto out; + + /* If we've used up all the time we were allowed, + give up altogether. */ + if (!time_before (jiffies, expire)) + goto out; + + /* Yield the port for a while. */ + if (count && polling (dev)) { + parport_release (dev); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ + 99) / 25); + parport_claim_or_block (dev); + } + else + /* We must have the device claimed here. */ + parport_wait_event (port, (HZ + 99) / 25); + + /* Is there a signal pending? */ + if (signal_pending (current)) + goto out; + } + + /* Is this a command? */ + if (rle) + /* The last byte was a run-length count, so + this can't be as well. */ + command = 0; + else + command = (parport_read_status (port) & + PARPORT_STATUS_BUSY) ? 1 : 0; + + /* Read the data. */ + byte = parport_read_data (port); + + /* If this is a channel command, rather than an RLE + command or a normal data byte, don't accept it. */ + if (command) { + if (byte & 0x80) { + DPRINTK (KERN_DEBUG "%s: stopping short at " + "channel command (%02x)\n", + port->name, byte); + goto out; + } + else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE) + DPRINTK (KERN_DEBUG "%s: device illegally " + "using RLE; accepting anyway\n", + port->name); + + rle_count = byte + 1; + + /* Are we allowed to read that many bytes? */ + if (rle_count > (len - count)) { + DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes " + "for next time\n", port->name, + rle_count); + break; + } + + rle = 1; + } + + /* Event 44: Set HostAck high, acknowledging handshake. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 45: The peripheral has 35ms to set nAck high. */ + if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { + /* It's gone wrong. Return what data we have + to the caller. */ + DPRINTK (KERN_DEBUG "ECP read timed out at 45\n"); + + if (command) + printk (KERN_WARNING + "%s: command ignored (%02x)\n", + port->name, byte); + + break; + } + + /* Event 46: Set HostAck low and accept the data. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* If we just read a run-length count, fetch the data. */ + if (command) + continue; + + /* If this is the byte after a run-length count, decompress. */ + if (rle) { + rle = 0; + memset (buf, byte, rle_count); + buf += rle_count; + count += rle_count; + DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n", + port->name, rle_count); + } + else + /* Normal data byte. */ + *buf++ = byte, count++; + } + + out: + return count; +#endif /* IEEE1284 support */ +} + +/* ECP mode, forward channel, commands. */ +size_t parport_ieee1284_ecp_write_addr (struct parport *port, + const void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + const unsigned char *buf = buffer; + size_t written; + int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD; + int retry; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) + if (ecp_reverse_to_forward (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* HostAck low (command, not data) */ + parport_write_control (port, ctl); + for (written = 0; written < len; written++, buf++) { + long expire = jiffies + port->cad->timeout; + unsigned char byte; + + byte = *buf; + try_again: + parport_write_data (port, byte); + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (5); + for (retry = 0; retry < 100; retry++) { + if (!parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, 0)) + goto success; + + if (signal_pending (current)) { + parport_write_control (port, ctl); + break; + } + } + + /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ + DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); + + parport_write_control (port, ctl | PARPORT_CONTROL_INIT); + udelay (50); + if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { + /* It's buggered. */ + parport_write_control (port, ctl); + break; + } + + parport_write_control (port, ctl); + udelay (50); + if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) + break; + + DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", + port->name); + + if (time_after_eq (jiffies, expire)) break; + goto try_again; + success: + parport_write_control (port, ctl); + udelay (5); + if (parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + /* Peripheral hasn't accepted the data. */ + break; + } + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +#endif /* IEEE1284 support */ +} + +/*** * + * EPP functions. * + * ***/ + +/* EPP mode, forward channel, data. */ +size_t parport_ieee1284_epp_write_data (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + return 0; /* FIXME */ +} + +/* EPP mode, reverse channel, data. */ +size_t parport_ieee1284_epp_read_data (struct parport *port, + void *buffer, size_t len, + int flags) +{ + return 0; /* FIXME */ +} + +/* EPP mode, forward channel, addresses. */ +size_t parport_ieee1284_epp_write_addr (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + return 0; /* FIXME */ +} + +/* EPP mode, reverse channel, addresses. */ +size_t parport_ieee1284_epp_read_addr (struct parport *port, + void *buffer, size_t len, + int flags) +{ + return 0; /* FIXME */ +} diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c index c250c77a7..974dcf725 100644 --- a/drivers/misc/parport_init.c +++ b/drivers/misc/parport_init.c @@ -22,7 +22,7 @@ static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY }; -static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO }; +static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); extern int parport_ax_init(void); @@ -119,10 +119,7 @@ __initfunc(int parport_init(void)) if (io[0] == PARPORT_DISABLE) return 1; -#ifdef CONFIG_PNP_PARPORT - parport_probe_hook = &parport_probe_one; -#endif -#ifdef CONFIG_SYSCTL +#ifdef CONFIG_SYSCTL parport_default_proc_register (); #endif @@ -161,13 +158,42 @@ EXPORT_SYMBOL(parport_unregister_driver); EXPORT_SYMBOL(parport_register_device); EXPORT_SYMBOL(parport_unregister_device); EXPORT_SYMBOL(parport_enumerate); -EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok); +EXPORT_SYMBOL(parport_negotiate); +EXPORT_SYMBOL(parport_write); +EXPORT_SYMBOL(parport_read); +EXPORT_SYMBOL(parport_ieee1284_wakeup); EXPORT_SYMBOL(parport_wait_peripheral); +EXPORT_SYMBOL(parport_wait_event); +EXPORT_SYMBOL(parport_set_timeout); +EXPORT_SYMBOL(parport_ieee1284_interrupt); +EXPORT_SYMBOL(parport_ieee1284_ecp_write_data); +EXPORT_SYMBOL(parport_ieee1284_ecp_read_data); +EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr); +EXPORT_SYMBOL(parport_ieee1284_write_compat); +EXPORT_SYMBOL(parport_ieee1284_read_nibble); +EXPORT_SYMBOL(parport_ieee1284_read_byte); +EXPORT_SYMBOL(parport_ieee1284_epp_write_data); +EXPORT_SYMBOL(parport_ieee1284_epp_read_data); +EXPORT_SYMBOL(parport_ieee1284_epp_write_addr); +EXPORT_SYMBOL(parport_ieee1284_epp_read_addr); EXPORT_SYMBOL(parport_proc_register); EXPORT_SYMBOL(parport_proc_unregister); -EXPORT_SYMBOL(parport_probe_hook); +EXPORT_SYMBOL(parport_device_proc_register); +EXPORT_SYMBOL(parport_device_proc_unregister); +EXPORT_SYMBOL(parport_default_proc_register); +EXPORT_SYMBOL(parport_default_proc_unregister); EXPORT_SYMBOL(parport_parse_irqs); EXPORT_SYMBOL(parport_parse_dmas); +#ifdef CONFIG_PARPORT_12843 +EXPORT_SYMBOL(parport_open); +EXPORT_SYMBOL(parport_close); +EXPORT_SYMBOL(parport_device_id); +EXPORT_SYMBOL(parport_device_num); +EXPORT_SYMBOL(parport_device_coords); +EXPORT_SYMBOL(parport_daisy_deselect_all); +EXPORT_SYMBOL(parport_daisy_select); +EXPORT_SYMBOL(parport_daisy_init); +#endif void inc_parport_count(void) { diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c index 63b67f3ba..bfba506ea 100644 --- a/drivers/misc/parport_pc.c +++ b/drivers/misc/parport_pc.c @@ -9,6 +9,7 @@ * based on work by Grant Guenther and Phil Blundell. * * Cleaned up include files - Russell King + * DMA support - Bert De Jonghe * Better EPP probing - Carlos Henrique Bauer */ @@ -46,9 +47,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -57,12 +60,138 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 +/* ECR modes */ +#define ECR_SPP 00 +#define ECR_PS2 01 +#define ECR_PPF 02 +#define ECR_ECP 03 +#define ECR_EPP 04 +#define ECR_VND 05 +#define ECR_TST 06 +#define ECR_CNF 07 + static int user_specified __initdata = 0; +/* frob_control, but for ECR */ +static void frob_econtrol (struct parport *pb, unsigned char m, + unsigned char v) +{ + outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb)); +} + +#ifdef CONFIG_PARPORT_1284 +/* Safely change the mode bits in the ECR */ +static int change_mode(struct parport *p, int m) +{ + const struct parport_pc_private *priv = p->physport->private_data; + int ecr = ECONTROL(p); + unsigned char oecr; + int mode; + + if (!priv->ecr) { + printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); + return 0; + } + + /* Bits <7:5> contain the mode. */ + oecr = inb (ecr); + mode = (oecr >> 5) & 0x7; + if (mode == m) return 0; + if (mode && m) + /* We have to go through mode 000 */ + change_mode (p, ECR_SPP); + + if (m < 2 && !(parport_read_control (p) & 0x20)) { + /* This mode resets the FIFO, so we may + * have to wait for it to drain first. */ + long expire = jiffies + p->physport->cad->timeout; + int counter; + switch (mode) { + case ECR_PPF: /* Parallel Port FIFO mode */ + case ECR_ECP: /* ECP Parallel Port mode */ + /* Busy wait for 200us */ + for (counter = 0; counter < 40; counter++) { + if (inb (ECONTROL (p)) & 0x01) + break; + if (signal_pending (current)) break; + udelay (5); + } + + /* Poll slowly. */ + while (!(inb (ECONTROL (p)) & 0x01)) { + if (time_after_eq (jiffies, expire)) + /* The FIFO is stuck. */ + return -EBUSY; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ + 99) / 100); + if (signal_pending (current)) + break; + } + } + } + + /* Set the mode. */ + oecr &= ~(7 << 5); + oecr |= m << 5; + outb (oecr, ecr); + return 0; +} + +/* Find FIFO lossage; FIFO is reset */ +static int get_fifo_residue (struct parport *p) +{ + int residue; + int cnfga; + const struct parport_pc_private *priv = p->physport->private_data; + + /* Prevent further data transfer. */ + parport_frob_control (p, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (residue = priv->fifo_depth; ; residue--) { + if (inb (ECONTROL (p)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (p)); + } + + printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, + residue); + + /* Reset the FIFO. */ + frob_econtrol (p, 0xe0, 0x20); + parport_frob_control (p, PARPORT_CONTROL_STROBE, 0); + + /* Now change to config mode and clean up. FIXME */ + frob_econtrol (p, 0xe0, 0xe0); + cnfga = inb (CONFIGA (p)); + printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); + + if (!(cnfga & (1<<2))) { + printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name); + residue++; + } + + /* Don't care about partial PWords until support is added for + * PWord != 1 byte. */ + + /* Back to PS2 mode. */ + frob_econtrol (p, 0xe0, 0x20); + + return residue; +} + +#endif /* IEEE 1284 support */ + /* * Clear TIMEOUT BIT in EPP MODE + * + * This is also used in SPP detection. */ -int parport_pc_epp_clear_timeout(struct parport *pb) +static int clear_epp_timeout(struct parport *pb) { unsigned char r; @@ -72,187 +201,719 @@ int parport_pc_epp_clear_timeout(struct parport *pb) /* To clear timeout some chips require double read */ parport_pc_read_status(pb); r = parport_pc_read_status(pb); - parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */ - parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */ + outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ + outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ r = parport_pc_read_status(pb); return !(r & 0x01); } +/* + * Access functions. + * + * These aren't static because they may be used by the parport_xxx_yyy + * macros. extern __inline__ versions of several of these are in + * parport_pc.h. + */ + static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { parport_generic_irq(irq, (struct parport *) dev_id, regs); } -void parport_pc_write_epp(struct parport *p, unsigned char d) +void parport_pc_write_data(struct parport *p, unsigned char d) { - outb(d, EPPDATA(p)); + outb (d, DATA (p)); } -unsigned char parport_pc_read_epp(struct parport *p) +unsigned char parport_pc_read_data(struct parport *p) { - return inb(EPPDATA(p)); + return inb (DATA (p)); } -void parport_pc_write_epp_addr(struct parport *p, unsigned char d) +unsigned char __frob_control (struct parport *p, unsigned char mask, + unsigned char val) { - outb(d, EPPADDR(p)); + 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 */ } -unsigned char parport_pc_read_epp_addr(struct parport *p) +void parport_pc_write_control(struct parport *p, unsigned char d) { - return inb(EPPADDR(p)); -} + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + /* Take this out when drivers have adapted to the newer interface. */ + if (d & 0x20) { + printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); + parport_pc_data_reverse (p); + } -int parport_pc_check_epp_timeout(struct parport *p) -{ - if (!(inb(STATUS(p)) & 1)) - return 0; - parport_pc_epp_clear_timeout(p); - return 1; + __frob_control (p, wm, d & wm); } -unsigned char parport_pc_read_configb(struct parport *p) +unsigned char parport_pc_read_control(struct parport *p) { - return inb(CONFIGB(p)); + const struct parport_pc_private *priv = p->physport->private_data; + return priv->ctr; /* Use soft copy */ } -void parport_pc_write_data(struct parport *p, unsigned char d) +unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, + unsigned char val) { - outb(d, DATA(p)); + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + /* Take this out when drivers have adapted to the newer interface. */ + if (mask & 0x20) { + printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); + parport_pc_data_reverse (p); + } + + /* Restrict mask and val to control lines. */ + mask &= wm; + val &= wm; + + return __frob_control (p, mask, val); } -unsigned char parport_pc_read_data(struct parport *p) +unsigned char parport_pc_read_status(struct parport *p) { - return inb(DATA(p)); + return inb (STATUS (p)); } -void parport_pc_write_control(struct parport *p, unsigned char d) +void parport_pc_disable_irq(struct parport *p) { - struct parport_pc_private *priv = p->private_data; - priv->ctr = d;/* update soft copy */ - outb(d, CONTROL(p)); + __frob_control (p, 0x10, 0); } -unsigned char parport_pc_read_control(struct parport *p) +void parport_pc_enable_irq(struct parport *p) { - struct parport_pc_private *priv = p->private_data; - return priv->ctr; + __frob_control (p, 0x10, 0x10); } -unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) +void parport_pc_data_forward (struct parport *p) { - struct parport_pc_private *priv = p->private_data; - unsigned char ctr = priv->ctr; - ctr = (ctr & ~mask) ^ val; - outb (ctr, CONTROL(p)); - return priv->ctr = ctr; /* update soft copy */ + __frob_control (p, 0x20, 0); } -void parport_pc_write_status(struct parport *p, unsigned char d) +void parport_pc_data_reverse (struct parport *p) { - outb(d, STATUS(p)); + __frob_control (p, 0x20, 0x20); } -unsigned char parport_pc_read_status(struct parport *p) +void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) { - return inb(STATUS(p)); + struct parport_pc_private *priv = dev->port->physport->private_data; + priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); + s->u.pc.ecr = 0x24; } -void parport_pc_write_econtrol(struct parport *p, unsigned char d) +void parport_pc_save_state(struct parport *p, struct parport_state *s) { - outb(d, ECONTROL(p)); + const struct parport_pc_private *priv = p->physport->private_data; + s->u.pc.ctr = inb (CONTROL (p)); + if (priv->ecr) + s->u.pc.ecr = inb (ECONTROL (p)); } -unsigned char parport_pc_read_econtrol(struct parport *p) +void parport_pc_restore_state(struct parport *p, struct parport_state *s) { - return inb(ECONTROL(p)); + const struct parport_pc_private *priv = p->physport->private_data; + outb (s->u.pc.ctr, CONTROL (p)); + if (priv->ecr) + outb (s->u.pc.ecr, ECONTROL (p)); } -unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) +#ifdef CONFIG_PARPORT_1284 +static size_t parport_pc_epp_read_data (struct parport *port, void *buf, + size_t length, int flags) { - unsigned char old = inb(ECONTROL(p)); - outb(((old & ~mask) ^ val), ECONTROL(p)); - return old; + size_t got = 0; + for (; got < length; got++) { + *((char*)buf)++ = inb (EPPDATA(port)); + if (inb (STATUS(port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return got; } -void parport_pc_change_mode(struct parport *p, int m) +static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, + size_t length, int flags) { - /* FIXME */ + size_t written = 0; + for (; written < length; written++) { + outb (*((char*)buf)++, EPPDATA(port)); + if (inb (STATUS(port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; } -void parport_pc_write_fifo(struct parport *p, unsigned char v) +static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, + size_t length, int flags) { - outb (v, CONFIGA(p)); + size_t got = 0; + for (; got < length; got++) { + *((char*)buf)++ = inb (EPPADDR (port)); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return got; } -unsigned char parport_pc_read_fifo(struct parport *p) +static size_t parport_pc_epp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) { - return inb (CONFIGA(p)); + size_t written = 0; + for (; written < length; written++) { + outb (*((char*)buf)++, EPPADDR (port)); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; } -void parport_pc_disable_irq(struct parport *p) +static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, + size_t length, int flags) { - parport_pc_frob_control(p, 0x10, 0); + size_t got; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + got = parport_pc_epp_read_data (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return got; } -void parport_pc_enable_irq(struct parport *p) +static size_t parport_pc_ecpepp_write_data (struct parport *port, + const void *buf, size_t length, + int flags) { - parport_pc_frob_control(p, 0x10, 0x10); + size_t written; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + written = parport_pc_epp_write_data (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return written; } -void parport_pc_init_state(struct parport_state *s) +static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, + size_t length, int flags) { - s->u.pc.ctr = 0xc; - s->u.pc.ecr = 0x0; + size_t got; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + got = parport_pc_epp_read_addr (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return got; } -void parport_pc_save_state(struct parport *p, struct parport_state *s) +static size_t parport_pc_ecpepp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) { - s->u.pc.ctr = parport_pc_read_control(p); - if (p->modes & PARPORT_MODE_PCECR) - s->u.pc.ecr = parport_pc_read_econtrol(p); + size_t written; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + written = parport_pc_epp_write_addr (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return written; } +#endif /* IEEE 1284 support */ -void parport_pc_restore_state(struct parport *p, struct parport_state *s) +#ifdef CONFIG_PARPORT_PC_FIFO +static size_t parport_pc_fifo_write_block_pio (struct parport *port, + const void *buf, size_t length) { - parport_pc_write_control(p, s->u.pc.ctr); - if (p->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(p, s->u.pc.ecr); + int ret = 0; + const unsigned char *bufp = buf; + size_t left = length; + long expire = jiffies + port->physport->cad->timeout; + const int fifo = FIFO (port); + int poll_for = 8; /* 80 usecs */ + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + + /* Forward mode. */ + parport_pc_data_forward (port); + + while (left) { + unsigned char byte; + unsigned char ecrval = inb (ECONTROL (port)); + int i = 0; + + if (current->need_resched && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); + break; + } + + if (ecrval & 0x02) { + /* FIFO is full. Wait for interrupt. */ + + /* Clear serviceIntr */ + outb (ecrval & ~(1<<2), ECONTROL (port)); + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + ecrval = inb (ECONTROL (port)); + if (!(ecrval & (1<<2))) { + if (current->need_resched && + time_before (jiffies, expire)) + schedule (); + + goto false_alarm; + } + + continue; + } + + /* Can't fail now. */ + expire = jiffies + port->cad->timeout; + + poll: + if (signal_pending (current)) + break; + + if (ecrval & 0x01) { + /* FIFO is empty. Blast it full. */ + const int n = left < fifo_depth ? left : fifo_depth; + outsb (fifo, bufp, n); + bufp += n; + left -= n; + + /* Adjust the poll time. */ + if (i < (poll_for - 2)) poll_for--; + continue; + } else if (i++ < poll_for) { + udelay (10); + ecrval = inb (ECONTROL (port)); + goto poll; + } + + /* Half-full (call me an optimist) */ + byte = *bufp++; + outb (byte, fifo); + left--; + } + + return length - left; } -size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length) +static size_t parport_pc_fifo_write_block_dma (struct parport *port, + const void *buf, size_t length) { - size_t got = 0; - for (; got < length; got++) { - *((char*)buf)++ = inb (EPPDATA(p)); - if (inb (STATUS(p)) & 0x01) + int ret = 0; + unsigned long dmaflag; + size_t left = length; + const struct parport_pc_private *priv = port->physport->private_data; + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + + /* Forward mode. */ + parport_pc_data_forward (port); + + while (left) { + long expire = jiffies + port->physport->cad->timeout; + + size_t count = left; + + if (count > PAGE_SIZE) + count = PAGE_SIZE; + + memcpy(priv->dma_buf, buf, count); + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + set_dma_mode(port->dma, DMA_MODE_WRITE); + set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf)); + set_dma_count(port->dma, count); + + /* Set DMA mode */ + frob_econtrol (port, 1<<3, 1<<3); + + /* Clear serviceIntr */ + frob_econtrol (port, 1<<2, 0); + + enable_dma(port->dma); + release_dma_lock(dmaflag); + + /* assume DMA will be successful */ + left -= count; + buf += count; + + /* Wait for interrupt. */ + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + /* Is serviceIntr set? */ + if (!(inb (ECONTROL (port)) & (1<<2))) { + if (current->need_resched) + schedule (); + + goto false_alarm; + } + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + count = get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + if (current->need_resched) + /* Can't yield the port. */ + schedule (); + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); break; + } + + /* update for possible DMA residue ! */ + buf -= count; + left += count; } - return got; + + /* Maybe got here through break, so adjust for DMA residue! */ + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + left += get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + /* Turn off DMA mode */ + frob_econtrol (port, 1<<3, 0); + + return length - left; } -size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length) +/* Parallel Port FIFO mode (ECP chipsets) */ +size_t parport_pc_compat_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) { - size_t written = 0; - for (; written < length; written++) { - outb (*((char*)buf)++, EPPDATA(p)); - if (inb (STATUS(p)) & 0x01) - break; + size_t written; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->physport->cad->timeout) + return parport_ieee1284_write_compat (port, buf, + length, flags); + + /* Set up parallel port FIFO mode.*/ + change_mode (port, ECR_PPF); /* Parallel port FIFO */ + parport_pc_data_forward (port); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + const struct parport_pc_private *priv = + port->physport->private_data; + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (port)); + } + + /* Reset the FIFO. */ + frob_econtrol (port, 0xe0, 0); + + /* De-assert strobe. */ + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); } + + parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + return written; } -int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) +/* ECP */ +#ifdef CONFIG_PARPORT_1284 +size_t parport_pc_ecp_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) { - return -ENOSYS; /* FIXME */ + size_t written; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->physport->cad->timeout) + return parport_ieee1284_ecp_write_data (port, buf, + length, flags); + + /* Switch to forward mode if necessary. */ + if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { + /* Event 47: Set nInit high. */ + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + + /* Event 40: PError goes high. */ + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + } + + /* Set up ECP parallel port mode.*/ + change_mode (port, ECR_ECP); /* ECP FIFO */ + parport_pc_data_forward (port); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + const struct parport_pc_private *priv = + port->physport->private_data; + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (port)); + } + + /* Reset the FIFO. */ + frob_econtrol (port, 0xe0, 0); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + + /* Host transfer recovery. */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + parport_pc_data_reverse (port); + parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + } + + parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; } -int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) +size_t parport_pc_ecp_read_block_pio (struct parport *port, + void *buf, size_t length, int flags) { - return -ENOSYS; /* FIXME */ + size_t left = length; + size_t fifofull; + const int fifo = FIFO(port); + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + char *bufp = buf; + + port = port->physport; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->cad->timeout) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + fifofull = fifo_depth; + if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) + /* If the peripheral is allowed to send RLE compressed + * data, it is possible for a byte to expand to 128 + * bytes in the FIFO. */ + fifofull = 128; + + /* If the caller wants less than a full FIFO's worth of data, + * go through software emulation. Otherwise we may have to through + * away data. */ + if (length < fifofull) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + /* Switch to reverse mode if necessary. */ + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { + /* Event 38: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + parport_pc_data_reverse (port); + udelay (5); + + /* Event 39: Set nInit low to initiate bus reversal */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + + /* Event 40: PError goes low */ + parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + } + + /* Set up ECP parallel port mode.*/ + change_mode (port, ECR_ECP); /* ECP FIFO */ + parport_pc_data_reverse (port); + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + + /* Do the transfer. */ + while (left > fifofull) { + int ret; + long int expire = jiffies + port->cad->timeout; + unsigned char ecrval = inb (ECONTROL (port)); + + if (current->need_resched && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* At this point, the FIFO may already be full. + * Ideally, we'd be able to tell the port to hold on + * for a second while we empty the FIFO, and we'd be + * able to ensure that no data is lost. I'm not sure + * that's the case. :-( It might be that you can play + * games with STB, as in the forward case; someone should + * look at a datasheet. */ + + if (ecrval & 0x01) { + /* FIFO is empty. Wait for interrupt. */ + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG + "Somebody wants the port\n"); + break; + } + + /* Clear serviceIntr */ + outb (ecrval & ~(1<<2), ECONTROL (port)); + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + ecrval = inb (ECONTROL (port)); + if (!(ecrval & (1<<2))) { + if (current->need_resched && + time_before (jiffies, expire)) + schedule (); + + goto false_alarm; + } + + continue; + } + + if (ecrval & 0x02) { + /* FIFO is full. */ + insb (fifo, bufp, fifo_depth); + bufp += fifo_depth; + left -= fifo_depth; + continue; + } + + *bufp++ = inb (fifo); + left--; + } + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + int lost = get_fifo_residue (port); + printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name, + lost); + } + + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + + return length - left; } +#endif /* IEEE 1284 support */ + +#endif /* Allowed to use FIFO/DMA */ + void parport_pc_inc_use_count(void) { #ifdef MODULE @@ -269,6 +930,7 @@ void parport_pc_dec_use_count(void) static void parport_pc_fill_inode(struct inode *inode, int fill) { + /* Is this still needed? -tim */ #ifdef MODULE if (fill) MOD_INC_USE_COUNT; @@ -286,46 +948,39 @@ struct parport_operations parport_pc_ops = parport_pc_read_control, parport_pc_frob_control, - parport_pc_write_econtrol, - parport_pc_read_econtrol, - parport_pc_frob_econtrol, - - parport_pc_write_status, parport_pc_read_status, - parport_pc_write_fifo, - parport_pc_read_fifo, - - parport_pc_change_mode, - - parport_pc_write_epp, - parport_pc_read_epp, - parport_pc_write_epp_addr, - parport_pc_read_epp_addr, - parport_pc_check_epp_timeout, + parport_pc_enable_irq, + parport_pc_disable_irq, - parport_pc_epp_write_block, - parport_pc_epp_read_block, + parport_pc_data_forward, + parport_pc_data_reverse, - parport_pc_ecp_write_block, - parport_pc_ecp_read_block, - + parport_pc_interrupt, parport_pc_init_state, parport_pc_save_state, parport_pc_restore_state, - parport_pc_enable_irq, - parport_pc_disable_irq, - parport_pc_interrupt, - parport_pc_inc_use_count, parport_pc_dec_use_count, - parport_pc_fill_inode + parport_pc_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; /* --- Mode detection ------------------------------------- */ - /* * Checks for port existence, all ports support SPP MODE */ @@ -339,22 +994,23 @@ static int __init parport_SPP_supported(struct parport *pb) * that does not even respond to SPP cycles if an EPP * timeout is pending */ - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); /* Do a simple read-write test to make sure the port exists. */ w = 0xc; - parport_pc_write_control(pb, w); + outb (w, CONTROL (pb)); - /* Can we read from the control register? Some ports don't - * allow reads, so read_control just returns a software - * copy. Some ports _do_ allow reads, so bypass the software - * copy here. In addition, some bits aren't writable. */ + /* Is there a control register that we can read from? Some + * ports don't allow reads, so read_control just returns a + * software copy. Some ports _do_ allow reads, so bypass the + * software copy here. In addition, some bits aren't + * writable. */ r = inb (CONTROL (pb)); if ((r & 0xf) == w) { w = 0xe; - parport_pc_write_control (pb, w); - r = inb (CONTROL(pb)); - parport_pc_write_control (pb, 0xc); + outb (w, CONTROL (pb)); + r = inb (CONTROL (pb)); + outb (0xc, CONTROL (pb)); if ((r & 0xf) == w) return PARPORT_MODE_PCSPP; } @@ -379,20 +1035,20 @@ static int __init parport_SPP_supported(struct parport *pb) } if (user_specified) - /* Didn't work with 0xaa, but the user is convinced - * this is the place. */ + /* Didn't work, but the user is convinced this is the + * place. */ printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n", pb->base, w, r); /* It's possible that we can't read the control register or - the data register. In that case just believe the user. */ + * the data register. In that case just believe the user. */ if (user_specified) return PARPORT_MODE_PCSPP; return 0; } -/* Check for ECP +/* Check for ECR * * Old style XT ports alias io ports every 0x400, hence accessing ECR * on these cards actually accesses the CTR. @@ -401,81 +1057,226 @@ static int __init parport_SPP_supported(struct parport *pb) * regardless of what is written here if the card does NOT support * ECP. * - * We will write 0x2c to ECR and 0xcc to CTR since both of these - * values are "safe" on the CTR since bits 6-7 of CTR are unused. + * We first check to see if ECR is the same as CTR. If not, the low + * two bits of ECR aren't writable, so we check by writing ECR and + * reading it back to see if it's what we expect. */ static int __init parport_ECR_present(struct parport *pb) { - unsigned char r; + struct parport_pc_private *priv = pb->private_data; + unsigned char r = 0xc; - parport_pc_write_control (pb, 0xc); - r = parport_pc_read_control(pb); - if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) { - parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ + priv->ecr = 0; + outb (r, CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { + outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ - r = parport_pc_read_control(pb); - if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2)) + r = inb (CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2)) goto no_reg; /* Sure that no ECR register exists */ } - if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1) + if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) goto no_reg; - parport_pc_write_econtrol(pb, 0x34); - if (parport_pc_read_econtrol(pb) != 0x35) + outb (0x34, ECONTROL (pb)); + if (inb (ECONTROL (pb)) != 0x35) goto no_reg; - parport_pc_write_control(pb, 0xc); - - /* Go to mode 000; SPP, reset FIFO */ - parport_pc_frob_econtrol (pb, 0xe0, 0x00); + priv->ecr = 1; + outb (0xc, CONTROL (pb)); - return PARPORT_MODE_PCECR; + /* Go to mode 000 */ + frob_econtrol (pb, 0xe0, ECR_SPP << 5); + + return 1; no_reg: - parport_pc_write_control (pb, 0xc); - return 0; + outb (0xc, CONTROL (pb)); + return 0; +} + +#ifdef CONFIG_PARPORT_1284 +/* Detect PS/2 support. + * + * Bit 5 (0x20) sets the PS/2 data direction; setting this high + * allows us to read data from the data lines. In theory we would get back + * 0xff but any peripheral attached to the port may drag some or all of the + * lines down to zero. So if we get back anything that isn't the contents + * of the data register we deem PS/2 support to be present. + * + * Some SPP ports have "half PS/2" ability - you can't turn off the line + * drivers, but an external peripheral with sufficiently beefy drivers of + * its own can overpower them and assert its own levels onto the bus, from + * where they can then be read back as normal. Ports with this property + * and the right type of device attached are likely to fail the SPP test, + * (as they will appear to have stuck bits) and so the fact that they might + * be misdetected here is rather academic. + */ + +static int __init parport_PS2_supported(struct parport *pb) +{ + int ok = 0; + + clear_epp_timeout(pb); + + /* try to tri-state the buffer */ + parport_pc_data_reverse (pb); + + parport_pc_write_data(pb, 0x55); + if (parport_pc_read_data(pb) != 0x55) ok++; + + parport_pc_write_data(pb, 0xaa); + if (parport_pc_read_data(pb) != 0xaa) ok++; + + /* cancel input mode */ + parport_pc_data_forward (pb); + + if (ok) + pb->modes |= PARPORT_MODE_TRISTATE; + else { + struct parport_pc_private *priv = pb->private_data; + priv->ctr_writable &= ~0x20; + } + + return ok; } static int __init parport_ECP_supported(struct parport *pb) { int i; - unsigned char oecr; - + int config; + int pword; + struct parport_pc_private *priv = pb->private_data; + /* If there is no ECR, we have no hope of supporting ECP. */ - if (!(pb->modes & PARPORT_MODE_PCECR)) + if (!priv->ecr) return 0; - oecr = parport_pc_read_econtrol(pb); + /* Find out FIFO depth */ + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */ + for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++) + outb (0xaa, FIFO (pb)); + /* * Using LGS chipset it uses ECR register, but * it doesn't support ECP or FIFO MODE */ + if (i == 1024) { + outb (ECR_SPP << 5, ECONTROL (pb)); + return 0; + } + + priv->fifo_depth = i; + printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i); + + /* Find out writeIntrThreshold */ + frob_econtrol (pb, 1<<2, 1<<2); + frob_econtrol (pb, 1<<2, 0); + for (i = 1; i <= priv->fifo_depth; i++) { + inb (FIFO (pb)); + udelay (50); + if (inb (ECONTROL (pb)) & (1<<2)) + break; + } + + if (i <= priv->fifo_depth) + printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n", + pb->base, i); + else + /* Number of bytes we know we can write if we get an + interrupt. */ + i = 0; + + priv->writeIntrThreshold = i; + + /* Find out readIntrThreshold */ + frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */ + parport_pc_data_reverse (pb); + frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */ + frob_econtrol (pb, 1<<2, 1<<2); + frob_econtrol (pb, 1<<2, 0); + for (i = 1; i <= priv->fifo_depth; i++) { + outb (0xaa, FIFO (pb)); + if (inb (ECONTROL (pb)) & (1<<2)) + break; + } + + if (i <= priv->fifo_depth) + printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n", + pb->base, i); + else + /* Number of bytes we can read if we get an interrupt. */ + i = 0; + + priv->readIntrThreshold = i; + + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb (0xf4, ECONTROL (pb)); /* Configuration mode */ + config = inb (FIFO (pb)); + pword = (config >> 4) & 0x7; + switch (pword) { + case 0: + pword = 2; + printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + pb->base); + break; + case 2: + pword = 4; + printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + pb->base); + break; + default: + printk (KERN_WARNING "0x%lx: Unknown implementation ID\n", + pb->base); + /* Assume 1 */ + case 1: + pword = 1; + } + priv->pword = pword; + printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword); + + config = inb (CONFIGB (pb)); + printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, + config & 0x80 ? "Level" : "Pulses"); + + if (!(config & 0x40)) { + printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base); + pb->irq = PARPORT_IRQ_NONE; + } + + /* Go back to mode 000 */ + frob_econtrol (pb, 0xe0, ECR_SPP << 5); + pb->modes |= PARPORT_MODE_ECP; + + return 1; +} + +static int __init parport_ECPPS2_supported(struct parport *pb) +{ + const struct parport_pc_private *priv = pb->private_data; + int result; + unsigned char oecr; + + if (!priv->ecr) + return 0; + + oecr = inb (ECONTROL (pb)); + outb (ECR_PS2 << 5, ECONTROL (pb)); - parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */ - for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++) - parport_pc_write_fifo(pb, 0xaa); + result = parport_PS2_supported(pb); - parport_pc_write_econtrol(pb, oecr); - return (i==1024)?0:PARPORT_MODE_PCECP; + outb (oecr, ECONTROL (pb)); + return result; } -/* EPP mode detection - * Theory: - * Bit 0 of STR is the EPP timeout bit, this bit is 0 - * when EPP is possible and is set high when an EPP timeout - * occurs (EPP uses the HALT line to stop the CPU while it does - * the byte transfer, an EPP timeout occurs if the attached - * device fails to respond after 10 micro seconds). - * - * This bit is cleared by either reading it (National Semi) - * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? - * This bit is always high in non EPP modes. - */ +/* EPP mode detection */ + static int __init parport_EPP_supported(struct parport *pb) { /* If EPP timeout bit clear then EPP available */ - if (!parport_pc_epp_clear_timeout(pb)) + if (!clear_epp_timeout(pb)) return 0; /* No way to clear timeout */ /* @@ -491,17 +1292,15 @@ static int __init parport_EPP_supported(struct parport *pb) * This bit is always high in non EPP modes. */ - parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20); - parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10); - parport_pc_epp_clear_timeout(pb); + parport_pc_data_reverse (pb); + parport_pc_enable_irq (pb); + clear_epp_timeout(pb); - parport_pc_read_epp(pb); + inb (EPPDATA (pb)); udelay(30); /* Wait for possible EPP timeout */ - if (parport_pc_read_status(pb) & 0x01) { - parport_pc_epp_clear_timeout(pb); - return PARPORT_MODE_PCEPP; - } + if (parport_pc_read_status(pb) & 0x01) + goto supported; /* * Theory: @@ -511,112 +1310,82 @@ static int __init parport_EPP_supported(struct parport *pb) * in others (EPP 1.7, ECPEPP?) it is possible to read back * its value. */ - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); udelay(30); /* Wait for possible EPP timeout */ - /* Previous test left outputs disabled. */ + /* Enable outputs. */ + parport_pc_data_forward (pb); outb (0x55, EPPADDR (pb)); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); udelay(30); /* Wait for possible EPP timeout */ /* We must enable the outputs to be able to read the address register. */ - parport_pc_frob_control (pb, 0x20, 0x00); + parport_pc_data_forward (pb); if (inb (EPPADDR (pb)) == 0x55) { - - /* wash ... */ - parport_pc_frob_control (pb, 0x20, 0x20); - outb (0xaa, EPPADDR (pb)); - - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); udelay(30); /* Wait for possible EPP timeout */ + outb (0xaa, EPPADDR (pb)); - /* ... and repeat */ - parport_pc_frob_control (pb, 0x20, 0x00); - - if (inb (EPPADDR (pb)) == 0xaa) { - parport_pc_epp_clear_timeout (pb); - return PARPORT_MODE_PCEPP; - } + if (inb (EPPADDR (pb)) == 0xaa) + goto supported; } return 0; + + supported: + clear_epp_timeout(pb); + pb->modes |= PARPORT_MODE_EPP; + + /* Set up access functions to use EPP hardware. */ + parport_pc_ops.epp_read_data = parport_pc_epp_read_data; + parport_pc_ops.epp_write_data = parport_pc_epp_write_data; + parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr; + parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr; + + return 1; } static int __init parport_ECPEPP_supported(struct parport *pb) { - int mode; + struct parport_pc_private *priv = pb->private_data; + int result; unsigned char oecr; - if (!(pb->modes & PARPORT_MODE_PCECR)) + if (!priv->ecr) return 0; - oecr = parport_pc_read_econtrol(pb); + oecr = inb (ECONTROL (pb)); /* Search for SMC style EPP+ECP mode */ - parport_pc_write_econtrol(pb, 0x80); - - mode = parport_EPP_supported(pb); - - parport_pc_write_econtrol(pb, oecr); + outb (0x80, ECONTROL (pb)); - return mode?PARPORT_MODE_PCECPEPP:0; -} - -/* Detect PS/2 support. - * - * Bit 5 (0x20) sets the PS/2 data direction; setting this high - * allows us to read data from the data lines. In theory we would get back - * 0xff but any peripheral attached to the port may drag some or all of the - * lines down to zero. So if we get back anything that isn't the contents - * of the data register we deem PS/2 support to be present. - * - * Some SPP ports have "half PS/2" ability - you can't turn off the line - * drivers, but an external peripheral with sufficiently beefy drivers of - * its own can overpower them and assert its own levels onto the bus, from - * where they can then be read back as normal. Ports with this property - * and the right type of device attached are likely to fail the SPP test, - * (as they will appear to have stuck bits) and so the fact that they might - * be misdetected here is rather academic. - */ + result = parport_EPP_supported(pb); -static int __init parport_PS2_supported(struct parport *pb) -{ - int ok = 0; - unsigned char octr = parport_pc_read_control(pb); - - parport_pc_epp_clear_timeout(pb); + outb (oecr, ECONTROL (pb)); - parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */ - - parport_pc_write_data(pb, 0x55); - if (parport_pc_read_data(pb) != 0x55) ok++; - - parport_pc_write_data(pb, 0xaa); - if (parport_pc_read_data(pb) != 0xaa) ok++; - - parport_pc_write_control(pb, octr); /* cancel input mode */ + if (result) { + /* Set up access functions to use ECP+EPP hardware. */ + parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data; + parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data; + parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr; + parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr; + } - return ok?PARPORT_MODE_PCPS2:0; + return result; } -static int __init parport_ECPPS2_supported(struct parport *pb) -{ - int mode; - unsigned char oecr; - - if (!(pb->modes & PARPORT_MODE_PCECR)) - return 0; +#else /* No IEEE 1284 support */ - oecr = parport_pc_read_econtrol(pb); - parport_pc_write_econtrol(pb, 0x20); - - mode = parport_PS2_supported(pb); +/* Don't bother probing for modes we know we won't use. */ +static int __init parport_PS2_supported(struct parport *pb) { return 0; } +static int __init parport_ECP_supported(struct parport *pb) { return 0; } +static int __init parport_EPP_supported(struct parport *pb) { return 0; } +static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; } +static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; } - parport_pc_write_econtrol(pb, oecr); - return mode?PARPORT_MODE_PCECPPS2:0; -} +#endif /* No IEEE 1284 support */ /* --- IRQ detection -------------------------------------- */ @@ -624,17 +1393,17 @@ static int __init parport_ECPPS2_supported(struct parport *pb) static int __init programmable_irq_support(struct parport *pb) { int irq, intrLine; - unsigned char oecr = parport_pc_read_econtrol(pb); + unsigned char oecr = inb (ECONTROL (pb)); static const int lookup[8] = { PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 }; - parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */ - - intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07; + outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */ + + intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; irq = lookup[intrLine]; - parport_pc_write_econtrol(pb, oecr); + outb (oecr, ECONTROL (pb)); return irq; } @@ -645,15 +1414,16 @@ static int __init irq_probe_ECP(struct parport *pb) sti(); irqs = probe_irq_on(); - parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ - parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb ((ECR_TST << 5) | 0x04, ECONTROL (pb)); + outb (ECR_TST << 5, ECONTROL (pb)); - /* If Full FIFO sure that WriteIntrThresold is generated */ - for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) - parport_pc_write_fifo(pb, 0xaa); + /* If Full FIFO sure that writeIntrThreshold is generated */ + for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) + outb (0xaa, FIFO (pb)); pb->irq = probe_irq_off(irqs); - parport_pc_write_econtrol(pb, 0x00); + outb (ECR_SPP << 5, ECONTROL (pb)); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; @@ -671,22 +1441,21 @@ static int __init irq_probe_EPP(struct parport *pb) return PARPORT_IRQ_NONE; #else int irqs; - unsigned char octr = parport_pc_read_control(pb); unsigned char oecr; if (pb->modes & PARPORT_MODE_PCECR) - oecr = parport_pc_read_econtrol(pb); + oecr = inb (ECONTROL (pb)); sti(); irqs = probe_irq_on(); if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_frob_econtrol (pb, 0x10, 0x10); + frob_econtrol (pb, 0x10, 0x10); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); parport_pc_frob_control (pb, 0x20, 0x20); parport_pc_frob_control (pb, 0x10, 0x10); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); /* Device isn't expecting an EPP read * and generates an IRQ. @@ -696,56 +1465,20 @@ static int __init irq_probe_EPP(struct parport *pb) pb->irq = probe_irq_off (irqs); if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, oecr); - parport_pc_write_control(pb, octr); + outb (oecr, ECONTROL (pb)); + parport_pc_write_control(pb, 0xc); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; return pb->irq; -#endif /* Advanced detection. */ +#endif /* Advanced detection */ } static int __init irq_probe_SPP(struct parport *pb) { -#ifndef ADVANCED_DETECT /* Don't even try to do this. */ return PARPORT_IRQ_NONE; -#else - int irqs; - unsigned char octr = parport_pc_read_control(pb); - unsigned char oecr; - - if (pb->modes & PARPORT_MODE_PCECR) - oecr = parport_pc_read_econtrol(pb); - probe_irq_off(probe_irq_on()); /* Clear any interrupts */ - irqs = probe_irq_on(); - - if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, 0x10); - - parport_pc_write_data(pb,0x00); - parport_pc_write_control(pb,0x00); - parport_pc_write_control(pb,0x0c); - udelay(5); - parport_pc_write_control(pb,0x0d); - udelay(5); - parport_pc_write_control(pb,0x0c); - udelay(25); - parport_pc_write_control(pb,0x08); - udelay(25); - parport_pc_write_control(pb,0x0c); - udelay(50); - - pb->irq = probe_irq_off(irqs); - if (pb->irq <= 0) - pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */ - - if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, oecr); - parport_pc_write_control(pb, octr); - return pb->irq; -#endif /* Advanced detection. */ } /* We will attempt to share interrupt requests since other devices @@ -757,25 +1490,27 @@ static int __init irq_probe_SPP(struct parport *pb) */ static int __init parport_irq_probe(struct parport *pb) { - if (pb->modes & PARPORT_MODE_PCECR) { + const struct parport_pc_private *priv = pb->private_data; + + if (priv->ecr) { pb->irq = programmable_irq_support(pb); if (pb->irq != PARPORT_IRQ_NONE) goto out; } - if (pb->modes & PARPORT_MODE_PCECP) + if (pb->modes & PARPORT_MODE_ECP) pb->irq = irq_probe_ECP(pb); - if (pb->irq == PARPORT_IRQ_NONE && - (pb->modes & PARPORT_MODE_PCECPEPP)) + if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && + (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); - if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP)) + if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); if (pb->irq == PARPORT_IRQ_NONE) pb->irq = irq_probe_SPP(pb); @@ -784,6 +1519,33 @@ out: return pb->irq; } +/* --- DMA detection -------------------------------------- */ + +/* Only if supports ECP mode */ +static int __init programmable_dma_support (struct parport *p) +{ + unsigned char oecr = inb (ECONTROL (p)); + int dma; + + frob_econtrol (p, 0xe0, ECR_CNF << 5); + + dma = inb (CONFIGB(p)) & 0x03; + if (!dma) + dma = PARPORT_DMA_NONE; + + outb (oecr, ECONTROL (p)); + return dma; +} + +static int __init parport_dma_probe (struct parport *p) +{ + const struct parport_pc_private *priv = p->private_data; + if (priv->ecr) + p->dma = programmable_dma_support(p); + + return p->dma; +} + /* --- Initialisation code -------------------------------- */ static int __init probe_one_port(unsigned long int base, @@ -801,6 +1563,10 @@ static int __init probe_one_port(unsigned long int base, return 0; } priv->ctr = 0xc; + priv->ctr_writable = 0xff; + priv->ecr = 0; + priv->fifo_depth = 0; + priv->dma_buf = 0; p->base = base; p->base_hi = base_hi; p->irq = irq; @@ -808,39 +1574,40 @@ static int __init probe_one_port(unsigned long int base, p->modes = PARPORT_MODE_PCSPP; p->ops = &parport_pc_ops; p->private_data = priv; - if (base_hi && !check_region (base_hi, 3)) { - p->modes |= parport_ECR_present (p); - p->modes |= parport_ECP_supported (p); - p->modes |= parport_ECPPS2_supported (p); + p->physport = p; + if (base_hi && !check_region(base_hi,3)) { + parport_ECR_present(p); + parport_ECP_supported(p); + parport_ECPPS2_supported(p); } - if (p->base != 0x3bc) { + if (base != 0x3bc) { if (!check_region(base+0x3, 5)) { - p->modes |= parport_EPP_supported (p); - p->modes |= parport_ECPEPP_supported (p); + parport_ECPEPP_supported(p); + parport_EPP_supported(p); } } - if (!parport_SPP_supported(p)) { + if (!parport_SPP_supported (p)) { /* No port. */ kfree (priv); return 0; } - p->modes |= parport_PS2_supported(p); + parport_PS2_supported (p); - if (!(p = parport_register_port (base, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, &parport_pc_ops))) { + if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, &parport_pc_ops))) { kfree (priv); return 0; } p->base_hi = base_hi; p->modes = tmp.modes; - p->size = (p->modes & PARPORT_MODE_PCEPP) ? 8 : 3; + p->size = (p->modes & PARPORT_MODE_EPP)?8:3; p->private_data = priv; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); - if (p->base_hi && (p->modes & PARPORT_MODE_PCECR)) - printk (" (0x%lx)", p->base_hi); + if (p->base_hi && (p->modes & PARPORT_MODE_ECP)) + printk(" (0x%lx)", p->base_hi); p->irq = irq; p->dma = dma; if (p->irq == PARPORT_IRQ_AUTO) { @@ -852,33 +1619,52 @@ static int __init probe_one_port(unsigned long int base, probedirq = p->irq; p->irq = PARPORT_IRQ_NONE; } - if (p->irq != PARPORT_IRQ_NONE) + if (p->irq != PARPORT_IRQ_NONE) { printk(", irq %d", p->irq); + + if (p->dma == PARPORT_DMA_AUTO) { + p->dma = PARPORT_DMA_NONE; + parport_dma_probe(p); + } + } if (p->dma == PARPORT_DMA_AUTO) p->dma = PARPORT_DMA_NONE; - if (p->dma != PARPORT_DMA_NONE) + if (p->dma != PARPORT_DMA_NONE) printk(", dma %d", p->dma); + +#ifdef CONFIG_PARPORT_PC_FIFO + if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) { + parport_pc_ops.compat_write_data = + parport_pc_compat_write_block_pio; +#ifdef CONFIG_PARPORT_1284 + parport_pc_ops.ecp_write_data = + parport_pc_ecp_write_block_pio; +#endif /* IEEE 1284 support */ + if (p->dma != PARPORT_DMA_NONE) + p->modes |= PARPORT_MODE_DMA; + printk(", using FIFO"); + } +#endif /* Allowed to use FIFO/DMA */ + printk(" ["); -#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}} +#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} { int f = 0; - printmode(SPP); - printmode(PS2); + printmode(PCSPP); + printmode(TRISTATE); + printmode(COMPAT) printmode(EPP); printmode(ECP); - printmode(ECPEPP); - printmode(ECPPS2); + printmode(DMA); } #undef printmode printk("]\n"); -#ifdef CONFIG_PROC_FS if (probedirq != PARPORT_IRQ_NONE) - printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq); -#endif + printk("%s: irq %d detected\n", p->name, probedirq); parport_proc_register(p); request_region (p->base, p->size, p->name); - if (p->modes & PARPORT_MODE_PCECR) + if (p->modes & PARPORT_MODE_ECP) request_region (p->base_hi, 3, p->name); if (p->irq != PARPORT_IRQ_NONE) { @@ -897,25 +1683,37 @@ static int __init probe_one_port(unsigned long int base, "resorting to PIO operation\n", p->name, p->dma); p->dma = PARPORT_DMA_NONE; + } else { + priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1); + if (! priv->dma_buf) { + printk (KERN_WARNING "%s: " + "cannot get buffer for DMA, " + "resorting to PIO operation\n", + p->name); + free_dma(p->dma); + p->dma = PARPORT_DMA_NONE; + } } } } - /* Done probing. Now put the port into a sensible start-up state. */ - if (p->modes & PARPORT_MODE_PCECR) + /* Done probing. Now put the port into a sensible start-up state. + * SELECT | INIT also puts IEEE1284-compliant devices into + * compatibility mode. */ + if (p->modes & PARPORT_MODE_ECP) /* * Put the ECP detected port in PS2 mode. */ - parport_pc_write_econtrol(p, 0x24); + outb (0x24, ECONTROL (p)); + parport_pc_write_data(p, 0); - parport_pc_write_control(p, 0x8); + parport_pc_write_control(p, PARPORT_CONTROL_SELECT); udelay (50); - parport_pc_write_control(p, 0xc); + parport_pc_write_control(p, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); udelay (50); - if (parport_probe_hook) - (*parport_probe_hook)(p); - /* Now that we've told the sharing engine about the port, and found out its characteristics, let the high-level drivers know about it. */ @@ -953,11 +1751,8 @@ static int __init parport_pc_init_pci (int irq, int dma) #define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */ #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */ -#endif /* IDs not defined */ +#endif - int count = 0; -#ifdef CONFIG_PCI - int i; struct { unsigned int vendor; unsigned int device; @@ -1014,6 +1809,9 @@ static int __init parport_pc_init_pci (int irq, int dma) { 0, } }; + int count = 0; + int i; + if (!pci_present ()) return 0; @@ -1036,7 +1834,6 @@ static int __init parport_pc_init_pci (int irq, int dma) } } } -#endif /* CONFIG_PCI */ return count; } @@ -1070,17 +1867,9 @@ static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PAR static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; - -MODULE_PARM_DESC(io, "base address"); MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); - -MODULE_PARM_DESC(io_hi, "base address for ECR"); MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); - -MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); - -MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); int init_module(void) @@ -1120,15 +1909,18 @@ void cleanup_module(void) struct parport *p = parport_enumerate(), *tmp; while (p) { tmp = p->next; - if (p->modes & PARPORT_MODE_PCSPP) { + if (p->modes & PARPORT_MODE_PCSPP) { + struct parport_pc_private *priv = p->private_data; if (p->dma != PARPORT_DMA_NONE) - free_dma (p->dma); + free_dma(p->dma); if (p->irq != PARPORT_IRQ_NONE) - free_irq (p->irq, p); - release_region (p->base, p->size); - if (p->modes & PARPORT_MODE_PCECP) - release_region (p->base_hi, 3); + free_irq(p->irq, p); + release_region(p->base, p->size); + if (p->modes & PARPORT_MODE_ECP) + release_region(p->base_hi, 3); parport_proc_unregister(p); + if (priv->dma_buf) + free_page((unsigned long) priv->dma_buf); kfree (p->private_data); parport_unregister_port(p); } diff --git a/drivers/misc/parport_probe.c b/drivers/misc/parport_probe.c new file mode 100644 index 000000000..a5b1524bd --- /dev/null +++ b/drivers/misc/parport_probe.c @@ -0,0 +1,212 @@ +/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $ + * Parallel port device probing code + * + * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de + * Philip Blundell + */ + +#include +#include +#include + +static struct { + char *token; + char *descr; +} classes[] = { + { "", "Legacy device" }, + { "PRINTER", "Printer" }, + { "MODEM", "Modem" }, + { "NET", "Network device" }, + { "HDC", "Hard disk" }, + { "PCMCIA", "PCMCIA" }, + { "MEDIA", "Multimedia device" }, + { "FDC", "Floppy disk" }, + { "PORTS", "Ports" }, + { "SCANNER", "Scanner" }, + { "DIGICAM", "Digital camera" }, + { "", "Unknown device" }, + { "", "Unspecified" }, + { "SCSIADAPTER", "SCSI adapter" }, + { NULL, NULL } +}; + +static void pretty_print(struct parport *port, int device) +{ + struct parport_device_info *info = &port->probe_info[device + 1]; + + printk(KERN_INFO "%s", port->name); + + if (device >= 0) + printk (" (addr %d)", device); + + printk (": %s", classes[info->class].descr); + if (info->class) + printk(", %s %s", info->mfr, info->model); + + printk("\n"); +} + +static char *strdup(char *str) +{ + int n = strlen(str)+1; + char *s = kmalloc(n, GFP_KERNEL); + if (!s) return NULL; + return strcpy(s, str); +} + +static void parse_data(struct parport *port, int device, char *str) +{ + char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); + char *p = txt, *q; + int guessed_class = PARPORT_CLASS_UNSPEC; + struct parport_device_info *info = &port->probe_info[device + 1]; + + if (!txt) { + printk("%s probe: memory squeeze\n", port->name); + return; + } + strcpy(txt, str); + while (p) { + char *sep; + q = strchr(p, ';'); + if (q) *q = 0; + sep = strchr(p, ':'); + if (sep) { + char *u = p; + *(sep++) = 0; + while (*u) { + *u = toupper(*u); + u++; + } + if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { + if (info->mfr) + kfree (info->mfr); + info->mfr = strdup(sep); + } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { + if (info->model) + kfree (info->model); + info->model = strdup(sep); + } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { + int i; + if (info->class_name) + kfree (info->class_name); + info->class_name = strdup(sep); + for (u = sep; *u; u++) + *u = toupper(*u); + for (i = 0; classes[i].token; i++) { + if (!strcmp(classes[i].token, sep)) { + info->class = i; + goto rock_on; + } + } + printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); + info->class = PARPORT_CLASS_OTHER; + } else if (!strcmp(p, "CMD") || + !strcmp(p, "COMMAND SET")) { + if (info->cmdset) + kfree (info->cmdset); + info->cmdset = strdup(sep); + /* if it speaks printer language, it's + probably a printer */ + if (strstr(sep, "PJL") || strstr(sep, "PCL")) + guessed_class = PARPORT_CLASS_PRINTER; + } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { + if (info->description) + kfree (info->description); + info->description = strdup(sep); + } + } + rock_on: + if (q) p = q+1; else p=NULL; + } + + /* If the device didn't tell us its class, maybe we have managed to + guess one from the things it did say. */ + if (info->class == PARPORT_CLASS_UNSPEC) + info->class = guessed_class; + + pretty_print (port, device); + + kfree(txt); +} + +/* Get Std 1284 Device ID. */ +ssize_t parport_device_id (int devnum, char *buffer, size_t len) +{ + ssize_t retval = -ENXIO; + struct pardevice *dev = parport_open (devnum, "Device ID probe", + NULL, NULL, NULL, 0, NULL); + if (!dev) + return -ENXIO; + + parport_claim_or_block (dev); + + /* Negotiate to compatibility mode, and then to device ID mode. + * (This is in case we are already in device ID mode.) */ + parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); + retval = parport_negotiate (dev->port, + IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID); + + if (!retval) { + int idlen; + unsigned char length[2]; + mm_segment_t oldfs = get_fs (); + set_fs (get_ds ()); + + /* First two bytes are MSB,LSB of inclusive length. */ + retval = parport_read (dev->port, length, 2); + + if (retval != 2) goto restore_fs; + + idlen = (length[0] << 8) + length[1] - 2; + if (idlen < len) + len = idlen; + retval = parport_read (dev->port, buffer, len); + + if (retval != len) { + printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n", + dev->port->name, retval, len); + goto restore_fs; + } + + /* Some printer manufacturers mistakenly believe that + the length field is supposed to be _exclusive_. */ + /* In addition, there are broken devices out there + that don't even finish off with a semi-colon. */ + if (idlen == len && buffer[len - 1] != ';') { + ssize_t diff; + diff = parport_read (dev->port, buffer + len, 2); + retval += diff; + + if (diff) + printk (KERN_DEBUG + "%s: device reported incorrect " + "length field (%d, should be %d)\n", + dev->port->name, idlen, retval); + else { + /* One semi-colon short of a device ID. */ + buffer[len++] = ';'; + buffer[len] = '\0'; + printk (KERN_DEBUG "%s: faking semi-colon\n", + dev->port->name); + + /* If we get here, I don't think we + need to worry about the possible + standard violation of having read + more than we were told to. The + device is non-compliant anyhow. */ + } + } + + restore_fs: + set_fs (oldfs); + parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); + } + parport_release (dev); + + if (retval > 0) + parse_data (dev->port, dev->daisy, buffer); + + parport_close (dev); + return retval; +} diff --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c index f3dc63c46..0c7be433c 100644 --- a/drivers/misc/parport_procfs.c +++ b/drivers/misc/parport_procfs.c @@ -62,7 +62,7 @@ static int do_active_device(ctl_table *table, int write, struct file *filp, return copy_to_user(result, buffer, len) ? -EFAULT : 0; } -#if 0 && defined (CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 static int do_autoprobe(ctl_table *table, int write, struct file *filp, void *result, size_t *lenp) { @@ -146,9 +146,11 @@ static int do_hardware(ctl_table *table, int write, struct file *filp, #define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}} int f = 0; printmode(PCSPP); - printmode(PCPS2); - printmode(PCEPP); - printmode(PCECP); + printmode(TRISTATE); + printmode(COMPAT); + printmode(EPP); + printmode(ECP); + printmode(DMA); #undef printmode } buffer[len++] = '\n'; @@ -190,7 +192,7 @@ static const struct parport_sysctl_table parport_sysctl_template = { NULL, 0, 0444, NULL, &do_hardware }, PARPORT_DEVICES_ROOT_DIR, -#if 0 && defined(CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 { DEV_PARPORT_AUTOPROBE, "autoprobe", NULL, 0, 0444, NULL, &do_autoprobe }, @@ -292,17 +294,11 @@ int parport_proc_register(struct parport *port) for (i = 0; i < 8; i++) t->vars[i].extra1 = port; -#if 0 /* Wait for IEEE 1284 support */ t->vars[0].data = &port->spintime; -#endif t->vars[2].child = t->device_dir; for (i = 0; i < 5; i++) -#if 0 t->vars[3 + i].extra2 = &port->probe_info[i]; -#else - t->vars[3 + i].extra2 = &port->probe_info; -#endif t->port_dir[0].procname = port->name; t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ @@ -348,7 +344,7 @@ int parport_device_proc_register(struct pardevice *device) t->port_dir[0].child = t->devices_root_dir; t->devices_root_dir[0].child = t->device_dir; -#if 0 && defined(CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 t->device_dir[0].ctl_name = parport_device_num(port->number, port->muxport, diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c index 4138df28a..0ca126a41 100644 --- a/drivers/misc/parport_share.c +++ b/drivers/misc/parport_share.c @@ -40,9 +40,7 @@ #define PARPORT_DEFAULT_TIMESLICE (HZ/5) unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE; - -/* This doesn't do anything yet. */ -int parport_default_spintime; +int parport_default_spintime = DEFAULT_SPIN_TIME; static struct parport *portlist = NULL, *portlist_tail = NULL; spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED; @@ -50,7 +48,7 @@ spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED; static struct parport_driver *driver_chain = NULL; spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED; -static void call_driver_chain (int attach, struct parport *port) +static void call_driver_chain(int attach, struct parport *port) { struct parport_driver *drv; @@ -96,17 +94,12 @@ void parport_unregister_driver (struct parport_driver *arg) } } -void (*parport_probe_hook)(struct parport *port) = NULL; - /* Return a list of all the ports we know about. */ struct parport *parport_enumerate(void) { #ifdef CONFIG_KMOD if (portlist == NULL) { request_module("parport_lowlevel"); -#ifdef CONFIG_PNP_PARPORT_MODULE - request_module("parport_probe"); -#endif /* CONFIG_PNP_PARPORT_MODULE */ } #endif /* CONFIG_KMOD */ return portlist; @@ -117,16 +110,9 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, { struct parport *tmp; int portnum; + int device; char *name; - /* Check for a previously registered port. - NOTE: we will ignore irq and dma if we find a previously - registered device. */ - for (tmp = portlist; tmp; tmp = tmp->next) { - if (tmp->base == base) - return tmp; - } - tmp = kmalloc(sizeof(struct parport), GFP_KERNEL); if (!tmp) { printk(KERN_WARNING "parport: memory squeeze\n"); @@ -154,16 +140,22 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->base = base; tmp->irq = irq; tmp->dma = dma; + tmp->muxport = tmp->daisy = tmp->muxsel = -1; tmp->modes = 0; tmp->next = NULL; tmp->devices = tmp->cad = NULL; tmp->flags = 0; tmp->ops = ops; - tmp->number = portnum; - memset (&tmp->probe_info, 0, sizeof (struct parport_device_info)); + tmp->portnum = tmp->number = portnum; + tmp->physport = tmp; + memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info)); tmp->cad_lock = RW_LOCK_UNLOCKED; spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->pardevice_lock); + tmp->ieee1284.mode = IEEE1284_MODE_COMPAT; + tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */ + tmp->spintime = parport_default_spintime; name = kmalloc(15, GFP_KERNEL); if (!name) { @@ -188,7 +180,10 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, portlist = tmp; spin_unlock(&parportlist_lock); - tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */ + for (device = 0; device < 5; device++) + /* assume the worst */ + tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; + tmp->waithead = tmp->waittail = NULL; return tmp; @@ -196,6 +191,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, void parport_announce_port (struct parport *port) { +#ifdef CONFIG_PARPORT_1284 + /* Analyse the IEEE1284.3 topology of the port. */ + parport_daisy_init (port); +#endif + /* Let drivers know that a new port has arrived. */ call_driver_chain (1, port); } @@ -203,10 +203,16 @@ void parport_announce_port (struct parport *port) void parport_unregister_port(struct parport *port) { struct parport *p; + int d; /* Spread the word. */ call_driver_chain (0, port); +#ifdef CONFIG_PARPORT_1284 + /* Forget the IEEE1284.3 topology of the port. */ + parport_daisy_fini (port); +#endif + spin_lock(&parportlist_lock); if (portlist == port) { if ((portlist = port->next) == NULL) @@ -222,16 +228,20 @@ void parport_unregister_port(struct parport *port) "%s not found in port list!\n", port->name); } spin_unlock(&parportlist_lock); - if (port->probe_info.class_name) - kfree (port->probe_info.class_name); - if (port->probe_info.mfr) - kfree (port->probe_info.mfr); - if (port->probe_info.model) - kfree (port->probe_info.model); - if (port->probe_info.cmdset) - kfree (port->probe_info.cmdset); - if (port->probe_info.description) - kfree (port->probe_info.description); + + for (d = 0; d < 5; d++) { + if (port->probe_info[d].class_name) + kfree (port->probe_info[d].class_name); + if (port->probe_info[d].mfr) + kfree (port->probe_info[d].mfr); + if (port->probe_info[d].model) + kfree (port->probe_info[d].model); + if (port->probe_info[d].cmdset) + kfree (port->probe_info[d].cmdset); + if (port->probe_info[d].description) + kfree (port->probe_info[d].description); + } + kfree(port->name); kfree(port); } @@ -243,7 +253,7 @@ struct pardevice *parport_register_device(struct parport *port, const char *name { struct pardevice *tmp; - if (port->flags & PARPORT_FLAG_EXCL) { + if (port->physport->flags & PARPORT_FLAG_EXCL) { /* An exclusive device is registered. */ printk (KERN_DEBUG "%s: no more devices allowed\n", port->name); @@ -272,13 +282,14 @@ struct pardevice *parport_register_device(struct parport *port, const char *name tmp->name = name; tmp->port = port; + tmp->daisy = -1; tmp->preempt = pf; tmp->wakeup = kf; tmp->private = handle; tmp->flags = flags; tmp->irq_func = irq_func; - port->ops->init_state(tmp->state); tmp->waiting = 0; + tmp->timeout = 5 * HZ; /* Chain this onto the list */ tmp->prev = NULL; @@ -286,11 +297,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name * This function must not run from an irq handler so we don' t need * to clear irq on the local CPU. -arca */ - spin_lock(&port->pardevice_lock); + spin_lock(&port->physport->pardevice_lock); if (flags & PARPORT_DEV_EXCL) { - if (port->devices) { - spin_unlock (&port->pardevice_lock); + if (port->physport->devices) { + spin_unlock (&port->physport->pardevice_lock); kfree (tmp->state); kfree (tmp); printk (KERN_DEBUG @@ -301,11 +312,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name port->flags |= PARPORT_FLAG_EXCL; } - tmp->next = port->devices; - if (port->devices) - port->devices->prev = tmp; - port->devices = tmp; - spin_unlock(&port->pardevice_lock); + tmp->next = port->physport->devices; + if (port->physport->devices) + port->physport->devices->prev = tmp; + port->physport->devices = tmp; + spin_unlock(&port->physport->pardevice_lock); inc_parport_count(); port->ops->inc_use_count(); @@ -314,6 +325,12 @@ struct pardevice *parport_register_device(struct parport *port, const char *name tmp->timeslice = parport_default_timeslice; tmp->waitnext = tmp->waitprev = NULL; + /* + * This has to be run as last thing since init_state may need other + * pardevice fields. -arca + */ + port->ops->init_state(tmp, tmp->state); + parport_device_proc_register(tmp); return tmp; } @@ -328,7 +345,9 @@ void parport_unregister_device(struct pardevice *dev) } #endif - port = dev->port; + parport_device_proc_unregister(dev); + + port = dev->port->physport; if (port->cad == dev) { printk(KERN_DEBUG "%s: %s forgot to release port\n", @@ -354,19 +373,17 @@ void parport_unregister_device(struct pardevice *dev) dec_parport_count(); port->ops->dec_use_count(); - - return; } int parport_claim(struct pardevice *dev) { struct pardevice *oldcad; - struct parport *port = dev->port; + struct parport *port = dev->port->physport; unsigned long flags; if (port->cad == dev) { printk(KERN_INFO "%s: %s already owner\n", - dev->port->name,dev->name); + dev->port->name,dev->name); return 0; } @@ -407,24 +424,27 @@ try_again: dev->waitprev = dev->waitnext = NULL; } - if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func) - /* - * If there was an irq pending it should hopefully happen - * before return from enable_irq(). -arca - */ - enable_irq(port->irq); - - /* - * Avoid running irq handlers if the pardevice doesn' t use it. -arca - */ - if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) - disable_irq(port->irq); - /* Now we do the change of devices */ write_lock_irqsave(&port->cad_lock, flags); port->cad = dev; write_unlock_irqrestore(&port->cad_lock, flags); +#ifdef CONFIG_PARPORT_1284 + /* If it's a mux port, select it. */ + if (dev->port->muxport >= 0) { + /* FIXME */ + port->muxsel = dev->port->muxport; + } + + /* If it's a daisy chain device, select it. */ + if (dev->daisy >= 0) { + /* This could be lazier. */ + if (!parport_daisy_select (port, dev->daisy, + IEEE1284_MODE_COMPAT)) + port->daisy = dev->daisy; + } +#endif /* IEEE1284.3 support */ + /* Restore control registers */ port->ops->restore_state(port, dev->state); dev->time = jiffies; @@ -487,8 +507,11 @@ int parport_claim_or_block(struct pardevice *dev) } restore_flags(flags); #ifdef PARPORT_DEBUG_SHARING - if (dev->port->cad != dev) - printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody"); + if (dev->port->physport->cad != dev) + printk(KERN_DEBUG "%s: exiting parport_claim_or_block " + "but %s owns port!\n", dev->name, + dev->port->physport->cad ? + dev->port->physport->cad->name:"nobody"); #endif } dev->waiting = 0; @@ -497,7 +520,7 @@ int parport_claim_or_block(struct pardevice *dev) void parport_release(struct pardevice *dev) { - struct parport *port = dev->port; + struct parport *port = dev->port->physport; struct pardevice *pd; unsigned long flags; @@ -507,17 +530,25 @@ void parport_release(struct pardevice *dev) "when not owner\n", port->name, dev->name); return; } + +#ifdef CONFIG_PARPORT_1284 + /* If this is on a mux port, deselect it. */ + if (dev->port->muxport >= 0) { + /* FIXME */ + port->muxsel = -1; + } + + /* If this is a daisy device, deselect it. */ + if (dev->daisy >= 0) { + parport_daisy_deselect_all (port); + port->daisy = -1; + } +#endif + write_lock_irqsave(&port->cad_lock, flags); port->cad = NULL; write_unlock_irqrestore(&port->cad_lock, flags); - /* - * Reenable irq and so discard the eventually pending irq while - * cad is NULL. -arca - */ - if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) - enable_irq(port->irq); - /* Save control registers */ port->ops->save_state(port, dev->state); diff --git a/drivers/pnp/Config.in b/drivers/pnp/Config.in index f8279fd67..0aa5aa426 100644 --- a/drivers/pnp/Config.in +++ b/drivers/pnp/Config.in @@ -1,16 +1,3 @@ # # Plug and Play configuration # - -mainmenu_option next_comment -comment 'Plug and Play support' - -bool 'Plug and Play support' CONFIG_PNP - -if [ "$CONFIG_PNP" = "y" ]; then - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT - fi -fi - -endmenu diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile index 565062f7e..a801f1992 100644 --- a/drivers/pnp/Makefile +++ b/drivers/pnp/Makefile @@ -7,10 +7,6 @@ # # Note 2! The CFLAGS definitions are now inherited from the # parent makes.. -# -# Note 3! Plug and Play is the Borg. We have assimilated some other -# drivers in the `char', `net' and `scsi' directories, but left them -# there to allay suspicion. SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) @@ -22,12 +18,4 @@ LX_OBJS := MI_OBJS := MIX_OBJS := -ifeq ($(CONFIG_PNP_PARPORT),y) - LX_OBJS += parport_probe.o -else - ifeq ($(CONFIG_PNP_PARPORT),m) - MX_OBJS += parport_probe.o - endif -endif - include $(TOPDIR)/Rules.make diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c deleted file mode 100644 index 8ae499311..000000000 --- a/drivers/pnp/parport_probe.c +++ /dev/null @@ -1,288 +0,0 @@ -/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $ - * Parallel port device probing code - * - * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de - * Philip Blundell - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#undef DEBUG_PROBE - -static inline int read_nibble(struct parport *port) -{ - unsigned char i; - i = parport_read_status(port)>>3; - i &= ~8; - if ((i & 0x10) == 0) i |= 8; - return (i & 0x0f); -} - -static void read_terminate(struct parport *port) { - parport_write_control(port, (parport_read_control(port) & ~2) | 8); - /* SelectIN high, AutoFeed low */ - if (parport_wait_peripheral(port, 0x80, 0)) - /* timeout, SelectIN high, Autofeed low */ - return; - parport_write_control(port, parport_read_control(port) | 2); - /* AutoFeed high */ - parport_wait_peripheral(port, 0x80, 0x80); - /* no timeout possible, Autofeed low, SelectIN high */ - parport_write_control(port, (parport_read_control(port) & ~2) | 8); -} - -static long read_polled(struct parport *port, char *buf, - unsigned long length) -{ - int i; - char *temp=buf; - unsigned int count = 0; - unsigned char z=0; - unsigned char Byte=0; - unsigned long igiveupat=jiffies+5*HZ; - - for (i=0; time_before(jiffies, igiveupat); i++) { - /* if(current->need_resched) schedule(); */ - parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */ - if (parport_wait_peripheral(port, 0x40, 0)) { -#ifdef DEBUG_PROBE - /* Some peripherals just time out when they've sent - all their data. */ - printk("%s: read1 timeout.\n", port->name); -#endif - parport_write_control(port, parport_read_control(port) & ~2); - break; - } - z = read_nibble(port); - parport_write_control(port, parport_read_control(port) & ~2); /* AutoFeed low */ - if (parport_wait_peripheral(port, 0x40, 0x40)) { - printk("%s: read2 timeout.\n", port->name); - break; - } - if ((i & 1) != 0) { - Byte |= (z<<4); - if (temp) - *(temp++) = Byte; - if (++count == length) - temp = NULL; - /* Does the error line indicate end of data? */ - if ((parport_read_status(port) & LP_PERRORP) == - LP_PERRORP) - break; - } else - Byte=z; - } - read_terminate(port); - return count; -} - -int parport_probe(struct parport *port, char *buffer, int len) -{ - struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev); - - int result = 0; - - if (!dev) { - printk("%s: unable to register for probe.\n", port->name); - return -EINVAL; - } - - parport_claim_or_block(dev); - - switch (parport_ieee1284_nibble_mode_ok(port, 4)) { - case 2: - current->state=TASK_INTERRUPTIBLE; - /* HACK: wait 10ms because printer seems to ack wrong */ - schedule_timeout((HZ+99)/100); - result = read_polled(port, buffer, len); - break; - default: - result = -EIO; - break; - } - - parport_release(dev); - parport_unregister_device(dev); - - return result; -} - -static struct { - char *token; - char *descr; -} classes[] = { - { "", "Legacy device" }, - { "PRINTER", "Printer" }, - { "MODEM", "Modem" }, - { "NET", "Network device" }, - { "HDC", "Hard disk" }, - { "PCMCIA", "PCMCIA" }, - { "MEDIA", "Multimedia device" }, - { "FDC", "Floppy disk" }, - { "PORTS", "Ports" }, - { "SCANNER", "Scanner" }, - { "DIGICAM", "Digital camera" }, - { "", "Unknown device" }, - { "", "Unspecified" }, - { NULL, NULL } -}; - -static char *strdup(char *str) -{ - int n = strlen(str)+1; - char *s = kmalloc(n, GFP_KERNEL); - if (!s) return NULL; - return strcpy(s, str); -} - -static void parse_data(struct parport *port, char *str) -{ - char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); - char *p = txt, *q; - int guessed_class = PARPORT_CLASS_UNSPEC; - - if (!txt) { - printk("%s probe: memory squeeze\n", port->name); - return; - } - strcpy(txt, str); - while (p) { - char *sep; - q = strchr(p, ';'); - if (q) *q = 0; - sep = strchr(p, ':'); - if (sep) { - char *u = p; - *(sep++) = 0; - while (*u) { - *u = toupper(*u); - u++; - } - if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { - if (port->probe_info.mfr) - kfree (port->probe_info.mfr); - port->probe_info.mfr = strdup(sep); - } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { - if (port->probe_info.model) - kfree (port->probe_info.model); - port->probe_info.model = strdup(sep); - } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { - int i; - if (port->probe_info.class_name) - kfree (port->probe_info.class_name); - port->probe_info.class_name = strdup(sep); - for (u = sep; *u; u++) - *u = toupper(*u); - for (i = 0; classes[i].token; i++) { - if (!strcmp(classes[i].token, sep)) { - port->probe_info.class = i; - goto rock_on; - } - } - printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); - port->probe_info.class = PARPORT_CLASS_OTHER; - } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) { - if (port->probe_info.cmdset) - kfree (port->probe_info.cmdset); - port->probe_info.cmdset = strdup(sep); - /* if it speaks printer language, it's - probably a printer */ - if (strstr(sep, "PJL") || strstr(sep, "PCL")) - guessed_class = PARPORT_CLASS_PRINTER; - } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { - if (port->probe_info.description) - kfree (port->probe_info.description); - port->probe_info.description = strdup(sep); - } - } - rock_on: - if (q) p = q+1; else p=NULL; - } - - /* If the device didn't tell us its class, maybe we have managed to - guess one from the things it did say. */ - if (port->probe_info.class == PARPORT_CLASS_UNSPEC) - port->probe_info.class = guessed_class; - - kfree(txt); -} - -static void pretty_print(struct parport *port) -{ - printk(KERN_INFO "%s: %s", port->name, - classes[port->probe_info.class].descr); - if (port->probe_info.class) { - printk(", %s %s", port->probe_info.mfr, - port->probe_info.model); - } - printk("\n"); -} - -void parport_probe_one(struct parport *port) -{ - char *buffer = kmalloc(2048, GFP_KERNEL); - int r; - - MOD_INC_USE_COUNT; - port->probe_info.model = strdup ("Unknown device"); - port->probe_info.mfr = strdup ("Unknown vendor"); - port->probe_info.description = port->probe_info.cmdset = NULL; - port->probe_info.class = PARPORT_CLASS_UNSPEC; - port->probe_info.class_name = NULL; - - if (!buffer) { - printk(KERN_ERR "%s probe: Memory squeeze.\n", port->name); - return; - } - - r = parport_probe(port, buffer, 2047); - - if (r < 0) { - printk(KERN_INFO "%s: no IEEE-1284 device present.\n", - port->name); - port->probe_info.class = PARPORT_CLASS_LEGACY; - } else if (r == 0) { - printk(KERN_INFO "%s: no ID data returned by device.\n", - port->name); - } else { - buffer[r] = 0; -#ifdef DEBUG_PROBE - printk("%s id: %s\n", port->name, buffer+2); -#endif - parse_data(port, buffer+2); - pretty_print(port); - } - kfree(buffer); - MOD_DEC_USE_COUNT; -} - -#if MODULE -int init_module(void) -{ - struct parport *p; - for (p = parport_enumerate(); p; p = p->next) - parport_probe_one(p); - parport_probe_hook = &parport_probe_one; - return 0; -} - -void cleanup_module(void) -{ - parport_probe_hook = NULL; -} -#endif diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 82c7e61e0..f2b0df9c5 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1672,7 +1672,6 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout) #endif while (info->xmit_cnt || !info->all_sent) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(char_time); if (signal_pending(current)) break; diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index b80b93e92..7aacd3291 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1836,7 +1836,6 @@ su_wait_until_sent(struct tty_struct *tty, int timeout) printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 5904c881c..715a15acf 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -158,14 +158,14 @@ int ppa_detect(Scsi_Host_Template * host) */ ppa_hosts[i].mode = PPA_NIBBLE; - if (modes & PARPORT_MODE_PCPS2) + if (modes & PARPORT_MODE_TRISTATE) ppa_hosts[i].mode = PPA_PS2; - if (modes & PARPORT_MODE_PCECPPS2) { + if (modes & PARPORT_MODE_ECP) { w_ecr(ppb, 0x20); ppa_hosts[i].mode = PPA_PS2; } - if (modes & PARPORT_MODE_PCECPEPP) + if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) w_ecr(ppb, 0x80); /* Done configuration */ diff --git a/drivers/sgi/char/graphics.c b/drivers/sgi/char/graphics.c index c1b2bb04f..de0ecf1f2 100644 --- a/drivers/sgi/char/graphics.c +++ b/drivers/sgi/char/graphics.c @@ -262,8 +262,7 @@ static struct vm_operations_struct graphics_mmap = { NULL, /* no special mmap-advise */ sgi_graphics_nopage, /* our magic no-page fault handler */ NULL, /* no special mmap-wppage */ - NULL, /* no special mmap-swapout */ - NULL /* no special mmap-swapin */ + NULL /* no special mmap-swapout */ }; int diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c index 6b93fdd28..59ec035cb 100644 --- a/drivers/sgi/char/shmiq.c +++ b/drivers/sgi/char/shmiq.c @@ -302,8 +302,7 @@ static struct vm_operations_struct qcntl_mmap = { NULL, /* no special mmap-advise */ shmiq_nopage, /* our magic no-page fault handler */ NULL, /* no special mmap-wppage */ - NULL, /* no special mmap-swapout */ - NULL /* no special mmap-swapin */ + NULL /* no special mmap-swapout */ }; static int diff --git a/drivers/usb/CREDITS b/drivers/usb/CREDITS index ce5a9e8a7..e1166797d 100644 --- a/drivers/usb/CREDITS +++ b/drivers/usb/CREDITS @@ -29,7 +29,7 @@ of hardware, support, time and development (this is from the original THANKS file in Inaky's driver): The following corporations have helped us in the development -of Linux USB / UUSBD: + of Linux USB / UUSBD: - USAR Systems provided us with one of their excellent USB Evaluation Kits. It allows us to test the Linux-USB driver diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 17294caba..534d0fed0 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -192,9 +192,11 @@ endif ifeq ($(CONFIG_FB_TGA),y) L_OBJS += tgafb.o +CONFIG_FBGEN_BUILTIN = y else ifeq ($(CONFIG_FB_TGA),m) M_OBJS += tgafb.o + CONFIG_FBGEN_MODULE = y endif endif diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e9d5a32fc..24e7ad742 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -74,6 +74,7 @@ extern void imsttfb_init(void); extern void imsttfb_setup(char *options, int *ints); extern void dnfb_init(void); extern void tgafb_init(void); +extern void tgafb_setup(char *options, int *ints); extern void virgefb_init(void); extern void virgefb_setup(char *options, int *ints); extern void resolver_video_setup(char *options, int *ints); @@ -158,7 +159,7 @@ static struct { { "s3trio", s3triofb_init, s3triofb_setup }, #endif #ifdef CONFIG_FB_TGA - { "tga", tgafb_init, NULL }, + { "tga", tgafb_init, tgafb_setup }, #endif #ifdef CONFIG_FB_VIRGE { "virge", virgefb_init, virgefb_setup }, diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index fe3bc4068..59902a57a 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -1,27 +1,29 @@ /* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * - * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1999 Martin Lucina, Tom Zerucha + * + * $Id: tgafb.c,v 1.12 1999/07/01 13:39:23 mato Exp $ * - * This driver is partly based on the original TGA console driver + * This driver is partly based on the original TGA framebuffer device, which + * was partly based on the original TGA console driver, which are * - * Copyright (C) 1995 Jay Estabrook + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1995 Jay Estabrook * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ - /* KNOWN PROBLEMS/TO DO ===================================================== * * * - How to set a single color register on 24-plane cards? * - * - Hardware cursor (useful for other graphics boards too) - * - * - Support for more resolutions + * - Hardware cursor/other text acceleration methods * * - Some redraws can stall kernel for several seconds + * [This should now be solved by the fast memmove() patch in 2.3.6] * * KNOWN PROBLEMS/TO DO ==================================================== */ @@ -45,477 +47,459 @@ #include