From 1fc742dd8e03a4957af9c1fee4a4e465781ba7a9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Feb 2002 20:33:43 -0800 Subject: [PATCH] v2.4.14.3 -> v2.4.14.4 - Mikael Pettersson: make proc_misc happy without modules - Arjan van de Ven: clean up acpitable implementation ("micro-acpi") - Anton Altaparmakov: LDM partition code update - Alan Cox: final (yeah, sure) small missing pieces - Andrey Savochkin/Andrew Morton: eepro100 config space save/restore over suspend - Arjan van de Ven: remove power from pcmcia socket on card remove - Greg KH: USB updates - Neil Brown: multipath updates - Martin Dalecki: fix up some "asmlinkage" routine markings --- Documentation/Configure.help | 22 +- Documentation/usb/usb-serial.txt | 242 ++-- Makefile | 3 +- arch/i386/boot/compressed/misc.c | 9 +- arch/i386/defconfig | 2 + arch/i386/kernel/acpitable.c | 515 ++------ arch/i386/kernel/acpitable.h | 260 ++++ arch/i386/kernel/bluesmoke.c | 6 +- arch/i386/kernel/setup.c | 143 ++- arch/i386/math-emu/fpu_proto.h | 2 +- drivers/char/Config.in | 14 +- drivers/isdn/isdnloop/isdnloop.c | 10 +- drivers/md/lvm-snap.c | 13 +- drivers/md/multipath.c | 346 ++---- drivers/net/eepro100.c | 8 + drivers/net/pcmcia/Config.in | 1 + drivers/net/pcmcia/Makefile | 1 + drivers/net/pcmcia/ax8390.h | 193 +++ drivers/net/pcmcia/axnet_cs.c | 1958 ++++++++++++++++++++++++++++++ drivers/parport/ChangeLog | 4 + drivers/parport/parport_pc.c | 12 + drivers/pci/pci.c | 43 +- drivers/pcmcia/Makefile | 6 +- drivers/pcmcia/cardbus.c | 1 - drivers/pcmcia/cb_enabler.c | 403 ------ drivers/pcmcia/cistpl.c | 10 +- drivers/pcmcia/cs.c | 35 +- drivers/pcmcia/ds.c | 26 +- drivers/pcmcia/i82365.c | 5 - drivers/pcmcia/old-yenta.h | 153 --- drivers/pcmcia/rsrc_mgr.c | 1 - drivers/pcmcia/rsrc_mgr.h | 33 - drivers/pcmcia/smc34c90.h | 52 - drivers/pnp/isapnp.c | 88 ++ drivers/sound/ac97_codec.c | 27 + drivers/sound/ymfpci.c | 22 +- drivers/usb/hub.c | 52 +- drivers/usb/hub.h | 4 +- drivers/usb/serial/ftdi_sio.c | 183 +-- drivers/usb/serial/ir-usb.c | 47 +- drivers/usb/serial/mct_u232.c | 5 +- drivers/usb/serial/visor.c | 64 +- drivers/usb/serial/visor.h | 1 + drivers/usb/usb-skeleton.c | 5 +- drivers/video/hgafb.c | 4 +- fs/Config.in | 1 + fs/Makefile | 1 + fs/ext2/super.c | 4 +- fs/partitions/ldm.c | 112 +- fs/partitions/ldm.h | 18 +- fs/proc/proc_misc.c | 20 +- fs/seq_file.c | 3 +- include/linux/ac97_codec.h | 3 +- include/linux/console.h | 1 + include/linux/isapnp.h | 15 + include/linux/kernel.h | 2 +- include/linux/pci.h | 5 + include/linux/raid/md_k.h | 1 + include/linux/raid/multipath.h | 22 +- kernel/sched.c | 2 +- 60 files changed, 3413 insertions(+), 1831 deletions(-) create mode 100644 arch/i386/kernel/acpitable.h create mode 100644 drivers/net/pcmcia/ax8390.h create mode 100644 drivers/net/pcmcia/axnet_cs.c delete mode 100644 drivers/pcmcia/cb_enabler.c delete mode 100644 drivers/pcmcia/old-yenta.h delete mode 100644 drivers/pcmcia/rsrc_mgr.h delete mode 100644 drivers/pcmcia/smc34c90.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index b33b56732f86..b97ed9c1d282 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -3524,25 +3524,30 @@ CONFIG_PCMCIA and ds.o. If you want to compile it as a module, say M here and read . -CardBus support +CardBus card and (Yenta) bridge support CONFIG_CARDBUS CardBus is a bus mastering architecture for PC-cards, which allows for 32 bit PC-cards (the original PCMCIA standard specifies only a 16 bit wide bus). Many newer PC-cards are actually CardBus cards. + This option enables support for CardBus PC Cards, as well as support + for CardBus host bridges. Virtually all modern PCMCIA bridges are + CardBus compatible. A "bridge" is the hardware inside your computer + that PCMCIA cards are plugged into. + To use your PC-cards, you will need supporting software from David Hinds' pcmcia-cs package (see the file for location). If unsure, say Y. -i82365 compatible bridge support +i82365 compatible host bridge support CONFIG_I82365 - Say Y here to include support for PCMCIA bridges that are register - compatible with the Intel i82365 specification: this includes - virtually all common PCMCIA bridges that are not 'Yenta' Cardbus - bridges. "Bridge" is the name used for the hardware inside your - computer that PCMCIA cards are plugged into. If unsure, say Y. + Say Y here to include support for ISA-bus PCMCIA host bridges that + are register compatible with the Intel i82365. These are found on + older laptops and ISA-bus card readers for desktop systems. A + "bridge" is the hardware inside your computer that PCMCIA cards are + plugged into. If unsure, say N. Databook TCIC host bridge support CONFIG_TCIC @@ -12729,8 +12734,9 @@ USB FTDI Single Port Serial Driver CONFIG_USB_SERIAL_FTDI_SIO Say Y here if you want to use a FTDI SIO single port USB to serial converter device. The implementation I have is called the USC-1000. + This driver has also be tested with the 245 and 232 devices. - See for more + See http://ftdi-usb-sio.sourceforge.net for more information on this driver and the device. This code is also available as a module ( = code which can be diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 06a734a31eb6..a3b816d1a07b 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -44,28 +44,33 @@ ConnectTech WhiteHEAT 4 port converter device, including providing a unit to test with. This driver will end up being fully supported. -Current status: - The device's firmware is downloaded on connection, the new firmware - runs properly and all four ports are successfully recognized and connected. - Data can be sent and received through the device on all ports. - Hardware flow control needs to be implemented. + Current status: + The device's firmware is downloaded on connection, the new firmware + runs properly and all four ports are successfully recognized and connected. + Data can be sent and received through the device on all ports. + Hardware flow control needs to be implemented. + For any questions or problems with this driver, please contact Greg + Kroah-Hartman at greg@kroah.com -HandSpring Visor USB docking station -Current status: - Only when the Visor tries to connect to the host, does the docking - station show up as a valid USB device. When this happens, the device is +HandSpring Visor, Palm USB, and Clié USB driver + + This driver works with all HandSpring USB, Palm USB, and Sony Clié USB + devices. + + Only when the device tries to connect to the host, will the device show + up to the host as a valid USB device. When this happens, the device is properly enumerated, assigned a port, and then communication _should_ be possible. The driver cleans up properly when the device is removed, or - the connection is canceled on the Visor. + the connection is canceled on the device. NOTE: - This means that in order to talk to the Visor, the sync button must be - pressed BEFORE trying to get any program to communicate to the Visor. + This means that in order to talk to the device, the sync button must be + pressed BEFORE trying to get any program to communicate to the device. This goes against the current documentation for pilot-xfer and other packages, but is the only way that it will work due to the hardware - in the Visor. + in the device. When the device is connected, try talking to it on the second port (this is usually /dev/ttyUSB1 if you do not have any other usb-serial @@ -73,37 +78,49 @@ Current status: the port to use for the HotSync transfer. The "Generic" port can be used for other device communication, such as a PPP link. + For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the + device. This is true for all OS version 3.5 devices, and most devices + that have had a flash upgrade to a newer version of the OS. See the + kernel system log for information on which is the correct port to use. + If after pressing the sync button, nothing shows up in the system log, - try resetting the Visor, first a hot reset, and then a cold reset if - necessary. Some Visors need this before they can talk to the USB port + try resetting the device, first a hot reset, and then a cold reset if + necessary. Some devices need this before they can talk to the USB port properly. - There is a webpage and mailing lists for this portion of the driver at: + There is a webpage and mailing lists for this portion of the driver at: http://usbvisor.sourceforge.net/ + For any questions or problems with this driver, please contact Greg + Kroah-Hartman at greg@kroah.com + Keyspan PDA Serial Adapter Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly sold in Macintosh catalogs, comes in a translucent white/green dongle). Fairly simple device. Firmware is homebrew. - -Current status: - Things that work: - basic input/output (tested with 'cu') - blocking write when serial line can't keep up - changing baud rates (up to 115200) - getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) - sending break (although duration looks suspect) - Things that don't: - device strings (as logged by kernel) have trailing binary garbage - device ID isn't right, might collide with other Keyspan products - changing baud rates ought to flush tx/rx to avoid mangled half characters - Big Things on the todo list: - parity, 7 vs 8 bits per char, 1 or 2 stop bits - HW flow control - not all of the standard USB descriptors are handled: Get_Status, Set_Feature - O_NONBLOCK, select() + This driver also works for the Xircom/Entrgra single port serial adapter. + + Current status: + Things that work: + basic input/output (tested with 'cu') + blocking write when serial line can't keep up + changing baud rates (up to 115200) + getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) + sending break (although duration looks suspect) + Things that don't: + device strings (as logged by kernel) have trailing binary garbage + device ID isn't right, might collide with other Keyspan products + changing baud rates ought to flush tx/rx to avoid mangled half characters + Big Things on the todo list: + parity, 7 vs 8 bits per char, 1 or 2 stop bits + HW flow control + not all of the standard USB descriptors are handled: Get_Status, Set_Feature + O_NONBLOCK, select() + + For any questions or problems with this driver, please contact Brian + Warner at warner@lothar.com Keyspan USA-series Serial Adapters @@ -111,19 +128,22 @@ Keyspan USA-series Serial Adapters Single, Dual and Quad port adapters - driver uses Keyspan supplied firmware and is being developed with their support. -Current status: - The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and - have been pretty throughly tested at various baud rates with 8-N-1 - character settings. Other character lengths and parity setups are - presently untested. - - The USA-28 isn't yet supported though doing so should be pretty - straightforward. Contact the maintainer if you require this - functionality. + Current status: + The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and + have been pretty throughly tested at various baud rates with 8-N-1 + character settings. Other character lengths and parity setups are + presently untested. + + The USA-28 isn't yet supported though doing so should be pretty + straightforward. Contact the maintainer if you require this + functionality. More information is available at: - http://www.linuxcare.com.au/hugh/keyspan.html + http://misc.nu/hugh/keyspan.html + For any questions or problems with this driver, please contact Hugh + Blemings at hugh@misc.nu + FTDI Single Port Serial Driver @@ -131,6 +151,9 @@ FTDI Single Port Serial Driver device and the Linux driver can be found at: http://reality.sgi.com/bryder_wellington/ftdi_sio/ + For any questions or problems with this driver, please contact Bill Ryder + at bryder@sgi.com + ZyXEL omni.net lcd plus ISDN TA @@ -162,65 +185,71 @@ Digi AccelePort Driver Belkin USB Serial Adapter F5U103 Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. - The Peracom single port serial adapter also works with this driver. - -Current status: - The following have been tested and work: - Baud rate 300-230400 - Data bits 5-8 - Stop bits 1-2 - Parity N,E,O,M,S - Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)* - Break Set and clear - Line contrl Input/Output query and control ** - - * Hardware input flow control is only enabled for firmware - levels above 2.06. Read source code comments describing Belkin - firmware errata. Hardware output flow control is working for all - firmware versions. - ** Queries of inputs (CTS,DSR,CD,RI) show the last - reported state. Queries of outputs (DTR,RTS) show the last - requested state and may not reflect current state as set by - automatic hardware flow control. - -TO DO List: - -- Add true modem contol line query capability. Currently tracks the - states reported by the interrupt and the states requested. - -- Add error reporting back to application for UART error conditions. - -- Add support for flush ioctls. - -- Add everything else that is missing :) - - -Empeg empeg-car Mark I/II Driver (empeg.c) + The Peracom single port serial adapter also works with this driver, as + well as the GoHubs adapter. + + Current status: + The following have been tested and work: + Baud rate 300-230400 + Data bits 5-8 + Stop bits 1-2 + Parity N,E,O,M,S + Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)* + Break Set and clear + Line contrl Input/Output query and control ** + + * Hardware input flow control is only enabled for firmware + levels above 2.06. Read source code comments describing Belkin + firmware errata. Hardware output flow control is working for all + firmware versions. + ** Queries of inputs (CTS,DSR,CD,RI) show the last + reported state. Queries of outputs (DTR,RTS) show the last + requested state and may not reflect current state as set by + automatic hardware flow control. + + TO DO List: + -- Add true modem contol line query capability. Currently tracks the + states reported by the interrupt and the states requested. + -- Add error reporting back to application for UART error conditions. + -- Add support for flush ioctls. + -- Add everything else that is missing :) + + For any questions or problems with this driver, please contact William + Greathouse at wgreathouse@smva.com + + +Empeg empeg-car Mark I/II Driver This is an experimental driver to provide connectivity support for the client synchronization tools for an Empeg empeg-car mp3 player. Tips: - * Don't forget to create the device nodes for ttyUSB{0,1,2,...} * modprobe empeg (modprobe is your friend) * emptool --usb /dev/ttyUSB0 (or whatever you named your device node) - The driver is still pretty new, so some testing 'in the wild' would be - helpful. :) + For any questions or problems with this driver, please contact Gary + Brubaker at xavyer@ix.netcom.com MCT USB Single Port Serial Adapter U232 - This driver is for the MCT USB-RS232 Converter (25 pin, Model No. - U232-P25) from Magic Control Technology Corp. (there is also a 9 pin - Model No. U232-P9). More information about this device can be found - at the manufacture's web-site: http://www.mct.com.tw. + This driver is for the MCT USB-RS232 Converter (25 pin, Model No. + U232-P25) from Magic Control Technology Corp. (there is also a 9 pin + Model No. U232-P9). More information about this device can be found at + the manufacture's web-site: http://www.mct.com.tw. - The driver is generally working, though it still needs some more - testing. It is derived from the Belkin USB Serial Adapter F5U103 - driver and its TODO list is valid for this driver as well. + The driver is generally working, though it still needs some more testing. + It is derived from the Belkin USB Serial Adapter F5U103 driver and its + TODO list is valid for this driver as well. - This driver has also been found to work for other products, which have - the same Vendor ID but different Product IDs. Sitecom's U232-P25 - serial converter uses Product ID 0x230 and Vendor ID 0x711 and works with - this driver. Also, D-Link's DU-H3SP USB BAY also works with this driver. + This driver has also been found to work for other products, which have + the same Vendor ID but different Product IDs. Sitecom's U232-P25 serial + converter uses Product ID 0x230 and Vendor ID 0x711 and works with this + driver. Also, D-Link's DU-H3SP USB BAY also works with this driver. + + For any questions or problems with this driver, please contact Wolfgang + Grandegger at wolfgang@ces.ch Inside Out Networks Edgeport Driver @@ -244,17 +273,34 @@ Inside Out Networks Edgeport Driver Edgeport/4 DIN Edgeport/16 Dual + For any questions or problems with this driver, please contact Greg + Kroah-Hartman at greg@kroah.com + REINER SCT cyberJack pinpad/e-com USB chipcard reader Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs. -Current status: - This is the kernel part of the driver for this USB card reader. - There is also a user part for a CT-API driver available. A site - for downloading is TBA. For now, you can request it from the - maintainer (linux-usb@sii.li). + Current status: + This is the kernel part of the driver for this USB card reader. + There is also a user part for a CT-API driver available. A site + for downloading is TBA. For now, you can request it from the + maintainer (linux-usb@sii.li). + + For any questions or problems with this driver, please contact + linux-usb@sii.li + +Prolific PL2303 Driver + + This driver support any device that has the PL2303 chip from Prolific + in it. This includes a number of single port USB to serial + converters and USB GPS devices. Devices from Aten (the UC-232) and + IO-Data work with this driver. + + For any questions or problems with this driver, please contact Greg + Kroah-Hartman at greg@kroah.com + Generic Serial driver @@ -275,13 +321,17 @@ Generic Serial driver development board, providing a way to develop USB firmware without having to write a custom driver. + For any questions or problems with this driver, please contact Greg + Kroah-Hartman at greg@kroah.com + CONTACT: - If anyone has any problems using this driver, with any of the above - specified products, please contact me, or join the Linux-USB mailing - list (information on joining the mailing list, as well as a link to its - searchable archive is at http://www.linux-usb.org/ ) + If anyone has any problems using these drivers, with any of the above + specified products, please contact the specific driver's author listed + above, or join the Linux-USB mailing list (information on joining the + mailing list, as well as a link to its searchable archive is at + http://www.linux-usb.org/ ) Greg Kroah-Hartman diff --git a/Makefile b/Makefile index a29f763020ed..2d8279ce5a7e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 15 -EXTRAVERSION =-pre3 +EXTRAVERSION =-pre4 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -183,6 +183,7 @@ DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o +DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS := $(DRIVERS-y) diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index dbbf1fb54223..e5dd5627dd99 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -9,6 +9,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#include #include #include #include @@ -304,7 +305,7 @@ struct { short b; } stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS }; -void setup_normal_output_buffer(void) +static void setup_normal_output_buffer(void) { #ifdef STANDARD_MEMORY_BIOS_CALL if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n"); @@ -320,7 +321,7 @@ struct moveparams { uch *high_buffer_start; int hcount; }; -void setup_output_buffer_if_we_run_high(struct moveparams *mv) +static void setup_output_buffer_if_we_run_high(struct moveparams *mv) { high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); #ifdef STANDARD_MEMORY_BIOS_CALL @@ -342,7 +343,7 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv) mv->high_buffer_start = high_buffer_start; } -void close_output_buffer_if_we_run_high(struct moveparams *mv) +static void close_output_buffer_if_we_run_high(struct moveparams *mv) { if (bytes_out > low_buffer_size) { mv->lcount = low_buffer_size; @@ -355,7 +356,7 @@ void close_output_buffer_if_we_run_high(struct moveparams *mv) } -int decompress_kernel(struct moveparams *mv, void *rmode) +asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) { real_mode = rmode; diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 0a0026a790ee..c064a7f54300 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -469,6 +469,7 @@ CONFIG_PCMCIA_PCNET=y # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set # CONFIG_PCMCIA_XIRCOM is not set @@ -644,6 +645,7 @@ CONFIG_EXT2_FS=y # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set diff --git a/arch/i386/kernel/acpitable.c b/arch/i386/kernel/acpitable.c index a4c0297833c9..7bd40b56bfff 100644 --- a/arch/i386/kernel/acpitable.c +++ b/arch/i386/kernel/acpitable.c @@ -25,6 +25,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + * $Id: acpitable.c,v 1.7 2001/11/04 12:21:18 fenrus Exp $ */ #include #include @@ -40,244 +41,13 @@ #include #include -#define SELF_CONTAINED_ACPI - -#ifdef SELF_CONTAINED_ACPI -/* - * The following codes are cut&pasted from drivers/acpi. Part of the code - * there can be not updated or delivered yet. - * To avoid conflicts when CONFIG_ACPI is defined, the following codes are - * modified so that they are self-contained in this file. - * -- jun - */ -#define dprintk printk -typedef unsigned int ACPI_TBLPTR; - -#define AE_CODE_ENVIRONMENTAL 0x0000 -#define AE_OK (u32) 0x0000 -#define AE_ERROR (u32) (0x0001 | AE_CODE_ENVIRONMENTAL) -#define AE_NO_ACPI_TABLES (u32) (0x0002 | AE_CODE_ENVIRONMENTAL) -#define AE_NOT_FOUND (u32) (0x0005 | AE_CODE_ENVIRONMENTAL) - -typedef struct { /* ACPI common table header */ - char signature[4]; /* identifies type of table */ - u32 length; /* length of table, - in bytes, * including header */ - u8 revision; /* specification minor version # */ - u8 checksum; /* to make sum of entire table == 0 */ - char oem_id[6]; /* OEM identification */ - char oem_table_id[8]; /* OEM table identification */ - u32 oem_revision; /* OEM revision number */ - char asl_compiler_id[4]; /* ASL compiler vendor ID */ - u32 asl_compiler_revision; /* ASL compiler revision number */ -} acpi_table_header __attribute__ ((packed));; - -enum { - ACPI_APIC = 0, - ACPI_BOOT, - ACPI_DBGP, - ACPI_DSDT, - ACPI_ECDT, - ACPI_ETDT, - ACPI_FACP, - ACPI_FACS, - ACPI_OEMX, - ACPI_PSDT, - ACPI_SBST, - ACPI_SLIT, - ACPI_SPCR, - ACPI_SRAT, - ACPI_SSDT, - ACPI_SPMI, - ACPI_XSDT, - ACPI_TABLE_COUNT -}; - -static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { - "APIC", - "BOOT", - "DBGP", - "DSDT", - "ECDT", - "ETDT", - "FACP", - "FACS", - "OEM", - "PSDT", - "SBST", - "SLIT", - "SPCR", - "SRAT", - "SSDT", - "SPMI", - "XSDT" -}; - -struct acpi_table_madt { - acpi_table_header header; - u32 lapic_address; - struct { - u32 pcat_compat:1; - u32 reserved:31; - } flags __attribute__ ((packed)); -} __attribute__ ((packed));; - -enum { - ACPI_MADT_LAPIC = 0, - ACPI_MADT_IOAPIC, - ACPI_MADT_INT_SRC_OVR, - ACPI_MADT_NMI_SRC, - ACPI_MADT_LAPIC_NMI, - ACPI_MADT_LAPIC_ADDR_OVR, - ACPI_MADT_IOSAPIC, - ACPI_MADT_LSAPIC, - ACPI_MADT_PLAT_INT_SRC, - ACPI_MADT_ENTRY_COUNT -}; - -#define RSDP_SIG "RSD PTR " -#define RSDT_SIG "RSDT" - -#define ACPI_DEBUG_PRINT(pl) - -#define ACPI_MEMORY_MODE 0x01 -#define ACPI_LOGICAL_ADDRESSING 0x00 -#define ACPI_PHYSICAL_ADDRESSING 0x01 - -#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ -#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ -#define LO_RSDP_WINDOW_SIZE 0x400 -#define HI_RSDP_WINDOW_SIZE 0x20000 -#define RSDP_SCAN_STEP 16 -#define RSDP_CHECKSUM_LENGTH 20 - -typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); +#include "acpitable.h" static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT]; -struct acpi_table_rsdp { - char signature[8]; - u8 checksum; - char oem_id[6]; - u8 revision; - u32 rsdt_address; -} __attribute__ ((packed)); - -struct acpi_table_rsdt { - acpi_table_header header; - u32 entry[ACPI_TABLE_COUNT]; -} __attribute__ ((packed)); - -typedef struct { - u8 type; - u8 length; -} acpi_madt_entry_header __attribute__ ((packed)); - -typedef struct { - u16 polarity:2; - u16 trigger:2; - u16 reserved:12; -} acpi_madt_int_flags __attribute__ ((packed)); - -struct acpi_table_lapic { - acpi_madt_entry_header header; - u8 acpi_id; - u8 id; - struct { - u32 enabled:1; - u32 reserved:31; - } flags __attribute__ ((packed)); -} __attribute__ ((packed)); - -struct acpi_table_ioapic { - acpi_madt_entry_header header; - u8 id; - u8 reserved; - u32 address; - u32 global_irq_base; -} __attribute__ ((packed)); - -struct acpi_table_int_src_ovr { - acpi_madt_entry_header header; - u8 bus; - u8 bus_irq; - u32 global_irq; - acpi_madt_int_flags flags; -} __attribute__ ((packed)); - -struct acpi_table_nmi_src { - acpi_madt_entry_header header; - acpi_madt_int_flags flags; - u32 global_irq; -} __attribute__ ((packed)); - -struct acpi_table_lapic_nmi { - acpi_madt_entry_header header; - u8 acpi_id; - acpi_madt_int_flags flags; - u8 lint; -} __attribute__ ((packed)); - -struct acpi_table_lapic_addr_ovr { - acpi_madt_entry_header header; - u8 reserved[2]; - u64 address; -} __attribute__ ((packed)); - -struct acpi_table_iosapic { - acpi_madt_entry_header header; - u8 id; - u8 reserved; - u32 global_irq_base; - u64 address; -} __attribute__ ((packed)); - -struct acpi_table_lsapic { - acpi_madt_entry_header header; - u8 acpi_id; - u8 id; - u8 eid; - u8 reserved[3]; - struct { - u32 enabled:1; - u32 reserved:31; - } flags; -} __attribute__ ((packed)); - -struct acpi_table_plat_int_src { - acpi_madt_entry_header header; - acpi_madt_int_flags flags; - u8 type; - u8 id; - u8 eid; - u8 iosapic_vector; - u32 global_irq; - u32 reserved; -} __attribute__ ((packed)); - -/* - * ACPI Table Descriptor. One per ACPI table - */ -typedef struct acpi_table_desc { - struct acpi_table_desc *prev; - struct acpi_table_desc *next; - struct acpi_table_desc *installed_desc; - acpi_table_header *pointer; - void *base_pointer; - u8 *aml_pointer; - u64 physical_address; - u32 aml_length; - u32 length; - u32 count; - u16 table_id; - u8 type; - u8 allocation; - u8 loaded_into_namespace; - -} acpi_table_desc __attribute__ ((packed));; static unsigned char __init -acpi_tb_checksum(void *buffer, int length) +acpi_checksum(void *buffer, int length) { int i; unsigned char *bytebuffer; @@ -294,24 +64,6 @@ acpi_tb_checksum(void *buffer, int length) return sum; } -static int __init -acpi_table_checksum(acpi_table_header * header) -{ - u8 *p = (u8 *) header; - int length = 0; - int sum = 0; - - if (!header) - return -EINVAL; - - length = header->length; - - while (length--) - sum += *p++; - - return sum & 0xFF; -} - static void __init acpi_print_table_header(acpi_table_header * header) { @@ -328,19 +80,19 @@ acpi_print_table_header(acpi_table_header * header) /******************************************************************************* * - * FUNCTION: Acpi_tb_scan_memory_for_rsdp + * FUNCTION: acpi_tb_scan_memory_for_rsdp * - * PARAMETERS: Start_address - Starting pointer for search - * Length - Maximum length to search + * PARAMETERS: address - Starting pointer for search + * length - Maximum length to search * - * RETURN: Pointer to the RSDP if found, otherwise NULL. + * RETURN: Pointer to the RSDP if found and valid, otherwise NULL. * * DESCRIPTION: Search a block of memory for the RSDP signature * ******************************************************************************/ -static unsigned char *__init -acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) +static void *__init +acpi_tb_scan_memory_for_rsdp(void *address, int length) { u32 offset; @@ -354,10 +106,9 @@ acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) while (offset < length) { /* The signature must match and the checksum must be correct */ if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 && - acpi_tb_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { + acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { /* If so, we have found the RSDP */ - printk(KERN_INFO - "ACPI: RSDP located at physical address %p\n", + printk(KERN_INFO "ACPI: RSDP located at physical address %p\n", address); return address; } @@ -372,13 +123,11 @@ acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) /******************************************************************************* * - * FUNCTION: acpi_tb_find_rsdp + * FUNCTION: acpi_find_root_pointer * - * PARAMETERS: *Table_info - Where the table info is returned - * Flags - Current memory mode (logical vs. - * physical addressing) + * PARAMETERS: none * - * RETURN: Status + * RETURN: physical address of the RSDP * * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor * pointer structure. If it is found, set *RSDP to point to it. @@ -389,80 +138,38 @@ acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) * ******************************************************************************/ -static int __init -acpi_tb_find_rsdp(acpi_table_desc * table_info, u32 flags) +static struct acpi_table_rsdp * __init +acpi_find_root_pointer(void) { - unsigned char *address; + struct acpi_table_rsdp * rsdp; /* - * Physical address is given. + * Physical address is given */ /* * Region 1) Search EBDA (low memory) paragraphs */ - address = - acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), + rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), LO_RSDP_WINDOW_SIZE); - if (address) { - /* Found it, return the physical address */ - table_info->physical_address = (ACPI_TBLPTR) __pa(address); - return AE_OK; - } + if (rsdp) + return rsdp; /* * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ - address = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), + rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), HI_RSDP_WINDOW_SIZE); - if (address) { - /* Found it, return the physical address */ - table_info->physical_address = (ACPI_TBLPTR) __pa(address); - return AE_OK; - } - - /* RSDP signature was not found */ - return AE_NOT_FOUND; -} -static unsigned long __init -acpi_find_root_pointer(u32 flags) -{ - acpi_table_desc table_info; - int status; - - /* Get the RSDP */ - - status = acpi_tb_find_rsdp(&table_info, flags); - if (status) - return 0; + + + if (rsdp) + return rsdp; - return table_info.physical_address; + printk(KERN_ERR "ACPI: System description tables not found\n"); + return NULL; } -static unsigned long __init -acpi_os_get_root_pointer(u32 flags) -{ - unsigned long address; - -#ifndef CONFIG_ACPI_EFI - - address = acpi_find_root_pointer(flags); - -#else - if (efi.acpi20) - address = (unsigned long) efi.acpi20; - else if (efi.acpi) - address = (unsigned long) efi.acpi; - else - address = 0; -#endif /*CONFIG_ACPI_EFI */ - - if (address == 0) - printk(KERN_ERR "ACPI: System description tables not found\n"); - - return address; -} /* * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0, @@ -506,29 +213,23 @@ __va_range(unsigned long phys, unsigned long size) static int __init acpi_tables_init(void) { int result = -ENODEV; - int status = AE_OK; - unsigned long rsdp_addr = 0; acpi_table_header *header = NULL; struct acpi_table_rsdp *rsdp = NULL; -#ifndef CONFIG_IA64 struct acpi_table_rsdt *rsdt = NULL; struct acpi_table_rsdt saved_rsdt; -#else - struct acpi071_table_rsdt *rsdt = NULL; -#endif int tables = 0; int type = 0; int i = 0; - rsdp_addr = acpi_os_get_root_pointer(ACPI_PHYSICAL_ADDRESSING); - if (!rsdp_addr) - return -ENODEV; - - rsdp = (struct acpi_table_rsdp *) rsdp_addr; + rsdp = (struct acpi_table_rsdp *) acpi_find_root_pointer(); + if (!rsdp) + return -ENODEV; + printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, rsdp->oem_id); + if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { printk(KERN_WARNING "RSDP table signature incorrect\n"); return -EINVAL; @@ -537,54 +238,53 @@ static int __init acpi_tables_init(void) rsdt = (struct acpi_table_rsdt *) __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); - if (rsdt) { - header = (acpi_table_header *) & rsdt->header; - acpi_print_table_header(header); - if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { - printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); - rsdt = NULL; - } else { - /* - * The number of tables is computed by taking the - * size of all entries (header size minus total - * size of RSDT) divided by the size of each entry - * (4-byte table pointers). - */ - tables = - (header->length - sizeof(acpi_table_header)) / 4; - } - } - if (!rsdt) { - printk(KERN_WARNING - "ACPI: Invalid root system description tables (RSDT)\n"); + printk(KERN_WARNING "ACPI: Invalid root system description tables (RSDT)\n"); return -ENODEV; } - + + header = & rsdt->header; + acpi_print_table_header(header); + + if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); + return -ENODEV; + } + + /* + * The number of tables is computed by taking the + * size of all entries (header size minus total + * size of RSDT) divided by the size of each entry + * (4-byte table pointers). + */ + tables = (header->length - sizeof(acpi_table_header)) / 4; + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); if (saved_rsdt.header.length > sizeof(saved_rsdt)) { - printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", - saved_rsdt.header.length); + printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length); return -ENODEV; } for (i = 0; i < tables; i++) { - if (rsdt) { - header = (acpi_table_header *) + header = (acpi_table_header *) __va_range(saved_rsdt.entry[i], sizeof(acpi_table_header)); - } if (!header) break; acpi_print_table_header(header); - + + if (acpi_checksum(header,header->length)) { + printk(KERN_WARNING "ACPI %s has invalid checksum\n", + acpi_table_signatures[i]); + continue; + } + for (type = 0; type < ACPI_TABLE_COUNT; type++) - if (!strncmp - ((char *) &header->signature, + if (!strncmp((char *) &header->signature, acpi_table_signatures[type],strlen(acpi_table_signatures[type]))) break; @@ -594,22 +294,17 @@ static int __init acpi_tables_init(void) continue; } - if (acpi_table_checksum(header)) { - printk(KERN_WARNING "ACPI %s has invalid checksum\n", - acpi_table_signatures[i]); - continue; - } - if (acpi_boot_ops && acpi_boot_ops[type]) - result = - acpi_boot_ops[type] (header, + if (!acpi_boot_ops[type]) + continue; + + result = acpi_boot_ops[type] (header, (unsigned long) saved_rsdt. entry[i]); } return result; } -#endif /* SELF_CONTAINED_ACPI */ static int total_cpus __initdata = 0; int have_acpi_tables; @@ -625,10 +320,10 @@ acpi_parse_lapic(struct acpi_table_lapic *local_apic) if (!local_apic) return; - dprintk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", + printk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", local_apic->acpi_id, local_apic->id, local_apic->flags.enabled); - dprintk("CPU %d (0x%02x00)", total_cpus, local_apic->id); + printk(KERN_INFO "CPU %d (0x%02x00)", total_cpus, local_apic->id); if (local_apic->flags.enabled) { printk(" enabled"); @@ -652,9 +347,9 @@ acpi_parse_lapic(struct acpi_table_lapic *local_apic) proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR; } proc_entry.mpc_cpufeature = - (boot_cpu_data.x86 << 8) | (boot_cpu_data. - x86_model << 4) | boot_cpu_data. - x86_mask; + (boot_cpu_data.x86 << 8) | + (boot_cpu_data.x86_model << 4) | + boot_cpu_data.x86_mask; proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0]; proc_entry.mpc_reserved[0] = 0; proc_entry.mpc_reserved[1] = 0; @@ -684,18 +379,17 @@ acpi_parse_ioapic(struct acpi_table_ioapic *ioapic) printk(KERN_WARNING "Max # of I/O APICs (%d) exceeded (found %d).\n", MAX_IO_APICS, nr_ioapics); - panic("Recompile kernel with bigger MAX_IO_APICS!\n"); +/* panic("Recompile kernel with bigger MAX_IO_APICS!\n"); */ } } + +/* Interrupt source overrides inform the machine about exceptions + to the normal "PIC" mode interrupt routing */ + static void __init acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc) { - /* - static int first_time_switch = 0; - struct mpc_config_intsrc my_intsrc; - int i; - */ if (!intsrc) return; @@ -743,33 +437,6 @@ acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr) } -#ifdef CONFIG_IA64 -static void __init -acpi_parse_iosapic(struct acpi_table_iosapic *iosapic) -{ - if (!iosapic) - return; - - printk(KERN_INFO "IOSAPIC (id[%x] global_irq_base[%x] address[%lx])\n", - iosapic->id, iosapic->global_irq_base, - (unsigned long) iosapic->address); - - return 0; -} -static void __init -acpi_parse_lsapic(struct acpi_table_lsapic *lsapic) -{ - if (!lsapic) - return; - - printk(KERN_INFO - "LSAPIC (acpi_id[0x%04x] id[0x%x] eid[0x%x] enabled[%d])\n", - lsapic->acpi_id, lsapic->id, lsapic->eid, lsapic->flags.enabled); - - if (!lsapic->flags.enabled) - return; -} -#endif static void __init acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc) { @@ -786,10 +453,11 @@ static int __init acpi_parse_madt(acpi_table_header * header, unsigned long phys) { - struct acpi_table_madt *madt = - (struct acpi_table_madt *) __va_range(phys, header->length); - acpi_madt_entry_header *entry_header = NULL; - int table_size = 0; + struct acpi_table_madt *madt; + acpi_madt_entry_header *entry_header; + int table_size; + + madt = (struct acpi_table_madt *) __va_range(phys, header->length); if (!madt) return -EINVAL; @@ -825,16 +493,6 @@ acpi_parse_madt(acpi_table_header * header, unsigned long phys) acpi_table_lapic_addr_ovr *) entry_header); break; -#ifdef CONFIG_IA64 - case ACPI_MADT_IOSAPIC: - acpi_parse_iosapic((struct acpi_table_iosapic *) - entry_header); - break; - case ACPI_MADT_LSAPIC: - acpi_parse_lsapic((struct acpi_table_lsapic *) - entry_header); - break; -#endif case ACPI_MADT_PLAT_INT_SRC: acpi_parse_plat_int_src((struct acpi_table_plat_int_src *) entry_header); @@ -877,20 +535,15 @@ extern int enable_acpi_smp_table; void __init config_acpi_tables(void) { - int result = 0; + + memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); + acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; /* * Only do this when requested, either because of CPU/Bios type or from the command line */ - if (!enable_acpi_smp_table) { - return; - } - - memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); - acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; - result = acpi_tables_init(); - if (!result) { + if (enable_acpi_smp_table && !acpi_tables_init()) { have_acpi_tables = 1; printk("Enabling the CPU's according to the ACPI table\n"); } diff --git a/arch/i386/kernel/acpitable.h b/arch/i386/kernel/acpitable.h new file mode 100644 index 000000000000..ddf1c84a6549 --- /dev/null +++ b/arch/i386/kernel/acpitable.h @@ -0,0 +1,260 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * $Id: acpitable.h,v 1.3 2001/11/03 22:41:34 fenrus Exp $ + */ + +/* + * The following codes are cut&pasted from drivers/acpi. Part of the code + * there can be not updated or delivered yet. + * To avoid conflicts when CONFIG_ACPI is defined, the following codes are + * modified so that they are self-contained in this file. + * -- jun + */ + +#ifndef _HEADER_ACPITABLE_H_ +#define _HEADER_ACPITABLE_H_ + +#define dprintk printk +typedef unsigned int ACPI_TBLPTR; + +typedef struct { /* ACPI common table header */ + char signature[4]; /* identifies type of table */ + u32 length; /* length of table, + in bytes, * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_table_header __attribute__ ((packed));; + +enum { + ACPI_APIC = 0, + ACPI_BOOT, + ACPI_DBGP, + ACPI_DSDT, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, + ACPI_FACS, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_XSDT, + ACPI_TABLE_COUNT +}; + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + "APIC", + "BOOT", + "DBGP", + "DSDT", + "ECDT", + "ETDT", + "FACP", + "FACS", + "OEM", + "PSDT", + "SBST", + "SLIT", + "SPCR", + "SRAT", + "SSDT", + "SPMI", + "XSDT" +}; + +struct acpi_table_madt { + acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed));; + +enum { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +#define RSDP_SIG "RSD PTR " +#define RSDT_SIG "RSDT" + +#define ACPI_DEBUG_PRINT(pl) + +#define ACPI_MEMORY_MODE 0x01 +#define ACPI_LOGICAL_ADDRESSING 0x00 +#define ACPI_PHYSICAL_ADDRESSING 0x01 + +#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ +#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 +#define RSDP_CHECKSUM_LENGTH 20 + +typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi_table_rsdt { + acpi_table_header header; + u32 entry[ACPI_TABLE_COUNT]; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_madt_entry_header __attribute__ ((packed)); + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_madt_int_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_madt_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_madt_int_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_madt_entry_header header; + u8 acpi_id; + acpi_madt_int_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_madt_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u8 type; + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc { + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + acpi_table_header *pointer; + void *base_pointer; + u8 *aml_pointer; + u64 physical_address; + u32 aml_length; + u32 length; + u32 count; + u16 table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} acpi_table_desc __attribute__ ((packed));; + +#endif diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index 07531b806e31..0aa4b209cf74 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -100,11 +100,11 @@ static void unexpected_machine_check(struct pt_regs * regs, long error_code) /* * Call the installed machine check handler for this CPU setup. - */ - + */ + static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; -void do_machine_check(struct pt_regs * regs, long error_code) +asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) { machine_check_vector(regs, error_code); } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 92502849a51f..1ba2d8b2d236 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -98,6 +98,7 @@ #endif #include #include +#include #include #include #include @@ -2686,11 +2687,8 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) /* * Get CPU information for use by the procfs. */ - -int get_cpuinfo(char * buffer) +static int show_cpuinfo(struct seq_file *m, void *v) { - char *p = buffer; - /* * These flag bits must match the definitions in . * NULL means this bit is undefined or reserved; either way it doesn't @@ -2724,75 +2722,88 @@ int get_cpuinfo(char * buffer) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; - struct cpuinfo_x86 *c = cpu_data; - int i, n; + struct cpuinfo_x86 *c = v; + int i, n = c - cpu_data; + int fpu_exception; - for (n = 0; n < NR_CPUS; n++, c++) { - int fpu_exception; #ifdef CONFIG_SMP - if (!(cpu_online_map & (1< (3*PAGE_SIZE)/4) - break; + seq_printf(m, "processor\t: %d\n" + "vendor_id\t: %s\n" + "cpu family\t: %d\n" + "model\t\t: %d\n" + "model name\t: %s\n", + n, + c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", + c->x86, + c->x86_model, + c->x86_model_id[0] ? c->x86_model_id : "unknown"); + + if (c->x86_mask || c->cpuid_level >= 0) + seq_printf(m, "stepping\t: %d\n", c->x86_mask); + else + seq_printf(m, "stepping\t: unknown\n"); - p += sprintf(p,"processor\t: %d\n" - "vendor_id\t: %s\n" - "cpu family\t: %d\n" - "model\t\t: %d\n" - "model name\t: %s\n", - n, - c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", - c->x86, - c->x86_model, - c->x86_model_id[0] ? c->x86_model_id : "unknown"); - - if (c->x86_mask || c->cpuid_level >= 0) - p += sprintf(p, "stepping\t: %d\n", c->x86_mask); - else - p += sprintf(p, "stepping\t: unknown\n"); + if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) { + seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n", + cpu_khz / 1000, (cpu_khz % 1000)); + } - if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) { - p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n", - cpu_khz / 1000, (cpu_khz % 1000)); - } + /* Cache size */ + if (c->x86_cache_size >= 0) + seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); + + /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ + fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); + seq_printf(m, "fdiv_bug\t: %s\n" + "hlt_bug\t\t: %s\n" + "f00f_bug\t: %s\n" + "coma_bug\t: %s\n" + "fpu\t\t: %s\n" + "fpu_exception\t: %s\n" + "cpuid level\t: %d\n" + "wp\t\t: %s\n" + "flags\t\t:", + c->fdiv_bug ? "yes" : "no", + c->hlt_works_ok ? "no" : "yes", + c->f00f_bug ? "yes" : "no", + c->coma_bug ? "yes" : "no", + c->hard_math ? "yes" : "no", + fpu_exception ? "yes" : "no", + c->cpuid_level, + c->wp_works_ok ? "yes" : "no"); + + for ( i = 0 ; i < 32*NCAPINTS ; i++ ) + if ( test_bit(i, &c->x86_capability) && + x86_cap_flags[i] != NULL ) + seq_printf(m, " %s", x86_cap_flags[i]); + + seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n", + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); + return 0; +} - /* Cache size */ - if (c->x86_cache_size >= 0) - p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size); - - /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ - fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); - p += sprintf(p, "fdiv_bug\t: %s\n" - "hlt_bug\t\t: %s\n" - "f00f_bug\t: %s\n" - "coma_bug\t: %s\n" - "fpu\t\t: %s\n" - "fpu_exception\t: %s\n" - "cpuid level\t: %d\n" - "wp\t\t: %s\n" - "flags\t\t:", - c->fdiv_bug ? "yes" : "no", - c->hlt_works_ok ? "no" : "yes", - c->f00f_bug ? "yes" : "no", - c->coma_bug ? "yes" : "no", - c->hard_math ? "yes" : "no", - fpu_exception ? "yes" : "no", - c->cpuid_level, - c->wp_works_ok ? "yes" : "no"); - - for ( i = 0 ; i < 32*NCAPINTS ; i++ ) - if ( test_bit(i, &c->x86_capability) && - x86_cap_flags[i] != NULL ) - p += sprintf(p, " %s", x86_cap_flags[i]); - - p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", - c->loops_per_jiffy/(500000/HZ), - (c->loops_per_jiffy/(5000/HZ)) % 100); - } - return p - buffer; +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? &cpu_data[*pos] : NULL; } +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} +static void c_stop(struct seq_file *m, void *v) +{ +} +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; unsigned long cpu_initialized __initdata = 0; diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h index 4fccf05fee88..b5f25b45ac21 100644 --- a/arch/i386/math-emu/fpu_proto.h +++ b/arch/i386/math-emu/fpu_proto.h @@ -53,7 +53,7 @@ extern void ffreep(void); extern void fst_i_(void); extern void fstp_i(void); /* fpu_entry.c */ -extern void math_emulate(long arg); +asmlinkage extern void math_emulate(long arg); extern void math_abort(struct info *info, unsigned int signal); /* fpu_etc.c */ extern void FPU_etc(void); diff --git a/drivers/char/Config.in b/drivers/char/Config.in index fb6fc03d901a..bbed2582b0bf 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -16,6 +16,9 @@ if [ "$CONFIG_SERIAL" = "y" ]; then tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi +if [ "$CONFIG_ACPI" = "y" ]; then + bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI +fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS @@ -155,17 +158,18 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT - tristate ' IB700 SBC Watchdog Timer' CONFIG_IB700_WDT - tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT - tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT - tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD - tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG fi fi + tristate ' Eurotech CPU-1220/1410 Watchdog Timer' CONFIG_EUROTECH_WDT + tristate ' IB700 SBC Watchdog Timer' CONFIG_IB700_WDT + tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO + tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT fi endmenu diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 18f9d10e8073..c551abfed701 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.11.6.6 2001/09/23 22:24:56 kai Exp $ +/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $ * * ISDN low-level module implementing a dummy loop driver. * @@ -14,7 +14,7 @@ #include #include "isdnloop.h" -static char *revision = "$Revision: 1.11.6.6 $"; +static char *revision = "$Revision: 1.11.6.7 $"; static char *isdnloop_id; MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); @@ -1542,7 +1542,11 @@ isdnloop_init(void) } else strcpy(rev, " ??? "); printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev); - return (isdnloop_addcard(isdnloop_id)); + + if (isdnloop_id) + return (isdnloop_addcard(isdnloop_id)); + + return 0; } static void __exit diff --git a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c index e3d2a8b99d27..e888707802fd 100644 --- a/drivers/md/lvm-snap.c +++ b/drivers/md/lvm-snap.c @@ -500,10 +500,9 @@ out: int lvm_snapshot_alloc(lv_t * lv_snap) { int ret, max_sectors; - int nbhs = KIO_MAX_SECTORS; /* allocate kiovec to do chunk io */ - ret = alloc_kiovec_sz(1, &lv_snap->lv_iobuf, &nbhs); + ret = alloc_kiovec(1, &lv_snap->lv_iobuf); if (ret) goto out; max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9); @@ -512,7 +511,7 @@ int lvm_snapshot_alloc(lv_t * lv_snap) if (ret) goto out_free_kiovec; /* allocate kiovec to do exception table io */ - ret = alloc_kiovec_sz(1, &lv_snap->lv_COW_table_iobuf, &nbhs); + ret = alloc_kiovec(1, &lv_snap->lv_COW_table_iobuf); if (ret) goto out_free_kiovec; ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf, @@ -528,12 +527,12 @@ out: out_free_both_kiovecs: unmap_kiobuf(lv_snap->lv_COW_table_iobuf); - free_kiovec_sz(1, &lv_snap->lv_COW_table_iobuf, &nbhs); + free_kiovec(1, &lv_snap->lv_COW_table_iobuf); lv_snap->lv_COW_table_iobuf = NULL; out_free_kiovec: unmap_kiobuf(lv_snap->lv_iobuf); - free_kiovec_sz(1, &lv_snap->lv_iobuf, &nbhs); + free_kiovec(1, &lv_snap->lv_iobuf); lv_snap->lv_iobuf = NULL; if (lv_snap->lv_snapshot_hash_table != NULL) vfree(lv_snap->lv_snapshot_hash_table); @@ -560,14 +559,14 @@ void lvm_snapshot_release(lv_t * lv) { kiobuf_wait_for_io(lv->lv_iobuf); unmap_kiobuf(lv->lv_iobuf); - free_kiovec_sz(1, &lv->lv_iobuf, &nbhs); + free_kiovec(1, &lv->lv_iobuf); lv->lv_iobuf = NULL; } if (lv->lv_COW_table_iobuf) { kiobuf_wait_for_io(lv->lv_COW_table_iobuf); unmap_kiobuf(lv->lv_COW_table_iobuf); - free_kiovec_sz(1, &lv->lv_COW_table_iobuf, &nbhs); + free_kiovec(1, &lv->lv_COW_table_iobuf); lv->lv_COW_table_iobuf = NULL; } } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 58baccf787a7..5cbbd2c162f3 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -7,10 +7,7 @@ * * MULTIPATH management functions. * - * Better read-balancing code written by Mika Kuoppala , 2000 - * - * Fixes to reconstruction by Jakob Østergaard" - * Various fixes by Neil Brown + * derived from raid1.c. * * 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 @@ -33,6 +30,9 @@ #define MAX_WORK_PER_DISK 128 +#define NR_RESERVED_BUFS 32 + + /* * The following can be used to debug the driver */ @@ -53,147 +53,55 @@ struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state); -struct buffer_head *multipath_alloc_bh(multipath_conf_t *conf, int cnt) -{ - /* return a linked list of "cnt" struct buffer_heads. - * don't take any off the free list unless we know we can - * get all we need, otherwise we could deadlock - */ - struct buffer_head *bh=NULL; - - while(cnt) { - struct buffer_head *t; - md_spin_lock_irq(&conf->device_lock); - if (conf->freebh_cnt >= cnt) - while (cnt) { - t = conf->freebh; - conf->freebh = t->b_next; - t->b_next = bh; - bh = t; - t->b_state = 0; - conf->freebh_cnt--; - cnt--; - } - md_spin_unlock_irq(&conf->device_lock); - if (cnt == 0) - break; - t = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), GFP_NOIO); - if (t) { - memset(t, 0, sizeof(*t)); - t->b_next = bh; - bh = t; - cnt--; - } else { - PRINTK("waiting for %d bh\n", cnt); - wait_event(conf->wait_buffer, conf->freebh_cnt >= cnt); - } - } - return bh; -} -static inline void multipath_free_bh(multipath_conf_t *conf, struct buffer_head *bh) -{ - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - while (bh) { - struct buffer_head *t = bh; - bh=bh->b_next; - if (t->b_pprev == NULL) - kfree(t); - else { - t->b_next= conf->freebh; - conf->freebh = t; - conf->freebh_cnt++; - } - } - spin_unlock_irqrestore(&conf->device_lock, flags); - wake_up(&conf->wait_buffer); -} - -static int multipath_grow_bh(multipath_conf_t *conf, int cnt) -{ - /* allocate cnt buffer_heads, possibly less if kalloc fails */ - int i = 0; - - while (i < cnt) { - struct buffer_head *bh; - bh = kmalloc(sizeof(*bh), GFP_KERNEL); - if (!bh) break; - memset(bh, 0, sizeof(*bh)); - - md_spin_lock_irq(&conf->device_lock); - bh->b_pprev = &conf->freebh; - bh->b_next = conf->freebh; - conf->freebh = bh; - conf->freebh_cnt++; - md_spin_unlock_irq(&conf->device_lock); - - i++; - } - return i; -} - -static int multipath_shrink_bh(multipath_conf_t *conf, int cnt) -{ - /* discard cnt buffer_heads, if we can find them */ - int i = 0; - - md_spin_lock_irq(&conf->device_lock); - while ((i < cnt) && conf->freebh) { - struct buffer_head *bh = conf->freebh; - conf->freebh = bh->b_next; - kfree(bh); - i++; - conf->freebh_cnt--; - } - md_spin_unlock_irq(&conf->device_lock); - return i; -} - static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf) { - struct multipath_bh *r1_bh = NULL; + struct multipath_bh *mp_bh = NULL; do { md_spin_lock_irq(&conf->device_lock); - if (conf->freer1) { - r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - r1_bh->next_r1 = NULL; - r1_bh->state = 0; - r1_bh->bh_req.b_state = 0; + if (!conf->freer1_blocked && conf->freer1) { + mp_bh = conf->freer1; + conf->freer1 = mp_bh->next_mp; + conf->freer1_cnt--; + mp_bh->next_mp = NULL; + mp_bh->state = (1 << MPBH_PreAlloc); + mp_bh->bh_req.b_state = 0; } md_spin_unlock_irq(&conf->device_lock); - if (r1_bh) - return r1_bh; - r1_bh = (struct multipath_bh *) kmalloc(sizeof(struct multipath_bh), + if (mp_bh) + return mp_bh; + mp_bh = (struct multipath_bh *) kmalloc(sizeof(struct multipath_bh), GFP_NOIO); - if (r1_bh) { - memset(r1_bh, 0, sizeof(*r1_bh)); - return r1_bh; + if (mp_bh) { + memset(mp_bh, 0, sizeof(*mp_bh)); + return mp_bh; } - wait_event(conf->wait_buffer, conf->freer1); + conf->freer1_blocked = 1; + wait_disk_event(conf->wait_buffer, + !conf->freer1_blocked || + conf->freer1_cnt > NR_RESERVED_BUFS/2 + ); + conf->freer1_blocked = 0; } while (1); } -static inline void multipath_free_mpbh(struct multipath_bh *r1_bh) +static inline void multipath_free_mpbh(struct multipath_bh *mp_bh) { - struct buffer_head *bh = r1_bh->multipath_bh_list; - multipath_conf_t *conf = mddev_to_conf(r1_bh->mddev); - - r1_bh->multipath_bh_list = NULL; + multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - if (test_bit(MPBH_PreAlloc, &r1_bh->state)) { + if (test_bit(MPBH_PreAlloc, &mp_bh->state)) { unsigned long flags; spin_lock_irqsave(&conf->device_lock, flags); - r1_bh->next_r1 = conf->freer1; - conf->freer1 = r1_bh; + mp_bh->next_mp = conf->freer1; + conf->freer1 = mp_bh; + conf->freer1_cnt++; spin_unlock_irqrestore(&conf->device_lock, flags); + wake_up(&conf->wait_buffer); } else { - kfree(r1_bh); + kfree(mp_bh); } - multipath_free_bh(conf, bh); } static int multipath_grow_mpbh (multipath_conf_t *conf, int cnt) @@ -201,18 +109,15 @@ static int multipath_grow_mpbh (multipath_conf_t *conf, int cnt) int i = 0; while (i < cnt) { - struct multipath_bh *r1_bh; - r1_bh = (struct multipath_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL); - if (!r1_bh) + struct multipath_bh *mp_bh; + mp_bh = (struct multipath_bh*)kmalloc(sizeof(*mp_bh), GFP_KERNEL); + if (!mp_bh) break; - memset(r1_bh, 0, sizeof(*r1_bh)); - - md_spin_lock_irq(&conf->device_lock); - set_bit(MPBH_PreAlloc, &r1_bh->state); - r1_bh->next_r1 = conf->freer1; - conf->freer1 = r1_bh; - md_spin_unlock_irq(&conf->device_lock); + memset(mp_bh, 0, sizeof(*mp_bh)); + set_bit(MPBH_PreAlloc, &mp_bh->state); + mp_bh->mddev = conf->mddev; + multipath_free_mpbh(mp_bh); i++; } return i; @@ -222,29 +127,15 @@ static void multipath_shrink_mpbh(multipath_conf_t *conf) { md_spin_lock_irq(&conf->device_lock); while (conf->freer1) { - struct multipath_bh *r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - kfree(r1_bh); + struct multipath_bh *mp_bh = conf->freer1; + conf->freer1 = mp_bh->next_mp; + conf->freer1_cnt--; + kfree(mp_bh); } md_spin_unlock_irq(&conf->device_lock); } - -static inline void multipath_free_buf(struct multipath_bh *r1_bh) -{ - unsigned long flags; - struct buffer_head *bh = r1_bh->multipath_bh_list; - multipath_conf_t *conf = mddev_to_conf(r1_bh->mddev); - r1_bh->multipath_bh_list = NULL; - - spin_lock_irqsave(&conf->device_lock, flags); - r1_bh->next_r1 = conf->freebuf; - conf->freebuf = r1_bh; - spin_unlock_irqrestore(&conf->device_lock, flags); - multipath_free_bh(conf, bh); -} - static int multipath_map (mddev_t *mddev, kdev_t *rdev) { multipath_conf_t *conf = mddev_to_conf(mddev); @@ -266,77 +157,45 @@ static int multipath_map (mddev_t *mddev, kdev_t *rdev) return (-1); } -static void multipath_reschedule_retry (struct multipath_bh *r1_bh) +static void multipath_reschedule_retry (struct multipath_bh *mp_bh) { unsigned long flags; - mddev_t *mddev = r1_bh->mddev; + mddev_t *mddev = mp_bh->mddev; multipath_conf_t *conf = mddev_to_conf(mddev); md_spin_lock_irqsave(&retry_list_lock, flags); if (multipath_retry_list == NULL) multipath_retry_tail = &multipath_retry_list; - *multipath_retry_tail = r1_bh; - multipath_retry_tail = &r1_bh->next_r1; - r1_bh->next_r1 = NULL; + *multipath_retry_tail = mp_bh; + multipath_retry_tail = &mp_bh->next_mp; + mp_bh->next_mp = NULL; md_spin_unlock_irqrestore(&retry_list_lock, flags); md_wakeup_thread(conf->thread); } -static void inline io_request_done(unsigned long sector, multipath_conf_t *conf, int phase) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector < conf->start_active) - conf->cnt_done--; - else if (sector >= conf->start_future && conf->phase == phase) - conf->cnt_future--; - else if (!--conf->cnt_pending) - wake_up(&conf->wait_ready); - - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -static void inline sync_request_done (unsigned long sector, multipath_conf_t *conf) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector >= conf->start_ready) - --conf->cnt_ready; - else if (sector >= conf->start_active) { - if (!--conf->cnt_active) { - conf->start_active = conf->start_ready; - wake_up(&conf->wait_done); - } - } - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - /* * multipath_end_bh_io() is called when we have finished servicing a multipathed * operation and are ready to return a success/failure code to the buffer * cache layer. */ -static void multipath_end_bh_io (struct multipath_bh *r1_bh, int uptodate) +static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate) { - struct buffer_head *bh = r1_bh->master_bh; - - io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev), - test_bit(MPBH_SyncPhase, &r1_bh->state)); + struct buffer_head *bh = mp_bh->master_bh; bh->b_end_io(bh, uptodate); - multipath_free_mpbh(r1_bh); + multipath_free_mpbh(mp_bh); } void multipath_end_request (struct buffer_head *bh, int uptodate) { - struct multipath_bh * r1_bh = (struct multipath_bh *)(bh->b_private); + struct multipath_bh * mp_bh = (struct multipath_bh *)(bh->b_private); /* * this branch is our 'one multipath IO has finished' event handler: */ if (!uptodate) - md_error (r1_bh->mddev, bh->b_dev); + md_error (mp_bh->mddev, bh->b_dev); else /* * Set MPBH_Uptodate in our master buffer_head, so that @@ -347,11 +206,11 @@ void multipath_end_request (struct buffer_head *bh, int uptodate) * user-side. So if something waits for IO, then it will * wait for the 'master' buffer_head. */ - set_bit (MPBH_Uptodate, &r1_bh->state); + set_bit (MPBH_Uptodate, &mp_bh->state); if (uptodate) { - multipath_end_bh_io(r1_bh, uptodate); + multipath_end_bh_io(mp_bh, uptodate); return; } /* @@ -359,20 +218,13 @@ void multipath_end_request (struct buffer_head *bh, int uptodate) */ printk(KERN_ERR "multipath: %s: rescheduling block %lu\n", partition_name(bh->b_dev), bh->b_blocknr); - multipath_reschedule_retry(r1_bh); + multipath_reschedule_retry(mp_bh); return; } /* * This routine returns the disk from which the requested read should - * be done. It bookkeeps the last read position for every disk - * in array and when new read requests come, the disk which last - * position is nearest to the request, is chosen. - * - * TODO: now if there are 2 multipaths in the same 2 devices, performance - * degrades dramatically because position is multipath, not device based. - * This should be changed to be device based. Also atomic sequential - * reads should be somehow balanced. + * be done. */ static int multipath_read_balance (multipath_conf_t *conf) @@ -391,7 +243,7 @@ static int multipath_make_request (mddev_t *mddev, int rw, { multipath_conf_t *conf = mddev_to_conf(mddev); struct buffer_head *bh_req; - struct multipath_bh * r1_bh; + struct multipath_bh * mp_bh; struct multipath_info *multipath; if (!buffer_locked(bh)) @@ -406,45 +258,25 @@ static int multipath_make_request (mddev_t *mddev, int rw, if (rw == READA) rw = READ; - r1_bh = multipath_alloc_mpbh (conf); - - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, - bh->b_rsector < conf->start_active || - bh->b_rsector >= conf->start_future, - conf->segment_lock); - if (bh->b_rsector < conf->start_active) - conf->cnt_done++; - else { - conf->cnt_future++; - if (conf->phase) - set_bit(MPBH_SyncPhase, &r1_bh->state); - } - spin_unlock_irq(&conf->segment_lock); - - /* - * i think the read and write branch should be separated completely, - * since we want to do read balancing on the read side for example. - * Alternative implementations? :) --mingo - */ + mp_bh = multipath_alloc_mpbh (conf); - r1_bh->master_bh = bh; - r1_bh->mddev = mddev; - r1_bh->cmd = rw; + mp_bh->master_bh = bh; + mp_bh->mddev = mddev; + mp_bh->cmd = rw; /* * read balancing logic: */ multipath = conf->multipaths + multipath_read_balance(conf); - bh_req = &r1_bh->bh_req; + bh_req = &mp_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); bh_req->b_blocknr = bh->b_rsector; bh_req->b_dev = multipath->dev; bh_req->b_rdev = multipath->dev; /* bh_req->b_rsector = bh->n_rsector; */ bh_req->b_end_io = multipath_end_request; - bh_req->b_private = r1_bh; + bh_req->b_private = mp_bh; generic_make_request (rw, bh_req); return 0; } @@ -540,12 +372,10 @@ static int multipath_error (mddev_t *mddev, kdev_t dev) mdp_disk_t *spare; mdp_super_t *sb = mddev->sb; -// MD_BUG(); spare = get_spare(mddev); if (spare) { err = multipath_diskop(mddev, &spare, DISKOP_SPARE_WRITE); printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare)); -// MD_BUG(); } if (!err && !disk_faulty(spare)) { multipath_diskop(mddev, &spare, DISKOP_SPARE_ACTIVE); @@ -553,7 +383,6 @@ static int multipath_error (mddev_t *mddev, kdev_t dev) mark_disk_active(spare); sb->active_disks++; sb->spare_disks--; -// MD_BUG(); } } } @@ -697,7 +526,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) case DISKOP_SPARE_WRITE: sdisk = conf->multipaths + spare_disk; sdisk->operational = 1; - sdisk->write_only = 1; break; /* * Deactivate a spare disk: @@ -705,7 +533,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) case DISKOP_SPARE_INACTIVE: sdisk = conf->multipaths + spare_disk; sdisk->operational = 0; - sdisk->write_only = 0; break; /* * Activate (mark read-write) the (now sync) spare disk, @@ -757,10 +584,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) spare_rdev = find_rdev_nr(mddev, spare_desc->number); failed_rdev = find_rdev_nr(mddev, failed_desc->number); xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr); -// if (failed_rdev->alias_device) -// MD_BUG(); -// if (!spare_rdev->alias_device) -// MD_BUG(); spare_rdev->alias_device = 0; failed_rdev->alias_device = 1; @@ -788,7 +611,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) * this really activates the spare. */ fdisk->spare = 0; - fdisk->write_only = 0; /* * if we activate a spare, we definitely replace a @@ -828,10 +650,8 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) adisk->dev = MKDEV(added_desc->major,added_desc->minor); adisk->operational = 0; - adisk->write_only = 0; adisk->spare = 1; adisk->used_slot = 1; - adisk->head_position = 0; conf->nr_disks++; break; @@ -865,7 +685,7 @@ abort: static void multipathd (void *data) { - struct multipath_bh *r1_bh; + struct multipath_bh *mp_bh; struct buffer_head *bh; unsigned long flags; mddev_t *mddev; @@ -874,31 +694,31 @@ static void multipathd (void *data) for (;;) { md_spin_lock_irqsave(&retry_list_lock, flags); - r1_bh = multipath_retry_list; - if (!r1_bh) + mp_bh = multipath_retry_list; + if (!mp_bh) break; - multipath_retry_list = r1_bh->next_r1; + multipath_retry_list = mp_bh->next_mp; md_spin_unlock_irqrestore(&retry_list_lock, flags); - mddev = r1_bh->mddev; + mddev = mp_bh->mddev; if (mddev->sb_dirty) { printk(KERN_INFO "dirty sb detected, updating.\n"); mddev->sb_dirty = 0; md_update_sb(mddev); } - bh = &r1_bh->bh_req; + bh = &mp_bh->bh_req; dev = bh->b_dev; multipath_map (mddev, &bh->b_dev); if (bh->b_dev == dev) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); - multipath_end_bh_io(r1_bh, 0); + multipath_end_bh_io(mp_bh, 0); } else { printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); bh->b_rdev = bh->b_dev; bh->b_rsector = bh->b_blocknr; - generic_make_request (r1_bh->cmd, bh); + generic_make_request (mp_bh->cmd, bh); } } md_spin_unlock_irqrestore(&retry_list_lock, flags); @@ -1016,7 +836,7 @@ static int multipath_run (mddev_t *mddev) mdp_disk_t *desc, *desc2; mdk_rdev_t *rdev, *def_rdev = NULL; struct md_list_head *tmp; - int start_recovery = 0, num_rdevs = 0; + int num_rdevs = 0; MOD_INC_USE_COUNT; @@ -1072,12 +892,9 @@ static int multipath_run (mddev_t *mddev) disk->number = desc->number; disk->raid_disk = desc->raid_disk; disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; - disk->write_only = 0; disk->spare = 1; disk->used_slot = 1; - disk->head_position = 0; mark_disk_sync(desc); if (disk_active(desc)) { @@ -1135,10 +952,7 @@ static int multipath_run (mddev_t *mddev) conf->mddev = mddev; conf->device_lock = MD_SPIN_LOCK_UNLOCKED; - conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; init_waitqueue_head(&conf->wait_buffer); - init_waitqueue_head(&conf->wait_done); - init_waitqueue_head(&conf->wait_ready); if (!conf->working_disks) { printk(NONE_OPERATIONAL, mdidx(mddev)); @@ -1150,17 +964,17 @@ static int multipath_run (mddev_t *mddev) * As a minimum, 1 mpbh and raid_disks buffer_heads * would probably get us by in tight memory situations, * but a few more is probably a good idea. - * For now, try 16 mpbh and 16*raid_disks bufferheads - * This will allow at least 16 concurrent reads or writes - * even if kmalloc starts failing + * For now, try NR_RESERVED_BUFS mpbh and + * NR_RESERVED_BUFS*raid_disks bufferheads + * This will allow at least NR_RESERVED_BUFS concurrent + * reads or writes even if kmalloc starts failing */ - if (multipath_grow_mpbh(conf, 16) < 16 || - multipath_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) { + if (multipath_grow_mpbh(conf, NR_RESERVED_BUFS) < NR_RESERVED_BUFS) { printk(MEM_ERROR, mdidx(mddev)); goto out_free_conf; } - if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { + if ((sb->state & (1 << MD_SB_CLEAN))) { /* * we do sanity checks even if the device says * it's clean ... @@ -1202,7 +1016,6 @@ static int multipath_run (mddev_t *mddev) out_free_conf: multipath_shrink_mpbh(conf); - multipath_shrink_bh(conf, conf->freebh_cnt); kfree(conf); mddev->private = NULL; out: @@ -1228,7 +1041,6 @@ static int multipath_stop (mddev_t *mddev) md_unregister_thread(conf->thread); multipath_shrink_mpbh(conf); - multipath_shrink_bh(conf, conf->freebh_cnt); kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 93ceec9f7c9d..ddeccc817cc1 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -499,6 +499,9 @@ struct speedo_private { unsigned short phy[2]; /* PHY media interfaces available. */ unsigned short advertising; /* Current PHY advertised caps. */ unsigned short partner; /* Link partner caps. */ +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif }; /* The parameters for a CmdConfigure operation. @@ -2193,8 +2196,11 @@ static void set_rx_mode(struct net_device *dev) static int eepro100_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); + struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; + pci_save_state(pdev, sp->pm_state); + if (!netif_running(dev)) return 0; @@ -2211,6 +2217,8 @@ static int eepro100_resume(struct pci_dev *pdev) struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; + pci_restore_state(pdev, sp->pm_state); + if (!netif_running(dev)) return 0; diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index 4ca0b0e87740..e4be90c3d2da 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -14,6 +14,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA + dep_tristate ' broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_IBMTR" != "y" ]; then dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile index 3de15cfde382..c8300131540e 100644 --- a/drivers/net/pcmcia/Makefile +++ b/drivers/net/pcmcia/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o +obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o # 16-bit wireless client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff --git a/drivers/net/pcmcia/ax8390.h b/drivers/net/pcmcia/ax8390.h new file mode 100644 index 000000000000..4d94199ad633 --- /dev/null +++ b/drivers/net/pcmcia/ax8390.h @@ -0,0 +1,193 @@ +/* Generic NS8390 register definitions. */ +/* This file is part of Donald Becker's 8390 drivers, and is distributed + under the same license. Auto-loading of 8390.o only in v2.2 - Paul G. + Some of these names and comments originated from the Crynwr + packet drivers, which are distributed under the GPL. */ + +#ifndef _8390_h +#define _8390_h + +#include +#include +#include +#include + +#define TX_2X_PAGES 12 +#define TX_1X_PAGES 6 + +/* Should always use two Tx slots to get back-to-back transmits. */ +#define EI_PINGPONG + +#ifdef EI_PINGPONG +#define TX_PAGES TX_2X_PAGES +#else +#define TX_PAGES TX_1X_PAGES +#endif + +#define ETHER_ADDR_LEN 6 + +/* The 8390 specific per-packet-header format. */ +struct e8390_pkt_hdr { + unsigned char status; /* status */ + unsigned char next; /* pointer to next packet. */ + unsigned short count; /* header + packet length in bytes */ +}; + +#ifdef notdef +extern int ei_debug; +#else +#define ei_debug 1 +#endif + +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c */ +extern void autoirq_setup(int waittime); +extern unsigned long autoirq_report(int waittime); +#endif + +static int ethdev_init(struct net_device *dev); +static void NS8390_init(struct net_device *dev, int startp); +static int ei_open(struct net_device *dev); +static int ei_close(struct net_device *dev); +static void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* Most of these entries should be in 'struct net_device' (or most of the + things in there should be here!) */ +/* You have one of these per-board */ +struct ei_device { + const char *name; + void (*reset_8390)(struct net_device *); + void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int); + void (*block_output)(struct net_device *, int, const unsigned char *, int); + void (*block_input)(struct net_device *, int, struct sk_buff *, int); + unsigned char mcfilter[8]; + unsigned open:1; + unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */ + unsigned txing:1; /* Transmit Active */ + unsigned irqlock:1; /* 8390's intrs disabled when '1'. */ + unsigned dmaing:1; /* Remote DMA Active */ + unsigned char tx_start_page, rx_start_page, stop_page; + unsigned char current_page; /* Read pointer in buffer */ + unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */ + unsigned char txqueue; /* Tx Packet buffer queue length. */ + short tx1, tx2; /* Packet lengths for ping-pong tx. */ + short lasttx; /* Alpha version consistency check. */ + unsigned char reg0; /* Register '0' in a WD8013 */ + unsigned char reg5; /* Register '5' in a WD8013 */ + unsigned char saved_irq; /* Original dev->irq value. */ + struct net_device_stats stat; /* The new statistics table. */ + u32 *reg_offset; /* Register mapping table */ + spinlock_t page_lock; /* Page register locks */ + unsigned long priv; /* Private field to store bus IDs etc. */ +}; + +/* The maximum number of 8390 interrupt service routines called per IRQ. */ +#define MAX_SERVICE 12 + +/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */ +#define TX_TIMEOUT (20*HZ/100) + +#define ei_status (*(struct ei_device *)(dev->priv)) + +/* Some generic ethernet register configurations. */ +#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ +#define E8390_RX_IRQ_MASK 0x5 +#define E8390_RXCONFIG 0x44 /* EN0_RXCR: broadcasts, no multicast,errors */ +#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */ +#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */ +#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */ + +/* Register accessed at EN_CMD, the 8390 base addr. */ +#define E8390_STOP 0x01 /* Stop and reset the chip */ +#define E8390_START 0x02 /* Start the chip, clear reset */ +#define E8390_TRANS 0x04 /* Transmit a frame */ +#define E8390_RREAD 0x08 /* Remote read */ +#define E8390_RWRITE 0x10 /* Remote write */ +#define E8390_NODMA 0x20 /* Remote DMA */ +#define E8390_PAGE0 0x00 /* Select page chip registers */ +#define E8390_PAGE1 0x40 /* using the two high-order bits */ +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ + +/* + * Only generate indirect loads given a machine that needs them. + */ + +#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ + defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \ + defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) +#define EI_SHIFT(x) (ei_local->reg_offset[x]) +#else +#define EI_SHIFT(x) (x) +#endif + +#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */ +/* Page 0 register offsets. */ +#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */ +#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */ +#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */ +#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */ +#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */ +#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */ +#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */ +#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */ +#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */ +#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */ +#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */ +#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */ +#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */ +#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */ +#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */ +#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */ +#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */ +#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */ +#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */ +#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */ +#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */ +#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */ +#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */ +#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */ +#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */ +#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */ + +/* Bits in EN0_ISR - Interrupt status register */ +#define ENISR_RX 0x01 /* Receiver, no error */ +#define ENISR_TX 0x02 /* Transmitter, no error */ +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ +#define ENISR_RDC 0x40 /* remote dma complete */ +#define ENISR_RESET 0x80 /* Reset completed */ +#define ENISR_ALL 0x3f /* Interrupts we will enable */ + +/* Bits in EN0_DCFG - Data config register */ +#define ENDCFG_WTS 0x01 /* word transfer mode selection */ + +/* Page 1 register offsets. */ +#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */ +#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */ +#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */ +#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */ +#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */ + +/* Bits in received packet status byte and EN0_RSR*/ +#define ENRSR_RXOK 0x01 /* Received a good packet */ +#define ENRSR_CRC 0x02 /* CRC error */ +#define ENRSR_FAE 0x04 /* frame alignment error */ +#define ENRSR_FO 0x08 /* FIFO overrun */ +#define ENRSR_MPA 0x10 /* missed pkt */ +#define ENRSR_PHY 0x20 /* physical/multicast address */ +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ +#define ENRSR_DEF 0x80 /* deferring */ + +/* Transmitted packet status, EN0_TSR. */ +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ + +#endif /* _8390_h */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c new file mode 100644 index 000000000000..815823b79cc8 --- /dev/null +++ b/drivers/net/pcmcia/axnet_cs.c @@ -0,0 +1,1958 @@ +/*====================================================================== + + A PCMCIA ethernet driver for Asix AX88190-based cards + + The Asix AX88190 is a NS8390-derived chipset with a few nasty + idiosyncracies that make it very inconvenient to support with a + standard 8390 driver. This driver is based on pcnet_cs, with the + tweaked 8390 code grafted on the end. Much of what I did was to + clean up and update a similar driver supplied by Asix, which was + adapted by William Lee, william@asix.com.tw. + + Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net + + axnet_cs.c 1.11 2001/06/12 12:42:40 + + The network driver code is based on Donald Becker's NE2000 code: + + Written 1992,1993 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. This software may be used and + distributed according to the terms of the GNU General Public License, + incorporated herein by reference. + Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ax8390.h" + +#include +#include +#include +#include +#include +#include +#include + +#define AXNET_CMD 0x00 +#define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ +#define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ +#define AXNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ +#define AXNET_MII_EEP 0x14 /* Offset of MII access port */ + +#define AXNET_START_PG 0x40 /* First page of TX buffer */ +#define AXNET_STOP_PG 0x80 /* Last page +1 of RX ring */ + +#define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); +#define skb_tx_check(dev, skb) +#define add_rx_bytes(stats, n) (stats)->rx_bytes += n; +#define add_tx_bytes(stats, n) (stats)->tx_bytes += n; +#define netif_mark_up(dev) do { } while (0) +#define netif_mark_down(dev) do { } while (0) + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") + +/* Bit map of interrupts to choose from */ +INT_MODULE_PARM(irq_mask, 0xdeb8); +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); + +/* Ugh! Let the user hardwire the hardware address for queer cards */ +static int hw_addr[6] = { 0, /* ... */ }; +MODULE_PARM(hw_addr, "6i"); + +/*====================================================================*/ + +static void axnet_config(dev_link_t *link); +static void axnet_release(u_long arg); +static int axnet_event(event_t event, int priority, + event_callback_args_t *args); +static int axnet_open(struct net_device *dev); +static int axnet_close(struct net_device *dev); +static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); +static void ei_watchdog(u_long arg); +static void axnet_reset_8390(struct net_device *dev); + +static int mdio_read(ioaddr_t addr, int phy_id, int loc); +static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value); + +static void get_8390_hdr(struct net_device *, + struct e8390_pkt_hdr *, int); +static void block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void block_output(struct net_device *dev, int count, + const u_char *buf, const int start_page); + +static dev_link_t *axnet_attach(void); +static void axnet_detach(dev_link_t *); + +static dev_info_t dev_info = "axnet_cs"; +static dev_link_t *dev_list; + +/*====================================================================*/ + +typedef struct axnet_dev_t { + struct net_device dev; /* so &dev == &axnet_dev_t */ + dev_link_t link; + dev_node_t node; + caddr_t base; + struct timer_list watchdog; + int stale, fast_poll; + u_short link_status; + u_char duplex_flag; + int phy_id; +} axnet_dev_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + axnet_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + We never need to do anything when a axnet device is "initialized" + by the net software, because we only register already-found cards. + +======================================================================*/ + +static int axnet_init(struct net_device *dev) +{ + return 0; +} + +/*====================================================================== + + axnet_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static dev_link_t *axnet_attach(void) +{ + axnet_dev_t *info; + dev_link_t *link; + struct net_device *dev; + client_reg_t client_reg; + int i, ret; + + DEBUG(0, "axnet_attach()\n"); + flush_stale_links(); + + /* Create new ethernet device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; dev = &info->dev; + link->priv = info; + + link->release.function = &axnet_release; + link->release.data = (u_long)link; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.IntType = INT_MEMORY_AND_IO; + + ethdev_init(dev); + dev->init = &axnet_init; + dev->open = &axnet_open; + dev->stop = &axnet_close; + dev->do_ioctl = &axnet_ioctl; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &axnet_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + axnet_detach(link); + return NULL; + } + + return link; +} /* axnet_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void axnet_detach(dev_link_t *link) +{ + axnet_dev_t *info = link->priv; + dev_link_t **linkp; + + DEBUG(0, "axnet_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) { + axnet_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->dev) + unregister_netdev(&info->dev); + kfree(info); + +} /* axnet_detach */ + +/*====================================================================== + + This probes for a card's hardware address by reading the PROM. + +======================================================================*/ + +static int get_prom(dev_link_t *link) +{ + struct net_device *dev = link->priv; + ioaddr_t ioaddr = dev->base_addr; + int i, j; + + /* This is based on drivers/net/ne.c */ + struct { + u_char value, offset; + } program_seq[] = { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x01, EN0_DCFG}, /* Set word-wide access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {0x10, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0400. */ + {0x04, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + /* Not much of a test, but the alternatives are messy */ + if (link->conf.ConfigBase != 0x03c0) + return 0; + + axnet_reset_8390(dev); + mdelay(10); + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + + for (i = 0; i < 6; i += 2) { + j = inw(ioaddr + AXNET_DATAPORT); + dev->dev_addr[i] = j & 0xff; + dev->dev_addr[i+1] = j >> 8; + } + return 1; +} /* get_prom */ + +/*====================================================================== + + This should be totally unnecessary... but when we can't figure + out the hardware address any other way, we'll let the user hard + wire it when the module is initialized. + +======================================================================*/ + +static int get_hwired(dev_link_t *link) +{ + struct net_device *dev = link->priv; + int i; + + for (i = 0; i < 6; i++) + if (hw_addr[i] != 0) break; + if (i == 6) + return 0; + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = hw_addr[i]; + + return 1; +} /* get_hwired */ + +/*====================================================================== + + axnet_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static int try_io_port(dev_link_t *link) +{ + int j, ret; + if (link->io.NumPorts1 == 32) { + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (link->io.NumPorts2 > 0) { + /* for master/slave multifunction cards */ + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->irq.Attributes = + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + } + } else { + /* This should be two 16-port windows */ + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + } + if (link->io.BasePort1 == 0) { + link->io.IOAddrLines = 16; + for (j = 0; j < 0x400; j += 0x20) { + link->io.BasePort1 = j ^ 0x300; + link->io.BasePort2 = (j ^ 0x300) + 0x10; + ret = CardServices(RequestIO, link->handle, &link->io); + if (ret == CS_SUCCESS) return ret; + } + return ret; + } else { + return CardServices(RequestIO, link->handle, &link->io); + } +} + +static void axnet_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + axnet_dev_t *info = link->priv; + struct net_device *dev = &info->dev; + tuple_t tuple; + cisparse_t parse; + int i, j, last_ret, last_fn; + u_short buf[64]; + config_info_t conf; + + DEBUG(0, "axnet_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (last_ret == CS_SUCCESS) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + cistpl_io_t *io = &(parse.cftable_entry.io); + + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if ((cfg->index == 0) || (cfg->io.nwin == 0)) + goto next_entry; + + link->conf.ConfigIndex = cfg->index; + /* For multifunction cards, by convention, we configure the + network function with window 0, and serial with window 1 */ + if (io->nwin > 1) { + i = (io->win[1].len > io->win[0].len); + link->io.BasePort2 = io->win[1-i].base; + link->io.NumPorts2 = io->win[1-i].len; + } else { + i = link->io.NumPorts2 = 0; + } + link->io.BasePort1 = io->win[i].base; + link->io.NumPorts1 = io->win[i].len; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { + last_ret = try_io_port(link); + if (last_ret == CS_SUCCESS) break; + } + next_entry: + last_ret = CardServices(GetNextTuple, handle, &tuple); + } + if (last_ret != CS_SUCCESS) { + cs_error(handle, RequestIO, last_ret); + goto failed; + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + + if (link->io.NumPorts2 == 8) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + CS_CHECK(RequestConfiguration, handle, &link->conf); + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); + goto failed; + } + + if (!get_prom(link) && !get_hwired(link)) { + printk(KERN_NOTICE "axnet_cs: unable to read hardware net" + " address for io base %#3lx\n", dev->base_addr); + unregister_netdev(dev); + goto failed; + } + + ei_status.name = "AX88190"; + ei_status.word16 = 1; + ei_status.tx_start_page = AXNET_START_PG; + ei_status.rx_start_page = AXNET_START_PG + TX_PAGES; + ei_status.stop_page = AXNET_STOP_PG; + ei_status.reset_8390 = &axnet_reset_8390; + ei_status.get_8390_hdr = &get_8390_hdr; + ei_status.block_input = &block_input; + ei_status.block_output = &block_output; + + strcpy(info->node.dev_name, dev->name); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + printk(KERN_INFO "%s: Asix AX88190: io %#3lx, irq %d, hw_addr ", + dev->name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + + for (i = 0; i < 32; i++) { + j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); + if ((j != 0) && (j != 0xffff)) break; + } + info->phy_id = (i < 32) ? i : -1; + if (i < 32) { + DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j); + } else { + printk(KERN_NOTICE " No MII transceivers found!\n"); + } + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + axnet_release((u_long)link); + return; +} /* axnet_config */ + +/*====================================================================== + + After a card is removed, axnet_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void axnet_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "axnet_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", + info->node.dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + +} /* axnet_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + +======================================================================*/ + +static int axnet_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + axnet_dev_t *info = link->priv; + + DEBUG(2, "axnet_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_device_detach(&info->dev); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT; + axnet_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) + netif_device_detach(&info->dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + axnet_reset_8390(&info->dev); + NS8390_init(&info->dev, 1); + netif_device_attach(&info->dev); + } + } + break; + } + return 0; +} /* axnet_event */ + +/*====================================================================== + + MII interface support + +======================================================================*/ + +#define MDIO_SHIFT_CLK 0x01 +#define MDIO_DATA_WRITE0 0x00 +#define MDIO_DATA_WRITE1 0x08 +#define MDIO_DATA_READ 0x04 +#define MDIO_MASK 0x0f +#define MDIO_ENB_IN 0x02 + +static void mdio_sync(ioaddr_t addr) +{ + int bits; + for (bits = 0; bits < 32; bits++) { + outb_p(MDIO_DATA_WRITE1, addr); + outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); + } +} + +static int mdio_read(ioaddr_t addr, int phy_id, int loc) +{ + u_int cmd = (0xf6<<10)|(phy_id<<5)|loc; + int i, retval = 0; + + mdio_sync(addr); + for (i = 14; i >= 0; i--) { + int dat = (cmd&(1< 0; i--) { + outb_p(MDIO_ENB_IN, addr); + retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0); + outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) +{ + u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; + int i; + + mdio_sync(addr); + for (i = 31; i >= 0; i--) { + int dat = (cmd&(1<= 0; i--) { + outb_p(MDIO_ENB_IN, addr); + outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr); + } +} + +/*====================================================================*/ + +static int axnet_open(struct net_device *dev) +{ + axnet_dev_t *info = (axnet_dev_t *)dev; + dev_link_t *link = &info->link; + + DEBUG(2, "axnet_open('%s')\n", dev->name); + + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + + request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev); + + info->link_status = 0x00; + info->watchdog.function = &ei_watchdog; + info->watchdog.data = (u_long)info; + info->watchdog.expires = jiffies + HZ; + add_timer(&info->watchdog); + + return ei_open(dev); +} /* axnet_open */ + +/*====================================================================*/ + +static int axnet_close(struct net_device *dev) +{ + axnet_dev_t *info = (axnet_dev_t *)dev; + dev_link_t *link = &info->link; + + DEBUG(2, "axnet_close('%s')\n", dev->name); + + free_irq(dev->irq, dev); + + link->open--; + netif_stop_queue(dev); + netif_mark_down(dev); + del_timer(&info->watchdog); + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + MOD_DEC_USE_COUNT; + + return 0; +} /* axnet_close */ + +/*====================================================================== + + Hard reset the card. This used to pause for the same period that + a 8390 reset command required, but that shouldn't be necessary. + +======================================================================*/ + +static void axnet_reset_8390(struct net_device *dev) +{ + ioaddr_t nic_base = dev->base_addr; + int i; + + ei_status.txing = ei_status.dmaing = 0; + + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD); + + outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET); + + for (i = 0; i < 100; i++) { + if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0) + break; + udelay(100); + } + outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ + + if (i == 100) + printk(KERN_ERR "%s: axnet_reset_8390() did not complete.\n", + dev->name); + +} /* axnet_reset_8390 */ + +/*====================================================================*/ + +static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) +{ + axnet_dev_t *info = dev_id; + info->stale = 0; + ei_interrupt(irq, dev_id, regs); +} + +static void ei_watchdog(u_long arg) +{ + axnet_dev_t *info = (axnet_dev_t *)(arg); + struct net_device *dev = &info->dev; + ioaddr_t nic_base = dev->base_addr; + ioaddr_t mii_addr = nic_base + AXNET_MII_EEP; + u_short link; + + if (!netif_device_present(dev)) goto reschedule; + + /* Check for pending interrupt with expired latency timer: with + this, we can limp along even if the interrupt is blocked */ + if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) { + if (!info->fast_poll) + printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); + ei_irq_wrapper(dev->irq, dev, NULL); + info->fast_poll = HZ; + } + if (info->fast_poll) { + info->fast_poll--; + info->watchdog.expires = jiffies + 1; + add_timer(&info->watchdog); + return; + } + + if (info->phy_id < 0) + goto reschedule; + link = mdio_read(mii_addr, info->phy_id, 1); + if (!link || (link == 0xffff)) { + printk(KERN_INFO "%s: MII is missing!\n", dev->name); + info->phy_id = -1; + goto reschedule; + } + + link &= 0x0004; + if (link != info->link_status) { + u_short p = mdio_read(mii_addr, info->phy_id, 5); + printk(KERN_INFO "%s: %s link beat\n", dev->name, + (link) ? "found" : "lost"); + if (link) { + info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00; + if (p) + printk(KERN_INFO "%s: autonegotiation complete: " + "%sbaseT-%cD selected\n", dev->name, + ((p & 0x0180) ? "100" : "10"), + ((p & 0x0140) ? 'F' : 'H')); + else + printk(KERN_INFO "%s: link partner did not autonegotiate\n", + dev->name); + NS8390_init(dev, 1); + } + info->link_status = link; + } + +reschedule: + info->watchdog.expires = jiffies + HZ; + add_timer(&info->watchdog); +} + +/*====================================================================*/ + +static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + axnet_dev_t *info = (axnet_dev_t *)dev; + u16 *data = (u16 *)&rq->ifr_data; + ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; + switch (cmd) { + case SIOCDEVPRIVATE: + data[0] = info->phy_id; + case SIOCDEVPRIVATE+1: + data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); + return 0; + } + return -EOPNOTSUPP; +} + +/*====================================================================*/ + +static void get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, + int ring_page) +{ + ioaddr_t nic_base = dev->base_addr; + + outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); + + insw(nic_base + AXNET_DATAPORT, hdr, + sizeof(struct e8390_pkt_hdr)>>1); + /* Fix for big endian systems */ + hdr->count = le16_to_cpu(hdr->count); + +} + +/*====================================================================*/ + +static void block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + ioaddr_t nic_base = dev->base_addr; + int xfer_count = count; + char *buf = skb->data; + +#ifdef PCMCIA_DEBUG + if ((ei_debug > 4) && (count != 4)) + printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4); +#endif + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); + + insw(nic_base + AXNET_DATAPORT,buf,count>>1); + if (count & 0x01) + buf[count-1] = inb(nic_base + AXNET_DATAPORT), xfer_count++; + +} + +/*====================================================================*/ + +static void block_output(struct net_device *dev, int count, + const u_char *buf, const int start_page) +{ + ioaddr_t nic_base = dev->base_addr; + +#ifdef PCMCIA_DEBUG + if (ei_debug > 4) + printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count); +#endif + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (count & 0x01) + count++; + + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD); + outsw(nic_base + AXNET_DATAPORT, buf, count>>1); +} + +/*====================================================================*/ + +static int __init init_axnet_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "axnet_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &axnet_attach, &axnet_detach); + return 0; +} + +static void __exit exit_axnet_cs(void) +{ + DEBUG(0, "axnet_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + axnet_detach(dev_list); +} + +module_init(init_axnet_cs); +module_exit(exit_axnet_cs); + +/*====================================================================*/ + +/* 8390.c: A general NS8390 ethernet driver core for linux. */ +/* + Written 1992-94 by Donald Becker. + + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + This is the chip-specific code for many 8390-based ethernet adaptors. + This is not a complete driver, it must be combined with board-specific + code such as ne.c, wd.c, 3c503.c, etc. + + Seeing how at least eight drivers use this code, (not counting the + PCMCIA ones either) it is easy to break some card by what seems like + a simple innocent change. Please contact me or Donald if you think + you have found something that needs changing. -- PG + + + Changelog: + + Paul Gortmaker : remove set_bit lock, other cleanups. + Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to + ei_block_input() for eth_io_copy_and_sum(). + Paul Gortmaker : exchange static int ei_pingpong for a #define, + also add better Tx error handling. + Paul Gortmaker : rewrite Rx overrun handling as per NS specs. + Alexey Kuznetsov : use the 8390's six bit hash multicast filter. + Paul Gortmaker : tweak ANK's above multicast changes a bit. + Paul Gortmaker : update packet statistics for v2.1.x + Alan Cox : support arbitary stupid port mappings on the + 68K Macintosh. Support >16bit I/O spaces + Paul Gortmaker : add kmod support for auto-loading of the 8390 + module by all drivers that require it. + Alan Cox : Spinlocking work, added 'BUG_83C690' + Paul Gortmaker : Separate out Tx timeout code from Tx path. + + Sources: + The National Semiconductor LAN Databook, and the 3Com 3c503 databook. + + */ + +static const char *version = + "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + +#include +#include +#include +#include +#include +#include + +#include + +#define BUG_83C690 + +/* These are the operational function interfaces to board-specific + routines. + void reset_8390(struct net_device *dev) + Resets the board associated with DEV, including a hardware reset of + the 8390. This is only called when there is a transmit timeout, and + it is always followed by 8390_init(). + void block_output(struct net_device *dev, int count, const unsigned char *buf, + int start_page) + Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The + "page" value uses the 8390's 256-byte pages. + void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page) + Read the 4 byte, page aligned 8390 header. *If* there is a + subsequent read, it will be of the rest of the packet. + void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) + Read COUNT bytes from the packet buffer into the skb data area. Start + reading from RING_OFFSET, the address as the 8390 sees it. This will always + follow the read of the 8390 header. +*/ +#define ei_reset_8390 (ei_local->reset_8390) +#define ei_block_output (ei_local->block_output) +#define ei_block_input (ei_local->block_input) +#define ei_get_8390_hdr (ei_local->get_8390_hdr) + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef ei_debug +int ei_debug = 1; +#endif + +/* Index to functions. */ +static void ei_tx_intr(struct net_device *dev); +static void ei_tx_err(struct net_device *dev); +static void ei_tx_timeout(struct net_device *dev); +static void ei_receive(struct net_device *dev); +static void ei_rx_overrun(struct net_device *dev); + +/* Routines generic to NS8390-based boards. */ +static void NS8390_trigger_send(struct net_device *dev, unsigned int length, + int start_page); +static void set_multicast_list(struct net_device *dev); +static void do_set_multicast_list(struct net_device *dev); + +/* + * SMP and the 8390 setup. + * + * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is + * a page register that controls bank and packet buffer access. We guard + * this with ei_local->page_lock. Nobody should assume or set the page other + * than zero when the lock is not held. Lock holders must restore page 0 + * before unlocking. Even pure readers must take the lock to protect in + * page 0. + * + * To make life difficult the chip can also be very slow. We therefore can't + * just use spinlocks. For the longer lockups we disable the irq the device + * sits on and hold the lock. We must hold the lock because there is a dual + * processor case other than interrupts (get stats/set multicast list in + * parallel with each other and transmit). + * + * Note: in theory we can just disable the irq on the card _but_ there is + * a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs" + * enter lock, take the queued irq. So we waddle instead of flying. + * + * Finally by special arrangement for the purpose of being generally + * annoying the transmit function is called bh atomic. That places + * restrictions on the user context callers as disable_irq won't save + * them. + */ + + + +/** + * ei_open - Open/initialize the board. + * @dev: network device to initialize + * + * This routine goes all-out, setting everything + * up anew at each open, even though many of these registers should only + * need to be set once at boot. + */ +static int ei_open(struct net_device *dev) +{ + unsigned long flags; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + + /* This can't happen unless somebody forgot to call ethdev_init(). */ + if (ei_local == NULL) + { + printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); + return -ENXIO; + } + +#ifdef HAVE_TX_TIMEOUT + /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout + wrapper that does e.g. media check & then calls ei_tx_timeout. */ + if (dev->tx_timeout == NULL) + dev->tx_timeout = ei_tx_timeout; + if (dev->watchdog_timeo <= 0) + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + /* + * Grab the page lock so we own the register set, then call + * the init function. + */ + + spin_lock_irqsave(&ei_local->page_lock, flags); + NS8390_init(dev, 1); + /* Set the flag before we drop the lock, That way the IRQ arrives + after its set and we get no silly warnings */ + netif_mark_up(dev); + netif_start_queue(dev); + spin_unlock_irqrestore(&ei_local->page_lock, flags); + ei_local->irqlock = 0; + return 0; +} + +/** + * ei_close - shut down network device + * @dev: network device to close + * + * Opposite of ei_open(). Only used when "ifconfig down" is done. + */ +static int ei_close(struct net_device *dev) +{ + unsigned long flags; + + /* + * Hold the page lock during close + */ + + spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); + NS8390_init(dev, 0); + spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); + netif_stop_queue(dev); + return 0; +} + +/** + * ei_tx_timeout - handle transmit time out condition + * @dev: network device which has apparently fallen asleep + * + * Called by kernel when device never acknowledges a transmit has + * completed (or failed) - i.e. never posted a Tx related interrupt. + */ + +void ei_tx_timeout(struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + int txsr, isr, tickssofar = jiffies - dev->trans_start; + unsigned long flags; + + ei_local->stat.tx_errors++; + + spin_lock_irqsave(&ei_local->page_lock, flags); + txsr = inb(e8390_base+EN0_TSR); + isr = inb(e8390_base+EN0_ISR); + spin_unlock_irqrestore(&ei_local->page_lock, flags); + + printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", + dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : + (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); + + if (!isr && !ei_local->stat.tx_packets) + { + /* The 8390 probably hasn't gotten on the cable yet. */ + ei_local->interface_num ^= 1; /* Try a different xcvr. */ + } + + /* Ugly but a reset can be slow, yet must be protected */ + + disable_irq_nosync(dev->irq); + spin_lock(&ei_local->page_lock); + + /* Try to restart the card. Perhaps the user has fixed something. */ + ei_reset_8390(dev); + NS8390_init(dev, 1); + + spin_unlock(&ei_local->page_lock); + enable_irq(dev->irq); + netif_wake_queue(dev); +} + +/** + * ei_start_xmit - begin packet transmission + * @skb: packet to be sent + * @dev: network device to which packet is sent + * + * Sends a packet to an 8390 network device. + */ + +static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + int length, send_length, output_page; + unsigned long flags; + + netif_stop_queue(dev); + skb_tx_check(dev, skb); + + length = skb->len; + + /* Mask interrupts from the ethercard. + SMP: We have to grab the lock here otherwise the IRQ handler + on another CPU can flip window and race the IRQ mask set. We end + up trashing the mcast filter not disabling irqs if we dont lock */ + + spin_lock_irqsave(&ei_local->page_lock, flags); + outb_p(0x00, e8390_base + EN0_IMR); + spin_unlock_irqrestore(&ei_local->page_lock, flags); + + + /* + * Slow phase with lock held. + */ + + disable_irq_nosync(dev->irq); + + spin_lock(&ei_local->page_lock); + + ei_local->irqlock = 1; + + send_length = ETH_ZLEN < length ? length : ETH_ZLEN; + +#ifdef EI_PINGPONG + + /* + * We have two Tx slots available for use. Find the first free + * slot, and then perform some sanity checks. With two Tx bufs, + * you get very close to transmitting back-to-back packets. With + * only one Tx buf, the transmitter sits idle while you reload the + * card, leaving a substantial gap between each transmitted packet. + */ + + if (ei_local->tx1 == 0) + { + output_page = ei_local->tx_start_page; + ei_local->tx1 = send_length; + if (ei_debug && ei_local->tx2 > 0) + printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n", + dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing); + } + else if (ei_local->tx2 == 0) + { + output_page = ei_local->tx_start_page + TX_1X_PAGES; + ei_local->tx2 = send_length; + if (ei_debug && ei_local->tx1 > 0) + printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", + dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing); + } + else + { /* We should never get here. */ + if (ei_debug) + printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n", + dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx); + ei_local->irqlock = 0; + netif_stop_queue(dev); + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + spin_unlock(&ei_local->page_lock); + enable_irq(dev->irq); + ei_local->stat.tx_errors++; + return 1; + } + + /* + * Okay, now upload the packet and trigger a send if the transmitter + * isn't already sending. If it is busy, the interrupt handler will + * trigger the send later, upon receiving a Tx done interrupt. + */ + + ei_block_output(dev, length, skb->data, output_page); + if (! ei_local->txing) + { + ei_local->txing = 1; + NS8390_trigger_send(dev, send_length, output_page); + dev->trans_start = jiffies; + if (output_page == ei_local->tx_start_page) + { + ei_local->tx1 = -1; + ei_local->lasttx = -1; + } + else + { + ei_local->tx2 = -1; + ei_local->lasttx = -2; + } + } + else ei_local->txqueue++; + + if (ei_local->tx1 && ei_local->tx2) + netif_stop_queue(dev); + else + netif_start_queue(dev); + +#else /* EI_PINGPONG */ + + /* + * Only one Tx buffer in use. You need two Tx bufs to come close to + * back-to-back transmits. Expect a 20 -> 25% performance hit on + * reasonable hardware if you only use one Tx buffer. + */ + + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + ei_local->txing = 1; + NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); + dev->trans_start = jiffies; + netif_stop_queue(dev); + +#endif /* EI_PINGPONG */ + + /* Turn 8390 interrupts back on. */ + ei_local->irqlock = 0; + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + + spin_unlock(&ei_local->page_lock); + enable_irq(dev->irq); + + DEV_KFREE_SKB (skb); + add_tx_bytes(&ei_local->stat, send_length); + + return 0; +} + +/** + * ei_interrupt - handle the interrupts from an 8390 + * @irq: interrupt number + * @dev_id: a pointer to the net_device + * @regs: unused + * + * Handle the ether interface interrupts. We pull packets from + * the 8390 via the card specific functions and fire them at the networking + * stack. We also handle transmit completions and wake the transmit path if + * neccessary. We also update the counters and do other housekeeping as + * needed. + */ + +static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + long e8390_base; + int interrupts, nr_serviced = 0, i; + struct ei_device *ei_local; + + if (dev == NULL) + { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + e8390_base = dev->base_addr; + ei_local = (struct ei_device *) dev->priv; + + /* + * Protect the irq test too. + */ + + spin_lock(&ei_local->page_lock); + + if (ei_local->irqlock) + { +#if 1 /* This might just be an interrupt for a PCI device sharing this line */ + /* The "irqlock" check is only for testing. */ + printk(ei_local->irqlock + ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n" + : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n", + dev->name, inb_p(e8390_base + EN0_ISR), + inb_p(e8390_base + EN0_IMR)); +#endif + spin_unlock(&ei_local->page_lock); + return; + } + + if (ei_debug > 3) + printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name, + inb_p(e8390_base + EN0_ISR)); + + outb_p(0x00, e8390_base + EN0_ISR); + ei_local->irqlock = 1; + + /* !!Assumption!! -- we stay in page 0. Don't break this. */ + while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 + && ++nr_serviced < MAX_SERVICE) + { + if (!netif_running(dev) || (interrupts == 0xff)) { + if (ei_debug > 1) + printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); + outb_p(interrupts, e8390_base + EN0_ISR); + interrupts = 0; + break; + } + /* AX88190 bug fix. */ + outb_p(interrupts, e8390_base + EN0_ISR); + for (i = 0; i < 10; i++) { + if (!(inb(e8390_base + EN0_ISR) & interrupts)) + break; + outb_p(0, e8390_base + EN0_ISR); + outb_p(interrupts, e8390_base + EN0_ISR); + } + if (interrupts & ENISR_OVER) + ei_rx_overrun(dev); + else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) + { + /* Got a good (?) packet. */ + ei_receive(dev); + } + /* Push the next to-transmit packet through. */ + if (interrupts & ENISR_TX) + ei_tx_intr(dev); + else if (interrupts & ENISR_TX_ERR) + ei_tx_err(dev); + + if (interrupts & ENISR_COUNTERS) + { + ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); + ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); + ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); + } + } + + if (interrupts && ei_debug) + { + if (nr_serviced >= MAX_SERVICE) + { + /* 0xFF is valid for a card removal */ + if(interrupts!=0xFF) + printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n", + dev->name, interrupts); + outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */ + } else { + printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts); + outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */ + } + } + + /* Turn 8390 interrupts back on. */ + ei_local->irqlock = 0; + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + + spin_unlock(&ei_local->page_lock); + return; +} + +/** + * ei_tx_err - handle transmitter error + * @dev: network device which threw the exception + * + * A transmitter error has happened. Most likely excess collisions (which + * is a fairly normal condition). If the error is one where the Tx will + * have been aborted, we try and send another one right away, instead of + * letting the failed packet sit and collect dust in the Tx buffer. This + * is a much better solution as it avoids kernel based Tx timeouts, and + * an unnecessary card reset. + * + * Called with lock held. + */ + +static void ei_tx_err(struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + unsigned char txsr = inb_p(e8390_base+EN0_TSR); + unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); + +#ifdef VERBOSE_ERROR_DUMP + printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr); + if (txsr & ENTSR_ABT) + printk("excess-collisions "); + if (txsr & ENTSR_ND) + printk("non-deferral "); + if (txsr & ENTSR_CRS) + printk("lost-carrier "); + if (txsr & ENTSR_FU) + printk("FIFO-underrun "); + if (txsr & ENTSR_CDH) + printk("lost-heartbeat "); + printk("\n"); +#endif + + if (tx_was_aborted) + ei_tx_intr(dev); + else + { + ei_local->stat.tx_errors++; + if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; + if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; + if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++; + } +} + +/** + * ei_tx_intr - transmit interrupt handler + * @dev: network device for which tx intr is handled + * + * We have finished a transmit: check for errors and then trigger the next + * packet to be sent. Called with lock held. + */ + +static void ei_tx_intr(struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + int status = inb(e8390_base + EN0_TSR); + +#ifdef EI_PINGPONG + + /* + * There are two Tx buffers, see which one finished, and trigger + * the send of another one if it exists. + */ + ei_local->txqueue--; + + if (ei_local->tx1 < 0) + { + if (ei_local->lasttx != 1 && ei_local->lasttx != -1) + printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n", + ei_local->name, ei_local->lasttx, ei_local->tx1); + ei_local->tx1 = 0; + if (ei_local->tx2 > 0) + { + ei_local->txing = 1; + NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6); + dev->trans_start = jiffies; + ei_local->tx2 = -1, + ei_local->lasttx = 2; + } + else ei_local->lasttx = 20, ei_local->txing = 0; + } + else if (ei_local->tx2 < 0) + { + if (ei_local->lasttx != 2 && ei_local->lasttx != -2) + printk("%s: bogus last_tx_buffer %d, tx2=%d.\n", + ei_local->name, ei_local->lasttx, ei_local->tx2); + ei_local->tx2 = 0; + if (ei_local->tx1 > 0) + { + ei_local->txing = 1; + NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page); + dev->trans_start = jiffies; + ei_local->tx1 = -1; + ei_local->lasttx = 1; + } + else + ei_local->lasttx = 10, ei_local->txing = 0; + } +// else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", +// dev->name, ei_local->lasttx); + +#else /* EI_PINGPONG */ + /* + * Single Tx buffer: mark it free so another packet can be loaded. + */ + ei_local->txing = 0; +#endif + + /* Minimize Tx latency: update the statistics after we restart TXing. */ + if (status & ENTSR_COL) + ei_local->stat.collisions++; + if (status & ENTSR_PTX) + ei_local->stat.tx_packets++; + else + { + ei_local->stat.tx_errors++; + if (status & ENTSR_ABT) + { + ei_local->stat.tx_aborted_errors++; + ei_local->stat.collisions += 16; + } + if (status & ENTSR_CRS) + ei_local->stat.tx_carrier_errors++; + if (status & ENTSR_FU) + ei_local->stat.tx_fifo_errors++; + if (status & ENTSR_CDH) + ei_local->stat.tx_heartbeat_errors++; + if (status & ENTSR_OWC) + ei_local->stat.tx_window_errors++; + } + netif_wake_queue(dev); +} + +/** + * ei_receive - receive some packets + * @dev: network device with which receive will be run + * + * We have a good packet(s), get it/them out of the buffers. + * Called with lock held. + */ + +static void ei_receive(struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + unsigned char rxing_page, this_frame, next_frame; + unsigned short current_offset; + int rx_pkt_count = 0; + struct e8390_pkt_hdr rx_frame; + + while (++rx_pkt_count < 10) + { + int pkt_len, pkt_stat; + + /* Get the rx page (incoming packet pointer). */ + rxing_page = inb_p(e8390_base + EN1_CURPAG -1); + + /* Remove one frame from the ring. Boundary is always a page behind. */ + this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1; + if (this_frame >= ei_local->stop_page) + this_frame = ei_local->rx_start_page; + + /* Someday we'll omit the previous, iff we never get this message. + (There is at least one clone claimed to have a problem.) + + Keep quiet if it looks like a card removal. One problem here + is that some clones crash in roughly the same way. + */ + if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF)) + printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n", + dev->name, this_frame, ei_local->current_page); + + if (this_frame == rxing_page) /* Read all the frames? */ + break; /* Done for now */ + + current_offset = this_frame << 8; + ei_get_8390_hdr(dev, &rx_frame, this_frame); + + pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr); + pkt_stat = rx_frame.status; + + next_frame = this_frame + 1 + ((pkt_len+4)>>8); + + if (pkt_len < 60 || pkt_len > 1518) + { + if (ei_debug) + printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", + dev->name, rx_frame.count, rx_frame.status, + rx_frame.next); + ei_local->stat.rx_errors++; + ei_local->stat.rx_length_errors++; + } + else if ((pkt_stat & 0x0F) == ENRSR_RXOK) + { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_len+2); + if (skb == NULL) + { + if (ei_debug > 1) + printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n", + dev->name, pkt_len); + ei_local->stat.rx_dropped++; + break; + } + else + { + skb_reserve(skb,2); /* IP headers on 16 byte boundaries */ + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + dev->last_rx = jiffies; + ei_local->stat.rx_packets++; + add_rx_bytes(&ei_local->stat, pkt_len); + if (pkt_stat & ENRSR_PHY) + ei_local->stat.multicast++; + } + } + else + { + if (ei_debug) + printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", + dev->name, rx_frame.status, rx_frame.next, + rx_frame.count); + ei_local->stat.rx_errors++; + /* NB: The NIC counts CRC, frame and missed errors. */ + if (pkt_stat & ENRSR_FO) + ei_local->stat.rx_fifo_errors++; + } + next_frame = rx_frame.next; + + /* This _should_ never happen: it's here for avoiding bad clones. */ + if (next_frame >= ei_local->stop_page) { + printk("%s: next frame inconsistency, %#2x\n", dev->name, + next_frame); + next_frame = ei_local->rx_start_page; + } + ei_local->current_page = next_frame; + outb_p(next_frame-1, e8390_base+EN0_BOUNDARY); + } + + return; +} + +/** + * ei_rx_overrun - handle receiver overrun + * @dev: network device which threw exception + * + * We have a receiver overrun: we have to kick the 8390 to get it started + * again. Problem is that you have to kick it exactly as NS prescribes in + * the updated datasheets, or "the NIC may act in an unpredictable manner." + * This includes causing "the NIC to defer indefinitely when it is stopped + * on a busy network." Ugh. + * Called with lock held. Don't call this with the interrupts off or your + * computer will hate you - it takes 10ms or so. + */ + +static void ei_rx_overrun(struct net_device *dev) +{ + axnet_dev_t *info = (axnet_dev_t *)dev; + long e8390_base = dev->base_addr; + unsigned char was_txing, must_resend = 0; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + + /* + * Record whether a Tx was in progress and then issue the + * stop command. + */ + was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); + + if (ei_debug > 1) + printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name); + ei_local->stat.rx_over_errors++; + + /* + * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. + * Early datasheets said to poll the reset bit, but now they say that + * it "is not a reliable indicator and subsequently should be ignored." + * We wait at least 10ms. + */ + + mdelay(10); + + /* + * Reset RBCR[01] back to zero as per magic incantation. + */ + outb_p(0x00, e8390_base+EN0_RCNTLO); + outb_p(0x00, e8390_base+EN0_RCNTHI); + + /* + * See if any Tx was interrupted or not. According to NS, this + * step is vital, and skipping it will cause no end of havoc. + */ + + if (was_txing) + { + unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR); + if (!tx_completed) + must_resend = 1; + } + + /* + * Have to enter loopback mode and then restart the NIC before + * you are allowed to slurp packets up off the ring. + */ + outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); + outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD); + + /* + * Clear the Rx ring of all the debris, and ack the interrupt. + */ + ei_receive(dev); + + /* + * Leave loopback mode, and resend any packet that got stopped. + */ + outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); + if (must_resend) + outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD); +} + +/* + * Collect the stats. This is called unlocked and from several contexts. + */ + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + unsigned long flags; + + /* If the card is stopped, just return the present stats. */ + if (!netif_running(dev)) + return &ei_local->stat; + + spin_lock_irqsave(&ei_local->page_lock,flags); + /* Read the counter registers, assuming we are in page 0. */ + ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); + ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); + ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); + spin_unlock_irqrestore(&ei_local->page_lock, flags); + + return &ei_local->stat; +} + +/** + * do_set_multicast_list - set/clear multicast filter + * @dev: net device for which multicast filter is adjusted + * + * Set or clear the multicast filter for this adaptor. May be called + * from a BH in 2.1.x. Must be called with lock held. + */ + +static void do_set_multicast_list(struct net_device *dev) +{ + long e8390_base = dev->base_addr; + + if(dev->flags&IFF_PROMISC) + outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); + else if(dev->flags&IFF_ALLMULTI || dev->mc_list) + outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); + else + outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); +} + +/* + * Called without lock held. This is invoked from user context and may + * be parallel to just about everything else. Its also fairly quick and + * not called too often. Must protect against both bh and irq users + */ + +static void set_multicast_list(struct net_device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); + do_set_multicast_list(dev); + spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); +} + +/** + * ethdev_init - init rest of 8390 device struct + * @dev: network device structure to init + * + * Initialize the rest of the 8390 device structure. Do NOT __init + * this, as it is used by 8390 based modular drivers too. + */ + +static int ethdev_init(struct net_device *dev) +{ + if (ei_debug > 1) + printk(version); + + if (dev->priv == NULL) + { + struct ei_device *ei_local; + + dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct ei_device)); + ei_local = (struct ei_device *)dev->priv; + spin_lock_init(&ei_local->page_lock); + } + + dev->hard_start_xmit = &ei_start_xmit; + dev->get_stats = get_stats; + dev->set_multicast_list = &set_multicast_list; + + ether_setup(dev); + + return 0; +} + + + +/* This page of functions should be 8390 generic */ +/* Follow National Semi's recommendations for initializing the "NIC". */ + +/** + * NS8390_init - initialize 8390 hardware + * @dev: network device to initialize + * @startp: boolean. non-zero value to initiate chip processing + * + * Must be called with lock held. + */ + +static void NS8390_init(struct net_device *dev, int startp) +{ + axnet_dev_t *info = (axnet_dev_t *)dev; + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + int i; + int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; + + if(sizeof(struct e8390_pkt_hdr)!=4) + panic("8390.c: header struct mispacked\n"); + /* Follow National Semi's recommendations for initing the DP83902. */ + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */ + outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */ + /* Clear the remote byte count registers. */ + outb_p(0x00, e8390_base + EN0_RCNTLO); + outb_p(0x00, e8390_base + EN0_RCNTHI); + /* Set to monitor and loopback mode -- this is vital!. */ + outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */ + outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */ + /* Set the transmit page and receive ring. */ + outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR); + ei_local->tx1 = ei_local->tx2 = 0; + outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG); + outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/ + ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */ + outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG); + /* Clear the pending interrupts and mask. */ + outb_p(0xFF, e8390_base + EN0_ISR); + outb_p(0x00, e8390_base + EN0_IMR); + + /* Copy the station address into the DS8390 registers. */ + + outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */ + for(i = 0; i < 6; i++) + { + outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i)); + if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i]) + printk(KERN_ERR "Hw. address read/write mismap %d\n",i); + } + /* + * Initialize the multicast list to accept-all. If we enable multicast + * the higher levels can do the filtering. + */ + for (i = 0; i < 8; i++) + outb_p(0xff, e8390_base + EN1_MULT + i); + + outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); + + netif_start_queue(dev); + ei_local->tx1 = ei_local->tx2 = 0; + ei_local->txing = 0; + + if (startp) + { + outb_p(0xff, e8390_base + EN0_ISR); + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD); + outb_p(E8390_TXCONFIG | info->duplex_flag, + e8390_base + EN0_TXCR); /* xmit on. */ + /* 3c503 TechMan says rxconfig only after the NIC is started. */ + outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ + do_set_multicast_list(dev); /* (re)load the mcast table */ + } +} + +/* Trigger a transmit start, assuming the length is valid. + Always called with the page lock held */ + +static void NS8390_trigger_send(struct net_device *dev, unsigned int length, + int start_page) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + + if (inb_p(e8390_base) & E8390_TRANS) + { + printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n", + dev->name); + return; + } + outb_p(length & 0xff, e8390_base + EN0_TCNTLO); + outb_p(length >> 8, e8390_base + EN0_TCNTHI); + outb_p(start_page, e8390_base + EN0_TPSR); + outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD); +} diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index c6fb2633b590..39ef2e14d192 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,3 +1,7 @@ +2001-11-12 Tim Waugh + + * parport_pc.c (init_module): Warn when parameters are ignored. + 2001-11-01 Damian Gruszka * parport_serial.c (serial_register): Set base_baud before diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 96120ba2218a..0c5c82a3bebd 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -3047,6 +3047,12 @@ int init_module(void) case PARPORT_IRQ_NONE: case PARPORT_IRQ_AUTO: irqval[0] = val; + break; + default: + printk (KERN_WARNING + "parport_pc: irq specified " + "without base address. Use 'io=' " + "to specify one\n"); } if (dma[0] && !parport_parse_dmas (1, dma, &val)) @@ -3054,6 +3060,12 @@ int init_module(void) case PARPORT_DMA_NONE: case PARPORT_DMA_AUTO: dmaval[0] = val; + break; + default: + printk (KERN_WARNING + "parport_pc: dma specified " + "without base address. Use 'io=' " + "to specify one\n"); } } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 015b5b0778ae..9aa9ab1616ca 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -684,22 +684,17 @@ run_sbin_hotplug(struct pci_dev *pdev, int insert) } /** - * pci_insert_device - insert a hotplug device - * @dev: the device to insert - * @bus: where to insert it + * pci_announce_device_to_drivers - tell the drivers a new device has appeared + * @dev: the device that has shown up * - * Add a new device to the device lists and notify userspace (/sbin/hotplug). + * Notifys the drivers that a new device has appeared, and also notifys + * userspace through /sbin/hotplug. */ void -pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) +pci_announce_device_to_drivers(struct pci_dev *dev) { struct list_head *ln; - list_add_tail(&dev->bus_list, &bus->devices); - list_add_tail(&dev->global_list, &pci_devices); -#ifdef CONFIG_PROC_FS - pci_proc_attach_device(dev); -#endif for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) { struct pci_driver *drv = list_entry(ln, struct pci_driver, node); if (drv->remove && pci_announce_device(drv, dev)) @@ -710,6 +705,24 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) run_sbin_hotplug(dev, TRUE); } +/** + * pci_insert_device - insert a hotplug device + * @dev: the device to insert + * @bus: where to insert it + * + * Add a new device to the device lists and notify userspace (/sbin/hotplug). + */ +void +pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) +{ + list_add_tail(&dev->bus_list, &bus->devices); + list_add_tail(&dev->global_list, &pci_devices); +#ifdef CONFIG_PROC_FS + pci_proc_attach_device(dev); +#endif + pci_announce_device_to_drivers(dev); +} + static void pci_free_resources(struct pci_dev *dev) { @@ -951,7 +964,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } } -void __init pci_read_bridge_bases(struct pci_bus *child) +void __devinit pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; @@ -1979,6 +1992,14 @@ EXPORT_SYMBOL(pci_find_parent_resource); EXPORT_SYMBOL(pci_setup_device); EXPORT_SYMBOL(pci_insert_device); EXPORT_SYMBOL(pci_remove_device); +EXPORT_SYMBOL(pci_announce_device_to_drivers); +EXPORT_SYMBOL(pci_add_new_bus); +EXPORT_SYMBOL(pci_do_scan_bus); +EXPORT_SYMBOL(pci_scan_slot); +EXPORT_SYMBOL(pci_proc_attach_device); +EXPORT_SYMBOL(pci_proc_detach_device); +EXPORT_SYMBOL(pci_proc_attach_bus); +EXPORT_SYMBOL(pci_proc_detach_bus); #endif EXPORT_SYMBOL(pci_set_power_state); diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 90d22f414f7b..f4c21c2ba25b 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -10,7 +10,7 @@ O_TARGET := pcmcia.o -export-objs := ds.o cs.o cb_enabler.o yenta.o pci_socket.o +export-objs := ds.o cs.o yenta.o pci_socket.o list-multi := pcmcia_core.o yenta_socket.o @@ -24,7 +24,7 @@ endif ifeq ($(CONFIG_PCMCIA),y) obj-y := cistpl.o rsrc_mgr.o bulkmem.o ds.o cs.o ifeq ($(CONFIG_CARDBUS),y) - obj-y += cardbus.o cb_enabler.o yenta.o pci_socket.o + obj-y += cardbus.o yenta.o pci_socket.o endif ifeq ($(CONFIG_I82365),y) obj-y += i82365.o @@ -54,7 +54,7 @@ else obj-m += hd64465_ss.o endif ifeq ($(CONFIG_CARDBUS),y) - obj-m += yenta_socket.o cb_enabler.o + obj-m += yenta_socket.o endif endif endif diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index c016aa449f06..875160beb31c 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -66,7 +66,6 @@ #include #include #include "cs_internal.h" -#include "rsrc_mgr.h" #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; diff --git a/drivers/pcmcia/cb_enabler.c b/drivers/pcmcia/cb_enabler.c deleted file mode 100644 index ca074012e8cc..000000000000 --- a/drivers/pcmcia/cb_enabler.c +++ /dev/null @@ -1,403 +0,0 @@ -/*====================================================================== - - CardBus device enabler - - cb_enabler.c 1.31 2000/06/12 21:29:36 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - - The general idea: - - A client driver registers using register_driver(). This module - then creates a Card Services pseudo-client and registers it, and - configures the socket if this is the first client. It then - invokes the appropriate PCI client routines in response to Card - Services events. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"cb_enabler.c 1.31 2000/06/12 21:29:36 (David Hinds)"; -#else -#define DEBUG(n, args...) do { } while (0) -#endif - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("CardBus stub enabler module"); -MODULE_LICENSE("Dual MPL/GPL"); - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/*====================================================================*/ - -typedef struct driver_info_t { - dev_link_t *(*attach)(void); - dev_info_t dev_info; - driver_operations *ops; - dev_link_t *dev_list; -} driver_info_t; - -static dev_link_t *cb_attach(int n); -#define MK_ENTRY(fn, n) \ -static dev_link_t *fn(void) { return cb_attach(n); } - -#define MAX_DRIVER 4 - -MK_ENTRY(attach_0, 0); -MK_ENTRY(attach_1, 1); -MK_ENTRY(attach_2, 2); -MK_ENTRY(attach_3, 3); - -static driver_info_t driver[4] = { - { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 } -}; - -typedef struct bus_info_t { - u_char bus; - int flags, ncfg, nuse; - dev_link_t *owner; -} bus_info_t; - -#define DID_REQUEST 1 -#define DID_CONFIG 2 - -static void cb_release(u_long arg); -static int cb_event(event_t event, int priority, - event_callback_args_t *args); - -static void cb_detach(dev_link_t *); - -static bus_info_t bus_table[MAX_DRIVER]; - -/*====================================================================*/ - -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - pcmcia_report_error(handle, &err); -} - -/*====================================================================*/ - -struct dev_link_t *cb_attach(int n) -{ - client_reg_t client_reg; - dev_link_t *link; - int ret; - - DEBUG(0, "cb_attach(%d)\n", n); - - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) return NULL; - - MOD_INC_USE_COUNT; - memset(link, 0, sizeof(struct dev_link_t)); - link->conf.IntType = INT_CARDBUS; - link->conf.Vcc = 33; - - /* Insert into instance chain for this driver */ - link->priv = &driver[n]; - link->next = driver[n].dev_list; - driver[n].dev_list = link; - - /* Register with Card Services */ - client_reg.dev_info = &driver[n].dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.event_handler = &cb_event; - client_reg.EventMask = CS_EVENT_RESET_PHYSICAL | - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = pcmcia_register_client(&link->handle, &client_reg); - if (ret != 0) { - cs_error(link->handle, RegisterClient, ret); - cb_detach(link); - return NULL; - } - return link; -} - -/*====================================================================*/ - -static void cb_detach(dev_link_t *link) -{ - driver_info_t *dev = link->priv; - dev_link_t **linkp; - bus_info_t *b = (void *)link->win; - - DEBUG(0, "cb_detach(0x%p)\n", link); - - /* Locate device structure */ - for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; - - if (link->state & DEV_CONFIG) - cb_release((u_long)link); - - /* Don't drop Card Services connection if we are the bus owner */ - if (b && (b->flags != 0) && (link == b->owner)) { - link->state |= DEV_STALE_LINK; - return; - } - - if (link->handle) - pcmcia_deregister_client(link->handle); - - *linkp = link->next; - kfree(link); - MOD_DEC_USE_COUNT; -} - -/*====================================================================*/ - -static void cb_config(dev_link_t *link) -{ - client_handle_t handle = link->handle; - driver_info_t *drv = link->priv; - dev_locator_t loc; - bus_info_t *b; - config_info_t config; - u_char bus, devfn; - int i; - - DEBUG(0, "cb_config(0x%p)\n", link); - link->state |= DEV_CONFIG; - - /* Get PCI bus info */ - pcmcia_get_configuration_info(handle, &config); - bus = config.Option; devfn = config.Function; - - /* Is this a new bus? */ - for (i = 0; i < MAX_DRIVER; i++) - if (bus == bus_table[i].bus) break; - if (i == MAX_DRIVER) { - for (i = 0; i < MAX_DRIVER; i++) - if (bus_table[i].bus == 0) break; - b = &bus_table[i]; link->win = (void *)b; - b->bus = bus; - b->flags = 0; - b->ncfg = b->nuse = 1; - - /* Special hook: CS know what to do... */ - i = pcmcia_request_io(handle, NULL); - if (i != CS_SUCCESS) { - cs_error(handle, RequestIO, i); - return; - } - b->flags |= DID_REQUEST; - b->owner = link; - i = pcmcia_request_configuration(handle, &link->conf); - if (i != CS_SUCCESS) { - cs_error(handle, RequestConfiguration, i); - return; - } - b->flags |= DID_CONFIG; - } else { - b = &bus_table[i]; link->win = (void *)b; - if (b->flags & DID_CONFIG) { - b->ncfg++; b->nuse++; - } - } - loc.bus = LOC_PCI; - loc.b.pci.bus = bus; - loc.b.pci.devfn = devfn; - link->dev = drv->ops->attach(&loc); - - link->state &= ~DEV_CONFIG_PENDING; -} - -/*====================================================================*/ - -static void cb_release(u_long arg) -{ - dev_link_t *link = (dev_link_t *)arg; - driver_info_t *drv = link->priv; - bus_info_t *b = (void *)link->win; - - DEBUG(0, "cb_release(0x%p)\n", link); - - if (link->dev != NULL) { - drv->ops->detach(link->dev); - link->dev = NULL; - } - if (link->state & DEV_CONFIG) { - /* If we're suspended, config was already released */ - if (link->state & DEV_SUSPEND) - b->flags &= ~DID_CONFIG; - else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) { - pcmcia_release_configuration(b->owner->handle); - b->flags &= ~DID_CONFIG; - } - if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) { - pcmcia_release_io(b->owner->handle, NULL); - b->flags &= ~DID_REQUEST; - } - if (b->flags == 0) { - if (b->owner && (b->owner->state & DEV_STALE_LINK)) - cb_detach(b->owner); - b->bus = 0; b->owner = NULL; - } - } - link->state &= ~DEV_CONFIG; -} - -/*====================================================================*/ - -static int cb_event(event_t event, int priority, - event_callback_args_t *args) -{ - dev_link_t *link = args->client_data; - driver_info_t *drv = link->priv; - bus_info_t *b = (void *)link->win; - - DEBUG(0, "cb_event(0x%06x)\n", event); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) - cb_release((u_long)link); - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - cb_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - if (link->state & DEV_CONFIG) { - if (drv->ops->suspend != NULL) - drv->ops->suspend(link->dev); - b->ncfg--; - if (b->ncfg == 0) - pcmcia_release_configuration(link->handle); - } - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (link->state & DEV_CONFIG) { - b->ncfg++; - if (b->ncfg == 1) - pcmcia_request_configuration(link->handle, - &link->conf); - if (drv->ops->resume != NULL) - drv->ops->resume(link->dev); - } - break; - } - return 0; -} - -/*====================================================================*/ - -int register_driver(struct driver_operations *ops) -{ - int i; - - DEBUG(0, "register_driver('%s')\n", ops->name); - - for (i = 0; i < MAX_DRIVER; i++) - if (driver[i].ops == NULL) break; - if (i == MAX_DRIVER) - return -1; - - MOD_INC_USE_COUNT; - driver[i].ops = ops; - strcpy(driver[i].dev_info, ops->name); - register_pccard_driver(&driver[i].dev_info, driver[i].attach, - &cb_detach); - return 0; -} - -void unregister_driver(struct driver_operations *ops) -{ - int i; - - DEBUG(0, "unregister_driver('%s')\n", ops->name); - for (i = 0; i < MAX_DRIVER; i++) - if (driver[i].ops == ops) break; - if (i < MAX_DRIVER) { - unregister_pccard_driver(&driver[i].dev_info); - driver[i].ops = NULL; - MOD_DEC_USE_COUNT; - } -} - -/*====================================================================*/ - -EXPORT_SYMBOL(register_driver); -EXPORT_SYMBOL(unregister_driver); - -static int __init init_cb_enabler(void) -{ - servinfo_t serv; - DEBUG(0, "%s\n", version); - pcmcia_get_card_services_info(&serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "cb_enabler: Card Services release " - "does not match!\n"); - return -1; - } - return 0; -} - -static void __exit exit_cb_enabler(void) -{ - DEBUG(0, "cb_enabler: unloading\n"); -} - -module_init(init_cb_enabler); -module_exit(exit_cb_enabler); - -/*====================================================================*/ - diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 6d95e555b25f..2eb64a8f0c33 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -2,7 +2,7 @@ PCMCIA Card Information Structure parser - cistpl.c 1.91 2000/09/16 03:48:28 + cistpl.c 1.97 2001/10/04 03:33:49 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,6 @@ #include #include #include "cs_internal.h" -#include "rsrc_mgr.h" static const u_char mantissa[] = { 10, 12, 13, 15, 20, 25, 30, 35, @@ -644,8 +644,6 @@ static int parse_device(tuple_t *tuple, cistpl_device_t *device) case 4: device->dev[i].speed = 100; break; case 7: if (++p == q) return CS_BAD_TUPLE; - if (p == q) - return CS_BAD_TUPLE; device->dev[i].speed = SPEED_CVT(*p); while (*p & 0x80) if (++p == q) return CS_BAD_TUPLE; diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 3e1775c1021d..53927ece5ce0 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -60,14 +60,6 @@ #include #include #include "cs_internal.h" -#include "rsrc_mgr.h" - -#ifdef PCMCIA_DEBUG -int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -static const char *version = -"cs.c 1.271 2000/10/02 20:27:49 (David Hinds)"; -#endif #ifdef CONFIG_PCI #define PCI_OPT " [pci]" @@ -93,15 +85,15 @@ static const char *version = static const char *release = "Linux Kernel Card Services " CS_RELEASE; static const char *options = "options: " OPTIONS; +/*====================================================================*/ + +/* Module parameters */ + MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Linux Kernel Card Services " CS_RELEASE "\n options:" OPTIONS); MODULE_LICENSE("Dual MPL/GPL"); -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") INT_MODULE_PARM(setup_delay, 10); /* centiseconds */ @@ -126,6 +118,12 @@ INT_MODULE_PARM(do_apm, 1); INT_MODULE_PARM(do_apm, 0); #endif +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +static const char *version = +"cs.c 1.279 2001/10/13 00:08:28 (David Hinds)"; +#endif + /*====================================================================*/ socket_state_t dead_socket = { @@ -472,6 +470,15 @@ static void shutdown_socket(socket_info_t *s) kfree(s->fake_cis); s->fake_cis = NULL; } + /* Should not the socket be forced quiet as well? e.g. turn off Vcc */ + /* Without these changes, the socket is left hot, even though card-services */ + /* realizes that no card is in place. */ + s->socket.flags &= ~SS_OUTPUT_ENA; + s->socket.Vpp = 0; + s->socket.Vcc = 0; + s->socket.io_irq = 0; + set_socket(s, &s->socket); + /* */ #ifdef CONFIG_CARDBUS cb_release_cis_mem(s); cb_free(s); @@ -622,7 +629,7 @@ static void unreset_socket(socket_info_t *s) The central event handler. Send_event() sends an event to all valid clients. Parse_events() interprets the event bits from - a card status change report. Do_shotdown() handles the high + a card status change report. Do_shutdown() handles the high priority stuff associated with a card removal. ======================================================================*/ @@ -1508,7 +1515,7 @@ int pcmcia_release_configuration(client_handle_t handle) if (!(handle->state & CLIENT_STALE)) { config_t *c = CONFIG(handle); if (--(s->lock_count) == 0) { - s->socket.flags = SS_OUTPUT_ENA; + s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ s->socket.Vpp = 0; s->socket.io_irq = 0; set_socket(s, &s->socket); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index d3d89ddf7b5c..29ca88040ecf 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -2,7 +2,7 @@ PC Card Driver Services - ds.c 1.108 2000/08/07 19:06:15 + ds.c 1.112 2001/10/13 00:08:28 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -56,21 +56,25 @@ #include #include +/*====================================================================*/ + +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") + #ifdef PCMCIA_DEBUG -int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static const char *version = -"ds.c 1.108 2000/08/07 19:06:15 (David Hinds)"; +"ds.c 1.112 2001/10/13 00:08:28 (David Hinds)"; #else #define DEBUG(n, args...) #endif -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); -MODULE_LICENSE("Dual MPL/GPL"); - - /*====================================================================*/ typedef struct driver_info_t { diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 3ac564e3b4ec..a066eab9cd2a 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -66,11 +66,6 @@ #include "ricoh.h" #include "o2micro.h" -/* PCI-bus controllers */ -#include "old-yenta.h" -#include "smc34c90.h" -#include "topic.h" - #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); diff --git a/drivers/pcmcia/old-yenta.h b/drivers/pcmcia/old-yenta.h deleted file mode 100644 index 8a2c3e1259ce..000000000000 --- a/drivers/pcmcia/old-yenta.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * yenta.h 1.16 1999/10/25 20:03:34 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#ifndef _LINUX_YENTA_H -#define _LINUX_YENTA_H - -/* PCI Configuration Registers */ - -#define PCI_STATUS_CAPLIST 0x10 -#define PCI_CB_CAPABILITY_POINTER 0x14 /* 8 bit */ -#define PCI_CAPABILITY_ID 0x00 /* 8 bit */ -#define PCI_CAPABILITY_PM 0x01 -#define PCI_NEXT_CAPABILITY 0x01 /* 8 bit */ -#define PCI_PM_CAPABILITIES 0x02 /* 16 bit */ -#define PCI_PMCAP_PME_D3COLD 0x8000 -#define PCI_PMCAP_PME_D3HOT 0x4000 -#define PCI_PMCAP_PME_D2 0x2000 -#define PCI_PMCAP_PME_D1 0x1000 -#define PCI_PMCAP_PME_D0 0x0800 -#define PCI_PMCAP_D2_CAP 0x0400 -#define PCI_PMCAP_D1_CAP 0x0200 -#define PCI_PMCAP_DYN_DATA 0x0100 -#define PCI_PMCAP_DSI 0x0020 -#define PCI_PMCAP_AUX_PWR 0x0010 -#define PCI_PMCAP_PMECLK 0x0008 -#define PCI_PMCAP_VERSION_MASK 0x0007 -#define PCI_PM_CONTROL_STATUS 0x04 /* 16 bit */ -#define PCI_PMCS_PME_STATUS 0x8000 -#define PCI_PMCS_DATASCALE_MASK 0x6000 -#define PCI_PMCS_DATASCALE_SHIFT 13 -#define PCI_PMCS_DATASEL_MASK 0x1e00 -#define PCI_PMCS_DATASEL_SHIFT 9 -#define PCI_PMCS_PME_ENABLE 0x0100 -#define PCI_PMCS_PWR_STATE_MASK 0x0003 -#define PCI_PMCS_PWR_STATE_D0 0x0000 -#define PCI_PMCS_PWR_STATE_D1 0x0001 -#define PCI_PMCS_PWR_STATE_D2 0x0002 -#define PCI_PMCS_PWR_STATE_D3 0x0003 -#define PCI_PM_BRIDGE_EXT 0x06 /* 8 bit */ -#define PCI_PM_DATA 0x07 /* 8 bit */ - -#define CB_PRIMARY_BUS 0x18 /* 8 bit */ -#define CB_CARDBUS_BUS 0x19 /* 8 bit */ -#define CB_SUBORD_BUS 0x1a /* 8 bit */ -#define CB_LATENCY_TIMER 0x1b /* 8 bit */ - -#define CB_MEM_BASE(m) (0x1c + 8*(m)) -#define CB_MEM_LIMIT(m) (0x20 + 8*(m)) -#define CB_IO_BASE(m) (0x2c + 8*(m)) -#define CB_IO_LIMIT(m) (0x30 + 8*(m)) - -#define CB_BRIDGE_CONTROL 0x3e /* 16 bit */ -#define CB_BCR_PARITY_ENA 0x0001 -#define CB_BCR_SERR_ENA 0x0002 -#define CB_BCR_ISA_ENA 0x0004 -#define CB_BCR_VGA_ENA 0x0008 -#define CB_BCR_MABORT 0x0020 -#define CB_BCR_CB_RESET 0x0040 -#define CB_BCR_ISA_IRQ 0x0080 -#define CB_BCR_PREFETCH(m) (0x0100 << (m)) -#define CB_BCR_WRITE_POST 0x0400 - -#define CB_LEGACY_MODE_BASE 0x44 - -/* Memory mapped registers */ - -#define CB_SOCKET_EVENT 0x0000 -#define CB_SE_CSTSCHG 0x00000001 -#define CB_SE_CCD1 0x00000002 -#define CB_SE_CCD2 0x00000004 -#define CB_SE_PWRCYCLE 0x00000008 - -#define CB_SOCKET_MASK 0x0004 -#define CB_SM_CSTSCHG 0x00000001 -#define CB_SM_CCD 0x00000006 -#define CB_SM_PWRCYCLE 0x00000008 - -#define CB_SOCKET_STATE 0x0008 -#define CB_SS_CSTSCHG 0x00000001 -#define CB_SS_CCD1 0x00000002 -#define CB_SS_CCD2 0x00000004 -#define CB_SS_PWRCYCLE 0x00000008 -#define CB_SS_16BIT 0x00000010 -#define CB_SS_32BIT 0x00000020 -#define CB_SS_CINT 0x00000040 -#define CB_SS_BADCARD 0x00000080 -#define CB_SS_DATALOST 0x00000100 -#define CB_SS_BADVCC 0x00000200 -#define CB_SS_5VCARD 0x00000400 -#define CB_SS_3VCARD 0x00000800 -#define CB_SS_XVCARD 0x00001000 -#define CB_SS_YVCARD 0x00002000 -#define CB_SS_5VSOCKET 0x10000000 -#define CB_SS_3VSOCKET 0x20000000 -#define CB_SS_XVSOCKET 0x40000000 -#define CB_SS_YVSOCKET 0x80000000 - -#define CB_SOCKET_FORCE 0x000c -#define CB_SF_CVSTEST 0x00004000 - -#define CB_SOCKET_CONTROL 0x0010 -#define CB_SC_VPP_MASK 0x00000007 -#define CB_SC_VPP_OFF 0x00000000 -#define CB_SC_VPP_12V 0x00000001 -#define CB_SC_VPP_5V 0x00000002 -#define CB_SC_VPP_3V 0x00000003 -#define CB_SC_VPP_XV 0x00000004 -#define CB_SC_VPP_YV 0x00000005 -#define CB_SC_VCC_MASK 0x00000070 -#define CB_SC_VCC_OFF 0x00000000 -#define CB_SC_VCC_5V 0x00000020 -#define CB_SC_VCC_3V 0x00000030 -#define CB_SC_VCC_XV 0x00000040 -#define CB_SC_VCC_YV 0x00000050 -#define CB_SC_CCLK_STOP 0x00000080 - -#define CB_SOCKET_POWER 0x0020 -#define CB_SP_CLK_CTRL 0x00000001 -#define CB_SP_CLK_CTRL_ENA 0x00010000 -#define CB_SP_CLK_MODE 0x01000000 -#define CB_SP_ACCESS 0x02000000 - -/* Address bits 31..24 for memory windows for 16-bit cards, - accessable only by memory mapping the 16-bit register set */ -#define CB_MEM_PAGE(map) (0x40 + (map)) - -#endif /* _LINUX_YENTA_H */ diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 532b1e04c580..5cfd31aac8b4 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -53,7 +53,6 @@ #include #include #include "cs_internal.h" -#include "rsrc_mgr.h" /*====================================================================*/ diff --git a/drivers/pcmcia/rsrc_mgr.h b/drivers/pcmcia/rsrc_mgr.h deleted file mode 100644 index 0f9c1d95ca2d..000000000000 --- a/drivers/pcmcia/rsrc_mgr.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * rsrc_mgr.h 1.20 2000/06/12 21:29:37 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#ifndef _RSRC_MGR_H -#define _RSRC_MGR_H - -#endif /* _RSRC_MGR_H */ diff --git a/drivers/pcmcia/smc34c90.h b/drivers/pcmcia/smc34c90.h deleted file mode 100644 index 0c4f063d6780..000000000000 --- a/drivers/pcmcia/smc34c90.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * smc34c90.h 1.7 1999/10/25 20:03:34 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use - * your version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#ifndef _LINUX_SMC34C90_H -#define _LINUX_SMC34C90_H - -#ifndef PCI_VENDOR_ID_SMC -#define PCI_VENDOR_ID_SMC 0x10b3 -#endif - -#ifndef PCI_DEVICE_ID_SMC_34C90 -#define PCI_DEVICE_ID_SMC_34C90 0xb106 -#endif - -/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */ - -/* EEPROM Information Register */ -#define SMC34C90_EEINFO 0x0088 -#define SMC34C90_EEINFO_ONE_SOCKET 0x0001 -#define SMC34C90_EEINFO_5V_ONLY 0x0002 -#define SMC34C90_EEINFO_ISA_IRQ 0x0004 -#define SMC34C90_EEINFO_ZV_PORT 0x0008 -#define SMC34C90_EEINFO_RING 0x0010 -#define SMC34C90_EEINFO_LED 0x0020 - -#endif /* _LINUX_SMC34C90_H */ diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c index 14956faee5db..17efd648290d 100644 --- a/drivers/pnp/isapnp.c +++ b/drivers/pnp/isapnp.c @@ -25,6 +25,9 @@ * 2001-06-03 Added release_region calls to correspond with * request_region calls when a failure occurs. Also * added KERN_* constants to printk() calls. + * 2001-11-07 Added isapnp_{,un}register_driver calls along the lines + * of the pci driver interface + * Kai Germaschewski */ #include @@ -2162,6 +2165,89 @@ static void isapnp_free_all_resources(void) #endif } +static int isapnp_announce_device(struct isapnp_driver *drv, + struct pci_dev *dev) +{ + const struct isapnp_device_id *id; + int ret = 0; + + if (drv->id_table) { + id = isapnp_match_dev(drv->id_table, dev); + if (!id) { + ret = 0; + goto out; + } + } else + id = NULL; + + if (drv->probe(dev, id) >= 0) { + dev->driver = (struct pci_driver *) drv; + ret = 1; + } +out: + return ret; +} + +/** + * isapnp_dev_driver - get the isapnp_driver of a device + * @dev: the device to query + * + * Returns the appropriate isapnp_driver structure or %NULL if there is no + * registered driver for the device. + */ +static struct isapnp_driver *isapnp_dev_driver(const struct pci_dev *dev) +{ + return (struct isapnp_driver *) dev->driver; +} + +static LIST_HEAD(isapnp_drivers); + +/** + * isapnp_register_driver - register a new ISAPnP driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered ISAPnP drivers + * Returns the number of isapnp devices which were claimed by the driver + * during registration. The driver remains registered even if the + * return value is zero. + */ +int isapnp_register_driver(struct isapnp_driver *drv) +{ + struct pci_dev *dev; + int count = 0; + + list_add_tail(&drv->node, &isapnp_drivers); + + isapnp_for_each_dev(dev) { + if (!isapnp_dev_driver(dev)) + count += isapnp_announce_device(drv, dev); + } + return count; +} + +/** + * isapnp_unregister_driver - unregister an isapnp driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered ISAPnP drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ +void isapnp_unregister_driver(struct isapnp_driver *drv) +{ + struct pci_dev *dev; + + list_del(&drv->node); + isapnp_for_each_dev(dev) { + if (dev->driver == (struct pci_driver *) drv) { + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } + } +} + EXPORT_SYMBOL(isapnp_cards); EXPORT_SYMBOL(isapnp_devices); EXPORT_SYMBOL(isapnp_present); @@ -2183,6 +2269,8 @@ EXPORT_SYMBOL(isapnp_probe_cards); EXPORT_SYMBOL(isapnp_probe_devs); EXPORT_SYMBOL(isapnp_activate_dev); EXPORT_SYMBOL(isapnp_resource_change); +EXPORT_SYMBOL(isapnp_register_driver); +EXPORT_SYMBOL(isapnp_unregister_driver); int __init isapnp_init(void) { diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index b467e1e8c9b2..093058e7d30c 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -1019,4 +1019,31 @@ unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate) } EXPORT_SYMBOL(ac97_set_adc_rate); + +int ac97_save_state(struct ac97_codec *codec) +{ + return 0; +} + +EXPORT_SYMBOL(ac97_save_state); + +int ac97_restore_state(struct ac97_codec *codec) +{ + int i; + unsigned int left, right, val; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!supported_mixer(codec, i)) + continue; + + val = codec->mixer_state[i]; + right = val >> 8; + left = val & 0xff; + codec->write_mixer(codec, i, left, right); + } + return 0; +} + +EXPORT_SYMBOL(ac97_restore_state); + MODULE_LICENSE("GPL"); diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c index 5849b807501f..b6d857b23cd6 100644 --- a/drivers/sound/ymfpci.c +++ b/drivers/sound/ymfpci.c @@ -1824,7 +1824,7 @@ static int ymf_open(struct inode *inode, struct file *file) } unit = NULL; /* gcc warns */ - for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { + list_for_each(list, &ymf_devs) { unit = list_entry(list, ymfpci_t, ymf_devs); if (((unit->dev_audio ^ minor) & ~0x0F) == 0) break; @@ -1935,7 +1935,7 @@ static int ymf_open_mixdev(struct inode *inode, struct file *file) struct list_head *list; ymfpci_t *unit; - for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { + list_for_each(list, &ymf_devs) { unit = list_entry(list, ymfpci_t, ymf_devs); for (i = 0; i < NR_AC97; i++) { if (unit->ac97_codec[i] != NULL && @@ -1990,16 +1990,25 @@ static /*const*/ struct file_operations ymf_mixer_fops = { static int ymf_suspend(struct pci_dev *pcidev, u32 unused) { + int i; struct ymf_unit *unit = pci_get_drvdata(pcidev); unsigned long flags; struct ymf_dmabuf *dmabuf; struct list_head *p; struct ymf_state *state; + struct ac97_codec *codec; spin_lock_irqsave(&unit->reg_lock, flags); unit->suspended = 1; + for (i = 0; i < NR_AC97; i++) { + codec = unit->ac97_codec[i]; + if (!codec) + continue; + ac97_save_state(codec); + } + list_for_each(p, &unit->states) { state = list_entry(p, struct ymf_state, chain); @@ -2024,14 +2033,23 @@ static int ymf_suspend(struct pci_dev *pcidev, u32 unused) static int ymf_resume(struct pci_dev *pcidev) { + int i; struct ymf_unit *unit = pci_get_drvdata(pcidev); unsigned long flags; struct list_head *p; struct ymf_state *state; + struct ac97_codec *codec; ymfpci_aclink_reset(unit->pci); ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */ + for (i = 0; i < NR_AC97; i++) { + codec = unit->ac97_codec[i]; + if (!codec) + continue; + ac97_restore_state(codec); + } + #ifdef CONFIG_SOUND_YMFPCI_LEGACY /* XXX At this time the legacy registers are probably deprogrammed. */ #endif diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index 911c8cbe2447..0e52bf2ea3fc 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -356,7 +356,7 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; - atomic_set(&hub->refcnt, 1); + init_MUTEX(&hub->khubd_sem); /* Record the new hub's existence */ spin_lock_irqsave(&hub_event_lock, flags); @@ -385,34 +385,11 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, return NULL; } -static void hub_get(struct usb_hub *hub) -{ - atomic_inc(&hub->refcnt); -} - -static void hub_put(struct usb_hub *hub) -{ - if (atomic_dec_and_test(&hub->refcnt)) { - if (hub->descriptor) { - kfree(hub->descriptor); - hub->descriptor = NULL; - } - - kfree(hub); - } -} - static void hub_disconnect(struct usb_device *dev, void *ptr) { struct usb_hub *hub = (struct usb_hub *)ptr; unsigned long flags; - if (hub->urb) { - usb_unlink_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } - spin_lock_irqsave(&hub_event_lock, flags); /* Delete it and then reset it */ @@ -423,7 +400,22 @@ static void hub_disconnect(struct usb_device *dev, void *ptr) spin_unlock_irqrestore(&hub_event_lock, flags); - hub_put(hub); + down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ + up(&hub->khubd_sem); + + if (hub->urb) { + usb_unlink_urb(hub->urb); + usb_free_urb(hub->urb); + hub->urb = NULL; + } + + if (hub->descriptor) { + kfree(hub->descriptor); + hub->descriptor = NULL; + } + + /* Free the memory */ + kfree(hub); } static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) @@ -534,10 +526,6 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port, dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus, portchange, portspeed (portstatus)); - /* Device went away? */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return 1; - /* bomb out completely if something weird happened */ if ((portchange & USB_PORT_STAT_C_CONNECTION)) return -1; @@ -745,7 +733,7 @@ static void usb_hub_events(void) list_del(tmp); INIT_LIST_HEAD(tmp); - hub_get(hub); + down(&hub->khubd_sem); /* never blocks, we were on list */ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -753,8 +741,8 @@ static void usb_hub_events(void) if (usb_hub_reset(hub)) { err("error resetting hub %d - disconnecting", dev->devnum); + up(&hub->khubd_sem); usb_hub_disconnect(dev); - hub_put(hub); continue; } @@ -830,7 +818,7 @@ static void usb_hub_events(void) usb_hub_power_on(hub); } } - hub_put(hub); + up(&hub->khubd_sem); } /* end while (1) */ spin_unlock_irqrestore(&hub_event_lock, flags); diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h index b76ae6f010ae..50ae148c5156 100644 --- a/drivers/usb/hub.h +++ b/drivers/usb/hub.h @@ -135,7 +135,7 @@ struct usb_hub { struct usb_hub_descriptor *descriptor; - atomic_t refcnt; + struct semaphore khubd_sem; }; -#endif +#endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d62521c764f1..d8d767f24407 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -12,9 +12,18 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info + * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (04/Nov/2001) Bill Ryder + * Fixed bug in read_bulk_callback where incorrect urb buffer was used. + * cleaned up write offset calculation + * added write_room since default values can be incorrect for sio + * changed write_bulk_callback to use same queue_task as other drivers + * (the previous version caused panics) + * Removed port iteration code since the device only has one I/O port and it + * was wrong anyway. + * * (31/May/2001) gkh * switched from using spinlock to a semaphore, which fixes lots of problems. * @@ -97,7 +106,6 @@ #include #include #include - #ifdef CONFIG_USB_SERIAL_DEBUG static int debug = 1; #else @@ -111,7 +119,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.1.0" +#define DRIVER_VERSION "v1.2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder " #define DRIVER_DESC "USB FTDI RS232 Converters Driver" @@ -146,6 +154,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); struct ftdi_private { ftdi_type_t ftdi_type; __u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */ + int write_offset; }; /* function prototypes for a FTDI serial converter */ static int ftdi_sio_startup (struct usb_serial *serial); @@ -154,6 +163,7 @@ static void ftdi_sio_shutdown (struct usb_serial *serial); static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp); static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp); static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int ftdi_sio_write_room (struct usb_serial_port *port); static void ftdi_sio_write_bulk_callback (struct urb *urb); static void ftdi_sio_read_bulk_callback (struct urb *urb); static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old); @@ -176,6 +186,7 @@ struct usb_serial_device_type ftdi_sio_device = { open: ftdi_sio_open, close: ftdi_sio_close, write: ftdi_sio_write, + write_room: ftdi_sio_write_room, read_bulk_callback: ftdi_sio_read_bulk_callback, write_bulk_callback: ftdi_sio_write_bulk_callback, ioctl: ftdi_sio_ioctl, @@ -198,6 +209,7 @@ struct usb_serial_device_type ftdi_8U232AM_device = { open: ftdi_sio_open, close: ftdi_sio_close, write: ftdi_sio_write, + write_room: ftdi_sio_write_room, read_bulk_callback: ftdi_sio_read_bulk_callback, write_bulk_callback: ftdi_sio_write_bulk_callback, ioctl: ftdi_sio_ioctl, @@ -252,7 +264,6 @@ static int ftdi_sio_startup (struct usb_serial *serial) { struct ftdi_private *priv; - init_waitqueue_head(&serial->port[0].write_wait); priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ @@ -261,6 +272,7 @@ static int ftdi_sio_startup (struct usb_serial *serial) } priv->ftdi_type = sio; + priv->write_offset = 1; return (0); } @@ -270,7 +282,6 @@ static int ftdi_8U232AM_startup (struct usb_serial *serial) { struct ftdi_private *priv; - init_waitqueue_head(&serial->port[0].write_wait); priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ @@ -279,6 +290,7 @@ static int ftdi_8U232AM_startup (struct usb_serial *serial) } priv->ftdi_type = F8U232AM; + priv->write_offset = 0; return (0); } @@ -288,13 +300,14 @@ static void ftdi_sio_shutdown (struct usb_serial *serial) dbg (__FUNCTION__); - /* Close ports if they are open */ + + /* stop reads and writes on all ports */ while (serial->port[0].open_count > 0) { - ftdi_sio_close (&serial->port[0], NULL); + ftdi_sio_close (&serial->port[0], NULL); } - if (serial->port->private){ - kfree(serial->port->private); - serial->port->private = NULL; + if (serial->port[0].private){ + kfree(serial->port[0].private); + serial->port[0].private = NULL; } } @@ -361,7 +374,7 @@ static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp) static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp) { /* ftdi_sio_close */ - struct usb_serial *serial = port->serial; + struct usb_serial *serial = port->serial; /* Checked in usbserial.c */ unsigned int c_cflag = port->tty->termios->c_cflag; char buf[1]; @@ -393,6 +406,7 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp) } /* Note change no line is hupcl is off */ /* shutdown our bulk reads and writes */ + /* ***CHECK*** behaviour when there is nothing queued */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); } @@ -403,7 +417,6 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp) if (!(port->tty->termios->c_cflag & CLOCAL)){ tty_hangup(port->tty); } - } up (&port->sem); @@ -423,10 +436,10 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, { /* ftdi_sio_write */ struct usb_serial *serial = port->serial; struct ftdi_private *priv = (struct ftdi_private *)port->private; + unsigned char *first_byte = port->write_urb->transfer_buffer; + unsigned char dbug_byte; int data_offset ; - int rc; int result; - DECLARE_WAITQUEUE(wait, current); dbg(__FUNCTION__ " port %d, %d bytes", port->number, count); @@ -435,95 +448,70 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, return 0; } - if (priv->ftdi_type == sio){ - data_offset = 1; - } else { - data_offset = 0; - } + data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); - /* only do something if we have a bulk out endpoint */ - if (serial->num_bulk_out) { - unsigned char *first_byte = port->write_urb->transfer_buffer; - - /* Was seeing a race here, got a read callback, then write callback before - hitting interuptible_sleep_on - so wrapping in a wait_queue */ - - add_wait_queue(&port->write_wait, &wait); - set_current_state (TASK_INTERRUPTIBLE); - while (port->write_urb->status == -EINPROGRESS) { - dbg(__FUNCTION__ " write in progress - retrying"); - if (signal_pending(current)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->write_wait, &wait); - rc = -ERESTARTSYS; - goto err; - } - schedule(); - } - remove_wait_queue(&port->write_wait, &wait); - set_current_state(TASK_RUNNING); + if (port->write_urb->status == -EINPROGRESS) { + dbg (__FUNCTION__ " - already writing"); + return (0); + } - count += data_offset; - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - if (count == 0) { - return 0; - } + down(&port->sem); + + count += data_offset; + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; /* Copy in the data to send */ - if (from_user) { - if (copy_from_user(port->write_urb->transfer_buffer + data_offset, - buf, count - data_offset )) - return -EFAULT; - } - else { - memcpy(port->write_urb->transfer_buffer + data_offset, - buf, count - data_offset ); - } - - first_byte = port->write_urb->transfer_buffer; - if (data_offset > 0){ - /* Write the control byte at the front of the packet*/ - *first_byte = 1 | ((count-data_offset) << 2) ; + if (from_user) { + if (copy_from_user(port->write_urb->transfer_buffer + data_offset, + buf, count - data_offset )){ + up (&port->sem); + return -EFAULT; } + } else { + memcpy(port->write_urb->transfer_buffer + data_offset, + buf, count - data_offset ); + } + + first_byte = port->write_urb->transfer_buffer; + if (data_offset > 0){ + /* Write the control byte at the front of the packet*/ + *first_byte = 1 | ((count-data_offset) << 2) ; + } - dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, first_byte[0]); - usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); + dbg(__FUNCTION__ " Bytes: %d, First Byte: 0x%02x",count, first_byte[0]); + usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); - /* send the data out the bulk port */ - FILL_BULK_URB(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ftdi_sio_write_bulk_callback, port); + /* send the data out the bulk port */ + FILL_BULK_URB(port->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + ftdi_sio_write_bulk_callback, port); - result = usb_submit_urb(port->write_urb); - if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); - return 0; - } - - dbg(__FUNCTION__ " write returning: %d", count - data_offset); - return (count - data_offset); + result = usb_submit_urb(port->write_urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + up (&port->sem); + return 0; } - - /* no bulk out, so return 0 bytes written */ - return 0; - err: /* error exit */ - return(rc); + up (&port->sem); + + dbg(__FUNCTION__ " write returning: %d", count - data_offset); + return (count - data_offset); + } /* ftdi_sio_write */ static void ftdi_sio_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - struct tty_struct *tty = port->tty; dbg("ftdi_sio_write_bulk_callback"); if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) { return; } - + serial = port->serial; if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) { return; @@ -533,16 +521,29 @@ static void ftdi_sio_write_bulk_callback (struct urb *urb) dbg("nonzero write bulk status received: %d", urb->status); return; } + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); - wake_up_interruptible(&port->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); - return; } /* ftdi_sio_write_bulk_callback */ + +static int ftdi_sio_write_room( struct usb_serial_port *port ) +{ + struct ftdi_private *priv = (struct ftdi_private *)port->private; + int room; + if ( port->write_urb->status == -EINPROGRESS) { + /* There is a race here with the _write routines but it won't hurt */ + room = 0; + } else { + room = port->bulk_out_size - priv->write_offset; + } + return(room); + + +} /* ftdi_sio_write_room */ + + static void ftdi_sio_read_bulk_callback (struct urb *urb) { /* ftdi_sio_serial_buld_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -555,7 +556,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) int i; int result; - dbg(__FUNCTION__); + dbg(__FUNCTION__ " - port %d", port->number); if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) { return; @@ -647,12 +648,12 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) #endif /* Continue trying to always read */ - FILL_BULK_URB(urb, serial->dev, + FILL_BULK_URB(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - urb->transfer_buffer, urb->transfer_buffer_length, + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_sio_read_bulk_callback, port); - result = usb_submit_urb(urb); + result = usb_submit_urb(port->read_urb); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 611a3022e273..4443e9624865 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -17,9 +17,13 @@ * Portions of this driver were taken from drivers/net/irda/irda-usb.c, which * was written by Roman Weissgaerber , Dag Brattli * , and Jean Tourrilhes - + * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * 2001_Nov_08 greg kh + * Changed the irda_usb_find_class_desc() function based on comments and + * code from Martin Diehl. + * * 2001_Nov_01 greg kh * Added support for more IrDA USB devices. * Added support for zero packet. Added buffer override paramater, so @@ -58,7 +62,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.2" +#define DRIVER_VERSION "v0.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB IR Dongle driver" @@ -128,12 +132,12 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) * The class descriptor is some extra info that IrDA USB devices will * offer to us, describing their IrDA characteristics. We will use that in * irda_usb_init_qos() + * + * Based on the same function in drivers/net/irda/irda-usb.c */ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) { - struct usb_interface_descriptor *interface; struct irda_class_desc *desc; - struct irda_class_desc *ptr; int ret; desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); @@ -141,28 +145,27 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, return NULL; memset(desc, 0, sizeof(struct irda_class_desc)); - ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); - dbg(__FUNCTION__ " - ret=%d", ret); - if (ret) - dbg(__FUNCTION__ " - usb_get_class_descriptor failed (0x%x)", ret); - - /* Check if we found it? */ - if (desc->bDescriptorType == USB_DT_IRDA) - goto exit; - - dbg(__FUNCTION__ " - parsing extra descriptors..."); + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + IU_REQ_GET_CLASS_DESC, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); - /* Check if the class descriptor is interleaved with standard descriptors */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); - if (ret) { - kfree(desc); - return NULL; + dbg(__FUNCTION__ " - ret=%d", ret); + if (ret < sizeof(*desc)) { + dbg(__FUNCTION__ " - class descriptor read %s (%d)", + (ret<0) ? "failed" : "too short", ret); + goto error; } - *desc = *ptr; -exit: + if (desc->bDescriptorType != USB_DT_IRDA) { + dbg(__FUNCTION__ " - bad class descriptor type"); + goto error; + } + irda_usb_dump_class_desc(desc); return desc; +error: + kfree(desc); + return NULL; } static int ir_startup (struct usb_serial *serial) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 51e73015e61b..a9fdf4a3a285 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -24,6 +24,9 @@ * Basic tests have been performed with minicom/zmodem transfers and * modem dialing under Linux 2.4.0-test10 (for me it works fine). * + * 10-Nov-2001 Wolfgang Grandegger + * - Fixed an endianess problem with the baudrate selection for PowerPC. + * * 30-May-2001 Greg Kroah-Hartman * switched from using spinlock to a semaphore, which fixes lots of problems. * @@ -263,7 +266,7 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, int value) { unsigned int divisor; int rc; - divisor = mct_u232_calculate_baud_rate(serial, value); + divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value)); rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_BAUD_RATE_REQUEST, MCT_U232_SET_REQUEST_TYPE, diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 8dc10bd95873..98bcc37b6740 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -12,6 +12,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (11/11/2001) gkh + * Added support for the m125 devices, and added check to prevent oopses + * for Clié devices that lie about the number of ports they have. + * * (08/30/2001) gkh * Added support for the Clie devices, both the 3.5 and 4.0 os versions. * Many thanks to Daniel Burke, and Bryan Payne for helping with this. @@ -123,9 +127,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4" +#define DRIVER_VERSION "v1.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman " -#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clie driver" +#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver" /* function prototypes for a handspring visor */ static int visor_open (struct usb_serial_port *port, struct file *filp); @@ -148,13 +152,10 @@ static __devinitdata struct usb_device_id visor_id_table [] = { { } /* Terminating entry */ }; -static __devinitdata struct usb_device_id palm_m500_id_table [] = { +static __devinitdata struct usb_device_id palm_4_0_id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id palm_m505_id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { } /* Terminating entry */ }; @@ -172,6 +173,7 @@ static __devinitdata struct usb_device_id id_table [] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, { } /* Terminating entry */ @@ -207,10 +209,10 @@ struct usb_serial_device_type handspring_device = { read_bulk_callback: visor_read_bulk_callback, }; -/* device info for the Palm M500 */ -struct usb_serial_device_type palm_m500_device = { - name: "Palm M500", - id_table: palm_m500_id_table, +/* device info for the Palm 4.0 devices */ +struct usb_serial_device_type palm_4_0_device = { + name: "Palm 4.0", + id_table: palm_4_0_id_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ @@ -233,35 +235,10 @@ struct usb_serial_device_type palm_m500_device = { read_bulk_callback: visor_read_bulk_callback, }; -/* device info for the Palm M505 */ -struct usb_serial_device_type palm_m505_device = { - name: "Palm M505", - id_table: palm_m505_id_table, - needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_interrupt_in: 0, - num_bulk_in: 2, - num_bulk_out: 2, - num_ports: 2, - open: visor_open, - close: visor_close, - throttle: visor_throttle, - unthrottle: visor_unthrottle, - startup: visor_startup, - shutdown: visor_shutdown, - ioctl: visor_ioctl, - set_termios: visor_set_termios, - write: visor_write, - write_room: visor_write_room, - chars_in_buffer: visor_chars_in_buffer, - write_bulk_callback: visor_write_bulk_callback, - read_bulk_callback: visor_read_bulk_callback, -}; /* device info for the Sony Clie OS version 3.5 */ static struct usb_serial_device_type clie_3_5_device = { - name: "Sony Clie 3.5", + name: "Sony Clié 3.5", id_table: clie_id_3_5_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ @@ -285,7 +262,7 @@ static struct usb_serial_device_type clie_3_5_device = { /* device info for the Sony Clie OS version 4.0 */ static struct usb_serial_device_type clie_4_0_device = { - name: "Sony Clie 4.0", + name: "Sony Clié 4.0", id_table: clie_id_4_0_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ @@ -330,6 +307,11 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) dbg(__FUNCTION__ " - port %d", port->number); + if (!port->read_urb) { + err ("Device lied about number of ports, please use a lower one."); + return -ENODEV; + } + down (&port->sem); ++port->open_count; @@ -819,8 +801,7 @@ static int __init visor_init (void) int i; usb_serial_register (&handspring_device); - usb_serial_register (&palm_m500_device); - usb_serial_register (&palm_m505_device); + usb_serial_register (&palm_4_0_device); usb_serial_register (&clie_3_5_device); usb_serial_register (&clie_4_0_device); @@ -854,8 +835,7 @@ static void __exit visor_exit (void) unsigned long flags; usb_serial_deregister (&handspring_device); - usb_serial_deregister (&palm_m500_device); - usb_serial_deregister (&palm_m505_device); + usb_serial_deregister (&palm_4_0_device); usb_serial_deregister (&clie_3_5_device); usb_serial_deregister (&clie_4_0_device); diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index c96b7823a946..17b1605ec12d 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -23,6 +23,7 @@ #define PALM_VENDOR_ID 0x0830 #define PALM_M500_ID 0x0001 #define PALM_M505_ID 0x0002 +#define PALM_M125_ID 0x0040 #define SONY_VENDOR_ID 0x054C #define SONY_CLIE_3_5_ID 0x0038 diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 4777aef7a688..1c570b5494b3 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -1,5 +1,5 @@ /* - * USB Skeleton driver - 0.5 + * USB Skeleton driver - 0.6 * * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * @@ -22,6 +22,8 @@ * * History: * + * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. + * Thanks to Pete Zaitcev for the fix. * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux * 2001_08_21 - 0.4 - more small bug fixes. * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel @@ -604,6 +606,7 @@ static void skel_disconnect(struct usb_device *udev, void *ptr) /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { + up (&dev->sem); skel_delete (dev); } else { dev->udev = NULL; diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 266e2bf810f3..61b6ce730d37 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -312,8 +312,8 @@ static void hga_blank(int blank_mode) static int __init hga_card_detect(void) { int count=0; - unsigned char p, p_save; - unsigned char q, q_save; + unsigned long p, q; + unsigned short p_save, q_save; hga_vram_base = 0xb0000; hga_vram_len = 0x08000; diff --git a/fs/Config.in b/fs/Config.in index 7459c16cf842..976ff9fff3b3 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -92,6 +92,7 @@ if [ "$CONFIG_NET" = "y" ]; then comment 'Network File Systems' dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET + dep_tristate 'InterMezzo file system support (experimental, replicating fs)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP diff --git a/fs/Makefile b/fs/Makefile index d97aa64dbb23..01eaf026bb2d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -33,6 +33,7 @@ subdir-$(CONFIG_ZLIB_FS_INFLATE) += inflate_fs subdir-$(CONFIG_CRAMFS) += cramfs subdir-$(CONFIG_RAMFS) += ramfs subdir-$(CONFIG_CODA_FS) += coda +subdir-$(CONFIG_INTERMEZZO_FS) += intermezzo subdir-$(CONFIG_MINIX_FS) += minix subdir-$(CONFIG_FAT_FS) += fat subdir-$(CONFIG_UMSDOS_FS) += umsdos diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 207e23fb970c..ee386b01e0ec 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -640,9 +640,9 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, if (sb->s_root) { dput(sb->s_root); sb->s_root = NULL; - printk ("EXT2-fs: corrupt root inode, run e2fsck\n"); + printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); } else - printk ("EXT2-fs: get root inode failed\n"); + printk(KERN_ERR "EXT2-fs: get root inode failed\n"); goto failed_mount2; } ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 9cef2a18fbd0..8d77aca6ece7 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c @@ -1,10 +1,8 @@ /* - * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $ - * * ldm - Part of the Linux-NTFS project. * - * Copyright (C) 2001 Richard Russon - * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001 Richard Russon + * Copyright (C) 2001 Anton Altaparmakov (AIA) * * Documentation is available at http://linux-ntfs.sf.net/ldm * @@ -22,6 +20,8 @@ * along with this program (in the main directory of the Linux-NTFS source * in the file COPYING); if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 28/10/2001 - Added sorting of ldm partitions. (AIA) */ #include #include @@ -157,6 +157,60 @@ static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) return err; } +/** + * add_partition_to_list - insert partition into a partition list + * @pl: sorted list of partitions + * @hd: gendisk structure to which the data partition belongs + * @disk_minor: minor number of the disk device + * @start: first sector within the disk device + * @size: number of sectors on the partition device + * + * This sanity checks the partition specified by @start and @size against the + * device specified by @hd and inserts the partition into the sorted partition + * list @pl if the checks pass. + * + * On success return 1, otherwise return -1. + * + * TODO: Add sanity check for overlapping partitions. (AIA) + */ +static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd, + const int disk_minor, const unsigned long start, + const unsigned long size) +{ + struct ldm_part *lp, *lptmp; + struct list_head *tmp; + + if (!hd->part) + return -1; + if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { + printk(LDM_CRIT "LDM partition exceeds physical disk. " + "Skipping.\n"); + return -1; + } + lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL); + if (!lp) { + printk(LDM_CRIT "Not enough memory! Aborting LDM partition " + "parsing.\n"); + return -2; + } + INIT_LIST_HEAD(&lp->part_list); + lp->start = start; + lp->size = size; + list_for_each(tmp, pl) { + lptmp = list_entry(tmp, struct ldm_part, part_list); + if (start > lptmp->start) + continue; + if (start < lptmp->start) + break; + printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n"); + kfree(lp); + return -1; + } + list_add_tail(&lp->part_list, tmp); + ldm_debug("Added LDM partition successfully.\n"); + return 1; +} + /** * create_data_partitions - create the data partition devices * @hd: gendisk structure in which to create the data partitions @@ -172,7 +226,10 @@ static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) * the partitions in the database that belong to this disk. * * For each found partition, we create a corresponding partition device starting - * with minor number @first_part_minor. + * with minor number @first_part_minor. But we do this in such a way that we + * actually sort the partitions in order of on-disk position. Any invalid + * partitions are completely ignored/skipped (an error is output but that's + * all). * * Return 1 on success and -1 on error. */ @@ -182,13 +239,16 @@ static int create_data_partitions(struct gendisk *hd, const struct privhead *ph, const struct ldmdisk *dk, unsigned long base) { - Sector sect; + Sector sect; unsigned char *data; struct vblk *vb; + LIST_HEAD(pl); /* Sorted list of partitions. */ + struct ldm_part *lp; + struct list_head *tmp; int vblk; int vsize; /* VBLK size. */ int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err; + int buffer, lastbuf, lastofs, err, disk_minor; vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL); if (!vb) @@ -207,7 +267,11 @@ static int create_data_partitions(struct gendisk *hd, if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > ph->config_size * 512) goto err_out; - printk(" <"); + /* + * Get the minor number of the parent device so we can check we don't + * go beyond the end of the device. + */ + disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift; for (buffer = 0; buffer < lastbuf; buffer++) { data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); if (!data) @@ -226,17 +290,34 @@ static int create_data_partitions(struct gendisk *hd, continue; if (dk->obj_id != vb->disk_id) continue; - if (create_partition(hd, first_part_minor, + /* Ignore invalid partition errors. */ + if (add_partition_to_list(&pl, hd, disk_minor, first_sector + vb->start_sector + ph->logical_disk_start, - vb->num_sectors) == 1) - first_part_minor++; + vb->num_sectors) < -1) + goto brelse_out; } put_dev_sector(sect); } - printk(" >\n"); err = 1; out: + /* Finally create the nicely sorted data partitions. */ + printk(" <"); + list_for_each(tmp, &pl) { + lp = list_entry(tmp, struct ldm_part, part_list); + add_gd_partition(hd, first_part_minor++, lp->start, lp->size); + } + printk(" >\n"); + if (!list_empty(&pl)) { + struct list_head *tmp2; + + /* Cleanup the partition list which is now superfluous. */ + list_for_each_safe(tmp, tmp2, &pl) { + lp = list_entry(tmp, struct ldm_part, part_list); + list_del(tmp); + kfree(lp); + } + } kfree(vb); return err; brelse_out: @@ -372,7 +453,10 @@ static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm, delta = vblk * vsize + 0x18; if (delta >= 512) goto brelse_out; - if (block[0x13] != VBLK_DISK) + if (block[0x0D] != 0) /* Extended VBLK, ignore */ + continue; + if ((block[0x13] != VBLK_DSK1) && + (block[0x13] != VBLK_DSK2)) continue; /* Calculate relative offsets. */ rel_objid = 1 + block[0x18]; @@ -895,7 +979,7 @@ static int validate_partition_table(struct block_device *bdev) put_dev_sector(sect); return 1; not_dynamic_disk: - ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n"); +// ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n"); no_msdos_partition: put_dev_sector(sect); return 0; diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h index 0404543ec1b2..6f452ba450c8 100644 --- a/fs/partitions/ldm.h +++ b/fs/partitions/ldm.h @@ -1,11 +1,9 @@ #ifndef _FS_PT_LDM_H_ #define _FS_PT_LDM_H_ /* - * $Id: ldm.h,v 1.13 2001/07/23 19:49:49 antona Exp $ - * * ldm - Part of the Linux-NTFS project. * - * Copyright (C) 2001 Richard Russon + * Copyright (C) 2001 Richard Russon * Copyright (C) 2001 Anton Altaparmakov * * Documentation is available at http://linux-ntfs.sf.net/ldm @@ -25,7 +23,7 @@ * in the file COPYING); if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include #include #include @@ -45,8 +43,10 @@ /* The defined vblk types. */ #define VBLK_COMP 0x32 /* Component */ #define VBLK_PART 0x33 /* Partition */ -#define VBLK_DISK 0x34 /* Disk */ -#define VBLK_DGRP 0x45 /* Disk Group */ +#define VBLK_DSK1 0x34 /* Disk */ +#define VBLK_DSK2 0x44 /* Disk */ +#define VBLK_DGR1 0x35 /* Disk Group */ +#define VBLK_DGR2 0x45 /* Disk Group */ #define VBLK_VOLU 0x51 /* Volume */ /* Other constants. */ @@ -144,6 +144,12 @@ struct vblk { u64 num_sectors; }; +struct ldm_part { + struct list_head part_list; + unsigned long start; + unsigned long size; +}; + int ldm_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ee030ece19d2..ae01df6796f6 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -50,7 +50,6 @@ * have a way to deal with that gracefully. Right now I used straightforward * wrappers, but this needs further analysis wrt potential overflows. */ -extern int get_cpuinfo(char *); extern int get_hardware_list(char *); extern int get_stram_list(char *); #ifdef CONFIG_DEBUG_MALLOC @@ -208,12 +207,17 @@ static int version_read_proc(char *page, char **start, off_t off, return proc_calc_metrics(page, start, off, count, eof, len); } -static int cpuinfo_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +extern struct seq_operations cpuinfo_op; +static int cpuinfo_open(struct inode *inode, struct file *file) { - int len = get_cpuinfo(page); - return proc_calc_metrics(page, start, off, count, eof, len); + return seq_open(file, &cpuinfo_op); } +static struct file_operations proc_cpuinfo_operations = { + open: cpuinfo_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; #ifdef CONFIG_PROC_HARDWARE static int hardware_read_proc(char *page, char **start, off_t off, @@ -526,7 +530,6 @@ void __init proc_misc_init(void) {"uptime", uptime_read_proc}, {"meminfo", meminfo_read_proc}, {"version", version_read_proc}, - {"cpuinfo", cpuinfo_read_proc}, #ifdef CONFIG_PROC_HARDWARE {"hardware", hardware_read_proc}, #endif @@ -568,9 +571,14 @@ void __init proc_misc_init(void) entry = create_proc_entry("mounts", 0, NULL); if (entry) entry->proc_fops = &proc_mounts_operations; + entry = create_proc_entry("cpuinfo", 0, NULL); + if (entry) + entry->proc_fops = &proc_cpuinfo_operations; +#ifdef CONFIG_MODULES entry = create_proc_entry("ksyms", 0, NULL); if (entry) entry->proc_fops = &proc_ksyms_operations; +#endif proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); if (proc_root_kcore) { proc_root_kcore->proc_fops = &proc_kcore_operations; diff --git a/fs/seq_file.c b/fs/seq_file.c index 3786b3f37d70..8929a841ab37 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -5,9 +5,10 @@ * initial implementation -- AV, Oct 2001. */ -#include #include #include +#include + #include /** diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h index 96944938fc18..8701d6a01164 100644 --- a/include/linux/ac97_codec.h +++ b/include/linux/ac97_codec.h @@ -239,6 +239,7 @@ extern int ac97_read_proc (char *page_out, char **start, off_t off, extern int ac97_probe_codec(struct ac97_codec *); extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate); extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate); - +extern int ac97_save_state(struct ac97_codec *codec); +extern int ac97_restore_state(struct ac97_codec *codec); #endif /* _AC97_CODEC_H_ */ diff --git a/include/linux/console.h b/include/linux/console.h index d2ae967af36c..0fca958bd07e 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -112,6 +112,7 @@ extern struct console *console_drivers; extern void acquire_console_sem(void); extern void release_console_sem(void); extern void console_conditional_schedule(void); +extern void console_unblank(void); /* VESA Blanking Levels */ #define VESA_NO_BLANKING 0 diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h index f42165a80799..136dac530b93 100644 --- a/include/linux/isapnp.h +++ b/include/linux/isapnp.h @@ -162,6 +162,14 @@ struct isapnp_device_id { unsigned long driver_data; /* data private to the driver */ }; +struct isapnp_driver { + struct list_head node; + char *name; + const struct isapnp_device_id *id_table; /* NULL if wants all devices */ + int (*probe) (struct pci_dev *dev, const struct isapnp_device_id *id); /* New device inserted */ + void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ +}; + #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) #define __ISAPNP__ @@ -214,6 +222,9 @@ extern struct list_head isapnp_devices; #define isapnp_for_each_dev(dev) \ for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next)) +int isapnp_register_driver(struct isapnp_driver *drv); +void isapnp_unregister_driver(struct isapnp_driver *drv); + #else /* !CONFIG_ISAPNP */ /* lowlevel configuration */ @@ -249,6 +260,10 @@ static inline void isapnp_resource_change(struct resource *resource, unsigned long size) { ; } static inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; } +static inline int isapnp_register_driver(struct isapnp_driver *drv) { return 0; } + +static inline void isapnp_unregister_driver(struct isapnp_driver *drv) { } + #endif /* CONFIG_ISAPNP */ #endif /* __KERNEL__ */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index f6821a2668b2..ce4aef9e5666 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -51,7 +51,7 @@ struct completion; extern struct notifier_block *panic_notifier_list; NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))); -NORET_TYPE void do_exit(long error_code) +asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET; NORET_TYPE void complete_and_exit(struct completion *, long) ATTRIB_NORET; diff --git a/include/linux/pci.h b/include/linux/pci.h index 8eaa73a08c3e..e1cd3b4203e0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -532,6 +532,8 @@ struct pci_bus *pci_alloc_primary_bus(int bus); struct pci_dev *pci_scan_slot(struct pci_dev *temp); int pci_proc_attach_device(struct pci_dev *dev); int pci_proc_detach_device(struct pci_dev *dev); +int pci_proc_attach_bus(struct pci_bus *bus); +int pci_proc_detach_bus(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); @@ -589,6 +591,9 @@ void pci_insert_device(struct pci_dev *, struct pci_bus *); void pci_remove_device(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); +void pci_announce_device_to_drivers(struct pci_dev *); +unsigned int pci_do_scan_bus(struct pci_bus *bus); +struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); /* kmem_cache style wrapper around pci_alloc_consistent() */ struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev, diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 851df24f4a5a..b53549dda951 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -43,6 +43,7 @@ static inline int pers_to_level (int pers) static inline int level_to_pers (int level) { switch (level) { + case -4: return MULTIPATH; case -3: return HSM; case -2: return TRANSLUCENT; case -1: return LINEAR; diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index db2f3ec99bda..261c1c837d7b 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -7,14 +7,11 @@ struct multipath_info { int number; int raid_disk; kdev_t dev; - int sect_limit; - int head_position; /* * State bits: */ int operational; - int write_only; int spare; int used_slot; @@ -36,22 +33,10 @@ struct multipath_private_data { * multipath_bh that are pre-allocated have MPBH_PreAlloc set. * All these variable are protected by device_lock */ - struct buffer_head *freebh; - int freebh_cnt; /* how many are on the list */ struct multipath_bh *freer1; - struct multipath_bh *freebuf; /* each bh_req has a page allocated */ + int freer1_blocked; + int freer1_cnt; md_wait_queue_head_t wait_buffer; - - /* for use when syncing multipaths: */ - unsigned long start_active, start_ready, - start_pending, start_future; - int cnt_done, cnt_active, cnt_ready, - cnt_pending, cnt_future; - int phase; - int window; - md_wait_queue_head_t wait_done; - md_wait_queue_head_t wait_ready; - md_spinlock_t segment_lock; }; typedef struct multipath_private_data multipath_conf_t; @@ -76,9 +61,8 @@ struct multipath_bh { unsigned long state; mddev_t *mddev; struct buffer_head *master_bh; - struct buffer_head *multipath_bh_list; struct buffer_head bh_req; - struct multipath_bh *next_r1; /* next for retry or in free list */ + struct multipath_bh *next_mp; /* next for retry or in free list */ }; /* bits for multipath_bh.state */ #define MPBH_Uptodate 1 diff --git a/kernel/sched.c b/kernel/sched.c index 15e96ada76dd..11de5d6951a9 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -515,7 +515,7 @@ needs_resched: #endif /* CONFIG_SMP */ } -void schedule_tail(struct task_struct *prev) +asmlinkage void schedule_tail(struct task_struct *prev) { __schedule_tail(prev); } -- 2.39.5