diff -u --recursive --new-file v2.3.11/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.11/linux/Documentation/Configure.help Wed Jul 21 15:46:48 1999 +++ linux/Documentation/Configure.help Tue Jul 27 16:05:50 1999 @@ -11921,7 +11921,7 @@ CONFIG_USB_HUB To expand beyond the USB ports on the computer, a device called a hub is used. This driver supports hubs, allowing them to be used. - Say 'Y' + Say 'Y'. USB mouse support CONFIG_USB_MOUSE @@ -11931,7 +11931,7 @@ USB keyboard support CONFIG_USB_KBD - This driver allows usb keyboards to work under the USB stack. + This driver allows USB keyboards to work under the USB stack. USB audio parsing support (Preliminary) CONFIG_USB_AUDIO @@ -11943,10 +11943,17 @@ This driver allows for devices which support the Abstract Control Model, including many USB-based modems, ISDN adapters, and network adapters. +USB /proc filesystem entry support (Preliminary) +CONFIG_USB_PROC + This reports USB drivers and devices in the /proc filesystem. + Entries are located in /proc/bus/usb. + Note that you must enable support for the proc filesystem + for this to work. + Support for user-space parallel port device drivers CONFIG_PPDEV Saying Y to this adds support for /dev/parport device nodes. This - is needed for programs that want portable access to the parallel + is needed for programs that want low-level access to the parallel port, for instance deviceid (which displays Plug-and-Play device IDs) and vlp (which makes a Linux computer act as though it's a printer). diff -u --recursive --new-file v2.3.11/linux/Documentation/IO-APIC.txt linux/Documentation/IO-APIC.txt --- v2.3.11/linux/Documentation/IO-APIC.txt Wed Jun 24 14:30:07 1998 +++ linux/Documentation/IO-APIC.txt Sun Jul 25 10:26:01 1999 @@ -1,51 +1,41 @@ -Most (all) Intel SMP boards have the so-called 'IO-APIC', which is -an enhanced interrupt controller, able to route hardware interrupts -to multiple CPUs, or to CPU groups. +Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC', +which is an enhanced interrupt controller, it enables us to route +hardware interrupts to multiple CPUs, or to CPU groups. + +Linux supports all variants of compliant SMP boards, including ones with +multiple IO-APICs. (multiple IO-APICs are used in high-end servers to +distribute IRQ load further). + +There are (a few) known breakages in certain older boards, which bugs are +usually worked around by the kernel. If your MP-compliant SMP board does +not boot Linux, then consult the linux-smp mailing list archives first. -Linux supports the IO-APIC, but unfortunately there are broken boards -out there which make it unsafe to enable the IO-APIC unconditionally. -The Linux policy thus is to enable the IO-APIC only if it's 100% safe, ie.: - - - the board is on the 'whitelist' - - or - the board does not have PCI pins connected to the IO-APIC - - or - the user has overridden blacklisted settings with the - pirq= boot option line. - -Kernel messages tell you whether the board is 'safe'. If your box -boots with enabled IO-APIC IRQs, then you have nothing else to do. Your +If your box boots fine with enabled IO-APIC IRQs, then your /proc/interrupts will look like this one: ----------------------------> - hell:~> cat /proc/interrupts - CPU0 CPU1 - 0: 90782 0 XT PIC timer - 1: 4135 2375 IO-APIC keyboard - 2: 0 0 XT PIC cascade - 3: 851 807 IO-APIC serial - 9: 6 22 IO-APIC ncr53c8xx - 11: 307 154 IO-APIC NE2000 - 13: 4 0 XT PIC fpu - 14: 56000 30610 IO-APIC ide0 - NMI: 0 - IPI: 0 - <---------------------------- - -some interrupts will still be 'XT PIC', but this is not a problem, none -of those IRQ sources is 'heavy'. - -If one of your boot messages says 'unlisted/blacklisted board, DISABLING -IO-APIC IRQs', then you should do this to get multi-CPU IO-APIC IRQs -running: - - A) if your board is unlisted, then mail to linux-smp to get - it into either the white or the blacklist - B) if your board is blacklisted, then figure out the appropriate - pirq= option to get your system to boot - - -pirq= lines look like the following in /etc/lilo.conf: + hell:~> cat /proc/interrupts + CPU0 + 0: 1360293 IO-APIC-edge timer + 1: 4 IO-APIC-edge keyboard + 2: 0 XT-PIC cascade + 13: 1 XT-PIC fpu + 14: 1448 IO-APIC-edge ide0 + 16: 28232 IO-APIC-level Intel EtherExpress Pro 10/100 Ethernet + 17: 51304 IO-APIC-level eth0 + NMI: 0 + ERR: 0 + hell:~> + <---------------------------- + +some interrupts are still listed as 'XT PIC', but this is not a problem, +none of those IRQ sources is performance-critical. + + +in the unlikely case that your board does not create a working mp-table, +you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This +is nontrivial though and cannot be automated. One sample /etc/lilo.conf +entry: append="pirq=15,11,10" @@ -111,22 +101,13 @@ won't function properly (if it's inserted as eg. a module). If you have 2 PCI buses, then you can use up to 8 pirq values. Although such -boards tend to have a good configuration and will be included in the -whitelist. +boards tend to have a good configuration. Be prepared that it might happen that you need some strange pirq line: append="pirq=0,0,0,0,0,0,9,11" use smart try-and-err techniques to find out the correct pirq line ... - - -the following pirq line can be used to force a board into the whitelist: - - append="pirq=0" - -[if your system works with no problems after this, then it should be added -to the official whitelist, contact us] good luck and mail to linux-smp@vger.rutgers.edu or linux-kernel@vger.rutgers.edu if you have any problems that are not covered diff -u --recursive --new-file v2.3.11/linux/Documentation/proc_usb_info.txt linux/Documentation/proc_usb_info.txt --- v2.3.11/linux/Documentation/proc_usb_info.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/proc_usb_info.txt Tue Jul 27 16:05:50 1999 @@ -0,0 +1,221 @@ +/proc/bus/usb filesystem output +=============================== +(version 19990722) + + +The /proc filesystem for USB devices generates +/proc/bus/usb/drivers and /proc/bus/usb/devices. + +/proc/bus/usb/drivers just lists the registered drivers, +one per line. Not very interesting or pretty. + +In /proc/bus/usb/devices, each device's output has multiple +lines (except for a root hub) of ASCII output. +I made it ASCII instead of binary on purpose, so that someone +can obtain some useful data from it without the use of an +auxiliary program. However, with an auxiliary program, the numbers +in the first 4 columns of each "T:" line (topology info: +Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram. +(I think. I haven't proved this, but I have tested it with 3 +different topo/connections and it looked possible.) + +Each line is tagged with a one-character ID for that line: + +T = Topology (etc.) +D = Device descriptor info. +P = Product ID info. (from Device descriptor, but they won't fit + together on one line) +C = Configuration descriptor info. (* = active configuration) +I = Interface descriptor info. +E = Endpoint descriptor info. + +======================================================================= + +/proc/bus/usb/devices output format: + +Legend: + d = decimal number (may have leading spaces or 0's) + x = hexadecimal number (may have leading spaces or 0's) + s = string + + +Topology info: + +T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s +| | | | | | | | | |__DriverName +| | | | | | | | |__MaxChildren +| | | | | | | |__Configured InterfaceNumber +| | | | | | |__Device Speed in Mbps +| | | | | |__DeviceNumber +| | | | |__Count of devices at this level +| | | |__Connector/Port on Parent for this device +| | |__Parent DeviceNumber +| |__Level in topology +|__Topology info tag + + +Device descriptor info & Product ID info: + +D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd +P: Vendor=xxxx ProdID=xxxx Rev=xx.xx + +where +D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd +| | | | | | |__NumberConfigurations +| | | | | |__MaxPacketSize of Default Endpoint +| | | | |__DeviceProtocol +| | | |__DeviceSubClass +| | |__DeviceClass +| |__Device USB version +|__Device info tag #1 + +where +P: Vendor=xxxx ProdID=xxxx Rev=xx.xx +| | | |__Product revision number +| | |__Product ID code +| |__Vendor ID code +|__Device info tag #2 + + +Configuration descriptor info: + +C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA +| | | | |__MaxPower in mA +| | | |__Attributes +| | |__ConfiguratioNumber +| |__NumberOfInterfaces +|__Config info tag + + +Interface descriptor info (can be multiple per Config): + +I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx +| | | | | | |__InterfaceProtocol +| | | | | |__InterfaceSubClass +| | | | |__InterfaceClass +| | | |__NumberOfEndpoints +| | |__AlternateSettingNumber +| |__InterfaceNumber +|__Interface info tag + + +Endpoint descriptor info (can be multiple per Interface): + +E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms +E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms +| | | | |__Interval +| | | |__EndpointMaxPacketSize +| | |__Attributes(EndpointType) +| |__EndpointAddress(I=In,O=Out) +|__Endpoint info tag + +======================================================================= + + +If a user or script is interested only in Topology info, for +example, use something like "grep ^T: /proc/bus/usb/devices" +for only the Topology lines. A command like +"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list +only the lines that begin with the characters in square brackets, +where the valid characters are TDPCIE. With a slightly more able +script, it can display any selected lines (for example, only T, D, +and P lines) and change their output format. (The "procusb" +Perl script is the beginning of this idea. It will list only +selected lines [selected from TDPCIE] or "All" lines from +/proc/bus/usb/devices.) + +The Topology lines can be used to generate a graphic/pictorial +of the USB devices on a system's root hub. (See more below +on how to do this.) + +The Configuration lines could be used to list maximum power +(in milliamps) that a system's USB devices are using. +For example, "grep ^C: /proc/bus/usb/devices". + + +Here's an example, from a system which has a UHCI root hub, +an external hub connected to the root hub, and a mouse and +a video camera connected to the external hub. [The video +camera is listed as (none) since it is not recognized by +any driver.] + + +T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub) +T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub +D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0451 ProdID=1446 Rev= 1.00 +C:* #If= 1 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EP= 1 Cls=09(hub ) Sub=00 Prot=00 +E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms +T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse +D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0458 ProdID=0001 Rev= 0.00 +C:* #If= 1 Cfg#= 1 Atr=a0 MxPwr=100mA +I: If#= 0 Alt= 0 #EP= 1 Cls=03(HID ) Sub=01 Prot=02 +E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms +T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none) +D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=04c8 ProdID=0720 Rev= 1.01 +C:* #If= 1 Cfg#= 1 Atr=80 MxPwr=500mA +I: If#= 0 Alt= 0 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 +E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms +E: Ad=82(I) Atr=01(Isoc) MxPS= 384 Ivl= 1ms +I: If#= 0 Alt= 1 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 +E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms +E: Ad=82(I) Atr=01(Isoc) MxPS= 240 Ivl= 1ms +I: If#= 0 Alt= 2 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 +E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms +E: Ad=82(I) Atr=01(Isoc) MxPS= 576 Ivl= 1ms +I: If#= 0 Alt= 3 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 +E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms +E: Ad=82(I) Atr=01(Isoc) MxPS= 464 Ivl= 1ms +I: If#= 0 Alt= 4 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 +E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms +E: Ad=82(I) Atr=01(Isoc) MxPS= 688 Ivl= 1ms + + +Selecting only the "T:" lines from this (for example, by using +"procusb t"), we have: + +T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub) +T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub +T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse +T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none) + + +Physically this looks like (or could be converted to): + + +------------------+ + | PC/root_hub (12)| Dev# = -1 + +------------------+ (nn) is Mbps. + Level 0 | CN.0 | CN.1 | [CN = connector/port #] + +------------------+ + / + / + +-----------------------+ + Level 1 | Dev#1: 4-port hub (12)| + +-----------------------+ + |CN.0 |CN.1 |CN.2 |CN.3 | + +-----------------------+ + \ \____________________ + \_____ \ + \ \ + +--------------------+ +--------------------+ + Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: (none) (12)| + +--------------------+ +--------------------+ + + + +Or, in a more tree-like structure (ports [Connectors] without +connections could be omitted): + +PC: Dev# -1, root hub, 2 ports, 12 Mbps +|_ CN.0: Dev# 1, hub, 4 ports, 12 Mbps + |_ CN.0: Dev #3, mouse, 1.5 Mbps + |_ CN.1: + |_ CN.2: Dev #4, (none), 12 Mbps [or use "unknown" for (none)] + |_ CN.3: +|_ CN.1: + + + ### END ### diff -u --recursive --new-file v2.3.11/linux/Makefile linux/Makefile --- v2.3.11/linux/Makefile Wed Jul 21 15:46:48 1999 +++ linux/Makefile Sat Jul 24 16:46:46 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 11 +SUBLEVEL = 12 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -111,7 +111,7 @@ NETWORKS =net/network.a DRIVERS =drivers/block/block.a \ drivers/char/char.a \ - drivers/misc/misc.a + drivers/parport/parport.a LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib diff -u --recursive --new-file v2.3.11/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.11/linux/arch/alpha/config.in Thu Jul 8 15:42:19 1999 +++ linux/arch/alpha/config.in Sun Jul 25 15:32:53 1999 @@ -188,7 +188,7 @@ 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 -source drivers/misc/Config.in +source drivers/parport/Config.in endmenu source drivers/pnp/Config.in diff -u --recursive --new-file v2.3.11/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.11/linux/arch/alpha/kernel/process.c Wed Jul 21 15:46:48 1999 +++ linux/arch/alpha/kernel/process.c Mon Jul 26 22:41:09 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.3.11/linux/arch/alpha/kernel/signal.c Thu Jul 8 15:42:19 1999 +++ linux/arch/alpha/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -688,12 +688,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c --- v2.3.11/linux/arch/arm/kernel/init_task.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/init_task.c Mon Jul 26 22:41:09 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.3.11/linux/arch/arm/kernel/setup.c Wed Jul 21 15:46:48 1999 +++ linux/arch/arm/kernel/setup.c Fri Jul 23 12:20:23 1999 @@ -297,10 +297,10 @@ setup_processor(); - init_task.mm->start_code = TASK_SIZE; - init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; - init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; - init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + init_mm.start_code = TASK_SIZE; + init_mm.end_code = TASK_SIZE + (unsigned long) &_etext; + init_mm.end_data = TASK_SIZE + (unsigned long) &_edata; + init_mm.brk = TASK_SIZE + (unsigned long) &_end; /* * Add your machine dependencies here diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.3.11/linux/arch/arm/kernel/signal.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -543,12 +543,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.3.11/linux/arch/arm/mm/fault-common.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/mm/fault-common.c Fri Jul 23 12:20:23 1999 @@ -106,7 +106,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto no_context; down(&mm->mmap_sem); diff -u --recursive --new-file v2.3.11/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.11/linux/arch/i386/config.in Thu Jul 8 15:42:19 1999 +++ linux/arch/i386/config.in Sat Jul 24 16:46:46 1999 @@ -92,7 +92,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -source drivers/misc/Config.in +source drivers/parport/Config.in bool 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" = "y" ]; then diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c --- v2.3.11/linux/arch/i386/kernel/init_task.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/kernel/init_task.c Mon Jul 26 22:41:09 1999 @@ -8,7 +8,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.3.11/linux/arch/i386/kernel/io_apic.c Thu May 6 16:07:03 1999 +++ linux/arch/i386/kernel/io_apic.c Sun Jul 25 10:26:01 1999 @@ -5,6 +5,12 @@ * * Many thanks to Stig Venaas for trying out countless experimental * patches and reporting/debugging problems patiently! + * + * (c) 1999, Multiple IO-APIC support, developed by + * Ken-ichi Yaku and + * Hidemi Kishimoto , + * further tested and cleaned up by Zach Brown + * and Ingo Molnar */ #include @@ -19,7 +25,7 @@ * volatile is justified in this case, IO-APIC register contents * might change spontaneously, GCC should not cache it */ -#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE)) +#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx)) /* * The structure of the IO-APIC: @@ -45,9 +51,10 @@ } __attribute__ ((packed)); /* - * # of IRQ routing registers + * # of IO-APICs and # of IRQ routing registers */ -int nr_ioapic_registers = 0; +int nr_ioapics = 0; +int nr_ioapic_registers[MAX_IO_APICS]; enum ioapic_irq_destination_types { dest_Fixed = 0, @@ -94,6 +101,7 @@ mp_ExtINT = 3 }; +struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */ int mp_irq_entries = 0; /* # of MP IRQ source entries */ struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* MP IRQ source entries */ @@ -108,34 +116,34 @@ * between pins and IRQs. */ -static inline unsigned int io_apic_read(unsigned int reg) +static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) { - *IO_APIC_BASE = reg; - return *(IO_APIC_BASE+4); + *IO_APIC_BASE(apic) = reg; + return *(IO_APIC_BASE(apic)+4); } -static inline void io_apic_write(unsigned int reg, unsigned int value) +static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) { - *IO_APIC_BASE = reg; - *(IO_APIC_BASE+4) = value; + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = value; } /* * Re-write a value: to be used for read-modify-write * cycles where the read already set up the index register. */ -static inline void io_apic_modify(unsigned int value) +static inline void io_apic_modify(unsigned int apic, unsigned int value) { - *(IO_APIC_BASE+4) = value; + *(IO_APIC_BASE(apic)+4) = value; } /* * Synchronize the IO-APIC and the CPU by doing * a dummy read from the IO-APIC */ -static inline void io_apic_sync(void) +static inline void io_apic_sync(unsigned int apic) { - (void) *(IO_APIC_BASE+4); + (void) *(IO_APIC_BASE(apic)+4); } /* @@ -146,7 +154,7 @@ #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) static struct irq_pin_list { - int pin, next; + int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; /* @@ -154,7 +162,7 @@ * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq(unsigned int irq, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -168,6 +176,7 @@ if (++first_free_entry >= PIN_MAP_SIZE) panic("io_apic.c: whoops"); } + entry->apic = apic; entry->pin = pin; } @@ -183,9 +192,9 @@ pin = entry->pin; \ if (pin == -1) \ break; \ - reg = io_apic_read(0x10 + R + pin*2); \ + reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ reg ACTION; \ - io_apic_modify(reg); \ + io_apic_modify(entry->apic, reg); \ if (!entry->next) \ break; \ entry = irq_2_pin + entry->next; \ @@ -197,12 +206,12 @@ * We disable IO-APIC IRQs by setting their 'destination CPU mask' to * zero. Trick by Ramesh Nalluri. */ -DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync()) /* destination = 0x00 */ +DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */ DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */ -DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */ +DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ -static void clear_IO_APIC_pin(unsigned int pin) +static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -211,16 +220,17 @@ */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; - io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0)); - io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); + io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); + io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); } static void clear_IO_APIC (void) { - int pin; + int apic, pin; - for (pin = 0; pin < nr_ioapic_registers; pin++) - clear_IO_APIC_pin(pin); + for (apic = 0; apic < nr_ioapics; apic++) + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) + clear_IO_APIC_pin(apic, pin); } /* @@ -270,12 +280,13 @@ /* * Find the IRQ entry number of a certain pin. */ -static int __init find_irq_entry(int pin, int type) +static int __init find_irq_entry(int apic, int pin, int type) { int i; for (i = 0; i < mp_irq_entries; i++) if ( (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) && (mp_irqs[i].mpc_dstirq == pin)) return i; @@ -307,21 +318,26 @@ * Find a specific PCI IRQ entry. * Not an initfunc, possibly needed by modules */ +static int __init pin_2_irq(int idx, int apic, int pin); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) { - int i; + int apic, i; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; - if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) && + for (apic = 0; apic < nr_ioapics; apic++) + if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) + break; + + if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) && (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) && (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) - return mp_irqs[i].mpc_dstirq; + return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); } return -1; } @@ -491,9 +507,9 @@ return MPBIOS_trigger(idx); } -static int __init pin_2_irq(int idx, int pin) +static int __init pin_2_irq(int idx, int apic, int pin) { - int irq; + int irq, i; int bus = mp_irqs[idx].mpc_srcbus; /* @@ -513,9 +529,12 @@ case MP_BUS_PCI: /* PCI pin */ { /* - * PCI IRQs are 'directly mapped' + * PCI IRQs are mapped in order */ - irq = pin; + i = irq = 0; + while (i < apic) + irq += nr_ioapic_registers[i++]; + irq += pin; break; } default: @@ -545,12 +564,14 @@ static inline int IO_APIC_irq_trigger(int irq) { - int idx, pin; + int apic, idx, pin; - for (pin = 0; pin < nr_ioapic_registers; pin++) { - idx = find_irq_entry(pin,mp_INT); - if ((idx != -1) && (irq == pin_2_irq(idx,pin))) - return irq_trigger(idx); + for (apic = 0; apic < nr_ioapics; apic++) { + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { + idx = find_irq_entry(apic,pin,mp_INT); + if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) + return irq_trigger(idx); + } } /* * nonexistent IRQs are edge default @@ -582,11 +603,12 @@ void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; - int pin, idx, bus, irq, first_notcon = 1; + int apic, pin, idx, irq, first_notcon = 1; printk("init IO_APIC IRQs\n"); - for (pin = 0; pin < nr_ioapic_registers; pin++) { + for (apic = 0; apic < nr_ioapics; apic++) { + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { /* * add it to the IO-APIC irq-routing table: @@ -598,13 +620,13 @@ entry.mask = 0; /* enable IRQ */ entry.dest.logical.logical_dest = 0; /* but no route */ - idx = find_irq_entry(pin,mp_INT); + idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(" IO-APIC pin %d", pin); + printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin); first_notcon = 0; } else - printk(", %d", pin); + printk(", %d-%d", mp_apics[apic].mpc_apicid, pin); continue; } @@ -617,18 +639,17 @@ entry.dest.logical.logical_dest = 0xff; } - irq = pin_2_irq(idx,pin); - add_pin_to_irq(irq, pin); + irq = pin_2_irq(idx,apic,pin); + add_pin_to_irq(irq, apic, pin); - if (!IO_APIC_IRQ(irq)) + if (!apic && !IO_APIC_IRQ(irq)) continue; entry.vector = assign_irq_vector(irq); - bus = mp_irqs[idx].mpc_srcbus; - - io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); - io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + } } if (!first_notcon) @@ -638,7 +659,7 @@ /* * Set up a certain pin as ExtINT delivered interrupt */ -void __init setup_ExtINT_pin(unsigned int pin, int irq) +void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq) { struct IO_APIC_route_entry entry; @@ -662,8 +683,8 @@ entry.polarity = 0; entry.trigger = 0; - io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); - io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); } void __init UNEXPECTED_IO_APIC(void) @@ -674,17 +695,14 @@ void __init print_IO_APIC(void) { - int i; + int apic, i; struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; printk("number of MP IRQ sources: %d.\n", mp_irq_entries); - printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers); - - *(int *)®_00 = io_apic_read(0); - *(int *)®_01 = io_apic_read(1); - *(int *)®_02 = io_apic_read(2); + for (i = 0; i < nr_ioapics; i++) + printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]); /* * We are a bit conservative about what we expect. We have to @@ -692,6 +710,12 @@ */ printk("testing the IO APIC.......................\n"); + for (apic = 0; apic < nr_ioapics; apic++) { + + *(int *)®_00 = io_apic_read(apic, 0); + *(int *)®_01 = io_apic_read(apic, 1); + *(int *)®_02 = io_apic_read(apic, 2); + printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid); printk(".... register #00: %08X\n", *(int *)®_00); printk("....... : physical APIC id: %02X\n", reg_00.ID); if (reg_00.__reserved_1 || reg_00.__reserved_2) @@ -706,8 +730,6 @@ (reg_01.entries != 0x3F) /* bigger Xeon boards */ ) UNEXPECTED_IO_APIC(); - if (reg_01.entries == 0x0f) - printk("....... [IO-APIC cannot route PCI PIRQ 0-3]\n"); printk("....... : IO APIC version: %04X\n", reg_01.version); if ( (reg_01.version != 0x10) && /* oldest IO-APICs */ @@ -731,8 +753,8 @@ for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; - *(((int *)&entry)+0) = io_apic_read(0x10+i*2); - *(((int *)&entry)+1) = io_apic_read(0x11+i*2); + *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); + *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); printk(" %02x %03X %02X ", i, @@ -751,7 +773,7 @@ entry.vector ); } - + } printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; @@ -796,9 +818,12 @@ */ { struct IO_APIC_reg_01 reg_01; + int i; - *(int *)®_01 = io_apic_read(1); - nr_ioapic_registers = reg_01.entries+1; + for (i = 0; i < nr_ioapics; i++) { + *(int *)®_01 = io_apic_read(i, 1); + nr_ioapic_registers[i] = reg_01.entries+1; + } } /* @@ -827,55 +852,6 @@ printk("...done.\n"); } -char ioapic_OEM_ID [16]; -char ioapic_Product_ID [16]; - -struct ioapic_list_entry { - char * oem_id; - char * product_id; -}; - -struct ioapic_list_entry __initdata ioapic_whitelist [] = { - - { "INTEL " , "PR440FX " }, - { "INTEL " , "82440FX " }, - { "AIR " , "KDI " }, - { 0 , 0 } -}; - -struct ioapic_list_entry __initdata ioapic_blacklist [] = { - - { "OEM00000" , "PROD00000000" }, - { 0 , 0 } -}; - -static int __init in_ioapic_list(struct ioapic_list_entry * table) -{ - for ( ; table->oem_id ; table++) - if ((!strcmp(table->oem_id,ioapic_OEM_ID)) && - (!strcmp(table->product_id,ioapic_Product_ID))) - return 1; - return 0; -} - -static int __init ioapic_whitelisted(void) -{ -/* - * Right now, whitelist everything to see whether the new parsing - * routines really do work for everybody. - */ -#if 1 - return 1; -#else - return in_ioapic_list(ioapic_whitelist); -#endif -} - -static int __init ioapic_blacklisted(void) -{ - return in_ioapic_list(ioapic_blacklist); -} - static void __init setup_ioapic_id(void) { struct IO_APIC_reg_00 reg_00; @@ -897,15 +873,15 @@ /* * Set the ID */ - *(int *)®_00 = io_apic_read(0); + *(int *)®_00 = io_apic_read(0, 0); printk("...changing IO-APIC physical APIC ID to 2...\n"); reg_00.ID = 0x2; - io_apic_write(0, *(int *)®_00); + io_apic_write(0, 0, *(int *)®_00); /* * Sanity check */ - *(int *)®_00 = io_apic_read(0); + *(int *)®_00 = io_apic_read(0, 0); if (reg_00.ID != 0x2) panic("could not set ID"); } @@ -1227,7 +1203,10 @@ if (pin2 != -1) { printk(".. (found pin %d) ...", pin2); - setup_ExtINT_pin(pin2, 0); + /* + * legacy devices should be connected to IO APIC #0 + */ + setup_ExtINT_pin(0, pin2, 0); make_8259A_irq(0); } @@ -1238,9 +1217,9 @@ * Just in case ... */ if (pin1 != -1) - clear_IO_APIC_pin(pin1); + clear_IO_APIC_pin(0, pin1); if (pin2 != -1) - clear_IO_APIC_pin(pin2); + clear_IO_APIC_pin(0, pin2); make_8259A_irq(0); @@ -1273,29 +1252,8 @@ { init_sym_mode(); - /* - * Determine the range of IRQs handled by the IO-APIC. The - * following boards can be fully enabled: - * - * - whitelisted ones - * - those which have no PCI pins connected - * - those for which the user has specified a pirq= parameter - */ - if ( ioapic_whitelisted() || - (nr_ioapic_registers == 16) || - pirqs_enabled) - { - printk("ENABLING IO-APIC IRQs\n"); - io_apic_irqs = ~PIC_IRQS; - } else { - if (ioapic_blacklisted()) - printk(" blacklisted board, DISABLING IO-APIC IRQs\n"); - else - printk(" unlisted board, DISABLING IO-APIC IRQs\n"); - - printk(" see Documentation/IO-APIC.txt to enable them\n"); - io_apic_irqs = 0; - } + printk("ENABLING IO-APIC IRQs\n"); + io_apic_irqs = ~PIC_IRQS; /* * If there are no explicit MP IRQ entries, it's either one of the diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.3.11/linux/arch/i386/kernel/irq.h Thu Jul 8 15:42:19 1999 +++ linux/arch/i386/kernel/irq.h Wed Jul 28 13:58:07 1999 @@ -57,9 +57,9 @@ /* * Special IRQ vectors used by the SMP architecture: * - * (some of the following vectors are 'rare', they might be merged - * into a single vector to save vector space. TLB, reschedule and - * local APIC vectors are performance-critical.) + * (some of the following vectors are 'rare', they are merged + * into a single vector (FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical.) */ #define RESCHEDULE_VECTOR 0x30 #define INVALIDATE_TLB_VECTOR 0x31 @@ -120,8 +120,6 @@ }; extern int mp_bus_id_to_type [MAX_MP_BUSSES]; extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; -extern char ioapic_OEM_ID [16]; -extern char ioapic_Product_ID [16]; extern spinlock_t irq_controller_lock; diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.11/linux/arch/i386/kernel/process.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/kernel/process.c Sun Jul 25 23:15:13 1999 @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -321,13 +322,9 @@ pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* - * Use `swapper_pg_dir' as our page directory. We bother with - * `SET_PAGE_DIR' because although might be rebooting, but if we change - * the way we set root page dir in the future, then we wont break a - * seldom used feature ;) + * Use `swapper_pg_dir' as our page directory. */ - - SET_PAGE_DIR(current,swapper_pg_dir); + asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir))); /* Write 0x1234 to absolute memory location 0x472. The BIOS reads this on booting to tell it to "Bypass memory test (also warm @@ -488,16 +485,7 @@ */ if (ldt) { mm->segments = NULL; - /* - * special case, when we release the LDT from under - * the running CPU. Other CPUs cannot possibly use - * this LDT as we were getting here through mmput() ... - */ - if (mm == current->mm) - load_LDT(mm); - /* - * Nobody anymore uses the LDT, we can free it: - */ + clear_LDT(); vfree(ldt); } } @@ -579,12 +567,8 @@ } /* - * If new_mm is NULL, we're being called to set up the LDT for - * a clone task: this is easy since the clone is not running yet. - * otherwise we copy the old segment into a new segment. - * * we do not have to muck with descriptors here, that is - * done in __switch_to() and get_mmu_context(). + * done in switch_mm() as needed. */ void copy_segments(struct task_struct *p, struct mm_struct *new_mm) { @@ -595,22 +579,19 @@ /* * default LDT - use the one from init_task */ - if (new_mm) - new_mm->segments = NULL; + new_mm->segments = NULL; return; } - if (new_mm) { - /* - * Completely new LDT, we initialize it from the parent: - */ - ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (!ldt) - printk(KERN_WARNING "ldt allocation failed\n"); - else - memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); - new_mm->segments = ldt; - } + /* + * Completely new LDT, we initialize it from the parent: + */ + ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (!ldt) + printk(KERN_WARNING "ldt allocation failed\n"); + else + memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); + new_mm->segments = ldt; return; } @@ -754,21 +735,6 @@ */ asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs)); asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); - - /* - * Re-load LDT if necessary - */ - if (prev_p->active_mm->segments != next_p->active_mm->segments) - load_LDT(next_p->mm); - - /* Re-load page tables */ - { - unsigned long new_cr3 = next->cr3; - - tss->cr3 = new_cr3; - if (new_cr3 != prev->cr3) - asm volatile("movl %0,%%cr3": :"r" (new_cr3)); - } /* * Restore %fs and %gs. diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.11/linux/arch/i386/kernel/setup.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/kernel/setup.c Sun Jul 25 13:45:25 1999 @@ -313,10 +313,10 @@ if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; memory_start = (unsigned long) &_end; - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) &_etext; - init_task.mm->end_data = (unsigned long) &_edata; - init_task.mm->brk = (unsigned long) &_end; + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); @@ -354,7 +354,7 @@ *to = '\0'; *cmdline_p = command_line; -#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */ +#define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */ #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) if (memory_end > MAXMEM) diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.3.11/linux/arch/i386/kernel/signal.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -687,12 +687,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.11/linux/arch/i386/kernel/smp.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/kernel/smp.c Wed Jul 28 10:45:39 1999 @@ -128,6 +128,8 @@ const char lk_lockmsg[] = "lock from interrupt context at %p\n"; int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; +extern int nr_ioapics; +extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS]; extern int mp_irq_entries; extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; extern int mpc_default_type; @@ -258,12 +260,10 @@ } memcpy(str,mpc->mpc_oem,8); str[8]=0; - memcpy(ioapic_OEM_ID,str,9); printk("OEM ID: %s ",str); memcpy(str,mpc->mpc_productid,12); str[12]=0; - memcpy(ioapic_Product_ID,str,13); printk("Product ID: %s ",str); printk("APIC at: 0x%lX\n",mpc->mpc_lapic); @@ -368,11 +368,9 @@ printk("I/O APIC #%d Version %d at 0x%lX.\n", m->mpc_apicid,m->mpc_apicver, m->mpc_apicaddr); - /* - * we use the first one only currently - */ - if (ioapics == 1) - mp_ioapic_addr = m->mpc_apicaddr; + mp_apics [nr_ioapics] = *m; + if (++nr_ioapics > MAX_IO_APICS) + --nr_ioapics; } mpt+=sizeof(*m); count+=sizeof(*m); @@ -404,9 +402,9 @@ } } } - if (ioapics > 1) + if (ioapics > MAX_IO_APICS) { - printk("Warning: Multiple IO-APICs not yet supported.\n"); + printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics); printk("Warning: switching to non APIC mode.\n"); skip_ioapic_setup=1; } @@ -774,18 +772,22 @@ #ifdef CONFIG_X86_IO_APIC { - unsigned long ioapic_phys; + unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; + int i; - if (smp_found_config) { - ioapic_phys = mp_ioapic_addr; - } else { - ioapic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; + for (i = 0; i < nr_ioapics; i++) { + if (smp_found_config) { + ioapic_phys = mp_apics[i].mpc_apicaddr; + } else { + ioapic_phys = __pa(memory_start); + memset((void *)memory_start, 0, PAGE_SIZE); + memory_start += PAGE_SIZE; + } + set_fixmap(idx,ioapic_phys); + printk("mapped IOAPIC to %08lx (%08lx)\n", + __fix_to_virt(idx), ioapic_phys); + idx++; } - set_fixmap(FIX_IO_APIC_BASE,ioapic_phys); - printk("mapped IOAPIC to %08lx (%08lx)\n", - fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys); } #endif @@ -1382,12 +1384,6 @@ printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); SMP_PRINTK(("Boot done.\n")); - /* - * now we know the other CPUs have fired off and we know our - * APIC ID, so we can go init the TSS and stuff: - */ - cpu_init(); - cache_APIC_registers(); #ifndef CONFIG_VISWS /* @@ -1399,6 +1395,11 @@ #endif smp_done: + /* + * now we know the other CPUs have fired off and we know our + * APIC ID, so we can go init the TSS and stuff: + */ + cpu_init(); } @@ -1578,8 +1579,7 @@ * bad as in the early days of SMP, so we might ease some of the * paranoia here. */ - -void smp_flush_tlb(void) +static void flush_tlb_others(unsigned int cpumask) { int cpu = smp_processor_id(); int stuck; @@ -1589,17 +1589,9 @@ * it's important that we do not generate any APIC traffic * until the AP CPUs have booted up! */ - if (cpu_online_map) { - /* - * The assignment is safe because it's volatile so the - * compiler cannot reorder it, because the i586 has - * strict memory ordering and because only the kernel - * lock holder may issue a tlb flush. If you break any - * one of those three change this to an atomic bus - * locked or. - */ - - smp_invalidate_needed = cpu_online_map; + cpumask &= cpu_online_map; + if (cpumask) { + atomic_set_mask(cpumask, &smp_invalidate_needed); /* * Processors spinning on some lock with IRQs disabled @@ -1622,8 +1614,10 @@ /* * Take care of "crossing" invalidates */ - if (test_bit(cpu, &smp_invalidate_needed)) - clear_bit(cpu, &smp_invalidate_needed); + if (test_bit(cpu, &smp_invalidate_needed)) { + clear_bit(cpu, &smp_invalidate_needed); + local_flush_tlb(); + } --stuck; if (!stuck) { printk("stuck on TLB IPI wait (CPU#%d)\n",cpu); @@ -1632,12 +1626,58 @@ } __restore_flags(flags); } +} - /* - * Flush the local TLB - */ +/* + * Smarter SMP flushing macros. + * c/o Linus Torvalds. + * + * These mean you can really definitely utterly forget about + * writing to user space from interrupts. (Its not allowed anyway). + */ +void flush_tlb_current_task(void) +{ + unsigned long vm_mask = 1 << current->processor; + struct mm_struct *mm = current->mm; + + if (mm->cpu_vm_mask != vm_mask) { + flush_tlb_others(mm->cpu_vm_mask & ~vm_mask); + mm->cpu_vm_mask = vm_mask; + } local_flush_tlb(); +} + +void flush_tlb_mm(struct mm_struct * mm) +{ + unsigned long vm_mask = 1 << current->processor; + unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + + mm->cpu_vm_mask = 0; + if (current->active_mm == mm) { + mm->cpu_vm_mask = vm_mask; + local_flush_tlb(); + } + flush_tlb_others(cpu_mask); +} +void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) +{ + unsigned long vm_mask = 1 << current->processor; + struct mm_struct *mm = vma->vm_mm; + unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + + mm->cpu_vm_mask = 0; + if (current->active_mm == mm) { + __flush_tlb_one(va); + mm->cpu_vm_mask = vm_mask; + } + flush_tlb_others(cpu_mask); +} + +void flush_tlb_all(void) +{ + flush_tlb_others(~(1 << current->processor)); + local_flush_tlb(); } @@ -1860,13 +1900,24 @@ } /* - * Invalidate call-back + * Invalidate call-back. + * + * Mark the CPU as a VM user if there is a active + * thread holding on to an mm at this time. This + * allows us to optimize CPU cross-calls even in the + * presense of lazy TLB handling. */ asmlinkage void smp_invalidate_interrupt(void) { - if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed)) - local_flush_tlb(); + struct task_struct *tsk = current; + unsigned int cpu = tsk->processor; + if (test_and_clear_bit(cpu, &smp_invalidate_needed)) { + struct mm_struct *mm = tsk->mm; + if (mm) + atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); + local_flush_tlb(); + } ack_APIC_irq(); } diff -u --recursive --new-file v2.3.11/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c --- v2.3.11/linux/arch/i386/math-emu/fpu_entry.c Sun Sep 13 12:17:48 1998 +++ linux/arch/i386/math-emu/fpu_entry.c Fri Jul 23 13:19:02 1999 @@ -283,8 +283,8 @@ FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */ RE_ENTRANT_CHECK_OFF; - current->tss.trap_no = 16; - current->tss.error_code = 0; + current->thread.trap_no = 16; + current->thread.error_code = 0; send_sig(SIGFPE, current, 1); return; } @@ -662,8 +662,8 @@ void math_abort(struct info * info, unsigned int signal) { FPU_EIP = FPU_ORIG_EIP; - current->tss.trap_no = 16; - current->tss.error_code = 0; + current->thread.trap_no = 16; + current->thread.error_code = 0; send_sig(signal,current,1); RE_ENTRANT_CHECK_OFF; __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); diff -u --recursive --new-file v2.3.11/linux/arch/i386/math-emu/fpu_system.h linux/arch/i386/math-emu/fpu_system.h --- v2.3.11/linux/arch/i386/math-emu/fpu_system.h Sun Sep 13 12:58:04 1998 +++ linux/arch/i386/math-emu/fpu_system.h Fri Jul 23 13:19:02 1999 @@ -33,7 +33,7 @@ #define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \ == (1 << 10)) -#define I387 (current->tss.i387) +#define I387 (current->thread.i387) #define FPU_info (I387.soft.info) #define FPU_CS (*(unsigned short *) &(FPU_info->___cs)) diff -u --recursive --new-file v2.3.11/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.3.11/linux/arch/i386/mm/fault.c Wed Jul 21 15:46:48 1999 +++ linux/arch/i386/mm/fault.c Wed Jul 28 10:45:39 1999 @@ -245,9 +245,6 @@ printk(" at virtual address %08lx\n",address); printk(" printing eip:\n"); printk("%08lx\n", regs->eip); - __asm__("movl %%cr3,%0" : "=r" (page)); - printk(KERN_ALERT "current->thread.cr3 = %08lx, %%cr3 = %08lx\n", - tsk->thread.cr3, page); page = ((unsigned long *) __va(page))[address >> 22]; printk(KERN_ALERT "*pde = %08lx\n", page); if (page & 1) { diff -u --recursive --new-file v2.3.11/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v2.3.11/linux/arch/m68k/atari/stram.c Wed Nov 11 11:50:00 1998 +++ linux/arch/m68k/atari/stram.c Fri Jul 23 12:20:23 1999 @@ -805,7 +805,7 @@ /* * Go through process' page directory. */ - if (!mm || mm == &init_mm) + if (!mm) return; for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.3.11/linux/arch/m68k/kernel/process.c Tue May 11 09:57:14 1999 +++ linux/arch/m68k/kernel/process.c Mon Jul 26 22:41:09 1999 @@ -40,10 +40,9 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); union task_union init_task_union __attribute__((section("init_task"), aligned(2*PAGE_SIZE))) diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.3.11/linux/arch/m68k/kernel/setup.c Tue May 11 09:57:14 1999 +++ linux/arch/m68k/kernel/setup.c Fri Jul 23 12:20:23 1999 @@ -213,10 +213,10 @@ asm __volatile__ ("frestore %0" : : "m" (zero)); } - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) &_etext; - init_task.mm->end_data = (unsigned long) &_edata; - init_task.mm->brk = (unsigned long) &_end; + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; *cmdline_p = m68k_command_line; memcpy(saved_command_line, *cmdline_p, CL_SIZE); diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.3.11/linux/arch/m68k/kernel/signal.c Thu Jan 7 08:41:55 1999 +++ linux/arch/m68k/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -1084,9 +1084,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -u --recursive --new-file v2.3.11/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v2.3.11/linux/arch/m68k/mm/fault.c Thu Dec 17 09:06:30 1998 +++ linux/arch/m68k/mm/fault.c Fri Jul 23 12:20:23 1999 @@ -49,7 +49,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto no_context; down(&mm->mmap_sem); diff -u --recursive --new-file v2.3.11/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.3.11/linux/arch/mips/config.in Thu Jul 8 15:42:19 1999 +++ linux/arch/mips/config.in Sat Jul 24 16:46:46 1999 @@ -93,7 +93,7 @@ bool 'Sysctl support' CONFIG_SYSCTL if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then -source drivers/misc/Config.in +source drivers/parport/Config.in fi endmenu diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c --- v2.3.11/linux/arch/mips/kernel/init_task.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/init_task.c Mon Jul 26 22:41:09 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.3.11/linux/arch/mips/kernel/irixelf.c Wed Jul 21 15:46:48 1999 +++ linux/arch/mips/kernel/irixelf.c Sun Jul 25 13:45:25 1999 @@ -48,11 +48,13 @@ extern int dump_fpu (elf_fpregset_t *); static struct linux_binfmt irix_format = { + NULL, #ifndef MODULE - NULL, NULL, load_irix_binary, load_irix_library, irix_core_dump + NULL, #else - NULL, &__this_module.usecount, load_irix_binary, load_irix_library, irix_core_dump + &__this_module.usecount, #endif + load_irix_binary, load_irix_library, irix_core_dump, PAGE_SIZE }; #ifndef elf_addr_t @@ -1105,24 +1107,20 @@ #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (addr), (nr))) \ - goto close_coredump; + goto end_coredump; #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ - goto close_coredump; + goto end_coredump; /* Actual dumper. * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ -static int irix_core_dump(long signr, struct pt_regs * regs) +static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) { int has_dumped = 0; - struct file *file; - struct dentry *dentry; - struct inode *inode; mm_segment_t fs; - char corefile[6+sizeof(current->comm)]; int segs; int i; size_t size; @@ -1135,10 +1133,6 @@ struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - - if (!current->dumpable || limit < PAGE_SIZE) - return 0; - current->dumpable = 0; #ifndef CONFIG_BINFMT_IRIX MOD_INC_USE_COUNT; @@ -1188,27 +1182,6 @@ fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.", 5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (inode->i_nlink > 1) - goto close_coredump; /* multiple links - don't dump */ - - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; - has_dumped = 1; current->flags |= PF_DUMPCORE; @@ -1345,7 +1318,7 @@ for(i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) - goto close_coredump; + goto end_coredump; set_fs(fs); @@ -1371,9 +1344,6 @@ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } - - close_coredump: - filp_close(file, NULL); end_coredump: set_fs(fs); diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c --- v2.3.11/linux/arch/mips/kernel/irixsig.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/irixsig.c Thu Jul 22 09:47:55 1999 @@ -261,12 +261,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.3.11/linux/arch/mips/kernel/signal.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -493,12 +493,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.3.11/linux/arch/mips/mm/fault.c Thu Jul 8 15:42:19 1999 +++ linux/arch/mips/mm/fault.c Fri Jul 23 12:20:23 1999 @@ -55,7 +55,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto no_context; #if 0 printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid, diff -u --recursive --new-file v2.3.11/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.11/linux/arch/ppc/config.in Wed Jul 21 15:46:48 1999 +++ linux/arch/ppc/config.in Sat Jul 24 16:46:46 1999 @@ -66,7 +66,7 @@ define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -source drivers/misc/Config.in +source drivers/parport/Config.in bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.11/linux/arch/ppc/kernel/apus_setup.c Thu May 13 11:00:08 1999 +++ linux/arch/ppc/kernel/apus_setup.c Fri Jul 23 12:20:23 1999 @@ -345,7 +345,7 @@ { pte_t *pte; - pte = my_find_pte(init_task.mm, address); + pte = my_find_pte(&init_mm, address); if ( !pte ) { printk("pte NULL in kernel_set_cachemode()\n"); @@ -354,7 +354,7 @@ pte_val (*pte) &= mask; pte_val (*pte) |= flags; - flush_tlb_page(find_vma(init_task.mm,address),address); + flush_tlb_page(find_vma(&init_mm,address),address); address += PAGE_SIZE; } diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.3.11/linux/arch/ppc/kernel/idle.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/idle.c Fri Jul 23 12:20:23 1999 @@ -227,7 +227,7 @@ /* * Make the page no cache so we don't blow our cache with 0's */ - pte = find_pte(init_task.mm, pageptr); + pte = find_pte(&init_mm, pageptr); if ( !pte ) { printk("pte NULL in zero_paged()\n"); @@ -235,7 +235,7 @@ } pte_uncache(*pte); - flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr); + flush_tlb_page(find_vma(&init_mm,pageptr),pageptr); /* * Important here to not take time away from real processes. */ @@ -260,7 +260,7 @@ /* turn cache on for this page */ pte_cache(*pte); - flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr); + flush_tlb_page(find_vma(&init_mm,pageptr),pageptr); /* atomically add this page to the list */ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_cache */ " stw %0,0(%2)\n" /* update *pageptr */ diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.11/linux/arch/ppc/kernel/process.c Wed Jul 21 15:46:48 1999 +++ linux/arch/ppc/kernel/process.c Mon Jul 26 22:41:09 1999 @@ -47,7 +47,6 @@ struct task_struct *last_task_used_math = NULL; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.11/linux/arch/ppc/kernel/setup.c Wed Jul 21 15:46:48 1999 +++ linux/arch/ppc/kernel/setup.c Fri Jul 23 12:20:23 1999 @@ -527,10 +527,10 @@ /* reboot on panic */ panic_timeout = 180; - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) _etext; - init_task.mm->end_data = (unsigned long) _edata; - init_task.mm->brk = (unsigned long) klimit; + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) klimit; /* Save unparsed command line copy for /proc/cmdline */ strcpy(saved_command_line, cmd_line); diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.3.11/linux/arch/ppc/kernel/signal.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -444,12 +444,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.3.11/linux/arch/ppc/kernel/smp.c Wed Jul 21 15:46:48 1999 +++ linux/arch/ppc/kernel/smp.c Fri Jul 23 12:20:23 1999 @@ -403,7 +403,7 @@ #if 0 current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + current->mm->mmap->vm_end = init_mm.mmap->vm_end; #endif cpu_callin_map[current->processor] = 1; while(!smp_commenced) diff -u --recursive --new-file v2.3.11/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.3.11/linux/arch/ppc/mm/fault.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/mm/fault.c Fri Jul 23 12:20:23 1999 @@ -82,7 +82,7 @@ return; } #endif - if (in_interrupt()) { + if (in_interrupt() || !mm) { static int complained; if (complained < 20) { ++complained; diff -u --recursive --new-file v2.3.11/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.11/linux/arch/ppc/mm/init.c Wed Jul 21 15:46:48 1999 +++ linux/arch/ppc/mm/init.c Sun Jul 25 13:45:25 1999 @@ -444,11 +444,11 @@ #endif /* CONFIG_APUS */ #endif /* CONFIG_8xx */ /* Do we have a page table? */ - if (init_task.mm->pgd == NULL) + if (init_mm.pgd == NULL) return 0; /* Use upper 10 bits of addr to index the first level map */ - pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT)); + pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT)); if (pmd_none(*pd)) return 0; diff -u --recursive --new-file v2.3.11/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c --- v2.3.11/linux/arch/sparc/ap1000/apmmu.c Tue Apr 14 17:44:18 1998 +++ linux/arch/sparc/ap1000/apmmu.c Fri Jul 23 12:20:23 1999 @@ -295,7 +295,7 @@ static inline void apmmu_uncache_page(unsigned long addr) { - pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr); + pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr); pmd_t *pmdp; pte_t *ptep; @@ -316,7 +316,7 @@ static inline void apmmu_recache_page(unsigned long addr) { - pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr); + pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr); pmd_t *pmdp; pte_t *ptep; @@ -782,7 +782,7 @@ pte_t *ptep; while(start < end) { - pgdp = apmmu_pgd_offset(init_task.mm, start); + pgdp = apmmu_pgd_offset(&init_mm, start); if(apmmu_pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); apmmu_early_pgd_set(pgdp, pmdp); @@ -804,7 +804,7 @@ pte_t *ptep; unsigned start = virt_page<<12; - pgdp = apmmu_pgd_offset(init_task.mm, start); + pgdp = apmmu_pgd_offset(&init_mm, start); if(apmmu_pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); apmmu_early_pgd_set(pgdp, pmdp); @@ -824,7 +824,7 @@ pgd_t *pgdp; unsigned start = virt_page<<12; - pgdp = apmmu_pgd_offset(init_task.mm, start); + pgdp = apmmu_pgd_offset(&init_mm, start); *pgdp = __pgd((phys_page<<8) | prot); } @@ -907,7 +907,7 @@ make_large_page((KERNBASE+phys)>>12, (phys>>12), APMMU_CACHE|APMMU_PRIV|APMMU_VALID); - init_task.mm->mmap->vm_start = page_offset = KERNBASE; + init_mm.mmap->vm_start = page_offset = KERNBASE; stack_top = page_offset - PAGE_SIZE; } diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c --- v2.3.11/linux/arch/sparc/kernel/init_task.c Wed May 12 08:41:12 1999 +++ linux/arch/sparc/kernel/init_task.c Mon Jul 26 22:41:09 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.3.11/linux/arch/sparc/kernel/setup.c Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/kernel/setup.c Fri Jul 23 12:20:23 1999 @@ -489,10 +489,10 @@ /* Due to stack alignment restrictions and assumptions... */ - init_task.mm->mmap->vm_page_prot = PAGE_SHARED; - init_task.mm->mmap->vm_start = KERNBASE; - init_task.mm->mmap->vm_end = *memory_end_p; - init_task.mm->context = (unsigned long) NO_CONTEXT; + init_mm.mmap->vm_page_prot = PAGE_SHARED; + init_mm.mmap->vm_start = KERNBASE; + init_mm.mmap->vm_end = *memory_end_p; + init_mm.context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; if (serial_console) diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.3.11/linux/arch/sparc/kernel/signal.c Thu Jun 17 01:08:50 1999 +++ linux/arch/sparc/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -1160,14 +1160,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - if(current->binfmt && current->binfmt->core_dump) { - lock_kernel(); - if(current->binfmt && - current->binfmt->core_dump && - current->binfmt->core_dump(signr, regs)) - exit_code |= 0x80; - unlock_kernel(); - } + if (do_coredump(signr, regs)) + exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.11/linux/arch/sparc/kernel/sun4d_smp.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc/kernel/sun4d_smp.c Fri Jul 23 12:20:23 1999 @@ -131,7 +131,7 @@ current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + current->mm->mmap->vm_end = init_mm.mmap->vm_end; local_flush_cache_all(); local_flush_tlb_all(); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.11/linux/arch/sparc/kernel/sun4m_smp.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc/kernel/sun4m_smp.c Fri Jul 23 12:20:23 1999 @@ -109,7 +109,7 @@ : "memory" /* paranoid */); current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + current->mm->mmap->vm_end = init_mm.mmap->vm_end; while(!smp_commenced) barrier(); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.3.11/linux/arch/sparc/mm/fault.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc/mm/fault.c Fri Jul 23 12:20:23 1999 @@ -205,7 +205,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto do_kernel_fault; down(&mm->mmap_sem); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.11/linux/arch/sparc/mm/srmmu.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc/mm/srmmu.c Sun Jul 25 13:45:25 1999 @@ -846,7 +846,7 @@ unsigned long tmp; physaddr &= PAGE_MASK; - pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); + pgdp = srmmu_pgd_offset(&init_mm, virt_addr); pmdp = pmd_offset(pgdp, virt_addr); ptep = pte_offset(pmdp, virt_addr); tmp = (physaddr >> 4) | SRMMU_ET_PTE; @@ -871,7 +871,7 @@ pmd_t *pmdp; pte_t *ptep; - pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); + pgdp = srmmu_pgd_offset(&init_mm, virt_addr); pmdp = pmd_offset(pgdp, virt_addr); ptep = pte_offset(pmdp, virt_addr); @@ -1476,7 +1476,7 @@ pte_t *ptep; while(start < end) { - pgdp = srmmu_pgd_offset(init_task.mm, start); + pgdp = srmmu_pgd_offset(&init_mm, start); if(srmmu_pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); srmmu_early_pgd_set(pgdp, pmdp); @@ -1526,7 +1526,7 @@ what = 2; } - pgdp = srmmu_pgd_offset(init_task.mm, start); + pgdp = srmmu_pgd_offset(&init_mm, start); if(what == 2) { *pgdp = __pgd(prompte); start += SRMMU_PGDIR_SIZE; @@ -1626,7 +1626,7 @@ /* Create a third-level SRMMU 16MB page mapping. */ __initfunc(static void do_large_mapping(unsigned long vaddr, unsigned long phys_base)) { - pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, vaddr); + pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr); unsigned long big_pte; MKTRACE(("dlm[v<%08lx>-->p<%08lx>]", vaddr, phys_base)); @@ -1840,7 +1840,7 @@ } } MKTRACE(("success\n")); - init_task.mm->mmap->vm_start = page_offset = low_base; + init_mm.mmap->vm_start = page_offset = low_base; stack_top = page_offset - PAGE_SIZE; BTFIXUPSET_SETHI(page_offset, low_base); BTFIXUPSET_SETHI(stack_top, page_offset - PAGE_SIZE); diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.11/linux/arch/sparc/mm/sun4c.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc/mm/sun4c.c Sun Jul 25 13:45:25 1999 @@ -1560,7 +1560,7 @@ memset((void *) start_mem, 0, bitmap_size); start_mem += bitmap_size; - sun4c_kstack_vma.vm_mm = init_task.mm; + sun4c_kstack_vma.vm_mm = &init_mm; sun4c_kstack_vma.vm_start = sun4c_taskstack_start; sun4c_kstack_vma.vm_end = sun4c_taskstack_end; sun4c_kstack_vma.vm_page_prot = PAGE_SHARED; diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.11/linux/arch/sparc64/config.in Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc64/config.in Sat Jul 24 16:46:46 1999 @@ -68,7 +68,7 @@ fi if [ "$CONFIG_PCI" = "y" ]; then - source drivers/misc/Config.in + source drivers/parport/Config.in dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.3.11/linux/arch/sparc64/kernel/binfmt_aout32.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Sun Jul 25 13:45:25 1999 @@ -39,7 +39,8 @@ extern void dump_thread(struct pt_regs *, struct user *); static struct linux_binfmt aout32_format = { - NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump + NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump, + PAGE_SIZE }; static void set_brk(unsigned long start, unsigned long end) @@ -63,12 +64,12 @@ #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (void *)(addr), (nr))) \ - goto close_coredump; + goto end_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ if (file->f_op->llseek(file,(offset),0) != (offset)) \ - goto close_coredump; \ + goto end_coredump; \ } else file->f_pos = (offset) /* @@ -82,45 +83,17 @@ */ static inline int -do_aout32_core_dump(long signr, struct pt_regs * regs) +do_aout32_core_dump(long signr, struct pt_regs * regs, struct file *file) { - struct dentry * dentry = NULL; - struct inode * inode = NULL; - struct file * file; mm_segment_t fs; int has_dumped = 0; - char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; # define START_DATA(u) (u.u_tsize) # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) - if (!current->dumpable || atomic_read(¤t->mm->count) != 1) - return 0; - current->dumpable = 0; - -/* See if we have enough room to write the upage. */ - if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) - return 0; fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); @@ -165,20 +138,18 @@ /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); -close_coredump: - filp_close(file, NULL); end_coredump: set_fs(fs); return has_dumped; } static int -aout32_core_dump(long signr, struct pt_regs * regs) +aout32_core_dump(long signr, struct pt_regs * regs, struct file * file) { int retval; MOD_INC_USE_COUNT; - retval = do_aout32_core_dump(signr, regs); + retval = do_aout32_core_dump(signr, regs, file); MOD_DEC_USE_COUNT; return retval; } diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/init_task.c linux/arch/sparc64/kernel/init_task.c --- v2.3.11/linux/arch/sparc64/kernel/init_task.c Wed May 12 08:41:12 1999 +++ linux/arch/sparc64/kernel/init_task.c Mon Jul 26 22:41:09 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.3.11/linux/arch/sparc64/kernel/setup.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/kernel/setup.c Fri Jul 23 12:20:23 1999 @@ -531,10 +531,10 @@ #endif /* Due to stack alignment restrictions and assumptions... */ - init_task.mm->mmap->vm_page_prot = PAGE_SHARED; - init_task.mm->mmap->vm_start = PAGE_OFFSET; - init_task.mm->mmap->vm_end = *memory_end_p; - init_task.mm->context = (unsigned long) NO_CONTEXT; + init_mm.mmap->vm_page_prot = PAGE_SHARED; + init_mm.mmap->vm_start = PAGE_OFFSET; + init_mm.mmap->vm_end = *memory_end_p; + init_mm.context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; #ifdef CONFIG_IP_PNP diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.3.11/linux/arch/sparc64/kernel/signal.c Thu Jun 17 01:08:50 1999 +++ linux/arch/sparc64/kernel/signal.c Thu Jul 22 09:47:55 1999 @@ -866,12 +866,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - if(current->binfmt && current->binfmt->core_dump) { - lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) - exit_code |= 0x80; - unlock_kernel(); - } + if (do_coredump(signr, regs)) + exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug the dynamic linker */ printk ("Sig %d going...\n", (int)signr); diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.3.11/linux/arch/sparc64/kernel/signal32.c Thu Jun 17 01:08:50 1999 +++ linux/arch/sparc64/kernel/signal32.c Thu Jul 22 09:47:55 1999 @@ -1291,14 +1291,8 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - if(current->binfmt && current->binfmt->core_dump) { - lock_kernel(); - if(current->binfmt && - current->binfmt->core_dump && - current->binfmt->core_dump(signr, regs)) - exit_code |= 0x80; - unlock_kernel(); - } + if (do_coredump(signr, regs)) + exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.3.11/linux/arch/sparc64/mm/fault.c Thu Jul 8 15:42:19 1999 +++ linux/arch/sparc64/mm/fault.c Fri Jul 23 12:20:23 1999 @@ -154,7 +154,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto do_kernel_fault; down(&mm->mmap_sem); diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c --- v2.3.11/linux/arch/sparc64/solaris/timod.c Wed May 12 08:41:12 1999 +++ linux/arch/sparc64/solaris/timod.c Mon Jul 26 22:41:09 1999 @@ -866,7 +866,7 @@ SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if(fd >= current->files->max_fds) goto out; filp = current->files->fd[fd]; if(!filp) goto out; @@ -933,7 +933,7 @@ SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if(fd >= current->files->max_fds) goto out; filp = current->files->fd[fd]; if(!filp) goto out; diff -u --recursive --new-file v2.3.11/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.11/linux/drivers/Makefile Wed Jun 30 13:38:19 1999 +++ linux/drivers/Makefile Sat Jul 24 16:46:46 1999 @@ -7,7 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile. -SUB_DIRS := block char net misc sound +SUB_DIRS := block char net parport sound MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \ macintosh video dio zorro fc4 usb \ diff -u --recursive --new-file v2.3.11/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.11/linux/drivers/block/ll_rw_blk.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/block/ll_rw_blk.c Tue Jul 27 16:06:40 1999 @@ -403,7 +403,7 @@ unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; if (maxsector < count || maxsector - count < sector) { - bh->b_state &= (1 << BH_Lock); + bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); /* This may well happen - the kernel calls bread() without checking the size of the device, e.g., when mounting a device. */ @@ -428,6 +428,9 @@ kstat.pgpgin++; max_req = NR_REQUEST; /* reads take precedence */ break; + case WRITERAW: + rw = WRITE; + goto do_write; /* Skip the buffer refile */ case WRITEA: rw_ahead = 1; rw = WRITE; /* drop into WRITE */ @@ -435,6 +438,7 @@ if (!test_and_clear_bit(BH_Dirty, &bh->b_state)) goto end_io; /* Hmmph! Nothing to write */ refile_buffer(bh); + do_write: /* * We don't allow the write-requests to fill up the * queue completely: we want some room for reads, @@ -641,7 +645,7 @@ #endif } - if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { + if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { printk(KERN_NOTICE "Can't write to read-only device %s\n", kdevname(bh[0]->b_dev)); goto sorry; diff -u --recursive --new-file v2.3.11/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.11/linux/drivers/char/Makefile Thu Jul 8 15:42:20 1999 +++ linux/drivers/char/Makefile Mon Jul 26 22:50:35 1999 @@ -20,7 +20,7 @@ L_TARGET := char.a M_OBJS := -L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o +L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o LX_OBJS := pty.o misc.o ifdef CONFIG_VT diff -u --recursive --new-file v2.3.11/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.11/linux/drivers/char/mem.c Fri May 14 18:15:02 1999 +++ linux/drivers/char/mem.c Mon Jul 26 22:50:35 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -602,6 +603,7 @@ if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); + raw_init(); #ifdef CONFIG_USB usb_init(); #endif diff -u --recursive --new-file v2.3.11/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.11/linux/drivers/char/ppdev.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/char/ppdev.c Wed Jul 28 01:19:37 1999 @@ -11,7 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * A /dev/parportxy device node represents an arbitrary device ('y') + * A /dev/parportx device node represents an arbitrary device * on port 'x'. The following operations are possible: * * open do nothing, set up default IEEE 1284 protocol to be COMPAT @@ -30,6 +30,8 @@ * RSTATUS read_status * NEGOT parport_negotiate * YIELD parport_yield_blocking + * WCTLONIRQ on interrupt, set control lines + * CLRIRQ clear (and return) interrupt count * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) */ @@ -53,9 +55,13 @@ struct pp_struct { struct pardevice * pdev; wait_queue_head_t irq_wait; - int got_irq; + atomic_t irqc; int mode; unsigned int flags; + int irqresponse; + unsigned char irqctl; + struct ieee1284_info state; + struct ieee1284_info saved_state; }; /* pp_struct.flags bitfields */ @@ -85,8 +91,10 @@ { size_t (*fn) (struct parport *, void *, size_t, int); struct parport *port = pp->pdev->port; + int addr = pp->mode & IEEE1284_ADDR; + int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - switch (pp->mode) { + switch (mode) { case IEEE1284_MODE_COMPAT: /* This is a write-only mode. */ return -EIO; @@ -100,7 +108,10 @@ break; case IEEE1284_MODE_EPP: - fn = port->ops->epp_read_data; + if (addr) + fn = port->ops->epp_read_addr; + else + fn = port->ops->epp_read_data; break; case IEEE1284_MODE_ECP: @@ -128,8 +139,10 @@ { size_t (*fn) (struct parport *, const void *, size_t, int); struct parport *port = pp->pdev->port; + int addr = pp->mode & IEEE1284_ADDR; + int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - switch (pp->mode) { + switch (mode) { case IEEE1284_MODE_NIBBLE: case IEEE1284_MODE_BYTE: /* Read-only modes. */ @@ -140,16 +153,25 @@ break; case IEEE1284_MODE_EPP: - fn = port->ops->epp_write_data; + if (addr) + fn = port->ops->epp_write_addr; + else + fn = port->ops->epp_write_data; break; case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: - fn = port->ops->ecp_write_data; + if (addr) + fn = port->ops->ecp_write_addr; + else + fn = port->ops->ecp_write_data; break; case IEEE1284_MODE_ECPSWE: - fn = parport_ieee1284_ecp_write_data; + if (addr) + fn = parport_ieee1284_ecp_write_addr; + else + fn = parport_ieee1284_ecp_write_data; break; default: @@ -271,7 +293,13 @@ static void pp_irq (int irq, void * private, struct pt_regs * unused) { struct pp_struct * pp = (struct pp_struct *) private; - pp->got_irq = 1; + + if (pp->irqresponse) { + parport_write_control (pp->pdev->port, pp->irqctl); + pp->irqresponse = 0; + } + + atomic_inc (&pp->irqc); wake_up_interruptible (&pp->irq_wait); } @@ -322,6 +350,9 @@ /* First handle the cases that don't take arguments. */ if (cmd == PPCLAIM) { + struct ieee1284_info *info; + int first_claim = 0; + if (pp->flags & PP_CLAIMED) { printk (KERN_DEBUG CHRDEV "%x: you've already got it!\n", minor); @@ -333,6 +364,8 @@ int err = register_device (minor, pp); if (err) return err; + + first_claim = 1; } parport_claim_or_block (pp->pdev); @@ -341,6 +374,30 @@ /* For interrupt-reporting to work, we need to be * informed of each interrupt. */ enable_irq (pp); + + /* We may need to fix up the state machine. */ + info = &pp->pdev->port->ieee1284; + pp->saved_state.mode = info->mode; + pp->saved_state.phase = info->phase; + if (pp->mode != info->mode) { + int phase = IEEE1284_PH_FWD_IDLE; + + if (first_claim) { + info->mode = pp->mode; + switch (pp->mode & ~(IEEE1284_DEVICEID + | IEEE1284_ADDR)) { + case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: + phase = IEEE1284_PH_REV_IDLE; + } + info->phase = phase; + } else { + /* Just restore the state. */ + info->mode = pp->state.mode; + info->phase = pp->state.phase; + } + } + return 0; } @@ -380,6 +437,7 @@ port = pp->pdev->port; switch (cmd) { + struct ieee1284_info *info; unsigned char reg; unsigned char mask; int mode; @@ -405,6 +463,12 @@ return 0; case PPRELEASE: + /* Save the state machine's state. */ + info = &pp->pdev->port->ieee1284; + pp->state.mode = info->mode; + pp->state.phase = info->phase; + info->mode = pp->saved_state.mode; + info->phase = pp->saved_state.phase; parport_release (pp->pdev); pp->flags &= ~PP_CLAIMED; return 0; @@ -443,11 +507,36 @@ case PPNEGOT: if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; - /* FIXME: validate mode */ - ret = parport_negotiate (port, mode); + switch ((ret = parport_negotiate (port, mode))) { + case 0: break; + case -1: /* handshake failed, peripheral not IEEE 1284 */ + ret = -EIO; + break; + case 1: /* handshake succeeded, peripheral rejected mode */ + ret = -ENXIO; + break; + } enable_irq (pp); return ret; + case PPWCTLONIRQ: + if (copy_from_user (®, (unsigned char *) arg, + sizeof (reg))) + return -EFAULT; + + /* Remember what to set the control lines to, for next + * time we get an interrupt. */ + pp->irqctl = reg; + pp->irqresponse = 1; + return 0; + + case PPCLRIRQ: + ret = atomic_read (&pp->irqc); + if (copy_to_user ((int *) arg, &ret, sizeof (ret))) + return -EFAULT; + atomic_sub (ret, &pp->irqc); + return 0; + default: printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd); @@ -472,7 +561,7 @@ pp->mode = IEEE1284_MODE_COMPAT; pp->flags = 0; - pp->got_irq = 0; + atomic_set (&pp->irqc, 0); init_waitqueue_head (&pp->irq_wait); /* Defer the actual device registration until the first claim. @@ -515,10 +604,10 @@ { struct pp_struct *pp = file->private_data; unsigned int mask = 0; - if (pp->got_irq) { - pp->got_irq = 0; + + if (atomic_read (&pp->irqc)) mask |= POLLIN | POLLRDNORM; - } + poll_wait (file, &pp->irq_wait, wait); return mask; } diff -u --recursive --new-file v2.3.11/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h --- v2.3.11/linux/drivers/char/ppdev.h Thu Jul 8 15:42:20 1999 +++ linux/drivers/char/ppdev.h Mon Jul 26 14:11:05 1999 @@ -63,3 +63,9 @@ /* Negotiate a particular IEEE 1284 mode. */ #define PPNEGOT _IOW(PP_IOCTL, 0x91, int) + +/* Set control lines when an interrupt occurs. */ +#define PPWCTLONIRQ _IOW(PP_IOCTL, 0x92, unsigned char) + +/* Clear (and return) interrupt count. */ +#define PPCLRIRQ _IOR(PP_IOCTL, 0x93, int) diff -u --recursive --new-file v2.3.11/linux/drivers/char/raw.c linux/drivers/char/raw.c --- v2.3.11/linux/drivers/char/raw.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/raw.c Mon Jul 26 22:50:35 1999 @@ -0,0 +1,384 @@ +/* + * linux/drivers/char/raw.c + * + * Front-end raw character devices. These can be bound to any block + * devices to provide genuine Unix raw character device semantics. + * + * We reserve minor number 0 for a control interface. ioctl()s on this + * device are used to bind the other minor numbers to block devices. + */ + +#include +#include +#include +#include +#include +#include + +#define dprintk(x...) + +static kdev_t raw_device_bindings[256] = {}; +static int raw_device_inuse[256] = {}; +static int raw_device_sector_size[256] = {}; +static int raw_device_sector_bits[256] = {}; + +extern struct file_operations * get_blkfops(unsigned int major); + +static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *); + +ssize_t raw_read(struct file *, char *, size_t, loff_t *); +ssize_t raw_write(struct file *, const char *, size_t, loff_t *); +int raw_open(struct inode *, struct file *); +int raw_release(struct inode *, struct file *); +int raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long); + + +static struct file_operations raw_fops = { + NULL, /* llseek */ + raw_read, /* read */ + raw_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + raw_open, /* open */ + NULL, /* flush */ + raw_release, /* release */ + NULL /* fsync */ +}; + +static struct file_operations raw_ctl_fops = { + NULL, /* llseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + raw_ctl_ioctl, /* ioctl */ + NULL, /* mmap */ + raw_open, /* open */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + + + +void __init raw_init(void) +{ + register_chrdev(RAW_MAJOR, "raw", &raw_fops); +} + + +/* + * The raw IO open and release code needs to fake appropriate + * open/release calls to the underlying block devices. + */ + +static int bdev_open(kdev_t dev, int mode) +{ + int err = 0; + struct file dummy_file = {}; + struct dentry dummy_dentry = {}; + struct inode * inode = get_empty_inode(); + + if (!inode) + return -ENOMEM; + + dummy_file.f_op = get_blkfops(MAJOR(dev)); + if (!dummy_file.f_op) { + err = -ENODEV; + goto done; + } + + if (dummy_file.f_op->open) { + inode->i_rdev = dev; + dummy_dentry.d_inode = inode; + dummy_file.f_dentry = &dummy_dentry; + dummy_file.f_mode = mode; + err = dummy_file.f_op->open(inode, &dummy_file); + } + + done: + iput(inode); + return err; +} + +static int bdev_close(kdev_t dev) +{ + int err; + struct inode * inode = get_empty_inode(); + + if (!inode) + return -ENOMEM; + + inode->i_rdev = dev; + err = blkdev_release(inode); + iput(inode); + return err; +} + + + +/* + * Open/close code for raw IO. + */ + +int raw_open(struct inode *inode, struct file *filp) +{ + int minor; + kdev_t bdev; + int err; + int sector_size; + int sector_bits; + + minor = MINOR(inode->i_rdev); + + /* + * Is it the control device? + */ + + if (minor == 0) { + filp->f_op = &raw_ctl_fops; + return 0; + } + + /* + * No, it is a normal raw device. All we need to do on open is + * to check that the device is bound, and force the underlying + * block device to a sector-size blocksize. + */ + + bdev = raw_device_bindings[minor]; + if (bdev == NODEV) + return -ENODEV; + + err = bdev_open(bdev, filp->f_mode); + if (err) + return err; + + /* + * Don't change the blocksize if we already have users using + * this device + */ + + if (raw_device_inuse[minor]++) + return 0; + + /* + * Don't interfere with mounted devices: we cannot safely set + * the blocksize on a device which is already mounted. + */ + + sector_size = 512; + if (lookup_vfsmnt(bdev) != NULL) { + if (blksize_size[MAJOR(bdev)]) + sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)]; + } else { + if (hardsect_size[MAJOR(bdev)]) + sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)]; + } + + set_blocksize(bdev, sector_size); + raw_device_sector_size[minor] = sector_size; + + for (sector_bits = 0; !(sector_size & 1); ) + sector_size>>=1, sector_bits++; + raw_device_sector_bits[minor] = sector_bits; + + return 0; +} + +int raw_release(struct inode *inode, struct file *filp) +{ + int minor; + kdev_t bdev; + + minor = MINOR(inode->i_rdev); + bdev = raw_device_bindings[minor]; + bdev_close(bdev); + raw_device_inuse[minor]--; + return 0; +} + + + +/* + * Deal with ioctls against the raw-device control interface, to bind + * and unbind other raw devices. + */ + +int raw_ctl_ioctl(struct inode *inode, + struct file *flip, + unsigned int command, + unsigned long arg) +{ + struct raw_config_request rq; + int err = 0; + int minor; + + switch (command) { + case RAW_SETBIND: + case RAW_GETBIND: + + /* First, find out which raw minor we want */ + + err = copy_from_user(&rq, (void *) arg, sizeof(rq)); + if (err) + break; + + minor = rq.raw_minor; + if (minor == 0 || minor > MINORMASK) { + err = -EINVAL; + break; + } + + if (command == RAW_SETBIND) { + /* + * For now, we don't need to check that the underlying + * block device is present or not: we can do that when + * the raw device is opened. Just check that the + * major/minor numbers make sense. + */ + + if (rq.block_major == NODEV || + rq.block_major > MAX_BLKDEV || + rq.block_minor > MINORMASK) { + err = -EINVAL; + break; + } + + if (raw_device_inuse[minor]) { + err = -EBUSY; + break; + } + raw_device_bindings[minor] = + MKDEV(rq.block_major, rq.block_minor); + } else { + rq.block_major = MAJOR(raw_device_bindings[minor]); + rq.block_minor = MINOR(raw_device_bindings[minor]); + err = copy_to_user((void *) arg, &rq, sizeof(rq)); + } + break; + + default: + err = -EINVAL; + } + + return err; +} + + + +ssize_t raw_read(struct file *filp, char * buf, + size_t size, loff_t *offp) +{ + return rw_raw_dev(READ, filp, buf, size, offp); +} + +ssize_t raw_write(struct file *filp, const char *buf, + size_t size, loff_t *offp) +{ + return rw_raw_dev(WRITE, filp, (char *) buf, size, offp); +} + +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1U << SECTOR_BITS) +#define SECTOR_MASK (SECTOR_SIZE - 1) + +ssize_t rw_raw_dev(int rw, struct file *filp, char *buf, + size_t size, loff_t *offp) +{ + struct kiobuf * iobuf; + int err; + unsigned long blocknr, blocks; + unsigned long b[KIO_MAX_SECTORS]; + size_t transferred; + int iosize; + int i; + int minor; + kdev_t dev; + unsigned long limit; + + int sector_size, sector_bits, sector_mask; + int max_sectors; + + /* + * First, a few checks on device size limits + */ + + minor = MINOR(filp->f_dentry->d_inode->i_rdev); + dev = raw_device_bindings[minor]; + sector_size = raw_device_sector_size[minor]; + sector_bits = raw_device_sector_bits[minor]; + sector_mask = sector_size- 1; + max_sectors = KIO_MAX_SECTORS >> (sector_bits - 9); + + if (blk_size[MAJOR(dev)]) + limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits; + else + limit = INT_MAX; + dprintk ("rw_raw_dev: dev %d:%d (+%d)\n", + MAJOR(dev), MINOR(dev), limit); + + if ((*offp & sector_mask) || (size & sector_mask)) + return -EINVAL; + if ((*offp >> sector_bits) > limit) + return 0; + + /* + * We'll just use one kiobuf + */ + + err = alloc_kiovec(1, &iobuf); + if (err) + return err; + + /* + * Split the IO into KIO_MAX_SECTORS chunks, mapping and + * unmapping the single kiobuf as we go to perform each chunk of + * IO. + */ + + transferred = 0; + blocknr = *offp >> sector_bits; + while (size > 0) { + blocks = size >> sector_bits; + if (blocks > max_sectors) + blocks = max_sectors; + if (blocks > limit - blocknr) + blocks = limit - blocknr; + if (!blocks) + break; + + iosize = blocks << sector_bits; + + err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize); + if (err) + break; + + for (i=0; i < blocks; i++) + b[i] = blocknr++; + + err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size, 0); + + if (err >= 0) { + transferred += err; + size -= err; + buf += err; + } + + unmap_kiobuf(iobuf); + + if (err != iosize) + break; + } + + free_kiovec(1, &iobuf); + + if (transferred) { + *offp += transferred; + return transferred; + } + + return err; +} diff -u --recursive --new-file v2.3.11/linux/drivers/misc/BUGS-parport linux/drivers/misc/BUGS-parport --- v2.3.11/linux/drivers/misc/BUGS-parport Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/BUGS-parport Wed Dec 31 16:00:00 1969 @@ -1,5 +0,0 @@ -Currently known (or at least suspected) bugs in parport: - -o lp doesn't allow you to read status while printing is in progress. - -See . diff -u --recursive --new-file v2.3.11/linux/drivers/misc/Config.in linux/drivers/misc/Config.in --- v2.3.11/linux/drivers/misc/Config.in Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/Config.in Wed Dec 31 16:00:00 1969 @@ -1,37 +0,0 @@ -# -# 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 -u --recursive --new-file v2.3.11/linux/drivers/misc/Makefile linux/drivers/misc/Makefile --- v2.3.11/linux/drivers/misc/Makefile Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/Makefile Wed Dec 31 16:00:00 1969 @@ -1,102 +0,0 @@ -# -# Makefile for the kernel miscellaneous drivers. -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -# -# Note 3! Parport 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) -ALL_SUB_DIRS := $(SUB_DIRS) - -L_TARGET := misc.a -MX_OBJS := -LX_OBJS := -MI_OBJS := -MIX_OBJS := - -ifeq ($(CONFIG_PARPORT),y) - 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 - ifeq ($(CONFIG_PARPORT_PC),m) - M_OBJS += parport_pc.o - endif - endif - ifeq ($(CONFIG_PARPORT_AX),y) - LX_OBJS += parport_ax.o - else - ifeq ($(CONFIG_PARPORT_AX),m) - M_OBJS += parport_ax.o - endif - endif - ifeq ($(CONFIG_PARPORT_AMIGA),y) - LX_OBJS += parport_amiga.o - else - ifeq ($(CONFIG_PARPORT_AMIGA),m) - M_OBJS += parport_amiga.o - endif - endif - ifeq ($(CONFIG_PARPORT_MFC3),y) - LX_OBJS += parport_mfc3.o - else - ifeq ($(CONFIG_PARPORT_MFC3),m) - M_OBJS += parport_mfc3.o - endif - endif - ifeq ($(CONFIG_PARPORT_ATARI),y) - LX_OBJS += parport_atari.o - else - ifeq ($(CONFIG_PARPORT_ATARI),m) - M_OBJS += parport_atari.o - endif - endif - LX_OBJS += parport_init.o -else - ifeq ($(CONFIG_PARPORT),m) - 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 - MIX_OBJS += parport_init.o - M_OBJS += parport.o - endif - ifeq ($(CONFIG_PARPORT_PC),m) - M_OBJS += parport_pc.o - endif - ifeq ($(CONFIG_PARPORT_AX),m) - M_OBJS += parport_ax.o - endif - ifeq ($(CONFIG_PARPORT_AMIGA),m) - M_OBJS += parport_amiga.o - endif - ifeq ($(CONFIG_PARPORT_MFC3),m) - M_OBJS += parport_mfc3.o - endif - ifeq ($(CONFIG_PARPORT_ATARI),m) - M_OBJS += parport_atari.o - endif -endif - -include $(TOPDIR)/Rules.make - -# Special rule to build the composite parport.o module -parport.o: $(MI_OBJS) $(MIX_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) diff -u --recursive --new-file v2.3.11/linux/drivers/misc/TODO-parport linux/drivers/misc/TODO-parport --- v2.3.11/linux/drivers/misc/TODO-parport Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/TODO-parport Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -Things to be done. - -0. Fix the bugs (see BUGS-parport). - -1. Proper documentation. - -2. A better lp.c: - - a) ECP support would be nice. This can only work if both the port and - the printer support it. - - b) Handle status readback automatically. IEEE1284 printers can post status - bits when they have something to say. We should read out and deal - with (maybe just log) whatever the printer wants to tell the world. - -3. Support more hardware (eg m68k, Sun bpp). - -4. A better PLIP (make use of bidirectional/ECP/EPP ports). - -See . diff -u --recursive --new-file v2.3.11/linux/drivers/misc/multiface.h linux/drivers/misc/multiface.h --- v2.3.11/linux/drivers/misc/multiface.h Tue May 11 09:55:49 1999 +++ linux/drivers/misc/multiface.h Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -#ifndef _MULTIFACE_H_ -#define _MULTIFACE_H_ - -/* - * Defines for SerialMaster, Multiface Card II and Multiface Card III - * The addresses given below are offsets to the board base address - * - * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de) - * - */ - -#define PIA_REG_PADWIDTH 255 - -#define DUARTBASE 0x0000 -#define PITBASE 0x0100 -#define ROMBASE 0x0200 -#define PIABASE 0x4000 - -#endif - diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_amiga.c linux/drivers/misc/parport_amiga.c --- v2.3.11/linux/drivers/misc/parport_amiga.c Mon Jun 7 12:10:10 1999 +++ linux/drivers/misc/parport_amiga.c Wed Dec 31 16:00:00 1969 @@ -1,312 +0,0 @@ -/* Low-level parallel port routines for the Amiga buildin port - * - * Author: Joerg Dorchain - * - * This is a complete rewrite of the code, but based heaviy upon the old - * lp_intern. code. - * - * The built-in Amiga parallel port provides one port at a fixed address - * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status - * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in - * hardware when the data register is accessed), and 1 input control line - * /ACK, able to cause an interrupt, but both not directly settable by - * software. - */ - -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK printk -#else -static inline int DPRINTK() {return 0;} -#endif - -static struct parport *this_port = NULL; - -static void amiga_write_data(struct parport *p, unsigned char data) -{ -DPRINTK("write_data %c\n",data); - /* Triggers also /STROBE. This behavior cannot be changed */ - ciaa.prb = data; -} - -static unsigned char amiga_read_data(struct parport *p) -{ - /* Triggers also /STROBE. This behavior cannot be changed */ - return ciaa.prb; -} - -#if 0 -static unsigned char control_pc_to_amiga(unsigned char control) -{ - unsigned char ret = 0; - - if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ - ; - if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ - ; - if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ - ; - if (control & PARPORT_CONTROL_INIT) /* INITP */ - /* reset connected to cpu reset pin */; - if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ - /* Not connected */; - if (control & PARPORT_CONTROL_STROBE) /* Strobe */ - /* Handled only directly by hardware */; - return ret; -} -#endif - -static unsigned char control_amiga_to_pc(unsigned char control) -{ - return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE; - /* fake value: interrupt enable, select in, no reset, - no autolf, no strobe - seems to be closest the wiring diagram */ -} - -static void amiga_write_control(struct parport *p, unsigned char control) -{ -DPRINTK("write_control %02x\n",control); - /* No implementation possible */ -} - -static unsigned char amiga_read_control( struct parport *p) -{ -DPRINTK("read_control \n"); - return control_amiga_to_pc(0); -} - -static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val) -{ - unsigned char old; - -DPRINTK("frob_control mask %02x, value %02x\n",mask,val); - old = amiga_read_control(p); - amiga_write_control(p, (old & ~mask) ^ val); - return old; -} - - -static unsigned char status_pc_to_amiga(unsigned char status) -{ - unsigned char ret = 1; - - if (status & PARPORT_STATUS_BUSY) /* Busy */ - ret &= ~1; - if (status & PARPORT_STATUS_ACK) /* Ack */ - /* handled in hardware */; - if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ - ret |= 2; - if (status & PARPORT_STATUS_SELECT) /* select */ - ret |= 4; - if (status & PARPORT_STATUS_ERROR) /* error */ - /* not connected */; - return ret; -} - -static unsigned char status_amiga_to_pc(unsigned char status) -{ - unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR; - - if (status & 1) /* Busy */ - ret &= ~PARPORT_STATUS_BUSY; - if (status & 2) /* PaperOut */ - ret |= PARPORT_STATUS_PAPEROUT; - if (status & 4) /* Selected */ - ret |= PARPORT_STATUS_SELECT; - /* the rest is not connected or handled autonomously in hardware */ - - return ret; -} - -static void amiga_write_status( struct parport *p, unsigned char status) -{ -DPRINTK("write_status %02x\n",status); - ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status); -} - -static unsigned char amiga_read_status(struct parport *p) -{ - unsigned char status; - - status = status_amiga_to_pc(ciab.pra & 7); -DPRINTK("read_status %02x\n", status); - return status; -} - -static void amiga_change_mode( struct parport *p, int m) -{ - /* XXX: This port only has one mode, and I am - not sure about the corresponding PC-style mode*/ -} - -/* as this ports irq handling is already done, we use a generic funktion */ -static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - parport_generic_irq(irq, (struct parport *) dev_id, regs); -} - - -static void amiga_init_state(struct parport_state *s) -{ - s->u.amiga.data = 0; - s->u.amiga.datadir = 255; - s->u.amiga.status = 0; - s->u.amiga.statusdir = 0; -} - -static void amiga_save_state(struct parport *p, struct parport_state *s) -{ - s->u.amiga.data = ciaa.prb; - s->u.amiga.datadir = ciaa.ddrb; - s->u.amiga.status = ciab.pra & 7; - s->u.amiga.statusdir = ciab.ddra & 7; -} - -static void amiga_restore_state(struct parport *p, struct parport_state *s) -{ - ciaa.prb = s->u.amiga.data; - ciaa.ddrb = s->u.amiga.datadir; - ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status; - ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir; -} - -static void amiga_enable_irq(struct parport *p) -{ - enable_irq(IRQ_AMIGA_CIAA_FLG); -} - -static void amiga_disable_irq(struct parport *p) -{ - disable_irq(IRQ_AMIGA_CIAA_FLG); -} - -static void amiga_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -static void amiga_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - -static void amiga_fill_inode(struct inode *inode, int fill) -{ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -static struct parport_operations pp_amiga_ops = { - amiga_write_data, - amiga_read_data, - - amiga_write_control, - amiga_read_control, - amiga_frob_control, - - NULL, /* write_econtrol */ - NULL, /* read_econtrol */ - NULL, /* frob_econtrol */ - - amiga_write_status, - amiga_read_status, - - NULL, /* write fifo */ - NULL, /* read fifo */ - - amiga_change_mode, - - - NULL, /* epp_write_data */ - NULL, /* epp_read_data */ - NULL, /* epp_write_addr */ - NULL, /* epp_read_addr */ - NULL, /* epp_check_timeout */ - - NULL, /* epp_write_block */ - NULL, /* epp_read_block */ - - NULL, /* ecp_write_block */ - NULL, /* ecp_read_block */ - - amiga_init_state, - amiga_save_state, - amiga_restore_state, - - amiga_enable_irq, - amiga_disable_irq, - amiga_interrupt, - - amiga_inc_use_count, - amiga_dec_use_count, - amiga_fill_inode -}; - -/* ----------- Initialisation code --------------------------------- */ - -__initfunc(int parport_amiga_init(void)) -{ - struct parport *p; - - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) { - ciaa.ddrb = 0xff; - ciab.ddra &= 0xf8; - if (!(p = parport_register_port((unsigned long)&ciaa.prb, - IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE, - &pp_amiga_ops))) - return 0; - this_port = p; - printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name); - /* XXX: set operating mode */ - parport_proc_register(p); - if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, - p->name, p)) { - parport_unregister_port (p); - return 0; - } - - if (parport_probe_hook) - (*parport_probe_hook)(p); - - parport_announce_port (p); - - return 1; - - } - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Joerg Dorchain"); -MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port"); -MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port"); - -int init_module(void) -{ - return ! parport_amiga_init(); -} - -void cleanup_module(void) -{ - if (p->irq != PARPORT_IRQ_NONE) - free_irq(IRQ_AMIGA_CIAA_FLG, p); - parport_proc_unregister(this_port); - parport_unregister_port(this_port); -} -#endif - - diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.3.11/linux/drivers/misc/parport_arc.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/misc/parport_arc.c Wed Dec 31 16:00:00 1969 @@ -1,160 +0,0 @@ -/* Low-level parallel port routines for Archimedes onboard hardware - * - * Author: Phil Blundell - */ - -/* This driver is for the parallel port hardware found on Acorn's old - * range of Archimedes machines. The A5000 and newer systems have PC-style - * I/O hardware and should use the parport_pc driver instead. - * - * The Acorn printer port hardware is very simple. There is a single 8-bit - * write-only latch for the data port and control/status bits are handled - * with various auxilliary input and output lines. The port is not - * bidirectional, does not support any modes other than SPP, and has only - * a subset of the standard printer control lines connected. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define DATA_ADDRESS 0x3350010 - -/* This is equivalent to the above and only used for request_region. */ -#define PORT_BASE 0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2) - -/* The hardware can't read from the data latch, so we must use a soft - copy. */ -static unsigned char data_copy; - -/* These are pretty simple. We know the irq is never shared and the - kernel does all the magic that's required. */ -static void arc_enable_irq(struct parport *p) -{ - enable_irq(p->irq); -} - -static void arc_disable_irq(struct parport *p) -{ - disable_irq(p->irq); -} - -static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - parport_generic_irq(irq, (struct parport *) dev_id, regs); -} - -static void arc_write_data(struct parport *p, unsigned char data) -{ - data_copy = data; - outb_t(data, DATA_LATCH); -} - -static unsigned char arc_read_data(struct parport *p) -{ - return data_copy; -} - -static void arc_inc_use_count(void) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void arc_dec_use_count(void) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static void arc_fill_inode(struct inode *inode, int fill) -{ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -static struct parport_operations parport_arc_ops = -{ - arc_write_data, - arc_read_data, - - arc_write_control, - arc_read_control, - arc_frob_control, - - arc_read_status, - - arc_enable_irq, - arc_disable_irq, - - arc_data_forward, - arc_data_reverse, - - arc_interrupt, - - arc_init_state, - arc_save_state, - arc_restore_state, - - arc_inc_use_count, - arc_dec_use_count, - 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 -------------------------------- */ - -int parport_arc_init(void) -{ - /* Archimedes hardware provides only one port, at a fixed address */ - struct parport *p; - - if (check_region(PORT_BASE, 1)) - return 0; - - p = parport_register_port (PORT_BASE, IRQ_PRINTERACK, - PARPORT_DMA_NONE, &parport_arc_ops); - - if (!p) - return 0; - - p->modes = PARPORT_MODE_ARCSPP; - p->size = 1; - - printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n", - p->irq); - parport_proc_register(p); - - /* Tell the high-level drivers about the port. */ - parport_announce_port (p); - - return 1; -} diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c --- v2.3.11/linux/drivers/misc/parport_atari.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_atari.c Wed Dec 31 16:00:00 1969 @@ -1,251 +0,0 @@ -/* Low-level parallel port routines for the Atari builtin port - * - * Author: Andreas Schwab - * - * Based on parport_amiga.c. - * - * The built-in Atari parallel port provides one port at a fixed address - * with 8 output data lines (D0 - D7), 1 output control line (STROBE) - * and 1 input status line (BUSY) able to cause an interrupt. - */ - -#include -#include -#include -#include -#include -#include -#include - -static struct parport *this_port = NULL; - -static unsigned char -parport_atari_read_data(struct parport *p) -{ - unsigned long flags; - unsigned char data; - - save_flags(flags); - cli(); - sound_ym.rd_data_reg_sel = 15; - data = sound_ym.rd_data_reg_sel; - restore_flags(flags); - return data; -} - -static void -parport_atari_write_data(struct parport *p, unsigned char data) -{ - unsigned long flags; - - save_flags(flags); - cli(); - sound_ym.rd_data_reg_sel = 15; - sound_ym.wd_data = data; - restore_flags(flags); -} - -static unsigned char -parport_atari_read_control(struct parport *p) -{ - unsigned long flags; - unsigned char control = 0; - - save_flags(flags); - cli(); - sound_ym.rd_data_reg_sel = 14; - if (!(sound_ym.rd_data_reg_sel & (1 << 5))) - control = PARPORT_CONTROL_STROBE; - restore_flags(flags); - return control; -} - -static void -parport_atari_write_control(struct parport *p, unsigned char control) -{ - unsigned long flags; - - save_flags(flags); - cli(); - sound_ym.rd_data_reg_sel = 14; - if (control & PARPORT_CONTROL_STROBE) - sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5); - else - sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); - restore_flags(flags); -} - -static unsigned char -parport_atari_frob_control(struct parport *p, unsigned char mask, - unsigned char val) -{ - unsigned char old = parport_atari_read_control(p); - parport_atari_write_control(p, (old & ~mask) ^ val); - return old; -} - -static unsigned char -parport_atari_read_status(struct parport *p) -{ - return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) | - PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR); -} - -static void -parport_atari_write_status(struct parport *p, unsigned char status) -{ -} - -static void -parport_atari_init_state(struct parport_state *s) -{ -} - -static void -parport_atari_save_state(struct parport *p, struct parport_state *s) -{ -} - -static void -parport_atari_restore_state(struct parport *p, struct parport_state *s) -{ -} - -static void -parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - parport_generic_irq(irq, (struct parport *) dev_id, regs); -} - -static void -parport_atari_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -static void -parport_atari_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - -static void -parport_atari_fill_inode(struct inode *inode, int fill) -{ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -static struct parport_operations parport_atari_ops = { - parport_atari_write_data, - parport_atari_read_data, - - parport_atari_write_control, - parport_atari_read_control, - parport_atari_frob_control, - - NULL, /* write_econtrol */ - NULL, /* read_econtrol */ - NULL, /* frob_econtrol */ - - parport_atari_write_status, - parport_atari_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 */ - - NULL, /* epp_write_block */ - NULL, /* epp_read_block */ - - NULL, /* ecp_write_block */ - NULL, /* ecp_read_block */ - - parport_atari_init_state, - parport_atari_save_state, - parport_atari_restore_state, - - NULL, /* enable_irq */ - NULL, /* disable_irq */ - parport_atari_interrupt, - - parport_atari_inc_use_count, - parport_atari_dec_use_count, - parport_atari_fill_inode -}; - - -int __init -parport_atari_init(void) -{ - struct parport *p; - unsigned long flags; - - if (MACH_IS_ATARI) { - save_flags(flags); - cli(); - /* Soundchip port A/B as output. */ - sound_ym.rd_data_reg_sel = 7; - sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0; - /* STROBE high. */ - sound_ym.rd_data_reg_sel = 14; - sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); - restore_flags(flags); - /* MFP port I0 as input. */ - mfp.data_dir &= ~1; - /* MFP port I0 interrupt on high->low edge. */ - mfp.active_edge &= ~1; - p = parport_register_port((unsigned long)&sound_ym.wd_data, - IRQ_MFP_BUSY, PARPORT_DMA_NONE, - &parport_atari_ops); - if (!p) - return 0; - if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt, - IRQ_TYPE_SLOW, p->name, p)) { - parport_unregister_port (p); - return 0; - } - - this_port = p; - printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name); - parport_proc_register(p); - - parport_announce_port (p); - - return 1; - } - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Andreas Schwab"); -MODULE_DESCRIPTION("Parport Driver for Atari builtin Port"); -MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port"); - -int -init_module(void) -{ - return parport_atari_init() ? 0 : -ENODEV; -} - -void -cleanup_module(void) -{ - if (p->irq != PARPORT_IRQ_NONE) - free_irq(IRQ_MFP_BUSY, p); - parport_proc_unregister(this_port); - parport_unregister_port(this_port); -} -#endif diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.3.11/linux/drivers/misc/parport_ax.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_ax.c Wed Dec 31 16:00:00 1969 @@ -1,600 +0,0 @@ -/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $ - * Parallel-port routines for Sun Ultra/AX architecture - * - * Author: Eddie C. Dost - * - * based on work by: - * Phil Blundell - * Tim Waugh - * Jose Renau - * David Campbell - * Grant Guenther - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - - -/* - * Define this if you have Devices which don't support short - * host read/write cycles. - */ -#undef HAVE_SLOW_DEVICES - - -#define DATA 0x00 -#define STATUS 0x01 -#define CONTROL 0x02 -#define EPPADDR 0x03 -#define EPPDATA 0x04 - -#define CFIFO 0x400 -#define DFIFO 0x400 -#define TFIFO 0x400 -#define CONFIGA 0x400 -#define CONFIGB 0x401 -#define ECONTROL 0x402 - -static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - parport_generic_irq(irq, (struct parport *) dev_id, regs); -} - -void -parport_ax_write_epp(struct parport *p, unsigned char d) -{ - outb(d, p->base + EPPDATA); -} - -unsigned char -parport_ax_read_epp(struct parport *p) -{ - return inb(p->base + EPPDATA); -} - -void -parport_ax_write_epp_addr(struct parport *p, unsigned char d) -{ - outb(d, p->base + EPPADDR); -} - -unsigned char -parport_ax_read_epp_addr(struct parport *p) -{ - return inb(p->base + EPPADDR); -} - -int parport_ax_epp_clear_timeout(struct parport *pb); - -int -parport_ax_check_epp_timeout(struct parport *p) -{ - if (!(inb(p->base+STATUS) & 1)) - return 0; - parport_ax_epp_clear_timeout(p); - return 1; -} - -unsigned char -parport_ax_read_configb(struct parport *p) -{ - return inb(p->base + CONFIGB); -} - -void -parport_ax_write_data(struct parport *p, unsigned char d) -{ - outb(d, p->base + DATA); -} - -unsigned char -parport_ax_read_data(struct parport *p) -{ - return inb(p->base + DATA); -} - -void -parport_ax_write_control(struct parport *p, unsigned char d) -{ - outb(d, p->base + CONTROL); -} - -unsigned char -parport_ax_read_control(struct parport *p) -{ - return inb(p->base + CONTROL); -} - -unsigned char -parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val) -{ - unsigned char old = inb(p->base + CONTROL); - outb(((old & ~mask) ^ val), p->base + CONTROL); - return old; -} - -void -parport_ax_write_status(struct parport *p, unsigned char d) -{ - outb(d, p->base + STATUS); -} - -unsigned char -parport_ax_read_status(struct parport *p) -{ - return inb(p->base + STATUS); -} - -void -parport_ax_write_econtrol(struct parport *p, unsigned char d) -{ - outb(d, p->base + ECONTROL); -} - -unsigned char -parport_ax_read_econtrol(struct parport *p) -{ - return inb(p->base + ECONTROL); -} - -unsigned char -parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) -{ - unsigned char old = inb(p->base + ECONTROL); - outb(((old & ~mask) ^ val), p->base + ECONTROL); - return old; -} - -void -parport_ax_change_mode(struct parport *p, int m) -{ - /* FIXME */ - parport_ax_frob_econtrol(p, 0xe0, m << 5); -} - -void -parport_ax_write_fifo(struct parport *p, unsigned char v) -{ - outb(v, p->base + DFIFO); -} - -unsigned char -parport_ax_read_fifo(struct parport *p) -{ - return inb(p->base + DFIFO); -} - -void -parport_ax_disable_irq(struct parport *p) -{ - struct linux_ebus_dma *dma = p->private_data; - unsigned int dcsr; - - dcsr = readl((unsigned long)&dma->dcsr); - dcsr &= ~(EBUS_DCSR_INT_EN); - writel(dcsr, (unsigned long)&dma->dcsr); -} - -void -parport_ax_enable_irq(struct parport *p) -{ - struct linux_ebus_dma *dma = p->private_data; - unsigned int dcsr; - - dcsr = readl((unsigned long)&dma->dcsr); - dcsr |= EBUS_DCSR_INT_EN; - writel(dcsr, (unsigned long)&dma->dcsr); -} - -void -parport_ax_init_state(struct pardevice *dev, struct parport_state *s) -{ - 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) -{ - 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) -{ - struct linux_ebus_dma *dma = p->private_data; - - 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 -parport_ax_inc_use_count(void) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void -parport_ax_dec_use_count(void) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static void parport_ax_fill_inode(struct inode *inode, int fill) -{ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -static struct parport_operations parport_ax_ops = -{ - parport_ax_write_data, - parport_ax_read_data, - - parport_ax_write_control, - parport_ax_read_control, - parport_ax_frob_control, - - parport_ax_read_status, - - parport_ax_enable_irq, - parport_ax_disable_irq, - - parport_ax_data_forward, - parport_ax_data_reverse, - - parport_ax_interrupt, - - parport_ax_init_state, - parport_ax_save_state, - parport_ax_restore_state, - - parport_ax_inc_use_count, - parport_ax_dec_use_count, - 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, -}; - - -/****************************************************** - * MODE detection section: - */ - -/* - * Clear TIMEOUT BIT in EPP MODE - */ -int parport_ax_epp_clear_timeout(struct parport *pb) -{ - unsigned char r; - - if (!(parport_ax_read_status(pb) & 0x01)) - return 1; - - /* To clear timeout some chips require double read */ - parport_ax_read_status(pb); - r = parport_ax_read_status(pb); - parport_ax_write_status(pb, r | 0x01); /* Some reset by writing 1 */ - parport_ax_write_status(pb, r & 0xfe); /* Others by writing 0 */ - r = parport_ax_read_status(pb); - - return !(r & 0x01); -} - -/* Check for ECP - * - * Old style XT ports alias io ports every 0x400, hence accessing ECONTROL - * on these cards actually accesses the CTR. - * - * Modern cards don't do this but reading from ECONTROL will return 0xff - * regardless of what is written here if the card does NOT support - * ECP. - * - * We will write 0x2c to ECONTROL and 0xcc to CTR since both of these - * values are "safe" on the CTR since bits 6-7 of CTR are unused. - */ -static int parport_ECR_present(struct parport *pb) -{ - unsigned int r; - unsigned char octr = pb->ops->read_control(pb), - oecr = pb->ops->read_econtrol(pb); - - r = pb->ops->read_control(pb); - if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) { - pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ - - r = pb->ops->read_control(pb); - if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) { - pb->ops->write_control(pb, octr); - return 0; /* Sure that no ECONTROL register exists */ - } - } - - if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1) - return 0; - - pb->ops->write_econtrol(pb, 0x34); - if (pb->ops->read_econtrol(pb) != 0x35) - return 0; - - pb->ops->write_econtrol(pb, oecr); - pb->ops->write_control(pb, octr); - - return PARPORT_MODE_PCECR; -} - -static int parport_ECP_supported(struct parport *pb) -{ - int i; - unsigned char oecr = pb->ops->read_econtrol(pb); - - /* If there is no ECONTROL, we have no hope of supporting ECP. */ - if (!(pb->modes & PARPORT_MODE_PCECR)) - return 0; - - /* - * Using LGS chipset it uses ECONTROL register, but - * it doesn't support ECP or FIFO MODE - */ - - pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */ - for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++) - pb->ops->write_fifo(pb, 0xaa); - - pb->ops->write_econtrol(pb, oecr); - return (i == 1024) ? 0 : PARPORT_MODE_PCECP; -} - -/* 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 parport_PS2_supported(struct parport *pb) -{ - int ok = 0; - unsigned char octr = pb->ops->read_control(pb); - - pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */ - - pb->ops->write_data(pb, 0x55); - if (pb->ops->read_data(pb) != 0x55) ok++; - - pb->ops->write_data(pb, 0xaa); - if (pb->ops->read_data(pb) != 0xaa) ok++; - - pb->ops->write_control(pb, octr); /* cancel input mode */ - - return ok ? PARPORT_MODE_PCPS2 : 0; -} - -static int parport_ECPPS2_supported(struct parport *pb) -{ - int mode; - unsigned char oecr = pb->ops->read_econtrol(pb); - - if (!(pb->modes & PARPORT_MODE_PCECR)) - return 0; - - pb->ops->write_econtrol(pb, 0x20); - - mode = parport_PS2_supported(pb); - - pb->ops->write_econtrol(pb, oecr); - return mode ? PARPORT_MODE_PCECPPS2 : 0; -} - -#define printmode(x) \ -{ \ - if (p->modes & PARPORT_MODE_PC##x) { \ - printk("%s%s", f ? "," : "", #x); \ - f++; \ - } \ -} - -int -init_one_port(struct linux_ebus_device *dev) -{ - struct parport tmpport, *p; - unsigned long base; - unsigned long config; - unsigned char tmp; - int irq, dma; - - /* Pointer to NS87303 Configuration Registers */ - config = dev->base_address[1]; - - /* Setup temporary access to Device operations */ - tmpport.base = dev->base_address[0]; - tmpport.ops = &parport_ax_ops; - - /* Enable ECP mode, set bit 2 of the CTR first */ - tmpport.ops->write_control(&tmpport, 0x04); - tmp = ns87303_readb(config, PCR); - tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA); - ns87303_writeb(config, PCR, tmp); - - /* LPT CTR bit 5 controls direction of parallel port */ - tmp = ns87303_readb(config, PTR); - tmp |= PTR_LPT_REG_DIR; - ns87303_writeb(config, PTR, tmp); - - /* Configure IRQ to Push Pull, Level Low */ - tmp = ns87303_readb(config, PCR); - tmp &= ~(PCR_IRQ_ODRAIN); - tmp |= PCR_IRQ_POLAR; - ns87303_writeb(config, PCR, tmp); - -#ifndef HAVE_SLOW_DEVICES - /* Enable Zero Wait State for ECP */ - tmp = ns87303_readb(config, FCR); - tmp |= FCR_ZWS_ENA; - ns87303_writeb(config, FCR, tmp); -#endif - - /* - * Now continue initializing the port - */ - base = dev->base_address[0]; - irq = dev->irqs[0]; - dma = PARPORT_DMA_AUTO; - - if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops))) - return 0; - - /* Save away pointer to our EBus DMA */ - p->private_data = (void *)dev->base_address[2]; - - p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p); - if (!check_region(p->base + 0x400, 3)) { - p->modes |= parport_ECR_present(p); - p->modes |= parport_ECP_supported(p); - p->modes |= parport_ECPPS2_supported(p); - } - p->size = 3; - - if (p->dma == PARPORT_DMA_AUTO) - p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE; - - 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)); - if (p->dma != PARPORT_DMA_NONE) - printk(", dma %d", p->dma); - printk(" ["); - { - int f = 0; - printmode(SPP); - printmode(PS2); - printmode(ECP); - printmode(ECPPS2); - } - 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); - - /* Tell the high-level drivers about the port. */ - parport_announce_port (p); - - return 1; -} - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -int init_module(void) -#else -__initfunc(int parport_ax_init(void)) -#endif -{ - struct linux_ebus *ebus; - struct linux_ebus_device *edev; - int count = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "ecpp")) - count += init_one_port(edev); - } - } - return count ? 0 : -ENODEV; -} - -#ifdef MODULE -void -cleanup_module(void) -{ - struct parport *p = parport_enumerate(), *tmp; - while (p) { - tmp = p->next; - if (p->modes & PARPORT_MODE_PCSPP) { - if (p->irq != PARPORT_IRQ_NONE) { - parport_ax_disable_irq(p); - free_irq(p->irq, p); - } - release_region(p->base, p->size); - if (p->modes & PARPORT_MODE_PCECR) - release_region(p->base+0x400, 3); - release_region((unsigned long)p->private_data, - sizeof(struct linux_ebus_dma)); - parport_proc_unregister(p); - parport_unregister_port(p); - } - p = tmp; - } -} -#endif diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_daisy.c linux/drivers/misc/parport_daisy.c --- v2.3.11/linux/drivers/misc/parport_daisy.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_daisy.c Wed Dec 31 16:00:00 1969 @@ -1,473 +0,0 @@ -/* - * 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 - -#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 -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c --- v2.3.11/linux/drivers/misc/parport_ieee1284.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/misc/parport_ieee1284.c Wed Dec 31 16:00:00 1969 @@ -1,545 +0,0 @@ -/* $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 - -#undef 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 & ~IEEE1284_ADDR; - unsigned char xflag; - - port = port->physport; - - /* Is there anything to do? */ - if (port->ieee1284.mode == mode) - return 0; - - /* Is the difference just an address-or-not bit? */ - if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){ - 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; - int addr = mode & IEEE1284_ADDR; - size_t (*fn) (struct parport *, const void *, size_t, int); - - /* Ignore the device-ID-request bit and the address bit. */ - mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - - /* 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); - if (addr) - fn = port->ops->epp_write_addr; - else - 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); - if (addr) - fn = port->ops->ecp_write_addr; - else - 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! */ - if (addr) - fn = parport_ieee1284_ecp_write_addr; - else - 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; - int addr = mode & IEEE1284_ADDR; - size_t (*fn) (struct parport *, void *, size_t, int); - - /* Ignore the device-ID-request bit and the address bit. */ - mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - - /* 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); - if (addr) - fn = port->ops->epp_read_addr; - else - 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 -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ieee1284_ops.c linux/drivers/misc/parport_ieee1284_ops.c --- v2.3.11/linux/drivers/misc/parport_ieee1284_ops.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_ieee1284_ops.c Wed Dec 31 16:00:00 1969 @@ -1,848 +0,0 @@ -/* 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) -{ - /* This is untested */ - unsigned char *bp = (unsigned char *) buffer; - size_t ret = 0; - - parport_frob_control (port, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_SELECT, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); - port->ops->data_forward (port); - for (; len > 0; len--, bp++) { - parport_write_data (port, *bp); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - /* Strobe data */ - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) - break; - - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - ret++; - } - - return ret; -} - -/* EPP mode, reverse channel, data. */ -size_t parport_ieee1284_epp_read_data (struct parport *port, - void *buffer, size_t len, - int flags) -{ - /* This is untested. */ - unsigned char *bp = (unsigned char *) buffer; - unsigned ret = 0; - - parport_frob_control (port, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_SELECT, 0); - port->ops->data_reverse (port); - for (; len > 0; len--, bp++) { - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) - break; - - *bp = parport_read_data (port); - - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - ret++; - } - port->ops->data_forward (port); - - return ret; -} - -/* EPP mode, forward channel, addresses. */ -size_t parport_ieee1284_epp_write_addr (struct parport *port, - const void *buffer, size_t len, - int flags) -{ - /* This is untested */ - unsigned char *bp = (unsigned char *) buffer; - size_t ret = 0; - - parport_frob_control (port, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); - port->ops->data_forward (port); - for (; len > 0; len--, bp++) { - parport_write_data (port, *bp); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - /* Strobe data */ - parport_frob_control (port, PARPORT_CONTROL_SELECT, - PARPORT_CONTROL_SELECT); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) - break; - - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); - ret++; - } - - return ret; -} - -/* EPP mode, reverse channel, addresses. */ -size_t parport_ieee1284_epp_read_addr (struct parport *port, - void *buffer, size_t len, - int flags) -{ - /* This is untested. */ - unsigned char *bp = (unsigned char *) buffer; - unsigned ret = 0; - - parport_frob_control (port, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD, 0); - port->ops->data_reverse (port); - for (; len > 0; len--, bp++) { - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - parport_frob_control (port, PARPORT_CONTROL_SELECT, - PARPORT_CONTROL_SELECT); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) - break; - - *bp = parport_read_data (port); - - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); - ret++; - } - port->ops->data_forward (port); - - return ret; -} diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.3.11/linux/drivers/misc/parport_init.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/misc/parport_init.c Wed Dec 31 16:00:00 1969 @@ -1,210 +0,0 @@ -/* Parallel-port initialisation code. - * - * Authors: David Campbell - * Tim Waugh - * Jose Renau - * - * based on work by Grant Guenther - * and Philip Blundell - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifndef MODULE -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_NONE }; - -extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); -extern int parport_ax_init(void); - -static int parport_setup_ptr __initdata = 0; - -__initfunc(void parport_setup(char *str, int *ints)) -{ - if (ints[0] == 0) { - if (str && !strncmp(str, "auto", 4)) { - irq[0] = PARPORT_IRQ_AUTO; - dma[0] = PARPORT_DMA_AUTO; - } - else if (str) - printk (KERN_ERR "parport: `%s': huh?\n", str); - else - printk (KERN_ERR "parport: parport=.. what?\n"); - - return; - } - else if (ints[1] == 0) { - /* Disable parport if "parport=0" in cmdline */ - io[0] = PARPORT_DISABLE; - return; - } - - if (parport_setup_ptr < PARPORT_MAX) { - char *sep; - io[parport_setup_ptr] = ints[1]; - irq[parport_setup_ptr] = PARPORT_IRQ_NONE; - dma[parport_setup_ptr] = PARPORT_DMA_NONE; - if (ints[0] > 1) { - irq[parport_setup_ptr] = ints[2]; - if (ints[0] > 2) { - dma[parport_setup_ptr] = ints[3]; - goto done; - } - - if (str == NULL) - goto done; - - goto dma_from_str; - } - else if (str == NULL) - goto done; - else if (!strncmp(str, "auto", 4)) - irq[parport_setup_ptr] = PARPORT_IRQ_AUTO; - else if (strncmp(str, "none", 4) != 0) { - printk(KERN_ERR "parport: bad irq `%s'\n", str); - return; - } - - if ((sep = strchr(str, ',')) == NULL) goto done; - str = sep+1; - dma_from_str: - if (!strncmp(str, "auto", 4)) - dma[parport_setup_ptr] = PARPORT_DMA_AUTO; - else if (strncmp(str, "none", 4) != 0) { - char *ep; - dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0); - if (ep == str) { - printk(KERN_ERR "parport: bad dma `%s'\n", - str); - return; - } - } - done: - parport_setup_ptr++; - } else - printk(KERN_ERR "parport=%s ignored, too many ports\n", str); -} -#endif - -#ifdef MODULE -int init_module(void) -{ -#ifdef CONFIG_SYSCTL - parport_default_proc_register (); -#endif - return 0; -} - -void cleanup_module(void) -{ -#ifdef CONFIG_SYSCTL - parport_default_proc_unregister (); -#endif -} - -#else - -__initfunc(int parport_init(void)) -{ - if (io[0] == PARPORT_DISABLE) - return 1; - -#ifdef CONFIG_SYSCTL - parport_default_proc_register (); -#endif - -#ifdef CONFIG_PARPORT_PC - parport_pc_init(io, io_hi, irq, dma); -#endif -#ifdef CONFIG_PARPORT_AX - parport_ax_init(); -#endif -#ifdef CONFIG_PARPORT_AMIGA - parport_amiga_init(); -#endif -#ifdef CONFIG_PARPORT_MFC3 - parport_mfc3_init(); -#endif -#ifdef CONFIG_PARPORT_ATARI - parport_atari_init(); -#endif -#ifdef CONFIG_PARPORT_ARC - parport_arc_init(); -#endif - return 0; -} -#endif - -/* Exported symbols for modules. */ - -EXPORT_SYMBOL(parport_claim); -EXPORT_SYMBOL(parport_claim_or_block); -EXPORT_SYMBOL(parport_release); -EXPORT_SYMBOL(parport_register_port); -EXPORT_SYMBOL(parport_announce_port); -EXPORT_SYMBOL(parport_unregister_port); -EXPORT_SYMBOL(parport_register_driver); -EXPORT_SYMBOL(parport_unregister_driver); -EXPORT_SYMBOL(parport_register_device); -EXPORT_SYMBOL(parport_unregister_device); -EXPORT_SYMBOL(parport_enumerate); -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_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_1284 -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) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void dec_parport_count(void) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_mfc3.c linux/drivers/misc/parport_mfc3.c --- v2.3.11/linux/drivers/misc/parport_mfc3.c Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/parport_mfc3.c Wed Dec 31 16:00:00 1969 @@ -1,414 +0,0 @@ -/* Low-level parallel port routines for the Multiface 3 card - * - * Author: Joerg Dorchain - * - * (C) The elitist m68k Users(TM) - * - * based on the existing parport_amiga and lp_mfc - * - * - * From the MFC3 documentation: - * - * Miscellaneous PIA Details - * ------------------------- - * - * The two open-drain interrupt outputs /IRQA and /IRQB are routed to - * /INT2 of the Z2 bus. - * - * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2 - * bus. This means that any PIA registers are accessed at even addresses. - * - * Centronics Pin Connections for the PIA - * -------------------------------------- - * - * The following table shows the connections between the PIA and the - * Centronics interface connector. These connections implement a single, but - * very complete, Centronics type interface. The Pin column gives the pin - * numbers of the PIA. The Centronics pin numbers can be found in the section - * "Parallel Connectors". - * - * - * Pin | PIA | Dir | Centronics Names - * -------+-----+-----+--------------------------------------------------------- - * 19 | CB2 | --> | /STROBE (aka /DRDY) - * 10-17 | PBx | <-> | DATA0 - DATA7 - * 18 | CB1 | <-- | /ACK - * 40 | CA1 | <-- | BUSY - * 3 | PA1 | <-- | PAPER-OUT (aka POUT) - * 4 | PA2 | <-- | SELECTED (aka SEL) - * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME) - * 6 | PA4 | <-- | /ERROR (aka /FAULT) - * 7 | PA5 | --> | DIR (aka /SELECT-IN) - * 8 | PA6 | --> | /AUTO-FEED-XT - * 39 | CA2 | --> | open - * 5 | PA3 | <-- | /ACK (same as CB1!) - * 2 | PA0 | <-- | BUSY (same as CA1!) - * -------+-----+-----+--------------------------------------------------------- - * - * Should be enough to understand some of the driver. - */ - -#include "multiface.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Maximum Number of Cards supported */ -#define MAX_MFC 5 - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK printk -#else -static inline int DPRINTK() {return 0;} -#endif - -static struct parport *this_port[MAX_MFC] = {NULL, }; -static volatile int dummy; /* for trigger readds */ - -#define pia(dev) ((struct pia *)(dev->base)) -static struct parport_operations pp_mfc3_ops; - -static void mfc3_write_data(struct parport *p, unsigned char data) -{ -DPRINTK("write_data %c\n",data); - - dummy = pia(p)->pprb; /* clears irq bit */ - /* Triggers also /STROBE.*/ - pia(p)->pprb = data; -} - -static unsigned char mfc3_read_data(struct parport *p) -{ - /* clears interupt bit. Triggers also /STROBE. */ - return pia(p)->pprb; -} - -static unsigned char control_pc_to_mfc3(unsigned char control) -{ - unsigned char ret = 32|64; - - if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ - ; - if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ - ; - if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ - ret &= ~32; /* /SELECT_IN */ - if (control & PARPORT_CONTROL_INIT) /* INITP */ - ret |= 128; - if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ - ret &= ~64; - if (control & PARPORT_CONTROL_STROBE) /* Strobe */ - /* Handled directly by hardware */; - return ret; -} - -static unsigned char control_mfc3_to_pc(unsigned char control) -{ - unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE - | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT; - - if (control & 128) /* /INITP */ - ret |= PARPORT_CONTROL_INIT; - if (control & 64) /* /AUTOLF */ - ret &= ~PARPORT_CONTROL_AUTOFD; - if (control & 32) /* /SELECT_IN */ - ret &= ~PARPORT_CONTROL_SELECT; - return ret; -} - -static void mfc3_write_control(struct parport *p, unsigned char control) -{ -DPRINTK("write_control %02x\n",control); - pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control); -} - -static unsigned char mfc3_read_control( struct parport *p) -{ -DPRINTK("read_control \n"); - return control_mfc3_to_pc(pia(p)->ppra & 0xe0); -} - -static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val) -{ - unsigned char old; - -DPRINTK("frob_control mask %02x, value %02x\n",mask,val); - old = mfc3_read_control(p); - mfc3_write_control(p, (old & ~mask) ^ val); - return old; -} - - -static unsigned char status_pc_to_mfc3(unsigned char status) -{ - unsigned char ret = 1; - - if (status & PARPORT_STATUS_BUSY) /* Busy */ - ret &= ~1; - if (status & PARPORT_STATUS_ACK) /* Ack */ - ret |= 8; - if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ - ret |= 2; - if (status & PARPORT_STATUS_SELECT) /* select */ - ret |= 4; - if (status & PARPORT_STATUS_ERROR) /* error */ - ret |= 16; - return ret; -} - -static unsigned char status_mfc3_to_pc(unsigned char status) -{ - unsigned char ret = PARPORT_STATUS_BUSY; - - if (status & 1) /* Busy */ - ret &= ~PARPORT_STATUS_BUSY; - if (status & 2) /* PaperOut */ - ret |= PARPORT_STATUS_PAPEROUT; - if (status & 4) /* Selected */ - ret |= PARPORT_STATUS_SELECT; - if (status & 8) /* Ack */ - ret |= PARPORT_STATUS_ACK; - if (status & 16) /* /ERROR */ - ret |= PARPORT_STATUS_ERROR; - - return ret; -} - -static void mfc3_write_status( struct parport *p, unsigned char status) -{ -DPRINTK("write_status %02x\n",status); - pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status); -} - -static unsigned char mfc3_read_status(struct parport *p) -{ - unsigned char status; - - status = status_mfc3_to_pc(pia(p)->ppra & 0x1f); -DPRINTK("read_status %02x\n", status); - return status; -} - -static void mfc3_change_mode( struct parport *p, int m) -{ - /* XXX: This port only has one mode, and I am - not sure about the corresponding PC-style mode*/ -} - -static int use_cnt = 0; - -static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int i; - - for( i = 0; i < MAX_MFC; i++) - if (this_port[i] != NULL) - if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */ - dummy = pia(this_port[i])->pprb; /* clear irq bit */ - parport_generic_irq(irq, this_port[i], regs); - } -} - -static int mfc3_claim_resources(struct parport *p) -{ -DPRINTK("claim_resources\n"); -} - -static void mfc3_init_state(struct parport_state *s) -{ - s->u.amiga.data = 0; - s->u.amiga.datadir = 255; - s->u.amiga.status = 0; - s->u.amiga.statusdir = 0xe0; -} - -static void mfc3_save_state(struct parport *p, struct parport_state *s) -{ - s->u.amiga.data = pia(p)->pprb; - pia(p)->crb &= ~PIA_DDR; - s->u.amiga.datadir = pia(p)->pddrb; - pia(p)->crb |= PIA_DDR; - s->u.amiga.status = pia(p)->ppra; - pia(p)->cra &= ~PIA_DDR; - s->u.amiga.statusdir = pia(p)->pddrb; - pia(p)->cra |= PIA_DDR; -} - -static void mfc3_restore_state(struct parport *p, struct parport_state *s) -{ - pia(p)->pprb = s->u.amiga.data; - pia(p)->crb &= ~PIA_DDR; - pia(p)->pddrb = s->u.amiga.datadir; - pia(p)->crb |= PIA_DDR; - pia(p)->ppra = s->u.amiga.status; - pia(p)->cra &= ~PIA_DDR; - pia(p)->pddrb = s->u.amiga.statusdir; - pia(p)->cra |= PIA_DDR; -} - -static void mfc3_enable_irq(struct parport *p) -{ - pia(p)->crb |= PIA_C1_ENABLE_IRQ; -} - -static void mfc3_disable_irq(struct parport *p) -{ - pia(p)->crb &= ~PIA_C1_ENABLE_IRQ; -} - -static void mfc3_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -static void mfc3_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - -static void mfc3_fill_inode(struct inode *inode, int fill) -{ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -static struct parport_operations pp_mfc3_ops = { - mfc3_write_data, - mfc3_read_data, - - mfc3_write_control, - mfc3_read_control, - mfc3_frob_control, - - NULL, /* write_econtrol */ - NULL, /* read_econtrol */ - NULL, /* frob_econtrol */ - - mfc3_write_status, - mfc3_read_status, - - NULL, /* write fifo */ - NULL, /* read fifo */ - - mfc3_change_mode, - - - mfc3_release_resources, - mfc3_claim_resources, - - - NULL, /* epp_write_data */ - NULL, /* epp_read_data */ - NULL, /* epp_write_addr */ - NULL, /* epp_read_addr */ - NULL, /* epp_check_timeout */ - - NULL, /* epp_write_block */ - NULL, /* epp_read_block */ - - NULL, /* ecp_write_block */ - NULL, /* ecp_read_block */ - - mfc3_init_state, - mfc3_save_state, - mfc3_restore_state, - - mfc3_enable_irq, - mfc3_disable_irq, - mfc3_interrupt, - - mfc3_inc_use_count, - mfc3_dec_use_count, - mfc3_fill_inode -}; - -/* ----------- Initialisation code --------------------------------- */ - -__initfunc(int parport_mfc3_init(void)) -{ - struct parport *p; - int pias = 0; - struct pia *pp; - unsigned int key = 0; - const struct ConfigDev *cd; - - if (MACH_IS_AMIGA) { - while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) { - cd = zorro_get_board(key); - pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE)); - if (pias < MAX_MFC) { - pp->crb = 0; - pp->pddrb = 255; /* all data pins output */ - pp->crb = PIA_DDR|32|8; - dummy = pp->pddrb; /* reading clears interrupt */ - pp->cra = 0; - pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */ - pp->cra = PIA_DDR; - pp->ppra = 0; /* reset printer */ - udelay(10); - pp->ppra = 128; - if ((p = parport_register_port((unsigned long)pp, - IRQ_AMIGA_PORTS, PARPORT_DMA_NONE, - &pp_mfc3_ops))) { - this_port[pias++] = p; - printk(KERN_INFO "%s: Multiface III port using irq\n", p->name); - /* XXX: set operating mode */ - parport_proc_register(p); - - if (p->irq != PARPORT_IRQ_NONE) - if (use_cnt++ == 0) - if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops)) - use_cnt--; - - if (parport_probe_hook) - (*parport_probe_hook)(p); - zorro_config_board(key, 0); - p->private_data = (void *)key; - parport_announce_port (p); - } - } - } - } - return pias; -} - -#ifdef MODULE - -MODULE_AUTHOR("Joerg Dorchain"); -MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port"); -MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port"); - -int init_module(void) -{ - return ! parport_mfc3_init(); -} - -void cleanup_module(void) -{ - int i; - - for (i = 0; i < MAX_MFC; i++) - if (this_port[i] != NULL) { - if (p->irq != PARPORT_IRQ_NONE) - if (--use_cnt == 0) - free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops); - parport_proc_unregister(this_port[i]); - parport_unregister_port(this_port[i]); - zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0); - } -} -#endif - - diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.3.11/linux/drivers/misc/parport_pc.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/misc/parport_pc.c Wed Dec 31 16:00:00 1969 @@ -1,1904 +0,0 @@ -/* Low-level parallel-port routines for 8255-based PC-style hardware. - * - * Authors: Phil Blundell - * Tim Waugh - * Jose Renau - * David Campbell - * Andrea Arcangeli - * - * 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 - */ - -/* This driver should work with any hardware that is broadly compatible - * with that in the IBM PC. This applies to the majority of integrated - * I/O chipsets that are commonly available. The expected register - * layout is: - * - * base+0 data - * base+1 status - * base+2 control - * - * In addition, there are some optional registers: - * - * base+3 EPP address - * base+4 EPP data - * base+0x400 ECP config A - * base+0x401 ECP config B - * base+0x402 ECP control - * - * All registers are 8 bits wide and read/write. If your hardware differs - * only in register addresses (eg because your registers are on 32-bit - * word boundaries) then you can alter the constants in parport_pc.h to - * accomodate this. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* Maximum number of ports to support. It is useless to set this greater - 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. - */ -static int clear_epp_timeout(struct parport *pb) -{ - unsigned char r; - - if (!(parport_pc_read_status(pb) & 0x01)) - return 1; - - /* To clear timeout some chips require double read */ - parport_pc_read_status(pb); - r = parport_pc_read_status(pb); - 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_data(struct parport *p, unsigned char d) -{ - outb (d, DATA (p)); -} - -unsigned char parport_pc_read_data(struct parport *p) -{ - return inb (DATA (p)); -} - -unsigned char __frob_control (struct parport *p, unsigned char mask, - unsigned char val) -{ - 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 */ -} - -void parport_pc_write_control(struct parport *p, unsigned char d) -{ - 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); - } - - __frob_control (p, wm, d & wm); -} - -unsigned char parport_pc_read_control(struct parport *p) -{ - const struct parport_pc_private *priv = p->physport->private_data; - return priv->ctr; /* Use soft copy */ -} - -unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, - unsigned char val) -{ - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); - - /* 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_status(struct parport *p) -{ - return inb (STATUS (p)); -} - -void parport_pc_disable_irq(struct parport *p) -{ - __frob_control (p, 0x10, 0); -} - -void parport_pc_enable_irq(struct parport *p) -{ - __frob_control (p, 0x10, 0x10); -} - -void parport_pc_data_forward (struct parport *p) -{ - __frob_control (p, 0x20, 0); -} - -void parport_pc_data_reverse (struct parport *p) -{ - __frob_control (p, 0x20, 0x20); -} - -void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) -{ - s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); - s->u.pc.ecr = 0x24; -} - -void parport_pc_save_state(struct parport *p, struct parport_state *s) -{ - 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)); -} - -void parport_pc_restore_state(struct parport *p, struct parport_state *s) -{ - 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)); -} - -#ifdef CONFIG_PARPORT_1284 -static size_t parport_pc_epp_read_data (struct parport *port, void *buf, - size_t length, int flags) -{ - 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; -} - -static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, - size_t length, int flags) -{ - 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; -} - -static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, - size_t length, int flags) -{ - 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; -} - -static size_t parport_pc_epp_write_addr (struct parport *port, - const void *buf, size_t length, - int flags) -{ - 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; -} - -static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, - size_t length, int flags) -{ - 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; -} - -static size_t parport_pc_ecpepp_write_data (struct parport *port, - const void *buf, size_t length, - int flags) -{ - 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; -} - -static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, - size_t length, int flags) -{ - 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; -} - -static size_t parport_pc_ecpepp_write_addr (struct parport *port, - const void *buf, size_t length, - int flags) -{ - 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 */ - -#ifdef CONFIG_PARPORT_PC_FIFO -static size_t parport_pc_fifo_write_block_pio (struct parport *port, - const void *buf, size_t length) -{ - 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; -} - -static size_t parport_pc_fifo_write_block_dma (struct parport *port, - const void *buf, size_t length) -{ - 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; - } - - /* 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; -} - -/* 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; - - /* 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; -} - -/* ECP */ -#ifdef CONFIG_PARPORT_1284 -size_t parport_pc_ecp_write_block_pio (struct parport *port, - const void *buf, size_t length, - int flags) -{ - 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; -} - -size_t parport_pc_ecp_read_block_pio (struct parport *port, - void *buf, size_t length, int flags) -{ - 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 - MOD_INC_USE_COUNT; -#endif -} - -void parport_pc_dec_use_count(void) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static void parport_pc_fill_inode(struct inode *inode, int fill) -{ - /* Is this still needed? -tim */ -#ifdef MODULE - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -#endif -} - -struct parport_operations parport_pc_ops = -{ - parport_pc_write_data, - parport_pc_read_data, - - parport_pc_write_control, - parport_pc_read_control, - parport_pc_frob_control, - - parport_pc_read_status, - - parport_pc_enable_irq, - parport_pc_disable_irq, - - parport_pc_data_forward, - parport_pc_data_reverse, - - parport_pc_interrupt, - parport_pc_init_state, - parport_pc_save_state, - parport_pc_restore_state, - - parport_pc_inc_use_count, - parport_pc_dec_use_count, - 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 - */ -static int __init parport_SPP_supported(struct parport *pb) -{ - unsigned char r, w; - - /* - * first clear an eventually pending EPP timeout - * I (sailer@ife.ee.ethz.ch) have an SMSC chipset - * that does not even respond to SPP cycles if an EPP - * timeout is pending - */ - clear_epp_timeout(pb); - - /* Do a simple read-write test to make sure the port exists. */ - w = 0xc; - outb (w, CONTROL (pb)); - - /* 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; - outb (w, CONTROL (pb)); - r = inb (CONTROL (pb)); - outb (0xc, CONTROL (pb)); - if ((r & 0xf) == w) - return PARPORT_MODE_PCSPP; - } - - if (user_specified) - /* That didn't work, but the user thinks there's a - * port here. */ - printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n", - pb->base, w, r); - - /* Try the data register. The data lines aren't tri-stated at - * this stage, so we expect back what we wrote. */ - w = 0xaa; - parport_pc_write_data (pb, w); - r = parport_pc_read_data (pb); - if (r == w) { - w = 0x55; - parport_pc_write_data (pb, w); - r = parport_pc_read_data (pb); - if (r == w) - return PARPORT_MODE_PCSPP; - } - - if (user_specified) - /* 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. */ - if (user_specified) - return PARPORT_MODE_PCSPP; - - return 0; -} - -/* Check for ECR - * - * Old style XT ports alias io ports every 0x400, hence accessing ECR - * on these cards actually accesses the CTR. - * - * Modern cards don't do this but reading from ECR will return 0xff - * regardless of what is written here if the card does NOT support - * ECP. - * - * 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) -{ - struct parport_pc_private *priv = pb->private_data; - unsigned char r = 0xc; - - priv->ecr = 0; - outb (r, CONTROL (pb)); - if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { - outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ - - r = inb (CONTROL (pb)); - if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2)) - goto no_reg; /* Sure that no ECR register exists */ - } - - if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) - goto no_reg; - - outb (0x34, ECONTROL (pb)); - if (inb (ECONTROL (pb)) != 0x35) - goto no_reg; - - priv->ecr = 1; - outb (0xc, CONTROL (pb)); - - /* Go to mode 000 */ - frob_econtrol (pb, 0xe0, ECR_SPP << 5); - - return 1; - - no_reg: - 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; - 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 (!priv->ecr) - return 0; - - /* 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)); - - result = parport_PS2_supported(pb); - - outb (oecr, ECONTROL (pb)); - return result; -} - -/* EPP mode detection */ - -static int __init parport_EPP_supported(struct parport *pb) -{ - const struct parport_pc_private *priv = pb->private_data; - - /* - * 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. - */ - - /* If EPP timeout bit clear then EPP available */ - if (!clear_epp_timeout(pb)) - return 0; /* No way to clear timeout */ - - /* Check for Intel bug. */ - if (priv->ecr) { - unsigned char i; - for (i = 0x00; i < 0x80; i += 0x20) { - outb (i, ECONTROL (pb)); - if (clear_epp_timeout (pb)) - /* Phony EPP in ECP. */ - return 0; - } - } - - 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) -{ - struct parport_pc_private *priv = pb->private_data; - int result; - unsigned char oecr; - - if (!priv->ecr) - return 0; - - oecr = inb (ECONTROL (pb)); - /* Search for SMC style EPP+ECP mode */ - outb (0x80, ECONTROL (pb)); - - result = parport_EPP_supported(pb); - - outb (oecr, ECONTROL (pb)); - - 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 result; -} - -#else /* No IEEE 1284 support */ - -/* 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; } - -#endif /* No IEEE 1284 support */ - -/* --- IRQ detection -------------------------------------- */ - -/* Only if supports ECP mode */ -static int __init programmable_irq_support(struct parport *pb) -{ - int irq, intrLine; - unsigned char oecr = inb (ECONTROL (pb)); - static const int lookup[8] = { - PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 - }; - - outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */ - - intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; - irq = lookup[intrLine]; - - outb (oecr, ECONTROL (pb)); - return irq; -} - -static int __init irq_probe_ECP(struct parport *pb) -{ - int i; - unsigned long irqs; - - sti(); - irqs = probe_irq_on(); - - 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 writeIntrThreshold is generated */ - for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) - outb (0xaa, FIFO (pb)); - - pb->irq = probe_irq_off(irqs); - outb (ECR_SPP << 5, ECONTROL (pb)); - - if (pb->irq <= 0) - pb->irq = PARPORT_IRQ_NONE; - - return pb->irq; -} - -/* - * This detection seems that only works in National Semiconductors - * This doesn't work in SMC, LGS, and Winbond - */ -static int __init irq_probe_EPP(struct parport *pb) -{ -#ifndef ADVANCED_DETECT - return PARPORT_IRQ_NONE; -#else - int irqs; - unsigned char oecr; - - if (pb->modes & PARPORT_MODE_PCECR) - oecr = inb (ECONTROL (pb)); - - sti(); - irqs = probe_irq_on(); - - if (pb->modes & PARPORT_MODE_PCECR) - frob_econtrol (pb, 0x10, 0x10); - - clear_epp_timeout(pb); - parport_pc_frob_control (pb, 0x20, 0x20); - parport_pc_frob_control (pb, 0x10, 0x10); - clear_epp_timeout(pb); - - /* Device isn't expecting an EPP read - * and generates an IRQ. - */ - parport_pc_read_epp(pb); - udelay(20); - - pb->irq = probe_irq_off (irqs); - if (pb->modes & PARPORT_MODE_PCECR) - 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 */ -} - -static int __init irq_probe_SPP(struct parport *pb) -{ - /* Don't even try to do this. */ - return PARPORT_IRQ_NONE; -} - -/* We will attempt to share interrupt requests since other devices - * such as sound cards and network cards seem to like using the - * printer IRQs. - * - * When ECP is available we can autoprobe for IRQs. - * NOTE: If we can autoprobe it, we can register the IRQ. - */ -static int __init parport_irq_probe(struct parport *pb) -{ - 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_ECP) - pb->irq = irq_probe_ECP(pb); - - if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && - (pb->modes & PARPORT_MODE_EPP)) - pb->irq = irq_probe_EPP(pb); - - clear_epp_timeout(pb); - - if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) - pb->irq = irq_probe_EPP(pb); - - clear_epp_timeout(pb); - - if (pb->irq == PARPORT_IRQ_NONE) - pb->irq = irq_probe_SPP(pb); - -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, - unsigned long int base_hi, - int irq, int dma) -{ - struct parport_pc_private *priv; - struct parport tmp; - struct parport *p = &tmp; - int probedirq = PARPORT_IRQ_NONE; - if (check_region(base, 3)) return 0; - priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL); - if (!priv) { - printk (KERN_DEBUG "parport (0x%lx): no memory!\n", 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; - p->dma = dma; - p->modes = PARPORT_MODE_PCSPP; - p->ops = &parport_pc_ops; - p->private_data = priv; - p->physport = p; - if (base_hi && !check_region(base_hi,3)) { - parport_ECR_present(p); - parport_ECP_supported(p); - parport_ECPPS2_supported(p); - } - if (base != 0x3bc) { - if (!check_region(base+0x3, 5)) { - parport_EPP_supported(p); - if (!(p->modes & PARPORT_MODE_EPP)) - parport_ECPEPP_supported(p); - } - } - if (!parport_SPP_supported (p)) { - /* No port. */ - kfree (priv); - return 0; - } - - parport_PS2_supported (p); - - 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_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_ECP)) - printk(" (0x%lx)", p->base_hi); - p->irq = irq; - p->dma = dma; - if (p->irq == PARPORT_IRQ_AUTO) { - p->irq = PARPORT_IRQ_NONE; - parport_irq_probe(p); - } else if (p->irq == PARPORT_IRQ_PROBEONLY) { - p->irq = PARPORT_IRQ_NONE; - parport_irq_probe(p); - probedirq = p->irq; - 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) - 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_##x){printk("%s%s",f?",":"",#x);f++;}} - { - int f = 0; - printmode(PCSPP); - printmode(TRISTATE); - printmode(COMPAT) - printmode(EPP); - printmode(ECP); - printmode(DMA); - } -#undef printmode - printk("]\n"); - if (probedirq != PARPORT_IRQ_NONE) - printk("%s: irq %d detected\n", p->name, probedirq); - parport_proc_register(p); - - request_region (p->base, 3, p->name); - if (p->size > 3) - request_region (p->base + 3, p->size - 3, p->name); - if (p->modes & PARPORT_MODE_ECP) - request_region (p->base_hi, 3, p->name); - - if (p->irq != PARPORT_IRQ_NONE) { - if (request_irq (p->irq, parport_pc_interrupt, - 0, p->name, p)) { - printk (KERN_WARNING "%s: irq %d in use, " - "resorting to polled operation\n", - p->name, p->irq); - p->irq = PARPORT_IRQ_NONE; - p->dma = PARPORT_DMA_NONE; - } - - if (p->dma != PARPORT_DMA_NONE) { - if (request_dma (p->dma, p->name)) { - printk (KERN_WARNING "%s: dma %d in use, " - "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. - * SELECT | INIT also puts IEEE1284-compliant devices into - * compatibility mode. */ - if (p->modes & PARPORT_MODE_ECP) - /* - * Put the ECP detected port in PS2 mode. - */ - outb (0x24, ECONTROL (p)); - - parport_pc_write_data(p, 0); - parport_pc_data_forward (p); - parport_pc_write_control(p, PARPORT_CONTROL_SELECT); - udelay (50); - parport_pc_write_control(p, - PARPORT_CONTROL_SELECT - | PARPORT_CONTROL_INIT); - udelay (50); - - /* Now that we've told the sharing engine about the port, and - found out its characteristics, let the high-level drivers - know about it. */ - parport_announce_port (p); - - return 1; -} - -/* Look for PCI parallel port cards. */ -static int __init parport_pc_init_pci (int irq, int dma) -{ -/* These need to go in pci.h: */ -#ifndef PCI_VENDOR_ID_SIIG -#define PCI_VENDOR_ID_SIIG 0x131f -#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010 -#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011 -#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012 -#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020 -#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036 -#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020 -#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 -#define PCI_VENDOR_ID_LAVA 0x1407 -#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 - - struct { - unsigned int vendor; - unsigned int device; - unsigned int numports; - struct { - unsigned int lo; - unsigned int hi; /* -ve if not there */ - } addr[4]; - } cards[] = { - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1, - { { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1, - { { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1, - { { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1, - { { 2, 3 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2, - { { 2, 3 }, { 4, 5 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1, - { { 4, 5 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1, - { { 4, 5 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1, - { { 4, 5 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1, - { { 0, 1 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2, - { { 0, 1 }, { 2, 3 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2, - { { 1, 2 }, { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2, - { { 1, 2 }, { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2, - { { 1, 2 }, { 3, 4 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1, - { { 1, 2 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1, - { { 1, 2 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1, - { { 1, 2 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1, - { { 2, 3 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1, - { { 2, 3 }, } }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1, - { { 2, 3 }, } }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1, - { { 0, -1 }, } }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1, - { { 0, -1 }, } }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1, - { { 0, -1 }, } }, - { 0, } - }; - - int count = 0; - int i; - - if (!pci_present ()) - return 0; - - for (i = 0; cards[i].vendor; i++) { - struct pci_dev *pcidev = NULL; - while ((pcidev = pci_find_device (cards[i].vendor, - cards[i].device, - pcidev)) != NULL) { - int n; - for (n = 0; n < cards[i].numports; n++) { - int lo = cards[i].addr[n].lo; - int hi = cards[i].addr[n].hi; - int io_lo = pcidev->base_address[lo]; - int io_hi = ((hi < 0) ? 0 : - pcidev->base_address[hi]); - io_lo &= PCI_BASE_ADDRESS_IO_MASK; - io_hi &= PCI_BASE_ADDRESS_IO_MASK; - count += probe_one_port (io_lo, io_hi, - irq, dma); - } - } - } - - return count; -} - -int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma) -{ - int count = 0, i = 0; - if (io && *io) { - /* Only probe the ports we were given. */ - user_specified = 1; - do { - if (!*io_hi) *io_hi = 0x400 + *io; - count += probe_one_port(*(io++), *(io_hi++), - *(irq++), *(dma++)); - } while (*io && (++i < PARPORT_PC_MAX_PORTS)); - } else { - /* Probe all the likely ports. */ - count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]); - count += probe_one_port(0x378, 0x778, irq[0], dma[0]); - count += probe_one_port(0x278, 0x678, irq[0], dma[0]); - count += parport_pc_init_pci (irq[0], dma[0]); - } - - return count; -} - -#ifdef MODULE -static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; -static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; -static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; -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(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); -MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); -MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); - -int init_module(void) -{ - /* Work out how many ports we have, then get parport_share to parse - the irq values. */ - unsigned int i; - for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); - if (i) { - if (parport_parse_irqs(i, irq, irqval)) return 1; - if (parport_parse_dmas(i, dma, dmaval)) return 1; - } - else { - /* The user can make us use any IRQs or DMAs we find. */ - int val; - - if (irq[0] && !parport_parse_irqs (1, irq, &val)) - switch (val) { - case PARPORT_IRQ_NONE: - case PARPORT_IRQ_AUTO: - irqval[0] = val; - } - - if (dma[0] && !parport_parse_dmas (1, dma, &val)) - switch (val) { - case PARPORT_DMA_NONE: - case PARPORT_DMA_AUTO: - dmaval[0] = val; - } - } - - return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1); -} - -void cleanup_module(void) -{ - struct parport *p = parport_enumerate(), *tmp; - while (p) { - tmp = p->next; - if (p->modes & PARPORT_MODE_PCSPP) { - struct parport_pc_private *priv = p->private_data; - if (p->dma != PARPORT_DMA_NONE) - free_dma(p->dma); - if (p->irq != PARPORT_IRQ_NONE) - free_irq(p->irq, p); - release_region(p->base, 3); - if (p->size > 3); - release_region(p->base + 3, p->size - 3); - 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); - } - p = tmp; - } -} -#endif diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_probe.c linux/drivers/misc/parport_probe.c --- v2.3.11/linux/drivers/misc/parport_probe.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_probe.c Wed Dec 31 16:00:00 1969 @@ -1,212 +0,0 @@ -/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem 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 -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.3.11/linux/drivers/misc/parport_procfs.c Thu Jul 8 15:42:20 1999 +++ linux/drivers/misc/parport_procfs.c Wed Dec 31 16:00:00 1969 @@ -1,434 +0,0 @@ -/* Sysctl interface for parport devices. - * - * Authors: David Campbell - * Tim Waugh - * Philip Blundell - * Andrea Arcangeli - * Riccardo Facchetti - * - * based on work by Grant Guenther - * and Philip Blundell - * - * Cleaned up include files - Russell King - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_SYSCTL - - -static int do_active_device(ctl_table *table, int write, struct file *filp, - void *result, size_t *lenp) -{ - struct parport *port = (struct parport *)table->extra1; - char buffer[256]; - struct pardevice *dev; - int len = 0; - - if (write) /* can't happen anyway */ - return -EACCES; - - if (filp->f_pos) { - *lenp = 0; - return 0; - } - - for (dev = port->devices; dev ; dev = dev->next) { - if(dev == port->cad) { - len += sprintf(buffer, "%s\n", dev->name); - } - } - - if(!len) { - len += sprintf(buffer, "%s\n", "none"); - } - - if (len > *lenp) - len = *lenp; - else - *lenp = len; - - filp->f_pos += len; - - return copy_to_user(result, buffer, len) ? -EFAULT : 0; -} - -#ifdef CONFIG_PARPORT_1284 -static int do_autoprobe(ctl_table *table, int write, struct file *filp, - void *result, size_t *lenp) -{ - struct parport_device_info *info = table->extra2; - const char *str; - char buffer[256]; - int len = 0; - - if (write) /* permissions stop this */ - return -EACCES; - - if (filp->f_pos) { - *lenp = 0; - return 0; - } - - if ((str = info->class_name) != NULL) - len += sprintf (buffer + len, "CLASS:%s;\n", str); - - if ((str = info->model) != NULL) - len += sprintf (buffer + len, "MODEL:%s;\n", str); - - if ((str = info->mfr) != NULL) - len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str); - - if ((str = info->description) != NULL) - len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str); - - if ((str = info->cmdset) != NULL) - len += sprintf (buffer + len, "COMMAND SET:%s;\n", str); - - if (len > *lenp) - len = *lenp; - else - *lenp = len; - - filp->f_pos += len; - - return copy_to_user (result, buffer, len) ? -EFAULT : 0; -} -#endif /* IEEE1284.3 support. */ - -static int do_hardware(ctl_table *table, int write, struct file *filp, - void *result, size_t *lenp) -{ - struct parport *port = (struct parport *)table->extra1; - char buffer[256]; - int len = 0; - - if (filp->f_pos) { - *lenp = 0; - return 0; - } - - if (write) /* can't happen anyway */ - return -EACCES; - - len += sprintf(buffer+len, "base:\t0x%lx", port->base); - if (port->base_hi) - len += sprintf(buffer+len, " (0x%lx)", port->base_hi); - buffer[len++] = '\n'; - - if (port->irq == PARPORT_IRQ_NONE) { - len += sprintf(buffer+len, "irq:\tnone\n"); - } else { -#ifdef __sparc__ - len += sprintf(buffer+len, "irq:\t%s\n", - __irq_itoa(port->irq)); -#else - len += sprintf(buffer+len, "irq:\t%d\n", port->irq); -#endif - } - - if (port->dma == PARPORT_DMA_NONE) - len += sprintf(buffer+len, "dma:\tnone\n"); - else - len += sprintf(buffer+len, "dma:\t%d\n", port->dma); - - len += sprintf(buffer+len, "modes:\t"); - { -#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}} - int f = 0; - printmode(PCSPP); - printmode(TRISTATE); - printmode(COMPAT); - printmode(EPP); - printmode(ECP); - printmode(DMA); -#undef printmode - } - buffer[len++] = '\n'; - - if (len > *lenp) - len = *lenp; - else - *lenp = len; - - filp->f_pos += len; - - return copy_to_user(result, buffer, len) ? -EFAULT : 0; -} - -#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child } -#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \ - NULL, 0, 0555, child } -#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child } -#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \ - NULL, 0, 0555, NULL } - - -struct parport_sysctl_table { - struct ctl_table_header *sysctl_header; - ctl_table vars[9]; - ctl_table device_dir[2]; - ctl_table port_dir[2]; - ctl_table parport_dir[2]; - ctl_table dev_dir[2]; -}; - -static const struct parport_sysctl_table parport_sysctl_template = { - NULL, - { - { DEV_PARPORT_SPINTIME, "spintime", - NULL, sizeof(int), 0644, NULL, - &proc_dointvec }, - { DEV_PARPORT_HARDWARE, "hardware", - NULL, 0, 0444, NULL, - &do_hardware }, - PARPORT_DEVICES_ROOT_DIR, -#ifdef CONFIG_PARPORT_1284 - { DEV_PARPORT_AUTOPROBE, "autoprobe", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3", - NULL, 0, 0444, NULL, - &do_autoprobe }, -#endif /* IEEE 1284 support */ - {0} - }, - { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL, - &do_active_device }, {0}}, - { PARPORT_PORT_DIR(NULL), {0}}, - { PARPORT_PARPORT_DIR(NULL), {0}}, - { PARPORT_DEV_DIR(NULL), {0}} -}; - -struct parport_device_sysctl_table -{ - struct ctl_table_header *sysctl_header; - ctl_table vars[2]; - ctl_table device_dir[2]; - ctl_table devices_root_dir[2]; - ctl_table port_dir[2]; - ctl_table parport_dir[2]; - ctl_table dev_dir[2]; -}; - -static const struct parport_device_sysctl_table -parport_device_sysctl_template = { - NULL, - { - { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice", - NULL, sizeof(int), 0644, NULL, - &proc_dointvec }, - }, - { {0, NULL, NULL, 0, 0555, NULL}, {0}}, - { PARPORT_DEVICES_ROOT_DIR, {0}}, - { PARPORT_PORT_DIR(NULL), {0}}, - { PARPORT_PARPORT_DIR(NULL), {0}}, - { PARPORT_DEV_DIR(NULL), {0}} -}; - -struct parport_default_sysctl_table -{ - struct ctl_table_header *sysctl_header; - ctl_table vars[3]; - ctl_table default_dir[2]; - ctl_table parport_dir[2]; - ctl_table dev_dir[2]; -}; - -extern unsigned long parport_default_timeslice; -extern int parport_default_spintime; - -static struct parport_default_sysctl_table -parport_default_sysctl_table = { - NULL, - { - { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice", - &parport_default_timeslice, - sizeof(parport_default_timeslice), 0644, NULL, - &proc_dointvec }, - { DEV_PARPORT_DEFAULT_SPINTIME, "spintime", - &parport_default_spintime, - sizeof(parport_default_timeslice), 0644, NULL, - &proc_dointvec }, - {0} - }, - { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555, - parport_default_sysctl_table.vars },{0}}, - { - PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), - {0}}, - { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}} -}; - - -int parport_proc_register(struct parport *port) -{ - struct parport_sysctl_table *t; - int i; - - t = kmalloc(sizeof(*t), GFP_KERNEL); - if (t == NULL) - return -ENOMEM; - memcpy(t, &parport_sysctl_template, sizeof(*t)); - - t->device_dir[0].extra1 = port; - - for (i = 0; i < 8; i++) - t->vars[i].extra1 = port; - - t->vars[0].data = &port->spintime; - t->vars[2].child = t->device_dir; - - for (i = 0; i < 5; i++) - t->vars[3 + i].extra2 = &port->probe_info[i]; - - t->port_dir[0].procname = port->name; - t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ - - t->port_dir[0].child = t->vars; - t->parport_dir[0].child = t->port_dir; - t->dev_dir[0].child = t->parport_dir; - - t->sysctl_header = register_sysctl_table(t->dev_dir, 0); - if (t->sysctl_header == NULL) { - kfree(t); - t = NULL; - } - port->sysctl_table = t; - return 0; -} - -int parport_proc_unregister(struct parport *port) -{ - if (port->sysctl_table) { - struct parport_sysctl_table *t = port->sysctl_table; - port->sysctl_table = NULL; - unregister_sysctl_table(t->sysctl_header); - kfree(t); - } - return 0; -} - -int parport_device_proc_register(struct pardevice *device) -{ - struct parport_device_sysctl_table *t; - struct parport * port = device->port; - - t = kmalloc(sizeof(*t), GFP_KERNEL); - if (t == NULL) - return -ENOMEM; - memcpy(t, &parport_device_sysctl_template, sizeof(*t)); - - t->dev_dir[0].child = t->parport_dir; - t->parport_dir[0].child = t->port_dir; - t->port_dir[0].procname = port->name; - t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ - t->port_dir[0].child = t->devices_root_dir; - t->devices_root_dir[0].child = t->device_dir; - -#ifdef CONFIG_PARPORT_1284 - - t->device_dir[0].ctl_name = - parport_device_num(port->number, port->muxport, - device->daisy) - + 1; /* nb 0 isn't legal here */ - -#else /* No IEEE 1284 support */ - - /* parport_device_num isn't available. */ - t->device_dir[0].ctl_name = 1; - -#endif /* IEEE 1284 support or not */ - - t->device_dir[0].procname = device->name; - t->device_dir[0].extra1 = device; - t->device_dir[0].child = t->vars; - t->vars[0].data = &device->timeslice; - - t->sysctl_header = register_sysctl_table(t->dev_dir, 0); - if (t->sysctl_header == NULL) { - kfree(t); - t = NULL; - } - device->sysctl_table = t; - return 0; -} - -int parport_device_proc_unregister(struct pardevice *device) -{ - if (device->sysctl_table) { - struct parport_device_sysctl_table *t = device->sysctl_table; - device->sysctl_table = NULL; - unregister_sysctl_table(t->sysctl_header); - kfree(t); - } - return 0; -} - -int parport_default_proc_register(void) -{ - parport_default_sysctl_table.sysctl_header = - register_sysctl_table(parport_default_sysctl_table.dev_dir, 0); - return 0; -} - -int parport_default_proc_unregister(void) -{ - if (parport_default_sysctl_table.sysctl_header) { - unregister_sysctl_table(parport_default_sysctl_table. - sysctl_header); - parport_default_sysctl_table.sysctl_header = NULL; - } - return 0; -} - -#else /* no sysctl */ - -int parport_proc_register(struct parport *pp) -{ - return 0; -} - -int parport_proc_unregister(struct parport *pp) -{ - return 0; -} - -int parport_device_proc_register(struct pardevice *device) -{ - return 0; -} - -int parport_device_proc_unregister(struct pardevice *device) -{ - return 0; -} - -int parport_default_proc_register (void) -{ - return 0; -} - -int parport_default_proc_unregister (void) -{ - return 0; -} -#endif diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.3.11/linux/drivers/misc/parport_share.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/misc/parport_share.c Wed Dec 31 16:00:00 1969 @@ -1,602 +0,0 @@ -/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $ - * Parallel-port resource manager code. - * - * Authors: David Campbell - * Tim Waugh - * Jose Renau - * Philip Blundell - * Andrea Arcangeli - * - * based on work by Grant Guenther - * and Philip Blundell - */ - -#undef PARPORT_DEBUG_SHARING /* undef for production */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#undef PARPORT_PARANOID - -#define PARPORT_DEFAULT_TIMESLICE (HZ/5) - -unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE; -int parport_default_spintime = DEFAULT_SPIN_TIME; - -static struct parport *portlist = NULL, *portlist_tail = NULL; -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) -{ - struct parport_driver *drv; - - for (drv = driver_chain; drv; drv = drv->next) { - if (attach) - drv->attach (port); - else - drv->detach (port); - } -} - -int parport_register_driver (struct parport_driver *drv) -{ - struct parport *port; - - spin_lock (&driverlist_lock); - drv->next = driver_chain; - driver_chain = drv; - spin_unlock (&driverlist_lock); - - for (port = portlist; port; port = port->next) - drv->attach (port); - - return 0; -} - -void parport_unregister_driver (struct parport_driver *arg) -{ - struct parport_driver *drv = driver_chain, *olddrv = NULL; - - while (drv) { - if (drv == arg) { - spin_lock (&driverlist_lock); - if (olddrv) - olddrv->next = drv->next; - else - driver_chain = drv->next; - spin_unlock (&driverlist_lock); - return; - } - olddrv = drv; - drv = drv->next; - } -} - -/* Return a list of all the ports we know about. */ -struct parport *parport_enumerate(void) -{ - return portlist; -} - -struct parport *parport_register_port(unsigned long base, int irq, int dma, - struct parport_operations *ops) -{ - struct parport *tmp; - int portnum; - int device; - char *name; - - tmp = kmalloc(sizeof(struct parport), GFP_KERNEL); - if (!tmp) { - printk(KERN_WARNING "parport: memory squeeze\n"); - return NULL; - } - - /* Search for the lowest free parport number. */ - for (portnum = 0; ; portnum++) { - struct parport *itr = portlist; - while (itr) { - if (itr->number == portnum) - /* No good, already used. */ - break; - else - itr = itr->next; - } - - if (itr == NULL) - /* Got to the end of the list. */ - break; - } - - /* Init our structure */ - memset(tmp, 0, sizeof(struct parport)); - 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->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) { - printk(KERN_ERR "parport: memory squeeze\n"); - kfree(tmp); - return NULL; - } - sprintf(name, "parport%d", portnum); - tmp->name = name; - - /* - * Chain the entry to our list. - * - * This function must not run from an irq handler so we don' t need - * to clear irq on the local CPU. -arca - */ - spin_lock(&parportlist_lock); - if (portlist_tail) - portlist_tail->next = tmp; - portlist_tail = tmp; - if (!portlist) - portlist = tmp; - spin_unlock(&parportlist_lock); - - for (device = 0; device < 5; device++) - /* assume the worst */ - tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; - - tmp->waithead = tmp->waittail = NULL; - - return tmp; -} - -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); -} - -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) - portlist_tail = NULL; - } else { - for (p = portlist; (p != NULL) && (p->next != port); - p=p->next); - if (p) { - if ((p->next = port->next) == NULL) - portlist_tail = p; - } - else printk (KERN_WARNING - "%s not found in port list!\n", port->name); - } - spin_unlock(&parportlist_lock); - - 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); -} - -struct pardevice *parport_register_device(struct parport *port, const char *name, - int (*pf)(void *), void (*kf)(void *), - void (*irq_func)(int, void *, struct pt_regs *), - int flags, void *handle) -{ - struct pardevice *tmp; - - if (port->physport->flags & PARPORT_FLAG_EXCL) { - /* An exclusive device is registered. */ - printk (KERN_DEBUG "%s: no more devices allowed\n", - port->name); - return NULL; - } - - if (flags & PARPORT_DEV_LURK) { - if (!pf || !kf) { - printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name); - return NULL; - } - } - - tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); - if (tmp == NULL) { - printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); - return NULL; - } - - tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); - if (tmp->state == NULL) { - printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); - kfree(tmp); - return NULL; - } - - 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; - tmp->waiting = 0; - tmp->timeout = 5 * HZ; - - /* Chain this onto the list */ - tmp->prev = NULL; - /* - * 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->physport->pardevice_lock); - - if (flags & PARPORT_DEV_EXCL) { - if (port->physport->devices) { - spin_unlock (&port->physport->pardevice_lock); - kfree (tmp->state); - kfree (tmp); - printk (KERN_DEBUG - "%s: cannot grant exclusive access for " - "device %s\n", port->name, name); - return NULL; - } - port->flags |= PARPORT_FLAG_EXCL; - } - - 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(); - - init_waitqueue_head(&tmp->wait_q); - 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; -} - -void parport_unregister_device(struct pardevice *dev) -{ - struct parport *port; - -#ifdef PARPORT_PARANOID - if (dev == NULL) { - printk(KERN_ERR "parport_unregister_device: passed NULL\n"); - return; - } -#endif - - parport_device_proc_unregister(dev); - - port = dev->port->physport; - - if (port->cad == dev) { - printk(KERN_DEBUG "%s: %s forgot to release port\n", - port->name, dev->name); - parport_release (dev); - } - - spin_lock(&port->pardevice_lock); - if (dev->next) - dev->next->prev = dev->prev; - if (dev->prev) - dev->prev->next = dev->next; - else - port->devices = dev->next; - - if (dev->flags & PARPORT_DEV_EXCL) - port->flags &= ~PARPORT_FLAG_EXCL; - - spin_unlock(&port->pardevice_lock); - - kfree(dev->state); - kfree(dev); - - dec_parport_count(); - port->ops->dec_use_count(); -} - -int parport_claim(struct pardevice *dev) -{ - struct pardevice *oldcad; - 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); - return 0; - } - -try_again: - /* Preempt any current device */ - if ((oldcad = port->cad) != NULL) { - if (oldcad->preempt) { - if (oldcad->preempt(oldcad->private)) - goto blocked; - port->ops->save_state(port, dev->state); - } else - goto blocked; - - if (port->cad != oldcad) { - printk(KERN_WARNING - "%s: %s released port when preempted!\n", - port->name, oldcad->name); - if (port->cad) - goto blocked; - } - } - - /* Can't fail from now on, so mark ourselves as no longer waiting. */ - if (dev->waiting & 1) { - dev->waiting = 0; - - /* Take ourselves out of the wait list again. */ - spin_lock_irqsave (&port->waitlist_lock, flags); - if (dev->waitprev) - dev->waitprev->waitnext = dev->waitnext; - else - port->waithead = dev->waitnext; - if (dev->waitnext) - dev->waitnext->waitprev = dev->waitprev; - else - port->waittail = dev->waitprev; - spin_unlock_irqrestore (&port->waitlist_lock, flags); - dev->waitprev = dev->waitnext = NULL; - } - - /* 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; - return 0; - -blocked: - /* If this is the first time we tried to claim the port, register an - interest. This is only allowed for devices sleeping in - parport_claim_or_block(), or those with a wakeup function. */ - if (dev->waiting & 2 || dev->wakeup) { - spin_lock_irqsave (&port->waitlist_lock, flags); - if (port->cad == NULL) { - /* The port got released in the meantime. */ - spin_unlock_irqrestore (&port->waitlist_lock, flags); - goto try_again; - } - if (test_and_set_bit(0, &dev->waiting) == 0) { - /* First add ourselves to the end of the wait list. */ - dev->waitnext = NULL; - dev->waitprev = port->waittail; - if (port->waittail) { - port->waittail->waitnext = dev; - port->waittail = dev; - } else - port->waithead = port->waittail = dev; - } - spin_unlock_irqrestore (&port->waitlist_lock, flags); - } - return -EAGAIN; -} - -int parport_claim_or_block(struct pardevice *dev) -{ - int r; - - /* Signal to parport_claim() that we can wait even without a - wakeup function. */ - dev->waiting = 2; - - /* Try to claim the port. If this fails, we need to sleep. */ - r = parport_claim(dev); - if (r == -EAGAIN) { - unsigned long flags; -#ifdef PARPORT_DEBUG_SHARING - printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name); -#endif - save_flags (flags); - cli(); - /* If dev->waiting is clear now, an interrupt - gave us the port and we would deadlock if we slept. */ - if (dev->waiting) { - sleep_on(&dev->wait_q); - r = 1; - } else { - r = 0; -#ifdef PARPORT_DEBUG_SHARING - printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n", - dev->name); -#endif - } - restore_flags(flags); -#ifdef PARPORT_DEBUG_SHARING - 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; - return r; -} - -void parport_release(struct pardevice *dev) -{ - struct parport *port = dev->port->physport; - struct pardevice *pd; - unsigned long flags; - - /* Make sure that dev is the current device */ - if (port->cad != dev) { - printk(KERN_WARNING "%s: %s tried to release parport " - "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); - - /* Save control registers */ - port->ops->save_state(port, dev->state); - - /* If anybody is waiting, find out who's been there longest and - then wake them up. (Note: no locking required) */ - for (pd = port->waithead; pd; pd = pd->waitnext) { - if (pd->waiting & 2) { /* sleeping in claim_or_block */ - parport_claim(pd); - if (waitqueue_active(&pd->wait_q)) - wake_up(&pd->wait_q); - return; - } else if (pd->wakeup) { - pd->wakeup(pd->private); - if (dev->port->cad) - return; - } else { - printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name); - } - } - - /* Nobody was waiting, so walk the list to see if anyone is - interested in being woken up. */ - for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { - if (pd->wakeup && pd != dev) - pd->wakeup(pd->private); - } -} - -static int parport_parse_params (int nports, const char *str[], int val[], - int automatic, int none) -{ - unsigned int i; - for (i = 0; i < nports && str[i]; i++) { - if (!strncmp(str[i], "auto", 4)) - val[i] = automatic; - else if (!strncmp(str[i], "none", 4)) - val[i] = none; - else { - char *ep; - unsigned long r = simple_strtoul(str[i], &ep, 0); - if (ep != str[i]) - val[i] = r; - else { - printk("parport: bad specifier `%s'\n", str[i]); - return -1; - } - } - } - - return 0; -} - -int parport_parse_irqs(int nports, const char *irqstr[], int irqval[]) -{ - return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO, - PARPORT_IRQ_NONE); -} - -int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[]) -{ - return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO, - PARPORT_DMA_NONE); -} diff -u --recursive --new-file v2.3.11/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.3.11/linux/drivers/net/hamradio/baycom_epp.c Fri Mar 26 13:57:41 1999 +++ linux/drivers/net/hamradio/baycom_epp.c Mon Jul 26 14:11:37 1999 @@ -3,7 +3,7 @@ /* * baycom_epp.c -- baycom epp radio modem driver. * - * Copyright (C) 1998 + * Copyright (C) 1998-1999 * Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ * 0.2 21.04.98 Massive rework by Thomas Sailer * Integrated FPGA EPP modem configuration routines * 0.3 11.05.98 Took FPGA config out and moved it into a separate program + * 0.4 26.07.99 Adapted to new lowlevel parport driver interface * */ @@ -148,7 +149,7 @@ static const char bc_drvname[] = "baycom_epp"; static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "baycom_epp: version 0.3 compiled " __TIME__ " " __DATE__ "\n"; +KERN_INFO "baycom_epp: version 0.4 compiled " __TIME__ " " __DATE__ "\n"; /* --------------------------------------------------------------------- */ @@ -264,7 +265,8 @@ struct { unsigned int intclk; - unsigned int divider; + unsigned int fclk; + unsigned int bps; unsigned int extmodem; unsigned int loopback; } cfg; @@ -433,7 +435,7 @@ * eppconfig_path should be setable via /proc/sys. */ -char eppconfig_path[256] = "/sbin/eppfpga"; +char eppconfig_path[256] = "/usr/sbin/eppfpga"; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; @@ -448,9 +450,10 @@ int i; /* set up arguments */ - sprintf(modearg, "%sclk,%smodem,divider=%d%s,extstat", + sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", bc->cfg.intclk ? "int" : "ext", - bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider, + bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, + (bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps), bc->cfg.loopback ? ",loopback" : ""); sprintf(portarg, "%ld", bc->pdev->port->base); printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); @@ -655,10 +658,11 @@ /* ---------------------------------------------------------------------- */ -static void transmit(struct baycom_state *bc, int cnt, unsigned char stat) +static int transmit(struct baycom_state *bc, int cnt, unsigned char stat) { struct parport *pp = bc->pdev->port; - int i; + unsigned char tmp[128]; + int i, j; if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT)) bc->hdlctx.state = tx_idle; @@ -666,17 +670,17 @@ if (bc->hdlctx.bufcnt <= 0) encode_hdlc(bc); if (bc->hdlctx.bufcnt <= 0) - return; + return 0; if (!bc->ch_params.fulldup) { if (!(stat & EPP_DCDBIT)) { bc->hdlctx.slotcnt = bc->ch_params.slottime; - return; + return 0; } if ((--bc->hdlctx.slotcnt) > 0) - return; + return 0; bc->hdlctx.slotcnt = bc->ch_params.slottime; if ((random_num() % 256) > bc->ch_params.ppersist) - return; + return 0; } } if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) { @@ -692,8 +696,13 @@ bc->hdlctx.flags -= i; if (bc->hdlctx.flags <= 0) bc->hdlctx.state = tx_data; - for (; i > 0; i--) - parport_epp_write_data(pp, 0x7e); + memset(tmp, 0x7e, sizeof(tmp)); + while (i > 0) { + j = (i > sizeof(tmp)) ? sizeof(tmp) : i; + if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) + return -1; + i -= j; + } break; case tx_data: @@ -708,8 +717,9 @@ i = min(cnt, bc->hdlctx.bufcnt); bc->hdlctx.bufcnt -= i; cnt -= i; - for (; i > 0; i--) - parport_epp_write_data(pp, *(bc->hdlctx.bufptr)++); + if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0)) + return -1; + bc->hdlctx.bufptr += i; break; case tx_tail: @@ -722,22 +732,33 @@ if (i) { cnt -= i; bc->hdlctx.flags -= i; - for (; i > 0; i--) - parport_epp_write_data(pp, 0x7e); + memset(tmp, 0x7e, sizeof(tmp)); + while (i > 0) { + j = (i > sizeof(tmp)) ? sizeof(tmp) : i; + if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) + return -1; + i -= j; + } break; } default: /* fall through */ if (bc->hdlctx.calibrate <= 0) - return; + return 0; i = min(cnt, bc->hdlctx.calibrate); cnt -= i; bc->hdlctx.calibrate -= i; - for (; i > 0; i--) - parport_epp_write_data(pp, 0); + memset(tmp, 0, sizeof(tmp)); + while (i > 0) { + j = (i > sizeof(tmp)) ? sizeof(tmp) : i; + if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) + return -1; + i -= j; + } break; } } + return 0; } /* ---------------------------------------------------------------------- */ @@ -800,57 +821,68 @@ goto enditer##j; \ }) -static void receive(struct device *dev, int cnt) +static int receive(struct device *dev, int cnt) { struct baycom_state *bc = (struct baycom_state *)dev->priv; struct parport *pp = bc->pdev->port; unsigned int bitbuf, notbitstream, bitstream, numbits, state; - unsigned char ch; + unsigned char tmp[128]; + unsigned char *cp; + int cnt2, ret = 0; numbits = bc->hdlcrx.numbits; state = bc->hdlcrx.state; bitstream = bc->hdlcrx.bitstream; bitbuf = bc->hdlcrx.bitbuf; - for (; cnt > 0; cnt--) { - ch = parport_epp_read_data(pp); - bitstream >>= 8; - bitstream |= ch << 8; - bitbuf >>= 8; - bitbuf |= ch << 8; - numbits += 8; - notbitstream = ~bitstream; - DECODEITERA(0); - DECODEITERA(1); - DECODEITERA(2); - DECODEITERA(3); - DECODEITERA(4); - DECODEITERA(5); - DECODEITERA(6); - DECODEITERA(7); - goto enddec; - DECODEITERB(0); - DECODEITERB(1); - DECODEITERB(2); - DECODEITERB(3); - DECODEITERB(4); - DECODEITERB(5); - DECODEITERB(6); - DECODEITERB(7); - enddec: - while (state && numbits >= 8) { - if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { - state = 0; - } else { - *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits); - bc->hdlcrx.bufcnt++; - numbits -= 8; + while (cnt > 0) { + cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt; + cnt -= cnt2; + if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) { + ret = -1; + break; + } + cp = tmp; + for (; cnt2 > 0; cnt2--, cp++) { + bitstream >>= 8; + bitstream |= (*cp) << 8; + bitbuf >>= 8; + bitbuf |= (*cp) << 8; + numbits += 8; + notbitstream = ~bitstream; + DECODEITERA(0); + DECODEITERA(1); + DECODEITERA(2); + DECODEITERA(3); + DECODEITERA(4); + DECODEITERA(5); + DECODEITERA(6); + DECODEITERA(7); + goto enddec; + DECODEITERB(0); + DECODEITERB(1); + DECODEITERB(2); + DECODEITERB(3); + DECODEITERB(4); + DECODEITERB(5); + DECODEITERB(6); + DECODEITERB(7); + enddec: + while (state && numbits >= 8) { + if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { + state = 0; + } else { + *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits); + bc->hdlcrx.bufcnt++; + numbits -= 8; + } } } - } + } bc->hdlcrx.numbits = numbits; bc->hdlcrx.state = state; bc->hdlcrx.bitstream = bitstream; bc->hdlcrx.bitbuf = bitbuf; + return ret; } /* --------------------------------------------------------------------- */ @@ -870,6 +902,7 @@ struct baycom_state *bc; struct parport *pp; unsigned char stat; + unsigned char tmp[2]; unsigned int time1 = 0, time2 = 0, time3 = 0; int cnt, cnt2; @@ -880,26 +913,40 @@ baycom_int_freq(bc); pp = bc->pdev->port; /* update status */ - bc->stat = stat = parport_epp_read_addr(pp); + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) + goto epptimeout; + bc->stat = stat; bc->debug_vals.last_pllcorr = stat; GETTICK(time1); if (bc->modem == EPP_FPGAEXTSTATUS) { /* get input count */ - parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1); - cnt = parport_epp_read_addr(pp); - cnt |= parport_epp_read_addr(pp) << 8; + tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1; + if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) + goto epptimeout; + if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) + goto epptimeout; + cnt = tmp[0] | (tmp[1] << 8); cnt &= 0x7fff; /* get output count */ - parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2); - cnt2 = parport_epp_read_addr(pp); - cnt2 |= parport_epp_read_addr(pp) << 8; + tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2; + if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) + goto epptimeout; + if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) + goto epptimeout; + cnt2 = tmp[0] | (tmp[1] << 8); cnt2 = 16384 - (cnt2 & 0x7fff); /* return to normal */ - parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE); - transmit(bc, cnt2, stat); + tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; + if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) + goto epptimeout; + if (transmit(bc, cnt2, stat)) + goto epptimeout; GETTICK(time2); - receive(dev, cnt); - bc->stat = stat = parport_epp_read_addr(pp); + if (receive(dev, cnt)) + goto epptimeout; + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) + goto epptimeout; + bc->stat = stat; } else { /* try to tx */ switch (stat & (EPP_NTAEF|EPP_NTHF)) { @@ -919,7 +966,8 @@ cnt = 2048 - 1025; break; } - transmit(bc, cnt, stat); + if (transmit(bc, cnt, stat)) + goto epptimeout; GETTICK(time2); /* do receiver */ while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) { @@ -936,9 +984,9 @@ cnt = 256; break; } - receive(dev, cnt); - stat = parport_epp_read_addr(pp); - if (parport_epp_check_timeout(pp)) + if (receive(dev, cnt)) + goto epptimeout; + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) goto epptimeout; } cnt = 0; @@ -947,9 +995,11 @@ else if (bc->bitrate < 100000) cnt = 128; while (cnt > 0 && stat & EPP_NREF) { - receive(dev, 1); + if (receive(dev, 1)) + goto epptimeout; cnt--; - stat = parport_epp_read_addr(pp); + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) + goto epptimeout; } } GETTICK(time3); @@ -957,8 +1007,6 @@ bc->debug_vals.mod_cycles = time2 - time1; bc->debug_vals.demod_cycles = time3 - time2; #endif /* BAYCOM_DEBUG */ - if (parport_epp_check_timeout(pp)) - goto epptimeout; queue_task(&bc->run_bh, &tq_timer); return; epptimeout: @@ -1040,6 +1088,7 @@ 0, 0, (void *)(void *)epp_bh, dev }; unsigned int i, j; + unsigned char tmp[128]; unsigned char stat; unsigned long tstart; @@ -1071,8 +1120,8 @@ parport_unregister_device(bc->pdev); return -EBUSY; } - if (!(pp->modes & (PARPORT_MODE_PCECPEPP|PARPORT_MODE_PCEPP))) { - printk(KERN_ERR "%s: parport at 0x%lx does not support any EPP mode\n", + if (!(pp->modes & PARPORT_MODE_TRISTATE)) { + printk(KERN_ERR "%s: parport at 0x%lx does not support bidirectional data transfer\n", bc_drvname, pp->base); parport_release(bc->pdev); parport_unregister_device(bc->pdev); @@ -1081,11 +1130,6 @@ dev->irq = /*pp->irq*/ 0; bc->run_bh = run_bh; bc->bh_running = 1; - if (pp->modes & PARPORT_MODE_PCECPEPP) { - printk(KERN_INFO "%s: trying to enable EPP mode\n", bc_drvname); - parport_frob_econtrol(pp, 0xe0, 0x80); - } - /* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCEPP); not yet implemented */ bc->modem = EPP_CONVENTIONAL; if (eppconfig(bc)) printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname); @@ -1093,26 +1137,33 @@ bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS; parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */ /* reset the modem */ - parport_epp_write_addr(pp, 0); - parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE); + tmp[0] = 0; + tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; + if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2) + goto epptimeout; /* autoprobe baud rate */ tstart = jiffies; i = 0; while ((signed)(jiffies-tstart-HZ/3) < 0) { - stat = parport_epp_read_addr(pp); + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) + goto epptimeout; if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) { schedule(); continue; } - for (j = 0; j < 256; j++) - parport_epp_read_data(pp); + if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) + goto epptimeout; + if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) + goto epptimeout; i += 256; } for (j = 0; j < 256; j++) { - stat = parport_epp_read_addr(pp); + if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) + goto epptimeout; if (!(stat & EPP_NREF)) break; - parport_epp_read_data(pp); + if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1) + goto epptimeout; i++; } tstart = jiffies - tstart; @@ -1125,7 +1176,9 @@ } printk(KERN_INFO "%s: autoprobed bitrate: %d int divider: %d int rate: %d\n", bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2)); - parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/); + tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/; + if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) + goto epptimeout; /* * initialise hdlc variables */ @@ -1143,12 +1196,12 @@ MOD_INC_USE_COUNT; return 0; -#if 0 - errreturn: + epptimeout: + printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname); + parport_write_control(pp, 0); /* reset the adapter */ parport_release(bc->pdev); parport_unregister_device(bc->pdev); return -EIO; -#endif } /* --------------------------------------------------------------------- */ @@ -1158,6 +1211,7 @@ struct baycom_state *bc; struct parport *pp; struct sk_buff *skb; + unsigned char tmp[1]; baycom_paranoia_check(dev, "epp_close", -EINVAL); if (!dev->start) @@ -1169,7 +1223,8 @@ dev->tbusy = 1; run_task_queue(&tq_timer); /* dequeue bottom half */ bc->stat = EPP_DCDBIT; - parport_epp_write_addr(pp, 0); + tmp[0] = 0; + pp->ops->epp_write_addr(pp, tmp, 1, 0); parport_write_control(pp, 0); /* reset the adapter */ parport_release(bc->pdev); parport_unregister_device(bc->pdev); @@ -1200,12 +1255,19 @@ bc->cfg.loopback = 0; if (strstr(modestr,"loopback")) bc->cfg.loopback = 1; - if ((cp = strstr(modestr,"divider="))) { - bc->cfg.divider = simple_strtoul(cp+8, NULL, 0); - if (bc->cfg.divider < 1) - bc->cfg.divider = 1; - if (bc->cfg.divider > 1023) - bc->cfg.divider = 1023; + if ((cp = strstr(modestr,"fclk="))) { + bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0); + if (bc->cfg.fclk < 1000000) + bc->cfg.fclk = 1000000; + if (bc->cfg.fclk > 25000000) + bc->cfg.fclk = 25000000; + } + if ((cp = strstr(modestr,"bps="))) { + bc->cfg.bps = simple_strtoul(cp+4, NULL, 0); + if (bc->cfg.bps < 1000) + bc->cfg.bps = 1000; + if (bc->cfg.bps > 1500000) + bc->cfg.bps = 1500000; } return 0; } @@ -1316,9 +1378,9 @@ break; case HDLCDRVCTL_GETMODE: - sprintf(hi.data.modename, "%sclk,%smodem,divider=%d%s", + sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s", bc->cfg.intclk ? "int" : "ext", - bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider, + bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, bc->cfg.loopback ? ",loopback" : ""); break; @@ -1441,6 +1503,8 @@ memset(bc, 0, sizeof(struct baycom_state)); bc->magic = BAYCOM_MAGIC; sprintf(bc->ifname, "bce%d", i); + bc->cfg.fclk = 19666600; + bc->cfg.bps = 9600; /* * initialize part of the device struct */ diff -u --recursive --new-file v2.3.11/linux/drivers/parport/BUGS-parport linux/drivers/parport/BUGS-parport --- v2.3.11/linux/drivers/parport/BUGS-parport Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/BUGS-parport Thu Jun 3 16:21:47 1999 @@ -0,0 +1,5 @@ +Currently known (or at least suspected) bugs in parport: + +o lp doesn't allow you to read status while printing is in progress. + +See . diff -u --recursive --new-file v2.3.11/linux/drivers/parport/Config.in linux/drivers/parport/Config.in --- v2.3.11/linux/drivers/parport/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/Config.in Thu Jul 1 14:22:57 1999 @@ -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 -u --recursive --new-file v2.3.11/linux/drivers/parport/Makefile linux/drivers/parport/Makefile --- v2.3.11/linux/drivers/parport/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/Makefile Tue Jul 27 13:55:52 1999 @@ -0,0 +1,94 @@ +# +# Makefile for the kernel miscellaneous drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# +# Note 3! Parport 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) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := parport.a +MX_OBJS := +LX_OBJS := +MI_OBJS := +MIX_OBJS := + +ifeq ($(CONFIG_PARPORT),y) + L_OBJS += share.o ieee1284.o ieee1284_ops.o procfs.o + + ifeq ($(CONFIG_PARPORT_1284),y) + L_OBJS += daisy.o probe.o + endif + + ifeq ($(CONFIG_PARPORT_PC),y) + LX_OBJS += parport_pc.o + else + ifeq ($(CONFIG_PARPORT_PC),m) + M_OBJS += parport_pc.o + endif + endif + ifeq ($(CONFIG_PARPORT_AMIGA),y) + LX_OBJS += parport_amiga.o + else + ifeq ($(CONFIG_PARPORT_AMIGA),m) + M_OBJS += parport_amiga.o + endif + endif + ifeq ($(CONFIG_PARPORT_MFC3),y) + LX_OBJS += parport_mfc3.o + else + ifeq ($(CONFIG_PARPORT_MFC3),m) + M_OBJS += parport_mfc3.o + endif + endif + ifeq ($(CONFIG_PARPORT_ATARI),y) + LX_OBJS += parport_atari.o + else + ifeq ($(CONFIG_PARPORT_ATARI),m) + M_OBJS += parport_atari.o + endif + endif + LX_OBJS += init.o +else + ifeq ($(CONFIG_PARPORT),m) + MI_OBJS += share.o ieee1284.o ieee1284_ops.o + ifeq ($(CONFIG_PARPORT_1284),y) + MI_OBJS += daisy.o probe.o + endif + ifneq ($(CONFIG_PROC_FS),n) + MI_OBJS += procfs.o + endif + MIX_OBJS += init.o + M_OBJS += parport.o + endif + ifeq ($(CONFIG_PARPORT_PC),m) + M_OBJS += parport_pc.o + endif + ifeq ($(CONFIG_PARPORT_AX),m) + M_OBJS += parport_ax.o + endif + ifeq ($(CONFIG_PARPORT_AMIGA),m) + M_OBJS += parport_amiga.o + endif + ifeq ($(CONFIG_PARPORT_MFC3),m) + M_OBJS += parport_mfc3.o + endif + ifeq ($(CONFIG_PARPORT_ATARI),m) + M_OBJS += parport_atari.o + endif +endif + +include $(TOPDIR)/Rules.make + +# Special rule to build the composite parport.o module +parport.o: $(MI_OBJS) $(MIX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) diff -u --recursive --new-file v2.3.11/linux/drivers/parport/TODO-parport linux/drivers/parport/TODO-parport --- v2.3.11/linux/drivers/parport/TODO-parport Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/TODO-parport Thu Jun 3 16:21:47 1999 @@ -0,0 +1,20 @@ +Things to be done. + +0. Fix the bugs (see BUGS-parport). + +1. Proper documentation. + +2. A better lp.c: + + a) ECP support would be nice. This can only work if both the port and + the printer support it. + + b) Handle status readback automatically. IEEE1284 printers can post status + bits when they have something to say. We should read out and deal + with (maybe just log) whatever the printer wants to tell the world. + +3. Support more hardware (eg m68k, Sun bpp). + +4. A better PLIP (make use of bidirectional/ECP/EPP ports). + +See . diff -u --recursive --new-file v2.3.11/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c --- v2.3.11/linux/drivers/parport/daisy.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/daisy.c Sat Jul 3 10:45:04 1999 @@ -0,0 +1,473 @@ +/* + * 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 + +#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 -u --recursive --new-file v2.3.11/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c --- v2.3.11/linux/drivers/parport/ieee1284.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/ieee1284.c Wed Jul 21 15:38:39 1999 @@ -0,0 +1,545 @@ +/* $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 + +#undef 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 & ~IEEE1284_ADDR; + unsigned char xflag; + + port = port->physport; + + /* Is there anything to do? */ + if (port->ieee1284.mode == mode) + return 0; + + /* Is the difference just an address-or-not bit? */ + if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){ + 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; + int addr = mode & IEEE1284_ADDR; + size_t (*fn) (struct parport *, const void *, size_t, int); + + /* Ignore the device-ID-request bit and the address bit. */ + mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); + + /* 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); + if (addr) + fn = port->ops->epp_write_addr; + else + 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); + if (addr) + fn = port->ops->ecp_write_addr; + else + 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! */ + if (addr) + fn = parport_ieee1284_ecp_write_addr; + else + 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; + int addr = mode & IEEE1284_ADDR; + size_t (*fn) (struct parport *, void *, size_t, int); + + /* Ignore the device-ID-request bit and the address bit. */ + mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); + + /* 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); + if (addr) + fn = port->ops->epp_read_addr; + else + 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 -u --recursive --new-file v2.3.11/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c --- v2.3.11/linux/drivers/parport/ieee1284_ops.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/ieee1284_ops.c Tue Jul 6 19:08:33 1999 @@ -0,0 +1,848 @@ +/* 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) +{ + /* This is untested */ + unsigned char *bp = (unsigned char *) buffer; + size_t ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT); + port->ops->data_forward (port); + for (; len > 0; len--, bp++) { + parport_write_data (port, *bp); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + /* Strobe data */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + ret++; + } + + return ret; +} + +/* EPP mode, reverse channel, data. */ +size_t parport_ieee1284_epp_read_data (struct parport *port, + void *buffer, size_t len, + int flags) +{ + /* This is untested. */ + unsigned char *bp = (unsigned char *) buffer; + unsigned ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT, 0); + port->ops->data_reverse (port); + for (; len > 0; len--, bp++) { + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + *bp = parport_read_data (port); + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + ret++; + } + port->ops->data_forward (port); + + return ret; +} + +/* EPP mode, forward channel, addresses. */ +size_t parport_ieee1284_epp_write_addr (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + /* This is untested */ + unsigned char *bp = (unsigned char *) buffer; + size_t ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT); + port->ops->data_forward (port); + for (; len > 0; len--, bp++) { + parport_write_data (port, *bp); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + /* Strobe data */ + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + ret++; + } + + return ret; +} + +/* EPP mode, reverse channel, addresses. */ +size_t parport_ieee1284_epp_read_addr (struct parport *port, + void *buffer, size_t len, + int flags) +{ + /* This is untested. */ + unsigned char *bp = (unsigned char *) buffer; + unsigned ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD, 0); + port->ops->data_reverse (port); + for (; len > 0; len--, bp++) { + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + *bp = parport_read_data (port); + + parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + ret++; + } + port->ops->data_forward (port); + + return ret; +} diff -u --recursive --new-file v2.3.11/linux/drivers/parport/init.c linux/drivers/parport/init.c --- v2.3.11/linux/drivers/parport/init.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/init.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,206 @@ +/* Parallel-port initialisation code. + * + * Authors: David Campbell + * Tim Waugh + * Jose Renau + * + * based on work by Grant Guenther + * and Philip Blundell + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef MODULE +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_NONE }; + +extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); + +static int parport_setup_ptr __initdata = 0; + +__initfunc(void parport_setup(char *str, int *ints)) +{ + if (ints[0] == 0) { + if (str && !strncmp(str, "auto", 4)) { + irq[0] = PARPORT_IRQ_AUTO; + dma[0] = PARPORT_DMA_AUTO; + } + else if (str) + printk (KERN_ERR "parport: `%s': huh?\n", str); + else + printk (KERN_ERR "parport: parport=.. what?\n"); + + return; + } + else if (ints[1] == 0) { + /* Disable parport if "parport=0" in cmdline */ + io[0] = PARPORT_DISABLE; + return; + } + + if (parport_setup_ptr < PARPORT_MAX) { + char *sep; + io[parport_setup_ptr] = ints[1]; + irq[parport_setup_ptr] = PARPORT_IRQ_NONE; + dma[parport_setup_ptr] = PARPORT_DMA_NONE; + if (ints[0] > 1) { + irq[parport_setup_ptr] = ints[2]; + if (ints[0] > 2) { + dma[parport_setup_ptr] = ints[3]; + goto done; + } + + if (str == NULL) + goto done; + + goto dma_from_str; + } + else if (str == NULL) + goto done; + else if (!strncmp(str, "auto", 4)) + irq[parport_setup_ptr] = PARPORT_IRQ_AUTO; + else if (strncmp(str, "none", 4) != 0) { + printk(KERN_ERR "parport: bad irq `%s'\n", str); + return; + } + + if ((sep = strchr(str, ',')) == NULL) goto done; + str = sep+1; + dma_from_str: + if (!strncmp(str, "auto", 4)) + dma[parport_setup_ptr] = PARPORT_DMA_AUTO; + else if (strncmp(str, "none", 4) != 0) { + char *ep; + dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0); + if (ep == str) { + printk(KERN_ERR "parport: bad dma `%s'\n", + str); + return; + } + } + done: + parport_setup_ptr++; + } else + printk(KERN_ERR "parport=%s ignored, too many ports\n", str); +} +#endif + +#ifdef MODULE +int init_module(void) +{ +#ifdef CONFIG_SYSCTL + parport_default_proc_register (); +#endif + return 0; +} + +void cleanup_module(void) +{ +#ifdef CONFIG_SYSCTL + parport_default_proc_unregister (); +#endif +} + +#else + +__initfunc(int parport_init(void)) +{ + if (io[0] == PARPORT_DISABLE) + return 1; + +#ifdef CONFIG_SYSCTL + parport_default_proc_register (); +#endif + +#ifdef CONFIG_PARPORT_PC + parport_pc_init(io, io_hi, irq, dma); +#endif +#ifdef CONFIG_PARPORT_AMIGA + parport_amiga_init(); +#endif +#ifdef CONFIG_PARPORT_MFC3 + parport_mfc3_init(); +#endif +#ifdef CONFIG_PARPORT_ATARI + parport_atari_init(); +#endif +#ifdef CONFIG_PARPORT_ARC + parport_arc_init(); +#endif + return 0; +} +#endif + +/* Exported symbols for modules. */ + +EXPORT_SYMBOL(parport_claim); +EXPORT_SYMBOL(parport_claim_or_block); +EXPORT_SYMBOL(parport_release); +EXPORT_SYMBOL(parport_register_port); +EXPORT_SYMBOL(parport_announce_port); +EXPORT_SYMBOL(parport_unregister_port); +EXPORT_SYMBOL(parport_register_driver); +EXPORT_SYMBOL(parport_unregister_driver); +EXPORT_SYMBOL(parport_register_device); +EXPORT_SYMBOL(parport_unregister_device); +EXPORT_SYMBOL(parport_enumerate); +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_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_1284 +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) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +void dec_parport_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} diff -u --recursive --new-file v2.3.11/linux/drivers/parport/multiface.h linux/drivers/parport/multiface.h --- v2.3.11/linux/drivers/parport/multiface.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/multiface.h Tue May 11 09:55:49 1999 @@ -0,0 +1,20 @@ +#ifndef _MULTIFACE_H_ +#define _MULTIFACE_H_ + +/* + * Defines for SerialMaster, Multiface Card II and Multiface Card III + * The addresses given below are offsets to the board base address + * + * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de) + * + */ + +#define PIA_REG_PADWIDTH 255 + +#define DUARTBASE 0x0000 +#define PITBASE 0x0100 +#define ROMBASE 0x0200 +#define PIABASE 0x4000 + +#endif + diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c --- v2.3.11/linux/drivers/parport/parport_amiga.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_amiga.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,295 @@ +/* Low-level parallel port routines for the Amiga buildin port + * + * Author: Joerg Dorchain + * + * This is a complete rewrite of the code, but based heaviy upon the old + * lp_intern. code. + * + * The built-in Amiga parallel port provides one port at a fixed address + * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status + * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in + * hardware when the data register is accessed), and 1 input control line + * /ACK, able to cause an interrupt, but both not directly settable by + * software. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK() {return 0;} +#endif + +static struct parport *this_port = NULL; + +static void amiga_write_data(struct parport *p, unsigned char data) +{ +DPRINTK("write_data %c\n",data); + /* Triggers also /STROBE. This behavior cannot be changed */ + ciaa.prb = data; +} + +static unsigned char amiga_read_data(struct parport *p) +{ + /* Triggers also /STROBE. This behavior cannot be changed */ + return ciaa.prb; +} + +#if 0 +static unsigned char control_pc_to_amiga(unsigned char control) +{ + unsigned char ret = 0; + + if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ + ; + if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ + ; + if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ + ; + if (control & PARPORT_CONTROL_INIT) /* INITP */ + /* reset connected to cpu reset pin */; + if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ + /* Not connected */; + if (control & PARPORT_CONTROL_STROBE) /* Strobe */ + /* Handled only directly by hardware */; + return ret; +} +#endif + +static unsigned char control_amiga_to_pc(unsigned char control) +{ + return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE; + /* fake value: interrupt enable, select in, no reset, + no autolf, no strobe - seems to be closest the wiring diagram */ +} + +static void amiga_write_control(struct parport *p, unsigned char control) +{ +DPRINTK("write_control %02x\n",control); + /* No implementation possible */ +} + +static unsigned char amiga_read_control( struct parport *p) +{ +DPRINTK("read_control \n"); + return control_amiga_to_pc(0); +} + +static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val) +{ + unsigned char old; + +DPRINTK("frob_control mask %02x, value %02x\n",mask,val); + old = amiga_read_control(p); + amiga_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char status_pc_to_amiga(unsigned char status) +{ + unsigned char ret = 1; + + if (status & PARPORT_STATUS_BUSY) /* Busy */ + ret &= ~1; + if (status & PARPORT_STATUS_ACK) /* Ack */ + /* handled in hardware */; + if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ + ret |= 2; + if (status & PARPORT_STATUS_SELECT) /* select */ + ret |= 4; + if (status & PARPORT_STATUS_ERROR) /* error */ + /* not connected */; + return ret; +} + +static unsigned char status_amiga_to_pc(unsigned char status) +{ + unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR; + + if (status & 1) /* Busy */ + ret &= ~PARPORT_STATUS_BUSY; + if (status & 2) /* PaperOut */ + ret |= PARPORT_STATUS_PAPEROUT; + if (status & 4) /* Selected */ + ret |= PARPORT_STATUS_SELECT; + /* the rest is not connected or handled autonomously in hardware */ + + return ret; +} + +static void amiga_write_status( struct parport *p, unsigned char status) +{ +DPRINTK("write_status %02x\n",status); + ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status); +} + +static unsigned char amiga_read_status(struct parport *p) +{ + unsigned char status; + + status = status_amiga_to_pc(ciab.pra & 7); +DPRINTK("read_status %02x\n", status); + return status; +} + +static void amiga_change_mode( struct parport *p, int m) +{ + /* XXX: This port only has one mode, and I am + not sure about the corresponding PC-style mode*/ +} + +/* as this ports irq handling is already done, we use a generic funktion */ +static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + + +static void amiga_init_state(struct parport_state *s) +{ + s->u.amiga.data = 0; + s->u.amiga.datadir = 255; + s->u.amiga.status = 0; + s->u.amiga.statusdir = 0; +} + +static void amiga_save_state(struct parport *p, struct parport_state *s) +{ + s->u.amiga.data = ciaa.prb; + s->u.amiga.datadir = ciaa.ddrb; + s->u.amiga.status = ciab.pra & 7; + s->u.amiga.statusdir = ciab.ddra & 7; +} + +static void amiga_restore_state(struct parport *p, struct parport_state *s) +{ + ciaa.prb = s->u.amiga.data; + ciaa.ddrb = s->u.amiga.datadir; + ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status; + ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir; +} + +static void amiga_enable_irq(struct parport *p) +{ + enable_irq(IRQ_AMIGA_CIAA_FLG); +} + +static void amiga_disable_irq(struct parport *p) +{ + disable_irq(IRQ_AMIGA_CIAA_FLG); +} + +static void amiga_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void amiga_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static struct parport_operations pp_amiga_ops = { + amiga_write_data, + amiga_read_data, + + amiga_write_control, + amiga_read_control, + amiga_frob_control, + + amiga_read_status, + + amiga_enable_irq, + amiga_disable_irq, + + NULL, /* data_forward */ + NULL, /* data_reverse */ + + amiga_interrupt, + + amiga_init_state, + amiga_save_state, + amiga_restore_state, + + amiga_inc_use_count, + amiga_dec_use_count, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, /* impossible? */ + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, /* impossible? */ + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, /* impossible? */ + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, /* FIXME - need to write amiga one */ + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, /* impossible? */ +}; + +/* ----------- Initialisation code --------------------------------- */ + +__initfunc(int parport_amiga_init(void)) +{ + struct parport *p; + + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) { + ciaa.ddrb = 0xff; + ciab.ddra &= 0xf8; + if (!(p = parport_register_port((unsigned long)&ciaa.prb, + IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE, + &pp_amiga_ops))) + return 0; + this_port = p; + printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name); + /* XXX: set operating mode */ + parport_proc_register(p); + if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, + p->name, p)) { + parport_unregister_port (p); + return 0; + } + + if (parport_probe_hook) + (*parport_probe_hook)(p); + + parport_announce_port (p); + + return 1; + + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Joerg Dorchain"); +MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port"); +MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port"); + +int init_module(void) +{ + return ! parport_amiga_init(); +} + +void cleanup_module(void) +{ + if (p->irq != PARPORT_IRQ_NONE) + free_irq(IRQ_AMIGA_CIAA_FLG, p); + parport_proc_unregister(this_port); + parport_unregister_port(this_port); +} +#endif + + diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_arc.c linux/drivers/parport/parport_arc.c --- v2.3.11/linux/drivers/parport/parport_arc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_arc.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,149 @@ +/* Low-level parallel port routines for Archimedes onboard hardware + * + * Author: Phil Blundell + */ + +/* This driver is for the parallel port hardware found on Acorn's old + * range of Archimedes machines. The A5000 and newer systems have PC-style + * I/O hardware and should use the parport_pc driver instead. + * + * The Acorn printer port hardware is very simple. There is a single 8-bit + * write-only latch for the data port and control/status bits are handled + * with various auxilliary input and output lines. The port is not + * bidirectional, does not support any modes other than SPP, and has only + * a subset of the standard printer control lines connected. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DATA_ADDRESS 0x3350010 + +/* This is equivalent to the above and only used for request_region. */ +#define PORT_BASE 0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2) + +/* The hardware can't read from the data latch, so we must use a soft + copy. */ +static unsigned char data_copy; + +/* These are pretty simple. We know the irq is never shared and the + kernel does all the magic that's required. */ +static void arc_enable_irq(struct parport *p) +{ + enable_irq(p->irq); +} + +static void arc_disable_irq(struct parport *p) +{ + disable_irq(p->irq); +} + +static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + +static void arc_write_data(struct parport *p, unsigned char data) +{ + data_copy = data; + outb_t(data, DATA_LATCH); +} + +static unsigned char arc_read_data(struct parport *p) +{ + return data_copy; +} + +static void arc_inc_use_count(void) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void arc_dec_use_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations parport_arc_ops = +{ + arc_write_data, + arc_read_data, + + arc_write_control, + arc_read_control, + arc_frob_control, + + arc_read_status, + + arc_enable_irq, + arc_disable_irq, + + arc_data_forward, + arc_data_reverse, + + arc_interrupt, + + arc_init_state, + arc_save_state, + arc_restore_state, + + arc_inc_use_count, + arc_dec_use_count, + + 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 -------------------------------- */ + +int parport_arc_init(void) +{ + /* Archimedes hardware provides only one port, at a fixed address */ + struct parport *p; + + if (check_region(PORT_BASE, 1)) + return 0; + + p = parport_register_port (PORT_BASE, IRQ_PRINTERACK, + PARPORT_DMA_NONE, &parport_arc_ops); + + if (!p) + return 0; + + p->modes = PARPORT_MODE_ARCSPP; + p->size = 1; + + printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n", + p->irq); + parport_proc_register(p); + + /* Tell the high-level drivers about the port. */ + parport_announce_port (p); + + return 1; +} diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_atari.c linux/drivers/parport/parport_atari.c --- v2.3.11/linux/drivers/parport/parport_atari.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_atari.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,229 @@ +/* Low-level parallel port routines for the Atari builtin port + * + * Author: Andreas Schwab + * + * Based on parport_amiga.c. + * + * The built-in Atari parallel port provides one port at a fixed address + * with 8 output data lines (D0 - D7), 1 output control line (STROBE) + * and 1 input status line (BUSY) able to cause an interrupt. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct parport *this_port = NULL; + +static unsigned char +parport_atari_read_data(struct parport *p) +{ + unsigned long flags; + unsigned char data; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 15; + data = sound_ym.rd_data_reg_sel; + restore_flags(flags); + return data; +} + +static void +parport_atari_write_data(struct parport *p, unsigned char data) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 15; + sound_ym.wd_data = data; + restore_flags(flags); +} + +static unsigned char +parport_atari_read_control(struct parport *p) +{ + unsigned long flags; + unsigned char control = 0; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 14; + if (!(sound_ym.rd_data_reg_sel & (1 << 5))) + control = PARPORT_CONTROL_STROBE; + restore_flags(flags); + return control; +} + +static void +parport_atari_write_control(struct parport *p, unsigned char control) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 14; + if (control & PARPORT_CONTROL_STROBE) + sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5); + else + sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); + restore_flags(flags); +} + +static unsigned char +parport_atari_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + unsigned char old = parport_atari_read_control(p); + parport_atari_write_control(p, (old & ~mask) ^ val); + return old; +} + +static unsigned char +parport_atari_read_status(struct parport *p) +{ + return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) | + PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR); +} + +static void +parport_atari_init_state(struct parport_state *s) +{ +} + +static void +parport_atari_save_state(struct parport *p, struct parport_state *s) +{ +} + +static void +parport_atari_restore_state(struct parport *p, struct parport_state *s) +{ +} + +static void +parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + +static void +parport_atari_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void +parport_atari_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static struct parport_operations parport_atari_ops = { + parport_atari_write_data, + parport_atari_read_data, + + parport_atari_write_control, + parport_atari_read_control, + parport_atari_frob_control, + + parport_atari_read_status, + + NULL, /* enable_irq - FIXME */ + NULL, /* disable_irq - FIXME */ + + NULL, /* data_forward - FIXME */ + NULL, /* data_reverse - FIXME */ + + parport_atari_interrupt, + + parport_atari_init_state, + parport_atari_save_state, + parport_atari_restore_state, + + parport_atari_inc_use_count, + parport_atari_dec_use_count, + + 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, +}; + + +int __init +parport_atari_init(void) +{ + struct parport *p; + unsigned long flags; + + if (MACH_IS_ATARI) { + save_flags(flags); + cli(); + /* Soundchip port A/B as output. */ + sound_ym.rd_data_reg_sel = 7; + sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0; + /* STROBE high. */ + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); + restore_flags(flags); + /* MFP port I0 as input. */ + mfp.data_dir &= ~1; + /* MFP port I0 interrupt on high->low edge. */ + mfp.active_edge &= ~1; + p = parport_register_port((unsigned long)&sound_ym.wd_data, + IRQ_MFP_BUSY, PARPORT_DMA_NONE, + &parport_atari_ops); + if (!p) + return 0; + if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt, + IRQ_TYPE_SLOW, p->name, p)) { + parport_unregister_port (p); + return 0; + } + + this_port = p; + printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name); + parport_proc_register(p); + + parport_announce_port (p); + + return 1; + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Andreas Schwab"); +MODULE_DESCRIPTION("Parport Driver for Atari builtin Port"); +MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port"); + +int +init_module(void) +{ + return parport_atari_init() ? 0 : -ENODEV; +} + +void +cleanup_module(void) +{ + if (p->irq != PARPORT_IRQ_NONE) + free_irq(IRQ_MFP_BUSY, p); + parport_proc_unregister(this_port); + parport_unregister_port(this_port); +} +#endif diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c --- v2.3.11/linux/drivers/parport/parport_mfc3.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_mfc3.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,393 @@ +/* Low-level parallel port routines for the Multiface 3 card + * + * Author: Joerg Dorchain + * + * (C) The elitist m68k Users(TM) + * + * based on the existing parport_amiga and lp_mfc + * + * + * From the MFC3 documentation: + * + * Miscellaneous PIA Details + * ------------------------- + * + * The two open-drain interrupt outputs /IRQA and /IRQB are routed to + * /INT2 of the Z2 bus. + * + * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2 + * bus. This means that any PIA registers are accessed at even addresses. + * + * Centronics Pin Connections for the PIA + * -------------------------------------- + * + * The following table shows the connections between the PIA and the + * Centronics interface connector. These connections implement a single, but + * very complete, Centronics type interface. The Pin column gives the pin + * numbers of the PIA. The Centronics pin numbers can be found in the section + * "Parallel Connectors". + * + * + * Pin | PIA | Dir | Centronics Names + * -------+-----+-----+--------------------------------------------------------- + * 19 | CB2 | --> | /STROBE (aka /DRDY) + * 10-17 | PBx | <-> | DATA0 - DATA7 + * 18 | CB1 | <-- | /ACK + * 40 | CA1 | <-- | BUSY + * 3 | PA1 | <-- | PAPER-OUT (aka POUT) + * 4 | PA2 | <-- | SELECTED (aka SEL) + * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME) + * 6 | PA4 | <-- | /ERROR (aka /FAULT) + * 7 | PA5 | --> | DIR (aka /SELECT-IN) + * 8 | PA6 | --> | /AUTO-FEED-XT + * 39 | CA2 | --> | open + * 5 | PA3 | <-- | /ACK (same as CB1!) + * 2 | PA0 | <-- | BUSY (same as CA1!) + * -------+-----+-----+--------------------------------------------------------- + * + * Should be enough to understand some of the driver. + */ + +#include "multiface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Maximum Number of Cards supported */ +#define MAX_MFC 5 + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK() {return 0;} +#endif + +static struct parport *this_port[MAX_MFC] = {NULL, }; +static volatile int dummy; /* for trigger readds */ + +#define pia(dev) ((struct pia *)(dev->base)) +static struct parport_operations pp_mfc3_ops; + +static void mfc3_write_data(struct parport *p, unsigned char data) +{ +DPRINTK("write_data %c\n",data); + + dummy = pia(p)->pprb; /* clears irq bit */ + /* Triggers also /STROBE.*/ + pia(p)->pprb = data; +} + +static unsigned char mfc3_read_data(struct parport *p) +{ + /* clears interupt bit. Triggers also /STROBE. */ + return pia(p)->pprb; +} + +static unsigned char control_pc_to_mfc3(unsigned char control) +{ + unsigned char ret = 32|64; + + if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ + ; + if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ + ; + if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ + ret &= ~32; /* /SELECT_IN */ + if (control & PARPORT_CONTROL_INIT) /* INITP */ + ret |= 128; + if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ + ret &= ~64; + if (control & PARPORT_CONTROL_STROBE) /* Strobe */ + /* Handled directly by hardware */; + return ret; +} + +static unsigned char control_mfc3_to_pc(unsigned char control) +{ + unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT; + + if (control & 128) /* /INITP */ + ret |= PARPORT_CONTROL_INIT; + if (control & 64) /* /AUTOLF */ + ret &= ~PARPORT_CONTROL_AUTOFD; + if (control & 32) /* /SELECT_IN */ + ret &= ~PARPORT_CONTROL_SELECT; + return ret; +} + +static void mfc3_write_control(struct parport *p, unsigned char control) +{ +DPRINTK("write_control %02x\n",control); + pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control); +} + +static unsigned char mfc3_read_control( struct parport *p) +{ +DPRINTK("read_control \n"); + return control_mfc3_to_pc(pia(p)->ppra & 0xe0); +} + +static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val) +{ + unsigned char old; + +DPRINTK("frob_control mask %02x, value %02x\n",mask,val); + old = mfc3_read_control(p); + mfc3_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char status_pc_to_mfc3(unsigned char status) +{ + unsigned char ret = 1; + + if (status & PARPORT_STATUS_BUSY) /* Busy */ + ret &= ~1; + if (status & PARPORT_STATUS_ACK) /* Ack */ + ret |= 8; + if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ + ret |= 2; + if (status & PARPORT_STATUS_SELECT) /* select */ + ret |= 4; + if (status & PARPORT_STATUS_ERROR) /* error */ + ret |= 16; + return ret; +} + +static unsigned char status_mfc3_to_pc(unsigned char status) +{ + unsigned char ret = PARPORT_STATUS_BUSY; + + if (status & 1) /* Busy */ + ret &= ~PARPORT_STATUS_BUSY; + if (status & 2) /* PaperOut */ + ret |= PARPORT_STATUS_PAPEROUT; + if (status & 4) /* Selected */ + ret |= PARPORT_STATUS_SELECT; + if (status & 8) /* Ack */ + ret |= PARPORT_STATUS_ACK; + if (status & 16) /* /ERROR */ + ret |= PARPORT_STATUS_ERROR; + + return ret; +} + +static void mfc3_write_status( struct parport *p, unsigned char status) +{ +DPRINTK("write_status %02x\n",status); + pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status); +} + +static unsigned char mfc3_read_status(struct parport *p) +{ + unsigned char status; + + status = status_mfc3_to_pc(pia(p)->ppra & 0x1f); +DPRINTK("read_status %02x\n", status); + return status; +} + +static void mfc3_change_mode( struct parport *p, int m) +{ + /* XXX: This port only has one mode, and I am + not sure about the corresponding PC-style mode*/ +} + +static int use_cnt = 0; + +static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + + for( i = 0; i < MAX_MFC; i++) + if (this_port[i] != NULL) + if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */ + dummy = pia(this_port[i])->pprb; /* clear irq bit */ + parport_generic_irq(irq, this_port[i], regs); + } +} + +static int mfc3_claim_resources(struct parport *p) +{ +DPRINTK("claim_resources\n"); +} + +static void mfc3_init_state(struct parport_state *s) +{ + s->u.amiga.data = 0; + s->u.amiga.datadir = 255; + s->u.amiga.status = 0; + s->u.amiga.statusdir = 0xe0; +} + +static void mfc3_save_state(struct parport *p, struct parport_state *s) +{ + s->u.amiga.data = pia(p)->pprb; + pia(p)->crb &= ~PIA_DDR; + s->u.amiga.datadir = pia(p)->pddrb; + pia(p)->crb |= PIA_DDR; + s->u.amiga.status = pia(p)->ppra; + pia(p)->cra &= ~PIA_DDR; + s->u.amiga.statusdir = pia(p)->pddrb; + pia(p)->cra |= PIA_DDR; +} + +static void mfc3_restore_state(struct parport *p, struct parport_state *s) +{ + pia(p)->pprb = s->u.amiga.data; + pia(p)->crb &= ~PIA_DDR; + pia(p)->pddrb = s->u.amiga.datadir; + pia(p)->crb |= PIA_DDR; + pia(p)->ppra = s->u.amiga.status; + pia(p)->cra &= ~PIA_DDR; + pia(p)->pddrb = s->u.amiga.statusdir; + pia(p)->cra |= PIA_DDR; +} + +static void mfc3_enable_irq(struct parport *p) +{ + pia(p)->crb |= PIA_C1_ENABLE_IRQ; +} + +static void mfc3_disable_irq(struct parport *p) +{ + pia(p)->crb &= ~PIA_C1_ENABLE_IRQ; +} + +static void mfc3_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void mfc3_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static struct parport_operations pp_mfc3_ops = { + mfc3_write_data, + mfc3_read_data, + + mfc3_write_control, + mfc3_read_control, + mfc3_frob_control, + + mfc3_read_status, + + mfc3_enable_irq, + mfc3_disable_irq, + + NULL, /* data_forward - FIXME */ + NULL, /* data_reverse - FIXME */ + + mfc3_interrupt, + + mfc3_init_state, + mfc3_save_state, + mfc3_restore_state, + + mfc3_inc_use_count, + mfc3_dec_use_count, + + 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 --------------------------------- */ + +__initfunc(int parport_mfc3_init(void)) +{ + struct parport *p; + int pias = 0; + struct pia *pp; + unsigned int key = 0; + const struct ConfigDev *cd; + + if (MACH_IS_AMIGA) { + while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) { + cd = zorro_get_board(key); + pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE)); + if (pias < MAX_MFC) { + pp->crb = 0; + pp->pddrb = 255; /* all data pins output */ + pp->crb = PIA_DDR|32|8; + dummy = pp->pddrb; /* reading clears interrupt */ + pp->cra = 0; + pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */ + pp->cra = PIA_DDR; + pp->ppra = 0; /* reset printer */ + udelay(10); + pp->ppra = 128; + if ((p = parport_register_port((unsigned long)pp, + IRQ_AMIGA_PORTS, PARPORT_DMA_NONE, + &pp_mfc3_ops))) { + this_port[pias++] = p; + printk(KERN_INFO "%s: Multiface III port using irq\n", p->name); + /* XXX: set operating mode */ + parport_proc_register(p); + + if (p->irq != PARPORT_IRQ_NONE) + if (use_cnt++ == 0) + if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops)) + use_cnt--; + + if (parport_probe_hook) + (*parport_probe_hook)(p); + zorro_config_board(key, 0); + p->private_data = (void *)key; + parport_announce_port (p); + } + } + } + } + return pias; +} + +#ifdef MODULE + +MODULE_AUTHOR("Joerg Dorchain"); +MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port"); +MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port"); + +int init_module(void) +{ + return ! parport_mfc3_init(); +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < MAX_MFC; i++) + if (this_port[i] != NULL) { + if (p->irq != PARPORT_IRQ_NONE) + if (--use_cnt == 0) + free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops); + parport_proc_unregister(this_port[i]); + parport_unregister_port(this_port[i]); + zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0); + } +} +#endif + + diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.11/linux/drivers/parport/parport_pc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_pc.c Wed Jul 28 10:26:36 1999 @@ -0,0 +1,1854 @@ +/* Low-level parallel-port routines for 8255-based PC-style hardware. + * + * Authors: Phil Blundell + * Tim Waugh + * Jose Renau + * David Campbell + * Andrea Arcangeli + * + * 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 + */ + +/* This driver should work with any hardware that is broadly compatible + * with that in the IBM PC. This applies to the majority of integrated + * I/O chipsets that are commonly available. The expected register + * layout is: + * + * base+0 data + * base+1 status + * base+2 control + * + * In addition, there are some optional registers: + * + * base+3 EPP address + * base+4 EPP data + * base+0x400 ECP config A + * base+0x401 ECP config B + * base+0x402 ECP control + * + * All registers are 8 bits wide and read/write. If your hardware differs + * only in register addresses (eg because your registers are on 32-bit + * word boundaries) then you can alter the constants in parport_pc.h to + * accomodate this. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* 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 + +/* 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. + */ +static int clear_epp_timeout(struct parport *pb) +{ + unsigned char r; + + if (!(parport_pc_read_status(pb) & 0x01)) + return 1; + + /* To clear timeout some chips require double read */ + parport_pc_read_status(pb); + r = parport_pc_read_status(pb); + 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_data(struct parport *p, unsigned char d) +{ + outb (d, DATA (p)); +} + +unsigned char parport_pc_read_data(struct parport *p) +{ + return inb (DATA (p)); +} + +unsigned char __frob_control (struct parport *p, unsigned char mask, + unsigned char val) +{ + 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 */ +} + +void parport_pc_write_control(struct parport *p, unsigned char d) +{ + 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); + } + + __frob_control (p, wm, d & wm); +} + +unsigned char parport_pc_read_control(struct parport *p) +{ + const struct parport_pc_private *priv = p->physport->private_data; + return priv->ctr; /* Use soft copy */ +} + +unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, + unsigned char val) +{ + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + /* 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_status(struct parport *p) +{ + return inb (STATUS (p)); +} + +void parport_pc_disable_irq(struct parport *p) +{ + __frob_control (p, 0x10, 0); +} + +void parport_pc_enable_irq(struct parport *p) +{ + __frob_control (p, 0x10, 0x10); +} + +void parport_pc_data_forward (struct parport *p) +{ + __frob_control (p, 0x20, 0); +} + +void parport_pc_data_reverse (struct parport *p) +{ + __frob_control (p, 0x20, 0x20); +} + +void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) +{ + s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); + s->u.pc.ecr = 0x24; +} + +void parport_pc_save_state(struct parport *p, struct parport_state *s) +{ + 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)); +} + +void parport_pc_restore_state(struct parport *p, struct parport_state *s) +{ + 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)); +} + +#ifdef CONFIG_PARPORT_1284 +static size_t parport_pc_epp_read_data (struct parport *port, void *buf, + size_t length, int flags) +{ + 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; +} + +static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, + size_t length, int flags) +{ + 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; +} + +static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, + size_t length, int flags) +{ + 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; +} + +static size_t parport_pc_epp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) +{ + 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; +} + +static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, + size_t length, int flags) +{ + 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; +} + +static size_t parport_pc_ecpepp_write_data (struct parport *port, + const void *buf, size_t length, + int flags) +{ + 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; +} + +static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, + size_t length, int flags) +{ + 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; +} + +static size_t parport_pc_ecpepp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) +{ + 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 */ + +#ifdef CONFIG_PARPORT_PC_FIFO +static size_t parport_pc_fifo_write_block_pio (struct parport *port, + const void *buf, size_t length) +{ + 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; +} + +static size_t parport_pc_fifo_write_block_dma (struct parport *port, + const void *buf, size_t length) +{ + 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; + } + + /* 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; +} + +/* 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; + + /* 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; +} + +/* ECP */ +#ifdef CONFIG_PARPORT_1284 +size_t parport_pc_ecp_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) +{ + 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; +} + +size_t parport_pc_ecp_read_block_pio (struct parport *port, + void *buf, size_t length, int flags) +{ + 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 + MOD_INC_USE_COUNT; +#endif +} + +void parport_pc_dec_use_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +struct parport_operations parport_pc_ops = +{ + parport_pc_write_data, + parport_pc_read_data, + + parport_pc_write_control, + parport_pc_read_control, + parport_pc_frob_control, + + parport_pc_read_status, + + parport_pc_enable_irq, + parport_pc_disable_irq, + + parport_pc_data_forward, + parport_pc_data_reverse, + + parport_pc_interrupt, + parport_pc_init_state, + parport_pc_save_state, + parport_pc_restore_state, + + parport_pc_inc_use_count, + parport_pc_dec_use_count, + + 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 + */ +static int __init parport_SPP_supported(struct parport *pb) +{ + unsigned char r, w; + + /* + * first clear an eventually pending EPP timeout + * I (sailer@ife.ee.ethz.ch) have an SMSC chipset + * that does not even respond to SPP cycles if an EPP + * timeout is pending + */ + clear_epp_timeout(pb); + + /* Do a simple read-write test to make sure the port exists. */ + w = 0xc; + outb (w, CONTROL (pb)); + + /* 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; + outb (w, CONTROL (pb)); + r = inb (CONTROL (pb)); + outb (0xc, CONTROL (pb)); + if ((r & 0xf) == w) + return PARPORT_MODE_PCSPP; + } + + if (user_specified) + /* That didn't work, but the user thinks there's a + * port here. */ + printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n", + pb->base, w, r); + + /* Try the data register. The data lines aren't tri-stated at + * this stage, so we expect back what we wrote. */ + w = 0xaa; + parport_pc_write_data (pb, w); + r = parport_pc_read_data (pb); + if (r == w) { + w = 0x55; + parport_pc_write_data (pb, w); + r = parport_pc_read_data (pb); + if (r == w) + return PARPORT_MODE_PCSPP; + } + + if (user_specified) + /* 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. */ + if (user_specified) + return PARPORT_MODE_PCSPP; + + return 0; +} + +/* Check for ECR + * + * Old style XT ports alias io ports every 0x400, hence accessing ECR + * on these cards actually accesses the CTR. + * + * Modern cards don't do this but reading from ECR will return 0xff + * regardless of what is written here if the card does NOT support + * ECP. + * + * 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) +{ + struct parport_pc_private *priv = pb->private_data; + unsigned char r = 0xc; + + priv->ecr = 0; + outb (r, CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { + outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ + + r = inb (CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2)) + goto no_reg; /* Sure that no ECR register exists */ + } + + if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) + goto no_reg; + + outb (0x34, ECONTROL (pb)); + if (inb (ECONTROL (pb)) != 0x35) + goto no_reg; + + priv->ecr = 1; + outb (0xc, CONTROL (pb)); + + /* Go to mode 000 */ + frob_econtrol (pb, 0xe0, ECR_SPP << 5); + + return 1; + + no_reg: + 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; + 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 (!priv->ecr) + return 0; + + /* 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)); + + result = parport_PS2_supported(pb); + + outb (oecr, ECONTROL (pb)); + return result; +} + +/* EPP mode detection */ + +static int __init parport_EPP_supported(struct parport *pb) +{ + const struct parport_pc_private *priv = pb->private_data; + + /* + * 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. + */ + + /* If EPP timeout bit clear then EPP available */ + if (!clear_epp_timeout(pb)) + return 0; /* No way to clear timeout */ + + /* Check for Intel bug. */ + if (priv->ecr) { + unsigned char i; + for (i = 0x00; i < 0x80; i += 0x20) { + outb (i, ECONTROL (pb)); + if (clear_epp_timeout (pb)) + /* Phony EPP in ECP. */ + return 0; + } + } + + 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) +{ + struct parport_pc_private *priv = pb->private_data; + int result; + unsigned char oecr; + + if (!priv->ecr) + return 0; + + oecr = inb (ECONTROL (pb)); + /* Search for SMC style EPP+ECP mode */ + outb (0x80, ECONTROL (pb)); + + result = parport_EPP_supported(pb); + + outb (oecr, ECONTROL (pb)); + + 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 result; +} + +#else /* No IEEE 1284 support */ + +/* 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; } + +#endif /* No IEEE 1284 support */ + +/* --- IRQ detection -------------------------------------- */ + +/* Only if supports ECP mode */ +static int __init programmable_irq_support(struct parport *pb) +{ + int irq, intrLine; + unsigned char oecr = inb (ECONTROL (pb)); + static const int lookup[8] = { + PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 + }; + + outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */ + + intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; + irq = lookup[intrLine]; + + outb (oecr, ECONTROL (pb)); + return irq; +} + +static int __init irq_probe_ECP(struct parport *pb) +{ + int i; + unsigned long irqs; + + sti(); + irqs = probe_irq_on(); + + 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 writeIntrThreshold is generated */ + for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) + outb (0xaa, FIFO (pb)); + + pb->irq = probe_irq_off(irqs); + outb (ECR_SPP << 5, ECONTROL (pb)); + + if (pb->irq <= 0) + pb->irq = PARPORT_IRQ_NONE; + + return pb->irq; +} + +/* + * This detection seems that only works in National Semiconductors + * This doesn't work in SMC, LGS, and Winbond + */ +static int __init irq_probe_EPP(struct parport *pb) +{ +#ifndef ADVANCED_DETECT + return PARPORT_IRQ_NONE; +#else + int irqs; + unsigned char oecr; + + if (pb->modes & PARPORT_MODE_PCECR) + oecr = inb (ECONTROL (pb)); + + sti(); + irqs = probe_irq_on(); + + if (pb->modes & PARPORT_MODE_PCECR) + frob_econtrol (pb, 0x10, 0x10); + + clear_epp_timeout(pb); + parport_pc_frob_control (pb, 0x20, 0x20); + parport_pc_frob_control (pb, 0x10, 0x10); + clear_epp_timeout(pb); + + /* Device isn't expecting an EPP read + * and generates an IRQ. + */ + parport_pc_read_epp(pb); + udelay(20); + + pb->irq = probe_irq_off (irqs); + if (pb->modes & PARPORT_MODE_PCECR) + 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 */ +} + +static int __init irq_probe_SPP(struct parport *pb) +{ + /* Don't even try to do this. */ + return PARPORT_IRQ_NONE; +} + +/* We will attempt to share interrupt requests since other devices + * such as sound cards and network cards seem to like using the + * printer IRQs. + * + * When ECP is available we can autoprobe for IRQs. + * NOTE: If we can autoprobe it, we can register the IRQ. + */ +static int __init parport_irq_probe(struct parport *pb) +{ + 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_ECP) + pb->irq = irq_probe_ECP(pb); + + if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && + (pb->modes & PARPORT_MODE_EPP)) + pb->irq = irq_probe_EPP(pb); + + clear_epp_timeout(pb); + + if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) + pb->irq = irq_probe_EPP(pb); + + clear_epp_timeout(pb); + + if (pb->irq == PARPORT_IRQ_NONE) + pb->irq = irq_probe_SPP(pb); + +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, + unsigned long int base_hi, + int irq, int dma) +{ + struct parport_pc_private *priv; + struct parport_operations *ops; + struct parport tmp; + struct parport *p = &tmp; + int probedirq = PARPORT_IRQ_NONE; + if (check_region(base, 3)) return 0; + priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL); + if (!priv) { + printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base); + return 0; + } + ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); + if (!ops) { + printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n", + base); + kfree (priv); + return 0; + } + memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations)); + 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; + p->dma = dma; + p->modes = PARPORT_MODE_PCSPP; + p->ops = ops; + p->private_data = priv; + p->physport = p; + if (base_hi && !check_region(base_hi,3)) { + parport_ECR_present(p); + parport_ECP_supported(p); + parport_ECPPS2_supported(p); + } + if (base != 0x3bc) { + if (!check_region(base+0x3, 5)) { + parport_EPP_supported(p); + if (!(p->modes & PARPORT_MODE_EPP)) + parport_ECPEPP_supported(p); + } + } + if (!parport_SPP_supported (p)) { + /* No port. */ + kfree (priv); + return 0; + } + + parport_PS2_supported (p); + + if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, ops))) { + kfree (priv); + kfree (ops); + return 0; + } + + p->base_hi = base_hi; + p->modes = tmp.modes; + 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_ECP)) + printk(" (0x%lx)", p->base_hi); + p->irq = irq; + p->dma = dma; + if (p->irq == PARPORT_IRQ_AUTO) { + p->irq = PARPORT_IRQ_NONE; + parport_irq_probe(p); + } else if (p->irq == PARPORT_IRQ_PROBEONLY) { + p->irq = PARPORT_IRQ_NONE; + parport_irq_probe(p); + probedirq = p->irq; + 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) + 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_##x){printk("%s%s",f?",":"",#x);f++;}} + { + int f = 0; + printmode(PCSPP); + printmode(TRISTATE); + printmode(COMPAT) + printmode(EPP); + printmode(ECP); + printmode(DMA); + } +#undef printmode + printk("]\n"); + if (probedirq != PARPORT_IRQ_NONE) + printk("%s: irq %d detected\n", p->name, probedirq); + parport_proc_register(p); + + request_region (p->base, 3, p->name); + if (p->size > 3) + request_region (p->base + 3, p->size - 3, p->name); + if (p->modes & PARPORT_MODE_ECP) + request_region (p->base_hi, 3, p->name); + + if (p->irq != PARPORT_IRQ_NONE) { + if (request_irq (p->irq, parport_pc_interrupt, + 0, p->name, p)) { + printk (KERN_WARNING "%s: irq %d in use, " + "resorting to polled operation\n", + p->name, p->irq); + p->irq = PARPORT_IRQ_NONE; + p->dma = PARPORT_DMA_NONE; + } + + if (p->dma != PARPORT_DMA_NONE) { + if (request_dma (p->dma, p->name)) { + printk (KERN_WARNING "%s: dma %d in use, " + "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. + * SELECT | INIT also puts IEEE1284-compliant devices into + * compatibility mode. */ + if (p->modes & PARPORT_MODE_ECP) + /* + * Put the ECP detected port in PS2 mode. + */ + outb (0x24, ECONTROL (p)); + + parport_pc_write_data(p, 0); + parport_pc_data_forward (p); + parport_pc_write_control(p, PARPORT_CONTROL_SELECT); + udelay (50); + parport_pc_write_control(p, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); + udelay (50); + + /* Now that we've told the sharing engine about the port, and + found out its characteristics, let the high-level drivers + know about it. */ + parport_announce_port (p); + + return 1; +} + +/* Look for PCI parallel port cards. */ +static int __init parport_pc_init_pci (int irq, int dma) +{ + struct { + unsigned int vendor; + unsigned int device; + unsigned int numports; + struct { + unsigned long lo; + unsigned long hi; /* -ve if not there */ + } addr[4]; + } cards[] = { + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1, + { { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1, + { { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1, + { { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1, + { { 2, 3 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2, + { { 2, 3 }, { 4, 5 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1, + { { 4, 5 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1, + { { 4, 5 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1, + { { 4, 5 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1, + { { 0, 1 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2, + { { 0, 1 }, { 2, 3 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2, + { { 1, 2 }, { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2, + { { 1, 2 }, { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2, + { { 1, 2 }, { 3, 4 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1, + { { 1, 2 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1, + { { 1, 2 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1, + { { 1, 2 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1, + { { 2, 3 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1, + { { 2, 3 }, } }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1, + { { 2, 3 }, } }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1, + { { 0, -1 }, } }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1, + { { 0, -1 }, } }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1, + { { 0, -1 }, } }, + { 0, } + }; + + int count = 0; + int i; + + if (!pci_present ()) + return 0; + + for (i = 0; cards[i].vendor; i++) { + struct pci_dev *pcidev = NULL; + while ((pcidev = pci_find_device (cards[i].vendor, + cards[i].device, + pcidev)) != NULL) { + int n; + for (n = 0; n < cards[i].numports; n++) { + unsigned long lo = cards[i].addr[n].lo; + unsigned long hi = cards[i].addr[n].hi; + unsigned long io_lo = pcidev->base_address[lo]; + unsigned long io_hi = ((hi < 0) ? 0 : + pcidev->base_address[hi]); + io_lo &= PCI_BASE_ADDRESS_IO_MASK; + io_hi &= PCI_BASE_ADDRESS_IO_MASK; + if (irq == PARPORT_IRQ_AUTO) + count += probe_one_port (io_lo, io_hi, + pcidev->irq, + dma); + else + count += probe_one_port (io_lo, io_hi, + irq, dma); + } + } + } + + return count; +} + +#ifdef MODULE +static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; +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(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); +MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); + +int init_module(void) +{ + /* Work out how many ports we have, then get parport_share to parse + the irq values. */ + unsigned int i; + for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); + if (i) { + if (parport_parse_irqs(i, irq, irqval)) return 1; + if (parport_parse_dmas(i, dma, dmaval)) return 1; + } + else { + /* The user can make us use any IRQs or DMAs we find. */ + int val; + + if (irq[0] && !parport_parse_irqs (1, irq, &val)) + switch (val) { + case PARPORT_IRQ_NONE: + case PARPORT_IRQ_AUTO: + irqval[0] = val; + } + + if (dma[0] && !parport_parse_dmas (1, dma, &val)) + switch (val) { + case PARPORT_DMA_NONE: + case PARPORT_DMA_AUTO: + dmaval[0] = val; + } + } + + return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1); +} + +void cleanup_module(void) +{ + struct parport *p = parport_enumerate(), *tmp; + while (p) { + tmp = p->next; + if (p->modes & PARPORT_MODE_PCSPP) { + struct parport_pc_private *priv = p->private_data; + struct parport_operations *ops = p->ops; + if (p->dma != PARPORT_DMA_NONE) + free_dma(p->dma); + if (p->irq != PARPORT_IRQ_NONE) + free_irq(p->irq, p); + release_region(p->base, 3); + if (p->size > 3); + release_region(p->base + 3, p->size - 3); + 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); + kfree (ops); /* hope no-one cached it */ + } + p = tmp; + } +} +#endif diff -u --recursive --new-file v2.3.11/linux/drivers/parport/probe.c linux/drivers/parport/probe.c --- v2.3.11/linux/drivers/parport/probe.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/probe.c Wed Jul 28 11:22:46 1999 @@ -0,0 +1,210 @@ +/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem 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); + + /* 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 (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++] = ';'; + 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: + buffer[len] = '\0'; + set_fs (oldfs); + parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); + } + parport_release (dev); + + if (retval > 2) + parse_data (dev->port, dev->daisy, buffer); + + parport_close (dev); + return retval; +} diff -u --recursive --new-file v2.3.11/linux/drivers/parport/procfs.c linux/drivers/parport/procfs.c --- v2.3.11/linux/drivers/parport/procfs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/procfs.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,429 @@ +/* Sysctl interface for parport devices. + * + * Authors: David Campbell + * Tim Waugh + * Philip Blundell + * Andrea Arcangeli + * Riccardo Facchetti + * + * based on work by Grant Guenther + * and Philip Blundell + * + * Cleaned up include files - Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_SYSCTL + + +static int do_active_device(ctl_table *table, int write, struct file *filp, + void *result, size_t *lenp) +{ + struct parport *port = (struct parport *)table->extra1; + char buffer[256]; + struct pardevice *dev; + int len = 0; + + if (write) /* can't happen anyway */ + return -EACCES; + + if (filp->f_pos) { + *lenp = 0; + return 0; + } + + for (dev = port->devices; dev ; dev = dev->next) { + if(dev == port->cad) { + len += sprintf(buffer, "%s\n", dev->name); + } + } + + if(!len) { + len += sprintf(buffer, "%s\n", "none"); + } + + if (len > *lenp) + len = *lenp; + else + *lenp = len; + + filp->f_pos += len; + + return copy_to_user(result, buffer, len) ? -EFAULT : 0; +} + +#ifdef CONFIG_PARPORT_1284 +static int do_autoprobe(ctl_table *table, int write, struct file *filp, + void *result, size_t *lenp) +{ + struct parport_device_info *info = table->extra2; + const char *str; + char buffer[256]; + int len = 0; + + if (write) /* permissions stop this */ + return -EACCES; + + if (filp->f_pos) { + *lenp = 0; + return 0; + } + + if ((str = info->class_name) != NULL) + len += sprintf (buffer + len, "CLASS:%s;\n", str); + + if ((str = info->model) != NULL) + len += sprintf (buffer + len, "MODEL:%s;\n", str); + + if ((str = info->mfr) != NULL) + len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str); + + if ((str = info->description) != NULL) + len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str); + + if ((str = info->cmdset) != NULL) + len += sprintf (buffer + len, "COMMAND SET:%s;\n", str); + + if (len > *lenp) + len = *lenp; + else + *lenp = len; + + filp->f_pos += len; + + return copy_to_user (result, buffer, len) ? -EFAULT : 0; +} +#endif /* IEEE1284.3 support. */ + +static int do_hardware(ctl_table *table, int write, struct file *filp, + void *result, size_t *lenp) +{ + struct parport *port = (struct parport *)table->extra1; + char buffer[256]; + int len = 0; + + if (filp->f_pos) { + *lenp = 0; + return 0; + } + + if (write) /* can't happen anyway */ + return -EACCES; + + len += sprintf(buffer+len, "base:\t0x%lx", port->base); + if (port->base_hi) + len += sprintf(buffer+len, " (0x%lx)", port->base_hi); + buffer[len++] = '\n'; + + if (port->irq == PARPORT_IRQ_NONE) { + len += sprintf(buffer+len, "irq:\tnone\n"); + } else { + len += sprintf(buffer+len, "irq:\t%d\n", port->irq); + } + + if (port->dma == PARPORT_DMA_NONE) + len += sprintf(buffer+len, "dma:\tnone\n"); + else + len += sprintf(buffer+len, "dma:\t%d\n", port->dma); + + len += sprintf(buffer+len, "modes:\t"); + { +#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}} + int f = 0; + printmode(PCSPP); + printmode(TRISTATE); + printmode(COMPAT); + printmode(EPP); + printmode(ECP); + printmode(DMA); +#undef printmode + } + buffer[len++] = '\n'; + + if (len > *lenp) + len = *lenp; + else + *lenp = len; + + filp->f_pos += len; + + return copy_to_user(result, buffer, len) ? -EFAULT : 0; +} + +#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child } +#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \ + NULL, 0, 0555, child } +#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child } +#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \ + NULL, 0, 0555, NULL } + + +struct parport_sysctl_table { + struct ctl_table_header *sysctl_header; + ctl_table vars[9]; + ctl_table device_dir[2]; + ctl_table port_dir[2]; + ctl_table parport_dir[2]; + ctl_table dev_dir[2]; +}; + +static const struct parport_sysctl_table parport_sysctl_template = { + NULL, + { + { DEV_PARPORT_SPINTIME, "spintime", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec }, + { DEV_PARPORT_HARDWARE, "hardware", + NULL, 0, 0444, NULL, + &do_hardware }, + PARPORT_DEVICES_ROOT_DIR, +#ifdef CONFIG_PARPORT_1284 + { DEV_PARPORT_AUTOPROBE, "autoprobe", + NULL, 0, 0444, NULL, + &do_autoprobe }, + { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0", + NULL, 0, 0444, NULL, + &do_autoprobe }, + { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1", + NULL, 0, 0444, NULL, + &do_autoprobe }, + { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2", + NULL, 0, 0444, NULL, + &do_autoprobe }, + { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3", + NULL, 0, 0444, NULL, + &do_autoprobe }, +#endif /* IEEE 1284 support */ + {0} + }, + { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL, + &do_active_device }, {0}}, + { PARPORT_PORT_DIR(NULL), {0}}, + { PARPORT_PARPORT_DIR(NULL), {0}}, + { PARPORT_DEV_DIR(NULL), {0}} +}; + +struct parport_device_sysctl_table +{ + struct ctl_table_header *sysctl_header; + ctl_table vars[2]; + ctl_table device_dir[2]; + ctl_table devices_root_dir[2]; + ctl_table port_dir[2]; + ctl_table parport_dir[2]; + ctl_table dev_dir[2]; +}; + +static const struct parport_device_sysctl_table +parport_device_sysctl_template = { + NULL, + { + { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec }, + }, + { {0, NULL, NULL, 0, 0555, NULL}, {0}}, + { PARPORT_DEVICES_ROOT_DIR, {0}}, + { PARPORT_PORT_DIR(NULL), {0}}, + { PARPORT_PARPORT_DIR(NULL), {0}}, + { PARPORT_DEV_DIR(NULL), {0}} +}; + +struct parport_default_sysctl_table +{ + struct ctl_table_header *sysctl_header; + ctl_table vars[3]; + ctl_table default_dir[2]; + ctl_table parport_dir[2]; + ctl_table dev_dir[2]; +}; + +extern unsigned long parport_default_timeslice; +extern int parport_default_spintime; + +static struct parport_default_sysctl_table +parport_default_sysctl_table = { + NULL, + { + { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice", + &parport_default_timeslice, + sizeof(parport_default_timeslice), 0644, NULL, + &proc_dointvec }, + { DEV_PARPORT_DEFAULT_SPINTIME, "spintime", + &parport_default_spintime, + sizeof(parport_default_timeslice), 0644, NULL, + &proc_dointvec }, + {0} + }, + { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555, + parport_default_sysctl_table.vars },{0}}, + { + PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), + {0}}, + { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}} +}; + + +int parport_proc_register(struct parport *port) +{ + struct parport_sysctl_table *t; + int i; + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (t == NULL) + return -ENOMEM; + memcpy(t, &parport_sysctl_template, sizeof(*t)); + + t->device_dir[0].extra1 = port; + + for (i = 0; i < 8; i++) + t->vars[i].extra1 = port; + + t->vars[0].data = &port->spintime; + t->vars[2].child = t->device_dir; + + for (i = 0; i < 5; i++) + t->vars[3 + i].extra2 = &port->probe_info[i]; + + t->port_dir[0].procname = port->name; + t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ + + t->port_dir[0].child = t->vars; + t->parport_dir[0].child = t->port_dir; + t->dev_dir[0].child = t->parport_dir; + + t->sysctl_header = register_sysctl_table(t->dev_dir, 0); + if (t->sysctl_header == NULL) { + kfree(t); + t = NULL; + } + port->sysctl_table = t; + return 0; +} + +int parport_proc_unregister(struct parport *port) +{ + if (port->sysctl_table) { + struct parport_sysctl_table *t = port->sysctl_table; + port->sysctl_table = NULL; + unregister_sysctl_table(t->sysctl_header); + kfree(t); + } + return 0; +} + +int parport_device_proc_register(struct pardevice *device) +{ + struct parport_device_sysctl_table *t; + struct parport * port = device->port; + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (t == NULL) + return -ENOMEM; + memcpy(t, &parport_device_sysctl_template, sizeof(*t)); + + t->dev_dir[0].child = t->parport_dir; + t->parport_dir[0].child = t->port_dir; + t->port_dir[0].procname = port->name; + t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ + t->port_dir[0].child = t->devices_root_dir; + t->devices_root_dir[0].child = t->device_dir; + +#ifdef CONFIG_PARPORT_1284 + + t->device_dir[0].ctl_name = + parport_device_num(port->number, port->muxport, + device->daisy) + + 1; /* nb 0 isn't legal here */ + +#else /* No IEEE 1284 support */ + + /* parport_device_num isn't available. */ + t->device_dir[0].ctl_name = 1; + +#endif /* IEEE 1284 support or not */ + + t->device_dir[0].procname = device->name; + t->device_dir[0].extra1 = device; + t->device_dir[0].child = t->vars; + t->vars[0].data = &device->timeslice; + + t->sysctl_header = register_sysctl_table(t->dev_dir, 0); + if (t->sysctl_header == NULL) { + kfree(t); + t = NULL; + } + device->sysctl_table = t; + return 0; +} + +int parport_device_proc_unregister(struct pardevice *device) +{ + if (device->sysctl_table) { + struct parport_device_sysctl_table *t = device->sysctl_table; + device->sysctl_table = NULL; + unregister_sysctl_table(t->sysctl_header); + kfree(t); + } + return 0; +} + +int parport_default_proc_register(void) +{ + parport_default_sysctl_table.sysctl_header = + register_sysctl_table(parport_default_sysctl_table.dev_dir, 0); + return 0; +} + +int parport_default_proc_unregister(void) +{ + if (parport_default_sysctl_table.sysctl_header) { + unregister_sysctl_table(parport_default_sysctl_table. + sysctl_header); + parport_default_sysctl_table.sysctl_header = NULL; + } + return 0; +} + +#else /* no sysctl */ + +int parport_proc_register(struct parport *pp) +{ + return 0; +} + +int parport_proc_unregister(struct parport *pp) +{ + return 0; +} + +int parport_device_proc_register(struct pardevice *device) +{ + return 0; +} + +int parport_device_proc_unregister(struct pardevice *device) +{ + return 0; +} + +int parport_default_proc_register (void) +{ + return 0; +} + +int parport_default_proc_unregister (void) +{ + return 0; +} +#endif diff -u --recursive --new-file v2.3.11/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.3.11/linux/drivers/parport/share.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/share.c Tue Jul 27 13:55:52 1999 @@ -0,0 +1,671 @@ +/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $ + * Parallel-port resource manager code. + * + * Authors: David Campbell + * Tim Waugh + * Jose Renau + * Philip Blundell + * Andrea Arcangeli + * + * based on work by Grant Guenther + * and Philip Blundell + */ + +#undef PARPORT_DEBUG_SHARING /* undef for production */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef PARPORT_PARANOID + +#define PARPORT_DEFAULT_TIMESLICE (HZ/5) + +unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE; +int parport_default_spintime = DEFAULT_SPIN_TIME; + +static struct parport *portlist = NULL, *portlist_tail = NULL; +spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED; + +static struct parport_driver *driver_chain = NULL; +spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED; + +/* What you can do to a port that's gone away.. */ +static void dead_write_lines (struct parport *p, unsigned char b){} +static unsigned char dead_read_lines (struct parport *p) { return 0; } +static unsigned char dead_frob_lines (struct parport *p, unsigned char b, + unsigned char c) { return 0; } +static void dead_onearg (struct parport *p){} +static void dead_irq (int i, void *p, struct pt_regs *r) { } +static void dead_initstate (struct pardevice *d, struct parport_state *s) { } +static void dead_state (struct parport *p, struct parport_state *s) { } +static void dead_noargs (void) { } +static size_t dead_write (struct parport *p, const void *b, size_t l, int f) +{ return 0; } +static size_t dead_read (struct parport *p, void *b, size_t l, int f) +{ return 0; } +static struct parport_operations dead_ops = { + dead_write_lines, /* data */ + dead_read_lines, + dead_write_lines, /* control */ + dead_read_lines, + dead_frob_lines, + dead_read_lines, /* status */ + dead_onearg, /* enable_irq */ + dead_onearg, /* disable_irq */ + dead_onearg, /* data_forward */ + dead_onearg, /* data_reverse */ + dead_irq, + dead_initstate, /* init_state */ + dead_state, + dead_state, + dead_noargs, /* xxx_use_count */ + dead_noargs, + dead_write, /* epp */ + dead_read, + dead_write, + dead_read, + dead_write, /* ecp */ + dead_read, + dead_write, + dead_write, /* compat */ + dead_read, /* nibble */ + dead_read /* byte */ +}; + +static void call_driver_chain(int attach, struct parport *port) +{ + struct parport_driver *drv; + + for (drv = driver_chain; drv; drv = drv->next) { + if (attach) + drv->attach (port); + else + drv->detach (port); + } +} + +int parport_register_driver (struct parport_driver *drv) +{ + struct parport *port; + + spin_lock (&driverlist_lock); + drv->next = driver_chain; + driver_chain = drv; + spin_unlock (&driverlist_lock); + + for (port = portlist; port; port = port->next) + drv->attach (port); + + return 0; +} + +void parport_unregister_driver (struct parport_driver *arg) +{ + struct parport_driver *drv = driver_chain, *olddrv = NULL; + + while (drv) { + if (drv == arg) { + spin_lock (&driverlist_lock); + if (olddrv) + olddrv->next = drv->next; + else + driver_chain = drv->next; + spin_unlock (&driverlist_lock); + return; + } + olddrv = drv; + drv = drv->next; + } +} + +/* Return a list of all the ports we know about. */ +struct parport *parport_enumerate(void) +{ + /* Attempt to make things work on 2.2 systems. */ + if (!portlist) { + request_module ("parport_lowlevel"); + if (portlist) + /* The user has a parport_lowlevel alias in + * conf.modules. Warn them that it won't work + * for long. */ + printk (KERN_WARNING + "parport: 'parport_lowlevel' is deprecated; " + "see parport.txt\n"); + } + + return portlist; +} + +struct parport *parport_register_port(unsigned long base, int irq, int dma, + struct parport_operations *ops) +{ + struct parport *tmp; + int portnum; + int device; + char *name; + + tmp = kmalloc(sizeof(struct parport), GFP_KERNEL); + if (!tmp) { + printk(KERN_WARNING "parport: memory squeeze\n"); + return NULL; + } + + /* Search for the lowest free parport number. */ + for (portnum = 0; ; portnum++) { + struct parport *itr = portlist; + while (itr) { + if (itr->number == portnum) + /* No good, already used. */ + break; + else + itr = itr->next; + } + + if (itr == NULL) + /* Got to the end of the list. */ + break; + } + + /* Init our structure */ + memset(tmp, 0, sizeof(struct parport)); + 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->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) { + printk(KERN_ERR "parport: memory squeeze\n"); + kfree(tmp); + return NULL; + } + sprintf(name, "parport%d", portnum); + tmp->name = name; + + /* + * Chain the entry to our list. + * + * This function must not run from an irq handler so we don' t need + * to clear irq on the local CPU. -arca + */ + spin_lock(&parportlist_lock); + if (portlist_tail) + portlist_tail->next = tmp; + portlist_tail = tmp; + if (!portlist) + portlist = tmp; + spin_unlock(&parportlist_lock); + + for (device = 0; device < 5; device++) + /* assume the worst */ + tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; + + tmp->waithead = tmp->waittail = NULL; + + return tmp; +} + +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); +} + +static void free_port (struct parport *port) +{ + int d; + 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); +} + +void parport_unregister_port(struct parport *port) +{ + struct parport *p; + + port->ops = &dead_ops; + + /* 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) + portlist_tail = NULL; + } else { + for (p = portlist; (p != NULL) && (p->next != port); + p=p->next); + if (p) { + if ((p->next = port->next) == NULL) + portlist_tail = p; + } + else printk (KERN_WARNING + "%s not found in port list!\n", port->name); + } + spin_unlock(&parportlist_lock); + + if (!port->devices) + free_port (port); +} + +struct pardevice *parport_register_device(struct parport *port, const char *name, + int (*pf)(void *), void (*kf)(void *), + void (*irq_func)(int, void *, struct pt_regs *), + int flags, void *handle) +{ + struct pardevice *tmp; + + if (port->physport->flags & PARPORT_FLAG_EXCL) { + /* An exclusive device is registered. */ + printk (KERN_DEBUG "%s: no more devices allowed\n", + port->name); + return NULL; + } + + if (flags & PARPORT_DEV_LURK) { + if (!pf || !kf) { + printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name); + return NULL; + } + } + + tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); + if (tmp == NULL) { + printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); + return NULL; + } + + tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); + if (tmp->state == NULL) { + printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); + kfree(tmp); + return NULL; + } + + 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; + tmp->waiting = 0; + tmp->timeout = 5 * HZ; + + /* Chain this onto the list */ + tmp->prev = NULL; + /* + * 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->physport->pardevice_lock); + + if (flags & PARPORT_DEV_EXCL) { + if (port->physport->devices) { + spin_unlock (&port->physport->pardevice_lock); + kfree (tmp->state); + kfree (tmp); + printk (KERN_DEBUG + "%s: cannot grant exclusive access for " + "device %s\n", port->name, name); + return NULL; + } + port->flags |= PARPORT_FLAG_EXCL; + } + + 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(); + + init_waitqueue_head(&tmp->wait_q); + 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; +} + +void parport_unregister_device(struct pardevice *dev) +{ + struct parport *port; + +#ifdef PARPORT_PARANOID + if (dev == NULL) { + printk(KERN_ERR "parport_unregister_device: passed NULL\n"); + return; + } +#endif + + parport_device_proc_unregister(dev); + + port = dev->port->physport; + + if (port->cad == dev) { + printk(KERN_DEBUG "%s: %s forgot to release port\n", + port->name, dev->name); + parport_release (dev); + } + + spin_lock(&port->pardevice_lock); + if (dev->next) + dev->next->prev = dev->prev; + if (dev->prev) + dev->prev->next = dev->next; + else + port->devices = dev->next; + + if (dev->flags & PARPORT_DEV_EXCL) + port->flags &= ~PARPORT_FLAG_EXCL; + + spin_unlock(&port->pardevice_lock); + + kfree(dev->state); + kfree(dev); + + dec_parport_count(); + port->ops->dec_use_count(); + + /* If this was the last device on a port that's already gone away, + * free up the resources. */ + if (port->ops == &dead_ops && !port->devices) + free_port (port); +} + +int parport_claim(struct pardevice *dev) +{ + struct pardevice *oldcad; + 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); + return 0; + } + +try_again: + /* Preempt any current device */ + if ((oldcad = port->cad) != NULL) { + if (oldcad->preempt) { + if (oldcad->preempt(oldcad->private)) + goto blocked; + port->ops->save_state(port, dev->state); + } else + goto blocked; + + if (port->cad != oldcad) { + printk(KERN_WARNING + "%s: %s released port when preempted!\n", + port->name, oldcad->name); + if (port->cad) + goto blocked; + } + } + + /* Can't fail from now on, so mark ourselves as no longer waiting. */ + if (dev->waiting & 1) { + dev->waiting = 0; + + /* Take ourselves out of the wait list again. */ + spin_lock_irqsave (&port->waitlist_lock, flags); + if (dev->waitprev) + dev->waitprev->waitnext = dev->waitnext; + else + port->waithead = dev->waitnext; + if (dev->waitnext) + dev->waitnext->waitprev = dev->waitprev; + else + port->waittail = dev->waitprev; + spin_unlock_irqrestore (&port->waitlist_lock, flags); + dev->waitprev = dev->waitnext = NULL; + } + + /* 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; + return 0; + +blocked: + /* If this is the first time we tried to claim the port, register an + interest. This is only allowed for devices sleeping in + parport_claim_or_block(), or those with a wakeup function. */ + if (dev->waiting & 2 || dev->wakeup) { + spin_lock_irqsave (&port->waitlist_lock, flags); + if (port->cad == NULL) { + /* The port got released in the meantime. */ + spin_unlock_irqrestore (&port->waitlist_lock, flags); + goto try_again; + } + if (test_and_set_bit(0, &dev->waiting) == 0) { + /* First add ourselves to the end of the wait list. */ + dev->waitnext = NULL; + dev->waitprev = port->waittail; + if (port->waittail) { + port->waittail->waitnext = dev; + port->waittail = dev; + } else + port->waithead = port->waittail = dev; + } + spin_unlock_irqrestore (&port->waitlist_lock, flags); + } + return -EAGAIN; +} + +int parport_claim_or_block(struct pardevice *dev) +{ + int r; + + /* Signal to parport_claim() that we can wait even without a + wakeup function. */ + dev->waiting = 2; + + /* Try to claim the port. If this fails, we need to sleep. */ + r = parport_claim(dev); + if (r == -EAGAIN) { + unsigned long flags; +#ifdef PARPORT_DEBUG_SHARING + printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name); +#endif + save_flags (flags); + cli(); + /* If dev->waiting is clear now, an interrupt + gave us the port and we would deadlock if we slept. */ + if (dev->waiting) { + sleep_on(&dev->wait_q); + r = 1; + } else { + r = 0; +#ifdef PARPORT_DEBUG_SHARING + printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n", + dev->name); +#endif + } + restore_flags(flags); +#ifdef PARPORT_DEBUG_SHARING + 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; + return r; +} + +void parport_release(struct pardevice *dev) +{ + struct parport *port = dev->port->physport; + struct pardevice *pd; + unsigned long flags; + + /* Make sure that dev is the current device */ + if (port->cad != dev) { + printk(KERN_WARNING "%s: %s tried to release parport " + "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); + + /* Save control registers */ + port->ops->save_state(port, dev->state); + + /* If anybody is waiting, find out who's been there longest and + then wake them up. (Note: no locking required) */ + for (pd = port->waithead; pd; pd = pd->waitnext) { + if (pd->waiting & 2) { /* sleeping in claim_or_block */ + parport_claim(pd); + if (waitqueue_active(&pd->wait_q)) + wake_up(&pd->wait_q); + return; + } else if (pd->wakeup) { + pd->wakeup(pd->private); + if (dev->port->cad) + return; + } else { + printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name); + } + } + + /* Nobody was waiting, so walk the list to see if anyone is + interested in being woken up. */ + for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { + if (pd->wakeup && pd != dev) + pd->wakeup(pd->private); + } +} + +static int parport_parse_params (int nports, const char *str[], int val[], + int automatic, int none) +{ + unsigned int i; + for (i = 0; i < nports && str[i]; i++) { + if (!strncmp(str[i], "auto", 4)) + val[i] = automatic; + else if (!strncmp(str[i], "none", 4)) + val[i] = none; + else { + char *ep; + unsigned long r = simple_strtoul(str[i], &ep, 0); + if (ep != str[i]) + val[i] = r; + else { + printk("parport: bad specifier `%s'\n", str[i]); + return -1; + } + } + } + + return 0; +} + +int parport_parse_irqs(int nports, const char *irqstr[], int irqval[]) +{ + return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO, + PARPORT_IRQ_NONE); +} + +int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[]) +{ + return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO, + PARPORT_DMA_NONE); +} diff -u --recursive --new-file v2.3.11/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.11/linux/drivers/usb/Config.in Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/Config.in Tue Jul 27 16:05:50 1999 @@ -35,6 +35,9 @@ dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI fi dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB + if [ "$CONFIG_PROC_FS" != "n" ]; then + bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC + fi fi endmenu diff -u --recursive --new-file v2.3.11/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.11/linux/drivers/usb/Makefile Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/Makefile Tue Jul 27 16:05:50 1999 @@ -22,6 +22,9 @@ ifeq ($(CONFIG_USB),m) M_OBJS +=usbcore.o MIX_OBJS +=usb.o usb-debug.o usb-core.o + ifeq ($(CONFIG_USB_PROC),y) + MIX_OBJS += proc_usb.o + endif endif ifeq ($(CONFIG_USB_UHCI),y) @@ -153,7 +156,10 @@ usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o +ifeq ($(CONFIG_USB_PROC),y) +usbcore.o: usb.o usb-debug.o usb-core.o proc_usb.o + $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o proc_usb.o +else usbcore.o: usb.o usb-debug.o usb-core.o $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o - - +endif diff -u --recursive --new-file v2.3.11/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.11/linux/drivers/usb/cpia.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/cpia.c Mon Jul 26 16:05:45 1999 @@ -583,7 +583,7 @@ cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); if (!cpia->fbuf) - return -ENOMEM; + goto open_err_ret; cpia->frame[0].state = FRAME_DONE; cpia->frame[1].state = FRAME_DONE; @@ -595,15 +595,15 @@ cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[0].data) - return -ENOMEM; + goto open_err_on0; cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[1].data) - return -ENOMEM; + goto open_err_on1; cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[2].data) - return -ENOMEM; + goto open_err_on2; printk("sbuf[0] @ %p\n", cpia->sbuf[0].data); printk("sbuf[1] @ %p\n", cpia->sbuf[1].data); @@ -617,6 +617,15 @@ cpia_init_isoc(cpia); return 0; + +open_err_on2: + kfree (cpia->sbuf[1].data); +open_err_on1: + kfree (cpia->sbuf[0].data); +open_err_on0: + rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); +open_err_ret: + return -ENOMEM; } static void cpia_close(struct video_device *dev) diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c --- v2.3.11/linux/drivers/usb/ezusb.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/ezusb.c Wed Jul 28 10:45:39 1999 @@ -27,7 +27,6 @@ /*****************************************************************************/ -#include #include #include #include diff -u --recursive --new-file v2.3.11/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.3.11/linux/drivers/usb/hub.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/hub.c Mon Jul 26 22:37:36 1999 @@ -432,38 +432,14 @@ void usb_hub_cleanup(void) { - struct list_head *next, *tmp, *head = &all_hubs_list; - struct usb_hub *hub; - unsigned long flags, flags2; - - /* Free the resources allocated by each hub */ - spin_lock_irqsave(&hub_list_lock, flags); - spin_lock_irqsave(&hub_event_lock, flags2); - - tmp = head->next; - while (tmp != head) { - hub = list_entry(tmp, struct usb_hub, hub_list); - - next = tmp->next; - - list_del(&hub->event_list); - INIT_LIST_HEAD(&hub->event_list); - list_del(tmp); /* &hub->hub_list */ - INIT_LIST_HEAD(tmp); /* &hub->hub_list */ - - /* XXX we should disconnect each connected port here */ - - usb_release_irq(hub->dev, hub->irq_handle); - hub->irq_handle = NULL; - kfree(hub); - - tmp = next; - } - + /* + * Hub resources are freed for us by usb_deregister. It + * usb_driver_purge on every device which in turn calls that + * devices disconnect function if it is using this driver. + * The hub_disconnect function takes care of releasing the + * individual hub resources. -greg + */ usb_deregister(&hub_driver); - - spin_unlock_irqrestore(&hub_event_lock, flags2); - spin_unlock_irqrestore(&hub_list_lock, flags); } /* usb_hub_cleanup() */ #ifdef MODULE diff -u --recursive --new-file v2.3.11/linux/drivers/usb/inits.h linux/drivers/usb/inits.h --- v2.3.11/linux/drivers/usb/inits.h Mon May 31 09:01:50 1999 +++ linux/drivers/usb/inits.h Tue Jul 27 16:05:50 1999 @@ -5,3 +5,5 @@ int usb_printer_init(void); void usb_hub_cleanup(void); void usb_mouse_cleanup(void); +int proc_usb_init (void); +void proc_usb_cleanup (void); diff -u --recursive --new-file v2.3.11/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c --- v2.3.11/linux/drivers/usb/mouse.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/mouse.c Sun Jul 25 20:30:46 1999 @@ -336,15 +336,15 @@ { struct mouse_state *mouse = &static_mouse_state; - misc_register(&usb_mouse); - mouse->present = mouse->active = 0; mouse->irq_handle = NULL; init_waitqueue_head(&mouse->wait); mouse->fasync = NULL; + misc_register(&usb_mouse); + usb_register(&mouse_driver); - printk(KERN_INFO "USB HID boot protocol mouse registered.\n"); + printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n"); return 0; } diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c --- v2.3.11/linux/drivers/usb/ohci-debug.c Thu Jul 8 15:42:21 1999 +++ linux/drivers/usb/ohci-debug.c Sun Jul 25 20:30:46 1999 @@ -131,7 +131,18 @@ printk(KERN_DEBUG " next_td = 0x%x\n", le32_to_cpup(&td->next_td)); printk(KERN_DEBUG " buf_end = 0x%x\n", le32_to_cpup(&td->buf_end)); printk(KERN_DEBUG " ohci TD driver fields:\n"); + printk(KERN_DEBUG " flags = %x {", td->hcd_flags); + if (td_allocated(*td)) + printk(" alloc"); + if (td_dummy(*td)) + printk(" dummy"); + if (td_endofchain(*td)) + printk(" endofchain"); + if (!can_auto_free(*td)) + printk(" noautofree"); + printk("}\n"); printk(KERN_DEBUG " data = %p\n", td->data); + printk(KERN_DEBUG " cmpltd = %p\n", td->completed); printk(KERN_DEBUG " dev_id = %p\n", td->dev_id); printk(KERN_DEBUG " ed = %p\n", td->ed); if (td->data != NULL) { diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c --- v2.3.11/linux/drivers/usb/ohci.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/ohci.c Sun Jul 25 20:30:46 1999 @@ -111,8 +111,8 @@ * * This function can be called by the interrupt handler. */ -static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td, - struct ohci_td *last_td, struct ohci_ed *ed) +static struct ohci_td *ohci_add_tds_to_ed(struct ohci_td *td, + struct ohci_ed *ed) { struct ohci_td *t, *dummy_td; u32 new_dummy; @@ -127,14 +127,14 @@ for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) { t->ed = ed; - if (t == last_td) + if (t->next_td == 0) break; } /* Make the last TD point back to the first, since it * will become the new dummy TD. */ new_dummy = cpu_to_le32(virt_to_bus(td)); - last_td->next_td = new_dummy; + t->next_td = new_dummy; /* Copy the contents of the first TD into the dummy */ *dummy_td = *td; @@ -146,34 +146,7 @@ ed->tail_td = new_dummy; return dummy_td; /* replacement head of chain */ -} /* ohci_add_td_to_ed() */ - - -/* - * Add a whole chain of TDs to an ED using the above function. - * The same restrictions apply. - * - * XXX This function is being removed in the future! XXX - */ -static struct ohci_td *ohci_add_td_chain_to_ed(struct ohci_td *td, struct ohci_ed *ed) -{ - struct ohci_td *cur_td; - if (!td) - return NULL; - - /* Find the last TD in this chain, storing its pointer in cur_td */ - cur_td = td; - for (;;) { - __u32 next_td = cur_td->next_td; - - /* advance to the next td, exit if there isn't one */ - if (!next_td) - break; - cur_td = bus_to_virt(le32_to_cpup(&next_td)); - } - - return td = ohci_add_td_to_ed(td, cur_td, ed); -} /* ohci_add_td_chain_to_ed() */ +} /* ohci_add_tds_to_ed() */ /* .......... */ @@ -261,6 +234,7 @@ */ int_ed = &root_hub->ed[ms_to_ed_int(period)]; #ifdef OHCI_DEBUG + if (MegaDebug) printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n", ms_to_ed_int(period), period); #endif @@ -278,6 +252,42 @@ } /* ohci_add_periodic_ed() */ /* + * Locate the periodic ED for a given interrupt endpoint. + */ +struct ohci_ed *ohci_get_periodic_ed(struct ohci_device *dev, int period, + unsigned int pipe, int isoc) +{ + struct ohci_device *root_hub = usb_to_ohci(dev->ohci->bus->root_hub); + unsigned long flags; + struct ohci_ed *int_ed; + unsigned int status, req_status; + + /* get the dummy ED before the EDs for this period */ + int_ed = &root_hub->ed[ms_to_ed_int(period)]; + + /* decide on what the status field should look like */ + req_status = ed_set_maxpacket(usb_maxpacket(ohci_to_usb(dev), pipe)) + | ed_set_speed(usb_pipeslow(pipe)) + | (usb_pipe_endpdev(pipe) & 0x7ff) + | ed_set_type_isoc(isoc); + + spin_lock_irqsave(&ohci_edtd_lock, flags); + for (;;) { + int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed)); + /* stop if we get to the end or to another dummy ED. */ + if (int_ed == 0) + break; + status = le32_to_cpup(&int_ed->status); + if ((status & OHCI_ED_FA) == 0) + break; + /* check whether all the appropriate fields match */ + if ((status & 0x7ffa7ff) == req_status) + return int_ed; + } + return 0; +} + +/* * Put an isochronous ED on the controller's list */ inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed) @@ -507,6 +517,7 @@ /* set the controller to skip this one and remove it from the list */ ed->status |= cpu_to_le32(OHCI_ED_SKIP); + /* XXX should call td->completed for each td */ *prevp = ed->next_ed; removed = 1; } else { @@ -670,6 +681,7 @@ new_ed->status |= cpu_to_le32(OHCI_ED_SKIP); /* mark it as allocated */ allocate_ed(new_ed); + new_ed->ohci_dev = dev; return new_ed; } } @@ -722,7 +734,7 @@ flags); td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data)); td->buf_end = (len == 0) ? 0 : - cpu_to_le32(le32_to_cpup(&td->cur_buf) + len - 1); + cpu_to_le32(virt_to_bus((char *)data + len - 1)); /* driver fields */ td->data = data; @@ -789,31 +801,24 @@ * * Returns the head TD in the chain. */ -struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigned int len, int dir, __u32 toggle, int round, int auto_free, void* dev_id, usb_device_irq handler, __u32 next_td) +struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, + void *data, unsigned int len, int dir, __u32 toggle, + int round, int auto_free, void* dev_id, + usb_device_irq handler, __u32 next_td) { struct ohci_td *head, *cur_td; - __u32 bus_data_start, bus_data_end; - unsigned short max_page0_len; + unsigned max_len; if (!data || (len == 0)) return NULL; - /* Setup the first TD, leaving buf_end = 0 */ + /* Get the first TD */ head = ohci_get_free_td(dev); if (head == NULL) { printk(KERN_ERR "usb-ohci: out of TDs\n"); return NULL; } - ohci_fill_new_td(head, - td_set_dir_out(dir), - toggle & OHCI_TD_DT, - (round ? OHCI_TD_ROUND : 0), - data, 0, - dev_id, handler); - if (!auto_free) - noauto_free_td(head); - cur_td = head; /* AFICT, that the OHCI controller takes care of the innards of @@ -821,66 +826,60 @@ * packets as necessary if the transfer falls on an even packet * size boundary, we don't need a special TD for that. */ - while (len > 0) { - bus_data_start = virt_to_bus(data); - bus_data_end = virt_to_bus(data+(len-1)); - - /* check the 4096 byte alignment of the start of the data */ - max_page0_len = 0x1000 - (bus_data_start & 0xfff); - - /* check if the remaining data occupies more than two pages */ - if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) { - struct ohci_td *new_td; - - /* Point this TD to data up through the end of - * the second page */ - cur_td->buf_end = bus_data_start + - (max_page0_len + 0xfff); - - /* adjust the data pointer & remaining length */ - data += (max_page0_len + 0x1000); - len -= (max_page0_len + 0x1000); - - /* TODO lookup effect of rounding bit on - * individual TDs vs. whole TD chain transfers; - * disable cur_td's rounding bit here if needed. */ - - /* mark that this is not the last TD... */ - clear_td_endofchain(cur_td); - - /* allocate another td */ - new_td = ohci_get_free_td(dev); - if (new_td == NULL) { - printk(KERN_ERR "usb-ohci: out of TDs\n"); - /* FIXME: free any allocated TDs */ - return NULL; - } + /* check the 4096 byte alignment of the start of the data */ + max_len = 0x2000 - ((unsigned long)data & 0xfff); - ohci_fill_new_td(new_td, - td_set_dir_out(dir), - TOGGLE_AUTO, /* toggle Data0/1 via the ED */ - round ? OHCI_TD_ROUND : 0, - data, 0, - dev_id, handler); - if (!auto_free) - noauto_free_td(new_td); - - /* Link the new TD to the chain & advance */ - cur_td->next_td = virt_to_bus(new_td); - cur_td = new_td; - } else { - /* Last TD in this chain, normal buf_end is fine */ - cur_td->buf_end = bus_data_end; - - set_td_endofchain(cur_td); + /* check if the remaining data occupies more than two pages */ + while (len > max_len) { + struct ohci_td *new_td; + + /* TODO lookup effect of rounding bit on + * individual TDs vs. whole TD chain transfers; + * disable cur_td's rounding bit here if needed. */ + + ohci_fill_new_td(cur_td, + td_set_dir_out(dir), + toggle & OHCI_TD_DT, + (round ? OHCI_TD_ROUND : 0), + data, max_len - 1, + dev_id, handler); + if (!auto_free) + noauto_free_td(head); + + /* adjust the data pointer & remaining length */ + data += max_len; + len -= max_len; + + /* allocate another td */ + new_td = ohci_get_free_td(dev); + if (new_td == NULL) { + printk(KERN_ERR "usb-ohci: out of TDs\n"); + /* FIXME: free any allocated TDs */ + return NULL; + } + + /* Link the new TD to the chain & advance */ + cur_td->next_td = cpu_to_le32(virt_to_bus(new_td)); + cur_td = new_td; + + /* address is page-aligned now */ + max_len = 0x2000; + toggle = TOGGLE_AUTO; /* toggle Data0/1 via the ED */ + } - len = 0; - break; - } - } /* while */ + ohci_fill_new_td(cur_td, + td_set_dir_out(dir), + toggle & OHCI_TD_DT, + (round ? OHCI_TD_ROUND : 0), + data, len, + dev_id, handler); + if (!auto_free) + noauto_free_td(head); /* link the given next_td to the end of this chain */ - cur_td->next_td = next_td; + cur_td->next_td = cpu_to_le32(next_td); + if (next_td == 0) + set_td_endofchain(cur_td); return head; } /* ohci_build_td_chain() */ @@ -902,10 +901,10 @@ /* if cur_buf is 0, all data has been transferred */ if (!td->cur_buf) { - return td->buf_end - bus_data_start + 1; + return le32_to_cpup(&td->buf_end) - bus_data_start + 1; } - bus_data_end = td->cur_buf; + bus_data_end = le32_to_cpup(&td->cur_buf); /* is it on the same page? */ if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) { @@ -945,13 +944,36 @@ struct ohci_td *td; struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ int maxps = usb_maxpacket(usb, pipe); + unsigned long flags; /* Get an ED and TD */ - interrupt_ed = ohci_get_free_ed(dev); - if (!interrupt_ed) { - printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev); - return NULL; + interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0); + if (interrupt_ed == 0) { + interrupt_ed = ohci_get_free_ed(dev); + if (!interrupt_ed) { + printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev); + return NULL; + } + + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + */ + ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), 0 /* normal TDs */); + interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); + + /* Assimilate the new ED into the collective */ + ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); } +#ifdef OHCI_DEBUG + if (MegaDebug) { + printk(KERN_DEBUG "ohci_request irq: using ED %p [%x %x %x %x]\n", + interrupt_ed, FIELDS_OF_ED(interrupt_ed)); + printk(KERN_DEBUG " for dev %d pipe %x period %d\n", usb->devnum, + pipe, period); + } +#endif td = ohci_get_free_td(dev); if (!td) { @@ -960,13 +982,6 @@ return NULL; } - /* - * Set the max packet size, device speed, endpoint number, usb - * device number (function address), and type of TD. - */ - ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe), - usb_pipe_endpdev(pipe), 0 /* normal TDs */); - /* Fill in the TD */ if (maxps > sizeof(dev->data)) maxps = sizeof(dev->data); @@ -975,20 +990,15 @@ OHCI_TD_ROUND, dev->data, maxps, dev_id, handler); + set_td_endofchain(td); /* * Put the TD onto our ED and make sure its ready to run */ - td = ohci_add_td_to_ed(td, td, interrupt_ed); - interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - ohci_unhalt_ed(interrupt_ed); - - /* Make sure all the stores above get done before - * the store which tells the OHCI about the new ed. */ - wmb(); - - /* Assimilate the new ED into the collective */ - ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); + td->next_td = 0; + spin_lock_irqsave(&ohci_edtd_lock, flags); + td = ohci_add_tds_to_ed(td, interrupt_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); return (void*)td; } /* ohci_request_irq() */ @@ -1148,6 +1158,7 @@ 0 /* flags */, NULL /* data */, 0 /* data len */, &completion_status, ohci_control_completed); + set_td_endofchain(status_td); status_td->next_td = 0; /* end of TDs */ /* If there is data to transfer, create the chain of data TDs @@ -1167,18 +1178,18 @@ } /* link the to the data & status TDs */ - setup_td->next_td = virt_to_bus(data_td); + setup_td->next_td = cpu_to_le32(virt_to_bus(data_td)); } else { /* no data TDs, link to the status TD */ - setup_td->next_td = virt_to_bus(status_td); + setup_td->next_td = cpu_to_le32(virt_to_bus(status_td)); } /* * Add the control TDs to the control ED (setup_td is the first) */ - setup_td = ohci_add_td_chain_to_ed(setup_td, control_ed); - control_ed->status &= ~OHCI_ED_SKIP; - ohci_unhalt_ed(control_ed); + setup_td = ohci_add_tds_to_ed(setup_td, control_ed); + control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); + /* ohci_unhalt_ed(control_ed); */ #ifdef OHCI_DEBUG if (MegaDebug) { @@ -1201,35 +1212,34 @@ /* Give the ED to the HC */ ohci_add_control_ed(dev->ohci, control_ed); - schedule_timeout(HZ/10); + schedule_timeout(HZ); remove_wait_queue(&control_wakeup, &wait); #ifdef OHCI_DEBUG - if (MegaDebug) { - /* complete transaction debugging output (after) */ - printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); - show_ohci_ed(control_ed); - printk(KERN_DEBUG " *after* Control TD chain:\n"); - show_ohci_td_chain(setup_td); - printk(KERN_DEBUG " *after* OHCI Controller Status:\n"); - show_ohci_status(dev->ohci); - } -#endif - - /* no TD cleanup, the TDs were auto-freed as they finished */ - - /* remove the control ED from the HC */ - ohci_remove_control_ed(dev->ohci, control_ed); - ohci_free_ed(control_ed); /* return it to the pool */ - -#ifdef OHCI_DEBUG if (completion_status != 0) { const char *what = (completion_status < 0)? "timed out": cc_names[completion_status & 0xf]; - printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n", + printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x", what, pipe, cmd->requesttype, cmd->request, cmd->value, cmd->index, cmd->length); + if (usb_pipeout(pipe) && len > 0) { + int i; + printk(" data"); + for (i = 0; i < 16 && i < len; ++i) + printk(" %.2x", ((unsigned char *)data)[i]); + if (i < len) + printk(" ..."); + } + printk("\n"); + if (MegaDebug && completion_status < 0) { + printk(KERN_DEBUG "control_ed at %p:\n", control_ed); + show_ohci_ed(control_ed); + if (ed_head_td(control_ed) != ed_tail_td(control_ed)) + show_ohci_td_chain(bus_to_virt(ed_head_td(control_ed))); + printk(KERN_DEBUG "setup TD at %p:\n", setup_td); + show_ohci_td(setup_td); + } } else if (!usb_pipeout(pipe)) { unsigned char *q = data; int i; @@ -1243,7 +1253,26 @@ } printk("\n"); } + + if (MegaDebug) { + /* complete transaction debugging output (after) */ + printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " *after* Control TD chain:\n"); + show_ohci_td_chain(setup_td); + printk(KERN_DEBUG " *after* OHCI Controller Status:\n"); + show_ohci_status(dev->ohci); + } #endif + + /* no TD cleanup, the TDs were auto-freed as they finished */ + + /* remove the control ED from the HC */ + ohci_remove_control_ed(dev->ohci, control_ed); + ohci_free_ed(control_ed); /* return it to the pool */ + + if (completion_status < 0) + completion_status = USB_ST_TIMEOUT; return completion_status; } /* ohci_control_msg() */ @@ -1278,6 +1307,7 @@ req = (struct ohci_bulk_request_state *) dev_id; #ifdef OHCI_DEBUG + if (MegaDebug) printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req); #endif @@ -1285,11 +1315,24 @@ if (stats == USB_ST_NOERROR) req->_bytes_done += len; +#ifdef OHCI_DEBUG + if (MegaDebug && req->_bytes_done) { + int i; + printk(KERN_DEBUG " %d bytes, bulk data:", req->_bytes_done); + for (i = 0; i < 16 && i < req->_bytes_done; ++i) + printk(" %.2x", ((unsigned char *)buffer)[i]); + if (i < req->_bytes_done) + printk(" ..."); + printk("\n"); + } +#endif + /* call the real completion handler when done or on an error */ if ((stats != USB_ST_NOERROR) || (req->_bytes_done >= req->length && req->completion != NULL)) { *req->bytes_transferred_p += req->_bytes_done; #ifdef OHCI_DEBUG + if (MegaDebug) printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req); #endif req->completion(stats, buffer, req->_bytes_done, req->dev_id); @@ -1305,7 +1348,7 @@ * to an error. * * bytes_transferred_p is a pointer to an integer that will be - * -incremented- by the number of bytes that have been successfully + * set to the number of bytes that have been successfully * transferred. The interrupt handler will update it after each * internal TD completes successfully. * @@ -1329,6 +1372,7 @@ unsigned long flags; #ifdef OHCI_DEBUG + if (MegaDebug) printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len); #endif @@ -1358,6 +1402,10 @@ usb_pipeslow(pipe), usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */); + /* initialize the toggle carry */ + if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) + ohci_ed_set_carry(bulk_ed); + /* initialize the internal counter */ bulk_request->_bytes_done = 0; @@ -1365,13 +1413,11 @@ * Add the TDs to the ED */ spin_lock_irqsave(&ohci_edtd_lock, flags); - bulk_ed->status |= OHCI_ED_SKIP; - head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed); - bulk_ed->status &= ~OHCI_ED_SKIP; - ohci_unhalt_ed(bulk_ed); + head_td = ohci_add_tds_to_ed(head_td, bulk_ed); + bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); + /* ohci_unhalt_ed(bulk_ed); */ spin_unlock_irqrestore(&ohci_edtd_lock, flags); - #ifdef OHCI_DEBUG if (MegaDebug) { /* complete request debugging output (before) */ @@ -1414,7 +1460,8 @@ struct ohci_bulk_request_state req; struct ohci_ed *req_ed; -#ifdef OHCI_DEBUG +#ifdef OHCI_DEBUG + if (MegaDebug) printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p); #endif @@ -1430,6 +1477,12 @@ req.bytes_transferred_p = bytes_transferred_p; req.dev_id = &completion_status; req.completion = ohci_bulk_msg_completed; + if (bytes_transferred_p) + *bytes_transferred_p = 0; + + if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe)) + && usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80))) + return USB_ST_STALL; /* * Start the transaction.. @@ -1442,7 +1495,8 @@ /* FIXME this should to wait for a caller specified time... */ schedule_timeout(HZ*5); - /* it'll only stay in this state of the request never finished */ + /* completion_status will only stay in this state of the + * request never finished */ if (completion_status == USB_ST_INTERNALERROR) { struct ohci_device *dev = usb_to_ohci(usb_dev); struct ohci_regs *regs = dev->ohci->regs; @@ -1485,9 +1539,15 @@ /* remove the ED from the HC */ ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed); + + /* save the toggle value back into the usb_dev */ + usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), + ohci_ed_carry(req_ed)); + ohci_free_ed(req_ed); /* return it to the pool */ #ifdef OHCI_DEBUG + if (completion_status != 0 || MegaDebug) printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p); #endif @@ -1659,7 +1719,6 @@ struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - fminterval = readl(&ohci->regs->fminterval) & 0x3fff; #if 0 printk(KERN_DEBUG "entering start_hc %p\n", ohci); #endif @@ -1671,16 +1730,22 @@ writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca); /* - * XXX Should fminterval also be set here? - * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant) + * fminterval has to be 11999 (it can be adjusted +/- 1 + * to sync with other things if necessary). */ - /* fminterval |= (0x2edf << 16); */ - fminterval = (10240 << 16) | 11999; - writel(fminterval, &ohci->regs->fminterval); + fminterval = 11999; + /* Start periodic transfers at 90% of fminterval (fmremaining * counts down; this will put them in the first 10% of the * frame). */ - writel((0x2edf*9)/10, &ohci->regs->periodicstart); + writel((fminterval * 9) / 10, &ohci->regs->periodicstart); + + /* Set largest data packet counter and frame interval. */ + fminterval |= ((fminterval - 210) * 6 / 7) << 16; + writel(fminterval, &ohci->regs->fminterval); + + /* Set low-speed threshold (value from MacOS) */ + writel(1576, &ohci->regs->lsthresh); /* * FNO (frame number overflow) could be enabled... they @@ -1926,7 +1991,8 @@ struct ohci_td *td; /* used for walking the list */ /* um... isn't this dangerous to do in an interrupt handler? -greg */ -// spin_lock(&ohci_edtd_lock); + /* nope. -paulus */ + spin_lock(&ohci_edtd_lock); /* create the FIFO ordered donelist */ td = ohci_reverse_donelist(ohci); @@ -1934,18 +2000,33 @@ while (td != NULL) { struct ohci_td *next_td = td->next_dl_td; int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info)); + struct ohci_ed *ed = td->ed; if (td_dummy(*td)) printk(KERN_ERR "yikes! reaping a dummy TD\n"); - if (cc != 0 && ohci_ed_halted(td->ed) && !td_endofchain(*td)) { +#ifdef OHCI_DEBUG + if (cc != 0 && MegaDebug) { + printk("cc=%s on td %p (ed %p)\n", cc_names[cc], td, ed); + show_ohci_td(td); + show_ohci_ed(ed); + if (ed_head_td(ed) != ed_tail_td(ed)) + show_ohci_td_chain(bus_to_virt(ed_head_td(ed))); + } +#endif + + if (cc == USB_ST_STALL) { + /* mark endpoint as halted */ + usb_endpoint_halt(ed->ohci_dev->usb, ed_get_en(ed)); + } + + if (cc != 0 && ohci_ed_halted(ed) && !td_endofchain(*td)) { /* * There was an error on this TD and the ED * is halted, and this was not the last TD * of the transaction, so there will be TDs * to clean off the ED. */ - struct ohci_ed *ed = td->ed; struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed)); struct ohci_td *ntd; @@ -1953,24 +2034,17 @@ td = ntd = bus_to_virt(ed_head_td(ed)); while (td != tail_td) { ntd = bus_to_virt(le32_to_cpup(&td->next_td)); + if (td_endofchain(*td)) + break; - /* only deal with TDs from this ED, - * the host controller could have - * processed other endpoints at the - * same time as this one.. */ - if (td->ed == ed) { - if (td_endofchain(*td)) - break; - - /* FIXME: unlink this TD from the - * reverse donelist! */ - ohci_free_td(td); - } + printk(KERN_DEBUG "skipping TD %p\n", td); + ohci_free_td(td); td = ntd; } /* Set the ED head past the ones we cleaned off, and clear the halted flag */ + printk(KERN_DEBUG "restarting ED %p at TD %p\n", ed, ntd); set_ed_head_td(ed, virt_to_bus(ntd)); ohci_unhalt_ed(ed); /* If we didn't find an endofchain TD, give up */ @@ -1996,8 +2070,9 @@ td->cur_buf = cpu_to_le32(virt_to_bus(td->data)); /* insert it back on its ED */ - ohci_add_td_to_ed(td, td, td->ed); - ohci_unhalt_ed(td->ed); + td->next_td = 0; + ohci_add_tds_to_ed(td, ed); + /* ohci_unhalt_ed(td->ed); */ } else { /* return it to the pool of free TDs */ if (can_auto_free(*td)) @@ -2007,7 +2082,7 @@ td = next_td; } -// spin_unlock(&ohci_edtd_lock); + spin_unlock(&ohci_edtd_lock); } /* ohci_reap_donelist() */ @@ -2259,8 +2334,10 @@ writel(0, &ohci->regs->ed_bulkhead); #ifdef OHCI_DEBUG + if (MegaDebug) { printk(KERN_DEBUG "alloc_ohci(): controller\n"); show_ohci_status(ohci); + } #endif #if 0 @@ -2333,7 +2410,7 @@ printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread); exit_mm(current); exit_files(current); - exit_fs(current); + /*exit_fs(current);*/ /* can't do kernel_thread if we do this */ strcpy(current->comm, "ohci-control"); @@ -2398,6 +2475,7 @@ #endif } else { /* unknown signal, exit the thread */ + printk(KERN_DEBUG "usb-ohci: control thread for %p exiting on signal %ld\n", __ohci, signr); break; } } @@ -2406,7 +2484,6 @@ reset_hc(ohci); release_ohci(ohci); usb_deregister_bus(ohci->bus); - printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci); return 0; } /* ohci_control_thread() */ diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h --- v2.3.11/linux/drivers/usb/ohci.h Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/ohci.h Sun Jul 25 20:30:46 1999 @@ -41,8 +41,7 @@ /* bit0: Is this TD allocated? */ /* bit1: Is this a dummy (end of list) TD? */ /* bit2: do NOT automatically free this TD on completion */ - /* bit3: this is NOT the last TD in a contiguious TD chain - * on the indicated ED. (0 means it is the last) */ + /* bit3: this is the last TD in a contiguious TD chain */ struct usb_device *usb_dev; /* the owning device */ @@ -86,9 +85,9 @@ #define make_dumb_td(td) ((td)->hcd_flags |= 2) #define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2) -#define td_endofchain(td) (!((td).hcd_flags & (1 << 3))) -#define set_td_endofchain(td) ((td)->hcd_flags &= ~(1 << 3)) -#define clear_td_endofchain(td) ((td)->hcd_flags |= (1 << 3)) +#define td_endofchain(td) ((td).hcd_flags & (1 << 3)) +#define clear_td_endofchain(td) ((td)->hcd_flags &= ~(1 << 3)) +#define set_td_endofchain(td) ((td)->hcd_flags |= (1 << 3)) /* * These control if the IRQ will call ohci_free_td after taking the TDs @@ -109,6 +108,10 @@ __u32 tail_td; /* TD Queue tail pointer */ __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */ __u32 next_ed; /* Next ED */ + + /* driver fields */ + struct ohci_device *ohci_dev; + struct ohci_ed *ed_chain; } __attribute((aligned(16))); /* get the head_td */ @@ -119,10 +122,13 @@ #define set_ed_head_td(ed, td) ((ed)->_head_td = cpu_to_le32((td)) \ | ((ed)->_head_td & cpu_to_le32(3))) -/* Control the ED's halted flag */ +/* Control the ED's halted and carry flags */ #define ohci_halt_ed(ed) ((ed)->_head_td |= cpu_to_le32(1)) #define ohci_unhalt_ed(ed) ((ed)->_head_td &= cpu_to_le32(~(__u32)1)) #define ohci_ed_halted(ed) ((ed)->_head_td & cpu_to_le32(1)) +#define ohci_ed_set_carry(ed) ((ed)->_head_td |= cpu_to_le32(2)) +#define ohci_ed_clr_carry(ed) ((ed)->_head_td &= ~cpu_to_le32(2)) +#define ohci_ed_carry(ed) ((le32_to_cpup(&(ed)->_head_td) >> 1) & 1) #define OHCI_ED_SKIP (1 << 14) #define OHCI_ED_MPS (0x7ff << 16) @@ -142,6 +148,8 @@ #define OHCI_ED_EN (0xf << 7) #define OHCI_ED_FA (0x7f) +#define ed_get_en(ed) ((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7) +#define ed_get_fa(ed) (le32_to_cpup(&(ed)->status) & OHCI_ED_FA) /* NOTE: bits 27-31 of the status dword are reserved for the HCD */ /* diff -u --recursive --new-file v2.3.11/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c --- v2.3.11/linux/drivers/usb/proc_usb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/proc_usb.c Wed Jul 28 10:45:39 1999 @@ -0,0 +1,487 @@ +/* + * drivers/usb/proc_usb.c + * (C) Copyright 1999 Randy Dunlap. + * + * 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 + * + ************************************************************* + * + * This is a /proc/bus/usb filesystem output module for USB. + * It creates /proc/bus/usb/drivers and /proc/bus/usb/devices. + * + * /proc/bus/usb/devices contains USB topology, device, config, class, + * interface, & endpoint data. + * + * I considered using /proc/bus/usb/devices/device# for each device + * as it is attached or detached, but I didn't like this for some + * reason -- maybe it's just too deep of a directory structure. + * I also don't like looking in multiple places to gather and view + * the data. Having only one file for ./devices also prevents race + * conditions that could arise if a program was reading device info + * for devices that are being removed (unplugged). (That is, the + * program may find a directory for devnum_12 then try to open it, + * but it was just unplugged, so the directory is now deleted. + * But programs would just have to be prepared for situations like + * this in any plug-and-play environment.) + */ + +#define __KERNEL__ 1 + +#include +#include +#include +/* #include */ +#include +#include +#include +#include +#include + +#include "usb.h" + +#define DUMP_LIMIT (PAGE_SIZE - 100) + /* limit to only one memory page of output */ + +#define MAX_TOPO_LEVEL 6 + + +static char *format_topo = +/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */ + "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n"; + +static char *format_device1 = +/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */ + "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n"; + +static char *format_device2 = +/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */ + "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n"; + +static char *format_config = +/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */ + "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n"; + +static char *format_iface = +/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */ + "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; + +static char *format_endpt = +/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */ + "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n"; + + +/* + * Need access to the driver and USB bus lists. + * extern struct list_head usb_driver_list; + * extern struct list_head usb_bus_list; + * However, these will come from functions that return ptrs to each of them. + */ + +extern struct list_head *usb_driver_get_list (void); +extern struct list_head *usb_bus_get_list (void); + +extern struct proc_dir_entry *proc_bus; + +static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL; +static struct proc_dir_entry *devicesdir = NULL; + +struct class_info { + int class; + char *class_name; +}; + +struct class_info clas_info [] = +{ /* max. 5 chars. per name string */ + {USB_CLASS_PER_INTERFACE, ">ifc"}, + {USB_CLASS_AUDIO, "audio"}, + {USB_CLASS_COMM, "comm."}, + {USB_CLASS_HID, "HID"}, + {USB_CLASS_HUB, "hub"}, + {USB_CLASS_PRINTER, "print"}, + {USB_CLASS_MASS_STORAGE, "stor."}, + {USB_CLASS_VENDOR_SPEC, "vend."}, + {-1, "unk."} /* leave as last */ +}; + +/*****************************************************************/ + +static char *class_decode (const int class) +{ + int ix; + + for (ix = 0; clas_info [ix].class != -1; ix++) + if (clas_info [ix].class == class) + break; + + return (clas_info [ix].class_name); +} +static int usb_dump_endpoint_descriptor (const struct usb_endpoint_descriptor *desc, + char *buf, int *len) +{ + char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."}; + + *len += sprintf (buf + *len, format_endpt, + desc->bEndpointAddress, + (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O', + desc->bmAttributes, + EndpointType[desc->bmAttributes & 3], + desc->wMaxPacketSize, + desc->bInterval + ); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint, + char *buf, int *len) +{ + if (usb_dump_endpoint_descriptor (endpoint, buf, len) < 0) + return -1; + + return 0; +} + +static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc, + char *buf, int *len) +{ + *len += sprintf (buf + *len, format_iface, + desc->bInterfaceNumber, + desc->bAlternateSetting, + desc->bNumEndpoints, + desc->bInterfaceClass, + class_decode (desc->bInterfaceClass), + desc->bInterfaceSubClass, + desc->bInterfaceProtocol + ); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +static int usb_dump_interface (const struct usb_interface_descriptor *interface, + char *buf, int *len) +{ + int i; + + if (usb_dump_interface_descriptor (interface, buf, len) < 0) + return -1; + + for (i = 0; i < interface->bNumEndpoints; i++) { + if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0) + return -1; + } + + return 0; +} + +/* TBD: + * 0. TBDs + * 1. marking active config and ifaces (code lists all, but should mark + * which ones are active, if any) + * 2. Add proc_usb_init() call from usb-core.c. + * 3. proc_usb as a MODULE ? + * 4. use __initfunc() ? + * 5. add status to each endpoint line + */ + +static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc, + const int active, char *buf, int *len) +{ + *len += sprintf (buf + *len, format_config, + active ? '*' : ' ', /* mark active/actual/current cfg. */ + desc->bNumInterfaces, + desc->bConfigurationValue, + desc->bmAttributes, + desc->MaxPower * 2 + ); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +static int usb_dump_config (const struct usb_config_descriptor *config, + const int active, char *buf, int *len) +{ + int i, j; + struct usb_alternate_setting *as; + + if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */ + *len += sprintf (buf + *len, "(null Cfg. desc.)\n"); + return 0; + } + + if (usb_dump_config_descriptor (config, active, buf, len) < 0) + return -1; + + for (i = 0; i < config->num_altsetting; i++) { + as = config->altsetting + i; + if ((as) == NULL) + break; + + for (j = 0; j < config->bNumInterfaces; j++) + if (usb_dump_interface (as->interface + j, buf, len) < 0) + return -1; + } + + return 0; +} + +/* + * Dump the different USB descriptors. + */ +static int usb_dump_device_descriptor (const struct usb_device_descriptor *desc, + char *buf, int *len) +{ + *len += sprintf (buf + *len, format_device1, + desc->bcdUSB >> 8, desc->bcdUSB & 0xff, + desc->bDeviceClass, + class_decode (desc->bDeviceClass), + desc->bDeviceSubClass, + desc->bDeviceProtocol, + desc->bMaxPacketSize0, + desc->bNumConfigurations + ); + if (*len >= DUMP_LIMIT) return -1; + + *len += sprintf (buf + *len, format_device2, + desc->idVendor, desc->idProduct, + desc->bcdDevice >> 8, desc->bcdDevice & 0xff + ); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len) +{ + int i; + + if (usb_dump_device_descriptor (&dev->descriptor, buf, len) < 0) + return -1; + + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + if (usb_dump_config (dev->config + i, + (dev->config + i) == dev->actconfig, /* active ? */ + buf, len) < 0) + return -1; + } + + return 0; +} + +#ifdef PROC_EXTRA /* TBD: may want to add this code later */ + +static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc, + char *buf, int *len) +{ + int leng = USB_DT_HUB_NONVAR_SIZE; + unsigned char *ptr = (unsigned char *) desc; + + *len += sprintf (buf + *len, "Interface:"); + + while (leng) { + *len += sprintf (buf + *len, " %02x", *ptr); + ptr++; leng--; + } + *len += sprintf (buf + *len, "\n"); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +static int usb_dump_string (const struct usb_device *dev, char *id, int index, + char *buf, int *len) +{ + if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index]) + *len += sprintf (buf + *len, "%s: %s ", id, dev->stringindex[index]); + + return (*len >= DUMP_LIMIT) ? -1 : 0; +} + +#endif /* PROC_EXTRA */ + +/*****************************************************************/ + +static int usb_device_dump (char *buf, int *len, + const struct usb_device *usbdev, + int level, int index, int count) +{ + int chix; + int cnt = 0; + int parent_devnum; + + if (level > MAX_TOPO_LEVEL) return -1; + + parent_devnum = usbdev->parent ? (usbdev->parent->devnum == -1) ? 0 + : usbdev->parent->devnum : 0; + /* + * So the root hub's parent is 0 and any device that is + * plugged into the root hub has a parent of 0. + */ + *len += sprintf (buf + *len, format_topo, + level, parent_devnum, index, count, + usbdev->devnum, + usbdev->slow ? "1.5" : "12 ", + usbdev->ifnum, usbdev->maxchild, + usbdev->driver ? usbdev->driver->name : + (level == 0) ? "(root hub)" : "(none)" + ); + /* + * level = topology-tier level; + * parent_devnum = parent device number; + * index = parent's connector number; + * count = device count at this level + */ + + if (*len >= DUMP_LIMIT) + return -1; + + if (usbdev->devnum > 0) { /* for any except root hub */ + if (usb_dump_desc (usbdev, buf, len) < 0) + return -1; + } + + /* Now look at all of this device's children. */ + for (chix = 0; chix < usbdev->maxchild; chix++) { + if (usbdev->children [chix]) { + if (usb_device_dump (buf, len, + usbdev->children [chix], + level + 1, chix, ++cnt) < 0) + return -1; + } + } + + return 0; +} + +static int usb_bus_list_dump (char *buf, int len) +{ + struct list_head *usb_bus_list = usb_bus_get_list (); + struct list_head *list = usb_bus_list->next; + + len = 0; + + /* + * Go thru each usb_bus. Within each usb_bus: each usb_device. + * Within each usb_device: all of its device & config. descriptors, + * marking the currently active ones. + */ + + + while (list != usb_bus_list) { + struct usb_bus *bus = list_entry (list, struct usb_bus, bus_list); + + if (usb_device_dump (buf, &len, bus->root_hub, 0, 0, 0) + < 0) + break; + + list = list->next; + + if (len >= DUMP_LIMIT) { + len += sprintf (buf + len, "(truncated)\n"); + break; + } + } + + return (len); +} + +static int usb_bus_list_dump_devices (char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + return usb_bus_list_dump (buf, len); +} + +/* + * Dump usb_driver_list. + * + * We now walk the list of registered USB drivers. + */ +static int usb_driver_list_dump (char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct list_head *usb_driver_list = usb_driver_get_list (); + struct list_head *tmp = usb_driver_list->next; + int cnt = 0; + + len = 0; + + while (tmp != usb_driver_list) { + struct usb_driver *driver = list_entry (tmp, struct usb_driver, + driver_list); + len += sprintf (buf + len, "%s\n", driver->name); + cnt++; + tmp = tmp->next; + + if (len >= DUMP_LIMIT) + { + len += sprintf (buf + len, "(truncated)\n"); + return (len); + } + } + + if (!cnt) + len += sprintf (buf + len, "(none)\n"); + return (len); +} + +void proc_usb_cleanup (void) +{ + if (driversdir) + remove_proc_entry ("drivers", usbdir); + if (devicesdir) + remove_proc_entry ("devices", usbdir); + if (usbdir) + remove_proc_entry ("usb", proc_bus); +} + +int proc_usb_init (void) +{ + usbdir = create_proc_entry ("usb", S_IFDIR, proc_bus); + if (!usbdir) { + printk ("proc_usb: cannot create /proc/bus/usb entry\n"); + return -1; + } + + driversdir = create_proc_entry ("drivers", 0, usbdir); + if (!driversdir) { + printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n"); + proc_usb_cleanup (); + return -1; + } + driversdir->read_proc = usb_driver_list_dump; + + devicesdir = create_proc_entry ("devices", 0, usbdir); + if (!devicesdir) { + printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n"); + proc_usb_cleanup (); + return -1; + } + devicesdir->read_proc = usb_bus_list_dump_devices; + + return 0; +} + +#ifdef PROCFS_MODULE /* TBD: support proc_fs MODULE ??? */ + +int init_module (void) +{ + return proc_usb_init (); +} + +void cleanup_module (void) +{ + proc_usb_cleanup (); +} + +#endif /* PROCFS_MODULE */ + +/* end proc_usb.c */ diff -u --recursive --new-file v2.3.11/linux/drivers/usb/procusb linux/drivers/usb/procusb --- v2.3.11/linux/drivers/usb/procusb Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/procusb Tue Jul 27 16:05:50 1999 @@ -0,0 +1,41 @@ +#!/usr/bin/perl + +# Reads /proc/bus/usb/devices and selectively lists and/or +# interprets it. + +$DEVFILENAME = "/proc/bus/usb/devices"; +$PROGNAME = $0; + +$TAGS = $ARGV[0]; # save user TAGS +if (length ($TAGS) == 0) +{ + print "usage: $PROGNAME tags\n"; + print " where 'tags' can be any number of 'TDPCIE' or 'A(LL)'\n"; + exit 1; +} + +$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i); + +# TBD: Check that $TAGS is valid. +if (! $ALL) +{ +} + +if (! open (DEVNUM, "<$DEVFILENAME")) +{ + print "$PROGNAME: cannot open '$DEVFILENAME'\n"; + exit 1; +} + +while ($line = ) # read a text line from DEVNUM +{ + if (($ALL) || ($line =~ /^[$TAGS]:/i)) # any of TAGS at beg. of line? + { + print "$line"; # still has newline char on it + # TBD: add more/paging functionality. + } +} # end while DEVNUM + +close (DEVNUM); + +# END. diff -u --recursive --new-file v2.3.11/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.11/linux/drivers/usb/uhci.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/uhci.c Mon Jul 26 16:05:45 1999 @@ -361,7 +361,7 @@ unsigned int destination, status; /* Destination: pipe destination with INPUT */ - destination = (pipe & PIPE_DEVEP_MASK) | 0x69; + destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe); /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */ status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27); @@ -371,7 +371,7 @@ interrupt_qh->element); td->link = 1; - td->status = status; /* In */ + td->status = status; td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); td->buffer = virt_to_bus(dev->data); @@ -633,12 +633,8 @@ td = &isodesc->td[i]; /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (pipe & PIPE_DEVEP_MASK); - - if (usb_pipeout(pipe)) - destination |= 0xE1; /* OUT */ - else - destination |= 0x69; /* IN */ + destination = (pipe & PIPE_DEVEP_MASK) + | usb_packetid (pipe); /* add IN or OUT */ /* Status: slow/fast, Active, Isochronous */ status = (pipe & (1 << 26)) | (1 << 23) | (1 << 25); @@ -1010,18 +1006,8 @@ if (len > maxsze * 31) printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze); - /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */ - /* - IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE - LOOK AT: usb_pipeout and the pipe bits - I FORGOT WHAT IT EXACTLY DOES - */ - if (usb_pipeout(pipe)) { - destination = (pipe & PIPE_DEVEP_MASK) | 0xE1; - } - else { - destination = (pipe & PIPE_DEVEP_MASK) | 0x69; - } + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe); /* Status: slow/fast, Active, Short Packet Detect Three Errors */ status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.3.11/linux/drivers/usb/usb-core.c Wed Jun 16 19:26:27 1999 +++ linux/drivers/usb/usb-core.c Tue Jul 27 16:05:50 1999 @@ -28,6 +28,7 @@ # endif #endif + int usb_init(void) { #ifndef CONFIG_USB_MODULE @@ -65,6 +66,9 @@ usb_scsi_init(); # endif #endif +#ifdef CONFIG_USB_PROC + proc_usb_init (); +#endif return 0; } /* @@ -72,6 +76,9 @@ */ void cleanup_drivers(void) { +#ifdef CONFIG_USB_PROC + proc_usb_cleanup (); +#endif #ifndef MODULE # ifdef CONFIG_USB_HUB usb_hub_cleanup(); diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.11/linux/drivers/usb/usb.c Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/usb.c Wed Jul 28 10:45:39 1999 @@ -36,6 +36,7 @@ * 6 wLength 2 Count Bytes for data */ +#include #include #include #include @@ -1140,3 +1141,15 @@ { return dev->bus->op->release_irq(handle); } + +#ifdef CONFIG_PROC_FS +struct list_head * usb_driver_get_list (void) +{ + return &usb_driver_list; +} + +struct list_head * usb_bus_get_list (void) +{ + return &usb_bus_list; +} +#endif diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.11/linux/drivers/usb/usb.h Wed Jul 21 15:46:48 1999 +++ linux/drivers/usb/usb.h Mon Jul 26 16:05:45 1999 @@ -406,6 +406,7 @@ #define usb_packetid(pipe) (((pipe) & 0x80) ? 0x69 : 0xE1) #define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1) +#define usb_pipein(pipe) (((pipe) >> 7) & 1) #define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) #define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) #define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c --- v2.3.11/linux/drivers/usb/usb_scsi.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/usb_scsi.c Sun Jul 25 20:30:47 1999 @@ -139,10 +139,20 @@ this_xfer = length > max_size ? max_size : length; length -= this_xfer; do { - US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer); + /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/ result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, this_xfer, &partial); + if (result != 0 || partial != this_xfer) + US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n", + result, partial, this_xfer); + + if (result == USB_ST_STALL) { + US_DEBUGP("clearing endpoing halt for pipe %x\n", pipe); + usb_clear_halt(us->pusb_dev, + usb_pipeendpoint(pipe) | (pipe & 0x80)); + } + /* we want to retry if the device reported NAK */ if (result == USB_ST_TIMEOUT) { if (partial != this_xfer) { @@ -171,28 +181,31 @@ return 0; } + static int us_transfer(Scsi_Cmnd *srb, int dir_in) { struct us_data *us = (struct us_data *)srb->host_scribble; int i; int result = -1; + unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : + usb_sndbulkpipe(us->pusb_dev, us->ep_out); if (srb->use_sg) { struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { - result = us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : - usb_sndbulkpipe(us->pusb_dev, us->ep_out), - sg[i].address, sg[i].length); + result = us_one_transfer(us, pipe, sg[i].address, sg[i].length); if (result) break; } - return result; } else - return us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : - usb_sndbulkpipe(us->pusb_dev, us->ep_out), - srb->request_buffer, srb->request_bufflen); + result = us_one_transfer(us, pipe, + srb->request_buffer, srb->request_bufflen); + + if (result) + US_DEBUGP("us_transfer returning error %d\n", result); + return result; } static unsigned int us_transfer_length(Scsi_Cmnd *srb) @@ -232,12 +245,13 @@ struct us_data *us = (struct us_data *)dev_id; if (state != USB_ST_REMOVED) { - us->ip_data = *(__u16 *)buffer; - US_DEBUGP("Interrupt Status %x\n", us->ip_data); + us->ip_data = le16_to_cpup((__u16 *)buffer); + /* US_DEBUGP("Interrupt Status %x\n", us->ip_data); */ } - if (us->ip_wanted) + if (us->ip_wanted) { + us->ip_wanted = 0; wake_up(&us->ip_waitq); - us->ip_wanted = 0; + } /* we dont want another interrupt */ @@ -250,6 +264,7 @@ devrequest dr; int result; + US_DEBUGP("pop_CB_reset\n"); dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE; dr.request = US_CBI_ADSC; dr.value = 0; @@ -262,12 +277,15 @@ usb_sndctrlpipe(us->pusb_dev,0), &dr, cmd, 12); - usb_clear_halt(us->pusb_dev, us->ep_in | 0x80); - usb_clear_halt(us->pusb_dev, us->ep_out); - /* long wait for reset */ schedule_timeout(HZ*5); + + US_DEBUGP("pop_CB_reset: clearing endpoint halt\n"); + usb_clear_halt(us->pusb_dev, us->ep_in | 0x80); + usb_clear_halt(us->pusb_dev, us->ep_out); + + US_DEBUGP("pop_CB_reset done\n"); return 0; } @@ -325,6 +343,7 @@ /* as per spec try a start command, wait and retry */ done_start++; + memset(cmd, 0, sizeof(cmd)); cmd[0] = START_STOP; cmd[4] = 1; /* start */ result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, @@ -338,7 +357,7 @@ result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, srb->cmnd, srb->cmd_len); - if (result != USB_ST_STALL && result != USB_ST_TIMEOUT) + if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT) return result; } return result; @@ -356,6 +375,7 @@ devrequest dr; int retry = 5; + US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol); switch (us->protocol) { case US_PR_CB: /* get from control */ @@ -439,23 +459,26 @@ if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) { return (DID_OK << 16) | 2; } - return DID_ABORT << 16; + return DID_ERROR << 16; } /* transfer the data */ if (us_transfer_length(srb)) { result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); - if (result && result != USB_ST_DATAUNDERRUN) { + if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) { US_DEBUGP("CBI transfer %x\n", result); - return DID_ABORT << 16; - } else if (result == USB_ST_DATAUNDERRUN) { + return DID_ERROR << 16; + } +#if 0 + else if (result == USB_ST_DATAUNDERRUN) { return DID_OK << 16; } } else { if (!result) { return DID_OK << 16; } +#endif } /* get status */ @@ -947,6 +970,7 @@ US_DEBUGP("Old/New length = %d/%d\n", savelen, length); if (us->srb->request_bufflen != length) { + US_DEBUGP("redoing cmd with len=%d\n", length); us->srb->request_bufflen = length; us->srb->result = us->pop(us->srb); } @@ -957,6 +981,15 @@ case REQUEST_SENSE: case INQUIRY: case MODE_SENSE: + if (us->srb->use_sg == 0 && length > 0) { + int i; + printk(KERN_DEBUG "Data is"); + for (i = 0; i < 32 && i < length; ++i) + printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]); + if (i < length) + printk(" ..."); + printk("\n"); + } us->srb->cmnd[4] = saveallocation; break; @@ -969,6 +1002,7 @@ } /* force attention on first command */ if (!us->attention_done) { + US_DEBUGP("forcing unit attention\n"); if (us->srb->cmnd[0] == REQUEST_SENSE) { if (us->srb->result == (DID_OK << 16)) { unsigned char *p = (unsigned char *)us->srb->request_buffer; @@ -987,6 +1021,7 @@ } } } + US_DEBUGP("scsi cmd done, result=%x\n", us->srb->result); us->srb->scsi_done(us->srb); us->srb = NULL; break; diff -u --recursive --new-file v2.3.11/linux/fs/Makefile linux/fs/Makefile --- v2.3.11/linux/fs/Makefile Wed Jun 30 13:38:20 1999 +++ linux/fs/Makefile Mon Jul 26 22:51:07 1999 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o inode.o attr.o bad_inode.o $(BINFMTS) + dcache.o inode.o attr.o bad_inode.o file.o iobuf.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.3.11/linux/fs/binfmt_aout.c Wed Jul 21 15:46:48 1999 +++ linux/fs/binfmt_aout.c Thu Jul 22 09:51:58 1999 @@ -31,16 +31,18 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout_library(int fd); -static int aout_core_dump(long signr, struct pt_regs * regs); +static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); extern void dump_thread(struct pt_regs *, struct user *); static struct linux_binfmt aout_format = { + NULL, #ifndef MODULE - NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump + NULL, #else - NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump + &__this_module, #endif + load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE }; static void set_brk(unsigned long start, unsigned long end) @@ -64,12 +66,12 @@ #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (void *)(addr), (nr))) \ - goto close_coredump; + goto end_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ if (file->f_op->llseek(file,(offset),0) != (offset)) \ - goto close_coredump; \ + goto end_coredump; \ } else file->f_pos = (offset) /* @@ -83,14 +85,10 @@ */ static inline int -do_aout_core_dump(long signr, struct pt_regs * regs) +do_aout_core_dump(long signr, struct pt_regs * regs, struct file *file) { - struct dentry * dentry = NULL; - struct inode * inode = NULL; - struct file * file; mm_segment_t fs; int has_dumped = 0; - char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; #if defined(__alpha__) @@ -106,32 +104,8 @@ # define START_STACK(u) (u.start_stack) #endif - if (!current->dumpable || atomic_read(¤t->mm->mm_users) != 1) - return 0; - current->dumpable = 0; - -/* See if we have enough room to write the upage. */ - if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) - return 0; fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); @@ -210,20 +184,18 @@ /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); -close_coredump: - filp_close(file, NULL); end_coredump: set_fs(fs); return has_dumped; } static int -aout_core_dump(long signr, struct pt_regs * regs) +aout_core_dump(long signr, struct pt_regs * regs, struct file *file) { int retval; MOD_INC_USE_COUNT; - retval = do_aout_core_dump(signr, regs); + retval = do_aout_core_dump(signr, regs, file); MOD_DEC_USE_COUNT; return retval; } diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.3.11/linux/fs/binfmt_elf.c Wed Jul 21 15:46:48 1999 +++ linux/fs/binfmt_elf.c Thu Jul 22 09:47:55 1999 @@ -54,7 +54,7 @@ * don't even try. */ #ifdef USE_ELF_CORE_DUMP -static int elf_core_dump(long signr, struct pt_regs * regs); +static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file); #else #define elf_core_dump NULL #endif @@ -64,11 +64,13 @@ #define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1)) static struct linux_binfmt elf_format = { + NULL, #ifndef MODULE - NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump + NULL, #else - NULL, &__this_module, load_elf_binary, load_elf_library, elf_core_dump + &__this_module, #endif + load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE }; static void set_brk(unsigned long start, unsigned long end) @@ -1026,10 +1028,10 @@ #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (addr), (nr))) \ - goto close_coredump; + goto end_coredump; #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ - goto close_coredump; + goto end_coredump; /* * Actual dumper * @@ -1037,14 +1039,10 @@ * and then they are actually written out. If we run out of core limit * we just truncate. */ -static int elf_core_dump(long signr, struct pt_regs * regs) +static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) { int has_dumped = 0; - struct file *file; - struct dentry *dentry; - struct inode *inode; mm_segment_t fs; - char corefile[6+sizeof(current->comm)]; int segs; int i; size_t size; @@ -1058,12 +1056,6 @@ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - if (!current->dumpable || - limit < ELF_EXEC_PAGESIZE || - atomic_read(¤t->mm->mm_users) != 1) - return 0; - current->dumpable = 0; - #ifndef CONFIG_BINFMT_ELF MOD_INC_USE_COUNT; #endif @@ -1112,27 +1104,6 @@ fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (inode->i_nlink > 1) - goto close_coredump; /* multiple links - don't dump */ - - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; - has_dumped = 1; current->flags |= PF_DUMPCORE; @@ -1289,7 +1260,7 @@ for(i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) - goto close_coredump; + goto end_coredump; set_fs(fs); @@ -1315,9 +1286,6 @@ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } - - close_coredump: - filp_close(file, NULL); end_coredump: set_fs(fs); diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c --- v2.3.11/linux/fs/binfmt_em86.c Wed Jun 2 13:49:55 1999 +++ linux/fs/binfmt_em86.c Thu Jul 22 09:47:55 1999 @@ -105,11 +105,13 @@ } struct linux_binfmt em86_format = { + NULL, #ifndef MODULE - NULL, 0, load_em86, NULL, NULL + NULL, #else - NULL, &__this_module, load_em86, NULL, NULL + &__this_module, #endif + load_em86, NULL, NULL, 0 }; int __init init_em86_binfmt(void) diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c --- v2.3.11/linux/fs/binfmt_misc.c Wed Jun 2 13:50:01 1999 +++ linux/fs/binfmt_misc.c Thu Jul 22 09:47:55 1999 @@ -64,11 +64,13 @@ static int entry_proc_setup(struct binfmt_entry *e); static struct linux_binfmt misc_format = { + NULL, #ifndef MODULE - NULL, 0, load_misc_binary, NULL, NULL + NULL, #else - NULL, &__this_module, load_misc_binary, NULL, NULL + &__this_module, #endif + load_misc_binary, NULL, NULL, 0 }; static struct proc_dir_entry *bm_dir = NULL; diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_script.c linux/fs/binfmt_script.c --- v2.3.11/linux/fs/binfmt_script.c Wed Jun 2 13:50:04 1999 +++ linux/fs/binfmt_script.c Thu Jul 22 09:47:55 1999 @@ -101,11 +101,13 @@ } struct linux_binfmt script_format = { + NULL, #ifndef MODULE - NULL, 0, load_script, NULL, NULL + NULL, #else - NULL, &__this_module, load_script, NULL, NULL + &__this_module, #endif + load_script, NULL, NULL, 0 }; int __init init_script_binfmt(void) diff -u --recursive --new-file v2.3.11/linux/fs/buffer.c linux/fs/buffer.c --- v2.3.11/linux/fs/buffer.c Wed Jul 21 15:46:48 1999 +++ linux/fs/buffer.c Mon Jul 26 22:50:35 1999 @@ -40,10 +40,12 @@ #include #include #include +#include #include #include #include +#include #define NR_SIZES 7 static char buffersize_index[65] = @@ -1526,6 +1528,221 @@ return err; } + +/* + * IO completion routine for a buffer_head being used for kiobuf IO: we + * can't dispatch the kiobuf callback until io_count reaches 0. + */ + +static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate) +{ + struct kiobuf *kiobuf; + + mark_buffer_uptodate(bh, uptodate); + + kiobuf = bh->b_kiobuf; + if (atomic_dec_and_test(&kiobuf->io_count)) + kiobuf->end_io(kiobuf); + if (!uptodate) + kiobuf->errno = -EIO; +} + + +/* + * For brw_kiovec: submit a set of buffer_head temporary IOs and wait + * for them to complete. Clean up the buffer_heads afterwards. + */ + +#define dprintk(x...) + +static int do_kio(struct kiobuf *kiobuf, + int rw, int nr, struct buffer_head *bh[], int size) +{ + int iosize; + int i; + struct buffer_head *tmp; + + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + dprintk ("do_kio start %d\n", rw); + + if (rw == WRITE) + rw = WRITERAW; + atomic_add(nr, &kiobuf->io_count); + kiobuf->errno = 0; + ll_rw_block(rw, nr, bh); + + kiobuf_wait_for_io(kiobuf); + + spin_lock(&unused_list_lock); + + iosize = 0; + for (i = nr; --i >= 0; ) { + iosize += size; + tmp = bh[i]; + if (!buffer_uptodate(tmp)) { + /* We are traversing bh'es in reverse order so + clearing iosize on error calculates the + amount of IO before the first error. */ + iosize = 0; + } + __put_unused_buffer_head(tmp); + } + + spin_unlock(&unused_list_lock); + + dprintk ("do_kio end %d %d\n", iosize, err); + + if (iosize) + return iosize; + if (kiobuf->errno) + return kiobuf->errno; + return -EIO; +} + +/* + * Start I/O on a physical range of kernel memory, defined by a vector + * of kiobuf structs (much like a user-space iovec list). + * + * The kiobuf must already be locked for IO. IO is submitted + * asynchronously: you need to check page->locked, page->uptodate, and + * maybe wait on page->wait. + * + * It is up to the caller to make sure that there are enough blocks + * passed in to completely map the iobufs to disk. + */ + +int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, int bmap) +{ + int err; + int length; + int transferred; + int i; + int bufind; + int pageind; + int bhind; + int offset; + unsigned long blocknr; + struct kiobuf * iobuf = NULL; + unsigned long page; + struct page * map; + struct buffer_head *tmp, *bh[KIO_MAX_SECTORS]; + + if (!nr) + return 0; + + /* + * First, do some alignment and validity checks + */ + for (i = 0; i < nr; i++) { + iobuf = iovec[i]; + if ((iobuf->offset & (size-1)) || + (iobuf->length & (size-1))) + return -EINVAL; + if (!iobuf->locked) + panic("brw_kiovec: iobuf not locked for I/O"); + if (!iobuf->nr_pages) + panic("brw_kiovec: iobuf not initialised"); + } + + /* DEBUG */ +#if 0 + return iobuf->length; +#endif + dprintk ("brw_kiovec: start\n"); + + /* + * OK to walk down the iovec doing page IO on each page we find. + */ + bufind = bhind = transferred = err = 0; + for (i = 0; i < nr; i++) { + iobuf = iovec[i]; + offset = iobuf->offset; + length = iobuf->length; + dprintk ("iobuf %d %d %d\n", offset, length, size); + + for (pageind = 0; pageind < iobuf->nr_pages; pageind++) { + page = iobuf->pagelist[pageind]; + map = iobuf->maplist[pageind]; + + while (length > 0) { + blocknr = b[bufind++]; + tmp = get_unused_buffer_head(0); + if (!tmp) { + err = -ENOMEM; + goto error; + } + + tmp->b_dev = B_FREE; + tmp->b_size = size; + tmp->b_data = (char *) (page + offset); + tmp->b_this_page = tmp; + + init_buffer(tmp, end_buffer_io_kiobuf, NULL); + tmp->b_dev = dev; + tmp->b_blocknr = blocknr; + tmp->b_state = 1 << BH_Mapped; + tmp->b_kiobuf = iobuf; + + if (rw == WRITE) { + set_bit(BH_Uptodate, &tmp->b_state); + set_bit(BH_Dirty, &tmp->b_state); + } + + dprintk ("buffer %d (%d) at %p\n", + bhind, tmp->b_blocknr, tmp->b_data); + bh[bhind++] = tmp; + length -= size; + offset += size; + + /* + * Start the IO if we have got too much + */ + if (bhind >= KIO_MAX_SECTORS) { + err = do_kio(iobuf, rw, bhind, bh, size); + if (err >= 0) + transferred += err; + else + goto finished; + bhind = 0; + } + + if (offset >= PAGE_SIZE) { + offset = 0; + break; + } + } /* End of block loop */ + } /* End of page loop */ + } /* End of iovec loop */ + + /* Is there any IO still left to submit? */ + if (bhind) { + err = do_kio(iobuf, rw, bhind, bh, size); + if (err >= 0) + transferred += err; + else + goto finished; + } + + finished: + dprintk ("brw_kiovec: end (%d, %d)\n", transferred, err); + if (transferred) + return transferred; + return err; + + error: + /* We got an error allocation the bh'es. Just free the current + buffer_heads and exit. */ + spin_lock(&unused_list_lock); + for (i = bhind; --i >= 0; ) { + __put_unused_buffer_head(bh[bhind]); + } + spin_unlock(&unused_list_lock); + goto finished; +} + /* * Start I/O on a page. * This function expects the page to be locked and may return @@ -1955,7 +2172,6 @@ return 0; } - /* This is the interface to bdflush. As we get more sophisticated, we can * pass tuning parameters to this "process", to adjust how it behaves. * We would want to verify each parameter, however, to make sure that it @@ -1963,57 +2179,45 @@ asmlinkage int sys_bdflush(int func, long data) { - int i, error = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto out; + return -EPERM; if (func == 1) { + int error; struct mm_struct *user_mm; + /* * bdflush will spend all of it's time in kernel-space, * without touching user-space, so we can switch it into * 'lazy TLB mode' to reduce the cost of context-switches * to and from bdflush. */ - user_mm = current->mm; - atomic_inc(&user_mm->mm_count); - current->mm = NULL; - /* active_mm is still 'user_mm' */ - + user_mm = start_lazy_tlb(); error = sync_old_buffers(); - - current->mm = user_mm; - mmdrop(current->active_mm); - current->active_mm = user_mm; - - goto out; + end_lazy_tlb(user_mm); + return error; } /* Basically func 1 means read param 1, 2 means write param 1, etc */ if (func >= 2) { - i = (func-2) >> 1; - error = -EINVAL; - if (i < 0 || i >= N_PARAM) - goto out; - if((func & 1) == 0) { - error = put_user(bdf_prm.data[i], (int*)data); - goto out; + int i = (func-2) >> 1; + if (i >= 0 && i < N_PARAM) { + if ((func & 1) == 0) + return put_user(bdf_prm.data[i], (int*)data); + + if (data >= bdflush_min[i] && data <= bdflush_max[i]) { + bdf_prm.data[i] = data; + return 0; + } } - if (data < bdflush_min[i] || data > bdflush_max[i]) - goto out; - bdf_prm.data[i] = data; - error = 0; - goto out; - }; + return -EINVAL; + } /* Having func 0 used to launch the actual bdflush and then never * return (unless explicitly killed). We return zero here to * remain semi-compatible with present update(8) programs. */ - error = 0; -out: - return error; + return 0; } /* diff -u --recursive --new-file v2.3.11/linux/fs/exec.c linux/fs/exec.c --- v2.3.11/linux/fs/exec.c Wed Jul 21 15:46:48 1999 +++ linux/fs/exec.c Tue Jul 27 14:53:14 1999 @@ -371,7 +371,6 @@ if (old_mm && atomic_read(&old_mm->mm_users) == 1) { flush_cache_mm(old_mm); mm_release(); - release_segments(old_mm); exit_mmap(old_mm); flush_tlb_mm(old_mm); return 0; @@ -379,26 +378,19 @@ mm = mm_alloc(); if (mm) { - mm->cpu_vm_mask = (1UL << smp_processor_id()); - mm->total_vm = 0; - mm->rss = 0; - mm->pgd = pgd_alloc(); - if (mm->pgd) { - struct mm_struct *active_mm = current->active_mm; - - current->mm = mm; - current->active_mm = mm; - SET_PAGE_DIR(current, mm->pgd); - activate_context(current); - mm_release(); - if (old_mm) { - mmput(old_mm); - return 0; - } - mmdrop(active_mm); + struct mm_struct *active_mm = current->active_mm; + + current->mm = mm; + current->active_mm = mm; + switch_mm(active_mm, mm, smp_processor_id()); + mm_release(); + if (old_mm) { + if (active_mm != old_mm) BUG(); + mmput(old_mm); return 0; } - kmem_cache_free(mm_cachep, mm); + mmdrop(active_mm); + return 0; } return -ENOMEM; } @@ -455,9 +447,9 @@ unsigned long set, i; i = j * __NFDBITS; - if (i >= files->max_fds) + if (i >= files->max_fds || i >= files->max_fdset) break; - set = xchg(&files->close_on_exec.fds_bits[j], 0); + set = xchg(&files->close_on_exec->fds_bits[j], 0); j++; for ( ; set ; i++,set >>= 1) { if (set & 1) @@ -836,4 +828,54 @@ free_page(bprm.page[i]); return retval; +} + +int do_coredump(long signr, struct pt_regs * regs) +{ + struct linux_binfmt * binfmt; + char corename[6+sizeof(current->comm)]; + struct file * file; + struct dentry * dentry; + struct inode * inode; + + lock_kernel(); + binfmt = current->binfmt; + if (!binfmt || !binfmt->core_dump) + goto fail; + if (!current->dumpable || atomic_read(¤t->mm->mm_users) != 1) + current->dumpable = 0; + if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) + goto fail; + + memcpy(corename,"core.", 5); +#if 0 + memcpy(corename+5,current->comm,sizeof(current->comm)); +#else + corename[4] = '\0'; +#endif + file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); + if (IS_ERR(file)) + goto fail; + dentry = file->f_dentry; + inode = dentry->d_inode; + if (inode->i_nlink > 1) + goto close_fail; /* multiple links - don't dump */ + + if (!S_ISREG(inode->i_mode)) + goto close_fail; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto close_fail; + if (!file->f_op->write) + goto close_fail; + if (!binfmt->core_dump(signr, regs, file)) + goto close_fail; + filp_close(file, NULL); + unlock_kernel(); + return 1; + +close_fail: + filp_close(file, NULL); +fail: + unlock_kernel(); + return 0; } diff -u --recursive --new-file v2.3.11/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.3.11/linux/fs/fcntl.c Wed Jul 21 15:46:48 1999 +++ linux/fs/fcntl.c Mon Jul 26 22:41:09 1999 @@ -12,36 +12,89 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); -static inline int dupfd(struct file *file, unsigned int arg) +/* + * locate_fd finds a free file descriptor in the open_fds fdset, + * expanding the fd arrays if necessary. The files write lock will be + * held on exit to ensure that the fd can be entered atomically. + */ + +static inline int locate_fd(struct files_struct *files, + struct file *file, int start) { - struct files_struct * files = current->files; + unsigned int newfd; int error; - error = -EMFILE; write_lock(&files->file_lock); - arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); - if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) - goto out_putf; - FD_SET(arg, &files->open_fds); - FD_CLR(arg, &files->close_on_exec); - write_unlock(&files->file_lock); - fd_install(arg, file); - error = arg; + +repeat: + error = -EMFILE; + if (start < files->next_fd) + start = files->next_fd; + if (start >= files->max_fdset) { + expand: + error = expand_files(files, start); + if (error < 0) + goto out; + goto repeat; + } + + newfd = find_next_zero_bit(files->open_fds->fds_bits, + files->max_fdset, start); + + error = -EMFILE; + if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) + goto out; + if (newfd >= files->max_fdset) + goto expand; + + error = expand_files(files, newfd); + if (error < 0) + goto out; + if (error) /* If we might have blocked, try again. */ + goto repeat; + + if (start <= files->next_fd) + files->next_fd = newfd + 1; + + error = newfd; + out: return error; +} + +static inline void allocate_fd(struct files_struct *files, + struct file *file, int fd) +{ + FD_SET(fd, files->open_fds); + FD_CLR(fd, files->close_on_exec); + write_unlock(&files->file_lock); + fd_install(fd, file); +} + +static int dupfd(struct file *file, int start) +{ + struct files_struct * files = current->files; + int ret; + + ret = locate_fd(files, file, start); + if (ret < 0) + goto out_putf; + allocate_fd(files, file, ret); + return ret; out_putf: write_unlock(&files->file_lock); fput(file); - goto out; + return ret; } asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) { int err = -EBADF; struct file * file; + struct files_struct * files = current->files; - read_lock(¤t->files->file_lock); + write_lock(¤t->files->file_lock); if (!(file = fcheck(oldfd))) goto out_unlock; err = newfd; @@ -50,15 +103,33 @@ err = -EBADF; if (newfd >= NR_OPEN) goto out_unlock; /* following POSIX.1 6.2.1 */ - get_file(file); - read_unlock(¤t->files->file_lock); + get_file(file); /* We are now finished with oldfd */ + + err = expand_files(files, newfd); + if (err < 0) { + write_unlock(&files->file_lock); + fput(file); + goto out; + } + + /* To avoid races with open() and dup(), we will mark the fd as + * in-use in the open-file bitmap throughout the entire dup2() + * process. This is quite safe: do_close() uses the fd array + * entry, not the bitmap, to decide what work needs to be + * done. --sct */ + FD_SET(newfd, files->open_fds); + write_unlock(&files->file_lock); + + do_close(newfd, 0); + + write_lock(&files->file_lock); + allocate_fd(files, file, newfd); + err = newfd; - sys_close(newfd); - err = dupfd(file, newfd); out: return err; out_unlock: - read_unlock(¤t->files->file_lock); + write_unlock(¤t->files->file_lock); goto out; } @@ -66,6 +137,7 @@ { int ret = -EBADF; struct file * file = fget(fildes); + if (file) ret = dupfd(file, 0); return ret; @@ -118,13 +190,13 @@ } break; case F_GETFD: - err = FD_ISSET(fd, ¤t->files->close_on_exec); + err = FD_ISSET(fd, current->files->close_on_exec); break; case F_SETFD: if (arg&1) - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); else - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case F_GETFL: err = filp->f_flags; @@ -152,7 +224,6 @@ err = filp->f_owner.pid; break; case F_SETOWN: - err = 0; filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; @@ -172,10 +243,9 @@ break; default: /* sockets need a few special fcntls. */ + err = -EINVAL; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, cmd, arg); - else - err = -EINVAL; break; } fput(filp); diff -u --recursive --new-file v2.3.11/linux/fs/file.c linux/fs/file.c --- v2.3.11/linux/fs/file.c Wed Dec 31 16:00:00 1969 +++ linux/fs/file.c Mon Jul 26 22:41:09 1999 @@ -0,0 +1,240 @@ +/* + * linux/fs/open.c + * + * Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes + * + * Manage the dynamic fd arrays in the process files_struct. + */ + +#include +#include +#include +#include +#include + +#include + + +/* + * Allocate an fd array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +struct file ** alloc_fd_array(int num) +{ + struct file **new_fds; + int size = num * sizeof(struct file *); + + if (size < PAGE_SIZE) + new_fds = (struct file **) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fds = (struct file **) __get_free_page(GFP_KERNEL); + else + new_fds = (struct file **) vmalloc(size); + return new_fds; +} + +void free_fd_array(struct file **array, int num) +{ + int size = num * sizeof(struct file *); + + if (!array) { + printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num); + return; + } + + if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */ + return; + else if (size < PAGE_SIZE) + kfree(array); + else if (size == PAGE_SIZE) + free_page((unsigned long) array); + else + vfree(array); +} + +/* + * Expand the fd array in the files_struct. Called with the files + * spinlock held for write. + */ + +int expand_fd_array(struct files_struct *files, int nr) +{ + struct file **new_fds; + int error, nfds; + + + error = -EMFILE; + if (files->max_fds >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fds; + write_unlock(&files->file_lock); + + /* + * Expand to the max in easy steps, and keep expanding it until + * we have enough for the requested fd array size. + */ + + do { +#if NR_OPEN_DEFAULT < 256 + if (nfds < 256) + nfds = 256; + else +#endif + if (nfds < (PAGE_SIZE / sizeof(struct file *))) + nfds = PAGE_SIZE / sizeof(struct file *); + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_fds = alloc_fd_array(nfds); + write_lock(&files->file_lock); + if (!new_fds) + goto out; + + /* Copy the existing array and install the new pointer */ + + if (nfds > files->max_fds) { + struct file **old_fds; + int i; + + old_fds = xchg(&files->fd, new_fds); + i = xchg(&files->max_fds, nfds); + + /* Don't copy/clear the array if we are creating a new + fd array for fork() */ + if (i) { + memcpy(new_fds, old_fds, i * sizeof(struct file *)); + /* clear the remainder of the array */ + memset(&new_fds[i], 0, + (nfds-i) * sizeof(struct file *)); + + write_unlock(&files->file_lock); + free_fd_array(old_fds, i); + write_lock(&files->file_lock); + } + } else { + /* Somebody expanded the array while we slept ... */ + write_unlock(&files->file_lock); + free_fd_array(new_fds, nfds); + write_lock(&files->file_lock); + } + error = 0; +out: + return error; +} + +/* + * Allocate an fdset array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +fd_set * alloc_fdset(int num) +{ + fd_set *new_fdset; + int size = num / 8; + + if (size < PAGE_SIZE) + new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fdset = (fd_set *) __get_free_page(GFP_KERNEL); + else + new_fdset = (fd_set *) vmalloc(size); + return new_fdset; +} + +void free_fdset(fd_set *array, int num) +{ + int size = num / 8; + + if (!array) { + printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num); + return; + } + + if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */ + return; + else if (size < PAGE_SIZE) + kfree(array); + else if (size == PAGE_SIZE) + free_page((unsigned long) array); + else + vfree(array); +} + +/* + * Expand the fdset in the files_struct. Called with the files spinlock + * held for write. + */ +int expand_fdset(struct files_struct *files, int nr) +{ + fd_set *new_openset = 0, *new_execset = 0; + int error, nfds = 0; + + error = -EMFILE; + if (files->max_fdset >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fdset; + write_unlock(&files->file_lock); + + /* Expand to the max in easy steps */ + do { + if (nfds < (PAGE_SIZE * 8)) + nfds = PAGE_SIZE * 8; + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_openset = alloc_fdset(nfds); + new_execset = alloc_fdset(nfds); + write_lock(&files->file_lock); + if (!new_openset || !new_execset) + goto out; + + error = 0; + + /* Copy the existing tables and install the new pointers */ + if (nfds > files->max_fdset) { + int i = files->max_fdset / (sizeof(unsigned long) * 8); + int count = (nfds - files->max_fdset) / 8; + + /* + * Don't copy the entire array if the current fdset is + * not yet initialised. + */ + if (i) { + memcpy (new_openset, files->open_fds, files->max_fdset/8); + memcpy (new_execset, files->close_on_exec, files->max_fdset/8); + memset (&new_openset->fds_bits[i], 0, count); + memset (&new_execset->fds_bits[i], 0, count); + } + + nfds = xchg(&files->max_fdset, nfds); + new_openset = xchg(&files->open_fds, new_openset); + new_execset = xchg(&files->close_on_exec, new_execset); + write_unlock(&files->file_lock); + free_fdset (new_openset, nfds); + free_fdset (new_execset, nfds); + write_lock(&files->file_lock); + return 0; + } + /* Somebody expanded the array while we slept ... */ + +out: + write_unlock(&files->file_lock); + if (new_openset) + free_fdset(new_openset, nfds); + if (new_execset) + free_fdset(new_execset, nfds); + write_lock(&files->file_lock); + return error; +} + diff -u --recursive --new-file v2.3.11/linux/fs/iobuf.c linux/fs/iobuf.c --- v2.3.11/linux/fs/iobuf.c Wed Dec 31 16:00:00 1969 +++ linux/fs/iobuf.c Mon Jul 26 22:50:35 1999 @@ -0,0 +1,136 @@ +/* + * iobuf.c + * + * Keep track of the general-purpose IO-buffer structures used to track + * abstract kernel-space io buffers. + * + */ + +#include +#include +#include + +static kmem_cache_t *kiobuf_cachep; + +/* + * The default IO completion routine for kiobufs: just wake up + * the kiobuf, nothing more. + */ + +void simple_wakeup_kiobuf(struct kiobuf *kiobuf) +{ + wake_up(&kiobuf->wait_queue); +} + + +void __init kiobuf_init(void) +{ + kiobuf_cachep = kmem_cache_create("kiobuf", + sizeof(struct kiobuf), + 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if(!kiobuf_cachep) + panic("Cannot create kernel iobuf cache\n"); +} + + +int alloc_kiovec(int nr, struct kiobuf **bufp) +{ + int i; + struct kiobuf *iobuf; + + for (i = 0; i < nr; i++) { + iobuf = kmem_cache_alloc(kiobuf_cachep, SLAB_KERNEL); + if (!iobuf) { + free_kiovec(i, bufp); + return -ENOMEM; + } + + memset(iobuf, 0, sizeof(*iobuf)); + init_waitqueue_head(&iobuf->wait_queue); + iobuf->end_io = simple_wakeup_kiobuf; + iobuf->array_len = KIO_STATIC_PAGES; + iobuf->pagelist = iobuf->page_array; + iobuf->maplist = iobuf->map_array; + *bufp++ = iobuf; + } + + return 0; +} + +void free_kiovec(int nr, struct kiobuf **bufp) +{ + int i; + struct kiobuf *iobuf; + + for (i = 0; i < nr; i++) { + iobuf = bufp[i]; + if (iobuf->array_len > KIO_STATIC_PAGES) { + kfree (iobuf->pagelist); + kfree (iobuf->maplist); + } + kmem_cache_free(kiobuf_cachep, bufp[i]); + } +} + +int expand_kiobuf(struct kiobuf *iobuf, int wanted) +{ + unsigned long * pagelist; + struct page ** maplist; + + if (iobuf->array_len >= wanted) + return 0; + + pagelist = (unsigned long *) + kmalloc(wanted * sizeof(unsigned long), GFP_KERNEL); + if (!pagelist) + return -ENOMEM; + + maplist = (struct page **) + kmalloc(wanted * sizeof(struct page **), GFP_KERNEL); + if (!maplist) { + kfree(pagelist); + return -ENOMEM; + } + + /* Did it grow while we waited? */ + if (iobuf->array_len >= wanted) { + kfree(pagelist); + kfree(maplist); + return 0; + } + + memcpy (pagelist, iobuf->pagelist, wanted * sizeof(unsigned long)); + memcpy (maplist, iobuf->maplist, wanted * sizeof(struct page **)); + + if (iobuf->array_len > KIO_STATIC_PAGES) { + kfree (iobuf->pagelist); + kfree (iobuf->maplist); + } + + iobuf->pagelist = pagelist; + iobuf->maplist = maplist; + iobuf->array_len = wanted; + return 0; +} + + +void kiobuf_wait_for_io(struct kiobuf *kiobuf) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&kiobuf->wait_queue, &wait); +repeat: + tsk->state = TASK_UNINTERRUPTIBLE; + run_task_queue(&tq_disk); + if (atomic_read(&kiobuf->io_count) != 0) { + schedule(); + goto repeat; + } + tsk->state = TASK_RUNNING; + remove_wait_queue(&kiobuf->wait_queue, &wait); +} + + + diff -u --recursive --new-file v2.3.11/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.3.11/linux/fs/ioctl.c Thu Jul 8 15:42:21 1999 +++ linux/fs/ioctl.c Mon Jul 26 22:41:09 1999 @@ -61,11 +61,11 @@ lock_kernel(); switch (cmd) { case FIOCLEX: - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); break; case FIONCLEX: - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case FIONBIO: diff -u --recursive --new-file v2.3.11/linux/fs/minix/file.c linux/fs/minix/file.c --- v2.3.11/linux/fs/minix/file.c Thu Jul 8 15:42:21 1999 +++ linux/fs/minix/file.c Fri Jul 23 10:30:42 1999 @@ -24,6 +24,7 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) #include +#include /* * Write to a file (through the page cache). diff -u --recursive --new-file v2.3.11/linux/fs/open.c linux/fs/open.c --- v2.3.11/linux/fs/open.c Wed Jul 21 15:46:48 1999 +++ linux/fs/open.c Mon Jul 26 22:41:09 1999 @@ -685,10 +685,14 @@ struct files_struct * files = current->files; int fd, error; - error = -EMFILE; - + error = -EMFILE; write_lock(&files->file_lock); - fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + +repeat: + fd = find_next_zero_bit(files->open_fds, + current->files->max_fdset, + files->next_fd); + /* * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. @@ -696,10 +700,31 @@ if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; - /* Check here for fd > files->max_fds to do dynamic expansion */ + /* Do we need to expand the fdset array? */ + if (fd >= current->files->max_fdset) { + error = expand_fdset(files, 0); + if (!error) { + error = -EMFILE; + goto repeat; + } + goto out; + } + + /* + * Check whether we need to expand the fd array. + */ + if (fd >= files->max_fds) { + error = expand_fd_array(files, 0); + if (!error) { + error = -EMFILE; + goto repeat; + } + goto out; + } - FD_SET(fd, &files->open_fds); - FD_CLR(fd, &files->close_on_exec); + FD_SET(fd, files->open_fds); + FD_CLR(fd, files->close_on_exec); + files->next_fd = fd + 1; #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { @@ -717,7 +742,9 @@ inline void put_unused_fd(unsigned int fd) { write_lock(¤t->files->file_lock); - FD_CLR(fd, ¤t->files->open_fds); + FD_CLR(fd, current->files->open_fds); + if (fd < current->files->next_fd) + current->files->next_fd = fd; write_unlock(¤t->files->file_lock); } @@ -790,8 +817,12 @@ * Careful here! We test whether the file pointer is NULL before * releasing the fd. This ensures that one clone task can't release * an fd while another clone is opening it. + * + * The "release" argument tells us whether or not to mark the fd as free + * or not in the open-files bitmap. dup2 uses this to retain the fd + * without races. */ -asmlinkage int sys_close(unsigned int fd) +int do_close(unsigned int fd, int release) { int error; struct file * filp; @@ -802,9 +833,10 @@ filp = frip(fd); if (!filp) goto out_unlock; - FD_CLR(fd, &files->close_on_exec); + FD_CLR(fd, files->close_on_exec); write_unlock(&files->file_lock); - put_unused_fd(fd); + if (release) + put_unused_fd(fd); lock_kernel(); error = filp_close(filp, files); unlock_kernel(); @@ -813,6 +845,11 @@ out_unlock: write_unlock(&files->file_lock); goto out; +} + +asmlinkage int sys_close(unsigned int fd) +{ + return do_close(fd, 1); } /* diff -u --recursive --new-file v2.3.11/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.3.11/linux/fs/proc/array.c Wed Jul 21 15:46:48 1999 +++ linux/fs/proc/array.c Wed Jul 28 10:45:39 1999 @@ -42,6 +42,8 @@ * Alan Cox : security fixes. * * + * Al Viro : safe handling of mm_struct + * */ #include @@ -386,21 +388,15 @@ return sprintf(buffer, "%s\n", saved_command_line); } -static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr) +static unsigned long get_phys_addr(struct mm_struct * mm, unsigned long ptr) { pgd_t *page_dir; pmd_t *page_middle; pte_t pte; - if (!p || !p->mm || ptr >= TASK_SIZE) - return 0; - /* Check for NULL pgd .. shouldn't happen! */ - if (!p->mm->pgd) { - printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid); + if (ptr >= TASK_SIZE) return 0; - } - - page_dir = pgd_offset(p->mm,ptr); + page_dir = pgd_offset(mm,ptr); if (pgd_none(*page_dir)) return 0; if (pgd_bad(*page_dir)) { @@ -422,7 +418,7 @@ return pte_page(pte) + (ptr & ~PAGE_MASK); } -static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer) +static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer) { unsigned long addr; int size = 0, result = 0; @@ -431,7 +427,7 @@ if (start >= end) return result; for (;;) { - addr = get_phys_addr(p, start); + addr = get_phys_addr(mm, start); if (!addr) return result; do { @@ -451,29 +447,42 @@ return result; } -static int get_env(int pid, char * buffer) +static struct mm_struct *get_mm(int pid) { struct task_struct *p; + struct mm_struct *mm = NULL; read_lock(&tasklist_lock); p = find_task_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ + if (p) + mm = p->mm; + if (mm) + atomic_inc(&mm->mm_users); + read_unlock(&tasklist_lock); + return mm; +} - if (!p || !p->mm) - return 0; - return get_array(p, p->mm->env_start, p->mm->env_end, buffer); + +static int get_env(int pid, char * buffer) +{ + struct mm_struct *mm = get_mm(pid); + int res = 0; + if (mm) { + res = get_array(mm, mm->env_start, mm->env_end, buffer); + mmput(mm); + } + return res; } static int get_arg(int pid, char * buffer) { - struct task_struct *p; - - read_lock(&tasklist_lock); - p = find_task_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ - if (!p || !p->mm) - return 0; - return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer); + struct mm_struct *mm = get_mm(pid); + int res = 0; + if (mm) { + res = get_array(mm, mm->arg_start, mm->arg_end, buffer); + mmput(mm); + } + return res; } /* @@ -725,11 +734,13 @@ "PPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n" + "FDSize:\t%d\n" "Groups:\t", get_task_state(p), p->pid, p->p_pptr->pid, p->uid, p->euid, p->suid, p->fsuid, - p->gid, p->egid, p->sgid, p->fsgid); + p->gid, p->egid, p->sgid, p->fsgid, + p->files ? p->files->max_fds : 0); for (g = 0; g < p->ngroups; g++) buffer += sprintf(buffer, "%d ", p->groups[g]); @@ -738,46 +749,44 @@ return buffer; } -static inline char * task_mem(struct task_struct *p, char *buffer) +static inline char * task_mem(struct mm_struct *mm, char *buffer) { - struct mm_struct * mm = p->mm; - - if (mm) { - struct vm_area_struct * vma = mm->mmap; - unsigned long data = 0, stack = 0; - unsigned long exec = 0, lib = 0; - - for (vma = mm->mmap; vma; vma = vma->vm_next) { - unsigned long len = (vma->vm_end - vma->vm_start) >> 10; - if (!vma->vm_file) { - data += len; - if (vma->vm_flags & VM_GROWSDOWN) - stack += len; - continue; - } - if (vma->vm_flags & VM_WRITE) + struct vm_area_struct * vma; + unsigned long data = 0, stack = 0; + unsigned long exec = 0, lib = 0; + + down(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) continue; - if (vma->vm_flags & VM_EXEC) { - exec += len; - if (vma->vm_flags & VM_EXECUTABLE) - continue; - lib += len; - } - } - buffer += sprintf(buffer, - "VmSize:\t%8lu kB\n" - "VmLck:\t%8lu kB\n" - "VmRSS:\t%8lu kB\n" - "VmData:\t%8lu kB\n" - "VmStk:\t%8lu kB\n" - "VmExe:\t%8lu kB\n" - "VmLib:\t%8lu kB\n", - mm->total_vm << (PAGE_SHIFT-10), - mm->locked_vm << (PAGE_SHIFT-10), - mm->rss << (PAGE_SHIFT-10), - data - stack, stack, - exec - lib, lib); + lib += len; + } } + buffer += sprintf(buffer, + "VmSize:\t%8lu kB\n" + "VmLck:\t%8lu kB\n" + "VmRSS:\t%8lu kB\n" + "VmData:\t%8lu kB\n" + "VmStk:\t%8lu kB\n" + "VmExe:\t%8lu kB\n" + "VmLib:\t%8lu kB\n", + mm->total_vm << (PAGE_SHIFT-10), + mm->locked_vm << (PAGE_SHIFT-10), + mm->rss << (PAGE_SHIFT-10), + data - stack, stack, + exec - lib, lib); + up(&mm->mmap_sem); return buffer; } @@ -838,44 +847,61 @@ { char * orig = buffer; struct task_struct *tsk; + struct mm_struct *mm = NULL; read_lock(&tasklist_lock); tsk = find_task_by_pid(pid); + if (tsk) + mm = tsk->mm; + if (mm) + atomic_inc(&mm->mm_users); read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!tsk) return 0; buffer = task_name(tsk, buffer); buffer = task_state(tsk, buffer); - buffer = task_mem(tsk, buffer); + if (mm) + buffer = task_mem(mm, buffer); buffer = task_sig(tsk, buffer); buffer = task_cap(tsk, buffer); + if (mm) + mmput(mm); return buffer - orig; } static int get_stat(int pid, char * buffer) { struct task_struct *tsk; + struct mm_struct *mm = NULL; unsigned long vsize, eip, esp, wchan; long priority, nice; int tty_pgrp; sigset_t sigign, sigcatch; char state; + int res; read_lock(&tasklist_lock); tsk = find_task_by_pid(pid); + if (tsk) + mm = tsk->mm; + if (mm) + atomic_inc(&mm->mm_users); read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!tsk) return 0; state = *get_task_state(tsk); vsize = eip = esp = 0; - if (tsk->mm) { - struct vm_area_struct *vma = tsk->mm->mmap; + if (mm) { + struct vm_area_struct *vma; + down(&mm->mmap_sem); + vma = mm->mmap; while (vma) { vsize += vma->vm_end - vma->vm_start; vma = vma->vm_next; } eip = KSTK_EIP(tsk); esp = KSTK_ESP(tsk); + up(&mm->mmap_sem); } wchan = get_wchan(tsk); @@ -894,7 +920,7 @@ nice = tsk->priority; nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; - return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n", pid, @@ -920,11 +946,11 @@ tsk->it_real_value, tsk->start_time, vsize, - tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */ + mm ? mm->rss : 0, /* you might want to shift this left 3 */ tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0, - tsk->mm ? tsk->mm->start_code : 0, - tsk->mm ? tsk->mm->end_code : 0, - tsk->mm ? tsk->mm->start_stack : 0, + mm ? mm->start_code : 0, + mm ? mm->end_code : 0, + mm ? mm->start_stack : 0, esp, eip, /* The signal information here is obsolete. @@ -940,6 +966,9 @@ tsk->cnswap, tsk->exit_signal, tsk->processor); + if (mm) + mmput(mm); + return res; } static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, @@ -1017,19 +1046,15 @@ static int get_statm(int pid, char * buffer) { - struct task_struct *tsk; + struct mm_struct *mm = get_mm(pid); int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; - read_lock(&tasklist_lock); - tsk = find_task_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ - if (!tsk) - return 0; - if (tsk->mm) { - struct vm_area_struct * vma = tsk->mm->mmap; - + if (mm) { + struct vm_area_struct * vma; + down(&mm->mmap_sem); + vma = mm->mmap; while (vma) { - pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start); + pgd_t *pgd = pgd_offset(mm, vma->vm_start); int pages = 0, shared = 0, dirty = 0, total = 0; statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); @@ -1047,6 +1072,8 @@ drs += pages; vma = vma->vm_next; } + up(&mm->mmap_sem); + mmput(mm); } return sprintf(buffer,"%d %d %d %d %d %d %d\n", size, resident, share, trs, lrs, drs, dt); diff -u --recursive --new-file v2.3.11/linux/fs/proc/link.c linux/fs/proc/link.c --- v2.3.11/linux/fs/proc/link.c Thu Jul 8 15:42:21 1999 +++ linux/fs/proc/link.c Wed Jul 28 10:45:39 1999 @@ -82,60 +82,70 @@ ino &= 0x0000ffff; result = ERR_PTR(-ENOENT); - read_lock(&tasklist_lock); - p = find_task_by_pid(pid); - if (!p) - goto out_unlock; switch (ino) { case PROC_PID_CWD: - if (!p->fs || !p->fs->pwd) - goto out_unlock; - result = p->fs->pwd; - goto out_dget; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + if (p && p->fs && p->fs->pwd) + result = dget(p->fs->pwd); + read_unlock(&tasklist_lock); + break; case PROC_PID_ROOT: - if (!p->fs || !p->fs->root) - goto out_unlock; - result = p->fs->root; - goto out_dget; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + if (p && p->fs && p->fs->root) + result = dget(p->fs->root); + read_unlock(&tasklist_lock); + break; case PROC_PID_EXE: { + struct mm_struct *mm = NULL; struct vm_area_struct * vma; - if (!p->mm) - goto out_unlock; - vma = p->mm->mmap; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + if (p) + mm = p->mm; + if (mm) + atomic_inc(&mm->mm_users); + read_unlock(&tasklist_lock); + if (!mm) + break; + down(&mm->mmap_sem); + vma = mm->mmap; while (vma) { if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { - result = vma->vm_file->f_dentry; - goto out_dget; + result = dget(vma->vm_file->f_dentry); + break; } vma = vma->vm_next; } - goto out_unlock; + up(&mm->mmap_sem); + mmput(mm); + break; } default: if (ino & PROC_PID_FD_DIR) { struct file * file; + struct files_struct *files = NULL; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + if (p) + files = p->files; + read_unlock(&tasklist_lock); + if (!files) + break; ino &= 0x7fff; - if (!p->files) /* shouldn't happen here */ - goto out_unlock; - read_lock(&p->files->file_lock); - file = fcheck_task(p, ino); - if (!file || !file->f_dentry) - goto out_unlock; - result = file->f_dentry; + read_lock(&files->file_lock); + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + if (ino < files->max_fds && + (file = files->fd[ino]) && file->f_dentry) + result = dget(file->f_dentry); read_unlock(&p->files->file_lock); - goto out_dget; } } -out_dget: - result = dget(result); - -out_unlock: - read_unlock(&tasklist_lock); - out: return result; } diff -u --recursive --new-file v2.3.11/linux/fs/select.c linux/fs/select.c --- v2.3.11/linux/fs/select.c Thu Jul 8 15:42:21 1999 +++ linux/fs/select.c Wed Jul 28 13:52:38 1999 @@ -106,7 +106,7 @@ /* handle last in-complete long-word first */ set = ~(~0UL << (n & (__NFDBITS-1))); n /= __NFDBITS; - open_fds = current->files->open_fds.fds_bits+n; + open_fds = current->files->open_fds->fds_bits+n; max = 0; if (set) { set &= BITS(fds, n); @@ -268,8 +268,8 @@ if (n < 0) goto out_nofds; - if (n > KFDS_NR) - n = KFDS_NR; + if (n > current->files->max_fdset) + n = current->files->max_fdset; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), @@ -380,7 +380,7 @@ lock_kernel(); /* Do a sanity check on nfds ... */ err = -EINVAL; - if (nfds > NR_OPEN) + if (nfds > current->files->max_fds) goto out; if (timeout) { diff -u --recursive --new-file v2.3.11/linux/include/asm-alpha/resource.h linux/include/asm-alpha/resource.h --- v2.3.11/linux/include/asm-alpha/resource.h Fri Aug 23 05:30:14 1996 +++ linux/include/asm-alpha/resource.h Mon Jul 26 22:41:09 1999 @@ -28,7 +28,7 @@ {_STK_LIM, _STK_LIM}, /* RLIMIT_STACK */ \ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ diff -u --recursive --new-file v2.3.11/linux/include/asm-arm/resource.h linux/include/asm-arm/resource.h --- v2.3.11/linux/include/asm-arm/resource.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/resource.h Mon Jul 26 22:41:09 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h --- v2.3.11/linux/include/asm-i386/apic.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/apic.h Sun Jul 25 10:26:01 1999 @@ -0,0 +1,95 @@ +#ifndef __ASM_APIC_H +#define __ASM_APIC_H + +/* + * Constants for various Intel APICs. (local APIC, IOAPIC, etc.) + * + * Alan Cox , 1995. + */ +#define APIC_PHYS_BASE 0xfee00000 /* IA s/w dev Vol 3, Section 7.4 */ + +#define APIC_ID 0x20 +#define GET_APIC_ID(x) (((x)>>24)&0x0F) +#define APIC_VERSION 0x30 +#define APIC_TASKPRI 0x80 +#define APIC_TPRI_MASK 0xFF +#define APIC_ARBPRI 0x90 +#define APIC_ARBPRI_MASK 0xFF +#define APIC_PROCPRI 0xA0 +#define APIC_EOI 0xB0 +#define APIC_EIO_ACK 0x0 /* Write this to the EOI register */ +#define APIC_RRR 0xC0 +#define APIC_LDR 0xD0 +#define APIC_LDR_MASK (0xFF<<24) +#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF) +#define SET_APIC_LOGICAL_ID(x) (((x)<<24)) +#define APIC_DFR 0xE0 +#define GET_APIC_DFR(x) (((x)>>28)&0x0F) +#define SET_APIC_DFR(x) ((x)<<28) +#define APIC_SPIV 0xF0 +#define APIC_ISR 0x100 +#define APIC_TMR 0x180 +#define APIC_IRR 0x200 +#define APIC_ESR 0x280 +#define APIC_ESR_SEND_CS 0x00001 +#define APIC_ESR_RECV_CS 0x00002 +#define APIC_ESR_SEND_ACC 0x00004 +#define APIC_ESR_RECV_ACC 0x00008 +#define APIC_ESR_SENDILL 0x00020 +#define APIC_ESR_RECVILL 0x00040 +#define APIC_ESR_ILLREGA 0x00080 +#define APIC_ICR 0x300 +#define APIC_DEST_SELF 0x40000 +#define APIC_DEST_ALLINC 0x80000 +#define APIC_DEST_ALLBUT 0xC0000 +#define APIC_DEST_RR_MASK 0x30000 +#define APIC_DEST_RR_INVALID 0x00000 +#define APIC_DEST_RR_INPROG 0x10000 +#define APIC_DEST_RR_VALID 0x20000 +#define APIC_DEST_LEVELTRIG 0x08000 +#define APIC_DEST_ASSERT 0x04000 +#define APIC_DEST_BUSY 0x01000 +#define APIC_DEST_LOGICAL 0x00800 +#define APIC_DEST_DM_FIXED 0x00000 +#define APIC_DEST_DM_LOWEST 0x00100 +#define APIC_DEST_DM_SMI 0x00200 +#define APIC_DEST_DM_REMRD 0x00300 +#define APIC_DEST_DM_NMI 0x00400 +#define APIC_DEST_DM_INIT 0x00500 +#define APIC_DEST_DM_STARTUP 0x00600 +#define APIC_DEST_VECTOR_MASK 0x000FF +#define APIC_ICR2 0x310 +#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) +#define SET_APIC_DEST_FIELD(x) ((x)<<24) +#define APIC_LVTT 0x320 +#define APIC_LVT0 0x350 +#define APIC_LVT_TIMER_PERIODIC (1<<17) +#define APIC_LVT_MASKED (1<<16) +#define APIC_LVT_LEVEL_TRIGGER (1<<15) +#define APIC_LVT_REMOTE_IRR (1<<14) +#define APIC_INPUT_POLARITY (1<<13) +#define APIC_SEND_PENDING (1<<12) +#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) +#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) +#define APIC_MODE_FIXED 0x0 +#define APIC_MODE_NMI 0x4 +#define APIC_MODE_EXINT 0x7 +#define APIC_LVT1 0x360 +#define APIC_LVERR 0x370 +#define APIC_TMICT 0x380 +#define APIC_TMCCT 0x390 +#define APIC_TDCR 0x3E0 +#define APIC_TDR_DIV_1 0xB +#define APIC_TDR_DIV_2 0x0 +#define APIC_TDR_DIV_4 0x1 +#define APIC_TDR_DIV_8 0x2 +#define APIC_TDR_DIV_16 0x3 +#define APIC_TDR_DIV_32 0x8 +#define APIC_TDR_DIV_64 0x9 +#define APIC_TDR_DIV_128 0xA + +#define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) + +#define MAX_IO_APICS 8 + +#endif diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h --- v2.3.11/linux/include/asm-i386/desc.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/desc.h Sun Jul 25 23:15:13 1999 @@ -69,17 +69,28 @@ extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size); extern void set_tss_desc(unsigned int n, void *addr); +extern inline void clear_LDT(void) +{ + int cpu = smp_processor_id(); + set_ldt_desc(cpu, &default_ldt, 1); + __load_LDT(cpu); +} + /* * load one particular LDT into the current CPU */ extern inline void load_LDT (struct mm_struct *mm) { int cpu = smp_processor_id(); + void *segments = mm->segments; + int count = LDT_ENTRIES; - if (mm->segments) - set_ldt_desc(cpu, mm->segments, LDT_ENTRIES); - else - set_ldt_desc(cpu, &default_ldt, 1); + if (!segments) { + segments = &default_ldt; + count = 1; + } + + set_ldt_desc(cpu, segments, count); __load_LDT(cpu); } diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h --- v2.3.11/linux/include/asm-i386/fixmap.h Tue Jun 22 14:41:40 1999 +++ linux/include/asm-i386/fixmap.h Wed Jul 28 13:56:29 1999 @@ -13,6 +13,7 @@ #include #include +#include #include /* @@ -45,7 +46,8 @@ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ #endif #ifdef CONFIG_X86_IO_APIC - FIX_IO_APIC_BASE, + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, #endif #ifdef CONFIG_X86_VISWS_APIC FIX_CO_CPU, /* Cobalt timer */ diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/i82489.h linux/include/asm-i386/i82489.h --- v2.3.11/linux/include/asm-i386/i82489.h Thu Jan 21 11:28:40 1999 +++ linux/include/asm-i386/i82489.h Wed Dec 31 16:00:00 1969 @@ -1,103 +0,0 @@ -#ifndef __ASM_I82489_H -#define __ASM_I82489_H - -/* - * Offsets for programming the 82489 and Pentium integrated APIC - * - * Alan Cox , 1995. - */ -#define APIC_PHYS_BASE 0xfee00000 /* IA s/w dev Vol 3, Section 7.4 */ - -#define APIC_ID 0x20 -#define GET_APIC_ID(x) (((x)>>24)&0x0F) -#define APIC_VERSION 0x30 -#define APIC_TASKPRI 0x80 -#define APIC_TPRI_MASK 0xFF -#define APIC_ARBPRI 0x90 -#define APIC_ARBPRI_MASK 0xFF -#define APIC_PROCPRI 0xA0 -#define APIC_EOI 0xB0 -#define APIC_EIO_ACK 0x0 /* Write this to the EOI register */ -#define APIC_RRR 0xC0 -#define APIC_LDR 0xD0 -#define APIC_LDR_MASK (0xFF<<24) -#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF) -#define SET_APIC_LOGICAL_ID(x) (((x)<<24)) -#define APIC_DFR 0xE0 -#define GET_APIC_DFR(x) (((x)>>28)&0x0F) -#define SET_APIC_DFR(x) ((x)<<28) -#define APIC_SPIV 0xF0 -#define APIC_ISR 0x100 -#define APIC_TMR 0x180 -#define APIC_IRR 0x200 -#define APIC_ESR 0x280 -#define APIC_ESR_SEND_CS 0x00001 -#define APIC_ESR_RECV_CS 0x00002 -#define APIC_ESR_SEND_ACC 0x00004 -#define APIC_ESR_RECV_ACC 0x00008 -#define APIC_ESR_SENDILL 0x00020 -#define APIC_ESR_RECVILL 0x00040 -#define APIC_ESR_ILLREGA 0x00080 -#define APIC_ICR 0x300 -#define APIC_DEST_SELF 0x40000 -#define APIC_DEST_ALLINC 0x80000 -#define APIC_DEST_ALLBUT 0xC0000 -#define APIC_DEST_RR_MASK 0x30000 -#define APIC_DEST_RR_INVALID 0x00000 -#define APIC_DEST_RR_INPROG 0x10000 -#define APIC_DEST_RR_VALID 0x20000 -#define APIC_DEST_LEVELTRIG 0x08000 -#define APIC_DEST_ASSERT 0x04000 -#define APIC_DEST_BUSY 0x01000 -#define APIC_DEST_LOGICAL 0x00800 -#define APIC_DEST_DM_FIXED 0x00000 -#define APIC_DEST_DM_LOWEST 0x00100 -#define APIC_DEST_DM_SMI 0x00200 -#define APIC_DEST_DM_REMRD 0x00300 -#define APIC_DEST_DM_NMI 0x00400 -#define APIC_DEST_DM_INIT 0x00500 -#define APIC_DEST_DM_STARTUP 0x00600 -#define APIC_DEST_VECTOR_MASK 0x000FF -#define APIC_ICR2 0x310 -#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) -#define SET_APIC_DEST_FIELD(x) ((x)<<24) -#define APIC_LVTT 0x320 -#define APIC_LVT0 0x350 -#define APIC_LVT_TIMER_PERIODIC (1<<17) -#define APIC_LVT_MASKED (1<<16) -#define APIC_LVT_LEVEL_TRIGGER (1<<15) -#define APIC_LVT_REMOTE_IRR (1<<14) -#define APIC_INPUT_POLARITY (1<<13) -#define APIC_SEND_PENDING (1<<12) -#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) -#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) -#define APIC_MODE_FIXED 0x0 -#define APIC_MODE_NMI 0x4 -#define APIC_MODE_EXINT 0x7 -#define APIC_LVT1 0x360 -#define APIC_LVERR 0x370 -#define APIC_TMICT 0x380 -#define APIC_TMCCT 0x390 -#define APIC_TDCR 0x3E0 -#define APIC_TDR_DIV_1 0xB -#define APIC_TDR_DIV_2 0x0 -#define APIC_TDR_DIV_4 0x1 -#define APIC_TDR_DIV_8 0x2 -#define APIC_TDR_DIV_16 0x3 -#define APIC_TDR_DIV_32 0x8 -#define APIC_TDR_DIV_64 0x9 -#define APIC_TDR_DIV_128 0xA - -#define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) - -extern __inline void apic_write(unsigned long reg, unsigned long v) -{ - *((volatile unsigned long *)(APIC_BASE+reg))=v; -} - -extern __inline unsigned long apic_read(unsigned long reg) -{ - return *((volatile unsigned long *)(APIC_BASE+reg)); -} - -#endif diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h --- v2.3.11/linux/include/asm-i386/mmu_context.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/mmu_context.h Wed Jul 28 13:56:27 1999 @@ -2,26 +2,29 @@ #define __I386_MMU_CONTEXT_H #include +#include /* - * get a new mmu context.. x86's don't know much about contexts, - * but we have to reload the new LDT in exec(). - * - * We implement lazy MMU context-switching on x86 to optimize context - * switches done to/from kernel threads. Kernel threads 'inherit' the - * previous MM, so Linux doesnt have to flush the TLB. In most cases - * we switch back to the same process so we preserve the TLB cache. - * This all means that kernel threads have about as much overhead as - * a function call ... - */ -#define get_mmu_context(next) do { } while (0) -#define set_mmu_context(prev,next) do { next->thread.cr3 = prev->thread.cr3; } while(0) - -#define init_new_context(mm) do { } while(0) -/* * possibly do the LDT unload here? */ -#define destroy_context(mm) do { } while(0) -#define activate_context(x) load_LDT((x)->mm) +#define destroy_context(mm) do { } while(0) +#define init_new_context(tsk,mm) do { } while (0) + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned cpu) +{ + + if (prev != next) { + /* + * Re-load LDT if necessary + */ + if (prev->segments != next->segments) + load_LDT(next); + + /* Re-load page tables */ + asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd))); + clear_bit(cpu, &prev->cpu_vm_mask); + } + set_bit(cpu, &next->cpu_vm_mask); +} #endif diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/parport.h linux/include/asm-i386/parport.h --- v2.3.11/linux/include/asm-i386/parport.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/parport.h Tue Jul 27 13:55:52 1999 @@ -0,0 +1,46 @@ +/* + * parport.h: ia32-specific parport initialisation + * + * Copyright (C) 1999 Tim Waugh + * + * This file should only be included by drivers/parport/parport_pc.c. + */ + +#ifndef _ASM_I386_PARPORT_H +#define _ASM_I386_PARPORT_H 1 + +/* Maximum number of ports to support. It is useless to set this greater + than PARPORT_MAX (in ). */ +#define PARPORT_PC_MAX_PORTS 8 + +static int __init probe_one_port(unsigned long int base, + unsigned long int base_hi, + int irq, int dma); +static int __init parport_pc_init_pci(int irq, int dma); + +static int user_specified __initdata = 0; +int __init +parport_pc_init(int *io, int *io_hi, int *irq, int *dma) +{ + int count = 0, i = 0; + + if (io && *io) { + /* Only probe the ports we were given. */ + user_specified = 1; + do { + if (!*io_hi) *io_hi = 0x400 + *io; + count += probe_one_port(*(io++), *(io_hi++), + *(irq++), *(dma++)); + } while (*io && (++i < PARPORT_PC_MAX_PORTS)); + } else { + /* Probe all the likely ports. */ + count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]); + count += probe_one_port(0x378, 0x778, irq[0], dma[0]); + count += probe_one_port(0x278, 0x678, irq[0], dma[0]); + count += parport_pc_init_pci (irq[0], dma[0]); + } + + return count; +} + +#endif /* !(_ASM_I386_PARPORT_H) */ diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.3.11/linux/include/asm-i386/pgtable.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/pgtable.h Wed Jul 28 13:56:31 1999 @@ -17,6 +17,8 @@ #include #include +extern pgd_t swapper_pg_dir[1024]; + /* Caches aren't brain-dead on the intel. */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) @@ -56,21 +58,21 @@ static inline void flush_tlb_mm(struct mm_struct *mm) { - if (mm == current->mm) + if (mm == current->active_mm) __flush_tlb(); } static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - if (vma->vm_mm == current->mm) + if (vma->vm_mm == current->active_mm) __flush_tlb_one(addr); } static inline void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - if (mm == current->mm) + if (mm == current->active_mm) __flush_tlb(); } @@ -86,79 +88,19 @@ #define local_flush_tlb() \ __flush_tlb() +extern void flush_tlb_all(void); +extern void flush_tlb_current_task(void); +extern void flush_tlb_mm(struct mm_struct *); +extern void flush_tlb_page(struct vm_area_struct *, unsigned long); -#define CLEVER_SMP_INVALIDATE -#ifdef CLEVER_SMP_INVALIDATE - -/* - * Smarter SMP flushing macros. - * c/o Linus Torvalds. - * - * These mean you can really definitely utterly forget about - * writing to user space from interrupts. (Its not allowed anyway). - */ - -static inline void flush_tlb_current_task(void) -{ - /* just one copy of this mm? */ - if (atomic_read(¤t->mm->mm_users) == 1) - local_flush_tlb(); /* and that's us, so.. */ - else - smp_flush_tlb(); -} - -#define flush_tlb() flush_tlb_current_task() - -#define flush_tlb_all() smp_flush_tlb() - -static inline void flush_tlb_mm(struct mm_struct * mm) -{ - if (mm == current->mm && atomic_read(&mm->mm_users) == 1) - local_flush_tlb(); - else - smp_flush_tlb(); -} - -static inline void flush_tlb_page(struct vm_area_struct * vma, - unsigned long va) -{ - if (vma->vm_mm == current->mm && atomic_read(¤t->mm->mm_users) == 1) - __flush_tlb_one(va); - else - smp_flush_tlb(); -} +#define flush_tlb() flush_tlb_current_task() -static inline void flush_tlb_range(struct mm_struct * mm, - unsigned long start, unsigned long end) +static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end) { flush_tlb_mm(mm); } -#else - -#define flush_tlb() \ - smp_flush_tlb() - -#define flush_tlb_all() flush_tlb() - -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - flush_tlb(); -} - -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) -{ - flush_tlb(); -} - -static inline void flush_tlb_range(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - flush_tlb(); -} -#endif #endif #endif /* !__ASSEMBLY__ */ @@ -302,15 +244,6 @@ #define PAGE_PTR(address) \ ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) -/* to set the page-dir */ -#define SET_PAGE_DIR(tsk,pgdir) \ -do { \ - unsigned long __pgdir = __pa(pgdir); \ - (tsk)->thread.cr3 = __pgdir; \ - if ((tsk) == current) \ - __asm__ __volatile__("movl %0,%%cr3": :"r" (__pgdir)); \ -} while (0) - #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0) @@ -401,13 +334,11 @@ extern __inline__ pgd_t *get_pgd_slow(void) { - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init; + pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); if (ret) { - init = pgd_offset(&init_mm, 0); - memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } return ret; } @@ -416,9 +347,9 @@ { unsigned long *ret; - if((ret = pgd_quicklist) != NULL) { + if ((ret = pgd_quicklist) != NULL) { pgd_quicklist = (unsigned long *)(*ret); - ret[0] = ret[1]; + ret[0] = 0; pgtable_cache_size--; } else ret = (unsigned long *)get_pgd_slow(); @@ -571,8 +502,6 @@ pgd[address >> PGDIR_SHIFT] = entry; #endif } - -extern pgd_t swapper_pg_dir[1024]; /* * The i386 doesn't have any external MMU info: the kernel page diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- v2.3.11/linux/include/asm-i386/processor.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/processor.h Wed Jul 28 13:56:29 1999 @@ -267,7 +267,7 @@ unsigned short ss1,__ss1h; unsigned long esp2; unsigned short ss2,__ss2h; - unsigned long cr3; + unsigned long __cr3; unsigned long eip; unsigned long eflags; unsigned long eax,ecx,edx,ebx; @@ -292,7 +292,6 @@ struct thread_struct { unsigned long esp0; - unsigned long cr3; unsigned long eip; unsigned long esp; unsigned long fs; @@ -313,7 +312,7 @@ }; #define INIT_THREAD { \ - 0,(long) &swapper_pg_dir - PAGE_OFFSET, \ + 0, \ 0, 0, 0, 0, \ { [0 ... 7] = 0 }, /* debugging registers */ \ 0, 0, 0, \ @@ -330,7 +329,7 @@ sizeof(init_stack) + (long) &init_stack, /* esp0 */ \ __KERNEL_DS, 0, /* ss0 */ \ 0,0,0,0,0,0, /* stack1, stack2 */ \ - (long) &swapper_pg_dir - PAGE_OFFSET, /* cr3 */ \ + 0, /* cr3 */ \ 0,0, /* eip,eflags */ \ 0,0,0,0, /* eax,ecx,edx,ebx */ \ 0,0,0,0, /* esp,ebp,esi,edi */ \ diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/resource.h linux/include/asm-i386/resource.h --- v2.3.11/linux/include/asm-i386/resource.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/resource.h Mon Jul 26 22:41:09 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { 0, 0 }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h --- v2.3.11/linux/include/asm-i386/semaphore.h Tue Jun 22 14:41:41 1999 +++ linux/include/asm-i386/semaphore.h Wed Jul 28 13:56:30 1999 @@ -17,6 +17,10 @@ * potential and subtle race discovered by Ulrich Schmid * in down_interruptible(). Since I started to play here I * also implemented the `trylock' semaphore operation. + * 1999-07-02 Artur Skawina + * Optimized "0(ecx)" -> "(ecx)" (the assembler does not + * do this). Changed calling sequences from push/jmp to + * traditional call/ret. * * If you would like to see an analysis of this implementation, please * ftp to gcom.com and download the file @@ -112,12 +116,12 @@ #ifdef __SMP__ "lock ; " #endif - "decl 0(%0)\n\t" + "decl (%0)\n\t" /* --sem->count */ "js 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" - "2:\tpushl $1b\n\t" - "jmp __down_failed\n" + "2:\tcall __down_failed\n\t" + "jmp 1b\n" ".previous" :/* no outputs */ :"c" (sem) @@ -137,13 +141,13 @@ #ifdef __SMP__ "lock ; " #endif - "decl 0(%1)\n\t" + "decl (%1)\n\t" /* --sem->count */ "js 2f\n\t" "xorl %0,%0\n" "1:\n" ".section .text.lock,\"ax\"\n" - "2:\tpushl $1b\n\t" - "jmp __down_failed_interruptible\n" + "2:\tcall __down_failed_interruptible\n\t" + "jmp 1b\n" ".previous" :"=a" (result) :"c" (sem) @@ -164,13 +168,13 @@ #ifdef __SMP__ "lock ; " #endif - "decl 0(%1)\n\t" + "decl (%1)\n\t" /* --sem->count */ "js 2f\n\t" "xorl %0,%0\n" "1:\n" ".section .text.lock,\"ax\"\n" - "2:\tpushl $1b\n\t" - "jmp __down_failed_trylock\n" + "2:\tcall __down_failed_trylock\n\t" + "jmp 1b\n" ".previous" :"=a" (result) :"c" (sem) @@ -194,12 +198,12 @@ #ifdef __SMP__ "lock ; " #endif - "incl 0(%0)\n\t" + "incl (%0)\n\t" /* ++sem->count */ "jle 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" - "2:\tpushl $1b\n\t" - "jmp __up_wakeup\n" + "2:\tcall __up_wakeup\n\t" + "jmp 1b\n" ".previous" :/* no outputs */ :"c" (sem) diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h --- v2.3.11/linux/include/asm-i386/signal.h Sun Dec 27 22:18:28 1998 +++ linux/include/asm-i386/signal.h Wed Jul 28 12:55:50 1999 @@ -180,12 +180,12 @@ extern __inline__ void sigaddset(sigset_t *set, int _sig) { - __asm__("btsl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc"); + __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } extern __inline__ void sigdelset(sigset_t *set, int _sig) { - __asm__("btrl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc"); + __asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } extern __inline__ int __const_sigismember(sigset_t *set, int _sig) @@ -198,7 +198,7 @@ { int ret; __asm__("btl %2,%1\n\tsbbl %0,%0" - : "=r"(ret) : "m"(*set), "ir"(_sig-1) : "cc"); + : "=r"(ret) : "m"(*set), "Ir"(_sig-1) : "cc"); return ret; } diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h --- v2.3.11/linux/include/asm-i386/smp.h Wed Jul 21 15:46:48 1999 +++ linux/include/asm-i386/smp.h Wed Jul 28 13:56:29 1999 @@ -8,7 +8,7 @@ #ifdef CONFIG_X86_LOCAL_APIC #ifndef ASSEMBLY #include -#include +#include #include #endif #endif @@ -184,6 +184,16 @@ extern inline int cpu_logical_map(int cpu) { return __cpu_logical_map[cpu]; +} + +extern __inline void apic_write(unsigned long reg, unsigned long v) +{ + *((volatile unsigned long *)(APIC_BASE+reg))=v; +} + +extern __inline unsigned long apic_read(unsigned long reg) +{ + return *((volatile unsigned long *)(APIC_BASE+reg)); } diff -u --recursive --new-file v2.3.11/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h --- v2.3.11/linux/include/asm-m68k/resource.h Tue Jan 5 11:20:43 1999 +++ linux/include/asm-m68k/resource.h Mon Jul 26 22:41:09 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ - {NR_OPEN, NR_OPEN}, \ + {INR_OPEN, INR_OPEN}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX} \ } diff -u --recursive --new-file v2.3.11/linux/include/asm-mips/resource.h linux/include/asm-mips/resource.h --- v2.3.11/linux/include/asm-mips/resource.h Wed Jun 30 13:38:20 1999 +++ linux/include/asm-mips/resource.h Mon Jul 26 22:41:09 1999 @@ -34,7 +34,7 @@ { LONG_MAX, LONG_MAX }, \ { _STK_LIM, LONG_MAX }, \ { 0, LONG_MAX }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ diff -u --recursive --new-file v2.3.11/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h --- v2.3.11/linux/include/asm-ppc/resource.h Mon Dec 21 08:37:24 1998 +++ linux/include/asm-ppc/resource.h Mon Jul 26 22:41:09 1999 @@ -25,7 +25,7 @@ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ } diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h --- v2.3.11/linux/include/asm-sparc/resource.h Wed Mar 10 16:53:37 1999 +++ linux/include/asm-sparc/resource.h Mon Jul 26 22:41:09 1999 @@ -31,7 +31,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc64/parport.h linux/include/asm-sparc64/parport.h --- v2.3.11/linux/include/asm-sparc64/parport.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/parport.h Tue Jul 27 13:55:52 1999 @@ -0,0 +1,152 @@ +/* $Id$ + * parport.h: sparc64 specific parport initialization and dma. + * + * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) + */ + +#ifndef _ASM_SPARC64_PARPORT_H +#define _ASM_SPARC64_PARPORT_H 1 + +#include +#include + +static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_MAX]; + +static __inline__ void +reset_dma(unsigned int dmanr) +{ + unsigned int dcsr; + + dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr) & EBUS_DCSR_INT_EN; + writel(EBUS_DCSR_RESET, &sparc_ebus_dmas[dmanr]->dcsr); + + dcsr |= EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS | + EBUS_DCSR_EN_CNT; + writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr); +} + +static __inline__ void +enable_dma(unsigned int dmanr) +{ + unsigned int dcsr; + + dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr); + dcsr |= EBUS_DCSR_EN_DMA; + writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr); +} + +static __inline__ void +disable_dma(unsigned int dmanr) +{ + unsigned int dcsr; + + dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr); + while (dcsr & EBUS_DCSR_DRAIN) + dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr); + dcsr &= ~(EBUS_DCSR_EN_DMA); + if (dcsr & EBUS_DCSR_ERR_PEND) { + reset_dma(dmanr); + dcsr &= ~(EBUS_DCSR_ERR_PEND); + } + writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr); +} + +static __inline__ void +clear_dma_ff(unsigned int dmanr) +{ + /* nothing */ +} + +static __inline__ void +set_dma_mode(unsigned int dmanr, char mode) +{ + unsigned int dcsr; + + dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr); + dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC; + if (mode == DMA_MODE_WRITE) + dcsr &= ~(EBUS_DCSR_WRITE); + else + dcsr |= EBUS_DCSR_WRITE; + writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr); +} + +static __inline__ void +set_dma_addr(unsigned int dmanr, unsigned int addr) +{ + writel(addr, &sparc_ebus_dmas[dmanr]->dacr); +} + +static __inline__ void +set_dma_count(unsigned int dmanr, unsigned int count) +{ + writel(count, &sparc_ebus_dmas[dmanr]->dbcr); +} + +static __inline__ int +get_dma_residue(unsigned int dmanr) +{ + return readl(&sparc_ebus_dmas[dmanr]->dbcr); +} + +static int __init probe_one_port(unsigned long int base, + unsigned long int base_hi, + int irq, int dma); +static int __init parport_pc_init_pci(int irq, int dma); + +int __init +parport_pc_init(int *io, int *io_hi, int *irq, int *dma) +{ + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + int count = 0; + + if (!pci_present()) + return 0; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "ecpp")) { + unsigned long base = edev->base_address[0]; + unsigned long config = edev->base_address[1]; + unsigned char cfg; + + sparc_ebus_dmas[count] = + (struct linux_ebus_dma *) + edev->base_address[2]; + + /* Enable ECP, set bit 2 of the CTR first */ + outb(0x04, base + 0x02); + cfg = ns87303_readb(config, PCR); + cfg |= (PCR_ECP_ENABLE | PCR_ECP_CLK_ENA); + ns87303_writeb(config, PCR, cfg); + + /* CTR bit 5 controls direction of port */ + cfg = ns87303_readb(config, PTR); + cfg |= PTR_LPT_REG_DIR; + ns87303_writeb(config, PTR, cfg); + + /* Configure IRQ to Push Pull, Level Low */ + cfg = ns87303_readb(config, PCR); + cfg &= ~(PCR_IRQ_ODRAIN); + cfg |= PCR_IRQ_POLAR; + ns87303_writeb(config, PCR, cfg); + +#ifndef HAVE_SLOW_DEVICES + /* Enable Zero Wait State for ECP */ + cfg = ns87303_readb(config, FCR); + cfg |= FCR_ZWS_ENA; + ns87303_writeb(config, FCR, cfg); +#endif + + count += probe_one_port(base, base + 0x400, + edev->irqs[0], count); + } + } + } + + count += parport_pc_init_pci(PARPORT_IRQ_AUTO, PARPORT_DMA_NONE); + return count; +} + +#endif /* !(_ASM_SPARC64_PARPORT_H */ diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h --- v2.3.11/linux/include/asm-sparc64/resource.h Wed Mar 10 16:53:38 1999 +++ linux/include/asm-sparc64/resource.h Mon Jul 26 22:41:09 1999 @@ -30,7 +30,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -u --recursive --new-file v2.3.11/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h --- v2.3.11/linux/include/linux/arcdevice.h Tue Dec 29 11:18:18 1998 +++ linux/include/linux/arcdevice.h Wed Jul 28 11:23:14 1999 @@ -69,7 +69,7 @@ * increased. The larger it is, though, the longer it will be between * necessary transmits - don't set this too large. */ -#define TX_TIMEOUT 20 +#define TX_TIMEOUT (20*HZ/100) /* Display warnings about the driver being an ALPHA version. diff -u --recursive --new-file v2.3.11/linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- v2.3.11/linux/include/linux/binfmts.h Wed Jun 30 13:38:20 1999 +++ linux/include/linux/binfmts.h Wed Jul 28 13:56:37 1999 @@ -38,7 +38,8 @@ struct module *module; int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(int fd); - int (*core_dump)(long signr, struct pt_regs * regs); + int (*core_dump)(long signr, struct pt_regs * regs, struct file * file); + unsigned long min_coredump; /* minimal dump size */ }; extern int register_binfmt(struct linux_binfmt *); @@ -66,6 +67,7 @@ extern int copy_strings(int argc,char ** argv,struct linux_binprm *bprm); extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm); extern void compute_creds(struct linux_binprm *binprm); +extern int do_coredump(long signr, struct pt_regs * regs); #if 0 diff -u --recursive --new-file v2.3.11/linux/include/linux/file.h linux/include/linux/file.h --- v2.3.11/linux/include/linux/file.h Wed Jul 21 15:46:48 1999 +++ linux/include/linux/file.h Mon Jul 26 22:41:09 1999 @@ -56,18 +56,6 @@ } /* - * Install a file pointer in the fd array. - */ -extern inline void fd_install(unsigned int fd, struct file * file) -{ - struct files_struct *files = current->files; - - write_lock(&files->file_lock); - files->fd[fd] = file; - write_unlock(&files->file_lock); -} - -/* * 23/12/1998 Marcin Dalecki : * * Since those functions where calling other functions, it was compleatly @@ -89,5 +77,27 @@ _fput(file); } extern void put_filp(struct file *); + +/* + * Install a file pointer in the fd array. + * + * The VFS is full of places where we drop the files lock between + * setting the open_fds bitmap and installing the file in the file + * array. At any such point, we are vulnerable to a dup2() race + * installing a file in the array before us. We need to detect this and + * fput() the struct file we are about to overwrite in this case. + */ + +extern inline void fd_install(unsigned int fd, struct file * file) +{ + struct files_struct *files = current->files; + struct file * result; + + write_lock(&files->file_lock); + result = xchg(&files->fd[fd], file); + write_unlock(&files->file_lock); + if (result) + fput(result); +} #endif /* __LINUX_FILE_H */ diff -u --recursive --new-file v2.3.11/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.3.11/linux/include/linux/fs.h Thu Jul 8 15:42:21 1999 +++ linux/include/linux/fs.h Wed Jul 28 13:56:34 1999 @@ -27,17 +27,19 @@ /* - * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix - * that later. Anyway, now the file code is no longer dependent - * on bitmaps in unsigned longs, but uses the new fd_set structure.. + * It's silly to have NR_OPEN bigger than NR_FILE, but you can change + * the file limit at runtime and only root can increase the per-process + * nr_file rlimit, so it's safe to set up a ridiculously high absolute + * upper limit on files-per-process. * * Some programs (notably those using select()) may have to be - * recompiled to take full advantage of the new limits.. + * recompiled to take full advantage of the new limits.. */ /* Fixed constants first: */ #undef NR_OPEN -#define NR_OPEN 1024 +#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ +#define INR_OPEN 1024 /* Initial setting for nfile rlimits */ #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1< +#include +#include +#include + +/* + * The kiobuf structure describes a physical set of pages reserved + * locked for IO. The reference counts on each page will have been + * incremented, and the flags field will indicate whether or not we have + * pre-locked all of the pages for IO. + * + * kiobufs may be passed in arrays to form a kiovec, but we must + * preserve the property that no page is present more than once over the + * entire iovec. + */ + +#define KIO_MAX_ATOMIC_IO 64 /* in kb */ +#define KIO_MAX_ATOMIC_BYTES (64 * 1024) +#define KIO_STATIC_PAGES (KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1) +#define KIO_MAX_SECTORS (KIO_MAX_ATOMIC_IO * 2) + +struct kiobuf +{ + int nr_pages; /* Pages actually referenced */ + int array_len; /* Space in the allocated lists */ + int offset; /* Offset to start of valid data */ + int length; /* Number of valid bytes of data */ + + /* Keep separate track of the physical addresses and page + * structs involved. If we do IO to a memory-mapped device + * region, there won't necessarily be page structs defined for + * every address. */ + + unsigned long * pagelist; + struct page ** maplist; + + unsigned int locked : 1; /* If set, pages has been locked */ + + /* Always embed enough struct pages for 64k of IO */ + unsigned long page_array[KIO_STATIC_PAGES]; + struct page * map_array[KIO_STATIC_PAGES]; + + /* Dynamic state for IO completion: */ + atomic_t io_count; /* IOs still in progress */ + int errno; /* Status of completed IO */ + void (*end_io) (struct kiobuf *); /* Completion callback */ + wait_queue_head_t wait_queue; +}; + + +/* mm/memory.c */ + +int map_user_kiobuf(int rw, struct kiobuf *, unsigned long va, size_t len); +void unmap_kiobuf(struct kiobuf *iobuf); + +/* fs/iobuf.c */ + +void __init kiobuf_init(void); +void simple_wakeup_kiobuf(struct kiobuf *); +int alloc_kiovec(int nr, struct kiobuf **); +void free_kiovec(int nr, struct kiobuf **); +int expand_kiobuf(struct kiobuf *, int); +void kiobuf_wait_for_io(struct kiobuf *); + +/* fs/buffer.c */ + +int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, int bmap); + +#endif /* __LINUX_IOBUF_H */ diff -u --recursive --new-file v2.3.11/linux/include/linux/limits.h linux/include/linux/limits.h --- v2.3.11/linux/include/linux/limits.h Tue Dec 2 13:44:40 1997 +++ linux/include/linux/limits.h Wed Jul 28 10:30:10 1999 @@ -1,7 +1,7 @@ #ifndef _LINUX_LIMITS_H #define _LINUX_LIMITS_H -#define NR_OPEN 1024 +#define NR_OPEN 1024 #define NGROUPS_MAX 32 /* supplemental group IDs are available */ #define ARG_MAX 131072 /* # bytes of args + environ for exec() */ diff -u --recursive --new-file v2.3.11/linux/include/linux/major.h linux/include/linux/major.h --- v2.3.11/linux/include/linux/major.h Thu Jul 8 15:42:21 1999 +++ linux/include/linux/major.h Mon Jul 26 22:50:35 1999 @@ -115,6 +115,8 @@ #define AURORA_MAJOR 79 +#define RAW_MAJOR 162 + #define UNIX98_PTY_MASTER_MAJOR 128 #define UNIX98_PTY_MAJOR_COUNT 8 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) diff -u --recursive --new-file v2.3.11/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.3.11/linux/include/linux/mm.h Wed Jul 21 15:46:48 1999 +++ linux/include/linux/mm.h Wed Jul 28 13:56:38 1999 @@ -304,7 +304,6 @@ extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, unsigned long address); -extern void free_page_tables(struct mm_struct * mm); extern void clear_page_tables(struct mm_struct *, unsigned long, int); extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size); diff -u --recursive --new-file v2.3.11/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.3.11/linux/include/linux/parport.h Wed Jul 21 15:46:48 1999 +++ linux/include/linux/parport.h Wed Jul 28 13:57:23 1999 @@ -74,6 +74,7 @@ * parport_negotiate to use address operations. They have no effect * other than to make parport_read/write use address transfers. */ #define IEEE1284_ADDR (1<<13) /* This is a flag */ +#define IEEE1284_DATA 0 /* So is this */ /* The rest is for the kernel only */ #ifdef __KERNEL__ @@ -143,7 +144,7 @@ void (*data_reverse) (struct parport *); /* For core parport code. */ - void (*interrupt)(int, void *, struct pt_regs *); /* ? */ + void (*interrupt)(int, void *, struct pt_regs *); void (*init_state)(struct pardevice *, struct parport_state *); void (*save_state)(struct parport *, struct parport_state *); @@ -151,7 +152,6 @@ void (*inc_use_count)(void); void (*dec_use_count)(void); - void (*fill_inode)(struct inode *inode, int fill); /* ? */ /* Block read/write */ size_t (*epp_write_data) (struct parport *port, const void *buf, diff -u --recursive --new-file v2.3.11/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.3.11/linux/include/linux/pci.h Thu Jul 8 15:42:21 1999 +++ linux/include/linux/pci.h Wed Jul 28 13:56:27 1999 @@ -994,8 +994,34 @@ #define PCI_VENDOR_ID_CBOARDS 0x1307 #define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001 +#define PCI_VENDOR_ID_SIIG 0x131f +#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012 +#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020 +#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036 +#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020 +#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 + #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a + +#define PCI_VENDOR_ID_LAVA 0x1407 +#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 */ #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_DEVICE_ID_SYMPHONY_101 0x0001 diff -u --recursive --new-file v2.3.11/linux/include/linux/raw.h linux/include/linux/raw.h --- v2.3.11/linux/include/linux/raw.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/raw.h Mon Jul 26 22:50:35 1999 @@ -0,0 +1,23 @@ +#ifndef __LINUX_RAW_H +#define __LINUX_RAW_H + +#include + +#define RAW_SETBIND _IO( 0xac, 0 ) +#define RAW_GETBIND _IO( 0xac, 1 ) + +struct raw_config_request +{ + int raw_minor; + __u64 block_major; + __u64 block_minor; +}; + +#ifdef __KERNEL__ + +/* drivers/char/raw.c */ +extern void raw_init(void); + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_RAW_H */ diff -u --recursive --new-file v2.3.11/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.3.11/linux/include/linux/sched.h Wed Jul 21 15:46:48 1999 +++ linux/include/linux/sched.h Wed Jul 28 13:56:37 1999 @@ -35,6 +35,7 @@ #define CLONE_PID 0x00001000 /* set if pid shared */ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ +#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ /* * These are the constant used to fake the fixed-point load-average @@ -127,24 +128,40 @@ asmlinkage void schedule(void); /* + * The default fd array needs to be at least BITS_PER_LONG, + * as this is the granularity returned by copy_fdset(). + */ +#define NR_OPEN_DEFAULT BITS_PER_LONG + +/* * Open file table structure */ struct files_struct { atomic_t count; rwlock_t file_lock; int max_fds; + int max_fdset; + int next_fd; struct file ** fd; /* current fd array */ - fd_set close_on_exec; - fd_set open_fds; + fd_set *close_on_exec; + fd_set *open_fds; + fd_set close_on_exec_init; + fd_set open_fds_init; + struct file * fd_array[NR_OPEN_DEFAULT]; }; #define INIT_FILES { \ ATOMIC_INIT(1), \ RW_LOCK_UNLOCKED, \ - NR_OPEN, \ - &init_fd_array[0], \ + NR_OPEN_DEFAULT, \ + __FD_SETSIZE, \ + 0, \ + &init_files.fd_array[0], \ + &init_files.close_on_exec_init, \ + &init_files.open_fds_init, \ { { 0, } }, \ - { { 0, } } \ + { { 0, } }, \ + { NULL, } \ } struct fs_struct { @@ -593,6 +610,9 @@ */ extern struct mm_struct * mm_alloc(void); +extern struct mm_struct * start_lazy_tlb(void); +extern void end_lazy_tlb(struct mm_struct *mm); + /* mmdrop drops the mm and the page tables */ extern inline void FASTCALL(__mmdrop(struct mm_struct *)); static inline void mmdrop(struct mm_struct * mm) @@ -605,6 +625,48 @@ extern void mmput(struct mm_struct *); /* Remove the current tasks stale references to the old mm_struct */ extern void mm_release(void); + +/* + * Routines for handling the fd arrays + */ +extern struct file ** alloc_fd_array(int); +extern int expand_fd_array(struct files_struct *, int nr); +extern void free_fd_array(struct file **, int); + +extern fd_set *alloc_fdset(int); +extern int expand_fdset(struct files_struct *, int nr); +extern void free_fdset(fd_set *, int); + +/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, + * we may have blocked. + * + * Should be called with the files->file_lock spinlock held for write. + */ +static inline int expand_files(struct files_struct *files, int nr) +{ + int err, expand = 0; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); diff -u --recursive --new-file v2.3.11/linux/init/main.c linux/init/main.c --- v2.3.11/linux/init/main.c Wed Jul 21 15:46:48 1999 +++ linux/init/main.c Mon Jul 26 22:50:35 1999 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1193,6 +1194,7 @@ vma_init(); buffer_init(memory_end-memory_start); page_cache_init(memory_end-memory_start); + kiobuf_init(); signals_init(); inode_init(); file_table_init(); diff -u --recursive --new-file v2.3.11/linux/kernel/exit.c linux/kernel/exit.c --- v2.3.11/linux/kernel/exit.c Wed Jul 21 15:46:48 1999 +++ linux/kernel/exit.c Wed Jul 28 10:30:45 1999 @@ -26,13 +26,17 @@ { if (p != current) { #ifdef __SMP__ + int has_cpu; + /* * Wait to make sure the process isn't on the * runqueue (active on some other CPU still) */ do { - barrier(); - } while (p->has_cpu); + spin_lock_irq(&runqueue_lock); + has_cpu = p->has_cpu; + spin_unlock_irq(&runqueue_lock); + } while (has_cpu); #endif free_uid(p); unhash_process(p); @@ -145,11 +149,11 @@ j = 0; for (;;) { - unsigned long set = files->open_fds.fds_bits[j]; + unsigned long set; i = j * __NFDBITS; - j++; - if (i >= files->max_fds) + if (i >= files->max_fdset || i >= files->max_fds) break; + set = files->open_fds->fds_bits[j++]; while (set) { if (set & 1) { struct file * file = xchg(&files->fd[i], NULL); @@ -172,12 +176,14 @@ if (atomic_dec_and_test(&files->count)) { close_files(files); /* - * Free the fd array as appropriate ... + * Free the fd and fdset arrays if we expanded them. */ - if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE) - free_page((unsigned long) files->fd); - else - kfree(files->fd); + if (files->fd != &files->fd_array[0]) + free_fd_array(files->fd, files->max_fds); + if (files->max_fdset > __FD_SETSIZE) { + free_fdset(files->open_fds, files->max_fdset); + free_fdset(files->close_on_exec, files->max_fdset); + } kmem_cache_free(files_cachep, files); } } @@ -230,6 +236,31 @@ } /* + * We can use these to temporarily drop into + * "lazy TLB" mode and back. + */ +struct mm_struct * start_lazy_tlb(void) +{ + struct mm_struct *mm = current->mm; + current->mm = NULL; + /* active_mm is still 'mm' */ + atomic_inc(&mm->mm_count); + return mm; +} + +void end_lazy_tlb(struct mm_struct *mm) +{ + struct mm_struct *active_mm = current->active_mm; + + current->mm = mm; + if (mm != active_mm) { + current->active_mm = mm; + switch_mm(active_mm, mm, current->processor); + } + mmdrop(active_mm); +} + +/* * Turn us into a lazy TLB process if we * aren't already.. */ @@ -238,8 +269,9 @@ struct mm_struct * mm = tsk->mm; if (mm) { - mm_release(); atomic_inc(&mm->mm_count); + mm_release(); + if (mm != tsk->active_mm) BUG(); tsk->mm = NULL; mmput(mm); } diff -u --recursive --new-file v2.3.11/linux/kernel/fork.c linux/kernel/fork.c --- v2.3.11/linux/kernel/fork.c Wed Jul 21 15:46:48 1999 +++ linux/kernel/fork.c Wed Jul 28 13:23:22 1999 @@ -300,13 +300,39 @@ mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL); if (mm) { memset(mm, 0, sizeof(*mm)); - init_new_context(mm); atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); init_MUTEX(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; + mm->pgd = pgd_alloc(); + if (mm->pgd) + return mm; + kmem_cache_free(mm_cachep, mm); + } + return NULL; +} + +/* + * Called when the last reference to the mm + * is dropped: either by a lazy thread or by + * mmput. Free the page directory and the mm. + */ +inline void __mmdrop(struct mm_struct *mm) +{ + if (mm == &init_mm) BUG(); + pgd_free(mm->pgd); + kmem_cache_free(mm_cachep, mm); +} + +/* + * Decrement the use count and release all resources for an mm. + */ +void mmput(struct mm_struct *mm) +{ + if (atomic_dec_and_test(&mm->mm_users)) { + exit_mmap(mm); + mmdrop(mm); } - return mm; } /* Please note the differences between mmput and mm_release. @@ -333,30 +359,6 @@ } } -/* - * Called when the last reference to the mm - * is dropped: either by a lazy thread or by - * mmput - */ -inline void __mmdrop(struct mm_struct *mm) -{ - if (mm == &init_mm) BUG(); - free_page_tables(mm); - kmem_cache_free(mm_cachep, mm); -} - -/* - * Decrement the use count and release all resources for an mm. - */ -void mmput(struct mm_struct *mm) -{ - if (atomic_dec_and_test(&mm->mm_users)) { - release_segments(mm); - exit_mmap(mm); - mmdrop(mm); - } -} - static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) { struct mm_struct * mm; @@ -391,10 +393,6 @@ tsk->mm = mm; tsk->active_mm = mm; - mm->pgd = pgd_alloc(); - if (!mm->pgd) - goto free_mm; - /* * child gets a private LDT (if there was an LDT in the parent) */ @@ -409,12 +407,9 @@ good_mm: tsk->mm = mm; tsk->active_mm = mm; - SET_PAGE_DIR(tsk, mm->pgd); + init_new_context(tsk,mm); return 0; -free_mm: - kmem_cache_free(mm_cachep, mm); - return retval; free_pt: mmput(mm); fail_nomem: @@ -437,32 +432,24 @@ return 0; } -/* - * Copy a fd_set and compute the maximum fd it contains. - */ -static inline int __copy_fdset(unsigned long *d, unsigned long *src) +static int count_open_files(struct files_struct *files, int size) { - int i; - unsigned long *p = src; - unsigned long *max = src; - - for (i = __FDSET_LONGS; i; --i) { - if ((*d++ = *p++) != 0) - max = p; + int i; + + /* Find the last open fd */ + for (i = size/(8*sizeof(long)); i > 0; ) { + if (files->open_fds->fds_bits[--i]) + break; } - return (max - src)*sizeof(long)*8; -} - -static inline int copy_fdset(fd_set *dst, fd_set *src) -{ - return __copy_fdset(dst->fds_bits, src->fds_bits); + i = (i+1) * 8 * sizeof(long); + return i; } static int copy_files(unsigned long clone_flags, struct task_struct * tsk) { struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; - int size, i, error = 0; + int open_files, nfds, size, i, error = 0; /* * A background process may not have any files ... @@ -482,43 +469,85 @@ if (!newf) goto out; - /* - * Allocate the fd array, using get_free_page() if possible. - * Eventually we want to make the array size variable ... - */ - size = NR_OPEN * sizeof(struct file *); - if (size == PAGE_SIZE) - new_fds = (struct file **) __get_free_page(GFP_KERNEL); - else - new_fds = (struct file **) kmalloc(size, GFP_KERNEL); - if (!new_fds) - goto out_release; - - newf->file_lock = RW_LOCK_UNLOCKED; atomic_set(&newf->count, 1); - newf->max_fds = NR_OPEN; - newf->fd = new_fds; + + newf->file_lock = RW_LOCK_UNLOCKED; + newf->next_fd = 0; + newf->max_fds = NR_OPEN_DEFAULT; + newf->max_fdset = __FD_SETSIZE; + newf->close_on_exec = &newf->close_on_exec_init; + newf->open_fds = &newf->open_fds_init; + newf->fd = &newf->fd_array[0]; + + /* We don't yet have the oldf readlock, but even if the old + fdset gets grown now, we'll only copy up to "size" fds */ + size = oldf->max_fdset; + if (size > __FD_SETSIZE) { + newf->max_fdset = 0; + write_lock(&newf->file_lock); + error = expand_fdset(newf, size); + write_unlock(&newf->file_lock); + if (error) + goto out_release; + } read_lock(&oldf->file_lock); - newf->close_on_exec = oldf->close_on_exec; - i = copy_fdset(&newf->open_fds, &oldf->open_fds); + + open_files = count_open_files(oldf, size); + + /* + * Check whether we need to allocate a larger fd array. + * Note: we're not a clone task, so the open count won't + * change. + */ + nfds = NR_OPEN_DEFAULT; + if (open_files > nfds) { + read_unlock(&oldf->file_lock); + newf->max_fds = 0; + write_lock(&newf->file_lock); + error = expand_fd_array(newf, open_files); + write_unlock(&newf->file_lock); + if (error) + goto out_release; + nfds = newf->max_fds; + read_lock(&oldf->file_lock); + } old_fds = oldf->fd; - for (; i != 0; i--) { + new_fds = newf->fd; + + memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); + memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); + + for (i = open_files; i != 0; i--) { struct file *f = *old_fds++; if (f) get_file(f); *new_fds++ = f; } read_unlock(&oldf->file_lock); + + /* compute the remainder to be cleared */ + size = (newf->max_fds - open_files) * sizeof(struct file *); + /* This is long word aligned thus could use a optimized version */ - memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); - + memset(new_fds, 0, size); + + if (newf->max_fdset > open_files) { + int left = (newf->max_fdset-open_files)/8; + int start = open_files / (8 * sizeof(unsigned long)); + + memset(&newf->open_fds->fds_bits[start], 0, left); + memset(&newf->close_on_exec->fds_bits[start], 0, left); + } + tsk->files = newf; error = 0; out: return error; out_release: + free_fdset (newf->close_on_exec, newf->max_fdset); + free_fdset (newf->open_fds, newf->max_fdset); kmem_cache_free(files_cachep, newf); goto out; } @@ -608,7 +637,8 @@ p->run_list.next = NULL; p->run_list.prev = NULL; - p->p_pptr = p->p_opptr = current; + if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) + p->p_pptr = p->p_opptr = current; p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); p->vfork_sem = NULL; diff -u --recursive --new-file v2.3.11/linux/kernel/sched.c linux/kernel/sched.c --- v2.3.11/linux/kernel/sched.c Wed Jul 21 15:46:48 1999 +++ linux/kernel/sched.c Wed Jul 28 10:45:39 1999 @@ -621,15 +621,6 @@ */ static inline void __schedule_tail(struct task_struct *prev) { - if (!current->active_mm) BUG(); - - if (!prev->mm) { - struct mm_struct *mm = prev->active_mm; - if (mm) { - prev->active_mm = NULL; - mmdrop(mm); - } - } #ifdef __SMP__ if ((prev->state == TASK_RUNNING) && (prev != idle_task(smp_processor_id()))) @@ -790,16 +781,26 @@ */ { struct mm_struct *mm = next->mm; + struct mm_struct *oldmm = prev->active_mm; if (!mm) { - mm = prev->active_mm; - set_mmu_context(prev,next); if (next->active_mm) BUG(); - next->active_mm = mm; - atomic_inc(&mm->mm_count); + next->active_mm = oldmm; + atomic_inc(&oldmm->mm_count); + } else { + if (next->active_mm != mm) BUG(); + switch_mm(oldmm, mm, this_cpu); + } + + if (!prev->mm) { + prev->active_mm = NULL; + mmdrop(oldmm); } } - get_mmu_context(next); + /* + * This just switches the register state and the + * stack. + */ switch_to(prev, next, prev); __schedule_tail(prev); diff -u --recursive --new-file v2.3.11/linux/lib/vsprintf.c linux/lib/vsprintf.c --- v2.3.11/linux/lib/vsprintf.c Mon Mar 15 11:19:05 1999 +++ linux/lib/vsprintf.c Sat Jul 24 16:42:01 1999 @@ -156,7 +156,9 @@ int precision; /* min. # of digits for integers; max number of chars for from string */ int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + for (str=buf ; *fmt ; ++fmt) { if (*fmt != '%') { *str++ = *fmt; @@ -206,7 +208,7 @@ /* get the conversion qualifier */ qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='z') { qualifier = *fmt; ++fmt; } @@ -255,6 +257,9 @@ if (qualifier == 'l') { long * ip = va_arg(args, long *); *ip = (str - buf); + } else if (qualifier == 'z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); } else { int * ip = va_arg(args, int *); *ip = (str - buf); @@ -292,6 +297,8 @@ } if (qualifier == 'l') num = va_arg(args, unsigned long); + else if (qualifier == 'z') + num = va_arg(args, size_t); else if (qualifier == 'h') { num = (unsigned short) va_arg(args, int); if (flags & SIGN) diff -u --recursive --new-file v2.3.11/linux/mm/memory.c linux/mm/memory.c --- v2.3.11/linux/mm/memory.c Wed Jul 21 15:46:48 1999 +++ linux/mm/memory.c Wed Jul 28 11:32:23 1999 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -142,28 +143,6 @@ check_pgt_cache(); } -/* - * This function just free's the page directory - the - * pages tables themselves have been freed earlier by - * clear_page_tables(). - */ -void free_page_tables(struct mm_struct * mm) -{ - pgd_t * page_dir = mm->pgd; - - if (page_dir) { - if (page_dir == swapper_pg_dir) - goto out_bad; - pgd_free(page_dir); - } - return; - -out_bad: - printk(KERN_ERR - "free_page_tables: Trying to free kernel pgd\n"); - return; -} - #define PTE_TABLE_MASK ((PTRS_PER_PTE-1) * sizeof(pte_t)) #define PMD_TABLE_MASK ((PTRS_PER_PMD-1) * sizeof(pmd_t)) @@ -406,6 +385,190 @@ } } + +/* + * Do a quick page-table lookup for a single page. + */ +static unsigned long follow_page(unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset(current->mm, address); + pmd = pmd_offset(pgd, address); + if (pmd) { + pte_t * pte = pte_offset(pmd, address); + if (pte && pte_present(*pte)) { + return pte_page(*pte); + } + } + + printk(KERN_ERR "Missing page in follow_page\n"); + return 0; +} + +/* + * Given a physical address, is there a useful struct page pointing to it? + */ + +static struct page * get_page_map(unsigned long page) +{ + struct page *map; + + if (MAP_NR(page) >= max_mapnr) + return 0; + if (page == ZERO_PAGE(page)) + return 0; + map = mem_map + MAP_NR(page); + if (PageReserved(map)) + return 0; + return map; +} + +/* + * Force in an entire range of pages from the current process's user VA, + * and pin and lock the pages for IO. + */ + +#define dprintk(x...) +int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) +{ + unsigned long ptr, end; + int err; + struct mm_struct * mm; + struct vm_area_struct * vma = 0; + unsigned long page; + struct page * map; + int doublepage = 0; + int repeat = 0; + int i; + + /* Make sure the iobuf is not already mapped somewhere. */ + if (iobuf->nr_pages) + return -EINVAL; + + mm = current->mm; + dprintk ("map_user_kiobuf: begin\n"); + + ptr = va & PAGE_MASK; + end = (va + len + PAGE_SIZE - 1) & PAGE_MASK; + err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT); + if (err) + return err; + + repeat: + down(&mm->mmap_sem); + + err = -EFAULT; + iobuf->locked = 1; + iobuf->offset = va & ~PAGE_MASK; + iobuf->length = len; + + i = 0; + + /* + * First of all, try to fault in all of the necessary pages + */ + while (ptr < end) { + if (!vma || ptr >= vma->vm_end) { + vma = find_vma(current->mm, ptr); + if (!vma) + goto out_unlock; + } + if (handle_mm_fault(current, vma, ptr, (rw==READ)) <= 0) + goto out_unlock; + spin_lock(&mm->page_table_lock); + page = follow_page(ptr); + if (!page) { + dprintk (KERN_ERR "Missing page in map_user_kiobuf\n"); + map = NULL; + goto retry; + } + map = get_page_map(page); + if (map) { + if (TryLockPage(map)) { + goto retry; + } + atomic_inc(&map->count); + } + spin_unlock(&mm->page_table_lock); + dprintk ("Installing page %p %p: %d\n", (void *)page, map, i); + iobuf->pagelist[i] = page; + iobuf->maplist[i] = map; + iobuf->nr_pages = ++i; + + ptr += PAGE_SIZE; + } + + up(&mm->mmap_sem); + dprintk ("map_user_kiobuf: end OK\n"); + return 0; + + out_unlock: + up(&mm->mmap_sem); + unmap_kiobuf(iobuf); + dprintk ("map_user_kiobuf: end %d\n", err); + return err; + + retry: + + /* + * Undo the locking so far, wait on the page we got to, and try again. + */ + spin_unlock(&mm->page_table_lock); + unmap_kiobuf(iobuf); + up(&mm->mmap_sem); + + /* + * Did the release also unlock the page we got stuck on? + */ + if (map) { + if (!PageLocked(map)) { + /* If so, we may well have the page mapped twice + * in the IO address range. Bad news. Of + * course, it _might_ * just be a coincidence, + * but if it happens more than * once, chances + * are we have a double-mapped page. */ + if (++doublepage >= 3) { + return -EINVAL; + } + } + + /* + * Try again... + */ + wait_on_page(map); + } + + if (++repeat < 16) + goto repeat; + return -EAGAIN; +} + + +/* + * Unmap all of the pages referenced by a kiobuf. We release the pages, + * and unlock them if they were locked. + */ + +void unmap_kiobuf (struct kiobuf *iobuf) +{ + int i; + struct page *map; + + for (i = 0; i < iobuf->nr_pages; i++) { + map = iobuf->maplist[i]; + + if (map && iobuf->locked) { + __free_page(map); + UnlockPage(map); + } + } + + iobuf->nr_pages = 0; + iobuf->locked = 0; +} + static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pgprot_t prot) { @@ -670,6 +833,7 @@ return 1; bad_wp_page: + spin_unlock(&tsk->mm->page_table_lock); printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page); return -1; } diff -u --recursive --new-file v2.3.11/linux/mm/mmap.c linux/mm/mmap.c --- v2.3.11/linux/mm/mmap.c Thu Jul 8 15:42:21 1999 +++ linux/mm/mmap.c Tue Jul 27 12:33:27 1999 @@ -813,6 +813,7 @@ { struct vm_area_struct * mpnt; + release_segments(mm); mpnt = mm->mmap; mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL; mm->rss = 0; diff -u --recursive --new-file v2.3.11/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.3.11/linux/net/ipv4/tcp_ipv4.c Thu Jul 8 15:42:21 1999 +++ linux/net/ipv4/tcp_ipv4.c Thu Jul 22 13:18:12 1999 @@ -401,10 +401,9 @@ * The sockhash lock must be held as a reader here. */ static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport, - u32 daddr, u16 dport, int dif) + u32 daddr, u16 hnum, int dif) { TCP_V4_ADDR_COOKIE(acookie, saddr, daddr) - __u16 hnum = ntohs(dport); __u32 ports = TCP_COMBINED_PORTS(sport, hnum); struct sock *sk; int hash; @@ -439,7 +438,7 @@ struct sock *sk; SOCKHASH_LOCK_READ(); - sk = __tcp_v4_lookup(saddr, sport, daddr, dport, dif); + sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif); SOCKHASH_UNLOCK_READ(); return sk; @@ -1729,7 +1728,7 @@ #endif SOCKHASH_LOCK_READ_BH(); sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, - skb->nh.iph->daddr, th->dest, skb->dev->ifindex); + skb->nh.iph->daddr, ntohs(th->dest), skb->dev->ifindex); SOCKHASH_UNLOCK_READ_BH(); #ifdef CONFIG_IP_TRANSPARENT_PROXY if (!sk) diff -u --recursive --new-file v2.3.11/linux/scripts/ver_linux linux/scripts/ver_linux --- v2.3.11/linux/scripts/ver_linux Thu Jul 8 15:42:21 1999 +++ linux/scripts/ver_linux Thu Jul 22 07:18:50 1999 @@ -5,7 +5,7 @@ # differ on your system. # PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH -echo '-- Versions installed: (if some fields are empty or looks' +echo '-- Versions installed: (if some fields are empty or look' echo '-- unusual then possibly you have very old versions)' uname -a insmod -V 2>&1 | awk 'NR==1 {print "Kernel modules ",$NF}'