diff options
214 files changed, 10321 insertions, 3591 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 9734577d171..11a3c1682ce 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -52,3 +52,36 @@ Description: facility is inherently dangerous, it is disabled by default for all devices except hubs. For more information, see Documentation/usb/persist.txt. + +What: /sys/bus/usb/device/.../power/connected_duration +Date: January 2008 +KernelVersion: 2.6.25 +Contact: Sarah Sharp <sarah.a.sharp@intel.com> +Description: + If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file + is present. When read, it returns the total time (in msec) + that the USB device has been connected to the machine. This + file is read-only. +Users: + PowerTOP <power@bughost.org> + http://www.lesswatts.org/projects/powertop/ + +What: /sys/bus/usb/device/.../power/active_duration +Date: January 2008 +KernelVersion: 2.6.25 +Contact: Sarah Sharp <sarah.a.sharp@intel.com> +Description: + If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file + is present. When read, it returns the total time (in msec) + that the USB device has been active, i.e. not in a suspended + state. This file is read-only. + + Tools can use this file and the connected_duration file to + compute the percentage of time that a device has been active. + For example, + echo $((100 * `cat active_duration` / `cat connected_duration`)) + will give an integer percentage. Note that this does not + account for counter wrap. +Users: + PowerTOP <power@bughost.org> + http://www.lesswatts.org/projects/powertop/ diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 181bff00516..a7d9d179131 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -156,22 +156,6 @@ Who: Arjan van de Ven <arjan@linux.intel.com> --------------------------- -What: USB driver API moves to EXPORT_SYMBOL_GPL -When: February 2008 -Files: include/linux/usb.h, drivers/usb/core/driver.c -Why: The USB subsystem has changed a lot over time, and it has been - possible to create userspace USB drivers using usbfs/libusb/gadgetfs - that operate as fast as the USB bus allows. Because of this, the USB - subsystem will not be allowing closed source kernel drivers to - register with it, after this grace period is over. If anyone needs - any help in converting their closed source drivers over to use the - userspace filesystems, please contact the - linux-usb-devel@lists.sourceforge.net mailing list, and the developers - there will be glad to help you out. -Who: Greg Kroah-Hartman <gregkh@suse.de> - ---------------------------- - What: vm_ops.nopage When: Soon, provided in-kernel callers have been converted Why: This interface is replaced by vm_ops.fault, but it has been around diff --git a/Documentation/pci.txt b/Documentation/pci.txt index 7754f5aea4e..72b20c63959 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -274,8 +274,6 @@ the PCI device by calling pci_enable_device(). This will: o allocate an IRQ (if BIOS did not). NOTE: pci_enable_device() can fail! Check the return value. -NOTE2: Also see pci_enable_device_bars() below. Drivers can - attempt to enable only a subset of BARs they need. [ OS BUG: we don't check resource allocations before enabling those resources. The sequence would make more sense if we called @@ -605,40 +603,7 @@ device lists. This is still possible but discouraged. -10. pci_enable_device_bars() and Legacy I/O Port space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Large servers may not be able to provide I/O port resources to all PCI -devices. I/O Port space is only 64KB on Intel Architecture[1] and is -likely also fragmented since the I/O base register of PCI-to-PCI -bridge will usually be aligned to a 4KB boundary[2]. On such systems, -pci_enable_device() and pci_request_region() will fail when -attempting to enable I/O Port regions that don't have I/O Port -resources assigned. - -Fortunately, many PCI devices which request I/O Port resources also -provide access to the same registers via MMIO BARs. These devices can -be handled without using I/O port space and the drivers typically -offer a CONFIG_ option to only use MMIO regions -(e.g. CONFIG_TULIP_MMIO). PCI devices typically provide I/O port -interface for legacy OSes and will work when I/O port resources are not -assigned. The "PCI Local Bus Specification Revision 3.0" discusses -this on p.44, "IMPLEMENTATION NOTE". - -If your PCI device driver doesn't need I/O port resources assigned to -I/O Port BARs, you should use pci_enable_device_bars() instead of -pci_enable_device() in order not to enable I/O port regions for the -corresponding devices. In addition, you should use -pci_request_selected_regions() and pci_release_selected_regions() -instead of pci_request_regions()/pci_release_regions() in order not to -request/release I/O port regions for the corresponding devices. - -[1] Some systems support 64KB I/O port space per PCI segment. -[2] Some PCI-to-PCI bridges support optional 1KB aligned I/O base. - - - -11. MMIO Space and "Write Posting" +10. MMIO Space and "Write Posting" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Converting a driver from using I/O Port space to using MMIO space diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt new file mode 100644 index 00000000000..ad995bf0db4 --- /dev/null +++ b/Documentation/usb/gadget_printer.txt @@ -0,0 +1,510 @@ + + Linux USB Printer Gadget Driver + 06/04/2007 + + Copyright (C) 2007 Craig W. Nadler <craig@nadler.us> + + + +GENERAL +======= + +This driver may be used if you are writing printer firmware using Linux as +the embedded OS. This driver has nothing to do with using a printer with +your Linux host system. + +You will need a USB device controller and a Linux driver for it that accepts +a gadget / "device class" driver using the Linux USB Gadget API. After the +USB device controller driver is loaded then load the printer gadget driver. +This will present a printer interface to the USB Host that your USB Device +port is connected to. + +This driver is structured for printer firmware that runs in user mode. The +user mode printer firmware will read and write data from the kernel mode +printer gadget driver using a device file. The printer returns a printer status +byte when the USB HOST sends a device request to get the printer status. The +user space firmware can read or write this status byte using a device file +/dev/g_printer . Both blocking and non-blocking read/write calls are supported. + + + + +HOWTO USE THIS DRIVER +===================== + +To load the USB device controller driver and the printer gadget driver. The +following example uses the Netchip 2280 USB device controller driver: + +modprobe net2280 +modprobe g_printer + + +The follow command line parameter can be used when loading the printer gadget +(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ): + +idVendor - This is the Vendor ID used in the device descriptor. The default is + the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID + BEFORE RELEASING A PRODUCT. If you plan to release a product and don't + already have a Vendor ID please see www.usb.org for details on how to + get one. + +idProduct - This is the Product ID used in the device descriptor. The default + is 0xa4a8, you should change this to an ID that's not used by any of + your other USB products if you have any. It would be a good idea to + start numbering your products starting with say 0x0001. + +bcdDevice - This is the version number of your product. It would be a good idea + to put your firmware version here. + +iManufacturer - A string containing the name of the Vendor. + +iProduct - A string containing the Product Name. + +iSerialNum - A string containing the Serial Number. This should be changed for + each unit of your product. + +iPNPstring - The PNP ID string used for this printer. You will want to set + either on the command line or hard code the PNP ID string used for + your printer product. + +qlen - The number of 8k buffers to use per endpoint. The default is 10, you + should tune this for your product. You may also want to tune the + size of each buffer for your product. + + + + +USING THE EXAMPLE CODE +====================== + +This example code talks to stdout, instead of a print engine. + +To compile the test code below: + +1) save it to a file called prn_example.c +2) compile the code with the follow command: + gcc prn_example.c -o prn_example + + + +To read printer data from the host to stdout: + + # prn_example -read_data + + +To write printer data from a file (data_file) to the host: + + # cat data_file | prn_example -write_data + + +To get the current printer status for the gadget driver: + + # prn_example -get_status + + Printer status is: + Printer is NOT Selected + Paper is Out + Printer OK + + +To set printer to Selected/On-line: + + # prn_example -selected + + +To set printer to Not Selected/Off-line: + + # prn_example -not_selected + + +To set paper status to paper out: + + # prn_example -paper_out + + +To set paper status to paper loaded: + + # prn_example -paper_loaded + + +To set error status to printer OK: + + # prn_example -no_error + + +To set error status to ERROR: + + # prn_example -error + + + + +EXAMPLE CODE +============ + + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <linux/poll.h> +#include <sys/ioctl.h> +#include <linux/usb/g_printer.h> + +#define PRINTER_FILE "/dev/g_printer" +#define BUF_SIZE 512 + + +/* + * 'usage()' - Show program usage. + */ + +static void +usage(const char *option) /* I - Option string or NULL */ +{ + if (option) { + fprintf(stderr,"prn_example: Unknown option \"%s\"!\n", + option); + } + + fputs("\n", stderr); + fputs("Usage: prn_example -[options]\n", stderr); + fputs("Options:\n", stderr); + fputs("\n", stderr); + fputs("-get_status Get the current printer status.\n", stderr); + fputs("-selected Set the selected status to selected.\n", stderr); + fputs("-not_selected Set the selected status to NOT selected.\n", + stderr); + fputs("-error Set the error status to error.\n", stderr); + fputs("-no_error Set the error status to NO error.\n", stderr); + fputs("-paper_out Set the paper status to paper out.\n", stderr); + fputs("-paper_loaded Set the paper status to paper loaded.\n", + stderr); + fputs("-read_data Read printer data from driver.\n", stderr); + fputs("-write_data Write printer sata to driver.\n", stderr); + fputs("-NB_read_data (Non-Blocking) Read printer data from driver.\n", + stderr); + fputs("\n\n", stderr); + + exit(1); +} + + +static int +read_printer_data() +{ + struct pollfd fd[1]; + + /* Open device file for printer gadget. */ + fd[0].fd = open(PRINTER_FILE, O_RDWR); + if (fd[0].fd < 0) { + printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE); + close(fd[0].fd); + return(-1); + } + + fd[0].events = POLLIN | POLLRDNORM; + + while (1) { + static char buf[BUF_SIZE]; + int bytes_read; + int retval; + + /* Wait for up to 1 second for data. */ + retval = poll(fd, 1, 1000); + + if (retval && (fd[0].revents & POLLRDNORM)) { + + /* Read data from printer gadget driver. */ + bytes_read = read(fd[0].fd, buf, BUF_SIZE); + + if (bytes_read < 0) { + printf("Error %d reading from %s\n", + fd[0].fd, PRINTER_FILE); + close(fd[0].fd); + return(-1); + } else if (bytes_read > 0) { + /* Write data to standard OUTPUT (stdout). */ + fwrite(buf, 1, bytes_read, stdout); + fflush(stdout); + } + + } + + } + + /* Close the device file. */ + close(fd[0].fd); + + return 0; +} + + +static int +write_printer_data() +{ + struct pollfd fd[1]; + + /* Open device file for printer gadget. */ + fd[0].fd = open (PRINTER_FILE, O_RDWR); + if (fd[0].fd < 0) { + printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE); + close(fd[0].fd); + return(-1); + } + + fd[0].events = POLLOUT | POLLWRNORM; + + while (1) { + int retval; + static char buf[BUF_SIZE]; + /* Read data from standard INPUT (stdin). */ + int bytes_read = fread(buf, 1, BUF_SIZE, stdin); + + if (!bytes_read) { + break; + } + + while (bytes_read) { + + /* Wait for up to 1 second to sent data. */ + retval = poll(fd, 1, 1000); + + /* Write data to printer gadget driver. */ + if (retval && (fd[0].revents & POLLWRNORM)) { + retval = write(fd[0].fd, buf, bytes_read); + if (retval < 0) { + printf("Error %d writing to %s\n", + fd[0].fd, + PRINTER_FILE); + close(fd[0].fd); + return(-1); + } else { + bytes_read -= retval; + } + + } + + } + + } + + /* Wait until the data has been sent. */ + fsync(fd[0].fd); + + /* Close the device file. */ + close(fd[0].fd); + + return 0; +} + + +static int +read_NB_printer_data() +{ + int fd; + static char buf[BUF_SIZE]; + int bytes_read; + + /* Open device file for printer gadget. */ + fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK); + if (fd < 0) { + printf("Error %d opening %s\n", fd, PRINTER_FILE); + close(fd); + return(-1); + } + + while (1) { + /* Read data from printer gadget driver. */ + bytes_read = read(fd, buf, BUF_SIZE); + if (bytes_read <= 0) { + break; + } + + /* Write data to standard OUTPUT (stdout). */ + fwrite(buf, 1, bytes_read, stdout); + fflush(stdout); + } + + /* Close the device file. */ + close(fd); + + return 0; +} + + +static int +get_printer_status() +{ + int retval; + int fd; + + /* Open device file for printer gadget. */ + fd = open(PRINTER_FILE, O_RDWR); + if (fd < 0) { + printf("Error %d opening %s\n", fd, PRINTER_FILE); + close(fd); + return(-1); + } + + /* Make the IOCTL call. */ + retval = ioctl(fd, GADGET_GET_PRINTER_STATUS); + if (retval < 0) { + fprintf(stderr, "ERROR: Failed to set printer status\n"); + return(-1); + } + + /* Close the device file. */ + close(fd); + + return(retval); +} + + +static int +set_printer_status(unsigned char buf, int clear_printer_status_bit) +{ + int retval; + int fd; + + retval = get_printer_status(); + if (retval < 0) { + fprintf(stderr, "ERROR: Failed to get printer status\n"); + return(-1); + } + + /* Open device file for printer gadget. */ + fd = open(PRINTER_FILE, O_RDWR); + + if (fd < 0) { + printf("Error %d opening %s\n", fd, PRINTER_FILE); + close(fd); + return(-1); + } + + if (clear_printer_status_bit) { + retval &= ~buf; + } else { + retval |= buf; + } + + /* Make the IOCTL call. */ + if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) { + fprintf(stderr, "ERROR: Failed to set printer status\n"); + return(-1); + } + + /* Close the device file. */ + close(fd); + + return 0; +} + + +static int +display_printer_status() +{ + char printer_status; + + printer_status = get_printer_status(); + if (printer_status < 0) { + fprintf(stderr, "ERROR: Failed to get printer status\n"); + return(-1); + } + + printf("Printer status is:\n"); + if (printer_status & PRINTER_SELECTED) { + printf(" Printer is Selected\n"); + } else { + printf(" Printer is NOT Selected\n"); + } + if (printer_status & PRINTER_PAPER_EMPTY) { + printf(" Paper is Out\n"); + } else { + printf(" Paper is Loaded\n"); + } + if (printer_status & PRINTER_NOT_ERROR) { + printf(" Printer OK\n"); + } else { + printf(" Printer ERROR\n"); + } + + return(0); +} + + +int +main(int argc, char *argv[]) +{ + int i; /* Looping var */ + int retval = 0; + + /* No Args */ + if (argc == 1) { + usage(0); + exit(0); + } + + for (i = 1; i < argc && !retval; i ++) { + + if (argv[i][0] != '-') { + continue; + } + + if (!strcmp(argv[i], "-get_status")) { + if (display_printer_status()) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-paper_loaded")) { + if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-paper_out")) { + if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-selected")) { + if (set_printer_status(PRINTER_SELECTED, 0)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-not_selected")) { + if (set_printer_status(PRINTER_SELECTED, 1)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-error")) { + if (set_printer_status(PRINTER_NOT_ERROR, 1)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-no_error")) { + if (set_printer_status(PRINTER_NOT_ERROR, 0)) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-read_data")) { + if (read_printer_data()) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-write_data")) { + if (write_printer_data()) { + retval = 1; + } + + } else if (!strcmp(argv[i], "-NB_read_data")) { + if (read_NB_printer_data()) { + retval = 1; + } + + } else { + usage(argv[i]); + retval = 1; + } + } + + exit(retval); +} diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt new file mode 100644 index 00000000000..e5f048067da --- /dev/null +++ b/Documentation/usb/iuu_phoenix.txt @@ -0,0 +1,84 @@ +Infinity Usb Unlimited Readme +----------------------------- + +Hi all, + + +This module provide a serial interface to use your +IUU unit in phoenix mode. Loading this module will +bring a ttyUSB[0-x] interface. This driver must be +used by your favorite application to pilot the IUU + +This driver is still in beta stage, so bugs can +occur and your system may freeze. As far I now, +I never had any problem with it, but I'm not a real +guru, so don't blame me if your system is unstable + +You can plug more than one IUU. Every unit will +have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...) + + + +How to tune the reader speed ? + + A few parameters can be used at load time + To use parameters, just unload the module if it is + already loaded and use modprobe iuu_phoenix param=value. + In case of prebuilt module, use the command + insmod iuu_phoenix param=value. + + Example: + + modprobe iuu_phoenix clockmode=3 + + The parameters are: + + parm: clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int) + parm: boost:overclock boost percent 100 to 500 (int) + parm: cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int) + parm: xmas:xmas color enabled or not (bool) + parm: debug:Debug enabled or not (bool) + +- clockmode will provide 3 different base settings commonly adopted by + different software: + 1. 3Mhz579 + 2. 3Mhz680 + 3. 6Mhz + +- boost provide a way to overclock the reader ( my favorite :-) ) + For example to have best performance than a simple clockmode=3, try this: + + modprobe boost=195 + + This will put the reader in a base of 3Mhz579 but boosted a 195 % ! + the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase + the speed to a score 10 to 20% better than the simple clockmode=3 !!! + + +- cdmode permit to setup the signal used to inform the userland ( ioctl answer ) + if the card is present or not. Eight signals are possible. + +- xmas is completely useless except for your eyes. This is one of my friend who was + so sad to have a nice device like the iuu without seeing all color range available. + So I have added this option to permit him to see a lot of color ( each activity change the color + and the frequency randomly ) + +- debug will produce a lot of debugging messages... + + + Last notes: + + Don't worry about the serial settings, the serial emulation + is an abstraction, so use any speed or parity setting will + work. ( This will not change anything ).Later I will perhaps + use this settings to deduce de boost but is that feature + really necessary ? + The autodetect feature used is the serial CD. If that doesn't + work for your software, disable detection mechanism in it. + + + Have fun ! + + Alain Degreffe + + eczema(at)ecze.com diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 4c002ba37e5..c613d5fb0da 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -318,11 +318,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config PCI_DOMAINS bool default y diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a00d8b97c30..4b1a8e3d292 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -577,11 +577,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config PCI_SYSCALL def_bool PCI diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 1919756900f..1a9c844ac7e 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -157,15 +157,10 @@ static void tosa_udc_command(int cmd) } } -static int tosa_udc_is_connected(void) -{ - return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0); -} - - static struct pxa2xx_udc_mach_info udc_info __initdata = { .udc_command = tosa_udc_command, - .udc_is_connected = tosa_udc_is_connected, + .gpio_vbus = TOSA_GPIO_USB_IN, + .gpio_vbus_inverted = 1, }; /* diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 2e25b95a494..e3f965c91e2 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -322,11 +322,6 @@ config PCI onboard. If you have one of these boards and you wish to use the PCI facilities, say Y here. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config RESERVE_DMA_COHERENT bool "Reserve DMA coherent memory" depends on PCI && !MMU diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index f7237c5f531..49326e9d441 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -359,11 +359,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.linuxdoc.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - choice prompt "PCI access mode" depends on PCI diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 01dee84f840..24e6bc09e7a 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -145,11 +145,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config MAC bool "Macintosh support" depends on !MMU_SUN3 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e387f3ab5f8..36a4018f71d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1961,11 +1961,6 @@ config PCI your box. Other bus systems are ISA, EISA, or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config PCI_DOMAINS bool diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig index fbc6f2c8649..7e816ededed 100644 --- a/arch/sh/drivers/pci/Kconfig +++ b/arch/sh/drivers/pci/Kconfig @@ -6,11 +6,6 @@ config PCI bus system, i.e. the way the CPU talks to the other stuff inside your box. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config SH_PCIDMA_NONCOHERENT bool "Cache and PCI noncoherent" depends on PCI diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 73fc05d0bfa..158522f51d3 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -351,11 +351,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - config PCI_DOMAINS def_bool PCI diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 34401f45ade..7109037bdf7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1377,11 +1377,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - choice prompt "PCI access mode" depends on X86_32 && PCI && !X86_VISWS diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 150ba29a0d3..3cd7a2dcd4f 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -30,8 +30,8 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); if (!(word & (1 << 13))) { - printk(KERN_INFO "Intel E7520/7320/7525 detected. " - "Disabling irq balancing and affinity\n"); + dev_info(&dev->dev, "Intel E7520/7320/7525 detected; " + "disabling irq balancing and affinity\n"); #ifdef CONFIG_IRQBALANCE irqbalance_disable(""); #endif @@ -104,14 +104,16 @@ static void ich_force_enable_hpet(struct pci_dev *dev) pci_read_config_dword(dev, 0xF0, &rcba); rcba &= 0xFFFFC000; if (rcba == 0) { - printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); + dev_printk(KERN_DEBUG, &dev->dev, "RCBA disabled; " + "cannot force enable HPET\n"); return; } /* use bits 31:14, 16 kB aligned */ rcba_base = ioremap_nocache(rcba, 0x4000); if (rcba_base == NULL) { - printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); + dev_printk(KERN_DEBUG, &dev->dev, "ioremap failed; " + "cannot force enable HPET\n"); return; } @@ -122,8 +124,8 @@ static void ich_force_enable_hpet(struct pci_dev *dev) /* HPET is enabled in HPTC. Just not reported by BIOS */ val = val & 0x3; force_hpet_address = 0xFED00000 | (val << 12); - printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " + "0x%lx\n", force_hpet_address); iounmap(rcba_base); return; } @@ -142,11 +144,12 @@ static void ich_force_enable_hpet(struct pci_dev *dev) if (err) { force_hpet_address = 0; iounmap(rcba_base); - printk(KERN_DEBUG "Failed to force enable HPET\n"); + dev_printk(KERN_DEBUG, &dev->dev, + "Failed to force enable HPET\n"); } else { force_hpet_resume_type = ICH_FORCE_HPET_RESUME; - printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " + "0x%lx\n", force_hpet_address); } } @@ -208,8 +211,8 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev) if (val & 0x4) { val &= 0x3; force_hpet_address = 0xFED00000 | (val << 12); - printk(KERN_DEBUG "HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n", + force_hpet_address); return; } @@ -229,14 +232,14 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev) /* HPET is enabled in HPTC. Just not reported by BIOS */ val &= 0x3; force_hpet_address = 0xFED00000 | (val << 12); - printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " + "0x%lx\n", force_hpet_address); cached_dev = dev; force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; return; } - printk(KERN_DEBUG "Failed to force enable HPET\n"); + dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n"); } /* @@ -294,8 +297,8 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev) */ if (val & 0x80) { force_hpet_address = (val & ~0x3ff); - printk(KERN_DEBUG "HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n", + force_hpet_address); return; } @@ -309,14 +312,14 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev) pci_read_config_dword(dev, 0x68, &val); if (val & 0x80) { force_hpet_address = (val & ~0x3ff); - printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", - force_hpet_address); + dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " + "0x%lx\n", force_hpet_address); cached_dev = dev; force_hpet_resume_type = VT8237_FORCE_HPET_RESUME; return; } - printk(KERN_DEBUG "Failed to force enable HPET\n"); + dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, @@ -344,7 +347,7 @@ static void nvidia_force_enable_hpet(struct pci_dev *dev) pci_read_config_dword(dev, 0x44, &val); force_hpet_address = val & 0xfffffffe; force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME; - printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", + dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n", force_hpet_address); cached_dev = dev; return; diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index cb63007e20b..74d30ff33c4 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -17,7 +17,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) int pxb, reg; u8 busno, suba, subb; - printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); + dev_warn(&d->dev, "Searching for i450NX host bridges\n"); reg = 0xd0; for(pxb = 0; pxb < 2; pxb++) { pci_read_config_byte(d, reg++, &busno); @@ -41,7 +41,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d) */ u8 busno; pci_read_config_byte(d, 0x4a, &busno); - printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); + dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno); pci_scan_bus_with_sysdata(busno); pcibios_last_bus = -1; } @@ -55,7 +55,7 @@ static void __devinit pci_fixup_umc_ide(struct pci_dev *d) */ int i; - printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d)); + dev_warn(&d->dev, "Fixing base address flags\n"); for(i = 0; i < 4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } @@ -68,7 +68,7 @@ static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) * Fix class to be PCI_CLASS_STORAGE_SCSI */ if (!d->class) { - printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d)); + dev_warn(&d->dev, "Fixing NCR 53C810 class code\n"); d->class = PCI_CLASS_STORAGE_SCSI << 8; } } @@ -80,7 +80,7 @@ static void __devinit pci_fixup_latency(struct pci_dev *d) * SiS 5597 and 5598 chipsets require latency timer set to * at most 32 to avoid lockups. */ - DBG("PCI: Setting max latency to 32\n"); + dev_dbg(&d->dev, "Setting max latency to 32\n"); pcibios_max_latency = 32; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); @@ -138,7 +138,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d) pci_read_config_byte(d, where, &v); if (v & ~mask) { - printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ + dev_warn(&d->dev, "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ d->device, d->revision, where, v, mask, v & mask); v &= mask; pci_write_config_byte(d, where, v); @@ -200,7 +200,7 @@ static void pci_fixup_nforce2(struct pci_dev *dev) * Apply fixup if needed, but don't touch disconnect state */ if ((val & 0x00FF0000) != 0x00010000) { - printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); + dev_warn(&dev->dev, "nForce2 C1 Halt Disconnect fixup\n"); pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000); } } @@ -348,7 +348,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) pci_read_config_word(pdev, PCI_COMMAND, &config); if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); + dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n"); } } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); @@ -388,11 +388,11 @@ static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev) /* verify the change for status output */ pci_read_config_byte(dev, 0x50, &val); if (val & 0x40) - printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " + dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; " "can't enable onboard soundcard!\n"); else - printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " - "enabled onboard soundcard.\n"); + dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; " + "enabled onboard soundcard\n"); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index d3cb3d6af4c..844721e8e3d 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -174,11 +174,6 @@ config PCI your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or VESA. If you have PCI, say Y, otherwise N. - The PCI-HOWTO, available from - <http://www.linuxdoc.org/docs.html#howto>, contains valuable - information about which PCI hardware does work under Linux and which - doesn't - source "drivers/pci/Kconfig" config HOTPLUG diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index d4590f546c4..7ed279b0a12 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -229,7 +229,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi return -ENOMEM; /* Perform set up for DMA */ - if (pci_enable_device_bars(pdev, 1<<2)) { + if (pci_enable_device_io(pdev)) { printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n"); return -ENODEV; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index c6179d6ac6e..a70c1c29a7a 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -922,11 +922,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - /* Fill what we shouldn't be filling, because usb-storage did so. */ - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ ub_complete(&sc->work_done); @@ -1313,9 +1308,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg), sg->length, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ @@ -1356,9 +1348,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->recv_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ @@ -1473,9 +1462,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { ub_complete(&sc->work_done); @@ -1953,9 +1939,6 @@ static int ub_sync_reset(struct ub_dev *sc) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { printk(KERN_WARNING @@ -2007,9 +1990,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe, (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) goto err_submit; @@ -2077,9 +2057,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { printk(KERN_WARNING diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index e6c4a2b762e..f5e7a70da83 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -492,7 +492,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, iface->pdev = pdev; iface->bar = bar; - rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar); + rc = pci_enable_device_io(iface->pdev); if (rc) goto errout_free; diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 9e01c6dc758..eb68a9ad0c9 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -156,8 +156,14 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic ide_setup_pci_noise(dev, d); /* We must not grab the entire device, it has 'ISA' space in its - BARS too and we will freak out other bits of the kernel */ - if (pci_enable_device_bars(dev, 1<<2)) { + * BARS too and we will freak out other bits of the kernel + * + * pci_enable_device_bars() is going away. I replaced it with + * IO only enable for now but I'll need confirmation this is + * allright for that device. If not, it will need some kind of + * quirk. --BenH. + */ + if (pci_enable_device_io(dev)) { printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); return -ENODEV; } diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 8ff5a0ef10a..05db429a7da 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -228,7 +228,9 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise); * @d: IDE port info * * Enable the IDE PCI device. We attempt to enable the device in full - * but if that fails then we only need BAR4 so we will enable that. + * but if that fails then we only need IO space. The PCI code should + * have setup the proper resources for us already for controllers in + * legacy mode. * * Returns zero on success or an error code */ @@ -238,7 +240,7 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d) int ret; if (pci_enable_device(dev)) { - ret = pci_enable_device_bars(dev, 1 << 4); + ret = pci_enable_device_io(dev); if (ret < 0) { printk(KERN_WARNING "%s: (ide_setup_pci_device:) " "Could not enable device.\n", d->name); diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 9e5ea074ad2..ef5a6a245f5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -108,6 +108,7 @@ int pci_bus_add_device(struct pci_dev *dev) void pci_bus_add_devices(struct pci_bus *bus) { struct pci_dev *dev; + struct pci_bus *child_bus; int retval; list_for_each_entry(dev, &bus->devices, bus_list) { @@ -138,11 +139,19 @@ void pci_bus_add_devices(struct pci_bus *bus) up_write(&pci_bus_sem); } pci_bus_add_devices(dev->subordinate); - retval = sysfs_create_link(&dev->subordinate->class_dev.kobj, - &dev->dev.kobj, "bridge"); + + /* register the bus with sysfs as the parent is now + * properly registered. */ + child_bus = dev->subordinate; + child_bus->dev.parent = child_bus->bridge; + retval = device_register(&child_bus->dev); + if (!retval) + retval = device_create_file(&child_bus->dev, + &dev_attr_cpuaffinity); if (retval) - dev_err(&dev->dev, "Error creating sysfs " - "bridge symlink, continuing...\n"); + dev_err(&dev->dev, "Error registering pci_bus" + " device bridge symlink," + " continuing...\n"); } } } @@ -204,7 +213,6 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), } up_read(&pci_bus_sem); } -EXPORT_SYMBOL_GPL(pci_walk_bus); EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL_GPL(pci_bus_add_device); diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 5dfdfdac92e..91b2dc956be 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/dmar.h> +#include "iova.h" #undef PREFIX #define PREFIX "DMAR:" @@ -263,8 +264,8 @@ parse_dmar_table(void) if (!dmar) return -ENODEV; - if (!dmar->width) { - printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n"); + if (dmar->width < PAGE_SHIFT_4K - 1) { + printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); return -EINVAL; } @@ -301,11 +302,24 @@ parse_dmar_table(void) int __init dmar_table_init(void) { - parse_dmar_table(); + int ret; + + ret = parse_dmar_table(); + if (ret) { + printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); + return ret; + } + if (list_empty(&dmar_drhd_units)) { printk(KERN_INFO PREFIX "No DMAR devices found\n"); return -ENODEV; } + + if (list_empty(&dmar_rmrr_units)) { + printk(KERN_INFO PREFIX "No RMRR found\n"); + return -ENODEV; + } + return 0; } diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index a64449d489d..2cdd8326f13 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -3,8 +3,8 @@ # menuconfig HOTPLUG_PCI - tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL && HOTPLUG + tristate "Support for PCI Hotplug" + depends on PCI && HOTPLUG ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 34a1891191f..9bdbe1a6688 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o @@ -16,6 +15,9 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o +# Link this last so it doesn't claim devices that have a real hotplug driver +obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o + pci_hotplug-objs := pci_hotplug_core.o ifdef CONFIG_HOTPLUG_PCI_CPCI diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 1ef417cca2d..7a29164d4b3 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -113,7 +113,6 @@ struct acpiphp_slot { u8 device; /* pci device# */ u32 sun; /* ACPI _SUN (slot unique number) */ - u32 slotno; /* slot number relative to bridge */ u32 flags; /* see below */ }; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ff1b1c71291..cf22f9e01e0 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -102,7 +102,7 @@ static int is_ejectable(acpi_handle handle) } -/* callback routine to check the existence of ejectable slots */ +/* callback routine to check for the existence of ejectable slots */ static acpi_status is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -117,7 +117,7 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) } } -/* callback routine to check for the existance of a pci dock device */ +/* callback routine to check for the existence of a pci dock device */ static acpi_status is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -1528,7 +1528,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); dbg("%s: re-enumerating slots under %s\n", __FUNCTION__, objname); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpiphp_check_bridge(bridge); } return AE_OK ; diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index d7a293e3faf..94b640146d4 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -39,6 +39,7 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/workqueue.h> #include "../pci.h" #if !defined(MODULE) @@ -63,10 +64,16 @@ struct dummy_slot { struct list_head node; struct hotplug_slot *slot; struct pci_dev *dev; + struct work_struct remove_work; + unsigned long removed; }; static int debug; static LIST_HEAD(slot_list); +static struct workqueue_struct *dummyphp_wq; + +static void pci_rescan_worker(struct work_struct *work); +static DECLARE_WORK(pci_rescan_work, pci_rescan_worker); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); @@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev) slot->name = &dev->dev.bus_id[0]; dbg("slot->name = %s\n", slot->name); - dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); + dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); if (!dslot) goto error_info; @@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot) err("Problem unregistering a slot %s\n", dslot->slot->name); } +/* called from the single-threaded workqueue handler to remove a slot */ +static void remove_slot_worker(struct work_struct *work) +{ + struct dummy_slot *dslot = + container_of(work, struct dummy_slot, remove_work); + remove_slot(dslot); +} + /** * pci_rescan_slot - Rescan slot * @temp: Device template. Should be set: bus and devfn. @@ -267,11 +282,17 @@ static inline void pci_rescan(void) { pci_rescan_buses(&pci_root_buses); } +/* called from the single-threaded workqueue handler to rescan all pci buses */ +static void pci_rescan_worker(struct work_struct *work) +{ + pci_rescan(); +} static int enable_slot(struct hotplug_slot *hotplug_slot) { /* mis-use enable_slot for rescanning of the pci bus */ - pci_rescan(); + cancel_work_sync(&pci_rescan_work); + queue_work(dummyphp_wq, &pci_rescan_work); return -ENODEV; } @@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot) err("Can't remove PCI devices with other PCI devices behind it yet.\n"); return -ENODEV; } + if (test_and_set_bit(0, &dslot->removed)) { + dbg("Slot already scheduled for removal\n"); + return -ENODEV; + } /* search for subfunctions and disable them first */ if (!(dslot->dev->devfn & 7)) { for (func = 1; func < 8; func++) { @@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot) /* remove the device from the pci core */ pci_remove_bus_device(dslot->dev); - /* blow away this sysfs entry and other parts. */ - remove_slot(dslot); + /* queue work item to blow away this sysfs entry and other parts. */ + INIT_WORK(&dslot->remove_work, remove_slot_worker); + queue_work(dummyphp_wq, &dslot->remove_work); return 0; } @@ -340,6 +366,7 @@ static void cleanup_slots (void) struct list_head *next; struct dummy_slot *dslot; + destroy_workqueue(dummyphp_wq); list_for_each_safe (tmp, next, &slot_list) { dslot = list_entry (tmp, struct dummy_slot, node); remove_slot(dslot); @@ -351,6 +378,10 @@ static int __init dummyphp_init(void) { info(DRIVER_DESC "\n"); + dummyphp_wq = create_singlethread_workqueue(MY_NAME); + if (!dummyphp_wq) + return -ENOMEM; + return pci_scan_buses(); } diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index a90c28d0c69..87b6b8b280e 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -761,10 +761,13 @@ static void ibm_unconfigure_device(struct pci_func *func) debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); for (j = 0; j < 0x08; j++) { - temp = pci_find_slot(func->busno, (func->device << 3) | j); - if (temp) + temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); + if (temp) { pci_remove_bus_device(temp); + pci_dev_put(temp); + } } + pci_dev_put(func->dev); } /* @@ -823,7 +826,7 @@ static int ibm_configure_device(struct pci_func *func) if (!(bus_structure_fixup(func->busno))) flag = 1; if (func->dev == NULL) - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { @@ -836,7 +839,7 @@ static int ibm_configure_device(struct pci_func *func) if (num) pci_bus_add_devices(bus); - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { err("ERROR... : pci_dev still NULL\n"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 47bb0e1ff3f..dd59a050260 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -137,7 +137,7 @@ static int get_##name (struct hotplug_slot *slot, type *value) \ int retval = 0; \ if (try_module_get(ops->owner)) { \ if (ops->get_##name) \ - retval = ops->get_##name (slot, value); \ + retval = ops->get_##name(slot, value); \ else \ *value = slot->info->name; \ module_put(ops->owner); \ @@ -625,7 +625,7 @@ int pci_hp_register (struct hotplug_slot *slot) if ((slot->info == NULL) || (slot->ops == NULL)) return -EINVAL; if (slot->release == NULL) { - dbg("Why are you trying to register a hotplug slot" + dbg("Why are you trying to register a hotplug slot " "without a proper release function?\n"); return -EINVAL; } diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 7959c222dc2..ca656b27a50 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -82,24 +82,18 @@ struct event_info { }; struct controller { - struct controller *next; struct mutex crit_sect; /* critical section mutex */ struct mutex ctrl_lock; /* controller lock */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; struct list_head slot_list; - struct slot *slot; struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ - u8 bus; - u8 device; - u8 function; u8 slot_device_offset; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 ctrlcap; - u16 vendor_id; u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; @@ -161,6 +155,9 @@ extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot); extern void pciehp_queue_pushbutton_work(struct work_struct *work); int pcie_init(struct controller *ctrl, struct pcie_device *dev); +int pciehp_enable_slot(struct slot *p_slot); +int pciehp_disable_slot(struct slot *p_slot); +int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev); static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 6462ac3b405..7f4836b8e71 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -453,13 +453,9 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ pci_set_drvdata(pdev, ctrl); - ctrl->bus = pdev->bus->number; /* ctrl bus */ - ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ - - ctrl->device = PCI_SLOT(pdev->devfn); - ctrl->function = PCI_FUNC(pdev->devfn); - dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, - ctrl->bus, ctrl->device, ctrl->function, pdev->irq); + dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", + __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); /* Setup the slot information structures */ rc = init_slots(ctrl); @@ -471,6 +467,11 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ + if (value) { + rc = pciehp_enable_slot(t_slot); + if (rc) /* -ENODEV: shouldn't happen, but deal with it */ + value = 0; + } if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) @@ -509,6 +510,24 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) static int pciehp_resume (struct pcie_device *dev) { printk("%s ENTRY\n", __FUNCTION__); + if (pciehp_force) { + struct pci_dev *pdev = dev->port; + struct controller *ctrl = pci_get_drvdata(pdev); + struct slot *t_slot; + u8 status; + + /* reinitialize the chipset's event detection logic */ + pcie_init_hardware_part2(ctrl, dev); + + t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); + + /* Check if slot is occupied */ + t_slot->hpc_ops->get_adapter_status(t_slot, &status); + if (status) + pciehp_enable_slot(t_slot); + else + pciehp_disable_slot(t_slot); + } return 0; } #endif diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f1e0966cee9..b23061c5611 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -37,8 +37,6 @@ #include "pciehp.h" static void interrupt_event_handler(struct work_struct *work); -static int pciehp_enable_slot(struct slot *p_slot); -static int pciehp_disable_slot(struct slot *p_slot); static int queue_interrupt_event(struct slot *p_slot, u32 event_type) { @@ -197,12 +195,6 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) __FUNCTION__); return; } - /* - * After turning power off, we must wait for at least - * 1 second before taking any action that relies on - * power having been removed from the slot/adapter. - */ - msleep(1000); } } @@ -215,15 +207,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) */ static int board_added(struct slot *p_slot) { - u8 hp_slot; int retval = 0; struct controller *ctrl = p_slot->ctrl; - hp_slot = p_slot->device - ctrl->slot_device_offset; - dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n", __FUNCTION__, p_slot->device, - ctrl->slot_device_offset, hp_slot); + ctrl->slot_device_offset, p_slot->hp_slot); if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ @@ -281,8 +270,6 @@ err_exit: */ static int remove_board(struct slot *p_slot) { - u8 device; - u8 hp_slot; int retval = 0; struct controller *ctrl = p_slot->ctrl; @@ -290,11 +277,7 @@ static int remove_board(struct slot *p_slot) if (retval) return retval; - device = p_slot->device; - hp_slot = p_slot->device - ctrl->slot_device_offset; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot); if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ @@ -621,12 +604,6 @@ int pciehp_disable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } - /* - * After turning power off, we must wait for at least - * 1 second before taking any action that relies on - * power having been removed from the slot/adapter. - */ - msleep(1000); } ret = remove_board(p_slot); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 06d025b8b13..6eba9b2cfb9 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot) return retval; } +static inline int pcie_mask_bad_dllp(struct controller *ctrl) +{ + struct pci_dev *dev = ctrl->pci_dev; + int pos; + u32 reg; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return 0; + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); + if (reg & PCI_ERR_COR_BAD_DLLP) + return 0; + reg |= PCI_ERR_COR_BAD_DLLP; + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); + return 1; +} + +static inline void pcie_unmask_bad_dllp(struct controller *ctrl) +{ + struct pci_dev *dev = ctrl->pci_dev; + u32 reg; + int pos; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return; + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); + if (!(reg & PCI_ERR_COR_BAD_DLLP)) + return; + reg &= ~PCI_ERR_COR_BAD_DLLP; + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); +} + static int hpc_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; int retval = 0; + int changed; dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); + /* + * Set Bad DLLP Mask bit in Correctable Error Mask + * Register. This is the workaround against Bad DLLP error + * that sometimes happens during turning power off the slot + * which conforms to PCI Express 1.0a spec. + */ + changed = pcie_mask_bad_dllp(ctrl); + slot_cmd = POWER_OFF; cmd_mask = PWR_CTRL; /* @@ -674,6 +716,16 @@ static int hpc_power_off_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. + */ + msleep(1000); + + if (changed) + pcie_unmask_bad_dllp(ctrl); + return retval; } @@ -1067,13 +1119,143 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif -int pcie_init(struct controller * ctrl, struct pcie_device *dev) +static int pcie_init_hardware_part1(struct controller *ctrl, + struct pcie_device *dev) +{ + int rc; + u16 temp_word; + u32 slot_cap; + u16 slot_status; + + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); + if (rc) { + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); + return -1; + } + + /* Mask Hot-plug Interrupt Enable */ + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + return -1; + } + + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | + 0x00; + + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + if (rc) { + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + return -1; + } + + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (rc) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + return -1; + } + + temp_word = 0x1F; /* Clear all events */ + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); + if (rc) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + return -1; + } + return 0; +} + +int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { int rc; u16 temp_word; - u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; + u16 slot_status; + + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + goto abort; + } + + intr_enable = intr_enable | PRSN_DETECT_ENABLE; + + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); + if (rc) { + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); + goto abort; + } + + if (ATTN_BUTTN(slot_cap)) + intr_enable = intr_enable | ATTN_BUTTN_ENABLE; + + if (POWER_CTRL(slot_cap)) + intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; + + if (MRL_SENS(slot_cap)) + intr_enable = intr_enable | MRL_DETECT_ENABLE; + + temp_word = (temp_word & ~intr_enable) | intr_enable; + + if (pciehp_poll_mode) { + temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; + } else { + temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; + } + + /* + * Unmask Hot-plug Interrupt Enable for the interrupt + * notification mechanism case. + */ + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + if (rc) { + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + goto abort; + } + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (rc) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + goto abort_disable_intr; + } + + temp_word = 0x1F; /* Clear all events */ + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); + if (rc) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + goto abort_disable_intr; + } + + if (pciehp_force) { + dbg("Bypassing BIOS check for pciehp use on %s\n", + pci_name(ctrl->pci_dev)); + } else { + rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); + if (rc) + goto abort_disable_intr; + } + + return 0; + + /* We end up here for the many possible ways to fail this API. */ +abort_disable_intr: + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (!rc) { + temp_word &= ~(intr_enable | HP_INTR_ENABLE); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + } + if (rc) + err("%s : disabling interrupts failed\n", __FUNCTION__); +abort: + return -1; +} + +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + int rc; + u16 cap_reg; + u32 slot_cap; int cap_base; u16 slot_status, slot_ctrl; struct pci_dev *pdev; @@ -1084,9 +1266,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", __FUNCTION__, pdev->vendor, pdev->device); - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { + cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap_base == 0) { dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } ctrl->cap_base = cap_base; @@ -1096,7 +1279,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = pciehp_readw(ctrl, CAPREG, &cap_reg); if (rc) { err("%s: Cannot read CAPREG register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); @@ -1106,26 +1289,26 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { dbg("%s : This is not a root port or the port is not " "connected to a slot\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTCAP offset %x slot_cap %x\n", __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } /* For debugging purpose */ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTSTATUS offset %x slot_status %x\n", __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); @@ -1133,7 +1316,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); @@ -1161,36 +1344,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->first_slot = slot_cap >> 19; ctrl->ctrlcap = slot_cap & 0x0000007f; - /* Mask Hot-plug Interrupt Enable */ - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - dbg("%s: SLOTCTRL %x value read %x\n", - __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | - 0x00; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; - } + rc = pcie_init_hardware_part1(ctrl, dev); + if (rc) + goto abort; if (pciehp_poll_mode) { /* Install interrupt polling timer. Start with 10 sec delay */ @@ -1206,7 +1362,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); - goto abort_free_ctlr; + goto abort; } } dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, @@ -1224,82 +1380,16 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) } } - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_irq; + rc = pcie_init_hardware_part2(ctrl, dev); + if (rc == 0) { + ctrl->hpc_ops = &pciehp_hpc_ops; + return 0; } - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; - - temp_word = (temp_word & ~intr_enable) | intr_enable; - - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - - /* - * Unmask Hot-plug Interrupt Enable for the interrupt - * notification mechanism case. - */ - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); - goto abort_free_irq; - } - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_disable_intr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); - goto abort_disable_intr; - } - - if (pciehp_force) { - dbg("Bypassing BIOS check for pciehp use on %s\n", - pci_name(ctrl->pci_dev)); - } else { - rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); - if (rc) - goto abort_disable_intr; - } - - ctrl->hpc_ops = &pciehp_hpc_ops; - - return 0; - - /* We end up here for the many possible ways to fail this API. */ -abort_disable_intr: - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (!rc) { - temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - } - if (rc) - err("%s : disabling interrupts failed\n", __FUNCTION__); - abort_free_irq: if (pciehp_poll_mode) del_timer_sync(&ctrl->poll_timer); else free_irq(ctrl->pci_dev->irq, ctrl); - -abort_free_ctlr: +abort: return -1; } diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index c424aded13f..dd50713966d 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -105,12 +105,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) } /* Find Advanced Error Reporting Enhanced Capability */ - pos = 256; - do { - pci_read_config_dword(dev, pos, ®32); - if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) - break; - } while ((pos = PCI_EXT_CAP_NEXT(reg32))); + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (!pos) return; @@ -248,11 +243,15 @@ int pciehp_unconfigure_device(struct slot *p_slot) u8 bctl = 0; u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + u16 command; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); + if (ret) + presence = 0; - for (j=0; j<8 ; j++) { + for (j = 0; j < 8; j++) { struct pci_dev* temp = pci_get_slot(parent, (p_slot->device << 3) | j); if (!temp) @@ -263,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot) pci_dev_put(temp); continue; } - if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - ret = p_slot->hpc_ops->get_adapter_status(p_slot, - &presence); - if (!ret && presence) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, - &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", - pci_name(temp)); - pci_dev_put(temp); - continue; - } + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", + pci_name(temp)); + pci_dev_put(temp); + continue; } } pci_remove_bus_device(temp); + /* + * Ensure that no new Requests will be generated from + * the device. + */ + if (presence) { + pci_read_config_word(temp, PCI_COMMAND, &command); + command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + command |= PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(temp, PCI_COMMAND, command); + } pci_dev_put(temp); } /* @@ -288,4 +292,3 @@ int pciehp_unconfigure_device(struct slot *p_slot) return rc; } - diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index c822a779653..7d5921b1ee7 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -74,7 +74,6 @@ struct slot { u32 type; u32 power_domain; char *name; - char *location; struct device_node *dn; struct pci_bus *bus; struct list_head *pci_devs; diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0de84533cd8..6571e9b4c2e 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -64,19 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) return rc; } -static void set_slot_name(struct slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *bridge; - - bridge = bus->self; - if (bridge) - strcpy(slot->name, pci_name(bridge)); - else - sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), - bus->number); -} - /** * rpaphp_enable_slot - record slot state, config pci device * @slot: target &slot @@ -115,7 +102,6 @@ int rpaphp_enable_slot(struct slot *slot) info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; - set_slot_name(slot); /* if there's an adapter in the slot, go add the pci devices */ if (state == PRESENT) { diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index d4ee8723fcb..8ad3debb379 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -33,23 +33,31 @@ #include <asm/rtas.h> #include "rpaphp.h" -static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) +static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf) { - char *value; - int retval = -ENOENT; + int retval; struct slot *slot = (struct slot *)php_slot->private; + struct pci_bus *bus; if (!slot) - return retval; + return -ENOENT; + + bus = slot->bus; + if (!bus) + return -ENOENT; + + if (bus->self) + retval = sprintf(buf, pci_name(bus->self)); + else + retval = sprintf(buf, "%04x:%02x:00.0", + pci_domain_nr(bus), bus->number); - value = slot->location; - retval = sprintf (buf, "%s\n", value); return retval; } -static struct hotplug_slot_attribute php_attr_location = { - .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, - .show = location_read_file, +static struct hotplug_slot_attribute php_attr_address = { + .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, + .show = address_read_file, }; /* free up the memory used by a slot */ @@ -64,7 +72,6 @@ void dealloc_slot_struct(struct slot *slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); - kfree(slot->location); kfree(slot); } @@ -83,16 +90,13 @@ struct slot *alloc_slot_struct(struct device_node *dn, GFP_KERNEL); if (!slot->hotplug_slot->info) goto error_hpslot; - slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL); + slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); if (!slot->hotplug_slot->name) goto error_info; - slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); - if (!slot->location) - goto error_name; slot->name = slot->hotplug_slot->name; + strcpy(slot->name, drc_name); slot->dn = dn; slot->index = drc_index; - strcpy(slot->location, drc_name); slot->power_domain = power_domain; slot->hotplug_slot->private = slot; slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; @@ -100,8 +104,6 @@ struct slot *alloc_slot_struct(struct device_node *dn, return (slot); -error_name: - kfree(slot->hotplug_slot->name); error_info: kfree(slot->hotplug_slot->info); error_hpslot: @@ -133,8 +135,8 @@ int rpaphp_deregister_slot(struct slot *slot) list_del(&slot->rpaphp_slot_list); - /* remove "phy_location" file */ - sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr); + /* remove "address" file */ + sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr); retval = pci_hp_deregister(php_slot); if (retval) @@ -166,8 +168,8 @@ int rpaphp_register_slot(struct slot *slot) return retval; } - /* create "phy_location" file */ - retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr); + /* create "address" file */ + retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr); if (retval) { err("sysfs_create_file failed with error %d\n", retval); goto sysfs_fail; @@ -175,8 +177,7 @@ int rpaphp_register_slot(struct slot *slot) /* add slot to our internal list */ list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); - info("Slot [%s](PCI location=%s) registered\n", slot->name, - slot->location); + info("Slot [%s] registered\n", slot->name); return 0; sysfs_fail: diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 5183a45d45b..e8aa138128c 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -597,7 +597,7 @@ static void hpc_release_ctlr(struct controller *ctrl) cleanup_slots(ctrl); /* - * Mask SERR and System Interrut generation + * Mask SERR and System Interrupt generation */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index e079a5237c9..4e01df99681 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1781,7 +1781,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain, /* * First try to allocate an io virtual address in * DMA_32BIT_MASK and if that fails then try allocating - * from higer range + * from higher range */ iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK); if (!iova) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 07c9f09c856..26938da8f43 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -25,6 +25,51 @@ static int pci_msi_enable = 1; +/* Arch hooks */ + +int __attribute__ ((weak)) +arch_msi_check_device(struct pci_dev *dev, int nvec, int type) +{ + return 0; +} + +int __attribute__ ((weak)) +arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) +{ + return 0; +} + +int __attribute__ ((weak)) +arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct msi_desc *entry; + int ret; + + list_for_each_entry(entry, &dev->msi_list, list) { + ret = arch_setup_msi_irq(dev, entry); + if (ret) + return ret; + } + + return 0; +} + +void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) +{ + return; +} + +void __attribute__ ((weak)) +arch_teardown_msi_irqs(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (entry->irq != 0) + arch_teardown_msi_irq(entry->irq); + } +} + static void msi_set_enable(struct pci_dev *dev, int enable) { int pos; @@ -230,7 +275,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable) pci_intx(dev, enable); } -#ifdef CONFIG_PM static void __pci_restore_msi_state(struct pci_dev *dev) { int pos; @@ -288,7 +332,7 @@ void pci_restore_msi_state(struct pci_dev *dev) __pci_restore_msi_state(dev); __pci_restore_msix_state(dev); } -#endif /* CONFIG_PM */ +EXPORT_SYMBOL_GPL(pci_restore_msi_state); /** * msi_capability_init - configure device's MSI capability structure @@ -683,49 +727,3 @@ void pci_msi_init_pci_dev(struct pci_dev *dev) { INIT_LIST_HEAD(&dev->msi_list); } - - -/* Arch hooks */ - -int __attribute__ ((weak)) -arch_msi_check_device(struct pci_dev* dev, int nvec, int type) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ - struct msi_desc *entry; - int ret; - - list_for_each_entry(entry, &dev->msi_list, list) { - ret = arch_setup_msi_irq(dev, entry); - if (ret) - return ret; - } - - return 0; -} - -void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) -{ - return; -} - -void __attribute__ ((weak)) -arch_teardown_msi_irqs(struct pci_dev *dev) -{ - struct msi_desc *entry; - - list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq != 0) - arch_teardown_msi_irq(entry->irq); - } -} diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 5c6a5d04300..e569645d59e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -156,13 +156,13 @@ run_osc_out: } /** - * pci_osc_support_set - register OS support to Firmware + * __pci_osc_support_set - register OS support to Firmware * @flags: OS support bits * * Update OS support fields and doing a _OSC Query to obtain an update * from Firmware on supported control bits. **/ -acpi_status pci_osc_support_set(u32 flags) +acpi_status __pci_osc_support_set(u32 flags, const char *hid) { u32 temp; acpi_status retval; @@ -176,7 +176,7 @@ acpi_status pci_osc_support_set(u32 flags) temp = ctrlset_buf[OSC_CONTROL_TYPE]; ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; - acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_get_devices(hid, acpi_query_osc, ctrlset_buf, (void **) &retval ); @@ -188,7 +188,6 @@ acpi_status pci_osc_support_set(u32 flags) } return AE_OK; } -EXPORT_SYMBOL(pci_osc_support_set); /** * pci_osc_control_set - commit requested control to Firmware diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c4fa35d1dd7..e571c72e675 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -186,13 +186,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, set_cpus_allowed(current, node_to_cpumask(node)); /* And set default memory allocation policy */ oldpol = current->mempolicy; - current->mempolicy = &default_policy; - mpol_get(current->mempolicy); + current->mempolicy = NULL; /* fall back to system default policy */ #endif error = drv->probe(dev, id); #ifdef CONFIG_NUMA set_cpus_allowed(current, oldmask); - mpol_free(current->mempolicy); current->mempolicy = oldpol; #endif return error; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7d1877341aa..abf4203304e 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -21,6 +21,7 @@ #include <linux/topology.h> #include <linux/mm.h> #include <linux/capability.h> +#include <linux/aspm.h> #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -358,7 +359,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); /* Only support 1, 2 or 4 byte accesses */ @@ -383,7 +384,7 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); /* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) @@ -407,7 +408,7 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, struct vm_area_struct *vma) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); return pci_mmap_legacy_page_range(bus, vma); @@ -650,6 +651,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) if (pcibios_add_platform_entries(pdev)) goto err_rom_file; + pcie_aspm_create_sysfs_dev_files(pdev); + return 0; err_rom_file: @@ -679,6 +682,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) if (!sysfs_initialized) return; + pcie_aspm_remove_sysfs_dev_files(pdev); + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7d4ce906d20..b3e9294e4a0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -18,6 +18,7 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/log2.h> +#include <linux/aspm.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -314,6 +315,24 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) } EXPORT_SYMBOL_GPL(pci_find_ht_capability); +void pcie_wait_pending_transaction(struct pci_dev *dev) +{ + int pos; + u16 reg16; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return; + while (1) { + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); + if (!(reg16 & PCI_EXP_DEVSTA_TRPND)) + break; + cpu_relax(); + } + +} +EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction); + /** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched @@ -353,7 +372,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * Restore the BAR values for a given device, so as to make it * accessible by its driver. */ -void +static void pci_restore_bars(struct pci_dev *dev) { int i, numres; @@ -501,6 +520,9 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (need_restore) pci_restore_bars(dev); + if (dev->bus->self) + pcie_aspm_pm_state_change(dev->bus->self); + return 0; } @@ -551,6 +573,7 @@ static int pci_save_pcie_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (pos <= 0) @@ -559,6 +582,8 @@ static int pci_save_pcie_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -569,7 +594,9 @@ static int pci_save_pcie_state(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_EXP; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -597,14 +624,17 @@ static int pci_save_pcix_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pos <= 0) return 0; - save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -612,7 +642,9 @@ static int pci_save_pcix_state(struct pci_dev *dev) cap = (u16 *)&save_state->data[0]; pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_PCIX; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -713,23 +745,19 @@ int pci_reenable_device(struct pci_dev *dev) return 0; } -/** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized - * @bars: bitmask of BAR's that must be configured - * - * Initialize device before it's used by a driver. Ask low-level code - * to enable selected I/O and memory resources. Wake up the device if it - * was suspended. Beware, this function can fail. - */ -int -pci_enable_device_bars(struct pci_dev *dev, int bars) +static int __pci_enable_device_flags(struct pci_dev *dev, + resource_size_t flags) { int err; + int i, bars = 0; if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + err = do_pci_enable_device(dev, bars); if (err < 0) atomic_dec(&dev->enable_cnt); @@ -737,6 +765,32 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) } /** + * pci_enable_device_io - Initialize a device for use with IO space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_io(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_IO); +} + +/** + * pci_enable_device_mem - Initialize a device for use with Memory space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable Memory resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_mem(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_MEM); +} + +/** * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * @@ -749,7 +803,7 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) */ int pci_enable_device(struct pci_dev *dev) { - return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); + return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } /* @@ -885,6 +939,9 @@ pci_disable_device(struct pci_dev *dev) if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; + /* Wait for all transactions are finished before disabling the device */ + pcie_wait_pending_transaction(dev); + pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; @@ -1619,9 +1676,9 @@ early_param("pci", pci_setup); device_initcall(pci_init); -EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_reenable_device); -EXPORT_SYMBOL(pci_enable_device_bars); +EXPORT_SYMBOL(pci_enable_device_io); +EXPORT_SYMBOL(pci_enable_device_mem); EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pcim_enable_device); EXPORT_SYMBOL(pcim_pin_device); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fc87e14b50d..eabeb1f2ec9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -6,8 +6,10 @@ extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); /* Firmware callbacks */ -extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); -extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); +extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, + pm_message_t state); +extern int (*platform_pci_set_power_state)(struct pci_dev *dev, + pci_power_t state); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); @@ -45,12 +47,6 @@ static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif -#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) -void pci_restore_msi_state(struct pci_dev *dev); -#else -static inline void pci_restore_msi_state(struct pci_dev *dev) {} -#endif - #ifdef CONFIG_PCIEAER void pci_no_aer(void); #else @@ -68,14 +64,14 @@ static inline int pci_no_d1d2(struct pci_dev *dev) } extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; -extern struct class_device_attribute class_device_attr_cpuaffinity; +extern struct device_attribute dev_attr_cpuaffinity; /** * pci_match_one_device - Tell if a PCI device structure has a matching * PCI device id structure * @id: single PCI device id structure to match * @dev: the PCI device structure to match against - * + * * Returns the matching pci_device_id structure or %NULL if there is no match. */ static inline const struct pci_device_id * diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 287a9311716..60104cf9879 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -26,3 +26,23 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. source "drivers/pci/pcie/aer/Kconfig" + +# +# PCI Express ASPM +# +config PCIEASPM + bool "PCI Express ASPM support(Experimental)" + depends on PCI && EXPERIMENTAL + default y + help + This enables PCI Express ASPM (Active State Power Management) and + Clock Power Management. ASPM supports state L0/L0s/L1. + + When in doubt, say N. +config PCIEASPM_DEBUG + bool "Debug PCI Express ASPM" + depends on PCIEASPM + default n + help + This enables PCI Express ASPM debug support. It will add per-device + interface to control ASPM. diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index e00fb99acf4..11f6bb1eae2 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -2,6 +2,9 @@ # Makefile for PCI-Express PORT Driver # +# Build PCI Express ASPM if needed +obj-$(CONFIG_PCIEASPM) += aspm.o + pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 1a1eb45a779..8c199ae84f6 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -31,26 +31,16 @@ int aer_osc_setup(struct pcie_device *pciedev) { acpi_status status = AE_NOT_FOUND; struct pci_dev *pdev = pciedev->port; - acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev); - struct pci_bus *parent; + acpi_handle handle = 0; - while (!handle) { - if (!pdev || !pdev->bus->parent) - break; - parent = pdev->bus->parent; - if (!parent->self) - /* Parent must be a host bridge */ - handle = acpi_get_pci_rootbridge_handle( - pci_domain_nr(parent), - parent->number); - else - handle = DEVICE_ACPI_HANDLE( - &(parent->self->dev)); - pdev = parent->self; - } + /* Find root host bridge */ + while (pdev->bus && pdev->bus->self) + pdev = pdev->bus->self; + handle = acpi_get_pci_rootbridge_handle( + pci_domain_nr(pdev->bus), pdev->bus->number); if (handle) { - pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); + pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c new file mode 100644 index 00000000000..1a5adeb10c9 --- /dev/null +++ b/drivers/pci/pcie/aspm.c @@ -0,0 +1,802 @@ +/* + * File: drivers/pci/pcie/aspm.c + * Enabling PCIE link L0s/L1 state and Clock Power Management + * + * Copyright (C) 2007 Intel + * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) + * Copyright (C) Shaohua Li (shaohua.li@intel.com) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/pci.h> +#include <linux/pci_regs.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/aspm.h> +#include <acpi/acpi_bus.h> +#include <linux/pci-acpi.h> +#include "../pci.h" + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "pcie_aspm." + +struct endpoint_state { + unsigned int l0s_acceptable_latency; + unsigned int l1_acceptable_latency; +}; + +struct pcie_link_state { + struct list_head sibiling; + struct pci_dev *pdev; + + /* ASPM state */ + unsigned int support_state; + unsigned int enabled_state; + unsigned int bios_aspm_state; + /* upstream component */ + unsigned int l0s_upper_latency; + unsigned int l1_upper_latency; + /* downstream component */ + unsigned int l0s_down_latency; + unsigned int l1_down_latency; + /* Clock PM state*/ + unsigned int clk_pm_capable; + unsigned int clk_pm_enabled; + unsigned int bios_clk_state; + + /* + * A pcie downstream port only has one slot under it, so at most there + * are 8 functions + */ + struct endpoint_state endpoints[8]; +}; + +static int aspm_disabled; +static DEFINE_MUTEX(aspm_lock); +static LIST_HEAD(link_list); + +#define POLICY_DEFAULT 0 /* BIOS default setting */ +#define POLICY_PERFORMANCE 1 /* high performance */ +#define POLICY_POWERSAVE 2 /* high power saving */ +static int aspm_policy; +static const char *policy_str[] = { + [POLICY_DEFAULT] = "default", + [POLICY_PERFORMANCE] = "performance", + [POLICY_POWERSAVE] = "powersave" +}; + +static int policy_to_aspm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Enable ASPM L0s/L1 */ + return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + case POLICY_DEFAULT: + return link_state->bios_aspm_state; + } + return 0; +} + +static int policy_to_clkpm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Disable Clock PM */ + return 1; + case POLICY_DEFAULT: + return link_state->bios_clk_state; + } + return 0; +} + +static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +{ + struct pci_dev *child_dev; + int pos; + u16 reg16; + struct pcie_link_state *link_state = pdev->link_state; + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (enable) + reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; + else + reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + } + link_state->clk_pm_enabled = !!enable; +} + +static void pcie_check_clock_pm(struct pci_dev *pdev) +{ + int pos; + u32 reg32; + u16 reg16; + int capable = 1, enabled = 1; + struct pci_dev *child_dev; + struct pcie_link_state *link_state = pdev->link_state; + + /* All functions should have the same cap and state, take the worst */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { + capable = 0; + enabled = 0; + break; + } + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) + enabled = 0; + } + link_state->clk_pm_capable = capable; + link_state->clk_pm_enabled = enabled; + link_state->bios_clk_state = enabled; + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); +} + +/* + * pcie_aspm_configure_common_clock: check if the 2 ends of a link + * could use common clock. If they are, configure them to use the + * common clock. That will reduce the ASPM state exit latency. + */ +static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +{ + int pos, child_pos; + u16 reg16 = 0; + struct pci_dev *child_dev; + int same_clock = 1; + + /* + * all functions of a slot should have the same Slot Clock + * Configuration, so just check one function + * */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + BUG_ON(!child_dev->is_pcie); + + /* Check downstream component if bit Slot Clock Configuration is 1 */ + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Check upstream component if bit Slot Clock Configuration is 1 */ + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Configure downstream component, all functions */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + reg16); + } + + /* Configure upstream component */ + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* retrain link */ + reg16 |= PCI_EXP_LNKCTL_RL; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* Wait for link training end */ + while (1) { + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + break; + cpu_relax(); + } +} + +/* + * calc_L0S_latency: Convert L0s latency encoding to ns + */ +static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 64; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 5*1000; /* > 4us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +/* + * calc_L1_latency: Convert L1 latency encoding to ns + */ +static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 1000; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 65*1000; /* > 64us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, + unsigned int *l0s, unsigned int *l1, unsigned int *enabled) +{ + int pos; + u16 reg16; + u32 reg32; + unsigned int latency; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); + *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; + if (*state != PCIE_LINK_STATE_L0S && + *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + * state = 0; + if (*state == 0) + return; + + latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_L0S_latency(latency, 0); + if (*state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_L1_latency(latency, 0); + } + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); +} + +static void pcie_aspm_cap_init(struct pci_dev *pdev) +{ + struct pci_dev *child_dev; + u32 state, tmp; + struct pcie_link_state *link_state = pdev->link_state; + + /* upstream component states */ + pcie_aspm_get_cap_device(pdev, &link_state->support_state, + &link_state->l0s_upper_latency, + &link_state->l1_upper_latency, + &link_state->enabled_state); + /* downstream component states, all functions have the same setting */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + pcie_aspm_get_cap_device(child_dev, &state, + &link_state->l0s_down_latency, + &link_state->l1_down_latency, + &tmp); + link_state->support_state &= state; + if (!link_state->support_state) + return; + link_state->enabled_state &= link_state->support_state; + link_state->bios_aspm_state = link_state->enabled_state; + + /* ENDPOINT states*/ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + int pos; + u32 reg32; + unsigned int latency; + struct endpoint_state *ep_state = + &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + + if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + continue; + + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); + latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + latency = calc_L0S_latency(latency, 1); + ep_state->l0s_acceptable_latency = latency; + if (link_state->support_state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + latency = calc_L1_latency(latency, 1); + ep_state->l1_acceptable_latency = latency; + } + } +} + +static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *parent_dev, *tmp_dev; + unsigned int latency, l1_latency = 0; + struct pcie_link_state *link_state; + struct endpoint_state *ep_state; + + parent_dev = pdev->bus->self; + link_state = parent_dev->link_state; + state &= link_state->support_state; + if (state == 0) + return 0; + ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + + /* + * Check latency for endpoint device. + * TBD: The latency from the endpoint to root complex vary per + * switch's upstream link state above the device. Here we just do a + * simple check which assumes all links above the device can be in L1 + * state, that is we just consider the worst case. If switch's upstream + * link can't be put into L0S/L1, then our check is too strictly. + */ + tmp_dev = pdev; + while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { + parent_dev = tmp_dev->bus->self; + link_state = parent_dev->link_state; + if (state & PCIE_LINK_STATE_L0S) { + latency = max_t(unsigned int, + link_state->l0s_upper_latency, + link_state->l0s_down_latency); + if (latency > ep_state->l0s_acceptable_latency) + state &= ~PCIE_LINK_STATE_L0S; + } + if (state & PCIE_LINK_STATE_L1) { + latency = max_t(unsigned int, + link_state->l1_upper_latency, + link_state->l1_down_latency); + if (latency + l1_latency > + ep_state->l1_acceptable_latency) + state &= ~PCIE_LINK_STATE_L1; + } + if (!parent_dev->bus->self) /* parent_dev is a root port */ + break; + else { + /* + * parent_dev is the downstream port of a switch, make + * tmp_dev the upstream port of the switch + */ + tmp_dev = parent_dev->bus->self; + /* + * every switch on the path to root complex need 1 more + * microsecond for L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + l1_latency += 1000; + } + } + return state; +} + +static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *child_dev; + + /* If no child, disable the link */ + if (list_empty(&pdev->subordinate->devices)) + return 0; + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + * */ + state = 0; + break; + } + if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + continue; + /* Device not in D0 doesn't need check latency */ + if (child_dev->current_state == PCI_D1 || + child_dev->current_state == PCI_D2 || + child_dev->current_state == PCI_D3hot || + child_dev->current_state == PCI_D3cold) + continue; + state = __pcie_aspm_check_state_one(child_dev, state); + } + return state; +} + +static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) +{ + u16 reg16; + int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~0x3; + reg16 |= state; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); +} + +static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +{ + struct pci_dev *child_dev; + int valid = 1; + struct pcie_link_state *link_state = pdev->link_state; + + /* + * if the downstream component has pci bridge function, don't do ASPM + * now + */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + valid = 0; + break; + } + } + if (!valid) + return; + + /* + * spec 2.0 suggests all functions should be configured the same + * setting for ASPM. Enabling ASPM L1 should be done in upstream + * component first and then downstream, and vice versa for disabling + * ASPM L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + __pcie_aspm_config_one_dev(pdev, state); + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) + __pcie_aspm_config_one_dev(child_dev, state); + + if (!(state & PCIE_LINK_STATE_L1)) + __pcie_aspm_config_one_dev(pdev, state); + + link_state->enabled_state = state; +} + +static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (link_state->support_state == 0) + return; + state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + + /* state 0 means disabling aspm */ + state = pcie_aspm_check_state(pdev, state); + if (link_state->enabled_state == state) + return; + __pcie_aspm_config_link(pdev, state); +} + +/* + * pcie_aspm_configure_link_state: enable/disable PCI express link state + * @pdev: the root port or switch downstream port + */ +static void pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + __pcie_aspm_configure_link_state(pdev, state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +static void free_link_state(struct pci_dev *pdev) +{ + kfree(pdev->link_state); + pdev->link_state = NULL; +} + +/* + * pcie_aspm_init_link_state: Initiate PCI express link state. + * It is called after the pcie and its children devices are scaned. + * @pdev: the root port or switch downstream port + */ +void pcie_aspm_init_link_state(struct pci_dev *pdev) +{ + unsigned int state; + struct pcie_link_state *link_state; + int error = 0; + + if (aspm_disabled || !pdev->is_pcie || pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + if (list_empty(&pdev->subordinate->devices)) + goto out; + + mutex_lock(&aspm_lock); + + link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); + if (!link_state) + goto unlock_out; + pdev->link_state = link_state; + + pcie_aspm_configure_common_clock(pdev); + + pcie_aspm_cap_init(pdev); + + /* config link state to avoid BIOS error */ + state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev)); + __pcie_aspm_config_link(pdev, state); + + pcie_check_clock_pm(pdev); + + link_state->pdev = pdev; + list_add(&link_state->sibiling, &link_list); + +unlock_out: + if (error) + free_link_state(pdev); + mutex_unlock(&aspm_lock); +out: + up_read(&pci_bus_sem); +} + +/* @pdev: the endpoint device */ +void pcie_aspm_exit_link_state(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state = parent->link_state; + + if (aspm_disabled || !pdev->is_pcie || !parent || !link_state) + return; + if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + + /* + * All PCIe functions are in one slot, remove one function will remove + * the the whole slot, so just wait + */ + if (!list_empty(&parent->subordinate->devices)) + goto out; + + /* All functions are removed, so just disable ASPM for the link */ + __pcie_aspm_config_one_dev(parent, 0); + list_del(&link_state->sibiling); + /* Clock PM is for endpoint device */ + + free_link_state(parent); +out: + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +/* @pdev: the root port or switch downstream port */ +void pcie_aspm_pm_state_change(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (aspm_disabled || !pdev->is_pcie || !pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + /* + * devices changed PM state, we should recheck if latency meets all + * functions' requirement + */ + pcie_aspm_configure_link_state(pdev, link_state->enabled_state); +} + +/* + * pci_disable_link_state - disable pci device's link state, so the link will + * never enter specific states + */ +void pci_disable_link_state(struct pci_dev *pdev, int state) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state; + + if (aspm_disabled || !pdev->is_pcie) + return; + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || + pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) + parent = pdev; + if (!parent) + return; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + link_state = parent->link_state; + link_state->support_state &= + ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); + if (state & PCIE_LINK_STATE_CLKPM) + link_state->clk_pm_capable = 0; + + __pcie_aspm_configure_link_state(parent, link_state->enabled_state); + if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) + pcie_set_clock_pm(parent, 0); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} +EXPORT_SYMBOL(pci_disable_link_state); + +static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) +{ + int i; + struct pci_dev *pdev; + struct pcie_link_state *link_state; + + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) + break; + if (i >= ARRAY_SIZE(policy_str)) + return -EINVAL; + if (i == aspm_policy) + return 0; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + aspm_policy = i; + list_for_each_entry(link_state, &link_list, sibiling) { + pdev = link_state->pdev; + __pcie_aspm_configure_link_state(pdev, + policy_to_aspm_state(pdev)); + if (link_state->clk_pm_capable && + link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + + } + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + return 0; +} + +static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp) +{ + int i, cnt = 0; + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (i == aspm_policy) + cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]); + else + cnt += sprintf(buffer + cnt, "%s ", policy_str[i]); + return cnt; +} + +module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy, + NULL, 0644); + +#ifdef CONFIG_PCIEASPM_DEBUG +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->enabled_state); +} + +static ssize_t link_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + if (state >= 0 && state <= 3) { + /* setup link aspm state */ + pcie_aspm_configure_link_state(pci_device, state); + return n; + } + + return -EINVAL; +} + +static ssize_t clk_ctl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->clk_pm_enabled); +} + +static ssize_t clk_ctl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + pcie_set_clock_pm(pci_device, !!state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + + return n; +} + +static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store); +static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store); + +static char power_group[] = "power"; +void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} + +void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} +#endif + +static int __init pcie_aspm_disable(char *str) +{ + aspm_disabled = 1; + return 1; +} + +__setup("pcie_noaspm", pcie_aspm_disable); + +static int __init pcie_aspm_init(void) +{ + if (aspm_disabled) + return 0; + pci_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| + OSC_CLOCK_PWR_CAPABILITY_SUPPORT); + return 0; +} + +fs_initcall(pcie_aspm_init); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index b20a9b81dae..23d9eb07329 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -192,9 +192,8 @@ static int get_port_device_capability(struct pci_dev *dev) if (reg32 & SLOT_HP_CAPABLE_MASK) services |= PCIE_PORT_SERVICE_HP; } - /* PME Capable */ - pos = pci_find_capability(dev, PCI_CAP_ID_PME); - if (pos) + /* PME Capable - root port capability */ + if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT) services |= PCIE_PORT_SERVICE_PME; pos = PCI_CFG_SPACE_SIZE; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5fd585293e7..8b505bd925a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/cpumask.h> +#include <linux/aspm.h> #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -53,7 +54,7 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; b->legacy_io->read = pci_read_legacy_io; b->legacy_io->write = pci_write_legacy_io; - class_device_create_bin_file(&b->class_dev, b->legacy_io); + device_create_bin_file(&b->dev, b->legacy_io); /* Allocated above after the legacy_io struct */ b->legacy_mem = b->legacy_io + 1; @@ -61,15 +62,15 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_mem->size = 1024*1024; b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; b->legacy_mem->mmap = pci_mmap_legacy_mem; - class_device_create_bin_file(&b->class_dev, b->legacy_mem); + device_create_bin_file(&b->dev, b->legacy_mem); } } void pci_remove_legacy_files(struct pci_bus *b) { if (b->legacy_io) { - class_device_remove_bin_file(&b->class_dev, b->legacy_io); - class_device_remove_bin_file(&b->class_dev, b->legacy_mem); + device_remove_bin_file(&b->dev, b->legacy_io); + device_remove_bin_file(&b->dev, b->legacy_mem); kfree(b->legacy_io); /* both are allocated here */ } } @@ -81,26 +82,27 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; } /* * PCI Bus Class Devices */ -static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, +static ssize_t pci_bus_show_cpuaffinity(struct device *dev, + struct device_attribute *attr, char *buf) { int ret; cpumask_t cpumask; - cpumask = pcibus_to_cpumask(to_pci_bus(class_dev)); + cpumask = pcibus_to_cpumask(to_pci_bus(dev)); ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask); if (ret < PAGE_SIZE) buf[ret++] = '\n'; return ret; } -CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); +DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); /* * PCI Bus Class */ -static void release_pcibus_dev(struct class_device *class_dev) +static void release_pcibus_dev(struct device *dev) { - struct pci_bus *pci_bus = to_pci_bus(class_dev); + struct pci_bus *pci_bus = to_pci_bus(dev); if (pci_bus->bridge) put_device(pci_bus->bridge); @@ -109,7 +111,7 @@ static void release_pcibus_dev(struct class_device *class_dev) static struct class pcibus_class = { .name = "pci_bus", - .release = &release_pcibus_dev, + .dev_release = &release_pcibus_dev, }; static int __init pcibus_class_init(void) @@ -392,7 +394,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { struct pci_bus *child; int i; - int retval; /* * Allocate a new bus, and inherit stuff from the parent.. @@ -408,15 +409,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) child->bus_flags = parent->bus_flags; child->bridge = get_device(&bridge->dev); - child->class_dev.class = &pcibus_class; - sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); - retval = class_device_register(&child->class_dev); - if (retval) - goto error_register; - retval = class_device_create_file(&child->class_dev, - &class_device_attr_cpuaffinity); - if (retval) - goto error_file_create; + /* initialize some portions of the bus device, but don't register it + * now as the parent is not properly set up yet. This device will get + * registered later in pci_bus_add_devices() + */ + child->dev.class = &pcibus_class; + sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr); /* * Set up the primary, secondary and subordinate @@ -434,12 +432,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) bridge->subordinate = child; return child; - -error_file_create: - class_device_unregister(&child->class_dev); -error_register: - kfree(child); - return NULL; } struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) @@ -471,8 +463,6 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) } } -unsigned int pci_scan_child_bus(struct pci_bus *bus); - /* * If it's a bridge, configure it and scan the bus behind it. * For CardBus bridges, we don't scan behind as the devices will @@ -641,13 +631,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass (child->number > bus->subordinate) || (child->number < bus->number) || (child->subordinate < bus->number)) { - pr_debug("PCI: Bus #%02x (-#%02x) is %s" + pr_debug("PCI: Bus #%02x (-#%02x) is %s " "hidden behind%s bridge #%02x (-#%02x)\n", child->number, child->subordinate, (bus->number > child->subordinate && bus->subordinate < child->number) ? - "wholly " : " partially", - bus->self->transparent ? " transparent" : " ", + "wholly" : "partially", + bus->self->transparent ? " transparent" : "", bus->number, bus->subordinate); } bus = bus->parent; @@ -971,6 +961,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) return dev; } +EXPORT_SYMBOL(pci_scan_single_device); /** * pci_scan_slot - scan a PCI slot on a bus for devices. @@ -1011,6 +1002,10 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) break; } } + + if (bus->self) + pcie_aspm_init_link_state(bus->self); + return nr; } @@ -1103,32 +1098,27 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge = get_device(dev); - b->class_dev.class = &pcibus_class; - sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus); - error = class_device_register(&b->class_dev); + b->dev.class = &pcibus_class; + b->dev.parent = b->bridge; + sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus); + error = device_register(&b->dev); if (error) goto class_dev_reg_err; - error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity); + error = device_create_file(&b->dev, &dev_attr_cpuaffinity); if (error) - goto class_dev_create_file_err; + goto dev_create_file_err; /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); - error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge"); - if (error) - goto sys_create_link_err; - b->number = b->secondary = bus; b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; return b; -sys_create_link_err: - class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity); -class_dev_create_file_err: - class_device_unregister(&b->class_dev); +dev_create_file_err: + device_unregister(&b->dev); class_dev_reg_err: device_unregister(dev); dev_reg_err: @@ -1140,7 +1130,6 @@ err_out: kfree(b); return NULL; } -EXPORT_SYMBOL_GPL(pci_create_bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) @@ -1159,7 +1148,6 @@ EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); -EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL_GPL(pci_scan_child_bus); #endif diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 716439e25dd..68aeeb7206d 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/smp_lock.h> #include <linux/capability.h> #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -202,15 +203,18 @@ struct pci_filp_private { int write_combine; }; -static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - const struct proc_dir_entry *dp = PDE(inode); + const struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); struct pci_dev *dev = dp->data; #ifdef HAVE_PCI_MMAP struct pci_filp_private *fpriv = file->private_data; #endif /* HAVE_PCI_MMAP */ int ret = 0; + lock_kernel(); + switch (cmd) { case PCIIOC_CONTROLLER: ret = pci_domain_nr(dev->bus); @@ -239,6 +243,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i break; }; + unlock_kernel(); return ret; } @@ -291,7 +296,7 @@ static const struct file_operations proc_bus_pci_operations = { .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, - .ioctl = proc_bus_pci_ioctl, + .unlocked_ioctl = proc_bus_pci_ioctl, #ifdef HAVE_PCI_MMAP .open = proc_bus_pci_open, .release = proc_bus_pci_release, @@ -370,7 +375,7 @@ static int show_device(struct seq_file *m, void *v) return 0; } -static struct seq_operations proc_bus_pci_devices_op = { +static const struct seq_operations proc_bus_pci_devices_op = { .start = pci_seq_start, .next = pci_seq_next, .stop = pci_seq_stop, @@ -480,7 +485,3 @@ static int __init pci_proc_init(void) __initcall(pci_proc_init); -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_proc_detach_bus); -#endif - diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 72e0bd5d80a..0a953d43b9a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/acpi.h> +#include <linux/kallsyms.h> #include "pci.h" /* The Mellanox Tavor device gives false positive parity errors @@ -46,14 +47,14 @@ static void quirk_passive_release(struct pci_dev *dev) while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d)); + dev_err(&d->dev, "PIIX3: Enabling Passive Release\n"); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release); /* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround but VIA don't answer queries. If you happen to have good contacts at VIA @@ -68,20 +69,20 @@ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) { if (!isa_dma_bridge_buggy) { isa_dma_bridge_buggy=1; - printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); + dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n"); } } /* * Its not totally clear which chipsets are the problematic ones * We know 82C586 and 82C596 variants are affected. */ -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs); int pci_pci_problems; EXPORT_SYMBOL(pci_pci_problems); @@ -92,12 +93,12 @@ EXPORT_SYMBOL(pci_pci_problems); static void __devinit quirk_nopcipci(struct pci_dev *dev) { if ((pci_pci_problems & PCIPCI_FAIL)==0) { - printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_FAIL; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci); static void __devinit quirk_nopciamd(struct pci_dev *dev) { @@ -105,11 +106,11 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev) pci_read_config_byte(dev, 0x08, &rev); if (rev == 0x13) { /* Erratum 24 */ - printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n"); + dev_info(&dev->dev, "Chipset erratum: Disabling direct PCI/AGP transfers\n"); pci_pci_problems |= PCIAGP_FAIL; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd); /* * Triton requires workarounds to be used by the drivers @@ -117,14 +118,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopci static void __devinit quirk_triton(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_TRITON)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_TRITON; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton); /* * VIA Apollo KT133 needs PCI latency patch @@ -139,25 +140,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir static void quirk_vialatency(struct pci_dev *dev) { struct pci_dev *p; - u8 rev; u8 busarb; /* Ok we have a potential problem chipset here. Now see if we have a buggy southbridge */ p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); if (p!=NULL) { - pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ /* Check for buggy part revisions */ - if (rev < 0x40 || rev > 0x42) + if (p->revision < 0x40 || p->revision > 0x42) goto exit; } else { p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); if (p==NULL) /* No problem parts */ goto exit; - pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* Check for buggy part revisions */ - if (rev < 0x10 || rev > 0x12) + if (p->revision < 0x10 || p->revision > 0x12) goto exit; } @@ -180,17 +178,17 @@ static void quirk_vialatency(struct pci_dev *dev) busarb &= ~(1<<5); busarb |= (1<<4); pci_write_config_byte(dev, 0x76, busarb); - printk(KERN_INFO "Applying VIA southbridge workaround.\n"); + dev_info(&dev->dev, "Applying VIA southbridge workaround\n"); exit: pci_dev_put(p); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency); /* Must restore this on a resume from RAM */ -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency); /* * VIA Apollo VP3 needs ETBF on BT848/878 @@ -198,20 +196,20 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_viala static void __devinit quirk_viaetbf(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VIAETBF; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf); static void __devinit quirk_vsfx(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VSFX)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VSFX; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx); /* * Ali Magik requires workarounds to be used by the drivers @@ -222,12 +220,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx static void __init quirk_alimagik(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik); /* * Natoma has some interesting boundary conditions with Zoran stuff @@ -236,16 +234,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimag static void __devinit quirk_natoma(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_NATOMA)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_NATOMA; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma); /* * This chip can cause PCI parity errors if config register 0xA0 is read @@ -255,7 +253,7 @@ static void __devinit quirk_citrine(struct pci_dev *dev) { dev->cfg_size = 0xA0; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine); /* * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. @@ -270,8 +268,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev) r->end = 0x3ffffff; } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr, const char *name) @@ -292,7 +290,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, pcibios_bus_to_resource(dev, res, &bus_region); pci_claim_resource(dev, nr); - printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); + dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); } } @@ -302,12 +300,12 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, */ static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) { - printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n"); + dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n"); /* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */ request_region(0x3b0, 0x0C, "RadeonIGP"); request_region(0x3d3, 0x01, "RadeonIGP"); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce); /* * Let's make the southbridge information explicit instead @@ -329,7 +327,7 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) pci_read_config_word(dev, 0xE2, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi); static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) { @@ -354,7 +352,7 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p * let's get enough confirmation reports first. */ base &= -size; - printk("%s PIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1); } static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) @@ -379,7 +377,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int * reserve it, but let's get enough confirmation reports first. */ base &= -size; - printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1); } /* @@ -418,8 +416,8 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20); piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi); /* * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at @@ -436,16 +434,16 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x58, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi); static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) { @@ -457,20 +455,20 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x48, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi); /* * VIA ACPI: One IO region pointed to by longword at @@ -486,7 +484,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi); /* * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at @@ -509,7 +507,7 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) smb &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi); /* * VIA VT8235 ISA Bridge: Two IO regions pointed to by words at @@ -551,14 +549,14 @@ static void quirk_via_ioapic(struct pci_dev *dev) else tmp = 0x1f; /* all known bits (4-0) routed to external APIC */ - printk(KERN_INFO "PCI: %sbling Via external APIC routing\n", + dev_info(&dev->dev, "%sbling VIA external APIC routing\n", tmp == 0 ? "Disa" : "Ena"); /* Offset 0x58: External APIC IRQ output control */ pci_write_config_byte (dev, 0x58, tmp); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); /* * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit. @@ -573,7 +571,7 @@ static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev) pci_read_config_byte(dev, 0x5B, &misc_control2); if (!(misc_control2 & BYPASS_APIC_DEASSERT)) { - printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n"); + dev_info(&dev->dev, "Bypassing VIA 8237 APIC De-Assert Message\n"); pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT); } } @@ -592,18 +590,18 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_v static void __devinit quirk_amd_ioapic(struct pci_dev *dev) { if (dev->revision >= 0x02) { - printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); - printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); + dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); + dev_warn(&dev->dev, " : booting with the \"noapic\" option\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic); static void __init quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); #define AMD8131_revA0 0x01 #define AMD8131_revB0 0x11 @@ -617,7 +615,7 @@ static void quirk_amd_8131_ioapic(struct pci_dev *dev) return; if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) { - printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); + dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n"); pci_read_config_byte( dev, AMD8131_MISC, &tmp); tmp &= ~(1 << AMD8131_NIOAMODE_BIT); pci_write_config_byte( dev, AMD8131_MISC, tmp); @@ -634,8 +632,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) { if (dev->subordinate && dev->revision <= 0x12) { - printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X " - "MMRBC\n", dev->revision); + dev_info(&dev->dev, "AMD8131 rev %x detected; " + "disabling PCI-X MMRBC\n", dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } @@ -660,8 +658,8 @@ static void __devinit quirk_via_acpi(struct pci_dev *d) if (irq && (irq != 2)) d->irq = irq; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi); /* @@ -742,8 +740,8 @@ static void quirk_via_vlink(struct pci_dev *dev) pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { - printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n", - pci_name(dev), irq, new_irq); + dev_info(&dev->dev, "VIA VLink IRQ fixup, from %d to %d\n", + irq, new_irq); udelay(15); /* unknown if delay really needed */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } @@ -761,7 +759,7 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev) pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id); /* * CardBus controllers have a legacy base address that enables them @@ -791,15 +789,15 @@ static void quirk_amd_ordering(struct pci_dev *dev) pci_read_config_dword(dev, 0x4C, &pcic); if ((pcic&6)!=6) { pcic |= 6; - printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n"); + dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n"); pci_write_config_dword(dev, 0x4C, pcic); pci_read_config_dword(dev, 0x84, &pcic); pcic |= (1<<23); /* Required in this mode */ pci_write_config_dword(dev, 0x84, pcic); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering); /* * DreamWorks provided workaround for Dunord I-3000 problem @@ -814,7 +812,7 @@ static void __devinit quirk_dunord ( struct pci_dev * dev ) r->start = 0; r->end = 0xffffff; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord); /* * i82380FB mobile docking controller: its PCI-to-PCI bridge @@ -826,8 +824,8 @@ static void __devinit quirk_transparent_bridge(struct pci_dev *dev) { dev->transparent = 1; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge); /* * Common misconfiguration of the MediaGX/Geode PCI master that will @@ -841,12 +839,12 @@ static void quirk_mediagx_master(struct pci_dev *dev) pci_read_config_byte(dev, 0x41, ®); if (reg & 2) { reg &= ~2; - printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); + dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); pci_write_config_byte(dev, 0x41, reg); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master); /* * Ensure C0 rev restreaming is off. This is normally done by @@ -863,11 +861,11 @@ static void quirk_disable_pxb(struct pci_dev *pdev) if (config & (1<<6)) { config &= ~(1<<6); pci_write_config_word(pdev, 0x40, config); - printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n"); + dev_info(&pdev->dev, "C0 revision 450NX. Disabling PCI restreaming\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); static void __devinit quirk_sb600_sata(struct pci_dev *pdev) @@ -902,7 +900,7 @@ static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev) /* PCI layer will sort out resources */ } } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide ); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide); /* * Intel 82801CAM ICH3-M datasheet says IDE modes must be the same @@ -914,7 +912,7 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev) pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) { - printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n"); + dev_info(&pdev->dev, "IDE mode mismatch; forcing legacy mode\n"); prog &= ~5; pdev->class &= ~5; pci_write_config_byte(pdev, PCI_CLASS_PROG, prog); @@ -929,7 +927,7 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge); /* @@ -1022,6 +1020,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } + else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB) + switch (dev->subsystem_device) { + case 0x12bf: /* HP xw4100 */ + asus_hides_smbus = 1; + } else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x099c: /* HP Compaq nx6110 */ @@ -1049,17 +1052,18 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) } } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge); static void asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -1073,25 +1077,25 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev) pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); if (val & 0x8) - printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); else - printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); + dev_info(&dev->dev, "Enabled i801 SMBus device\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc); static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { @@ -1106,10 +1110,10 @@ static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev) val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */ writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */ iounmap(base); - printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n"); + dev_info(&dev->dev, "Enabled ICH6/i801 SMBus device\n"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6); /* * SiS 96x south bridge: BIOS typically hides SMBus device... @@ -1119,18 +1123,18 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev) u8 val = 0; pci_read_config_byte(dev, 0x77, &val); if (val & 0x10) { - printk(KERN_INFO "Enabling SiS 96x SMBus.\n"); + dev_info(&dev->dev, "Enabling SiS 96x SMBus\n"); pci_write_config_byte(dev, 0x77, val & ~0x10); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus); /* * ... This is further complicated by the fact that some SiS96x south @@ -1163,8 +1167,8 @@ static void quirk_sis_503(struct pci_dev *dev) dev->device = devid; quirk_sis_96x_smbus(dev); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503); /* @@ -1191,13 +1195,13 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev) pci_write_config_byte(dev, 0x50, val & (~0xc0)); pci_read_config_byte(dev, 0x50, &val); if (val & 0xc0) - printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); else - printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n"); + dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc); #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) @@ -1292,7 +1296,7 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev) } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif int pcie_mch_quirk; @@ -1302,9 +1306,9 @@ static void __devinit quirk_pcie_mch(struct pci_dev *pdev) { pcie_mch_quirk = 1; } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch); /* @@ -1314,11 +1318,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir static void __devinit quirk_pcie_pxh(struct pci_dev *dev) { pci_msi_off(dev); - dev->no_msi = 1; - - printk(KERN_WARNING "PCI: PXH quirk detected, " - "disabling MSI for SHPC device\n"); + dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n"); } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_0, quirk_pcie_pxh); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_1, quirk_pcie_pxh); @@ -1399,7 +1400,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev) case PCI_DEVICE_ID_NETMOS_9855: if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL && num_parallel) { - printk(KERN_INFO "PCI: Netmos %04x (%u parallel, " + dev_info(&dev->dev, "Netmos %04x (%u parallel, " "%u serial); changing class SERIAL to OTHER " "(use parport_serial)\n", dev->device, num_parallel, num_serial); @@ -1412,9 +1413,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos); static void __devinit quirk_e100_interrupt(struct pci_dev *dev) { - u16 command; + u16 command, pmcsr; u8 __iomem *csr; u8 cmd_hi; + int pm; switch (dev->device) { /* PCI IDs taken from drivers/net/e100.c */ @@ -1448,18 +1450,28 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev) if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0)) return; + /* + * Check that the device is in the D0 power state. If it's not, + * there is no point to look any further. + */ + pm = pci_find_capability(dev, PCI_CAP_ID_PM); + if (pm) { + pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) + return; + } + /* Convert from PCI bus to resource space. */ csr = ioremap(pci_resource_start(dev, 0), 8); if (!csr) { - printk(KERN_WARNING "PCI: Can't map %s e100 registers\n", - pci_name(dev)); + dev_warn(&dev->dev, "Can't map e100 registers\n"); return; } cmd_hi = readb(csr + 3); if (cmd_hi == 0) { - printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts " - "enabled, disabling\n", pci_name(dev)); + dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; " + "disabling\n"); writeb(1, csr + 3); } @@ -1474,7 +1486,7 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) */ if (dev->class == PCI_CLASS_NOT_DEFINED) { - printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n"); + dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n"); dev->class = PCI_CLASS_STORAGE_SCSI; } } @@ -1485,7 +1497,11 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f while (f < end) { if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { - pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); +#ifdef DEBUG + dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook); + print_fn_descriptor_symbol(": %s()\n", + (unsigned long) f->hook); +#endif f->hook(dev); } f++; @@ -1553,7 +1569,7 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) pci_read_config_word(dev, 0x40, &en1k); if (en1k & 0x200) { - printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n"); + dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n"); pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); @@ -1585,7 +1601,7 @@ static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev) iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00); if (iobl_adr != iobl_adr_1k) { - printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n", + dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n", iobl_adr,iobl_adr_1k); pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k); } @@ -1603,9 +1619,8 @@ static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) if (pci_read_config_byte(dev, 0xf41, &b) == 0) { if (!(b & 0x20)) { pci_write_config_byte(dev, 0xf41, b | 0x20); - printk(KERN_INFO - "PCI: Linking AER extended capability on %s\n", - pci_name(dev)); + dev_info(&dev->dev, + "Linking AER extended capability\n"); } } } @@ -1614,6 +1629,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_pcie_aer_ext_cap); +static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) +{ + /* + * Disable PCI Bus Parking and PCI Master read caching on CX700 + * which causes unspecified timing errors with a VT6212L on the PCI + * bus leading to USB2.0 packet loss. The defaults are that these + * features are turned off but some BIOSes turn them on. + */ + + uint8_t b; + if (pci_read_config_byte(dev, 0x76, &b) == 0) { + if (b & 0x40) { + /* Turn off PCI Bus Parking */ + pci_write_config_byte(dev, 0x76, b ^ 0x40); + + /* Turn off PCI Master read caching */ + pci_write_config_byte(dev, 0x72, 0x0); + pci_write_config_byte(dev, 0x75, 0x1); + pci_write_config_byte(dev, 0x77, 0x0); + + printk(KERN_INFO + "PCI: VIA CX700 PCI parking/caching fixup on %s\n", + pci_name(dev)); + } + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); + #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually @@ -1624,7 +1667,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, static void __init quirk_disable_all_msi(struct pci_dev *dev) { pci_no_msi(); - printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n"); + dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n"); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi); @@ -1635,9 +1678,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab static void __devinit quirk_disable_msi(struct pci_dev *dev) { if (dev->subordinate) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } @@ -1656,9 +1698,9 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { - printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n", + dev_info(&dev->dev, "Found %s HT MSI Mapping\n", flags & HT_MSI_FLAGS_ENABLE ? - "enabled" : "disabled", pci_name(dev)); + "enabled" : "disabled"); return (flags & HT_MSI_FLAGS_ENABLE) != 0; } @@ -1672,17 +1714,40 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) static void __devinit quirk_msi_ht_cap(struct pci_dev *dev) { if (dev->subordinate && !msi_ht_cap_enabled(dev)) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "MSI disabled on chipset %s.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE, quirk_msi_ht_cap); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, - quirk_msi_ht_cap); + + +/* + * Force enable MSI mapping capability on HT bridges + */ +static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) +{ + int pos, ttl = 48; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { + printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n", + pci_name(dev)); + + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags | HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, + quirk_msi_ht_cap_enable); /* The nVidia CK804 chipset may have 2 HT MSI mappings. * MSI are supported if the MSI capability set in any of these mappings. @@ -1701,9 +1766,8 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) if (!pdev) return; if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "MSI disabled on chipset %s.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } pci_dev_put(pdev); @@ -1715,6 +1779,23 @@ static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) { dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; } +static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev) +{ + struct pci_dev *p; + + /* SB700 MSI issue will be fixed at HW level from revision A21, + * we need check PCI REVISION ID of SMBus controller to get SB700 + * revision. + */ + p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, + NULL); + if (!p) + return; + + if ((p->revision < 0x3B) && (p->revision >= 0x30)) + dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; + pci_dev_put(p); +} DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, quirk_msi_intx_disable_bug); @@ -1735,17 +1816,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, quirk_msi_intx_disable_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394, - quirk_msi_intx_disable_bug); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373, quirk_msi_intx_disable_bug); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 430281b2e92..ec4a82ba29a 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -1,5 +1,6 @@ #include <linux/pci.h> #include <linux/module.h> +#include <linux/aspm.h> #include "pci.h" static void pci_free_resources(struct pci_dev *dev) @@ -30,6 +31,9 @@ static void pci_stop_dev(struct pci_dev *dev) dev->global_list.next = dev->global_list.prev = NULL; up_write(&pci_bus_sem); } + + if (dev->bus->self) + pcie_aspm_exit_link_state(dev); } static void pci_destroy_dev(struct pci_dev *dev) @@ -74,10 +78,8 @@ void pci_remove_bus(struct pci_bus *pci_bus) list_del(&pci_bus->node); up_write(&pci_bus_sem); pci_remove_legacy_files(pci_bus); - class_device_remove_file(&pci_bus->class_dev, - &class_device_attr_cpuaffinity); - sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge"); - class_device_unregister(&pci_bus->class_dev); + device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity); + device_unregister(&pci_bus->dev); } EXPORT_SYMBOL(pci_remove_bus); diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index dbbcc04abd1..a98b2470b9e 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -162,6 +162,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) return rom; } +#if 0 /** * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy * @pdev: pointer to pci device struct @@ -196,6 +197,7 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) return (void __iomem *)(unsigned long)res->start; } +#endif /* 0 */ /** * pci_unmap_rom - unmap the ROM from kernel space @@ -218,6 +220,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) pci_disable_rom(pdev); } +#if 0 /** * pci_remove_rom - disable the ROM and remove its sysfs attribute * @pdev: pointer to pci device struct @@ -236,6 +239,7 @@ void pci_remove_rom(struct pci_dev *pdev) IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); } +#endif /* 0 */ /** * pci_cleanup_rom - internal routine for freeing the ROM copy created @@ -256,6 +260,4 @@ void pci_cleanup_rom(struct pci_dev *pdev) } EXPORT_SYMBOL(pci_map_rom); -EXPORT_SYMBOL(pci_map_rom_copy); EXPORT_SYMBOL(pci_unmap_rom); -EXPORT_SYMBOL(pci_remove_rom); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 401e03c920b..8a7232feb55 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *bus) * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. */ - printk(" IO window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, @@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); if (bus->resource[1]->flags & IORESOURCE_IO) { - printk(" IO window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, @@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_MEM) { - printk(" PREFETCH window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " PREFETCH window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, @@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); if (bus->resource[3]->flags & IORESOURCE_MEM) { - printk(" MEM window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, @@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; struct pci_bus_region region; - u32 l, io_upper16; + u32 l, bu, lu, io_upper16; DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge)); @@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus) /* Set up upper 16 bits of I/O base/limit. */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); DBG(KERN_INFO " IO window: %04lx-%04lx\n", - region.start, region.end); + (unsigned long)region.start, + (unsigned long)region.end); } else { /* Clear upper 16 bits of I/O base/limit. */ @@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus) if (bus->resource[1]->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - DBG(KERN_INFO " MEM window: %08lx-%08lx\n", - region.start, region.end); + DBG(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); } else { l = 0x0000fff0; @@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ + bu = lu = 0; pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n", - region.start, region.end); +#ifdef CONFIG_RESOURCES_64BIT + bu = region.start >> 32; + lu = region.end >> 32; +#endif + DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n", + (unsigned long long)region.start, + (unsigned long long)region.end); } else { l = 0x0000fff0; @@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus) } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - /* Clear out the upper 32 bits of PREF base. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus *bus) static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) { struct pci_dev *dev; - unsigned long min_align, align, size; - unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */ + resource_size_t min_align, align, size; + resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); @@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; - unsigned long r_size; + resource_size_t r_size; if (r->parent || (r->flags & mask) != type) continue; @@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long order = __ffs(align) - 20; if (order > 11) { printk(KERN_WARNING "PCI: region %s/%d " - "too large: %llx-%llx\n", + "too large: 0x%016llx-0x%016llx\n", pci_name(dev), i, - (unsigned long long)r->start, - (unsigned long long)r->end); + (unsigned long long)r->start, + (unsigned long long)r->end); r->flags = 0; continue; } @@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long align = 0; min_align = 0; for (order = 0; order <= max_order; order++) { - unsigned long align1 = 1UL << (order + 20); - +#ifdef CONFIG_RESOURCES_64BIT + resource_size_t align1 = 1ULL << (order + 20); +#else + resource_size_t align1 = 1U << (order + 20); +#endif if (!align) min_align = align1; else if (ALIGN(align + min_align, min_align) < align1) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 6dfd86167e3..4be7ccf7e3a 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) pcibios_resource_to_bus(dev, ®ion, res); - pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for " + pr_debug(" got res [%llx:%llx] bus [%llx:%llx] flags %lx for " "BAR %d of %s\n", (unsigned long long)res->start, (unsigned long long)res->end, - region.start, region.end, res->flags, resno, pci_name(dev)); + (unsigned long long)region.start, + (unsigned long long)region.end, + (unsigned long)res->flags, resno, pci_name(dev)); new = region.start | (res->flags & PCI_REGION_FLAG_MASK); if (res->flags & IORESOURCE_IO) @@ -125,7 +127,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return err; } -EXPORT_SYMBOL_GPL(pci_claim_resource); int pci_assign_resource(struct pci_dev *dev, int resno) { diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 2ac050d7f8c..645d7a60e41 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -34,7 +34,6 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, if (!dev) goto error; - lock_kernel(); switch (len) { case 1: cfg_ret = pci_user_read_config_byte(dev, off, &byte); @@ -47,10 +46,8 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, break; default: err = -EINVAL; - unlock_kernel(); goto error; }; - unlock_kernel(); err = -EIO; if (cfg_ret != PCIBIOS_SUCCESSFUL) @@ -107,7 +104,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, if (!dev) return -ENODEV; - lock_kernel(); switch(len) { case 1: err = get_user(byte, (u8 __user *)buf); @@ -140,7 +136,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = -EINVAL; break; } - unlock_kernel(); pci_dev_put(dev); return err; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3205f7488d1..29b4cf9e059 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2296,10 +2296,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; struct lpfc_sli *psli = &phba->sli; - int bars = pci_select_bars(pdev, IORESOURCE_MEM); dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); - if (pci_enable_device_bars(pdev, bars)) { + if (pci_enable_device_mem(pdev)) { printk(KERN_ERR "lpfc: Cannot re-enable " "PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6f129da3758..b72c7f17085 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2268,6 +2268,7 @@ typedef struct scsi_qla_host { spinlock_t hardware_lock ____cacheline_aligned; int bars; + int mem_only; device_reg_t __iomem *iobase; /* Base I/O address */ resource_size_t pio_address; #define MIN_IOBASE_LEN 0x100 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3954ed2d7b5..8f69caf8327 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1564,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; - int bars; + int bars, mem_only = 0; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); sht = &qla2x00_driver_template; @@ -1575,10 +1575,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { bars = pci_select_bars(pdev, IORESOURCE_MEM); sht = &qla24xx_driver_template; + mem_only = 1; } - if (pci_enable_device_bars(pdev, bars)) - goto probe_out; + if (mem_only) { + if (pci_enable_device_mem(pdev)) + goto probe_out; + } else { + if (pci_enable_device(pdev)) + goto probe_out; + } if (pci_find_aer_capability(pdev)) if (pci_enable_pcie_error_reporting(pdev)) @@ -1601,6 +1607,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no); ha->parent = NULL; ha->bars = bars; + ha->mem_only = mem_only; /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); @@ -2875,8 +2882,14 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) { pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; scsi_qla_host_t *ha = pci_get_drvdata(pdev); + int rc; + + if (ha->mem_only) + rc = pci_enable_device_mem(pdev); + else + rc = pci_enable_device(pdev); - if (pci_enable_device_bars(pdev, ha->bars)) { + if (rc) { qla_printk(KERN_WARNING, ha, "Can't re-enable PCI device after reset.\n"); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7a6499008b8..755823cdf62 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -42,6 +42,10 @@ config USB_ARCH_HAS_OHCI default y if PPC_MPC52xx # MIPS: default y if SOC_AU1X00 + # SH: + default y if CPU_SUBTYPE_SH7720 + default y if CPU_SUBTYPE_SH7721 + default y if CPU_SUBTYPE_SH7763 # more: default PCI @@ -50,6 +54,7 @@ config USB_ARCH_HAS_EHCI boolean default y if PPC_83xx default y if SOC_AU1200 + default y if ARCH_IXP4XX default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index b450cbaa3a0..86e64035edb 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -2,10 +2,7 @@ # USB/ATM DSL configuration # -menu "USB DSL modem support" - depends on USB - -config USB_ATM +menuconfig USB_ATM tristate "USB DSL modem support" depends on USB && ATM select CRC32 @@ -18,6 +15,8 @@ config USB_ATM To compile this driver as a module, choose M here: the module will be called usbatm. +if USB_ATM + config USB_SPEEDTOUCH tristate "Speedtouch USB support" depends on USB_ATM @@ -70,4 +69,4 @@ config USB_XUSBATM To compile this driver as a module, choose M here: the module will be called xusbatm. -endmenu +endif # USB_ATM diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 389c5b164eb..c5ec1a55eee 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -999,7 +999,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) bi.dwAddress = swab32(blockidx->PageAddress); uea_dbg(INS_TO_USBDEV(sc), - "sending block %u for DSP page %u size %u adress %x\n", + "sending block %u for DSP page %u size %u address %x\n", blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); /* send block info through the IDMA pipe */ @@ -1990,7 +1990,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) return; bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " "Function : %d, Subfunction : %d\n", E1_FUNCTION_TYPE(cmv->bFunction), E1_FUNCTION_SUBTYPE(cmv->bFunction)); @@ -2038,7 +2038,7 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) return; bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " "Function : %d, Subfunction : %d\n", E4_FUNCTION_TYPE(cmv->wFunction), E4_FUNCTION_SUBTYPE(cmv->wFunction)); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 912d97aaf9b..bcc42136c93 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) otherwise it is scheduled, and with high data rates data can get lost. */ tty->low_latency = 1; + if (usb_autopm_get_interface(acm->control)) { + mutex_unlock(&open_mutex); + return -EIO; + } + + mutex_lock(&acm->mutex); + mutex_unlock(&open_mutex); if (acm->used++) { + usb_autopm_put_interface(acm->control); goto done; } + acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dbg("usb_submit_urb(ctrl irq) failed"); @@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) done: err_out: - mutex_unlock(&open_mutex); + mutex_unlock(&acm->mutex); return rv; full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: + usb_autopm_put_interface(acm->control); acm->used--; - mutex_unlock(&open_mutex); + mutex_unlock(&acm->mutex); return -EIO; } @@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->writeurb); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); + usb_autopm_put_interface(acm->control); } else acm_tty_unregister(acm); } @@ -904,7 +915,7 @@ next_desc: } if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); + dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); skip_normal_probe: @@ -980,6 +991,7 @@ skip_normal_probe: spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); + mutex_init(&acm->mutex); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); @@ -1096,6 +1108,25 @@ alloc_fail: return -ENOMEM; } +static void stop_data_traffic(struct acm *acm) +{ + int i; + + tasklet_disable(&acm->urb_task); + + usb_kill_urb(acm->ctrlurb); + usb_kill_urb(acm->writeurb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->ru[i].urb); + + INIT_LIST_HEAD(&acm->filled_read_bufs); + INIT_LIST_HEAD(&acm->spare_read_bufs); + + tasklet_enable(&acm->urb_task); + + cancel_work_sync(&acm->work); +} + static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); @@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); - tasklet_disable(&acm->urb_task); - - usb_kill_urb(acm->ctrlurb); - usb_kill_urb(acm->writeurb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->ru[i].urb); - - INIT_LIST_HEAD(&acm->filled_read_bufs); - INIT_LIST_HEAD(&acm->spare_read_bufs); - - tasklet_enable(&acm->urb_task); - - flush_scheduled_work(); /* wait for acm_softint */ + stop_data_traffic(acm); acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); @@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf) tty_hangup(acm->tty); } +static int acm_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct acm *acm = usb_get_intfdata(intf); + + if (acm->susp_count++) + return 0; + /* + we treat opened interfaces differently, + we must guard against open + */ + mutex_lock(&acm->mutex); + + if (acm->used) + stop_data_traffic(acm); + + mutex_unlock(&acm->mutex); + return 0; +} + +static int acm_resume(struct usb_interface *intf) +{ + struct acm *acm = usb_get_intfdata(intf); + int rv = 0; + + if (--acm->susp_count) + return 0; + + mutex_lock(&acm->mutex); + if (acm->used) { + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); + if (rv < 0) + goto err_out; + + tasklet_schedule(&acm->urb_task); + } + +err_out: + mutex_unlock(&acm->mutex); + return rv; +} /* * USB driver structure. */ @@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, + .suspend = acm_suspend, + .resume = acm_resume, .id_table = acm_ids, + .supports_autosuspend = 1, }; /* diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 09f7765dbf8..8df6a57dcf9 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -107,6 +107,7 @@ struct acm { int write_used; /* number of non-empty write buffers */ int write_ready; /* write urb is not running */ spinlock_t write_lock; + struct mutex mutex; struct usb_cdc_line_coding line; /* bits, stop, parity */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct urb_task; /* rx processing */ @@ -120,6 +121,7 @@ struct acm { unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ + unsigned int susp_count; /* number of suspended interfaces */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 97b09f28270..5c33cdb9cac 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -9,6 +9,21 @@ config USB_DEBUG of debug messages to the system log. Select this if you are having a problem with USB support and want to see more of what is going on. +config USB_ANNOUNCE_NEW_DEVICES + bool "USB announce new devices" + depends on USB + default N + help + Say Y here if you want the USB core to always announce the + idVendor, idProduct, Manufacturer, Product, and SerialNumber + strings for every new USB device to the syslog. This option is + usually used by distro vendors to help with debugging and to + let users know what specific device was added to the machine + in what location. + + If you do not want this kind of information sent to the system + log, or have any doubts about this, say N here. + comment "Miscellaneous USB options" depends on USB diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 28d4972f7ad..cadb2dc1d28 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -53,11 +53,13 @@ int hcd_buffer_create(struct usb_hcd *hcd) char name[16]; int i, size; - if (!hcd->self.controller->dma_mask) + if (!hcd->self.controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) return 0; - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - if (!(size = pool_max [i])) + for (i = 0; i < HCD_BUFFER_POOLS; i++) { + size = pool_max[i]; + if (!size) continue; snprintf(name, sizeof name, "buffer-%d", size); hcd->pool[i] = dma_pool_create(name, hcd->self.controller, @@ -80,10 +82,10 @@ int hcd_buffer_create(struct usb_hcd *hcd) */ void hcd_buffer_destroy(struct usb_hcd *hcd) { - int i; + int i; - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool[i]; + for (i = 0; i < HCD_BUFFER_POOLS; i++) { + struct dma_pool *pool = hcd->pool[i]; if (pool) { dma_pool_destroy(pool); hcd->pool[i] = NULL; @@ -107,7 +109,8 @@ void *hcd_buffer_alloc( int i; /* some USB hosts just use PIO */ - if (!bus->controller->dma_mask) { + if (!bus->controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) { *dma = ~(dma_addr_t) 0; return kmalloc(size, mem_flags); } @@ -132,7 +135,8 @@ void hcd_buffer_free( if (!addr) return; - if (!bus->controller->dma_mask) { + if (!bus->controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) { kfree(addr); return; } diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 1a8edcee7f3..a92122a216b 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -238,7 +238,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno, /* Allocate space for the right(?) number of endpoints */ num_ep = num_ep_orig = alt->desc.bNumEndpoints; - alt->desc.bNumEndpoints = 0; // Use as a counter + alt->desc.bNumEndpoints = 0; /* Use as a counter */ if (num_ep > USB_MAXENDPOINTS) { dev_warn(ddev, "too many endpoints for config %d interface %d " "altsetting %d: %d, using maximum allowed: %d\n", @@ -246,7 +246,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, num_ep = USB_MAXENDPOINTS; } - if (num_ep > 0) { /* Can't allocate 0 bytes */ + if (num_ep > 0) { + /* Can't allocate 0 bytes */ len = sizeof(struct usb_host_endpoint) * num_ep; alt->endpoint = kzalloc(len, GFP_KERNEL); if (!alt->endpoint) @@ -475,8 +476,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, return 0; } -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally on disconnect/destroy path +/* hub-only!! ... and only exported for reset/reinit path. + * otherwise used internally on disconnect/destroy path + */ void usb_destroy_configuration(struct usb_device *dev) { int c, i; @@ -498,7 +500,7 @@ void usb_destroy_configuration(struct usb_device *dev) kfree(cf->string); for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) - kref_put(&cf->intf_cache[i]->ref, + kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); } } @@ -525,7 +527,7 @@ int usb_get_configuration(struct usb_device *dev) unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; - struct usb_config_descriptor *desc; + struct usb_config_descriptor *desc; cfgno = 0; if (dev->authorized == 0) /* Not really an error */ diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 87c794d60aa..83d9dc379d9 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -89,7 +89,7 @@ static const char *format_string_serialnumber = static const char *format_bandwidth = /* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */ "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n"; - + static const char *format_device1 = /* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */ "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n"; @@ -101,7 +101,7 @@ static const char *format_device2 = static const char *format_config = /* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */ "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n"; - + static const char *format_iad = /* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */ "A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; @@ -122,7 +122,7 @@ static const char *format_endpt = */ static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); -static unsigned int conndiscevcnt = 0; +static unsigned int conndiscevcnt; /* this struct stores the poll state for <mountpoint>/devices pollers */ struct usb_device_status { @@ -172,12 +172,8 @@ static const char *class_decode(const int class) return clas_info[ix].class_name; } -static char *usb_dump_endpoint_descriptor( - int speed, - char *start, - char *end, - const struct usb_endpoint_descriptor *desc -) +static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, + const struct usb_endpoint_descriptor *desc) { char dir, unit, *type; unsigned interval, bandwidth = 1; @@ -235,22 +231,24 @@ static char *usb_dump_endpoint_descriptor( start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, desc->bmAttributes, type, - (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * bandwidth, + (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * + bandwidth, interval, unit); return start; } static char *usb_dump_interface_descriptor(char *start, char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, - int setno) + const struct usb_interface_cache *intfc, + const struct usb_interface *iface, + int setno) { - const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; + const struct usb_interface_descriptor *desc; const char *driver_name = ""; int active = 0; if (start > end) return start; + desc = &intfc->altsetting[setno].desc; if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name @@ -270,14 +268,10 @@ static char *usb_dump_interface_descriptor(char *start, char *end, return start; } -static char *usb_dump_interface( - int speed, - char *start, - char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, - int setno -) { +static char *usb_dump_interface(int speed, char *start, char *end, + const struct usb_interface_cache *intfc, + const struct usb_interface *iface, int setno) +{ const struct usb_host_interface *desc = &intfc->altsetting[setno]; int i; @@ -292,7 +286,7 @@ static char *usb_dump_interface( } static char *usb_dump_iad_descriptor(char *start, char *end, - const struct usb_interface_assoc_descriptor *iad) + const struct usb_interface_assoc_descriptor *iad) { if (start > end) return start; @@ -311,13 +305,15 @@ static char *usb_dump_iad_descriptor(char *start, char *end, * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) */ - -static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) +static char *usb_dump_config_descriptor(char *start, char *end, + const struct usb_config_descriptor *desc, + int active) { if (start > end) return start; start += sprintf(start, format_config, - active ? '*' : ' ', /* mark active/actual/current cfg. */ + /* mark active/actual/current cfg. */ + active ? '*' : ' ', desc->bNumInterfaces, desc->bConfigurationValue, desc->bmAttributes, @@ -325,13 +321,8 @@ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb return start; } -static char *usb_dump_config ( - int speed, - char *start, - char *end, - const struct usb_host_config *config, - int active -) +static char *usb_dump_config(int speed, char *start, char *end, + const struct usb_host_config *config, int active) { int i, j; struct usb_interface_cache *intfc; @@ -339,7 +330,8 @@ static char *usb_dump_config ( if (start > end) return start; - if (!config) /* getting these some in 2.3.7; none in 2.3.6 */ + if (!config) + /* getting these some in 2.3.7; none in 2.3.6 */ return start + sprintf(start, "(null Cfg. desc.)\n"); start = usb_dump_config_descriptor(start, end, &config->desc, active); for (i = 0; i < USB_MAXIADS; i++) { @@ -364,7 +356,8 @@ static char *usb_dump_config ( /* * Dump the different USB descriptors. */ -static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc) +static char *usb_dump_device_descriptor(char *start, char *end, + const struct usb_device_descriptor *desc) { u16 bcdUSB = le16_to_cpu(desc->bcdUSB); u16 bcdDevice = le16_to_cpu(desc->bcdDevice); @@ -374,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb start += sprintf(start, format_device1, bcdUSB >> 8, bcdUSB & 0xff, desc->bDeviceClass, - class_decode (desc->bDeviceClass), + class_decode(desc->bDeviceClass), desc->bDeviceSubClass, desc->bDeviceProtocol, desc->bMaxPacketSize0, @@ -391,12 +384,14 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb /* * Dump the different strings that this device holds. */ -static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev) +static char *usb_dump_device_strings(char *start, char *end, + struct usb_device *dev) { if (start > end) return start; if (dev->manufacturer) - start += sprintf(start, format_string_manufacturer, dev->manufacturer); + start += sprintf(start, format_string_manufacturer, + dev->manufacturer); if (start > end) goto out; if (dev->product) @@ -405,7 +400,8 @@ static char *usb_dump_device_strings(char *start, char *end, struct usb_device * goto out; #ifdef ALLOW_SERIAL_NUMBER if (dev->serial) - start += sprintf(start, format_string_serialnumber, dev->serial); + start += sprintf(start, format_string_serialnumber, + dev->serial); #endif out: return start; @@ -417,12 +413,12 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) if (start > end) return start; - + start = usb_dump_device_descriptor(start, end, &dev->descriptor); if (start > end) return start; - + start = usb_dump_device_strings(start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { @@ -439,7 +435,8 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) #ifdef PROC_EXTRA /* TBD: may want to add this code later */ -static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc) +static char *usb_dump_hub_descriptor(char *start, char *end, + const struct usb_hub_descriptor *desc) { int leng = USB_DT_HUB_NONVAR_SIZE; unsigned char *ptr = (unsigned char *)desc; @@ -455,13 +452,16 @@ static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hu return start; } -static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index) +static char *usb_dump_string(char *start, char *end, + const struct usb_device *dev, char *id, int index) { if (start > end) return start; start += sprintf(start, "Interface:"); - if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index]) - start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]); + if (index <= dev->maxstring && dev->stringindex && + dev->stringindex[index]) + start += sprintf(start, "%s: %.100s ", id, + dev->stringindex[index]); return start; } @@ -476,8 +476,10 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de * file_offset - the offset into the devices file on completion * The caller must own the device lock. */ -static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, - struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) +static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, + loff_t *skip_bytes, loff_t *file_offset, + struct usb_device *usbdev, struct usb_bus *bus, + int level, int index, int count) { int chix; int ret, cnt = 0; @@ -485,17 +487,19 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski char *pages_start, *data_end, *speed; unsigned int length; ssize_t total_written = 0; - + /* don't bother with anything else if we're not writing any data */ if (*nbytes <= 0) return 0; - + if (level > MAX_TOPO_LEVEL) return 0; - /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */ - if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1))) - return -ENOMEM; - + /* allocate 2^1 pages = 8K (on i386); + * should be more than enough for one device */ + pages_start = (char *)__get_free_pages(GFP_KERNEL, 1); + if (!pages_start) + return -ENOMEM; + if (usbdev->parent && usbdev->parent->devnum != -1) parent_devnum = usbdev->parent->devnum; /* @@ -541,15 +545,16 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski bus->bandwidth_allocated, max, (100 * bus->bandwidth_allocated + max / 2) / max, - bus->bandwidth_int_reqs, - bus->bandwidth_isoc_reqs); - + bus->bandwidth_int_reqs, + bus->bandwidth_isoc_reqs); + } - data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev); - + data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, + usbdev); + if (data_end > (pages_start + (2 * PAGE_SIZE) - 256)) data_end += sprintf(data_end, "(truncated)\n"); - + length = data_end - pages_start; /* if we can start copying some data to the user */ if (length > *skip_bytes) { @@ -567,17 +572,18 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski *skip_bytes = 0; } else *skip_bytes -= length; - + free_pages((unsigned long)pages_start, 1); - + /* Now look at all of this device's children. */ for (chix = 0; chix < usbdev->maxchild; chix++) { struct usb_device *childdev = usbdev->children[chix]; if (childdev) { usb_lock_device(childdev); - ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev, - bus, level + 1, chix, ++cnt); + ret = usb_device_dump(buffer, nbytes, skip_bytes, + file_offset, childdev, bus, + level + 1, chix, ++cnt); usb_unlock_device(childdev); if (ret == -EFAULT) return total_written; @@ -587,7 +593,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski return total_written; } -static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t usb_device_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) { struct usb_bus *bus; ssize_t ret, total_written = 0; @@ -607,7 +614,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte if (!bus->root_hub) continue; usb_lock_device(bus->root_hub); - ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); + ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, + bus->root_hub, bus, 0, 0, 0); usb_unlock_device(bus->root_hub); if (ret < 0) { mutex_unlock(&usb_bus_list_lock); @@ -620,7 +628,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte } /* Kernel lock for "lastev" protection */ -static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int usb_device_poll(struct file *file, + struct poll_table_struct *wait) { struct usb_device_status *st = file->private_data; unsigned int mask = 0; @@ -629,7 +638,8 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - /* we may have dropped BKL - need to check for having lost the race */ + /* we may have dropped BKL - + * need to check for having lost the race */ if (file->private_data) { kfree(st); st = file->private_data; @@ -652,7 +662,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct } lost_race: if (file->f_mode & FMODE_READ) - poll_wait(file, &deviceconndiscwq, wait); + poll_wait(file, &deviceconndiscwq, wait); if (st->lastev != conndiscevcnt) mask |= POLLIN; st->lastev = conndiscevcnt; @@ -662,18 +672,18 @@ lost_race: static int usb_device_open(struct inode *inode, struct file *file) { - file->private_data = NULL; - return 0; + file->private_data = NULL; + return 0; } static int usb_device_release(struct inode *inode, struct file *file) { kfree(file->private_data); file->private_data = NULL; - return 0; + return 0; } -static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) +static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig) { loff_t ret; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 1f4f6d02fe2..ae94176c64e 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -75,14 +75,14 @@ struct async { u32 secid; }; -static int usbfs_snoop = 0; -module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); +static int usbfs_snoop; +module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define snoop(dev, format, arg...) \ do { \ if (usbfs_snoop) \ - dev_info( dev , format , ## arg); \ + dev_info(dev , format , ## arg); \ } while (0) #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) @@ -90,7 +90,7 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); #define MAX_USBFS_BUFFER_SIZE 16384 -static inline int connected (struct dev_state *ps) +static inline int connected(struct dev_state *ps) { return (!list_empty(&ps->list) && ps->dev->state != USB_STATE_NOTATTACHED); @@ -120,7 +120,8 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) return ret; } -static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) { struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; @@ -140,7 +141,8 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l } if (pos < sizeof(struct usb_device_descriptor)) { - struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */ + /* 18 bytes - fits on the stack */ + struct usb_device_descriptor temp_desc; memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor)); le16_to_cpus(&temp_desc.bcdUSB); @@ -210,17 +212,17 @@ err: static struct async *alloc_async(unsigned int numisoframes) { - unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); - struct async *as = kzalloc(assize, GFP_KERNEL); + struct async *as; - if (!as) - return NULL; + as = kzalloc(sizeof(struct async), GFP_KERNEL); + if (!as) + return NULL; as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); if (!as->urb) { kfree(as); return NULL; } - return as; + return as; } static void free_async(struct async *as) @@ -234,52 +236,54 @@ static void free_async(struct async *as) static inline void async_newpending(struct async *as) { - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_add_tail(&as->asynclist, &ps->async_pending); - spin_unlock_irqrestore(&ps->lock, flags); + struct dev_state *ps = as->ps; + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); + list_add_tail(&as->asynclist, &ps->async_pending); + spin_unlock_irqrestore(&ps->lock, flags); } static inline void async_removepending(struct async *as) { - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); + struct dev_state *ps = as->ps; + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); + list_del_init(&as->asynclist); + spin_unlock_irqrestore(&ps->lock, flags); } static inline struct async *async_getcompleted(struct dev_state *ps) { - unsigned long flags; - struct async *as = NULL; - - spin_lock_irqsave(&ps->lock, flags); - if (!list_empty(&ps->async_completed)) { - as = list_entry(ps->async_completed.next, struct async, asynclist); - list_del_init(&as->asynclist); - } - spin_unlock_irqrestore(&ps->lock, flags); - return as; + unsigned long flags; + struct async *as = NULL; + + spin_lock_irqsave(&ps->lock, flags); + if (!list_empty(&ps->async_completed)) { + as = list_entry(ps->async_completed.next, struct async, + asynclist); + list_del_init(&as->asynclist); + } + spin_unlock_irqrestore(&ps->lock, flags); + return as; } -static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb) +static inline struct async *async_getpending(struct dev_state *ps, + void __user *userurb) { - unsigned long flags; - struct async *as; + unsigned long flags; + struct async *as; - spin_lock_irqsave(&ps->lock, flags); + spin_lock_irqsave(&ps->lock, flags); list_for_each_entry(as, &ps->async_pending, asynclist) if (as->userurb == userurb) { list_del_init(&as->asynclist); spin_unlock_irqrestore(&ps->lock, flags); return as; } - spin_unlock_irqrestore(&ps->lock, flags); - return NULL; + spin_unlock_irqrestore(&ps->lock, flags); + return NULL; } static void snoop_urb(struct urb *urb, void __user *userurb) @@ -298,19 +302,19 @@ static void snoop_urb(struct urb *urb, void __user *userurb) dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); dev_info(&urb->dev->dev, "data: "); for (j = 0; j < urb->transfer_buffer_length; ++j) - printk ("%02x ", data[j]); + printk("%02x ", data[j]); printk("\n"); } static void async_completed(struct urb *urb) { - struct async *as = urb->context; - struct dev_state *ps = as->ps; + struct async *as = urb->context; + struct dev_state *ps = as->ps; struct siginfo sinfo; - spin_lock(&ps->lock); - list_move_tail(&as->asynclist, &ps->async_completed); - spin_unlock(&ps->lock); + spin_lock(&ps->lock); + list_move_tail(&as->asynclist, &ps->async_completed); + spin_unlock(&ps->lock); as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; @@ -325,7 +329,7 @@ static void async_completed(struct urb *urb) wake_up(&ps->wait); } -static void destroy_async (struct dev_state *ps, struct list_head *list) +static void destroy_async(struct dev_state *ps, struct list_head *list) { struct async *as; unsigned long flags; @@ -348,7 +352,8 @@ static void destroy_async (struct dev_state *ps, struct list_head *list) } } -static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum) +static void destroy_async_on_interface(struct dev_state *ps, + unsigned int ifnum) { struct list_head *p, *q, hitlist; unsigned long flags; @@ -364,7 +369,7 @@ static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum static inline void destroy_all_async(struct dev_state *ps) { - destroy_async(ps, &ps->async_pending); + destroy_async(ps, &ps->async_pending); } /* @@ -373,15 +378,15 @@ static inline void destroy_all_async(struct dev_state *ps) * they're also undone when devices disconnect. */ -static int driver_probe (struct usb_interface *intf, - const struct usb_device_id *id) +static int driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) { return -ENODEV; } static void driver_disconnect(struct usb_interface *intf) { - struct dev_state *ps = usb_get_intfdata (intf); + struct dev_state *ps = usb_get_intfdata(intf); unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; if (!ps) @@ -396,16 +401,31 @@ static void driver_disconnect(struct usb_interface *intf) else warn("interface number %u out of range", ifnum); - usb_set_intfdata (intf, NULL); + usb_set_intfdata(intf, NULL); /* force async requests to complete */ destroy_async_on_interface(ps, ifnum); } +/* The following routines are merely placeholders. There is no way + * to inform a user task about suspend or resumes. + */ +static int driver_suspend(struct usb_interface *intf, pm_message_t msg) +{ + return 0; +} + +static int driver_resume(struct usb_interface *intf) +{ + return 0; +} + struct usb_driver usbfs_driver = { .name = "usbfs", .probe = driver_probe, .disconnect = driver_disconnect, + .suspend = driver_suspend, + .resume = driver_resume, }; static int claimintf(struct dev_state *ps, unsigned int ifnum) @@ -459,15 +479,16 @@ static int checkintf(struct dev_state *ps, unsigned int ifnum) if (test_bit(ifnum, &ps->ifclaimed)) return 0; /* if not yet claimed, claim it for the driver */ - dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n", - task_pid_nr(current), current->comm, ifnum); + dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim " + "interface %u before use\n", task_pid_nr(current), + current->comm, ifnum); return claimintf(ps, ifnum); } static int findintfep(struct usb_device *dev, unsigned int ep) { unsigned int i, j, e; - struct usb_interface *intf; + struct usb_interface *intf; struct usb_host_interface *alts; struct usb_endpoint_descriptor *endpt; @@ -478,7 +499,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { intf = dev->actconfig->interface[i]; for (j = 0; j < intf->num_altsetting; j++) { - alts = &intf->altsetting[j]; + alts = &intf->altsetting[j]; for (e = 0; e < alts->desc.bNumEndpoints; e++) { endpt = &alts->endpoint[e].desc; if (endpt->bEndpointAddress == ep) @@ -486,10 +507,11 @@ static int findintfep(struct usb_device *dev, unsigned int ep) } } } - return -ENOENT; + return -ENOENT; } -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index) +static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, + unsigned int index) { int ret = 0; @@ -502,7 +524,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig index &= 0xff; switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: - if ((ret = findintfep(ps->dev, index)) >= 0) + ret = findintfep(ps->dev, index); + if (ret >= 0) ret = checkintf(ps, ret); break; @@ -546,7 +569,8 @@ static int usbdev_open(struct inode *inode, struct file *file) mutex_lock(&usbfs_mutex); ret = -ENOMEM; - if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) + ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); + if (!ps) goto out; ret = -ENOENT; @@ -627,15 +651,18 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; - if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) + ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); + if (ret) return ret; if (ctrl.wLength > PAGE_SIZE) return -EINVAL; - if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!tbuf) return -ENOMEM; tmo = ctrl.timeout; if (ctrl.bRequestType & 0x80) { - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { + if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, + ctrl.wLength)) { free_page((unsigned long)tbuf); return -EINVAL; } @@ -646,14 +673,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) ctrl.wIndex, ctrl.wLength); usb_unlock_device(dev); - i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, - ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); usb_lock_device(dev); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); for (j = 0; j < i; ++j) - printk("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (u8)(tbuf)[j]); printk("\n"); } if (copy_to_user(ctrl.data, tbuf, i)) { @@ -680,12 +708,13 @@ static int proc_control(struct dev_state *ps, void __user *arg) printk("\n"); } usb_unlock_device(dev); - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, - ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); usb_lock_device(dev); } free_page((unsigned long)tbuf); - if (i<0 && i != -EPIPE) { + if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, @@ -705,9 +734,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (copy_from_user(&bulk, arg, sizeof(bulk))) return -EFAULT; - if ((ret = findintfep(ps->dev, bulk.ep)) < 0) + ret = findintfep(ps->dev, bulk.ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; if (bulk.ep & USB_DIR_IN) pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); @@ -735,7 +766,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "bulk read: data "); for (j = 0; j < len2; ++j) - printk("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (u8)(tbuf)[j]); printk("\n"); } if (copy_to_user(bulk.data, tbuf, len2)) { @@ -775,9 +806,11 @@ static int proc_resetep(struct dev_state *ps, void __user *arg) if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = findintfep(ps->dev, ep)) < 0) + ret = findintfep(ps->dev, ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); return 0; @@ -791,18 +824,19 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg) if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = findintfep(ps->dev, ep)) < 0) + ret = findintfep(ps->dev, ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; if (ep & USB_DIR_IN) - pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); - else - pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); + pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); + else + pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); return usb_clear_halt(ps->dev, pipe); } - static int proc_getdriver(struct dev_state *ps, void __user *arg) { @@ -856,23 +890,23 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) { int u; int status = 0; - struct usb_host_config *actconfig; + struct usb_host_config *actconfig; if (get_user(u, (int __user *)arg)) return -EFAULT; - actconfig = ps->dev->actconfig; - - /* Don't touch the device if any interfaces are claimed. - * It could interfere with other drivers' operations, and if + actconfig = ps->dev->actconfig; + + /* Don't touch the device if any interfaces are claimed. + * It could interfere with other drivers' operations, and if * an interface is claimed by usbfs it could easily deadlock. */ - if (actconfig) { - int i; - - for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { - if (usb_interface_claimed(actconfig->interface[i])) { - dev_warn (&ps->dev->dev, + if (actconfig) { + int i; + + for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { + if (usb_interface_claimed(actconfig->interface[i])) { + dev_warn(&ps->dev->dev, "usbfs: interface %d claimed by %s " "while '%s' sets config #%d\n", actconfig->interface[i] @@ -881,11 +915,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) actconfig->interface[i] ->dev.driver->name, current->comm, u); - status = -EBUSY; + status = -EBUSY; break; } - } - } + } + } /* SET_CONFIGURATION is often abused as a "cheap" driver reset, * so avoid usb_set_configuration()'s kick to sysfs @@ -901,8 +935,8 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) } static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, - struct usbdevfs_iso_packet_desc __user *iso_frame_desc, - void __user *arg) + struct usbdevfs_iso_packet_desc __user *iso_frame_desc, + void __user *arg) { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; @@ -917,12 +951,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!uurb->buffer) return -EINVAL; - if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX)) + if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || + uurb->signr > SIGRTMAX)) return -EINVAL; - if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { - if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0) + if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && + (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { + ifnum = findintfep(ps->dev, uurb->endpoint); + if (ifnum < 0) return ifnum; - if ((ret = checkintf(ps, ifnum))) + ret = checkintf(ps, ifnum); + if (ret) return ret; } if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { @@ -938,10 +976,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; - /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ - if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) + /* min 8 byte setup packet, + * max 8 byte setup plus an arbitrary data stage */ + if (uurb->buffer_length < 8 || + uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) return -EINVAL; - if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { kfree(dr); @@ -951,7 +992,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EINVAL; } - if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) { + ret = check_ctrlrecip(ps, dr->bRequestType, + le16_to_cpup(&dr->wIndex)); + if (ret) { kfree(dr); return ret; } @@ -997,11 +1040,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_ISO: /* arbitrary limit */ - if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) + if (uurb->number_of_packets < 1 || + uurb->number_of_packets > 128) return -EINVAL; if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; - isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; + isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * + uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { @@ -1009,7 +1054,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EFAULT; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { - /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */ + /* arbitrary limit, + * sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { kfree(isopkt); return -EINVAL; @@ -1039,25 +1085,27 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, default: return -EINVAL; } - if (!(as = alloc_async(uurb->number_of_packets))) { + as = alloc_async(uurb->number_of_packets); + if (!as) { kfree(isopkt); kfree(dr); return -ENOMEM; } - if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) { + as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); + if (!as->urb->transfer_buffer) { kfree(isopkt); kfree(dr); free_async(as); return -ENOMEM; } - as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | + as->urb->dev = ps->dev; + as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags | + as->urb->transfer_flags = uurb->flags | (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; - as->urb->setup_packet = (unsigned char*)dr; + as->urb->setup_packet = (unsigned char *)dr; as->urb->start_frame = uurb->start_frame; as->urb->number_of_packets = uurb->number_of_packets; if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1065,8 +1113,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); else as->urb->interval = ep->desc.bInterval; - as->urb->context = as; - as->urb->complete = async_completed; + as->urb->context = as; + as->urb->complete = async_completed; for (totlen = u = 0; u < uurb->number_of_packets; u++) { as->urb->iso_frame_desc[u].offset = totlen; as->urb->iso_frame_desc[u].length = isopkt[u].length; @@ -1074,7 +1122,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } kfree(isopkt); as->ps = ps; - as->userurb = arg; + as->userurb = arg; if (uurb->endpoint & USB_DIR_IN) as->userbuffer = uurb->buffer; else @@ -1093,14 +1141,15 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } } snoop_urb(as->urb, as->userurb); - async_newpending(as); - if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { - dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); - async_removepending(as); - free_async(as); - return ret; - } - return 0; + async_newpending(as); + if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { + dev_printk(KERN_DEBUG, &ps->dev->dev, + "usbfs: usb_submit_urb returned %d\n", ret); + async_removepending(as); + free_async(as); + return ret; + } + return 0; } static int proc_submiturb(struct dev_state *ps, void __user *arg) @@ -1110,7 +1159,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); + return proc_do_submiturb(ps, &uurb, + (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), + arg); } static int proc_unlinkurb(struct dev_state *ps, void __user *arg) @@ -1132,7 +1183,8 @@ static int processcompl(struct async *as, void __user * __user *arg) unsigned int i; if (as->userbuffer) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) + if (copy_to_user(as->userbuffer, urb->transfer_buffer, + urb->transfer_buffer_length)) return -EFAULT; if (put_user(as->status, &userurb->status)) return -EFAULT; @@ -1159,16 +1211,17 @@ static int processcompl(struct async *as, void __user * __user *arg) return 0; } -static struct async* reap_as(struct dev_state *ps) +static struct async *reap_as(struct dev_state *ps) { - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; struct usb_device *dev = ps->dev; add_wait_queue(&ps->wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if ((as = async_getcompleted(ps))) + as = async_getcompleted(ps); + if (as) break; if (signal_pending(current)) break; @@ -1232,10 +1285,12 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; - if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg)) + if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) return -EFAULT; - return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg); + return proc_do_submiturb(ps, &uurb, + ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, + arg); } static int processcompl_compat(struct async *as, void __user * __user *arg) @@ -1246,7 +1301,8 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) unsigned int i; if (as->userbuffer) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) + if (copy_to_user(as->userbuffer, urb->transfer_buffer, + urb->transfer_buffer_length)) return -EFAULT; if (put_user(as->status, &userurb->status)) return -EFAULT; @@ -1337,16 +1393,16 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) struct usb_driver *driver = NULL; /* alloc buffer */ - if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { - if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) + if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { + if ((buf = kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { - if (copy_from_user (buf, ctl->data, size)) { + if (copy_from_user(buf, ctl->data, size)) { kfree(buf); return -EFAULT; } } else { - memset (buf, 0, size); + memset(buf, 0, size); } } @@ -1357,15 +1413,15 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) if (ps->dev->state != USB_STATE_CONFIGURED) retval = -EHOSTUNREACH; - else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) - retval = -EINVAL; + else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno))) + retval = -EINVAL; else switch (ctl->ioctl_code) { /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); - dev_dbg (&intf->dev, "disconnect by usbfs\n"); + dev_dbg(&intf->dev, "disconnect by usbfs\n"); usb_driver_release_interface(driver, intf); } else retval = -ENODATA; @@ -1373,9 +1429,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: - usb_unlock_device(ps->dev); - retval = bus_rescan_devices(intf->dev.bus); - usb_lock_device(ps->dev); + if (!intf->dev.driver) + retval = device_attach(&intf->dev); + else + retval = -EBUSY; break; /* talk directly to the interface's driver */ @@ -1385,7 +1442,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { - retval = driver->ioctl (intf, ctl->ioctl_code, buf); + retval = driver->ioctl(intf, ctl->ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -1393,9 +1450,9 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* cleanup and return */ if (retval >= 0 - && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 + && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0 && size > 0 - && copy_to_user (ctl->data, buf, size) != 0) + && copy_to_user(ctl->data, buf, size) != 0) retval = -EFAULT; kfree(buf); @@ -1406,7 +1463,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg) { struct usbdevfs_ioctl ctrl; - if (copy_from_user(&ctrl, arg, sizeof (ctrl))) + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; return proc_ioctl(ps, &ctrl); } @@ -1434,7 +1491,8 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) * are assuming that somehow the configuration has been prevented from * changing. But there's no mechanism to ensure that... */ -static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int usbdev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; @@ -1577,7 +1635,8 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } /* No kernel lock - fine */ -static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int usbdev_poll(struct file *file, + struct poll_table_struct *wait) { struct dev_state *ps = file->private_data; unsigned int mask = 0; @@ -1648,7 +1707,7 @@ int __init usb_devio_init(void) int retval; retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX, - "usb_device"); + "usb_device"); if (retval) { err("unable to register minors for usb_device"); goto out; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7c3aaa9c540..801b6f142fa 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,10 +202,10 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - if (udev->authorized == 0) { - dev_err(&intf->dev, "Device is not authorized for usage\n"); - return -ENODEV; - } + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } id = usb_match_id(intf, driver->id_table); if (!id) @@ -299,7 +299,7 @@ static int usb_unbind_interface(struct device *dev) * lock. */ int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void* priv) + struct usb_interface *iface, void *priv) { struct device *dev = &iface->dev; struct usb_device *udev = interface_to_usbdev(iface); @@ -325,7 +325,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, return retval; } -EXPORT_SYMBOL(usb_driver_claim_interface); +EXPORT_SYMBOL_GPL(usb_driver_claim_interface); /** * usb_driver_release_interface - unbind a driver from an interface @@ -370,7 +370,7 @@ void usb_driver_release_interface(struct usb_driver *driver, iface->needs_remote_wakeup = 0; usb_pm_unlock(udev); } -EXPORT_SYMBOL(usb_driver_release_interface); +EXPORT_SYMBOL_GPL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) @@ -398,7 +398,7 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && @@ -534,15 +534,15 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, id->driver_info is the way to create an entry that indicates that the driver want to examine every device and interface. */ - for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || - id->driver_info; id++) { + for (; id->idVendor || id->idProduct || id->bDeviceClass || + id->bInterfaceClass || id->driver_info; id++) { if (usb_match_one_id(interface, id)) return id; } return NULL; } -EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); +EXPORT_SYMBOL_GPL(usb_match_id); static int usb_device_match(struct device *dev, struct device_driver *drv) { @@ -586,7 +586,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) struct usb_device *usb_dev; /* driver is often null here; dev_dbg() would oops */ - pr_debug ("usb %s: uevent\n", dev->bus_id); + pr_debug("usb %s: uevent\n", dev->bus_id); if (is_usb_device(dev)) usb_dev = to_usb_device(dev); @@ -596,11 +596,11 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) } if (usb_dev->devnum < 0) { - pr_debug ("usb %s: already deleted?\n", dev->bus_id); + pr_debug("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; } if (!usb_dev->bus) { - pr_debug ("usb %s: bus removed?\n", dev->bus_id); + pr_debug("usb %s: bus removed?\n", dev->bus_id); return -ENODEV; } @@ -745,7 +745,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, return retval; } -EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); +EXPORT_SYMBOL_GPL(usb_register_driver); /** * usb_deregister - unregister a USB interface driver @@ -769,7 +769,7 @@ void usb_deregister(struct usb_driver *driver) usbfs_update_special(); } -EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); +EXPORT_SYMBOL_GPL(usb_deregister); #ifdef CONFIG_PM @@ -854,8 +854,10 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) dev_err(&intf->dev, "%s error %d\n", "suspend", status); } else { - // FIXME else if there's no suspend method, disconnect... - // Not possible if auto_pm is set... + /* + * FIXME else if there's no suspend method, disconnect... + * Not possible if auto_pm is set... + */ dev_warn(&intf->dev, "no suspend for driver %s?\n", driver->name); mark_quiesced(intf); @@ -894,7 +896,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) dev_err(&intf->dev, "%s error %d\n", "reset_resume", status); } else { - // status = -EOPNOTSUPP; + /* status = -EOPNOTSUPP; */ dev_warn(&intf->dev, "no %s for driver %s?\n", "reset_resume", driver->name); } @@ -905,7 +907,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) dev_err(&intf->dev, "%s error %d\n", "resume", status); } else { - // status = -EOPNOTSUPP; + /* status = -EOPNOTSUPP; */ dev_warn(&intf->dev, "no %s for driver %s?\n", "resume", driver->name); } @@ -1175,7 +1177,7 @@ static int usb_resume_both(struct usb_device *udev) * so if a root hub's controller is suspended * then we're stuck. */ status = usb_resume_device(udev); - } + } } else { /* Needed for setting udev->dev.power.power_state.event, diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 5d860bc9b42..8133c99c6c5 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -204,7 +204,7 @@ int usb_register_dev(struct usb_interface *intf, exit: return retval; } -EXPORT_SYMBOL(usb_register_dev); +EXPORT_SYMBOL_GPL(usb_register_dev); /** * usb_deregister_dev - deregister a USB device's dynamic minor. @@ -245,4 +245,4 @@ void usb_deregister_dev(struct usb_interface *intf, intf->minor = -1; destroy_usb_class(); } -EXPORT_SYMBOL(usb_deregister_dev); +EXPORT_SYMBOL_GPL(usb_deregister_dev); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 3fb9af80cbf..84760ddbc33 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -1,6 +1,6 @@ /* * (C) Copyright David Brownell 2000-2002 - * + * * 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 @@ -55,7 +55,7 @@ * * Store this function in the HCD's struct pci_driver as probe(). */ -int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct hc_driver *driver; struct usb_hcd *hcd; @@ -64,66 +64,71 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) if (usb_disabled()) return -ENODEV; - if (!id || !(driver = (struct hc_driver *) id->driver_data)) + if (!id) + return -EINVAL; + driver = (struct hc_driver *)id->driver_data; + if (!driver) return -EINVAL; - if (pci_enable_device (dev) < 0) + if (pci_enable_device(dev) < 0) return -ENODEV; dev->current_state = PCI_D0; dev->dev.power.power_state = PMSG_ON; - - if (!dev->irq) { - dev_err (&dev->dev, + + if (!dev->irq) { + dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); - retval = -ENODEV; + retval = -ENODEV; goto err1; - } + } - hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev)); + hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); if (!hcd) { retval = -ENOMEM; goto err1; } - if (driver->flags & HCD_MEMORY) { // EHCI, OHCI - hcd->rsrc_start = pci_resource_start (dev, 0); - hcd->rsrc_len = pci_resource_len (dev, 0); - if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len, + if (driver->flags & HCD_MEMORY) { + /* EHCI, OHCI */ + hcd->rsrc_start = pci_resource_start(dev, 0); + hcd->rsrc_len = pci_resource_len(dev, 0); + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { - dev_dbg (&dev->dev, "controller already in use\n"); + dev_dbg(&dev->dev, "controller already in use\n"); retval = -EBUSY; goto err2; } - hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { - dev_dbg (&dev->dev, "error mapping memory\n"); + dev_dbg(&dev->dev, "error mapping memory\n"); retval = -EFAULT; goto err3; } - } else { // UHCI + } else { + /* UHCI */ int region; for (region = 0; region < PCI_ROM_RESOURCE; region++) { - if (!(pci_resource_flags (dev, region) & + if (!(pci_resource_flags(dev, region) & IORESOURCE_IO)) continue; - hcd->rsrc_start = pci_resource_start (dev, region); - hcd->rsrc_len = pci_resource_len (dev, region); - if (request_region (hcd->rsrc_start, hcd->rsrc_len, + hcd->rsrc_start = pci_resource_start(dev, region); + hcd->rsrc_len = pci_resource_len(dev, region); + if (request_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) break; } if (region == PCI_ROM_RESOURCE) { - dev_dbg (&dev->dev, "no i/o regions available\n"); + dev_dbg(&dev->dev, "no i/o regions available\n"); retval = -EBUSY; goto err1; } } - pci_set_master (dev); + pci_set_master(dev); retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) @@ -132,19 +137,19 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) err4: if (driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); + iounmap(hcd->regs); err3: - release_mem_region (hcd->rsrc_start, hcd->rsrc_len); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else - release_region (hcd->rsrc_start, hcd->rsrc_len); + release_region(hcd->rsrc_start, hcd->rsrc_len); err2: - usb_put_hcd (hcd); + usb_put_hcd(hcd); err1: - pci_disable_device (dev); - dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); + pci_disable_device(dev); + dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_probe); +} +EXPORT_SYMBOL_GPL(usb_hcd_pci_probe); /* may be called without controller electrically present */ @@ -161,7 +166,7 @@ EXPORT_SYMBOL (usb_hcd_pci_probe); * * Store this function in the HCD's struct pci_driver as remove(). */ -void usb_hcd_pci_remove (struct pci_dev *dev) +void usb_hcd_pci_remove(struct pci_dev *dev) { struct usb_hcd *hcd; @@ -169,17 +174,17 @@ void usb_hcd_pci_remove (struct pci_dev *dev) if (!hcd) return; - usb_remove_hcd (hcd); + usb_remove_hcd(hcd); if (hcd->driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); - release_mem_region (hcd->rsrc_start, hcd->rsrc_len); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else { - release_region (hcd->rsrc_start, hcd->rsrc_len); + release_region(hcd->rsrc_start, hcd->rsrc_len); } - usb_put_hcd (hcd); + usb_put_hcd(hcd); pci_disable_device(dev); } -EXPORT_SYMBOL (usb_hcd_pci_remove); +EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); #ifdef CONFIG_PM @@ -191,7 +196,7 @@ EXPORT_SYMBOL (usb_hcd_pci_remove); * * Store this function in the HCD's struct pci_driver as suspend(). */ -int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) +int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) { struct usb_hcd *hcd; int retval = 0; @@ -246,12 +251,18 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) /* no DMA or IRQs except when HC is active */ if (dev->current_state == PCI_D0) { - pci_save_state (dev); - pci_disable_device (dev); + pci_save_state(dev); + pci_disable_device(dev); + } + + if (message.event == PM_EVENT_FREEZE || + message.event == PM_EVENT_PRETHAW) { + dev_dbg(hcd->self.controller, "--> no state change\n"); + goto done; } if (!has_pci_pm) { - dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); + dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n"); goto done; } @@ -260,30 +271,30 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset * some device state (e.g. as part of clock reinit). */ - retval = pci_set_power_state (dev, PCI_D3hot); + retval = pci_set_power_state(dev, PCI_D3hot); suspend_report_result(pci_set_power_state, retval); if (retval == 0) { int wake = device_can_wakeup(&hcd->self.root_hub->dev); wake = wake && device_may_wakeup(hcd->self.controller); - dev_dbg (hcd->self.controller, "--> PCI D3%s\n", + dev_dbg(hcd->self.controller, "--> PCI D3%s\n", wake ? "/wakeup" : ""); /* Ignore these return values. We rely on pci code to * reject requests the hardware can't implement, rather * than coding the same thing. */ - (void) pci_enable_wake (dev, PCI_D3hot, wake); - (void) pci_enable_wake (dev, PCI_D3cold, wake); + (void) pci_enable_wake(dev, PCI_D3hot, wake); + (void) pci_enable_wake(dev, PCI_D3cold, wake); } else { - dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", + dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n", retval); - (void) usb_hcd_pci_resume (dev); + (void) usb_hcd_pci_resume(dev); } } else if (hcd->state != HC_STATE_HALT) { - dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", + dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n", hcd->state); WARN_ON(1); retval = -EINVAL; @@ -298,7 +309,7 @@ done: if (machine_is(powermac)) { struct device_node *of_node; - of_node = pci_device_to_OF_node (dev); + of_node = pci_device_to_OF_node(dev); if (of_node) pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); @@ -308,7 +319,7 @@ done: return retval; } -EXPORT_SYMBOL (usb_hcd_pci_suspend); +EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); /** * usb_hcd_pci_resume - power management resume of a PCI-based HCD @@ -316,14 +327,14 @@ EXPORT_SYMBOL (usb_hcd_pci_suspend); * * Store this function in the HCD's struct pci_driver as resume(). */ -int usb_hcd_pci_resume (struct pci_dev *dev) +int usb_hcd_pci_resume(struct pci_dev *dev) { struct usb_hcd *hcd; int retval; hcd = pci_get_drvdata(dev); if (hcd->state != HC_STATE_SUSPENDED) { - dev_dbg (hcd->self.controller, + dev_dbg(hcd->self.controller, "can't resume, not suspended!\n"); return 0; } @@ -333,9 +344,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) if (machine_is(powermac)) { struct device_node *of_node; - of_node = pci_device_to_OF_node (dev); + of_node = pci_device_to_OF_node(dev); if (of_node) - pmac_call_feature (PMAC_FTR_USB_ENABLE, + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif @@ -374,8 +385,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev) } #endif /* yes, ignore these results too... */ - (void) pci_enable_wake (dev, dev->current_state, 0); - (void) pci_enable_wake (dev, PCI_D3cold, 0); + (void) pci_enable_wake(dev, dev->current_state, 0); + (void) pci_enable_wake(dev, PCI_D3cold, 0); } else { /* Same basic cases: clean (powered/not), dirty */ dev_dbg(hcd->self.controller, "PCI legacy resume\n"); @@ -386,14 +397,14 @@ int usb_hcd_pci_resume (struct pci_dev *dev) * but that won't re-enable bus mastering. Yet pci_disable_device() * explicitly disables bus mastering... */ - retval = pci_enable_device (dev); + retval = pci_enable_device(dev); if (retval < 0) { - dev_err (hcd->self.controller, + dev_err(hcd->self.controller, "can't re-enable after resume, %d!\n", retval); return retval; } - pci_set_master (dev); - pci_restore_state (dev); + pci_set_master(dev); + pci_restore_state(dev); dev->dev.power.power_state = PMSG_ON; @@ -402,15 +413,15 @@ int usb_hcd_pci_resume (struct pci_dev *dev) if (hcd->driver->resume) { retval = hcd->driver->resume(hcd); if (retval) { - dev_err (hcd->self.controller, + dev_err(hcd->self.controller, "PCI post-resume error %d!\n", retval); - usb_hc_died (hcd); + usb_hc_died(hcd); } } return retval; } -EXPORT_SYMBOL (usb_hcd_pci_resume); +EXPORT_SYMBOL_GPL(usb_hcd_pci_resume); #endif /* CONFIG_PM */ @@ -418,7 +429,7 @@ EXPORT_SYMBOL (usb_hcd_pci_resume); * usb_hcd_pci_shutdown - shutdown host controller * @dev: USB Host Controller being shutdown */ -void usb_hcd_pci_shutdown (struct pci_dev *dev) +void usb_hcd_pci_shutdown(struct pci_dev *dev) { struct usb_hcd *hcd; @@ -429,5 +440,5 @@ void usb_hcd_pci_shutdown (struct pci_dev *dev) if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } -EXPORT_SYMBOL (usb_hcd_pci_shutdown); +EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d5ed3fa9e30..e52ed1663b3 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -35,6 +35,7 @@ #include <linux/mutex.h> #include <asm/irq.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #include <linux/platform_device.h> #include <linux/workqueue.h> @@ -131,8 +132,8 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __le16 idVendor; */ - 0x00, 0x00, /* __le16 idProduct; */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x02, 0x00, /* __le16 idProduct; device 0x0002 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ @@ -154,8 +155,8 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __le16 idVendor; */ - 0x00, 0x00, /* __le16 idProduct; */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x01, 0x00, /* __le16 idProduct; device 0x0001 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ @@ -807,13 +808,13 @@ static int usb_register_bus(struct usb_bus *bus) } set_bit (busnum, busmap.busmap); bus->busnum = busnum; - bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", - busnum); - result = PTR_ERR(bus->class_dev); - if (IS_ERR(bus->class_dev)) + + bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0), + "usb_host%d", busnum); + result = PTR_ERR(bus->dev); + if (IS_ERR(bus->dev)) goto error_create_class_dev; - class_set_devdata(bus->class_dev, bus); + dev_set_drvdata(bus->dev, bus); /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); @@ -857,7 +858,7 @@ static void usb_deregister_bus (struct usb_bus *bus) clear_bit (bus->busnum, busmap.busmap); - class_device_unregister(bus->class_dev); + device_unregister(bus->dev); } /** @@ -970,7 +971,7 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) return -1; } } -EXPORT_SYMBOL (usb_calc_bus_time); +EXPORT_SYMBOL_GPL(usb_calc_bus_time); /*-------------------------------------------------------------------------*/ @@ -1112,48 +1113,177 @@ void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) } EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); -static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +/* + * Some usb host controllers can only perform dma using a small SRAM area. + * The usb core itself is however optimized for host controllers that can dma + * using regular system memory - like pci devices doing bus mastering. + * + * To support host controllers with limited dma capabilites we provide dma + * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag. + * For this to work properly the host controller code must first use the + * function dma_declare_coherent_memory() to point out which memory area + * that should be used for dma allocations. + * + * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for + * dma using dma_alloc_coherent() which in turn allocates from the memory + * area pointed out with dma_declare_coherent_memory(). + * + * So, to summarize... + * + * - We need "local" memory, canonical example being + * a small SRAM on a discrete controller being the + * only memory that the controller can read ... + * (a) "normal" kernel memory is no good, and + * (b) there's not enough to share + * + * - The only *portable* hook for such stuff in the + * DMA framework is dma_declare_coherent_memory() + * + * - So we use that, even though the primary requirement + * is that the memory be "local" (hence addressible + * by that device), not "coherent". + * + */ + +static int hcd_alloc_coherent(struct usb_bus *bus, + gfp_t mem_flags, dma_addr_t *dma_handle, + void **vaddr_handle, size_t size, + enum dma_data_direction dir) +{ + unsigned char *vaddr; + + vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr), + mem_flags, dma_handle); + if (!vaddr) + return -ENOMEM; + + /* + * Store the virtual address of the buffer at the end + * of the allocated dma buffer. The size of the buffer + * may be uneven so use unaligned functions instead + * of just rounding up. It makes sense to optimize for + * memory footprint over access speed since the amount + * of memory available for dma may be limited. + */ + put_unaligned((unsigned long)*vaddr_handle, + (unsigned long *)(vaddr + size)); + + if (dir == DMA_TO_DEVICE) + memcpy(vaddr, *vaddr_handle, size); + + *vaddr_handle = vaddr; + return 0; +} + +static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle, + void **vaddr_handle, size_t size, + enum dma_data_direction dir) +{ + unsigned char *vaddr = *vaddr_handle; + + vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size)); + + if (dir == DMA_FROM_DEVICE) + memcpy(vaddr, *vaddr_handle, size); + + hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle); + + *vaddr_handle = vaddr; + *dma_handle = 0; +} + +static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { + enum dma_data_direction dir; + int ret = 0; + /* Map the URB's buffers for DMA access. * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - urb->setup_dma = dma_map_single ( + if (is_root_hub(urb->dev)) + return 0; + + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (hcd->self.uses_dma) + urb->setup_dma = dma_map_single( hcd->self.controller, urb->setup_packet, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + else if (hcd->driver->flags & HCD_LOCAL_MEM) + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + } + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (ret == 0 && urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (hcd->self.uses_dma) urb->transfer_dma = dma_map_single ( hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + dir); + else if (hcd->driver->flags & HCD_LOCAL_MEM) { + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); + + if (ret && usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + hcd_free_coherent(urb->dev->bus, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } } + return ret; } static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + enum dma_data_direction dir; + + if (is_root_hub(urb->dev)) + return; + + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (hcd->self.uses_dma) dma_unmap_single(hcd->self.controller, urb->setup_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + else if (hcd->driver->flags & HCD_LOCAL_MEM) + hcd_free_coherent(urb->dev->bus, &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (hcd->self.uses_dma) dma_unmap_single(hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + dir); + else if (hcd->driver->flags & HCD_LOCAL_MEM) + hcd_free_coherent(urb->dev->bus, &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); } } @@ -1185,7 +1315,12 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * URBs must be submitted in process context with interrupts * enabled. */ - map_urb_for_dma(hcd, urb); + status = map_urb_for_dma(hcd, urb, mem_flags); + if (unlikely(status)) { + usbmon_urb_submit_error(&hcd->self, urb, status); + goto error; + } + if (is_root_hub(urb->dev)) status = rh_urb_enqueue(hcd, urb); else @@ -1194,6 +1329,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); + error: urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); @@ -1291,7 +1427,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) wake_up (&usb_kill_urb_queue); usb_put_urb (urb); } -EXPORT_SYMBOL (usb_hcd_giveback_urb); +EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ @@ -1531,7 +1667,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); return status; } -EXPORT_SYMBOL (usb_bus_start_enum); +EXPORT_SYMBOL_GPL(usb_bus_start_enum); #endif @@ -1638,7 +1774,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, "USB Host Controller"; return hcd; } -EXPORT_SYMBOL (usb_create_hcd); +EXPORT_SYMBOL_GPL(usb_create_hcd); static void hcd_release (struct kref *kref) { @@ -1653,14 +1789,14 @@ struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) kref_get (&hcd->kref); return hcd; } -EXPORT_SYMBOL (usb_get_hcd); +EXPORT_SYMBOL_GPL(usb_get_hcd); void usb_put_hcd (struct usb_hcd *hcd) { if (hcd) kref_put (&hcd->kref, hcd_release); } -EXPORT_SYMBOL (usb_put_hcd); +EXPORT_SYMBOL_GPL(usb_put_hcd); /** * usb_add_hcd - finish generic HCD structure initialization and register @@ -1786,7 +1922,7 @@ err_register_bus: hcd_buffer_destroy(hcd); return retval; } -EXPORT_SYMBOL (usb_add_hcd); +EXPORT_SYMBOL_GPL(usb_add_hcd); /** * usb_remove_hcd - shutdown processing for generic HCDs @@ -1828,7 +1964,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); } -EXPORT_SYMBOL (usb_remove_hcd); +EXPORT_SYMBOL_GPL(usb_remove_hcd); void usb_hcd_platform_shutdown(struct platform_device* dev) @@ -1838,7 +1974,7 @@ usb_hcd_platform_shutdown(struct platform_device* dev) if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } -EXPORT_SYMBOL (usb_hcd_platform_shutdown); +EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 98e24194a4a..2d1c3d5e47b 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -125,7 +125,7 @@ struct usb_hcd { /* more shared queuing code would be good; it should support * smarter scheduling, handle transaction translators, etc; - * input size of periodic table to an interrupt scheduler. + * input size of periodic table to an interrupt scheduler. * (ohci 32, uhci 1024, ehci 256/512/1024). */ @@ -133,16 +133,16 @@ struct usb_hcd { * this structure. */ unsigned long hcd_priv[0] - __attribute__ ((aligned (sizeof(unsigned long)))); + __attribute__ ((aligned(sizeof(unsigned long)))); }; /* 2.4 does this a bit differently ... */ -static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) +static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd) { return &hcd->self; } -static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus) +static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus) { return container_of(bus, struct usb_hcd, self); } @@ -165,6 +165,7 @@ struct hc_driver { int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */ #define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB2 0x0020 /* USB 2.0 */ @@ -201,15 +202,18 @@ struct hc_driver { struct usb_host_endpoint *ep); /* root hub support */ - int (*hub_status_data) (struct usb_hcd *hcd, char *buf); - int (*hub_control) (struct usb_hcd *hcd, + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); - int (*bus_suspend)(struct usb_hcd *); - int (*bus_resume)(struct usb_hcd *); - int (*start_port_reset)(struct usb_hcd *, unsigned port_num); - void (*hub_irq_enable)(struct usb_hcd *); + int (*bus_suspend)(struct usb_hcd *); + int (*bus_resume)(struct usb_hcd *); + int (*start_port_reset)(struct usb_hcd *, unsigned port_num); + void (*hub_irq_enable)(struct usb_hcd *); /* Needed only if port-change IRQs are level-triggered */ + + /* force handover of high-speed port to full-speed companion */ + void (*relinquish_port)(struct usb_hcd *, int); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); @@ -217,56 +221,56 @@ extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status); extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); -extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); -extern int usb_hcd_unlink_urb (struct urb *urb, int status); +extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags); +extern int usb_hcd_unlink_urb(struct urb *urb, int status); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); -extern int usb_hcd_get_frame_number (struct usb_device *udev); +extern int usb_hcd_get_frame_number(struct usb_device *udev); -extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, +extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, char *bus_name); -extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd); -extern void usb_put_hcd (struct usb_hcd *hcd); +extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd); +extern void usb_put_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); struct platform_device; -extern void usb_hcd_platform_shutdown(struct platform_device* dev); +extern void usb_hcd_platform_shutdown(struct platform_device *dev); #ifdef CONFIG_PCI struct pci_dev; struct pci_device_id; -extern int usb_hcd_pci_probe (struct pci_dev *dev, +extern int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); -extern void usb_hcd_pci_remove (struct pci_dev *dev); +extern void usb_hcd_pci_remove(struct pci_dev *dev); #ifdef CONFIG_PM -extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state); -extern int usb_hcd_pci_resume (struct pci_dev *dev); +extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state); +extern int usb_hcd_pci_resume(struct pci_dev *dev); #endif /* CONFIG_PM */ -extern void usb_hcd_pci_shutdown (struct pci_dev *dev); +extern void usb_hcd_pci_shutdown(struct pci_dev *dev); #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ -int hcd_buffer_create (struct usb_hcd *hcd); -void hcd_buffer_destroy (struct usb_hcd *hcd); +int hcd_buffer_create(struct usb_hcd *hcd); +void hcd_buffer_destroy(struct usb_hcd *hcd); -void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, +void *hcd_buffer_alloc(struct usb_bus *bus, size_t size, gfp_t mem_flags, dma_addr_t *dma); -void hcd_buffer_free (struct usb_bus *bus, size_t size, +void hcd_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); /* generic bus glue, needed for host controllers that don't use PCI */ -extern irqreturn_t usb_hcd_irq (int irq, void *__hcd); +extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); -extern void usb_hc_died (struct usb_hcd *hcd); +extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); /* -------------------------------------------------------------------------- */ @@ -319,9 +323,9 @@ extern void usb_destroy_configuration(struct usb_device *dev); * Generic bandwidth allocation constants/support */ #define FRAME_TIME_USECS 1000L -#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ +#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ /* Trying not to use worst-case bit-stuffing - of (7/6 * 8 * bytecount) = 9.33 * bytecount */ + * of (7/6 * 8 * bytecount) = 9.33 * bytecount */ /* bytecount = data payload byte count */ #define NS_TO_US(ns) ((ns + 500L) / 1000L) @@ -333,9 +337,9 @@ extern void usb_destroy_configuration(struct usb_device *dev); */ #define BW_HOST_DELAY 1000L /* nanoseconds */ #define BW_HUB_LS_SETUP 333L /* nanoseconds */ - /* 4 full-speed bit times (est.) */ + /* 4 full-speed bit times (est.) */ -#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ +#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ #define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) #define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) @@ -345,16 +349,16 @@ extern void usb_destroy_configuration(struct usb_device *dev); * to preallocate bandwidth) */ #define USB2_HOST_DELAY 5 /* nsec, guess */ -#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \ +#define HS_NSECS(bytes) (((55 * 8 * 2083) \ + (2083UL * (3 + BitTime(bytes))))/1000 \ + USB2_HOST_DELAY) -#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \ +#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \ + (2083UL * (3 + BitTime(bytes))))/1000 \ + USB2_HOST_DELAY) #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes)) #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes)) -extern long usb_calc_bus_time (int speed, int is_input, +extern long usb_calc_bus_time(int speed, int is_input, int isoc, int bytecount); /*-------------------------------------------------------------------------*/ @@ -370,16 +374,16 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; -extern void usb_enable_root_hub_irq (struct usb_bus *bus); +extern void usb_enable_root_hub_irq(struct usb_bus *bus); -extern int usb_find_interface_driver (struct usb_device *dev, +extern int usb_find_interface_driver(struct usb_device *dev, struct usb_interface *interface); #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #ifdef CONFIG_PM -extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); -extern void usb_root_hub_lost_power (struct usb_device *rhdev); +extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); +extern void usb_root_hub_lost_power(struct usb_device *rhdev); extern int hcd_bus_suspend(struct usb_device *rhdev); extern int hcd_bus_resume(struct usb_device *rhdev); #else @@ -399,13 +403,13 @@ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbfs_update_special (void); +extern void usbfs_update_special(void); extern int usbfs_init(void); extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbfs_update_special (void) {} +static inline void usbfs_update_special(void) {} static inline int usbfs_init(void) { return 0; } static inline void usbfs_cleanup(void) { } @@ -460,7 +464,7 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, /*-------------------------------------------------------------------------*/ /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ -// bleech -- resurfaced in 2.4.11 or 2.4.12 +/* bleech -- resurfaced in 2.4.11 or 2.4.12 */ #define bitmap DeviceRemovable @@ -468,8 +472,8 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, /* random stuff */ -#define RUN_CONTEXT (in_irq () ? "in_irq" \ - : (in_interrupt () ? "in_interrupt" : "can sleep")) +#define RUN_CONTEXT (in_irq() ? "in_irq" \ + : (in_interrupt() ? "in_interrupt" : "can sleep")) /* This rwsem is for use only by the hub driver and ehci-hcd. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b04d232d4c6..68fc5219ca1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -37,6 +37,13 @@ #define USB_PERSIST 0 #endif +/* if we are in debug mode, always announce new devices */ +#ifdef DEBUG +#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES +#define CONFIG_USB_ANNOUNCE_NEW_DEVICES +#endif +#endif + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -487,6 +494,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) schedule_work (&tt->kevent); spin_unlock_irqrestore (&tt->lock, flags); } +EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); static void hub_power_on(struct usb_hub *hub) { @@ -1027,8 +1035,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->children[i]) recursively_mark_NOTATTACHED(udev->children[i]); } - if (udev->state == USB_STATE_SUSPENDED) + if (udev->state == USB_STATE_SUSPENDED) { udev->discon_suspended = 1; + udev->active_duration -= jiffies; + } udev->state = USB_STATE_NOTATTACHED; } @@ -1077,6 +1087,12 @@ void usb_set_device_state(struct usb_device *udev, else device_init_wakeup(&udev->dev, 0); } + if (udev->state == USB_STATE_SUSPENDED && + new_state != USB_STATE_SUSPENDED) + udev->active_duration -= jiffies; + else if (new_state == USB_STATE_SUSPENDED && + udev->state != USB_STATE_SUSPENDED) + udev->active_duration += jiffies; udev->state = new_state; } else recursively_mark_NOTATTACHED(udev); @@ -1207,7 +1223,7 @@ void usb_disconnect(struct usb_device **pdev) put_device(&udev->dev); } -#ifdef DEBUG +#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES static void show_string(struct usb_device *udev, char *id, char *string) { if (!string) @@ -1215,12 +1231,24 @@ static void show_string(struct usb_device *udev, char *id, char *string) dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); } +static void announce_device(struct usb_device *udev) +{ + dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); +} #else -static inline void show_string(struct usb_device *udev, char *id, char *string) -{} +static inline void announce_device(struct usb_device *udev) { } #endif - #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" #endif @@ -1390,14 +1418,7 @@ int usb_new_device(struct usb_device *udev) } /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + announce_device(udev); return err; fail: @@ -2482,6 +2503,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); int status, i; @@ -2645,6 +2667,8 @@ loop: done: hub_port_disable(hub, port1, 1); + if (hcd->driver->relinquish_port && !hub->hdev->parent) + hcd->driver->relinquish_port(hcd, port1); } static void hub_events(void) @@ -2946,7 +2970,7 @@ static int config_descriptors_changed(struct usb_device *udev) if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) len = le16_to_cpu(udev->config[index].desc.wTotalLength); } - buf = kmalloc (len, GFP_KERNEL); + buf = kmalloc(len, GFP_NOIO); if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); /* assume the worst */ @@ -3093,7 +3117,7 @@ re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } -EXPORT_SYMBOL(usb_reset_device); +EXPORT_SYMBOL_GPL(usb_reset_device); /** * usb_reset_composite_device - warn interface drivers and perform a USB port reset @@ -3110,16 +3134,12 @@ EXPORT_SYMBOL(usb_reset_device); * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock * the device using usb_lock_device_for_reset(). - * - * The interface locks are acquired during the pre_reset stage and released - * during the post_reset stage. However if iface is not NULL and is - * currently being probed, we assume that the caller already owns its - * lock. */ int usb_reset_composite_device(struct usb_device *udev, struct usb_interface *iface) { int ret; + int i; struct usb_host_config *config = udev->actconfig; if (udev->state == USB_STATE_NOTATTACHED || @@ -3136,16 +3156,11 @@ int usb_reset_composite_device(struct usb_device *udev, iface = NULL; if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - cintf = config->interface[i]; - if (cintf != iface) - down(&cintf->dev.sem); - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { + struct usb_interface *cintf = config->interface[i]; + struct usb_driver *drv; + + if (cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); if (drv->pre_reset) (drv->pre_reset)(cintf); @@ -3157,25 +3172,20 @@ int usb_reset_composite_device(struct usb_device *udev, ret = usb_reset_device(udev); if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { - cintf = config->interface[i]; - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { + struct usb_interface *cintf = config->interface[i]; + struct usb_driver *drv; + + if (cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); if (drv->post_reset) (drv->post_reset)(cintf); /* FIXME: Unbind if post_reset returns an error or isn't defined */ } - if (cintf != iface) - up(&cintf->dev.sem); } } usb_autosuspend_device(udev); return ret; } -EXPORT_SYMBOL(usb_reset_composite_device); +EXPORT_SYMBOL_GPL(usb_reset_composite_device); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index cf9559c6c9b..1551aed65e0 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -55,16 +55,16 @@ #define USB_PORT_FEAT_TEST 21 #define USB_PORT_FEAT_INDICATOR 22 -/* +/* * Hub Status and Hub Change results * See USB 2.0 spec Table 11-19 and Table 11-20 */ struct usb_port_status { __le16 wPortStatus; - __le16 wPortChange; + __le16 wPortChange; } __attribute__ ((packed)); -/* +/* * wPortStatus bit field * See USB 2.0 spec Table 11-21 */ @@ -81,7 +81,7 @@ struct usb_port_status { #define USB_PORT_STAT_INDICATOR 0x1000 /* bits 13 to 15 are reserved */ -/* +/* * wPortChange bit field * See USB 2.0 spec Table 11-22 * Bits 0 to 4 shown, bits 5 to 15 are reserved @@ -93,7 +93,7 @@ struct usb_port_status { #define USB_PORT_STAT_C_RESET 0x0010 /* - * wHubCharacteristics (masks) + * wHubCharacteristics (masks) * See USB 2.0 spec Table 11-13, offset 3 */ #define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ @@ -119,8 +119,8 @@ struct usb_hub_status { #define HUB_CHANGE_OVERCURRENT 0x0002 -/* - * Hub descriptor +/* + * Hub descriptor * See USB 2.0 spec Table 11-13 */ @@ -134,7 +134,7 @@ struct usb_hub_descriptor { __le16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; - /* add 1 bit for hub status change; round to bytes */ + /* add 1 bit for hub status change; round to bytes */ __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; } __attribute__ ((packed)); @@ -190,6 +190,6 @@ struct usb_tt_clear { u16 devinfo; }; -extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); +extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index cd4f1115728..83a373e9cc3 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -38,10 +38,15 @@ #include <linux/usbdevice_fs.h> #include <linux/parser.h> #include <linux/notifier.h> +#include <linux/seq_file.h> #include <asm/byteorder.h> #include "usb.h" #include "hcd.h" +#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) +#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) +#define USBFS_DEFAULT_LISTMODE S_IRUGO + static struct super_operations usbfs_ops; static const struct file_operations default_file_operations; static struct vfsmount *usbfs_mount; @@ -57,9 +62,33 @@ static uid_t listuid; /* = 0 */ static gid_t devgid; /* = 0 */ static gid_t busgid; /* = 0 */ static gid_t listgid; /* = 0 */ -static umode_t devmode = S_IWUSR | S_IRUGO; -static umode_t busmode = S_IXUGO | S_IRUGO; -static umode_t listmode = S_IRUGO; +static umode_t devmode = USBFS_DEFAULT_DEVMODE; +static umode_t busmode = USBFS_DEFAULT_BUSMODE; +static umode_t listmode = USBFS_DEFAULT_LISTMODE; + +static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt) +{ + if (devuid != 0) + seq_printf(seq, ",devuid=%u", devuid); + if (devgid != 0) + seq_printf(seq, ",devgid=%u", devgid); + if (devmode != USBFS_DEFAULT_DEVMODE) + seq_printf(seq, ",devmode=%o", devmode); + if (busuid != 0) + seq_printf(seq, ",busuid=%u", busuid); + if (busgid != 0) + seq_printf(seq, ",busgid=%u", busgid); + if (busmode != USBFS_DEFAULT_BUSMODE) + seq_printf(seq, ",busmode=%o", busmode); + if (listuid != 0) + seq_printf(seq, ",listuid=%u", listuid); + if (listgid != 0) + seq_printf(seq, ",listgid=%u", listgid); + if (listmode != USBFS_DEFAULT_LISTMODE) + seq_printf(seq, ",listmode=%o", listmode); + + return 0; +} enum { Opt_devuid, Opt_devgid, Opt_devmode, @@ -93,9 +122,9 @@ static int parse_options(struct super_block *s, char *data) devgid = 0; busgid = 0; listgid = 0; - devmode = S_IWUSR | S_IRUGO; - busmode = S_IXUGO | S_IRUGO; - listmode = S_IRUGO; + devmode = USBFS_DEFAULT_DEVMODE; + busmode = USBFS_DEFAULT_BUSMODE; + listmode = USBFS_DEFAULT_LISTMODE; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -418,6 +447,7 @@ static struct super_operations usbfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .remount_fs = remount, + .show_options = usbfs_show_options, }; static int usbfs_fill_super(struct super_block *sb, void *data, int silent) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fcd40ecbeec..fefb92296e8 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -39,7 +39,7 @@ static void usb_api_blocking_completion(struct urb *urb) * own interruptible routines. */ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) -{ +{ struct api_context ctx; unsigned long expire; int retval; @@ -74,9 +74,9 @@ out: } /*-------------------------------------------------------------------*/ -// returns status (negative) or length (positive) +/* returns status (negative) or length (positive) */ static int usb_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, + unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout) { @@ -87,7 +87,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) return -ENOMEM; - + usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, len, usb_api_blocking_completion, NULL); @@ -99,47 +99,51 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, } /** - * usb_control_msg - Builds a control urb, sends it off and waits for completion - * @dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @request: USB message request value - * @requesttype: USB message request type value - * @value: USB message value - * @index: USB message index value - * @data: pointer to the data to send - * @size: length in bytes of the data to send - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple control message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns the number of bytes transferred, otherwise a negative error number. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to send - * a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. + * usb_control_msg - Builds a control urb, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @data: pointer to the data to send + * @size: length in bytes of the data to send + * @timeout: time in msecs to wait for the message to complete before timing + * out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a simple control message to a specified endpoint and + * waits for the message to complete, or timeout. + * + * If successful, it returns the number of bytes transferred, otherwise a + * negative error number. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb(). + * If a thread in your driver uses this call, make sure your disconnect() + * method can wait for it to complete. Since you don't have a handle on the + * URB used, you can't cancel the request. */ -int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, __u16 size, int timeout) +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, + __u8 requesttype, __u16 value, __u16 index, void *data, + __u16 size, int timeout) { - struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); + struct usb_ctrlrequest *dr; int ret; - + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); if (!dr) return -ENOMEM; - dr->bRequestType= requesttype; + dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16p(&value); dr->wIndex = cpu_to_le16p(&index); dr->wLength = cpu_to_le16p(&size); - //dbg("usb_control_msg"); + /* dbg("usb_control_msg"); */ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); @@ -147,7 +151,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u return ret; } - +EXPORT_SYMBOL_GPL(usb_control_msg); /** * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion @@ -155,9 +159,11 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * @pipe: endpoint "pipe" to send the message to * @data: pointer to the data to send * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred in bytes + * @actual_length: pointer to a location to put the actual length transferred + * in bytes * @timeout: time in msecs to wait for the message to complete before * timing out (if 0 the wait is forever) + * * Context: !in_interrupt () * * This function sends a simple interrupt message to a specified endpoint and @@ -181,38 +187,38 @@ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, EXPORT_SYMBOL_GPL(usb_interrupt_msg); /** - * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion - * @usb_dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @data: pointer to the data to send - * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple bulk message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns 0, otherwise a negative error number. - * The number of actual bytes transferred will be stored in the - * actual_length paramater. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to - * send a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. - * - * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT - * ioctl, users are forced to abuse this routine by using it to submit - * URBs for interrupt endpoints. We will take the liberty of creating - * an interrupt URB (with the default interval) if the target is an - * interrupt endpoint. + * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred + * in bytes + * @timeout: time in msecs to wait for the message to complete before + * timing out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a simple bulk message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns 0, otherwise a negative error number. The number + * of actual bytes transferred will be stored in the actual_length paramater. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb() If a thread in your + * driver uses this call, make sure your disconnect() method can wait for it to + * complete. Since you don't have a handle on the URB used, you can't cancel + * the request. + * + * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl, + * users are forced to abuse this routine by using it to submit URBs for + * interrupt endpoints. We will take the liberty of creating an interrupt URB + * (with the default interval) if the target is an interrupt endpoint. */ -int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) +int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) { struct urb *urb; struct usb_host_endpoint *ep; @@ -238,29 +244,30 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, return usb_start_wait_urb(urb, timeout, actual_length); } +EXPORT_SYMBOL_GPL(usb_bulk_msg); /*-------------------------------------------------------------------*/ -static void sg_clean (struct usb_sg_request *io) +static void sg_clean(struct usb_sg_request *io) { if (io->urbs) { while (io->entries--) - usb_free_urb (io->urbs [io->entries]); - kfree (io->urbs); + usb_free_urb(io->urbs [io->entries]); + kfree(io->urbs); io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), - io->sg, io->nents); + usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } -static void sg_complete (struct urb *urb) +static void sg_complete(struct urb *urb) { - struct usb_sg_request *io = urb->context; + struct usb_sg_request *io = urb->context; int status = urb->status; - spin_lock (&io->lock); + spin_lock(&io->lock); /* In 2.5 we require hcds' endpoint queues not to progress after fault * reports, until the completion callback (this!) returns. That lets @@ -276,13 +283,13 @@ static void sg_complete (struct urb *urb) && (io->status != -ECONNRESET || status != -ECONNRESET) && urb->actual_length) { - dev_err (io->dev->bus->controller, + dev_err(io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, usb_endpoint_num(&urb->ep->desc), usb_urb_dir_in(urb) ? "in" : "out", status, io->status); - // BUG (); + /* BUG (); */ } if (io->status == 0 && status && status != -ECONNRESET) { @@ -294,22 +301,22 @@ static void sg_complete (struct urb *urb) * unlink pending urbs so they won't rx/tx bad data. * careful: unlink can sometimes be synchronous... */ - spin_unlock (&io->lock); + spin_unlock(&io->lock); for (i = 0, found = 0; i < io->entries; i++) { if (!io->urbs [i] || !io->urbs [i]->dev) continue; if (found) { - retval = usb_unlink_urb (io->urbs [i]); + retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -ENODEV && retval != -EBUSY) - dev_err (&io->dev->dev, + dev_err(&io->dev->dev, "%s, unlink --> %d\n", __FUNCTION__, retval); } else if (urb == io->urbs [i]) found = 1; } - spin_lock (&io->lock); + spin_lock(&io->lock); } urb->dev = NULL; @@ -317,9 +324,9 @@ static void sg_complete (struct urb *urb) io->bytes += urb->actual_length; io->count--; if (!io->count) - complete (&io->complete); + complete(&io->complete); - spin_unlock (&io->lock); + spin_unlock(&io->lock); } @@ -348,28 +355,21 @@ static void sg_complete (struct urb *urb) * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. */ -int usb_sg_init ( - struct usb_sg_request *io, - struct usb_device *dev, - unsigned pipe, - unsigned period, - struct scatterlist *sg, - int nents, - size_t length, - gfp_t mem_flags -) +int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, + unsigned pipe, unsigned period, struct scatterlist *sg, + int nents, size_t length, gfp_t mem_flags) { - int i; - int urb_flags; - int dma; + int i; + int urb_flags; + int dma; if (!io || !dev || !sg - || usb_pipecontrol (pipe) - || usb_pipeisoc (pipe) + || usb_pipecontrol(pipe) + || usb_pipeisoc(pipe) || nents <= 0) return -EINVAL; - spin_lock_init (&io->lock); + spin_lock_init(&io->lock); io->dev = dev; io->pipe = pipe; io->sg = sg; @@ -381,7 +381,7 @@ int usb_sg_init ( dma = (dev->dev.dma_mask != NULL); if (dma) io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), - sg, nents); + sg, nents); else io->entries = nents; @@ -390,30 +390,30 @@ int usb_sg_init ( return io->entries; io->count = io->entries; - io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); + io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; - if (usb_pipein (pipe)) + if (usb_pipein(pipe)) urb_flags |= URB_SHORT_NOT_OK; for (i = 0; i < io->entries; i++) { - unsigned len; + unsigned len; - io->urbs [i] = usb_alloc_urb (0, mem_flags); - if (!io->urbs [i]) { + io->urbs[i] = usb_alloc_urb(0, mem_flags); + if (!io->urbs[i]) { io->entries = i; goto nomem; } - io->urbs [i]->dev = NULL; - io->urbs [i]->pipe = pipe; - io->urbs [i]->interval = period; - io->urbs [i]->transfer_flags = urb_flags; + io->urbs[i]->dev = NULL; + io->urbs[i]->pipe = pipe; + io->urbs[i]->interval = period; + io->urbs[i]->transfer_flags = urb_flags; - io->urbs [i]->complete = sg_complete; - io->urbs [i]->context = io; + io->urbs[i]->complete = sg_complete; + io->urbs[i]->context = io; /* * Some systems need to revert to PIO when DMA is temporarily @@ -432,8 +432,8 @@ int usb_sg_init ( * to prevent stale pointers and to help spot bugs. */ if (dma) { - io->urbs [i]->transfer_dma = sg_dma_address (sg + i); - len = sg_dma_len (sg + i); + io->urbs[i]->transfer_dma = sg_dma_address(sg + i); + len = sg_dma_len(sg + i); #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU) io->urbs[i]->transfer_buffer = NULL; #else @@ -441,31 +441,31 @@ int usb_sg_init ( #endif } else { /* hc may use _only_ transfer_buffer */ - io->urbs [i]->transfer_buffer = sg_virt(&sg[i]); - len = sg [i].length; + io->urbs[i]->transfer_buffer = sg_virt(&sg[i]); + len = sg[i].length; } if (length) { - len = min_t (unsigned, len, length); + len = min_t(unsigned, len, length); length -= len; if (length == 0) io->entries = i + 1; } - io->urbs [i]->transfer_buffer_length = len; + io->urbs[i]->transfer_buffer_length = len; } - io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; + io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; /* transaction state */ io->status = 0; io->bytes = 0; - init_completion (&io->complete); + init_completion(&io->complete); return 0; nomem: - sg_clean (io); + sg_clean(io); return -ENOMEM; } - +EXPORT_SYMBOL_GPL(usb_sg_init); /** * usb_sg_wait - synchronously execute scatter/gather request @@ -506,31 +506,32 @@ nomem: * speed interrupt endpoints, which allow at most one packet per millisecond, * of at most 8 or 64 bytes (respectively). */ -void usb_sg_wait (struct usb_sg_request *io) +void usb_sg_wait(struct usb_sg_request *io) { - int i, entries = io->entries; + int i; + int entries = io->entries; /* queue the urbs. */ - spin_lock_irq (&io->lock); + spin_lock_irq(&io->lock); i = 0; while (i < entries && !io->status) { - int retval; + int retval; - io->urbs [i]->dev = io->dev; - retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC); + io->urbs[i]->dev = io->dev; + retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC); /* after we submit, let completions or cancelations fire; * we handshake using io->status. */ - spin_unlock_irq (&io->lock); + spin_unlock_irq(&io->lock); switch (retval) { /* maybe we retrying will recover */ - case -ENXIO: // hc didn't queue this one + case -ENXIO: /* hc didn't queue this one */ case -EAGAIN: case -ENOMEM: io->urbs[i]->dev = NULL; retval = 0; - yield (); + yield(); break; /* no error? continue immediately. @@ -541,34 +542,35 @@ void usb_sg_wait (struct usb_sg_request *io) */ case 0: ++i; - cpu_relax (); + cpu_relax(); break; /* fail any uncompleted urbs */ default: - io->urbs [i]->dev = NULL; - io->urbs [i]->status = retval; - dev_dbg (&io->dev->dev, "%s, submit --> %d\n", + io->urbs[i]->dev = NULL; + io->urbs[i]->status = retval; + dev_dbg(&io->dev->dev, "%s, submit --> %d\n", __FUNCTION__, retval); - usb_sg_cancel (io); + usb_sg_cancel(io); } - spin_lock_irq (&io->lock); + spin_lock_irq(&io->lock); if (retval && (io->status == 0 || io->status == -ECONNRESET)) io->status = retval; } io->count -= entries - i; if (io->count == 0) - complete (&io->complete); - spin_unlock_irq (&io->lock); + complete(&io->complete); + spin_unlock_irq(&io->lock); /* OK, yes, this could be packaged as non-blocking. * So could the submit loop above ... but it's easier to * solve neither problem than to solve both! */ - wait_for_completion (&io->complete); + wait_for_completion(&io->complete); - sg_clean (io); + sg_clean(io); } +EXPORT_SYMBOL_GPL(usb_sg_wait); /** * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() @@ -578,32 +580,33 @@ void usb_sg_wait (struct usb_sg_request *io) * It can also prevents one initialized by usb_sg_init() from starting, * so that call just frees resources allocated to the request. */ -void usb_sg_cancel (struct usb_sg_request *io) +void usb_sg_cancel(struct usb_sg_request *io) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave (&io->lock, flags); + spin_lock_irqsave(&io->lock, flags); /* shut everything down, if it didn't already */ if (!io->status) { - int i; + int i; io->status = -ECONNRESET; - spin_unlock (&io->lock); + spin_unlock(&io->lock); for (i = 0; i < io->entries; i++) { - int retval; + int retval; if (!io->urbs [i]->dev) continue; - retval = usb_unlink_urb (io->urbs [i]); + retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -EBUSY) - dev_warn (&io->dev->dev, "%s, unlink --> %d\n", + dev_warn(&io->dev->dev, "%s, unlink --> %d\n", __FUNCTION__, retval); } - spin_lock (&io->lock); + spin_lock(&io->lock); } - spin_unlock_irqrestore (&io->lock, flags); + spin_unlock_irqrestore(&io->lock, flags); } +EXPORT_SYMBOL_GPL(usb_sg_cancel); /*-------------------------------------------------------------------*/ @@ -629,12 +632,13 @@ void usb_sg_cancel (struct usb_sg_request *io) * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +int usb_get_descriptor(struct usb_device *dev, unsigned char type, + unsigned char index, void *buf, int size) { int i; int result; - - memset(buf,0,size); // Make sure we parse really received data + + memset(buf, 0, size); /* Make sure we parse really received data */ for (i = 0; i < 3; ++i) { /* retry on length 0 or error; some devices are flakey */ @@ -652,6 +656,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char } return result; } +EXPORT_SYMBOL_GPL(usb_get_descriptor); /** * usb_get_string - gets a string descriptor @@ -708,7 +713,7 @@ static void usb_try_string_workarounds(unsigned char *buf, int *length) } static int usb_string_sub(struct usb_device *dev, unsigned int langid, - unsigned int index, unsigned char *buf) + unsigned int index, unsigned char *buf) { int rc; @@ -751,7 +756,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, * @buf: where to put the string * @size: how big is "buf"? * Context: !in_interrupt () - * + * * This converts the UTF-16LE encoded strings returned by devices, from * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones * that are more usable in most kernel contexts. Note that all characters @@ -787,23 +792,23 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (!dev->have_langid) { err = usb_string_sub(dev, 0, 0, tbuf); if (err < 0) { - dev_err (&dev->dev, + dev_err(&dev->dev, "string descriptor 0 read error: %d\n", err); goto errout; } else if (err < 4) { - dev_err (&dev->dev, "string descriptor 0 too short\n"); + dev_err(&dev->dev, "string descriptor 0 too short\n"); err = -EINVAL; goto errout; } else { dev->have_langid = 1; - dev->string_langid = tbuf[2] | (tbuf[3]<< 8); - /* always use the first langid listed */ - dev_dbg (&dev->dev, "default language 0x%04x\n", + dev->string_langid = tbuf[2] | (tbuf[3] << 8); + /* always use the first langid listed */ + dev_dbg(&dev->dev, "default language 0x%04x\n", dev->string_langid); } } - + err = usb_string_sub(dev, dev->string_langid, index, tbuf); if (err < 0) goto errout; @@ -821,12 +826,15 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = idx; if (tbuf[1] != USB_DT_STRING) - dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf); + dev_dbg(&dev->dev, + "wrong descriptor type %02x for string %d (\"%s\")\n", + tbuf[1], index, buf); errout: kfree(tbuf); return err; } +EXPORT_SYMBOL_GPL(usb_string); /** * usb_cache_string - read a string descriptor and cache it for later use @@ -842,9 +850,15 @@ char *usb_cache_string(struct usb_device *udev, int index) char *smallbuf = NULL; int len; - if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) { - if ((len = usb_string(udev, index, buf, 256)) > 0) { - if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL) + if (index <= 0) + return NULL; + + buf = kmalloc(256, GFP_KERNEL); + if (buf) { + len = usb_string(udev, index, buf, 256); + if (len > 0) { + smallbuf = kmalloc(++len, GFP_KERNEL); + if (!smallbuf) return buf; memcpy(smallbuf, buf, len); } @@ -883,7 +897,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) return -ENOMEM; ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); - if (ret >= 0) + if (ret >= 0) memcpy(&dev->descriptor, desc, size); kfree(desc); return ret; @@ -927,6 +941,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data) kfree(status); return ret; } +EXPORT_SYMBOL_GPL(usb_get_status); /** * usb_clear_halt - tells device to clear endpoint halt/stall condition @@ -955,8 +970,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe) { int result; int endp = usb_pipeendpoint(pipe); - - if (usb_pipein (pipe)) + + if (usb_pipein(pipe)) endp |= USB_DIR_IN; /* we don't care if it wasn't halted first. in fact some devices @@ -985,6 +1000,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) return 0; } +EXPORT_SYMBOL_GPL(usb_clear_halt); /** * usb_disable_endpoint -- Disable an endpoint by address @@ -1038,7 +1054,7 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) } } -/* +/** * usb_disable_device - Disable all the endpoints for a USB device * @dev: the device whose endpoints are being disabled * @skip_ep0: 0 to disable endpoint 0, 1 to skip it. @@ -1053,7 +1069,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) int i; dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__, - skip_ep0 ? "non-ep0" : "all"); + skip_ep0 ? "non-ep0" : "all"); for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i); usb_disable_endpoint(dev, i + USB_DIR_IN); @@ -1071,17 +1087,17 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) interface = dev->actconfig->interface[i]; if (!device_is_registered(&interface->dev)) continue; - dev_dbg (&dev->dev, "unregistering interface %s\n", + dev_dbg(&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); - device_del (&interface->dev); + device_del(&interface->dev); } /* Now that the interfaces are unbound, nobody should * try to access them. */ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - put_device (&dev->actconfig->interface[i]->dev); + put_device(&dev->actconfig->interface[i]->dev); dev->actconfig->interface[i] = NULL; } dev->actconfig = NULL; @@ -1090,8 +1106,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) } } - -/* +/** * usb_enable_endpoint - Enable an endpoint for USB communications * @dev: the device whose interface is being enabled * @ep: the endpoint @@ -1116,7 +1131,7 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) ep->enabled = 1; } -/* +/** * usb_enable_interface - Enable all the endpoints for an interface * @dev: the device whose interface is being enabled * @intf: pointer to the interface descriptor @@ -1172,6 +1187,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + unsigned int epaddr; + unsigned int pipe; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1226,11 +1243,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) int i; for (i = 0; i < alt->desc.bNumEndpoints; i++) { - unsigned int epaddr = - alt->endpoint[i].desc.bEndpointAddress; - unsigned int pipe = - __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr) - | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN); + epaddr = alt->endpoint[i].desc.bEndpointAddress; + pipe = __create_pipe(dev, + USB_ENDPOINT_NUMBER_MASK & epaddr) | + (usb_endpoint_out(epaddr) ? + USB_DIR_OUT : USB_DIR_IN); usb_clear_halt(dev, pipe); } @@ -1253,6 +1270,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return 0; } +EXPORT_SYMBOL_GPL(usb_set_interface); /** * usb_reset_configuration - lightweight device reset @@ -1328,6 +1346,7 @@ int usb_reset_configuration(struct usb_device *dev) } return 0; } +EXPORT_SYMBOL_GPL(usb_reset_configuration); static void usb_release_interface(struct device *dev) { @@ -1357,7 +1376,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; if (add_uevent_var(env, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + "MODALIAS=usb:" + "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice), @@ -1387,8 +1407,8 @@ struct device_type usb_if_device_type = { }; static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, - struct usb_host_config *config, - u8 inum) + struct usb_host_config *config, + u8 inum) { struct usb_interface_assoc_descriptor *retval = NULL; struct usb_interface_assoc_descriptor *intf_assoc; @@ -1415,7 +1435,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, return retval; } - /* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated @@ -1533,12 +1552,12 @@ free_interfaces: * getting rid of old interfaces means unbinding their drivers. */ if (dev->state != USB_STATE_ADDRESS) - usb_disable_device (dev, 1); // Skip ep0 - - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { + usb_disable_device(dev, 1); /* Skip ep0 */ + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) { /* All the old state is gone, so what else can we do? * The device is probably useless now anyway. */ @@ -1585,11 +1604,11 @@ free_interfaces: intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; intf->dev.dma_mask = dev->dev.dma_mask; - device_initialize (&intf->dev); + device_initialize(&intf->dev); mark_quiesced(intf); - sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, alt->desc.bInterfaceNumber); + sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d", + dev->bus->busnum, dev->devpath, + configuration, alt->desc.bInterfaceNumber); } kfree(new_interfaces); @@ -1605,11 +1624,11 @@ free_interfaces: for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; - dev_dbg (&dev->dev, + dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, intf->cur_altsetting->desc.bInterfaceNumber); - ret = device_add (&intf->dev); + ret = device_add(&intf->dev); if (ret != 0) { dev_err(&dev->dev, "device_add(%s) --> %d\n", intf->dev.bus_id, ret); @@ -1677,22 +1696,3 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); - -// synchronous request completion model -EXPORT_SYMBOL(usb_control_msg); -EXPORT_SYMBOL(usb_bulk_msg); - -EXPORT_SYMBOL(usb_sg_init); -EXPORT_SYMBOL(usb_sg_cancel); -EXPORT_SYMBOL(usb_sg_wait); - -// synchronous control message convenience routines -EXPORT_SYMBOL(usb_get_descriptor); -EXPORT_SYMBOL(usb_get_status); -EXPORT_SYMBOL(usb_string); - -// synchronous calls that also maintain usbcore state -EXPORT_SYMBOL(usb_clear_halt); -EXPORT_SYMBOL(usb_reset_configuration); -EXPORT_SYMBOL(usb_set_interface); - diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 6b36897ca15..7542dce3f5a 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(usb_register_notify); * usb_unregister_notify - unregister a notifier callback * @nb: pointer to the notifier block for the callback events. * - * usb_register_notifier() must have been previously called for this function + * usb_register_notify() must have been previously called for this function * to work properly. */ void usb_unregister_notify(struct notifier_block *nb) diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 7f31a495a25..e8cdce571bb 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -14,7 +14,7 @@ * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. * * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! - */ + */ static struct usb_device_id whitelist_table [] = { @@ -55,7 +55,7 @@ static int is_targeted(struct usb_device *dev) return 1; /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) return 0; @@ -86,7 +86,7 @@ static int is_targeted(struct usb_device *dev) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 32bd130b1ee..a37ccbd1e00 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -72,7 +72,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, return (value < 0) ? value : count; } -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, show_bConfigurationValue, set_bConfigurationValue); /* String fields */ @@ -249,6 +249,41 @@ static void remove_persist_attributes(struct device *dev) #ifdef CONFIG_USB_SUSPEND static ssize_t +show_connected_duration(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + + return sprintf(buf, "%u\n", + jiffies_to_msecs(jiffies - udev->connect_time)); +} + +static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL); + +/* + * If the device is resumed, the last time the device was suspended has + * been pre-subtracted from active_duration. We add the current time to + * get the duration that the device was actually active. + * + * If the device is suspended, the active_duration is up-to-date. + */ +static ssize_t +show_active_duration(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + int duration; + + if (udev->state != USB_STATE_SUSPENDED) + duration = jiffies_to_msecs(jiffies + udev->active_duration); + else + duration = jiffies_to_msecs(udev->active_duration); + return sprintf(buf, "%u\n", duration); +} + +static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); + +static ssize_t show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); @@ -365,6 +400,14 @@ static int add_power_attributes(struct device *dev) rc = sysfs_add_file_to_group(&dev->kobj, &dev_attr_level.attr, power_group); + if (rc == 0) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_connected_duration.attr, + power_group); + if (rc == 0) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_active_duration.attr, + power_group); } return rc; } @@ -372,6 +415,12 @@ static int add_power_attributes(struct device *dev) static void remove_power_attributes(struct device *dev) { sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_active_duration.attr, + power_group); + sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_connected_duration.attr, + power_group); + sysfs_remove_file_from_group(&dev->kobj, &dev_attr_level.attr, power_group); sysfs_remove_file_from_group(&dev->kobj, @@ -601,21 +650,21 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) /* Interface Accociation Descriptor fields */ #define usb_intf_assoc_attr(field, format_string) \ static ssize_t \ -show_iad_##field (struct device *dev, struct device_attribute *attr, \ +show_iad_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct usb_interface *intf = to_usb_interface (dev); \ + struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf (buf, format_string, \ - intf->intf_assoc->field); \ + return sprintf(buf, format_string, \ + intf->intf_assoc->field); \ } \ static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL); -usb_intf_assoc_attr (bFirstInterface, "%02x\n") -usb_intf_assoc_attr (bInterfaceCount, "%02d\n") -usb_intf_assoc_attr (bFunctionClass, "%02x\n") -usb_intf_assoc_attr (bFunctionSubClass, "%02x\n") -usb_intf_assoc_attr (bFunctionProtocol, "%02x\n") +usb_intf_assoc_attr(bFirstInterface, "%02x\n") +usb_intf_assoc_attr(bInterfaceCount, "%02d\n") +usb_intf_assoc_attr(bFunctionClass, "%02x\n") +usb_intf_assoc_attr(bFunctionSubClass, "%02x\n") +usb_intf_assoc_attr(bFunctionProtocol, "%02x\n") /* Interface fields */ #define usb_intf_attr(field, format_string) \ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index d05ead20081..9d7e63292c0 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -42,6 +42,7 @@ void usb_init_urb(struct urb *urb) INIT_LIST_HEAD(&urb->anchor_list); } } +EXPORT_SYMBOL_GPL(usb_init_urb); /** * usb_alloc_urb - creates a new urb for a USB driver to use @@ -73,6 +74,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) usb_init_urb(urb); return urb; } +EXPORT_SYMBOL_GPL(usb_alloc_urb); /** * usb_free_urb - frees the memory used by a urb when all users of it are finished @@ -89,6 +91,7 @@ void usb_free_urb(struct urb *urb) if (urb) kref_put(&urb->kref, urb_destroy); } +EXPORT_SYMBOL_GPL(usb_free_urb); /** * usb_get_urb - increments the reference count of the urb @@ -100,12 +103,13 @@ void usb_free_urb(struct urb *urb) * * A pointer to the urb with the incremented reference counter is returned. */ -struct urb * usb_get_urb(struct urb *urb) +struct urb *usb_get_urb(struct urb *urb) { if (urb) kref_get(&urb->kref); return urb; } +EXPORT_SYMBOL_GPL(usb_get_urb); /** * usb_anchor_urb - anchors an URB while it is processed @@ -172,7 +176,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink - * (a software-induced fault, also called "request cancellation"). + * (a software-induced fault, also called "request cancellation"). * * URBs may be submitted in interrupt context. * @@ -255,7 +259,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * semaphores), or * (c) current->state != TASK_RUNNING, this is the case only after * you've changed it. - * + * * GFP_NOIO is used in the block io path and error handling of storage * devices. * @@ -284,7 +288,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) + dev = urb->dev; + if ((!dev) || (dev->state < USB_STATE_DEFAULT)) return -ENODEV; /* For now, get the endpoint from the pipe. Eventually drivers @@ -347,11 +352,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) max *= mult; } - if (urb->number_of_packets <= 0) + if (urb->number_of_packets <= 0) return -EINVAL; for (n = 0; n < urb->number_of_packets; n++) { len = urb->iso_frame_desc[n].length; - if (len < 0 || len > max) + if (len < 0 || len > max) return -EMSGSIZE; urb->iso_frame_desc[n].status = -EXDEV; urb->iso_frame_desc[n].actual_length = 0; @@ -416,7 +421,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* too big? */ switch (dev->speed) { case USB_SPEED_HIGH: /* units are microframes */ - // NOTE usb handles 2^15 + /* NOTE usb handles 2^15 */ if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; max = 1024 * 8; @@ -426,12 +431,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; - // NOTE ohci only handles up to 32 + /* NOTE ohci only handles up to 32 */ max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; - // NOTE usb and ohci handle up to 2^15 + /* NOTE usb and ohci handle up to 2^15 */ max = 1024; } break; @@ -444,6 +449,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return usb_hcd_submit_urb(urb, mem_flags); } +EXPORT_SYMBOL_GPL(usb_submit_urb); /*-------------------------------------------------------------------*/ @@ -514,6 +520,7 @@ int usb_unlink_urb(struct urb *urb) return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } +EXPORT_SYMBOL_GPL(usb_unlink_urb); /** * usb_kill_urb - cancel a transfer request and wait for it to finish @@ -553,6 +560,7 @@ void usb_kill_urb(struct urb *urb) --urb->reject; mutex_unlock(&reject_mutex); } +EXPORT_SYMBOL_GPL(usb_kill_urb); /** * usb_kill_anchored_urbs - cancel transfer requests en masse @@ -567,7 +575,8 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor) spin_lock_irq(&anchor->lock); while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list); + victim = list_entry(anchor->urb_list.prev, struct urb, + anchor_list); /* we must make sure the URB isn't freed before we kill it*/ usb_get_urb(victim); spin_unlock_irq(&anchor->lock); @@ -595,11 +604,3 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, msecs_to_jiffies(timeout)); } EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); - -EXPORT_SYMBOL(usb_init_urb); -EXPORT_SYMBOL(usb_alloc_urb); -EXPORT_SYMBOL(usb_free_urb); -EXPORT_SYMBOL(usb_get_urb); -EXPORT_SYMBOL(usb_submit_urb); -EXPORT_SYMBOL(usb_unlink_urb); -EXPORT_SYMBOL(usb_kill_urb); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8f142370103..4e984060c98 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -96,6 +96,7 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, return NULL; } +EXPORT_SYMBOL_GPL(usb_ifnum_to_if); /** * usb_altnum_to_altsetting - get the altsetting structure with a given @@ -115,8 +116,9 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, * Don't call this function unless you are bound to the intf interface * or you have locked the device! */ -struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf, - unsigned int altnum) +struct usb_host_interface *usb_altnum_to_altsetting( + const struct usb_interface *intf, + unsigned int altnum) { int i; @@ -126,13 +128,14 @@ struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface * } return NULL; } +EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); struct find_interface_arg { int minor; struct usb_interface *interface; }; -static int __find_interface(struct device * dev, void * data) +static int __find_interface(struct device *dev, void *data) { struct find_interface_arg *arg = data; struct usb_interface *intf; @@ -154,7 +157,7 @@ static int __find_interface(struct device * dev, void * data) * @drv: the driver whose current configuration is considered * @minor: the minor number of the desired device * - * This walks the driver device list and returns a pointer to the interface + * This walks the driver device list and returns a pointer to the interface * with the matching minor. Note, this only works for devices that share the * USB major number. */ @@ -170,6 +173,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) __find_interface); return argb.interface; } +EXPORT_SYMBOL_GPL(usb_find_interface); /** * usb_release_dev - free a usb device structure when all users of it are finished. @@ -230,7 +234,7 @@ static int ksuspend_usb_init(void) * singlethreaded. Its job doesn't justify running on more * than one CPU. */ - ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd"); + ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd"); if (!ksuspend_usb_wq) return -ENOMEM; return 0; @@ -269,8 +273,8 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) * * This call may not be used in a non-sleeping context. */ -struct usb_device * -usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) +struct usb_device *usb_alloc_dev(struct usb_device *parent, + struct usb_bus *bus, unsigned port1) { struct usb_device *dev; struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); @@ -339,6 +343,8 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; + dev->connect_time = jiffies; + dev->active_duration = -jiffies; #endif if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; @@ -367,6 +373,7 @@ struct usb_device *usb_get_dev(struct usb_device *dev) get_device(&dev->dev); return dev; } +EXPORT_SYMBOL_GPL(usb_get_dev); /** * usb_put_dev - release a use of the usb device structure @@ -380,6 +387,7 @@ void usb_put_dev(struct usb_device *dev) if (dev) put_device(&dev->dev); } +EXPORT_SYMBOL_GPL(usb_put_dev); /** * usb_get_intf - increments the reference count of the usb interface structure @@ -400,6 +408,7 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf) get_device(&intf->dev); return intf; } +EXPORT_SYMBOL_GPL(usb_get_intf); /** * usb_put_intf - release a use of the usb interface structure @@ -414,7 +423,7 @@ void usb_put_intf(struct usb_interface *intf) if (intf) put_device(&intf->dev); } - +EXPORT_SYMBOL_GPL(usb_put_intf); /* USB device locking * @@ -461,11 +470,11 @@ int usb_lock_device_for_reset(struct usb_device *udev, return -EHOSTUNREACH; if (iface) { switch (iface->condition) { - case USB_INTERFACE_BINDING: + case USB_INTERFACE_BINDING: return 0; - case USB_INTERFACE_BOUND: + case USB_INTERFACE_BOUND: break; - default: + default: return -EINTR; } } @@ -487,7 +496,7 @@ int usb_lock_device_for_reset(struct usb_device *udev, } return 1; } - +EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) @@ -540,10 +549,10 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) struct list_head *buslist; struct usb_bus *bus; struct usb_device *dev = NULL; - + mutex_lock(&usb_bus_list_lock); for (buslist = usb_bus_list.next; - buslist != &usb_bus_list; + buslist != &usb_bus_list; buslist = buslist->next) { bus = container_of(buslist, struct usb_bus, bus_list); if (!bus->root_hub) @@ -576,6 +585,7 @@ int usb_get_current_frame_number(struct usb_device *dev) { return usb_hcd_get_frame_number(dev); } +EXPORT_SYMBOL_GPL(usb_get_current_frame_number); /*-------------------------------------------------------------------*/ /* @@ -584,7 +594,7 @@ int usb_get_current_frame_number(struct usb_device *dev) */ int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr) + unsigned char type, void **ptr) { struct usb_descriptor_header *header; @@ -595,7 +605,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, printk(KERN_ERR "%s: bogus descriptor, type %d length %d\n", usbcore_name, - header->bDescriptorType, + header->bDescriptorType, header->bLength); return -1; } @@ -610,6 +620,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, } return -1; } +EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); /** * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP @@ -633,17 +644,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc( - struct usb_device *dev, - size_t size, - gfp_t mem_flags, - dma_addr_t *dma -) +void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, + dma_addr_t *dma) { if (!dev || !dev->bus) return NULL; return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_alloc); /** * usb_buffer_free - free memory allocated with usb_buffer_alloc() @@ -656,12 +664,8 @@ void *usb_buffer_alloc( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free( - struct usb_device *dev, - size_t size, - void *addr, - dma_addr_t dma -) +void usb_buffer_free(struct usb_device *dev, size_t size, void *addr, + dma_addr_t dma) { if (!dev || !dev->bus) return; @@ -669,6 +673,7 @@ void usb_buffer_free( return; hcd_buffer_free(dev->bus, size, addr, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_free); /** * usb_buffer_map - create DMA mapping(s) for an urb @@ -708,14 +713,15 @@ struct urb *usb_buffer_map(struct urb *urb) urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - // FIXME generic api broken like pci, can't report errors - // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; + /* FIXME generic api broken like pci, can't report errors */ + /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */ } else urb->transfer_dma = ~0; urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); return urb; } +EXPORT_SYMBOL_GPL(usb_buffer_map); #endif /* 0 */ /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -753,6 +759,7 @@ void usb_buffer_dmasync(struct urb *urb) DMA_TO_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync); #endif /** @@ -788,6 +795,7 @@ void usb_buffer_unmap(struct urb *urb) urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap); #endif /* 0 */ /** @@ -828,10 +836,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in, || !controller->dma_mask) return -1; - // FIXME generic api broken like pci, can't report errors + /* FIXME generic api broken like pci, can't report errors */ return dma_map_sg(controller, sg, nents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_map_sg); /* XXX DISABLED, no users currently. If you wish to re-enable this * XXX please determine whether the sync is to transfer ownership of @@ -865,6 +874,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, dma_sync_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); #endif /** @@ -891,6 +901,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, dma_unmap_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); /* format to disable USB on kernel command line is: nousb */ __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444); @@ -902,6 +913,7 @@ int usb_disabled(void) { return nousb; } +EXPORT_SYMBOL_GPL(usb_disabled); /* * Init @@ -918,7 +930,7 @@ static int __init usb_init(void) if (retval) goto out; retval = bus_register(&usb_bus_type); - if (retval) + if (retval) goto bus_register_failed; retval = usb_host_init(); if (retval) @@ -983,45 +995,4 @@ static void __exit usb_exit(void) subsys_initcall(usb_init); module_exit(usb_exit); - -/* - * USB may be built into the kernel or be built as modules. - * These symbols are exported for device (or host controller) - * driver modules to use. - */ - -EXPORT_SYMBOL(usb_disabled); - -EXPORT_SYMBOL_GPL(usb_get_intf); -EXPORT_SYMBOL_GPL(usb_put_intf); - -EXPORT_SYMBOL(usb_put_dev); -EXPORT_SYMBOL(usb_get_dev); -EXPORT_SYMBOL(usb_hub_tt_clear_buffer); - -EXPORT_SYMBOL(usb_lock_device_for_reset); - -EXPORT_SYMBOL(usb_find_interface); -EXPORT_SYMBOL(usb_ifnum_to_if); -EXPORT_SYMBOL(usb_altnum_to_altsetting); - -EXPORT_SYMBOL(__usb_get_extra_descriptor); - -EXPORT_SYMBOL(usb_get_current_frame_number); - -EXPORT_SYMBOL(usb_buffer_alloc); -EXPORT_SYMBOL(usb_buffer_free); - -#if 0 -EXPORT_SYMBOL(usb_buffer_map); -EXPORT_SYMBOL(usb_buffer_dmasync); -EXPORT_SYMBOL(usb_buffer_unmap); -#endif - -EXPORT_SYMBOL(usb_buffer_map_sg); -#if 0 -EXPORT_SYMBOL(usb_buffer_dmasync_sg); -#endif -EXPORT_SYMBOL(usb_buffer_unmap_sg); - MODULE_LICENSE("GPL"); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index c52626c51f7..2375194a9d4 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,22 +1,23 @@ /* Functions local to drivers/usb/core/ */ -extern int usb_create_sysfs_dev_files (struct usb_device *dev); -extern void usb_remove_sysfs_dev_files (struct usb_device *dev); -extern int usb_create_sysfs_intf_files (struct usb_interface *intf); -extern void usb_remove_sysfs_intf_files (struct usb_interface *intf); -extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, +extern int usb_create_sysfs_dev_files(struct usb_device *dev); +extern void usb_remove_sysfs_dev_files(struct usb_device *dev); +extern int usb_create_sysfs_intf_files(struct usb_interface *intf); +extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); +extern int usb_create_ep_files(struct device *parent, + struct usb_host_endpoint *endpoint, struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); extern void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep); -extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); -extern void usb_disable_interface (struct usb_device *dev, +extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr); +extern void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); -extern void usb_disable_device (struct usb_device *dev, int skip_ep0); -extern int usb_deauthorize_device (struct usb_device *); -extern int usb_authorize_device (struct usb_device *); +extern void usb_disable_device(struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device(struct usb_device *); +extern int usb_authorize_device(struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 77a3759d6fc..c1395516468 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -12,10 +12,9 @@ # With help from a special transceiver and a "Mini-AB" jack, systems with # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). # -menu "USB Gadget Support" -config USB_GADGET - tristate "Support for USB Gadgets" +menuconfig USB_GADGET + tristate "USB Gadget Support" help USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. @@ -42,6 +41,8 @@ config USB_GADGET For more information, see <http://www.linux-usb.org/gadget> and the kernel DocBook documentation for this API. +if USB_GADGET + config USB_GADGET_DEBUG boolean "Debugging messages" depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL @@ -220,6 +221,16 @@ config USB_M66592 default USB_GADGET select USB_GADGET_SELECTED +config SUPERH_BUILT_IN_M66592 + boolean "Enable SuperH built-in USB like the M66592" + depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722 + help + SH7722 has USB like the M66592. + + The transfer rate is very slow when use "Ethernet Gadget". + However, this problem is improved if change a value of + NET_IP_ALIGN to 4. + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI @@ -538,6 +549,20 @@ config USB_MIDI_GADGET Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_midi". +config USB_G_PRINTER + tristate "Printer Gadget" + help + The Printer Gadget channels data between the USB host and a + userspace program driving the print engine. The user space + program reads and writes the device file /dev/g_printer to + receive or send printer data. It can use ioctl calls to + the device file to get or set printer status. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_printer". + + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. # put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. @@ -546,4 +571,4 @@ config USB_MIDI_GADGET endchoice -endmenu +endif # USB_GADGET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 904e57bf611..c3aab80b6c7 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,8 @@ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o +g_printer-objs := printer.o usbstring.o config.o \ + epautoconf.o ifeq ($(CONFIG_USB_ETH_RNDIS),y) g_ether-objs += rndis.o @@ -38,5 +40,6 @@ obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o +obj-$(CONFIG_USB_G_PRINTER) += g_printer.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index c72e9620bf8..b663f23f264 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1244,7 +1244,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) /* stop OUT naking */ if (!ep->in) { if (!use_dma && udc_rxfifo_pending) { - DBG(dev, "udc_queue(): pending bytes in" + DBG(dev, "udc_queue(): pending bytes in " "rxfifo after nyet\n"); /* * read pending bytes afer nyet: @@ -2038,6 +2038,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; dev->driver = NULL; /* set SD */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index cd62b029d17..a83e8b798ec 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,8 +21,7 @@ * Boston, MA 02111-1307, USA. */ -#undef DEBUG -#undef VERBOSE +#undef VERBOSE_DEBUG #undef PACKET_TRACE #include <linux/kernel.h> @@ -46,8 +45,8 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/mach-types.h> +#include <asm/gpio.h> -#include <asm/arch/gpio.h> #include <asm/arch/board.h> #include <asm/arch/cpu.h> #include <asm/arch/at91sam9261_matrix.h> @@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep) */ static struct usb_request * -at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags) +at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct at91_request *req; @@ -881,6 +880,8 @@ static void clk_off(struct at91_udc *udc) */ static void pullup(struct at91_udc *udc, int is_on) { + int active = !udc->board.pullup_active_low; + if (!udc->enabled || !udc->vbus) is_on = 0; DBG("%sactive\n", is_on ? "" : "in"); @@ -890,7 +891,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, 0); if (cpu_is_at91rm9200()) - at91_set_gpio_value(udc->board.pullup_pin, 1); + gpio_set_value(udc->board.pullup_pin, active); else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); @@ -908,7 +909,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); if (cpu_is_at91rm9200()) - at91_set_gpio_value(udc->board.pullup_pin, 0); + gpio_set_value(udc->board.pullup_pin, !active); else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); @@ -1153,7 +1154,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_GET_STATUS: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc)) + if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) goto stall; if (tmp) { @@ -1176,7 +1177,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_SET_FEATURE: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; if (!ep->desc || ep->is_iso) goto stall; @@ -1195,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_CLEAR_FEATURE: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; if (tmp == 0) goto succeed; @@ -1551,7 +1552,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc) /* vbus needs at least brief debouncing */ udelay(10); - value = at91_get_gpio_value(udc->board.vbus_pin); + value = gpio_get_value(udc->board.vbus_pin); if (value != udc->vbus) at91_vbus_session(&udc->gadget, value); @@ -1616,6 +1617,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) local_irq_enable(); driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->gadget.dev.driver_data = NULL; udc->driver = NULL; DBG("unbound from %s\n", driver->driver.name); @@ -1645,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev) } if (pdev->num_resources != 2) { - DBG("invalid num_resources"); + DBG("invalid num_resources\n"); return -ENODEV; } if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) { - DBG("invalid resource type"); + DBG("invalid resource type\n"); return -ENODEV; } @@ -1672,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev) udc->pdev = pdev; udc->enabled = 0; + /* rm9200 needs manual D+ pullup; off by default */ + if (cpu_is_at91rm9200()) { + if (udc->board.pullup_pin <= 0) { + DBG("no D+ pullup?\n"); + retval = -ENODEV; + goto fail0; + } + retval = gpio_request(udc->board.pullup_pin, "udc_pullup"); + if (retval) { + DBG("D+ pullup is busy\n"); + goto fail0; + } + gpio_direction_output(udc->board.pullup_pin, + udc->board.pullup_active_low); + } + udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1); if (!udc->udp_baseaddr) { - release_mem_region(res->start, res->end - res->start + 1); - return -ENOMEM; + retval = -ENOMEM; + goto fail0a; } udc_reinit(udc); @@ -1686,12 +1705,13 @@ static int __init at91udc_probe(struct platform_device *pdev) if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG("clocks missing\n"); retval = -ENODEV; - goto fail0; + /* NOTE: we "know" here that refcounts on these are NOPs */ + goto fail0b; } retval = device_register(&udc->gadget.dev); if (retval < 0) - goto fail0; + goto fail0b; /* don't do anything until we have both gadget driver and VBUS */ clk_enable(udc->iclk); @@ -1703,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev) /* request UDC and maybe VBUS irqs */ udc->udp_irq = platform_get_irq(pdev, 0); - if (request_irq(udc->udp_irq, at91_udc_irq, - IRQF_DISABLED, driver_name, udc)) { + retval = request_irq(udc->udp_irq, at91_udc_irq, + IRQF_DISABLED, driver_name, udc); + if (retval < 0) { DBG("request irq %d failed\n", udc->udp_irq); - retval = -EBUSY; goto fail1; } if (udc->board.vbus_pin > 0) { + retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); + if (retval < 0) { + DBG("request vbus pin failed\n"); + goto fail2; + } + gpio_direction_input(udc->board.vbus_pin); + /* * Get the initial state of VBUS - we cannot expect * a pending interrupt. */ - udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); + udc->vbus = gpio_get_value(udc->board.vbus_pin); if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { DBG("request vbus irq %d failed\n", udc->board.vbus_pin); free_irq(udc->udp_irq, udc); retval = -EBUSY; - goto fail1; + goto fail3; } } else { DBG("no VBUS detection, assuming always-on\n"); @@ -1734,8 +1761,18 @@ static int __init at91udc_probe(struct platform_device *pdev) INFO("%s version %s\n", driver_name, DRIVER_VERSION); return 0; +fail3: + if (udc->board.vbus_pin > 0) + gpio_free(udc->board.vbus_pin); +fail2: + free_irq(udc->udp_irq, udc); fail1: device_unregister(&udc->gadget.dev); +fail0b: + iounmap(udc->udp_baseaddr); +fail0a: + if (cpu_is_at91rm9200()) + gpio_free(udc->board.pullup_pin); fail0: release_mem_region(res->start, res->end - res->start + 1); DBG("%s probe failed, %d\n", driver_name, retval); @@ -1756,12 +1793,18 @@ static int __exit at91udc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); - if (udc->board.vbus_pin > 0) + if (udc->board.vbus_pin > 0) { free_irq(udc->board.vbus_pin, udc); + gpio_free(udc->board.vbus_pin); + } free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); iounmap(udc->udp_baseaddr); + + if (cpu_is_at91rm9200()) + gpio_free(udc->board.pullup_pin); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, res->end - res->start + 1); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 7e34e2f864f..a973f2a50fb 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -53,7 +53,7 @@ #define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ #define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ -#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ +#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrupt Status */ #define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ @@ -158,13 +158,7 @@ struct at91_request { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG # define VDBG DBG #else # define VDBG(stuff...) do{}while(0) @@ -176,9 +170,10 @@ struct at91_request { # define PACKET(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) +#define DBG(stuff...) pr_debug("udc: " stuff) #endif diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 4fb5ff46957..af8b2a3a2d4 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1384,8 +1384,7 @@ delegate: return retval; stall: - printk(KERN_ERR - "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " "halting endpoint...\n", ep->ep.name, crq->bRequestType, crq->bRequest, le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), @@ -1456,8 +1455,7 @@ restart: set_protocol_stall(udc, ep); break; default: - printk(KERN_ERR - "udc: %s: TXCOMP: Invalid endpoint state %d, " + pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, " "halting endpoint...\n", ep->ep.name, ep->state); set_protocol_stall(udc, ep); @@ -1486,8 +1484,7 @@ restart: default: usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - printk(KERN_ERR - "udc: %s: RXRDY: Invalid endpoint state %d, " + pr_err("udc: %s: RXRDY: Invalid endpoint state %d, " "halting endpoint...\n", ep->ep.name, ep->state); set_protocol_stall(udc, ep); @@ -1532,7 +1529,7 @@ restart: pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); DBG(DBG_HW, "Packet length: %u\n", pkt_len); if (pkt_len != sizeof(crq)) { - printk(KERN_WARNING "udc: Invalid packet length %u " + pr_warning("udc: Invalid packet length %u " "(expected %lu)\n", pkt_len, sizeof(crq)); set_protocol_stall(udc, ep); return; diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index a68304e31a6..08bf6f9aaf7 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -216,7 +216,6 @@ #define FIFO_IOMEM_ID 0 #define CTRL_IOMEM_ID 1 -#ifdef DEBUG #define DBG_ERR 0x0001 /* report all error returns */ #define DBG_HW 0x0002 /* debug hardware initialization */ #define DBG_GADGET 0x0004 /* calls to/from gadget driver */ @@ -230,14 +229,12 @@ #define DBG_NONE 0x0000 #define DEBUG_LEVEL (DBG_ERR) + #define DBG(level, fmt, ...) \ do { \ if ((level) & DEBUG_LEVEL) \ - printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + pr_debug("udc: " fmt, ## __VA_ARGS__); \ } while (0) -#else -#define DBG(level, fmt...) -#endif enum usba_ctrl_state { WAIT_FOR_SETUP, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 9db2482bdfa..cbe44535c0f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -61,6 +61,8 @@ #define DRIVER_DESC "USB Host+Gadget Emulator" #define DRIVER_VERSION "02 May 2005" +#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ + static const char driver_name [] = "dummy_hcd"; static const char driver_desc [] = "USB Host+Gadget Emulator"; @@ -772,18 +774,17 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) list_del_init (&dum->ep [0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); + driver->driver.bus = NULL; dum->driver = driver; dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = driver->bind (&dum->gadget)) != 0) - goto err_bind_gadget; - - driver->driver.bus = dum->gadget.dev.parent->bus; - if ((retval = driver_register (&driver->driver)) != 0) - goto err_register; - if ((retval = device_bind_driver (&dum->gadget.dev)) != 0) - goto err_bind_driver; + retval = driver->bind(&dum->gadget); + if (retval) { + dum->driver = NULL; + dum->gadget.dev.driver = NULL; + return retval; + } /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); @@ -793,20 +794,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; - -err_bind_driver: - driver_unregister (&driver->driver); -err_register: - if (driver->unbind) - driver->unbind (&dum->gadget); - spin_lock_irq (&dum->lock); - dum->pullup = 0; - set_link_state (dum); - spin_unlock_irq (&dum->lock); -err_bind_gadget: - dum->driver = NULL; - dum->gadget.dev.driver = NULL; - return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -830,11 +817,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); + dum->gadget.dev.driver = NULL; dum->driver = NULL; - device_release_driver (&dum->gadget.dev); - driver_unregister (&driver->driver); - spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; set_link_state (dum); @@ -1827,8 +1812,7 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - /* only show a low-power port: just 8mA */ - hcd->power_budget = 8; + hcd->power_budget = POWER_BUDGET; hcd->state = HC_STATE_RUNNING; hcd->uses_new_polling = 1; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9e732bff9df..a70e255402b 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1067,19 +1067,19 @@ done: /* on error, disable any endpoints */ if (result < 0) { - if (!subset_active(dev)) + if (!subset_active(dev) && dev->status_ep) (void) usb_ep_disable (dev->status_ep); dev->status = NULL; (void) usb_ep_disable (dev->in_ep); (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; - } else + } /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ - if (!cdc_active (dev)) { + else if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 1d174dcb3ac..3301167d4f2 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -275,19 +275,15 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#ifdef DEBUG #define LDBG(lun,fmt,args...) \ dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ - printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) -#else -#define LDBG(lun,fmt,args...) \ - do { } while (0) -#define MDBG(fmt,args...) \ - do { } while (0) + pr_debug(DRIVER_NAME ": " fmt , ## args) + +#ifndef DEBUG #undef VERBOSE_DEBUG #undef DUMP_MSGS -#endif /* DEBUG */ +#endif /* !DEBUG */ #ifdef VERBOSE_DEBUG #define VLDBG LDBG @@ -304,7 +300,7 @@ MODULE_LICENSE("Dual BSD/GPL"); dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ - printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) + pr_info(DRIVER_NAME ": " fmt , ## args) #define DBG(d, fmt, args...) \ dev_dbg(&(d)->gadget->dev , fmt , ## args) diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 038e7d7b4da..63e8fa3a69e 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -776,7 +776,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad params\n", __FUNCTION__); return -EINVAL; } - if (!_ep || (!ep->desc && ep_index(ep))) { + if (unlikely(!_ep || !ep->desc)) { VDBG("%s, bad ep\n", __FUNCTION__); return -EINVAL; } @@ -1896,7 +1896,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, spin_lock_irqsave(&udc->lock, flags); - /* ------basic driver infomation ---- */ + /* ------basic driver information ---- */ t = scnprintf(next, size, DRIVER_DESC "\n" "%s version: %s\n" diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 832ab82b488..9fb0b1ec852 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -551,9 +551,9 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length) #define VDBG(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 7da7fcb0564..5b42ccd0035 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1158,7 +1158,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget) /* support optional vendor/distro customization */ if (idVendor) { if (!idProduct) { - printk(KERN_ERR "idVendor needs idProduct!\n"); + pr_err("idVendor needs idProduct!\n"); return -ENODEV; } device_desc.idVendor = cpu_to_le16(idVendor); @@ -1190,7 +1190,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget) in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc); if (!in_ep) { autoconf_fail: - printk(KERN_ERR "%s: can't autoconfigure on %s\n", + pr_err("%s: can't autoconfigure on %s\n", shortname, gadget->name); return -ENODEV; } @@ -1212,7 +1212,7 @@ autoconf_fail: * it SHOULD NOT have problems with bulk-capable hardware. * so warn about unrecognized controllers, don't panic. */ - printk(KERN_WARNING "%s: controller '%s' not recognized\n", + pr_warning("%s: controller '%s' not recognized\n", shortname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 2ec9d196a8c..d3e702576de 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1422,6 +1422,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; DBG(dev, "unregistered driver '%s'\n", driver->driver.name); return 0; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 47ef8bd58a0..805602a687c 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1699,7 +1699,7 @@ gadgetfs_bind (struct usb_gadget *gadget) if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { - printk (KERN_ERR "%s expected %s controller not %s\n", + pr_err("%s expected %s controller not %s\n", shortname, CHIP, gadget->name); return -ENODEV; } diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 367b75c0b25..37243ef7104 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -474,6 +474,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; device_del(&dev->gadget.dev); udc_disable(dev); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index ebc5536aa27..835948f0715 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); -#define DRIVER_VERSION "29 May 2007" +#define DRIVER_VERSION "18 Oct 2007" /* module parameters */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +static unsigned short endian = M66592_LITTLE; +module_param(endian, ushort, 0644); +MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)"); +#else static unsigned short clock = M66592_XTAL24; module_param(clock, ushort, 0644); MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " @@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL; module_param(irq_sense, ushort, 0644); MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " "(default=2)"); +#endif static const char udc_name[] = "m66592_udc"; static const char *m66592_ep_name[] = { @@ -141,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); pid = m66592_read(m66592, offset) & M66592_PID; } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); return pid; } @@ -157,7 +163,7 @@ static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, offset = get_pipectr_addr(pipenum); m66592_mdfy(m66592, pid, M66592_PID, offset); } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); } static inline void pipe_start(struct m66592 *m66592, u16 pipenum) @@ -186,7 +192,7 @@ static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); ret = m66592_read(m66592, offset); } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); return ret; } @@ -203,7 +209,7 @@ static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); m66592_bset(m66592, M66592_SQCLR, offset); } else - printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum); + pr_err("unexpect pipe num(%d)\n", pipenum); } static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) @@ -285,7 +291,7 @@ static int pipe_buffer_setting(struct m66592 *m66592, break; } if (m66592->bi_bufnum > M66592_MAX_BUFNUM) { - printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n", + pr_err("m66592 pipe memory is insufficient(%d)\n", m66592->bi_bufnum); return -ENOMEM; } @@ -326,7 +332,7 @@ static void pipe_buffer_release(struct m66592 *m66592, if (info->type == M66592_BULK) m66592->bulk--; } else - printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", + pr_err("ep_release: unexpect pipenum (%d)\n", info->pipe); } @@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->fifosel = M66592_D0FIFOSEL; ep->fifoctr = M66592_D0FIFOCTR; ep->fifotrn = M66592_D0FIFOTRN; +#if !defined(CONFIG_SUPERH_BUILT_IN_M66592) } else if (m66592->num_dma == 1) { m66592->num_dma++; ep->use_dma = 1; @@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->fifosel = M66592_D1FIFOSEL; ep->fifoctr = M66592_D1FIFOCTR; ep->fifotrn = M66592_D1FIFOTRN; +#endif } else { ep->use_dma = 0; ep->fifoaddr = M66592_CFIFO; @@ -422,7 +430,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, case USB_ENDPOINT_XFER_BULK: if (m66592->bulk >= M66592_MAX_NUM_BULK) { if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - printk(KERN_ERR "bulk pipe is insufficient\n"); + pr_err("bulk pipe is insufficient\n"); return -ENODEV; } else { info.pipe = M66592_BASE_PIPENUM_ISOC @@ -438,7 +446,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, break; case USB_ENDPOINT_XFER_INT: if (m66592->interrupt >= M66592_MAX_NUM_INT) { - printk(KERN_ERR "interrupt pipe is insufficient\n"); + pr_err("interrupt pipe is insufficient\n"); return -ENODEV; } info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; @@ -447,7 +455,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, break; case USB_ENDPOINT_XFER_ISOC: if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - printk(KERN_ERR "isochronous pipe is insufficient\n"); + pr_err("isochronous pipe is insufficient\n"); return -ENODEV; } info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; @@ -455,7 +463,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, counter = &m66592->isochronous; break; default: - printk(KERN_ERR "unexpect xfer type\n"); + pr_err("unexpect xfer type\n"); return -EINVAL; } ep->type = info.type; @@ -470,7 +478,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, ret = pipe_buffer_setting(m66592, &info); if (ret < 0) { - printk(KERN_ERR "pipe_buffer_setting fail\n"); + pr_err("pipe_buffer_setting fail\n"); return ret; } @@ -606,11 +614,33 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) control_end(ep->m66592, 0); break; default: - printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq); + pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq); break; } } +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +static void init_controller(struct m66592 *m66592) +{ + usbf_start_clock(); + m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ + m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); + m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); + m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); + + /* This is a workaound for SH7722 2nd cut */ + m66592_bset(m66592, 0x8000, M66592_DVSTCTR); + m66592_bset(m66592, 0x1000, M66592_TESTMODE); + m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); + + m66592_bset(m66592, M66592_INTL, M66592_INTENB1); + + m66592_write(m66592, 0, M66592_CFBCFG); + m66592_write(m66592, 0, M66592_D0FBCFG); + m66592_bset(m66592, endian, M66592_CFBCFG); + m66592_bset(m66592, endian, M66592_D0FBCFG); +} +#else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ static void init_controller(struct m66592 *m66592) { m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), @@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592) m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, M66592_DMA0CFG); } +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ static void disable_controller(struct m66592 *m66592) { +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + usbf_stop_clock(); +#else m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); @@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592) m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); +#endif } static void m66592_start_xclock(struct m66592 *m66592) { +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + usbf_start_clock(); +#else u16 tmp; tmp = m66592_read(m66592, M66592_SYSCFG); if (!(tmp & M66592_XCKE)) m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); +#endif } /*-------------------------------------------------------------------------*/ @@ -709,7 +748,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) do { tmp = m66592_read(m66592, ep->fifoctr); if (i++ > 100000) { - printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus" + pr_err("pipe0 is busy. maybe cpu i/o bus " "conflict. please power off this controller."); return; } @@ -759,7 +798,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) if (unlikely((tmp & M66592_FRDY) == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); - printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum); + pr_err("write fifo not ready. pipnum=%d\n", pipenum); return; } @@ -808,7 +847,7 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) req->req.status = -EPIPE; pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); - printk(KERN_ERR "read fifo not ready"); + pr_err("read fifo not ready"); return; } @@ -1063,7 +1102,7 @@ static void m66592_update_usb_speed(struct m66592 *m66592) break; default: m66592->gadget.speed = USB_SPEED_UNKNOWN; - printk(KERN_ERR "USB speed unknown\n"); + pr_err("USB speed unknown\n"); } } @@ -1122,7 +1161,7 @@ __acquires(m66592->lock) control_end(m66592, 0); break; default: - printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq); + pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq); break; } } @@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) intsts0 = m66592_read(m66592, M66592_INTSTS0); intenb0 = m66592_read(m66592, M66592_INTENB0); +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + if (!intsts0 && !intenb0) { + /* + * When USB clock stops, it cannot read register. Even if a + * clock stops, the interrupt occurs. So this driver turn on + * a clock by this timing and do re-reading of register. + */ + m66592_start_xclock(m66592); + intsts0 = m66592_read(m66592, M66592_INTSTS0); + intenb0 = m66592_read(m66592, M66592_INTENB0); + } +#endif + savepipe = m66592_read(m66592, M66592_CFIFOSEL); mask0 = intsts0 & intenb0; @@ -1409,13 +1461,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) retval = device_add(&m66592->gadget.dev); if (retval) { - printk(KERN_ERR "device_add error (%d)\n", retval); + pr_err("device_add error (%d)\n", retval); goto error; } retval = driver->bind (&m66592->gadget); if (retval) { - printk(KERN_ERR "bind to driver error (%d)\n", retval); + pr_err("bind to driver error (%d)\n", retval); device_del(&m66592->gadget.dev); goto error; } @@ -1456,6 +1508,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); driver->unbind(&m66592->gadget); + m66592->gadget.dev.driver = NULL; init_controller(m66592); disable_controller(m66592); @@ -1485,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev) iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); + usbf_stop_clock(); kfree(m66592); return 0; } @@ -1508,28 +1562,28 @@ static int __init m66592_probe(struct platform_device *pdev) (char *)udc_name); if (!res) { ret = -ENODEV; - printk(KERN_ERR "platform_get_resource_byname error.\n"); + pr_err("platform_get_resource_byname error.\n"); goto clean_up; } irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENODEV; - printk(KERN_ERR "platform_get_irq error.\n"); + pr_err("platform_get_irq error.\n"); goto clean_up; } reg = ioremap(res->start, resource_len(res)); if (reg == NULL) { ret = -ENOMEM; - printk(KERN_ERR "ioremap error.\n"); + pr_err("ioremap error.\n"); goto clean_up; } /* initialize ucd */ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { - printk(KERN_ERR "kzalloc error\n"); + pr_err("kzalloc error\n"); goto clean_up; } @@ -1555,7 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev) ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED, udc_name, m66592); if (ret < 0) { - printk(KERN_ERR "request_irq error (%d)\n", ret); + pr_err("request_irq error (%d)\n", ret); goto clean_up; } diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index bfa0c645f22..17b792b7f6b 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -72,6 +72,11 @@ #define M66592_P_TST_J 0x0001 /* PERI TEST J */ #define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#define M66592_CFBCFG 0x0A +#define M66592_D0FBCFG 0x0C +#define M66592_LITTLE 0x0100 /* b8: Little endian mode */ +#else #define M66592_PINCFG 0x0A #define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ #define M66592_BIGEND 0x0100 /* b8: Big endian mode */ @@ -91,6 +96,7 @@ #define M66592_PKTM 0x0020 /* b5: Packet mode */ #define M66592_DENDE 0x0010 /* b4: Dend enable */ #define M66592_OBUS 0x0004 /* b2: OUTbus mode */ +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ #define M66592_CFIFO 0x10 #define M66592_D0FIFO 0x14 @@ -103,9 +109,13 @@ #define M66592_REW 0x4000 /* b14: Buffer rewind */ #define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ #define M66592_DREQE 0x1000 /* b12: DREQ output enable */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */ +#else #define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ #define M66592_MBW_8 0x0000 /* 8bit */ #define M66592_MBW_16 0x0400 /* 16bit */ +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ #define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ #define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ #define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ @@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592, { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + len = (len + 3) / 4; + insl(fifoaddr, buf, len); +#else len = (len + 1) / 2; insw(fifoaddr, buf, len); +#endif } static inline void m66592_write(struct m66592 *m66592, u16 val, @@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592, void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + unsigned long count; + unsigned char *pb; + int i; + + count = len / 4; + outsl(fifoaddr, buf, count); + + if (len & 0x00000003) { + pb = buf + count * 4; + for (i = 0; i < (len & 0x00000003); i++) { + if (m66592_read(m66592, M66592_CFBCFG)) /* little */ + outb(pb[i], fifoaddr + (3 - i)); + else + outb(pb[i], fifoaddr + i); + } + } +#else unsigned long odd = len & 0x0001; len = len / 2; @@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592, unsigned char *p = buf + len*2; outb(*p, fifoaddr); } +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ } static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, @@ -570,6 +604,26 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, #define m66592_bset(m66592, val, offset) \ m66592_mdfy(m66592, val, 0, offset) +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#include <asm/io.h> +#define MSTPCR2 0xA4150038 /* for SH7722 */ +#define MSTPCR2_USB 0x00000800 + +static inline void usbf_start_clock(void) +{ + ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2); +} + +static inline void usbf_stop_clock(void) +{ + ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2); +} + +#else +#define usbf_start_clock(x) +#define usbf_stop_clock(x) +#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ + #endif /* ifndef __M66592_UDC_H__ */ diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d5d473f8144..33469cf5aec 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2435,7 +2435,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x" + VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x " "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index d377154658b..e6d68bda428 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -4,6 +4,8 @@ * Copyright (C) 2004 Texas Instruments, Inc. * Copyright (C) 2004-2005 David Brownell * + * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com> + * * 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 @@ -60,11 +62,6 @@ /* bulk DMA seems to be behaving for both IN and OUT */ #define USE_DMA -/* FIXME: OMAP2 currently has some problem in DMA mode */ -#ifdef CONFIG_ARCH_OMAP2 -#undef USE_DMA -#endif - /* ISO too */ #define USE_ISO @@ -73,6 +70,8 @@ #define DMA_ADDR_INVALID (~(dma_addr_t)0) +#define OMAP2_DMA_CH(ch) (((ch) - 1) << 1) +#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch)) /* * The OMAP UDC needs _very_ early endpoint setup: before enabling the @@ -571,20 +570,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) const int sync_mode = cpu_is_omap15xx() ? OMAP_DMA_SYNC_FRAME : OMAP_DMA_SYNC_ELEMENT; + int dma_trigger = 0; + + if (cpu_is_omap24xx()) + dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel); /* measure length in either bytes or packets */ if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) + || (cpu_is_omap24xx() && length < ep->maxpacket) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - length, 1, sync_mode, 0, 0); + length, 1, sync_mode, dma_trigger, 0); } else { length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); txdma_ctrl = length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, ep->ep.maxpacket >> 1, length, sync_mode, - 0, 0); + dma_trigger, 0); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, @@ -622,20 +626,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) static void next_out_dma(struct omap_ep *ep, struct omap_req *req) { - unsigned packets; + unsigned packets = req->req.length - req->req.actual; + int dma_trigger = 0; + + if (cpu_is_omap24xx()) + dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel); /* NOTE: we filtered out "short reads" before, so we know * the buffer has only whole numbers of packets. + * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode */ - - /* set up this DMA transfer, enable the fifo, start */ - packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; - packets = min(packets, (unsigned)UDC_RXN_TC + 1); - req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, packets, - OMAP_DMA_SYNC_ELEMENT, - 0, 0); + if (cpu_is_omap24xx() && packets < ep->maxpacket) { + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + packets, 1, OMAP_DMA_SYNC_ELEMENT, + dma_trigger, 0); + req->dma_bytes = packets; + } else { + /* set up this DMA transfer, enable the fifo, start */ + packets /= ep->ep.maxpacket; + packets = min(packets, (unsigned)UDC_RXN_TC + 1); + req->dma_bytes = packets * ep->ep.maxpacket; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, packets, + OMAP_DMA_SYNC_ELEMENT, + dma_trigger, 0); + } omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, 0, 0); @@ -743,6 +758,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) { u16 reg; int status, restart, is_in; + int dma_channel; is_in = ep->bEndpointAddress & USB_DIR_IN; if (is_in) @@ -769,11 +785,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->dma_channel = channel; if (is_in) { - status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel, + if (cpu_is_omap24xx()) + dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel); + else + dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel; + status = omap_request_dma(dma_channel, ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_TXDMA_CFG_REG = reg; - /* EMIFF */ + /* EMIFF or SDRC */ omap_set_dma_src_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); omap_set_dma_src_data_pack(ep->lch, 1); @@ -785,7 +805,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) 0, 0); } } else { - status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, + if (cpu_is_omap24xx()) + dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel); + else + dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel; + + status = omap_request_dma(dma_channel, ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_RXDMA_CFG_REG = reg; @@ -795,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) OMAP_DMA_AMODE_CONSTANT, (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), 0, 0); - /* EMIFF */ + /* EMIFF or SDRC */ omap_set_dma_dest_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); omap_set_dma_dest_data_pack(ep->lch, 1); @@ -808,7 +833,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); /* channel type P: hw synch (fifo) */ - if (!cpu_is_omap15xx()) + if (cpu_class_is_omap1() && !cpu_is_omap15xx()) OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; } @@ -926,11 +951,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* this isn't bogus, but OMAP DMA isn't the only hardware to * have a hard time with partial packet reads... reject it. + * Except OMAP2 can handle the small packets. */ if (use_dma && ep->has_dma && ep->bEndpointAddress != 0 && (ep->bEndpointAddress & USB_DIR_IN) == 0 + && !cpu_class_is_omap2() && (req->req.length % ep->ep.maxpacket) != 0) { DBG("%s, no partial packet OUT reads\n", __FUNCTION__); return -EMSGSIZE; @@ -1001,7 +1028,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* STATUS for zero length DATA stages is * always an IN ... even for IN transfers, - * a wierd case which seem to stall OMAP. + * a weird case which seem to stall OMAP. */ UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR); UDC_CTRL_REG = UDC_CLR_EP; diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index 1dc398bb9ab..c6b9cbc7230 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -182,21 +182,16 @@ struct omap_udc { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - #ifdef VERBOSE # define VDBG DBG #else # define VDBG(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) +#define DBG(stuff...) pr_debug("udc: " stuff) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c new file mode 100644 index 00000000000..9fdabc8fcac --- /dev/null +++ b/drivers/usb/gadget/printer.c @@ -0,0 +1,1592 @@ +/* + * printer.c -- Printer gadget driver + * + * Copyright (C) 2003-2005 David Brownell + * Copyright (C) 2006 Craig W. Nadler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/utsname.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <linux/cdev.h> + +#include <asm/byteorder.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <asm/system.h> +#include <linux/uaccess.h> +#include <asm/unaligned.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/g_printer.h> + +#include "gadget_chips.h" + +#define DRIVER_DESC "Printer Gadget" +#define DRIVER_VERSION "2007 OCT 06" + +static const char shortname [] = "printer"; +static const char driver_desc [] = DRIVER_DESC; + +static dev_t g_printer_devno; + +static struct class *usb_gadget_class; + +/*-------------------------------------------------------------------------*/ + +struct printer_dev { + spinlock_t lock; /* lock this structure */ + /* lock buffer lists during read/write calls */ + spinlock_t lock_printer_io; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + u8 config; + s8 interface; + struct usb_ep *in_ep, *out_ep; + const struct usb_endpoint_descriptor + *in, *out; + struct list_head rx_reqs; /* List of free RX structs */ + struct list_head rx_reqs_active; /* List of Active RX xfers */ + struct list_head rx_buffers; /* List of completed xfers */ + /* wait until there is data to be read. */ + wait_queue_head_t rx_wait; + struct list_head tx_reqs; /* List of free TX structs */ + struct list_head tx_reqs_active; /* List of Active TX xfers */ + /* Wait until there are write buffers available to use. */ + wait_queue_head_t tx_wait; + /* Wait until all write buffers have been sent. */ + wait_queue_head_t tx_flush_wait; + struct usb_request *current_rx_req; + size_t current_rx_bytes; + u8 *current_rx_buf; + u8 printer_status; + u8 reset_printer; + struct class_device *printer_class_dev; + struct cdev printer_cdev; + struct device *pdev; + u8 printer_cdev_open; + wait_queue_head_t wait; +}; + +static struct printer_dev usb_printer_gadget; + +/*-------------------------------------------------------------------------*/ + +/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ + +/* Thanks to NetChip Technologies for donating this product ID. + */ +#define PRINTER_VENDOR_NUM 0x0525 /* NetChip */ +#define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ + +/* Some systems will want different product identifers published in the + * device descriptor, either numbers or strings or both. These string + * parameters are in UTF-8 (superset of ASCII's 7 bit characters). + */ + +static ushort __initdata idVendor; +module_param(idVendor, ushort, S_IRUGO); +MODULE_PARM_DESC(idVendor, "USB Vendor ID"); + +static ushort __initdata idProduct; +module_param(idProduct, ushort, S_IRUGO); +MODULE_PARM_DESC(idProduct, "USB Product ID"); + +static ushort __initdata bcdDevice; +module_param(bcdDevice, ushort, S_IRUGO); +MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); + +static char *__initdata iManufacturer; +module_param(iManufacturer, charp, S_IRUGO); +MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); + +static char *__initdata iProduct; +module_param(iProduct, charp, S_IRUGO); +MODULE_PARM_DESC(iProduct, "USB Product string"); + +static char *__initdata iSerialNum; +module_param(iSerialNum, charp, S_IRUGO); +MODULE_PARM_DESC(iSerialNum, "1"); + +static char *__initdata iPNPstring; +module_param(iPNPstring, charp, S_IRUGO); +MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); + +/* Number of requests to allocate per endpoint, not used for ep0. */ +static unsigned qlen = 10; +module_param(qlen, uint, S_IRUGO|S_IWUSR); + +#define QLEN qlen + +#ifdef CONFIG_USB_GADGET_DUALSPEED +#define DEVSPEED USB_SPEED_HIGH +#else /* full speed (low speed doesn't do bulk) */ +#define DEVSPEED USB_SPEED_FULL +#endif + +/*-------------------------------------------------------------------------*/ + +#define xprintk(d, level, fmt, args...) \ + printk(level "%s: " fmt, DRIVER_DESC, ## args) + +#ifdef DEBUG +#define DBG(dev, fmt, args...) \ + xprintk(dev, KERN_DEBUG, fmt, ## args) +#else +#define DBG(dev, fmt, args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG(dev, fmt, args...) \ + xprintk(dev, KERN_DEBUG, fmt, ## args) +#else +#define VDBG(dev, fmt, args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev, fmt, args...) \ + xprintk(dev, KERN_ERR, fmt, ## args) +#define WARN(dev, fmt, args...) \ + xprintk(dev, KERN_WARNING, fmt, ## args) +#define INFO(dev, fmt, args...) \ + xprintk(dev, KERN_INFO, fmt, ## args) + +/*-------------------------------------------------------------------------*/ + +/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly + * ep0 implementation: descriptors, config management, setup(). + * also optional class-specific notification interrupt transfer. + */ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. + */ + +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIALNUM 3 + +/* holds our biggest descriptor */ +#define USB_DESC_BUFSIZE 256 +#define USB_BUFSIZE 8192 + +/* This device advertises one configuration. */ +#define DEV_CONFIG_VALUE 1 +#define PRINTER_INTERFACE 0 + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .idVendor = __constant_cpu_to_le16(PRINTER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(PRINTER_PRODUCT_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUM, + .bNumConfigurations = 1 +}; + +static struct usb_otg_descriptor otg_desc = { + .bLength = sizeof otg_desc, + .bDescriptorType = USB_DT_OTG, + .bmAttributes = USB_OTG_SRP +}; + +static struct usb_config_descriptor config_desc = { + .bLength = sizeof config_desc, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 1, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1 /* Self-Powered */ +}; + +static struct usb_interface_descriptor intf_desc = { + .bLength = sizeof intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = PRINTER_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_PRINTER, + .bInterfaceSubClass = 1, /* Printer Sub-Class */ + .bInterfaceProtocol = 2, /* Bi-Directional */ + .iInterface = 0 +}; + +static struct usb_endpoint_descriptor fs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static struct usb_endpoint_descriptor fs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static const struct usb_descriptor_header *fs_printer_function [11] = { + (struct usb_descriptor_header *) &otg_desc, + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_ep_in_desc, + (struct usb_descriptor_header *) &fs_ep_out_desc, + NULL +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + */ + +static struct usb_endpoint_descriptor hs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512) +}; + +static struct usb_endpoint_descriptor hs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512) +}; + +static struct usb_qualifier_descriptor dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PRINTER, + .bNumConfigurations = 1 +}; + +static const struct usb_descriptor_header *hs_printer_function [11] = { + (struct usb_descriptor_header *) &otg_desc, + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_ep_in_desc, + (struct usb_descriptor_header *) &hs_ep_out_desc, + NULL +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g, hs, fs) (((void)(g)), (fs)) + +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ + +/*-------------------------------------------------------------------------*/ + +/* descriptors that are built on-demand */ + +static char manufacturer [50]; +static char product_desc [40] = DRIVER_DESC; +static char serial_num [40] = "1"; +static char pnp_string [1024] = + "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; + +/* static strings, in UTF-8 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, product_desc, }, + { STRING_SERIALNUM, serial_num, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, gfp_flags); + + if (req != NULL) { + req->length = len; + req->buf = kmalloc(len, gfp_flags); + if (req->buf == NULL) { + usb_ep_free_request(ep, req); + return NULL; + } + } + + return req; +} + +static void +printer_req_free(struct usb_ep *ep, struct usb_request *req) +{ + if (ep != NULL && req != NULL) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + int status = req->status; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + list_del_init(&req->list); /* Remode from Active List */ + + switch (status) { + + /* normal completion */ + case 0: + list_add_tail(&req->list, &dev->rx_buffers); + wake_up_interruptible(&dev->rx_wait); + DBG(dev, "G_Printer : rx length %d\n", req->actual); + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + VDBG(dev, "rx shutdown, code %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + + /* for hardware automagic (such as pxa) */ + case -ECONNABORTED: /* endpoint reset */ + DBG(dev, "rx %s reset\n", ep->name); + list_add(&req->list, &dev->rx_reqs); + break; + + /* data overrun */ + case -EOVERFLOW: + /* FALLTHROUGH */ + + default: + DBG(dev, "rx status %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + + switch (req->status) { + default: + VDBG(dev, "tx err %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + break; + case 0: + break; + } + + spin_lock(&dev->lock); + /* Take the request struct off the active list and put it on the + * free list. + */ + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + wake_up_interruptible(&dev->tx_wait); + if (likely(list_empty(&dev->tx_reqs_active))) + wake_up_interruptible(&dev->tx_flush_wait); + + spin_unlock(&dev->lock); +} + +/*-------------------------------------------------------------------------*/ + +static int +printer_open(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev; + unsigned long flags; + int ret = -EBUSY; + + dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); + + spin_lock_irqsave(&dev->lock, flags); + + if (!dev->printer_cdev_open) { + dev->printer_cdev_open = 1; + fd->private_data = dev; + ret = 0; + /* Change the printer status to show that it's on-line. */ + dev->printer_status |= PRINTER_SELECTED; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_open returned %x\n", ret); + + return ret; +} + +static int +printer_close(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + dev->printer_cdev_open = 0; + fd->private_data = NULL; + /* Change printer status to show that the printer is off-line. */ + dev->printer_status &= ~PRINTER_SELECTED; + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_close\n"); + + return 0; +} + +static ssize_t +printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; + size_t bytes_copied; + struct usb_request *req; + /* This is a pointer to the current USB rx request. */ + struct usb_request *current_rx_req; + /* This is the number of bytes in the current rx buffer. */ + size_t current_rx_bytes; + /* This is a pointer to the current rx buffer. */ + u8 *current_rx_buf; + + if (len == 0) + return -EINVAL; + + DBG(dev, "printer_read trying to read %d bytes\n", (int)len); + + spin_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* We will use this flag later to check if a printer reset happened + * after we turn interrupts back on. + */ + dev->reset_printer = 0; + + while (likely(!list_empty(&dev->rx_reqs))) { + int error; + + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del_init(&req->list); + + /* The USB Host sends us whatever amount of data it wants to + * so we always set the length field to the full USB_BUFSIZE. + * If the amount of data is more than the read() caller asked + * for it will be stored in the request buffer until it is + * asked for by read(). + */ + req->length = USB_BUFSIZE; + req->complete = rx_complete; + + error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); + if (error) { + DBG(dev, "rx submit --> %d\n", error); + list_add(&req->list, &dev->rx_reqs); + break; + } else { + list_add(&req->list, &dev->rx_reqs_active); + } + } + + bytes_copied = 0; + current_rx_req = dev->current_rx_req; + current_rx_bytes = dev->current_rx_bytes; + current_rx_buf = dev->current_rx_buf; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + /* Check if there is any data in the read buffers. Please note that + * current_rx_bytes is the number of bytes in the current rx buffer. + * If it is zero then check if there are any other rx_buffers that + * are on the completed list. We are only out of data if all rx + * buffers are empty. + */ + if ((current_rx_bytes == 0) && + (likely(list_empty(&dev->rx_buffers)))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If no data is available check if this is a NON-Blocking + * call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until data is available */ + wait_event_interruptible(dev->rx_wait, + (likely(!list_empty(&dev->rx_buffers)))); + spin_lock_irqsave(&dev->lock, flags); + } + + /* We have data to return then copy it to the caller's buffer.*/ + while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) + && len) { + if (current_rx_bytes == 0) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del_init(&req->list); + + if (req->actual && req->buf) { + current_rx_req = req; + current_rx_bytes = req->actual; + current_rx_buf = req->buf; + } else { + list_add(&req->list, &dev->rx_reqs); + continue; + } + } + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (len > current_rx_bytes) + size = current_rx_bytes; + else + size = len; + + size -= copy_to_user(buf, current_rx_buf, size); + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset free the req and buffer */ + if (dev->reset_printer) { + printer_req_free(dev->out_ep, current_rx_req); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* If we not returning all the data left in this RX request + * buffer then adjust the amount of data left in the buffer. + * Othewise if we are done with this RX request buffer then + * requeue it to get any incoming data from the USB host. + */ + if (size < current_rx_bytes) { + current_rx_bytes -= size; + current_rx_buf += size; + } else { + list_add(¤t_rx_req->list, &dev->rx_reqs); + current_rx_bytes = 0; + current_rx_buf = NULL; + current_rx_req = NULL; + } + } + + dev->current_rx_req = current_rx_req; + dev->current_rx_bytes = current_rx_bytes; + dev->current_rx_buf = current_rx_buf; + + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); + + if (bytes_copied) + return bytes_copied; + else + return -EAGAIN; +} + +static ssize_t +printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; /* Amount of data in a TX request. */ + size_t bytes_copied = 0; + struct usb_request *req; + + DBG(dev, "printer_write trying to send %d bytes\n", (int)len); + + if (len == 0) + return -EINVAL; + + spin_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* Check if a printer reset happens while we have interrupts on */ + dev->reset_printer = 0; + + /* Check if there is any available write buffers */ + if (likely(list_empty(&dev->tx_reqs))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If write buffers are available check if this is + * a NON-Blocking call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until a write buffer is available */ + wait_event_interruptible(dev->tx_wait, + (likely(!list_empty(&dev->tx_reqs)))); + spin_lock_irqsave(&dev->lock, flags); + } + + while (likely(!list_empty(&dev->tx_reqs)) && len) { + + if (len > USB_BUFSIZE) + size = USB_BUFSIZE; + else + size = len; + + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del_init(&req->list); + + req->complete = tx_complete; + req->length = size; + + /* Check if we need to send a zero length packet. */ + if (len > size) + /* They will be more TX requests so no yet. */ + req->zero = 0; + else + /* If the data amount is not a multple of the + * maxpacket size then send a zero length packet. + */ + req->zero = ((len % dev->in_ep->maxpacket) == 0); + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (copy_from_user(req->buf, buf, size)) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock(&dev->lock_printer_io); + return bytes_copied; + } + + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset so free the req and buffer */ + if (dev->reset_printer) { + printer_req_free(dev->in_ep, req); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + list_add(&req->list, &dev->tx_reqs_active); + + } + + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); + + if (bytes_copied) { + return bytes_copied; + } else { + return -EAGAIN; + } +} + +static int +printer_fsync(struct file *fd, struct dentry *dentry, int datasync) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int tx_list_empty; + + spin_lock_irqsave(&dev->lock, flags); + tx_list_empty = (likely(list_empty(&dev->tx_reqs))); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!tx_list_empty) { + /* Sleep until all data has been sent */ + wait_event_interruptible(dev->tx_flush_wait, + (likely(list_empty(&dev->tx_reqs_active)))); + } + + return 0; +} + +static unsigned int +printer_poll(struct file *fd, poll_table *wait) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + poll_wait(fd, &dev->rx_wait, wait); + poll_wait(fd, &dev->tx_wait, wait); + + spin_lock_irqsave(&dev->lock, flags); + if (likely(!list_empty(&dev->tx_reqs))) + status |= POLLOUT | POLLWRNORM; + + if (likely(!list_empty(&dev->rx_buffers))) + status |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +static int +printer_ioctl(struct inode *inode, struct file *fd, unsigned int code, + unsigned long arg) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); + + /* handle ioctls */ + + spin_lock_irqsave(&dev->lock, flags); + + switch (code) { + case GADGET_GET_PRINTER_STATUS: + status = (int)dev->printer_status; + break; + case GADGET_SET_PRINTER_STATUS: + dev->printer_status = (u8)arg; + break; + default: + /* could not handle ioctl */ + DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n", + code); + status = -ENOTTY; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +/* used after endpoint configuration */ +static struct file_operations printer_io_operations = { + .owner = THIS_MODULE, + .open = printer_open, + .read = printer_read, + .write = printer_write, + .fsync = printer_fsync, + .poll = printer_poll, + .ioctl = printer_ioctl, + .release = printer_close +}; + +/*-------------------------------------------------------------------------*/ + +static int +set_printer_interface(struct printer_dev *dev) +{ + int result = 0; + + dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); + dev->in_ep->driver_data = dev; + + dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc); + dev->out_ep->driver_data = dev; + + result = usb_ep_enable(dev->in_ep, dev->in); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + + result = usb_ep_enable(dev->out_ep, dev->out); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + +done: + /* on error, disable any endpoints */ + if (result != 0) { + (void) usb_ep_disable(dev->in_ep); + (void) usb_ep_disable(dev->out_ep); + dev->in = NULL; + dev->out = NULL; + } + + /* caller is responsible for cleanup on error */ + return result; +} + +static void printer_reset_interface(struct printer_dev *dev) +{ + if (dev->interface < 0) + return; + + DBG(dev, "%s\n", __FUNCTION__); + + if (dev->in) + usb_ep_disable(dev->in_ep); + + if (dev->out) + usb_ep_disable(dev->out_ep); + + dev->interface = -1; +} + +/* change our operational config. must agree with the code + * that returns config descriptors, and altsetting code. + */ +static int +printer_set_config(struct printer_dev *dev, unsigned number) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + if (gadget_is_sa1100(gadget) && dev->config) { + /* tx fifo is full, but we can't clear it...*/ + INFO(dev, "can't change configurations\n"); + return -ESPIPE; + } + + switch (number) { + case DEV_CONFIG_VALUE: + result = 0; + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + break; + } + + if (result) { + usb_gadget_vbus_draw(dev->gadget, + dev->gadget->is_otg ? 8 : 100); + } else { + char *speed; + unsigned power; + + power = 2 * config_desc.bMaxPower; + usb_gadget_vbus_draw(dev->gadget, power); + + switch (gadget->speed) { + case USB_SPEED_FULL: speed = "full"; break; +#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_SPEED_HIGH: speed = "high"; break; +#endif + default: speed = "?"; break; + } + + dev->config = number; + INFO(dev, "%s speed config #%d: %d mA, %s\n", + speed, number, power, driver_desc); + } + return result; +} + +static int +config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, + int is_otg) +{ + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (speed == USB_SPEED_HIGH); + + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + + if (hs) { + function = hs_printer_function; + } else { + function = fs_printer_function; + } +#else + function = fs_printer_function; +#endif + + if (index >= device_desc.bNumConfigurations) + return -EINVAL; + + /* for now, don't advertise srp-only devices */ + if (!is_otg) + function++; + + len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE, + function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; +} + +/* Change our operational Interface. */ +static int +set_interface(struct printer_dev *dev, unsigned number) +{ + int result = 0; + + if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) { + /* tx fifo is full, but we can't clear it...*/ + INFO(dev, "can't change interfaces\n"); + return -ESPIPE; + } + + /* Free the current interface */ + switch (dev->interface) { + case PRINTER_INTERFACE: + printer_reset_interface(dev); + break; + } + + switch (number) { + case PRINTER_INTERFACE: + result = set_printer_interface(dev); + if (result) { + printer_reset_interface(dev); + } else { + dev->interface = PRINTER_INTERFACE; + } + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + } + + if (!result) + INFO(dev, "Using interface %x\n", number); + + return result; +} + +static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DBG((struct printer_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +static void printer_soft_reset(struct printer_dev *dev) +{ + struct usb_request *req; + + INFO(dev, "Received Printer Reset Request\n"); + + if (usb_ep_disable(dev->in_ep)) + DBG(dev, "Failed to disable USB in_ep\n"); + if (usb_ep_disable(dev->out_ep)) + DBG(dev, "Failed to disable USB out_ep\n"); + + if (dev->current_rx_req != NULL) { + list_add(&dev->current_rx_req->list, &dev->rx_reqs); + dev->current_rx_req = NULL; + } + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + dev->reset_printer = 1; + + while (likely(!(list_empty(&dev->rx_buffers)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->rx_reqs_active)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->tx_reqs_active)))) { + req = container_of(dev->tx_reqs_active.next, + struct usb_request, list); + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + } + + if (usb_ep_enable(dev->in_ep, dev->in)) + DBG(dev, "Failed to enable USB in_ep\n"); + if (usb_ep_enable(dev->out_ep, dev->out)) + DBG(dev, "Failed to enable USB out_ep\n"); + + wake_up_interruptible(&dev->tx_wait); + wake_up_interruptible(&dev->tx_flush_wait); +} + +/*-------------------------------------------------------------------------*/ + +/* + * The setup() callback implements all the ep0 functionality that's not + * handled lower down. + */ +static int +printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct printer_dev *dev = get_gadget_data(gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); + + DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); + + req->complete = printer_setup_complete; + + switch (ctrl->bRequestType&USB_TYPE_MASK) { + + case USB_TYPE_STANDARD: + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + break; + switch (wValue >> 8) { + + case USB_DT_DEVICE: + value = min(wLength, (u16) sizeof device_desc); + memcpy(req->buf, &device_desc, value); + break; +#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; + value = min(wLength, + (u16) sizeof dev_qualifier); + memcpy(req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; + /* FALLTHROUGH */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + case USB_DT_CONFIG: + value = config_buf(gadget->speed, req->buf, + wValue >> 8, + wValue & 0xff, + gadget->is_otg); + if (value >= 0) + value = min(wLength, (u16) value); + break; + + case USB_DT_STRING: + value = usb_gadget_get_string(&stringtab, + wValue & 0xff, req->buf); + if (value >= 0) + value = min(wLength, (u16) value); + break; + } + break; + + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + break; + if (gadget->a_hnp_support) + DBG(dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DBG(dev, "HNP needs a different root port\n"); + value = printer_set_config(dev, wValue); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + break; + *(u8 *)req->buf = dev->config; + value = min(wLength, (u16) 1); + break; + + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE || + !dev->config) + break; + + value = set_interface(dev, PRINTER_INTERFACE); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != + (USB_DIR_IN|USB_RECIP_INTERFACE) + || !dev->config) + break; + + *(u8 *)req->buf = dev->interface; + value = min(wLength, (u16) 1); + break; + + default: + goto unknown; + } + break; + + case USB_TYPE_CLASS: + switch (ctrl->bRequest) { + case 0: /* Get the IEEE-1284 PNP String */ + /* Only one printer interface is supported. */ + if ((wIndex>>8) != PRINTER_INTERFACE) + break; + + value = (pnp_string[0]<<8)|pnp_string[1]; + memcpy(req->buf, pnp_string, value); + DBG(dev, "1284 PNP String: %x %s\n", value, + &pnp_string[2]); + break; + + case 1: /* Get Port Status */ + /* Only one printer interface is supported. */ + if (wIndex != PRINTER_INTERFACE) + break; + + *(u8 *)req->buf = dev->printer_status; + value = min(wLength, (u16) 1); + break; + + case 2: /* Soft Reset */ + /* Only one printer interface is supported. */ + if (wIndex != PRINTER_INTERFACE) + break; + + printer_soft_reset(dev); + + value = 0; + break; + + default: + goto unknown; + } + break; + + default: +unknown: + VDBG(dev, + "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); + break; + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < wLength + && (value % gadget->ep0->maxpacket) == 0; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(dev, "ep_queue --> %d\n", value); + req->status = 0; + printer_setup_complete(gadget->ep0, req); + } + } + + /* host either stalls (value < 0) or reports success */ + return value; +} + +static void +printer_disconnect(struct usb_gadget *gadget) +{ + struct printer_dev *dev = get_gadget_data(gadget); + unsigned long flags; + + DBG(dev, "%s\n", __FUNCTION__); + + spin_lock_irqsave(&dev->lock, flags); + + printer_reset_interface(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void +printer_unbind(struct usb_gadget *gadget) +{ + struct printer_dev *dev = get_gadget_data(gadget); + struct usb_request *req; + + + DBG(dev, "%s\n", __FUNCTION__); + + /* Remove sysfs files */ + device_destroy(usb_gadget_class, g_printer_devno); + + /* Remove Character Device */ + cdev_del(&dev->printer_cdev); + + /* we must already have been disconnected ... no i/o may be active */ + WARN_ON(!list_empty(&dev->tx_reqs_active)); + WARN_ON(!list_empty(&dev->rx_reqs_active)); + + /* Free all memory for this driver. */ + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + + if (dev->current_rx_req != NULL); + printer_req_free(dev->out_ep, dev->current_rx_req); + + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + + while (!list_empty(&dev->rx_buffers)) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + + if (dev->req) { + printer_req_free(gadget->ep0, dev->req); + dev->req = NULL; + } + + set_gadget_data(gadget, NULL); +} + +static int __init +printer_bind(struct usb_gadget *gadget) +{ + struct printer_dev *dev; + struct usb_ep *in_ep, *out_ep; + int status = -ENOMEM; + int gcnum; + size_t len; + u32 i; + struct usb_request *req; + + dev = &usb_printer_gadget; + + + /* Setup the sysfs files for the printer gadget. */ + dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, + "g_printer"); + if (IS_ERR(dev->pdev)) { + ERROR(dev, "Failed to create device: g_printer\n"); + goto fail; + } + + /* + * Register a character device as an interface to a user mode + * program that handles the printer specific functionality. + */ + cdev_init(&dev->printer_cdev, &printer_io_operations); + dev->printer_cdev.owner = THIS_MODULE; + status = cdev_add(&dev->printer_cdev, g_printer_devno, 1); + if (status) { + ERROR(dev, "Failed to open char device\n"); + goto fail; + } + + if (gadget_is_sa1100(gadget)) { + /* hardware can't write zero length packets. */ + ERROR(dev, "SA1100 controller is unsupport by this driver\n"); + goto fail; + } + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) { + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); + } else { + dev_warn(&gadget->dev, "controller '%s' not recognized\n", + gadget->name); + /* unrecognized, but safe unless bulk is REALLY quirky */ + device_desc.bcdDevice = + __constant_cpu_to_le16(0xFFFF); + } + snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + gadget->name); + + device_desc.idVendor = + __constant_cpu_to_le16(PRINTER_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(PRINTER_PRODUCT_NUM); + + /* support optional vendor/distro customization */ + if (idVendor) { + if (!idProduct) { + dev_err(&gadget->dev, "idVendor needs idProduct!\n"); + return -ENODEV; + } + device_desc.idVendor = cpu_to_le16(idVendor); + device_desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + device_desc.bcdDevice = cpu_to_le16(bcdDevice); + } + + if (iManufacturer) + strlcpy(manufacturer, iManufacturer, sizeof manufacturer); + + if (iProduct) + strlcpy(product_desc, iProduct, sizeof product_desc); + + if (iSerialNum) + strlcpy(serial_num, iSerialNum, sizeof serial_num); + + if (iPNPstring) + strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); + + len = strlen(pnp_string); + pnp_string[0] = (len >> 8) & 0xFF; + pnp_string[1] = len & 0xFF; + + /* all we really need is bulk IN/OUT */ + usb_ep_autoconfig_reset(gadget); + in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc); + if (!in_ep) { +autoconf_fail: + dev_err(&gadget->dev, "can't autoconfigure on %s\n", + gadget->name); + return -ENODEV; + } + in_ep->driver_data = in_ep; /* claim */ + + out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc); + if (!out_ep) + goto autoconf_fail; + out_ep->driver_data = out_ep; /* claim */ + +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; +#endif /* DUALSPEED */ + + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + usb_gadget_set_selfpowered(gadget); + + if (gadget->is_otg) { + otg_desc.bmAttributes |= USB_OTG_HNP, + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + config_desc.bMaxPower = 4; + } + + spin_lock_init(&dev->lock); + spin_lock_init(&dev->lock_printer_io); + INIT_LIST_HEAD(&dev->tx_reqs); + INIT_LIST_HEAD(&dev->tx_reqs_active); + INIT_LIST_HEAD(&dev->rx_reqs); + INIT_LIST_HEAD(&dev->rx_reqs_active); + INIT_LIST_HEAD(&dev->rx_buffers); + init_waitqueue_head(&dev->rx_wait); + init_waitqueue_head(&dev->tx_wait); + init_waitqueue_head(&dev->tx_flush_wait); + + dev->config = 0; + dev->interface = -1; + dev->printer_cdev_open = 0; + dev->printer_status = PRINTER_NOT_ERROR; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + dev->in_ep = in_ep; + dev->out_ep = out_ep; + + /* preallocate control message data and buffer */ + dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE, + GFP_KERNEL); + if (!dev->req) { + status = -ENOMEM; + goto fail; + } + + for (i = 0; i < QLEN; i++) { + req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) { + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + return -ENOMEM; + } + list_add(&req->list, &dev->tx_reqs); + } + + for (i = 0; i < QLEN; i++) { + req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) { + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + return -ENOMEM; + } + list_add(&req->list, &dev->rx_reqs); + } + + dev->req->complete = printer_setup_complete; + + /* finish hookup to lower layer ... */ + dev->gadget = gadget; + set_gadget_data(gadget, dev); + gadget->ep0->driver_data = dev; + + INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); + INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, + in_ep->name); + + return 0; + +fail: + printer_unbind(gadget); + return status; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver printer_driver = { + .speed = DEVSPEED, + + .function = (char *) driver_desc, + .bind = printer_bind, + .unbind = printer_unbind, + + .setup = printer_setup, + .disconnect = printer_disconnect, + + .driver = { + .name = (char *) shortname, + .owner = THIS_MODULE, + }, +}; + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Craig Nadler"); +MODULE_LICENSE("GPL"); + +static int __init +init(void) +{ + int status; + + usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); + if (IS_ERR(usb_gadget_class)) { + status = PTR_ERR(usb_gadget_class); + ERROR(dev, "unable to create usb_gadget class %d\n", status); + return status; + } + + status = alloc_chrdev_region(&g_printer_devno, 0, 1, + "USB printer gadget"); + if (status) { + ERROR(dev, "alloc_chrdev_region %d\n", status); + class_destroy(usb_gadget_class); + return status; + } + + status = usb_gadget_register_driver(&printer_driver); + if (status) { + class_destroy(usb_gadget_class); + unregister_chrdev_region(g_printer_devno, 1); + DBG(dev, "usb_gadget_register_driver %x\n", status); + } + + return status; +} +module_init(init); + +static void __exit +cleanup(void) +{ + int status; + + spin_lock(&usb_printer_gadget.lock_printer_io); + class_destroy(usb_gadget_class); + unregister_chrdev_region(g_printer_devno, 2); + + status = usb_gadget_unregister_driver(&printer_driver); + if (status) + ERROR(dev, "usb_gadget_unregister_driver %x\n", status); + + spin_unlock(&usb_printer_gadget.lock_printer_io); +} +module_exit(cleanup); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 3173b39f0bf..4402d6f042d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -24,7 +24,7 @@ * */ -// #define VERBOSE DBG_VERBOSE +/* #define VERBOSE_DEBUG */ #include <linux/device.h> #include <linux/module.h> @@ -38,13 +38,14 @@ #include <linux/timer.h> #include <linux/list.h> #include <linux/interrupt.h> -#include <linux/proc_fs.h> #include <linux/mm.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/irq.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/seq_file.h> +#include <linux/debugfs.h> #include <asm/byteorder.h> #include <asm/dma.h> @@ -127,8 +128,10 @@ static int is_vbus_present(void) { struct pxa2xx_udc_mach_info *mach = the_controller->mach; - if (mach->gpio_vbus) - return gpio_get_value(mach->gpio_vbus); + if (mach->gpio_vbus) { + int value = gpio_get_value(mach->gpio_vbus); + return mach->gpio_vbus_inverted ? !value : value; + } if (mach->udc_is_connected) return mach->udc_is_connected(); return 1; @@ -677,7 +680,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == 0 /* ep0 */) { + if (ep->desc == NULL/* ep0 */) { unsigned length = _req->length; switch (dev->ep0state) { @@ -731,7 +734,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* pio or dma irq handler advances the queue. */ - if (likely (req != 0)) + if (likely(req != NULL)) list_add_tail(&req->queue, &ep->queue); local_irq_restore(flags); @@ -991,45 +994,32 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = { /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static const char proc_node_name [] = "driver/udc"; +#ifdef CONFIG_USB_GADGET_DEBUG_FS static int -udc_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *_dev) +udc_seq_show(struct seq_file *m, void *d) { - char *buf = page; - struct pxa2xx_udc *dev = _dev; - char *next = buf; - unsigned size = count; + struct pxa2xx_udc *dev = m->private; unsigned long flags; - int i, t; + int i; u32 tmp; - if (off != 0) - return 0; - local_irq_save(flags); /* basic device status */ - t = scnprintf(next, size, DRIVER_DESC "\n" + seq_printf(m, DRIVER_DESC "\n" "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR "(pio)", dev->driver ? dev->driver->driver.name : "(none)", is_vbus_present() ? "full speed" : "disconnected"); - size -= t; - next += t; /* registers for device and ep0 */ - t = scnprintf(next, size, + seq_printf(m, "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); - size -= t; - next += t; tmp = UDCCR; - t = scnprintf(next, size, + seq_printf(m, "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp, (tmp & UDCCR_REM) ? " rem" : "", (tmp & UDCCR_RSTIR) ? " rstir" : "", @@ -1039,11 +1029,9 @@ udc_proc_read(char *page, char **start, off_t off, int count, (tmp & UDCCR_RSM) ? " rsm" : "", (tmp & UDCCR_UDA) ? " uda" : "", (tmp & UDCCR_UDE) ? " ude" : ""); - size -= t; - next += t; tmp = UDCCS0; - t = scnprintf(next, size, + seq_printf(m, "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp, (tmp & UDCCS0_SA) ? " sa" : "", (tmp & UDCCS0_RNE) ? " rne" : "", @@ -1053,28 +1041,22 @@ udc_proc_read(char *page, char **start, off_t off, int count, (tmp & UDCCS0_FTF) ? " ftf" : "", (tmp & UDCCS0_IPR) ? " ipr" : "", (tmp & UDCCS0_OPR) ? " opr" : ""); - size -= t; - next += t; if (dev->has_cfr) { tmp = UDCCFR; - t = scnprintf(next, size, + seq_printf(m, "udccfr %02X =%s%s\n", tmp, (tmp & UDCCFR_AREN) ? " aren" : "", (tmp & UDCCFR_ACM) ? " acm" : ""); - size -= t; - next += t; } if (!is_vbus_present() || !dev->driver) goto done; - t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", + seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", dev->stats.write.bytes, dev->stats.write.ops, dev->stats.read.bytes, dev->stats.read.ops, dev->stats.irqs); - size -= t; - next += t; /* dump endpoint queues */ for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { @@ -1082,61 +1064,68 @@ udc_proc_read(char *page, char **start, off_t off, int count, struct pxa2xx_request *req; if (i != 0) { - const struct usb_endpoint_descriptor *d; + const struct usb_endpoint_descriptor *desc; - d = ep->desc; - if (!d) + desc = ep->desc; + if (!desc) continue; tmp = *dev->ep [i].reg_udccs; - t = scnprintf(next, size, + seq_printf(m, "%s max %d %s udccs %02x irqs %lu\n", - ep->ep.name, le16_to_cpu (d->wMaxPacketSize), + ep->ep.name, le16_to_cpu(desc->wMaxPacketSize), "pio", tmp, ep->pio_irqs); /* TODO translate all five groups of udccs bits! */ } else /* ep0 should only have one transfer queued */ - t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n", + seq_printf(m, "ep0 max 16 pio irqs %lu\n", ep->pio_irqs); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "\t(nothing queued)\n"); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; + seq_printf(m, "\t(nothing queued)\n"); continue; } list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, + seq_printf(m, "\treq %p len %d/%d buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; } } done: local_irq_restore(flags); - *eof = 1; - return count - size; + return 0; } -#define create_proc_files() \ - create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) -#define remove_proc_files() \ - remove_proc_entry(proc_node_name, NULL) +static int +udc_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, udc_seq_show, inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = udc_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +#define create_debug_files(dev) \ + do { \ + dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ + S_IRUGO, NULL, dev, &debug_fops); \ + } while (0) +#define remove_debug_files(dev) \ + do { \ + if (dev->debugfs_udc) \ + debugfs_remove(dev->debugfs_udc); \ + } while (0) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ -#define create_proc_files() do {} while (0) -#define remove_proc_files() do {} while (0) +#define create_debug_files(dev) do {} while (0) +#define remove_debug_files(dev) do {} while (0) #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ @@ -1345,6 +1334,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) local_irq_enable(); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; dev->driver = NULL; device_del (&dev->gadget.dev); @@ -1397,6 +1387,9 @@ static irqreturn_t udc_vbus_irq(int irq, void *_dev) struct pxa2xx_udc *dev = _dev; int vbus = gpio_get_value(dev->mach->gpio_vbus); + if (dev->mach->gpio_vbus_inverted) + vbus = !vbus; + pxa2xx_udc_vbus_session(&dev->gadget, vbus); return IRQ_HANDLED; } @@ -2099,7 +2092,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) /* insist on Intel/ARM/XScale */ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { - printk(KERN_ERR "%s: not XScale!\n", driver_name); + pr_err("%s: not XScale!\n", driver_name); return -ENODEV; } @@ -2128,7 +2121,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) break; #endif default: - printk(KERN_ERR "%s: unrecognized processor: %08x\n", + pr_err("%s: unrecognized processor: %08x\n", driver_name, chiprev); /* iop3xx, ixp4xx, ... */ return -ENODEV; @@ -2199,7 +2192,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) retval = request_irq(irq, pxa2xx_udc_irq, IRQF_DISABLED, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %d, err %d\n", + pr_err("%s: can't get irq %d, err %d\n", driver_name, irq, retval); goto err_irq1; } @@ -2212,7 +2205,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_DISC_IRQ, retval); lubbock_fail0: goto err_irq_lub; @@ -2222,7 +2215,7 @@ lubbock_fail0: IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_IRQ, retval); free_irq(LUBBOCK_USB_DISC_IRQ, dev); goto lubbock_fail0; @@ -2235,12 +2228,12 @@ lubbock_fail0: IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, vbus_irq, retval); goto err_vbus_irq; } } - create_proc_files(); + create_debug_files(dev); return 0; @@ -2277,7 +2270,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) return -EBUSY; udc_disable(dev); - remove_proc_files(); + remove_debug_files(dev); if (dev->got_irq) { free_irq(platform_get_irq(pdev, 0), dev); @@ -2361,7 +2354,7 @@ static struct platform_driver udc_driver = { static int __init udc_init(void) { - printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); + pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); return platform_driver_probe(&udc_driver, pxa2xx_udc_probe); } module_init(udc_init); diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1db46d70577..b67e3ff5e4e 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -129,6 +129,10 @@ struct pxa2xx_udc { struct pxa2xx_udc_mach_info *mach; u64 dma_mask; struct pxa2xx_ep ep [PXA_UDC_NUM_ENDPOINTS]; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_udc; +#endif }; /*-------------------------------------------------------------------------*/ @@ -151,17 +155,19 @@ static struct pxa2xx_udc *the_controller; #define DBG_NOISY 3 /* ... even more: request level */ #define DBG_VERY_NOISY 4 /* ... even more: packet level */ +#define DMSG(stuff...) pr_debug("udc: " stuff) + #ifdef DEBUG +static int is_vbus_present(void); + static const char *state_name[] = { "EP0_IDLE", "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", "EP0_END_XFER", "EP0_STALL" }; -#define DMSG(stuff...) printk(KERN_DEBUG "udc: " stuff) - -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG # define UDC_DEBUG DBG_VERBOSE #else # define UDC_DEBUG DBG_NORMAL @@ -207,7 +213,7 @@ dump_state(struct pxa2xx_udc *dev) unsigned i; DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - is_usb_connected() ? "host " : "disconnected", + is_vbus_present() ? "host " : "disconnected", state_name[dev->ep0state], UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); dump_udccr("udccr"); @@ -224,7 +230,7 @@ dump_state(struct pxa2xx_udc *dev) } else DMSG("ep0 driver '%s'\n", dev->driver->driver.name); - if (!is_usb_connected()) + if (!is_vbus_present()) return; dump_udccs0 ("udccs0"); @@ -233,7 +239,7 @@ dump_state(struct pxa2xx_udc *dev) dev->stats.read.bytes, dev->stats.read.ops); for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { - if (dev->ep [i].desc == 0) + if (dev->ep [i].desc == NULL) continue; DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs); } @@ -241,8 +247,6 @@ dump_state(struct pxa2xx_udc *dev) #else -#define DMSG(stuff...) do{}while(0) - #define dump_udccr(x) do{}while(0) #define dump_udccs0(x) do{}while(0) #define dump_state(x) do{}while(0) @@ -253,8 +257,9 @@ dump_state(struct pxa2xx_udc *dev) #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) #endif /* __LINUX_USB_GADGET_PXA2XX_H */ diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index db1b2bfcee4..3d036647431 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -53,21 +53,18 @@ */ #if 0 -#define DBG(str,args...) do { \ - if (rndis_debug) \ - printk(KERN_DEBUG str , ## args ); \ - } while (0) static int rndis_debug = 0; - module_param (rndis_debug, int, 0); MODULE_PARM_DESC (rndis_debug, "enable debugging"); - #else - #define rndis_debug 0 -#define DBG(str,args...) do{}while(0) #endif +#define DBG(str,args...) do { \ + if (rndis_debug) \ + pr_debug(str , ## args); \ + } while (0) + #define RNDIS_MAX_CONFIGS 1 @@ -679,7 +676,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, #endif default: - printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", + pr_warning("%s: query unknown OID 0x%08X\n", __FUNCTION__, OID); } if (retval < 0) @@ -804,7 +801,7 @@ update_linkstate: #endif /* RNDIS_PM */ default: - printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", + pr_warning("%s: set unknown OID 0x%08X, size %d\n", __FUNCTION__, OID, buf_len); } @@ -1126,8 +1123,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf) * In one case those messages seemed to relate to the host * suspending itself. */ - printk (KERN_WARNING - "%s: unknown RNDIS message 0x%08X len %d\n", + pr_warning("%s: unknown RNDIS message 0x%08X len %d\n", __FUNCTION__ , MsgType, MsgLength); { unsigned i; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 4ce050c3d13..aadc4204d6f 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -893,7 +893,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) /* * s3c2410_udc_irq - interrupt handler */ -static irqreturn_t s3c2410_udc_irq(int irq, void *_dev) +static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) { struct s3c2410_udc *dev = _dev; int usb_status; @@ -1016,7 +1016,7 @@ static irqreturn_t s3c2410_udc_irq(int irq, void *_dev) } } - dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq); + dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); /* Restore old index */ udc_write(idx, S3C2410_UDC_INDEX_REG); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f5738eb8e76..f5c3896b1d9 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -89,9 +89,9 @@ static int debug = 1; #endif #define gs_debug(format, arg...) \ - do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) + do { if (debug) pr_debug(format, ## arg); } while (0) #define gs_debug_level(level, format, arg...) \ - do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) + do { if (debug >= level) pr_debug(format, ## arg); } while (0) /* Thanks to NetChip Technologies for donating this product ID. @@ -553,7 +553,8 @@ static int __init gs_module_init(void) retval = usb_gadget_register_driver(&gs_gadget_driver); if (retval) { - printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval); + pr_err("gs_module_init: cannot register gadget driver, " + "ret=%d\n", retval); return retval; } @@ -579,11 +580,13 @@ static int __init gs_module_init(void) if (retval) { usb_gadget_unregister_driver(&gs_gadget_driver); put_tty_driver(gs_tty_driver); - printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval); + pr_err("gs_module_init: cannot register tty driver, " + "ret=%d\n", retval); return retval; } - printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR); + pr_info("gs_module_init: %s %s loaded\n", + GS_LONG_NAME, GS_VERSION_STR); return 0; } @@ -598,7 +601,8 @@ static void __exit gs_module_exit(void) put_tty_driver(gs_tty_driver); usb_gadget_unregister_driver(&gs_gadget_driver); - printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR); + pr_info("gs_module_exit: %s %s unloaded\n", + GS_LONG_NAME, GS_VERSION_STR); } /* TTY Driver */ @@ -621,7 +625,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file); if (port_num < 0 || port_num >= GS_NUM_PORTS) { - printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n", + pr_err("gs_open: (%d,%p,%p) invalid port number\n", port_num, tty, file); return -ENODEV; } @@ -629,15 +633,14 @@ static int gs_open(struct tty_struct *tty, struct file *file) dev = gs_device; if (dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n", + pr_err("gs_open: (%d,%p,%p) NULL device pointer\n", port_num, tty, file); return -ENODEV; } mtx = &gs_open_close_lock[port_num]; if (mutex_lock_interruptible(mtx)) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) interrupted waiting for mutex\n", + pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n", port_num, tty, file); return -ERESTARTSYS; } @@ -645,8 +648,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_lock_irqsave(&dev->dev_lock, flags); if (dev->dev_config == GS_NO_CONFIG_ID) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) device is not connected\n", + pr_err("gs_open: (%d,%p,%p) device is not connected\n", port_num, tty, file); ret = -ENODEV; goto exit_unlock_dev; @@ -655,7 +657,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) port = dev->dev_port[port_num]; if (port == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n", + pr_err("gs_open: (%d,%p,%p) NULL port pointer\n", port_num, tty, file); ret = -ENODEV; goto exit_unlock_dev; @@ -665,7 +667,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_unlock(&dev->dev_lock); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n", port_num, tty, file); ret = -EIO; goto exit_unlock_port; @@ -692,8 +694,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* might have been disconnected while asleep, check */ if (port->port_dev == NULL) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) port disconnected (2)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n", port_num, tty, file); port->port_in_use = 0; ret = -EIO; @@ -701,7 +702,8 @@ static int gs_open(struct tty_struct *tty, struct file *file) } if ((port->port_write_buf=buf) == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n", + pr_err("gs_open: (%d,%p,%p) cannot allocate " + "port write buffer\n", port_num, tty, file); port->port_in_use = 0; ret = -ENOMEM; @@ -714,7 +716,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* might have been disconnected while asleep, check */ if (port->port_dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n", port_num, tty, file); port->port_in_use = 0; ret = -EIO; @@ -762,7 +764,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) struct mutex *mtx; if (port == NULL) { - printk(KERN_ERR "gs_close: NULL port pointer\n"); + pr_err("gs_close: NULL port pointer\n"); return; } @@ -774,8 +776,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); if (port->port_open_count == 0) { - printk(KERN_ERR - "gs_close: (%d,%p,%p) port is already closed\n", + pr_err("gs_close: (%d,%p,%p) port is already closed\n", port->port_num, tty, file); goto exit; } @@ -837,7 +838,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) int ret; if (port == NULL) { - printk(KERN_ERR "gs_write: NULL port pointer\n"); + pr_err("gs_write: NULL port pointer\n"); return -EIO; } @@ -850,14 +851,14 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n", + pr_err("gs_write: (%d,%p) port is not connected\n", port->port_num, tty); ret = -EIO; goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_write: (%d,%p) port is closed\n", + pr_err("gs_write: (%d,%p) port is closed\n", port->port_num, tty); ret = -EBADF; goto exit; @@ -888,7 +889,7 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_put_char: NULL port pointer\n"); + pr_err("gs_put_char: NULL port pointer\n"); return; } @@ -898,13 +899,13 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n", + pr_err("gs_put_char: (%d,%p) port is not connected\n", port->port_num, tty); goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n", + pr_err("gs_put_char: (%d,%p) port is closed\n", port->port_num, tty); goto exit; } @@ -924,7 +925,7 @@ static void gs_flush_chars(struct tty_struct *tty) struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_flush_chars: NULL port pointer\n"); + pr_err("gs_flush_chars: NULL port pointer\n"); return; } @@ -933,14 +934,13 @@ static void gs_flush_chars(struct tty_struct *tty) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR - "gs_flush_chars: (%d,%p) port is not connected\n", + pr_err("gs_flush_chars: (%d,%p) port is not connected\n", port->port_num, tty); goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n", + pr_err("gs_flush_chars: (%d,%p) port is closed\n", port->port_num, tty); goto exit; } @@ -1038,7 +1038,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_ioctl: NULL port pointer\n"); + pr_err("gs_ioctl: NULL port pointer\n"); return -EIO; } @@ -1076,7 +1076,7 @@ static int gs_send(struct gs_dev *dev) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_send: NULL device pointer\n"); + pr_err("gs_send: NULL device pointer\n"); return -ENODEV; } @@ -1103,7 +1103,7 @@ static int gs_send(struct gs_dev *dev) req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR + pr_err( "gs_send: cannot queue read request, ret=%d\n", ret); spin_lock_irqsave(&dev->dev_lock, flags); @@ -1144,9 +1144,7 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size) port = dev->dev_port[0]; if (port == NULL) { - printk(KERN_ERR - "gs_send_packet: port=%d, NULL port pointer\n", - 0); + pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0); return -EIO; } @@ -1193,7 +1191,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) port = dev->dev_port[0]; if (port == NULL) { - printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n", + pr_err("gs_recv_packet: port=%d, NULL port pointer\n", port->port_num); return -EIO; } @@ -1201,7 +1199,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) spin_lock(&port->port_lock); if (port->port_open_count == 0) { - printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n", + pr_err("gs_recv_packet: port=%d, port is closed\n", port->port_num); ret = -EIO; goto exit; @@ -1211,14 +1209,14 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) tty = port->port_tty; if (tty == NULL) { - printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n", + pr_err("gs_recv_packet: port=%d, NULL tty pointer\n", port->port_num); ret = -EIO; goto exit; } if (port->port_tty->magic != TTY_MAGIC) { - printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n", + pr_err("gs_recv_packet: port=%d, bad tty magic\n", port->port_num); ret = -EIO; goto exit; @@ -1245,7 +1243,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) struct gs_dev *dev = ep->driver_data; if (dev == NULL) { - printk(KERN_ERR "gs_read_complete: NULL device pointer\n"); + pr_err("gs_read_complete: NULL device pointer\n"); return; } @@ -1256,7 +1254,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) requeue: req->length = ep->maxpacket; if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR + pr_err( "gs_read_complete: cannot queue read request, ret=%d\n", ret); } @@ -1270,7 +1268,7 @@ requeue: default: /* unexpected */ - printk(KERN_ERR + pr_err( "gs_read_complete: unexpected status error, status=%d\n", req->status); goto requeue; @@ -1287,7 +1285,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) struct gs_req_entry *gs_req = req->context; if (dev == NULL) { - printk(KERN_ERR "gs_write_complete: NULL device pointer\n"); + pr_err("gs_write_complete: NULL device pointer\n"); return; } @@ -1296,8 +1294,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) /* normal completion */ requeue: if (gs_req == NULL) { - printk(KERN_ERR - "gs_write_complete: NULL request pointer\n"); + pr_err("gs_write_complete: NULL request pointer\n"); return; } @@ -1316,7 +1313,7 @@ requeue: break; default: - printk(KERN_ERR + pr_err( "gs_write_complete: unexpected status error, status=%d\n", req->status); goto requeue; @@ -1351,7 +1348,7 @@ static int __init gs_bind(struct usb_gadget *gadget) gs_device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); else { - printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", + pr_warning("gs_bind: controller '%s' not recognized\n", gadget->name); /* unrecognized, but safe unless bulk is REALLY quirky */ gs_device_desc.bcdDevice = @@ -1375,7 +1372,7 @@ static int __init gs_bind(struct usb_gadget *gadget) if (use_acm) { ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); if (!ep) { - printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); + pr_err("gs_bind: cannot run ACM on %s\n", gadget->name); goto autoconf_fail; } gs_device_desc.idProduct = __constant_cpu_to_le16( @@ -1425,7 +1422,7 @@ static int __init gs_bind(struct usb_gadget *gadget) set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { - printk(KERN_ERR "gs_bind: cannot allocate ports\n"); + pr_err("gs_bind: cannot allocate ports\n"); gs_unbind(gadget); return ret; } @@ -1441,13 +1438,13 @@ static int __init gs_bind(struct usb_gadget *gadget) gadget->ep0->driver_data = dev; - printk(KERN_INFO "gs_bind: %s %s bound\n", + pr_info("gs_bind: %s %s bound\n", GS_LONG_NAME, GS_VERSION_STR); return 0; autoconf_fail: - printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); + pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name); return -ENODEV; } @@ -1480,7 +1477,7 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) set_gadget_data(gadget, NULL); } - printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME, + pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME, GS_VERSION_STR); } @@ -1513,7 +1510,8 @@ static int gs_setup(struct usb_gadget *gadget, break; default: - printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", + pr_err("gs_setup: unknown request, type=%02x, request=%02x, " + "value=%04x, index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; @@ -1526,7 +1524,7 @@ static int gs_setup(struct usb_gadget *gadget, && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { - printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n", + pr_err("gs_setup: cannot queue response, ret=%d\n", ret); req->status = 0; gs_setup_complete(gadget->ep0, req); @@ -1656,7 +1654,8 @@ set_interface_done: break; default: - printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", + pr_err("gs_setup: unknown standard request, type=%02x, " + "request=%02x, value=%04x, index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; @@ -1682,7 +1681,7 @@ static int gs_setup_class(struct usb_gadget *gadget, * handler copy that data to port->port_line_coding (iff * it's valid) and maybe pass it on. Until then, fail. */ - printk(KERN_WARNING "gs_setup: set_line_coding " + pr_warning("gs_setup: set_line_coding " "unuspported\n"); break; @@ -1702,12 +1701,12 @@ static int gs_setup_class(struct usb_gadget *gadget, * handler use that to set the state (iff it's valid) and * maybe pass it on. Until then, fail. */ - printk(KERN_WARNING "gs_setup: set_control_line_state " + pr_warning("gs_setup: set_control_line_state " "unuspported\n"); break; default: - printk(KERN_ERR "gs_setup: unknown class request, " + pr_err("gs_setup: unknown class request, " "type=%02x, request=%02x, value=%04x, " "index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -1724,7 +1723,8 @@ static int gs_setup_class(struct usb_gadget *gadget, static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) { - printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n", + pr_err("gs_setup_complete: status error, status=%d, " + "actual=%d, length=%d\n", req->status, req->actual, req->length); } } @@ -1751,11 +1751,11 @@ static void gs_disconnect(struct usb_gadget *gadget) /* re-allocate ports for the next connection */ if (gs_alloc_ports(dev, GFP_ATOMIC) != 0) - printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n"); + pr_err("gs_disconnect: cannot re-allocate ports\n"); spin_unlock_irqrestore(&dev->dev_lock, flags); - printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME); + pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME); } /* @@ -1778,7 +1778,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_set_config: NULL device pointer\n"); + pr_err("gs_set_config: NULL device pointer\n"); return 0; } @@ -1823,7 +1823,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_notify_ep = ep; dev->dev_notify_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable NOTIFY " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1839,7 +1840,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_in_ep = ep; dev->dev_in_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable IN " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1855,7 +1857,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_out_ep = ep; dev->dev_out_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable OUT " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1865,7 +1868,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) { - printk(KERN_ERR "gs_set_config: cannot find endpoints\n"); + pr_err("gs_set_config: cannot find endpoints\n"); ret = -ENODEV; goto exit_reset_config; } @@ -1876,11 +1879,12 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) { req->complete = gs_read_complete; if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n", - ret); + pr_err("gs_set_config: cannot queue read " + "request, ret=%d\n", ret); } } else { - printk(KERN_ERR "gs_set_config: cannot allocate read requests\n"); + pr_err("gs_set_config: cannot allocate " + "read requests\n"); ret = -ENOMEM; goto exit_reset_config; } @@ -1893,13 +1897,14 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) req_entry->re_req->complete = gs_write_complete; list_add(&req_entry->re_entry, &dev->dev_req_list); } else { - printk(KERN_ERR "gs_set_config: cannot allocate write requests\n"); + pr_err("gs_set_config: cannot allocate " + "write requests\n"); ret = -ENOMEM; goto exit_reset_config; } } - printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n", + pr_info("gs_set_config: %s configured, %s speed %s config\n", GS_LONG_NAME, gadget->speed == USB_SPEED_HIGH ? "high" : "full", config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM"); @@ -1926,7 +1931,7 @@ static void gs_reset_config(struct gs_dev *dev) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_reset_config: NULL device pointer\n"); + pr_err("gs_reset_config: NULL device pointer\n"); return; } diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcde5d9c87d..d3d4f4048e6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1115,7 +1115,7 @@ zero_bind (struct usb_gadget *gadget) ep = usb_ep_autoconfig (gadget, &fs_source_desc); if (!ep) { autoconf_fail: - printk (KERN_ERR "%s: can't autoconfigure on %s\n", + pr_err("%s: can't autoconfigure on %s\n", shortname, gadget->name); return -ENODEV; } @@ -1139,7 +1139,7 @@ autoconf_fail: * things like configuration and altsetting numbering * can need hardware-specific attention though. */ - printk (KERN_WARNING "%s: controller '%s' not recognized\n", + pr_warning("%s: controller '%s' not recognized\n", shortname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999); } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 49a91c5ee51..d97b16b52ef 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -29,15 +29,6 @@ config USB_EHCI_HCD To compile this driver as a module, choose M here: the module will be called ehci-hcd. -config USB_EHCI_SPLIT_ISO - bool "Full speed ISO transactions (EXPERIMENTAL)" - depends on USB_EHCI_HCD && EXPERIMENTAL - default n - ---help--- - This code is new and hasn't been used with many different - EHCI or USB 2.0 transaction translator implementations. - It should work for ISO-OUT transfers, like audio. - config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators (EXPERIMENTAL)" depends on USB_EHCI_HCD && EXPERIMENTAL @@ -69,21 +60,30 @@ config USB_EHCI_TT_NEWSCHED config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX) + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX) default y config USB_EHCI_BIG_ENDIAN_DESC bool - depends on USB_EHCI_HCD && 440EPX + depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX) default y config USB_EHCI_FSL bool + depends on USB_EHCI_HCD select USB_EHCI_ROOT_HUB_TT default y if MPC834x || PPC_MPC831x ---help--- Variation of ARC USB block used in some Freescale chips. +config USB_EHCI_HCD_PPC_OF + bool "EHCI support for PPC USB controller on OF platform bus" + depends on USB_EHCI_HCD && PPC_OF + default y + ---help--- + Enables support for the USB controller present on the PowerPC + OpenFirmware platform bus. + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 766ef68a0b4..da7532d38bf 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -222,6 +222,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index c9cc4413198..64ebfc5548a 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -323,7 +323,43 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } #else -/* troubleshooting help: expose state in sysfs */ +/* troubleshooting help: expose state in debugfs */ + +static int debug_async_open(struct inode *, struct file *); +static int debug_periodic_open(struct inode *, struct file *); +static int debug_registers_open(struct inode *, struct file *); +static int debug_async_open(struct inode *, struct file *); +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, +}; + +static struct dentry *ehci_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct usb_bus *bus; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *page; +}; #define speed_char(info1) ({ char tmp; \ switch (info1 & (3 << 12)) { \ @@ -441,10 +477,8 @@ done: *nextp = next; } -static ssize_t -show_async (struct class_device *class_dev, char *buf) +static ssize_t fill_async_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -452,14 +486,13 @@ show_async (struct class_device *class_dev, char *buf) char *next; struct ehci_qh *qh; - *buf = 0; - - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; + *next = 0; + /* dumps a snapshot of the async schedule. * usually empty except for long-term bulk reads, or head. * one QH per line, and TDs we know about @@ -477,16 +510,12 @@ show_async (struct class_device *class_dev, char *buf) } spin_unlock_irqrestore (&ehci->lock, flags); - return strlen (buf); + return strlen(buf->page); } -static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL); #define DBG_SCHED_LIMIT 64 - -static ssize_t -show_periodic (struct class_device *class_dev, char *buf) +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -500,10 +529,9 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size); @@ -623,14 +651,10 @@ show_periodic (struct class_device *class_dev, char *buf) return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); - #undef DBG_SCHED_LIMIT -static ssize_t -show_registers (struct class_device *class_dev, char *buf) +static ssize_t fill_registers_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -639,15 +663,14 @@ show_registers (struct class_device *class_dev, char *buf) static char fmt [] = "%*s\n"; static char label [] = ""; - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; spin_lock_irqsave (&ehci->lock, flags); - if (bus->controller->power.power_state.event) { + if (buf->bus->controller->power.power_state.event) { size = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" @@ -763,9 +786,7 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p%s\n", - ehci->reclaim, - ehci->reclaim_ready ? " ready" : ""); + temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim); size -= temp; next += temp; } @@ -789,26 +810,150 @@ done: return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); -static inline void create_debug_files (struct ehci_hcd *ehci) +static struct debug_buffer *alloc_buffer(struct usb_bus *bus, + ssize_t (*fill_func)(struct debug_buffer *)) { - struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; - int retval; + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); - retval = class_device_create_file(cldev, &class_device_attr_async); - retval = class_device_create_file(cldev, &class_device_attr_periodic); - retval = class_device_create_file(cldev, &class_device_attr_registers); + if (buf) { + buf->bus = bus; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + } + + return buf; } -static inline void remove_debug_files (struct ehci_hcd *ehci) +static int fill_buffer(struct debug_buffer *buf) { - struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; + int ret = 0; + + if (!buf->page) + buf->page = (char *)get_zeroed_page(GFP_KERNEL); + + if (!buf->page) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); - class_device_remove_file(cldev, &class_device_attr_async); - class_device_remove_file(cldev, &class_device_attr_periodic); - class_device_remove_file(cldev, &class_device_attr_registers); + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; } -#endif /* STUB_DEBUG_FILES */ +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->page, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + if (buf) { + if (buf->page) + free_page((unsigned long)buf->page); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_periodic_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static inline void create_debug_files (struct ehci_hcd *ehci) +{ + struct usb_bus *bus = &ehci_to_hcd(ehci)->self; + + ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root); + if (!ehci->debug_dir) + goto dir_error; + + ehci->debug_async = debugfs_create_file("async", S_IRUGO, + ehci->debug_dir, bus, + &debug_async_fops); + if (!ehci->debug_async) + goto async_error; + + ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, + ehci->debug_dir, bus, + &debug_periodic_fops); + if (!ehci->debug_periodic) + goto periodic_error; + + ehci->debug_registers = debugfs_create_file("registers", S_IRUGO, + ehci->debug_dir, bus, + &debug_registers_fops); + if (!ehci->debug_registers) + goto registers_error; + return; + +registers_error: + debugfs_remove(ehci->debug_periodic); +periodic_error: + debugfs_remove(ehci->debug_async); +async_error: + debugfs_remove(ehci->debug_dir); +dir_error: + ehci->debug_periodic = NULL; + ehci->debug_async = NULL; + ehci->debug_dir = NULL; +} + +static inline void remove_debug_files (struct ehci_hcd *ehci) +{ + debugfs_remove(ehci->debug_registers); + debugfs_remove(ehci->debug_periodic); + debugfs_remove(ehci->debug_async); + debugfs_remove(ehci->debug_dir); +} + +#endif /* STUB_DEBUG_FILES */ diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 430821cb95c..adb0defa163 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -25,7 +25,7 @@ #include "ehci-fsl.h" -/* FIXME: Power Managment is un-ported so temporarily disable it */ +/* FIXME: Power Management is un-ported so temporarily disable it */ #undef CONFIG_PM /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ @@ -323,6 +323,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; static int ehci_fsl_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5f2d74ed5ad..4caa6a8b9a3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -33,6 +33,7 @@ #include <linux/usb.h> #include <linux/moduleparam.h> #include <linux/dma-mapping.h> +#include <linux/debugfs.h> #include "../core/hcd.h" @@ -109,7 +110,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -266,6 +267,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ +static void end_unlink_async(struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -275,25 +277,41 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ -static void ehci_watchdog (unsigned long param) +static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; + u32 status, cmd; spin_lock_irqsave (&ehci->lock, flags); + WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen with a vt8235 */ + status = ehci_readl(ehci, &ehci->regs->status); + cmd = ehci_readl(ehci, &ehci->regs->command); + ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); + + /* lost IAA irqs wedge things badly; seen first with a vt8235 */ if (ehci->reclaim) { - u32 status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); - ehci->reclaim_ready = 1; } + ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command); + end_unlink_async(ehci); } - /* stop async processing after it's idled a bit */ + spin_unlock_irqrestore(&ehci->lock, flags); +} + +static void ehci_watchdog(unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + unsigned long flags; + + spin_lock_irqsave(&ehci->lock, flags); + + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -363,8 +381,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -399,6 +415,7 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -447,6 +464,10 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; + init_timer(&ehci->iaa_watchdog); + ehci->iaa_watchdog.function = ehci_iaa_watchdog; + ehci->iaa_watchdog.data = (unsigned long) ehci; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -463,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; - ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -654,8 +674,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - ehci->reclaim_ready = 1; - bh = 1; + end_unlink_async(ehci); } /* remote wakeup [4.3.1] */ @@ -761,10 +780,16 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { + /* failfast */ + if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) + end_unlink_async(ehci); + + /* if it's not linked then there's nothing to do */ + if (qh->qh_state != QH_STATE_LINKED) + ; + + /* defer till later if busy */ + else if (ehci->reclaim) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -774,12 +799,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* bypass IAA if the hc can't care */ - } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) - end_unlink_async (ehci); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) + /* start IAA cycle */ + } else start_unlink_async (ehci, qh); } @@ -806,7 +827,19 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - unlink_async (ehci, qh); + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + unlink_async(ehci, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + WARN_ON(1); + break; + } break; case PIPE_INTERRUPT: @@ -829,16 +862,16 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) && HC_IS_RUNNING (hcd->state)) { - int status; + int schedule_status; - status = qh_schedule (ehci, qh); + schedule_status = qh_schedule (ehci, qh); spin_unlock_irqrestore (&ehci->lock, flags); - if (status != 0) { + if (schedule_status != 0) { // shouldn't happen often, but ... // FIXME kill those tds' urbs err ("can't reschedule qh %p, err %d", - qh, status); + qh, schedule_status); } return status; } @@ -898,6 +931,7 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); @@ -959,11 +993,26 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver #endif -#ifdef CONFIG_440EPX +#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE) #include "ehci-ppc-soc.c" #define PLATFORM_DRIVER ehci_ppc_soc_driver #endif +#ifdef CONFIG_USB_EHCI_HCD_PPC_OF +#include "ehci-ppc-of.c" +#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver +#endif + +#ifdef CONFIG_ARCH_ORION +#include "ehci-orion.c" +#define PLATFORM_DRIVER ehci_orion_driver +#endif + +#ifdef CONFIG_ARCH_IXP4XX +#include "ehci-ixp4xx.c" +#define PLATFORM_DRIVER ixp4xx_ehci_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ehci-hcd" @@ -978,41 +1027,66 @@ static int __init ehci_hcd_init(void) sizeof(struct ehci_qh), sizeof(struct ehci_qtd), sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); +#ifdef DEBUG + ehci_debug_root = debugfs_create_dir("ehci", NULL); + if (!ehci_debug_root) + return -ENOENT; +#endif + #ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) - return retval; + goto clean0; #endif #ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) { -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif - return retval; - } + if (retval < 0) + goto clean1; #endif #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) { -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); + if (retval < 0) + goto clean2; +#endif + +#ifdef OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + if (retval < 0) + goto clean3; +#endif + return retval; + +#ifdef OF_PLATFORM_DRIVER + /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ +clean3: +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +clean2: #endif #ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); + pci_unregister_driver(&PCI_DRIVER); +clean1: #endif - return retval; - } +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +clean0: +#endif +#ifdef DEBUG + debugfs_remove(ehci_debug_root); + ehci_debug_root = NULL; #endif - return retval; } module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif @@ -1022,6 +1096,9 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif +#ifdef DEBUG + debugfs_remove(ehci_debug_root); +#endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 735db4aec83..40e8240b785 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -123,6 +123,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) if (time_before (jiffies, ehci->next_statechange)) msleep(5); + del_timer_sync(&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); @@ -134,7 +136,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); /* Unlike other USB host controller types, EHCI doesn't have @@ -170,8 +172,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } } + /* Apparently some devices need a >= 1-uframe delay here */ + if (ehci->bus_suspended) + udelay(150); + /* turn off now-idle HC */ - del_timer_sync (&ehci->watchdog); ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; @@ -291,14 +296,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ /* Display the ports dedicated to the companion controller */ -static ssize_t show_companion(struct class_device *class_dev, char *buf) +static ssize_t show_companion(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ehci_hcd *ehci; int nports, index, n; int count = PAGE_SIZE; char *ptr = buf; - ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); nports = HCS_N_PORTS(ehci->hcs_params); for (index = 0; index < nports; ++index) { @@ -312,40 +319,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf) } /* - * Dedicate or undedicate a port to the companion controller. - * Syntax is "[-]portnum", where a leading '-' sign means - * return control of the port to the EHCI controller. + * Sets the owner of a port */ -static ssize_t store_companion(struct class_device *class_dev, - const char *buf, size_t count) +static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) { - struct ehci_hcd *ehci; - int portnum, new_owner, try; u32 __iomem *status_reg; u32 port_status; + int try; - ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); - new_owner = PORT_OWNER; /* Owned by companion */ - if (sscanf(buf, "%d", &portnum) != 1) - return -EINVAL; - if (portnum < 0) { - portnum = - portnum; - new_owner = 0; /* Owned by EHCI */ - } - if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) - return -ENOENT; - status_reg = &ehci->regs->port_status[--portnum]; - if (new_owner) - set_bit(portnum, &ehci->companion_ports); - else - clear_bit(portnum, &ehci->companion_ports); + status_reg = &ehci->regs->port_status[portnum]; /* * The controller won't set the OWNER bit if the port is * enabled, so this loop will sometimes require at least two * iterations: one to disable the port and one to set OWNER. */ - for (try = 4; try > 0; --try) { spin_lock_irq(&ehci->lock); port_status = ehci_readl(ehci, status_reg); @@ -362,9 +350,39 @@ static ssize_t store_companion(struct class_device *class_dev, if (try > 1) msleep(5); } +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + portnum--; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + set_owner(ehci, portnum, new_owner); return count; } -static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); +static DEVICE_ATTR(companion, 0644, show_companion, store_companion); static inline void create_companion_file(struct ehci_hcd *ehci) { @@ -372,16 +390,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci) /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, - &class_device_attr_companion); + i = device_create_file(ehci_to_hcd(ehci)->self.dev, + &dev_attr_companion); } static inline void remove_companion_file(struct ehci_hcd *ehci) { /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, - &class_device_attr_companion); + device_remove_file(ehci_to_hcd(ehci)->self.dev, + &dev_attr_companion); } @@ -393,10 +411,8 @@ static int check_reset_complete ( u32 __iomem *status_reg, int port_status ) { - if (!(port_status & PORT_CONNECT)) { - ehci->reset_done [index] = 0; + if (!(port_status & PORT_CONNECT)) return port_status; - } /* if reset finished and it's still not enabled -- handoff */ if (!(port_status & PORT_PE)) { @@ -475,8 +491,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) * controller by the user. */ - if (!(temp & PORT_CONNECT)) - ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 && time_after_eq(jiffies, @@ -864,3 +878,13 @@ error: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } + +static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + if (ehci_is_TDI(ehci)) + return; + set_owner(ehci, --portnum, PORT_OWNER); +} + diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c new file mode 100644 index 00000000000..3041d8f055f --- /dev/null +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -0,0 +1,152 @@ +/* + * IXP4XX EHCI Host Controller Driver + * + * Author: Vladimir Barinov <vbarinov@ru.mvista.com> + * + * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com> + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/platform_device.h> + +static int ixp4xx_ehci_init(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval = 0; + + ehci->big_endian_desc = 1; + ehci->big_endian_mmio = 1; + + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ehci->is_tdi_rh_tt = 1; + ehci_reset(ehci); + + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci_port_power(ehci, 0); + + return retval; +} + +static const struct hc_driver ixp4xx_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "IXP4XX EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = ixp4xx_ehci_init, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .get_frame_number = ehci_get_frame, + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#if defined(CONFIG_PM) + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +static int ixp4xx_ehci_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + const struct hc_driver *driver = &ixp4xx_ehci_hc_driver; + struct resource *res; + int irq; + int retval; + + if (usb_disabled()) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + return -ENODEV; + } + irq = res->start; + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto fail_create_hcd; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + pdev->dev.bus_id); + retval = -ENODEV; + goto fail_request_resource; + } + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + driver->description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + retval = -EBUSY; + goto fail_request_resource; + } + + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (hcd->regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail_ioremap; + } + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) + goto fail_add_hcd; + + return retval; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +fail_request_resource: + usb_put_hcd(hcd); +fail_create_hcd: + dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval); + return retval; +} + +static int ixp4xx_ehci_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + return 0; +} + +MODULE_ALIAS("ixp4xx-ehci"); + +static struct platform_driver ixp4xx_ehci_driver = { + .probe = ixp4xx_ehci_probe, + .remove = ixp4xx_ehci_remove, + .driver = { + .name = "ixp4xx-ehci", + .bus = &platform_bus_type + }, +}; diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c new file mode 100644 index 00000000000..e129981f139 --- /dev/null +++ b/drivers/usb/host/ehci-orion.c @@ -0,0 +1,272 @@ +/* + * drivers/usb/host/ehci-orion.c + * + * Tzachi Perelstein <tzachi@marvell.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <asm/arch/orion.h> + +#define rdl(off) __raw_readl(hcd->regs + (off)) +#define wrl(off, val) __raw_writel((val), hcd->regs + (off)) + +#define USB_CAUSE 0x310 +#define USB_MASK 0x314 +#define USB_CMD 0x140 +#define USB_MODE 0x1a8 +#define USB_IPG 0x360 +#define USB_PHY_PWR_CTRL 0x400 +#define USB_PHY_TX_CTRL 0x420 +#define USB_PHY_RX_CTRL 0x430 +#define USB_PHY_IVREF_CTRL 0x440 +#define USB_PHY_TST_GRP_CTRL 0x450 + +/* + * Implement Orion USB controller specification guidelines + */ +static void orion_usb_setup(struct usb_hcd *hcd) +{ + /* + * Clear interrupt cause and mask + */ + wrl(USB_CAUSE, 0); + wrl(USB_MASK, 0); + + /* + * Reset controller + */ + wrl(USB_CMD, rdl(USB_CMD) | 0x2); + while (rdl(USB_CMD) & 0x2); + + /* + * GL# USB-10: Set IPG for non start of frame packets + * Bits[14:8]=0xc + */ + wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00); + + /* + * GL# USB-9: USB 2.0 Power Control + * BG_VSEL[7:6]=0x1 + */ + wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40); + + /* + * GL# USB-1: USB PHY Tx Control - force calibration to '8' + * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8 + */ + wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040); + + /* + * GL# USB-3 GL# USB-9: USB PHY Rx Control + * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0, + * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1 + */ + wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010); + + /* + * GL# USB-3 GL# USB-9: USB PHY IVREF Control + * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0 + */ + wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32); + + /* + * GL# USB-3 GL# USB-9: USB PHY Test Group Control + * REG_FIFO_SQ_RST[15]=0 + */ + wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000); + + /* + * Stop and reset controller + */ + wrl(USB_CMD, rdl(USB_CMD) & ~0x1); + wrl(USB_CMD, rdl(USB_CMD) | 0x2); + while (rdl(USB_CMD) & 0x2); + + /* + * GL# USB-5 Streaming disable REG_USB_MODE[4]=1 + * TBD: This need to be done after each reset! + * GL# USB-4 Setup USB Host mode + */ + wrl(USB_MODE, 0x13); +} + +static int ehci_orion_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* + * data structure init + */ + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci_reset(ehci); + ehci_port_power(ehci, 0); + + return retval; +} + +static const struct hc_driver ehci_orion_hc_driver = { + .description = hcd_name, + .product_desc = "Marvell Orion EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_orion_setup, + .start = ehci_run, +#ifdef CONFIG_PM + .suspend = ehci_bus_suspend, + .resume = ehci_bus_resume, +#endif + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +static int __init ehci_orion_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + void __iomem *regs; + int irq, err; + + if (usb_disabled()) + return -ENODEV; + + pr_debug("Initializing Orion-SoC USB Host Controller\n"); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + err = -ENODEV; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + pdev->dev.bus_id); + err = -ENODEV; + goto err1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + ehci_orion_hc_driver.description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + err = -EBUSY; + goto err1; + } + + regs = ioremap(res->start, res->end - res->start + 1); + if (regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + err = -EFAULT; + goto err2; + } + + hcd = usb_create_hcd(&ehci_orion_hc_driver, + &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + err = -ENOMEM; + goto err3; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + hcd->regs = regs; + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + ehci->is_tdi_rh_tt = 1; + ehci->sbrn = 0x20; + + /* + * setup Orion USB controller + */ + orion_usb_setup(hcd); + + err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED); + if (err) + goto err4; + + return 0; + +err4: + usb_put_hcd(hcd); +err3: + iounmap(regs); +err2: + release_mem_region(res->start, res->end - res->start + 1); +err1: + dev_err(&pdev->dev, "init %s fail, %d\n", + pdev->dev.bus_id, err); + + return err; +} + +static int __exit ehci_orion_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + return 0; +} + +MODULE_ALIAS("platform:orion-ehci"); + +static struct platform_driver ehci_orion_driver = { + .probe = ehci_orion_drv_probe, + .remove = __exit_p(ehci_orion_drv_remove), + .shutdown = usb_hcd_platform_shutdown, + .driver.name = "orion-ehci", +}; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index ad0d4965f2f..3ba01664f82 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); spin_unlock_irq(&ehci->lock); @@ -364,6 +364,7 @@ static const struct hc_driver ehci_pci_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c new file mode 100644 index 00000000000..ee305b1f99f --- /dev/null +++ b/drivers/usb/host/ehci-ppc-of.c @@ -0,0 +1,238 @@ +/* + * EHCI HCD (Host Controller Driver) for USB. + * + * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus + * Tested on AMCC PPC 440EPx + * + * Valentine Barshak <vbarshak@ru.mvista.com> + * + * Based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de> + * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com> + * + * This file is licenced under the GPL. + */ + +#include <linux/signal.h> + +#include <linux/of.h> +#include <linux/of_platform.h> + +/* called during probe() after chip reset completes */ +static int ehci_ppc_of_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci->sbrn = 0x20; + return ehci_reset(ehci); +} + + +static const struct hc_driver ehci_ppc_of_hc_driver = { + .description = hcd_name, + .product_desc = "OF EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_ppc_of_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + + +/* + * 440EPx Errata USBH_3 + * Fix: Enable Break Memory Transfer (BMT) in INSNREG3 + */ +#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0) +static int __devinit +ppc44x_enable_bmt(struct device_node *dn) +{ + __iomem u32 *insreg_virt; + + insreg_virt = of_iomap(dn, 1); + if (!insreg_virt) + return -EINVAL; + + out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT); + + iounmap(insreg_virt); + return 0; +} + + +static int __devinit +ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dn = op->node; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource res; + int irq; + int rv; + + if (usb_disabled()) + return -ENODEV; + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + + rv = of_address_to_resource(dn, 0, &res); + if (rv) + return rv; + + hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = res.end - res.start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); + rv = -EBUSY; + goto err_rmr; + } + + irq = irq_of_parse_and_map(dn, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); + rv = -EBUSY; + goto err_irq; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + printk(KERN_ERR __FILE__ ": ioremap failed\n"); + rv = -ENOMEM; + goto err_ioremap; + } + + ehci = hcd_to_ehci(hcd); + + if (of_get_property(dn, "big-endian", NULL)) { + ehci->big_endian_mmio = 1; + ehci->big_endian_desc = 1; + } + if (of_get_property(dn, "big-endian-regs", NULL)) + ehci->big_endian_mmio = 1; + if (of_get_property(dn, "big-endian-desc", NULL)) + ehci->big_endian_desc = 1; + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) { + rv = ppc44x_enable_bmt(dn); + ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n", + rv ? "NOT ": ""); + } + + rv = usb_add_hcd(hcd, irq, 0); + if (rv == 0) + return 0; + + iounmap(hcd->regs); +err_ioremap: + irq_dispose_mapping(irq); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return rv; +} + + +static int ehci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + irq_dispose_mapping(hcd->irq); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + + +static int ehci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); + + return 0; +} + + +static struct of_device_id ehci_hcd_ppc_of_match[] = { + { + .compatible = "usb-ehci", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); + + +static struct of_platform_driver ehci_hcd_ppc_of_driver = { + .name = "ppc-of-ehci", + .match_table = ehci_hcd_ppc_of_match, + .probe = ehci_hcd_ppc_of_probe, + .remove = ehci_hcd_ppc_of_remove, + .shutdown = ehci_hcd_ppc_of_shutdown, + .driver = { + .name = "ppc-of-ehci", + .owner = THIS_MODULE, + }, +}; diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 452d4b1bc85..a3249078c80 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -162,6 +162,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 03a6b2f4e6e..bbda58eb881 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -72,6 +72,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, #endif + .relinquish_port = ehci_relinquish_port, }; static int ps3_ehci_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b10f39c047e..776a97f3391 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -198,7 +198,8 @@ static int qtd_copy_status ( /* if async CSPLIT failed, try cleaning out the TT buffer */ if (status != -EPIPE - && urb->dev->tt && !usb_pipeint (urb->pipe) + && urb->dev->tt + && !usb_pipeint(urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_TDI(ehci) @@ -211,6 +212,9 @@ static int qtd_copy_status ( urb->dev->ttport, urb->dev->devnum, usb_pipeendpoint (urb->pipe), token); #endif /* DEBUG */ + /* REVISIT ARC-derived cores don't clear the root + * hub TT buffer in this way... + */ usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } @@ -638,6 +642,7 @@ qh_make ( u32 info1 = 0, info2 = 0; int is_input, type; int maxp = 0; + struct usb_tt *tt = urb->dev->tt; if (!qh) return qh; @@ -661,8 +666,9 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0, - hb_mult (maxp) * max_packet (maxp))); + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + is_input, 0, + hb_mult(maxp) * max_packet(maxp))); qh->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { @@ -680,7 +686,6 @@ qh_make ( goto done; } } else { - struct usb_tt *tt = urb->dev->tt; int think_time; /* gap is f(FS/LS transfer times) */ @@ -736,10 +741,8 @@ qh_make ( /* set the address of the TT; for TDI's integrated * root hub tt, leave it zeroed. */ - if (!ehci_is_TDI(ehci) - || urb->dev->tt->hub != - ehci_to_hcd(ehci)->self.root_hub) - info2 |= urb->dev->tt->hub->devnum << 16; + if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub) + info2 |= tt->hub->devnum << 16; /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ @@ -973,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - timer_action_done (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_done(ehci); // qh->hw_next = cpu_to_hc32(qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -983,7 +986,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; - ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1059,11 +1061,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - ehci->reclaim_ready = 0; cmd |= CMD_IAAD; ehci_writel(ehci, cmd, &ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command); - timer_action (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_start(ehci); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 80d99bce2b3..8a8e08a51ba 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -119,7 +119,8 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: - usecs += q->itd->usecs [uframe]; + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; @@ -211,7 +212,7 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) * low/fullspeed transfer can "carry over" from one uframe to the next, * since the TT just performs downstream transfers in sequence. * - * For example two seperate 100 usec transfers can start in the same uframe, + * For example two separate 100 usec transfers can start in the same uframe, * and the second one would "carry over" 75 usecs into the next uframe. */ static void @@ -1536,7 +1537,6 @@ itd_link_urb ( uframe = next_uframe & 0x07; frame = next_uframe >> 3; - itd->usecs [uframe] = stream->usecs; itd_patch(ehci, itd, iso_sched, packet, uframe); next_uframe += stream->interval; @@ -1565,6 +1565,16 @@ itd_link_urb ( #define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) +/* Process and recycle a completed ITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ static unsigned itd_complete ( struct ehci_hcd *ehci, @@ -1577,6 +1587,7 @@ itd_complete ( int urb_index = -1; struct ehci_iso_stream *stream = itd->stream; struct usb_device *dev; + unsigned retval = false; /* for each uframe with a packet */ for (uframe = 0; uframe < 8; uframe++) { @@ -1610,30 +1621,21 @@ itd_complete ( } } - usb_put_urb (urb); - itd->urb = NULL; - itd->stream = NULL; - list_move (&itd->itd_list, &stream->free_list); - iso_stream_put (ehci, stream); - /* handle completion now? */ if (likely ((urb_index + 1) != urb->number_of_packets)) - return 0; + goto done; /* ASSERT: it's really the last itd for this urb list_for_each_entry (itd, &stream->td_list, itd_list) BUG_ON (itd->urb == urb); */ - /* give urb back to the driver ... can be out-of-order */ + /* give urb back to the driver; completion often (re)submits */ dev = urb->dev; ehci_urb_done(ehci, urb, 0); + retval = true; urb = NULL; - - /* defer stopping schedule; completion can submit */ ehci->periodic_sched--; - if (unlikely (!ehci->periodic_sched)) - (void) disable_periodic (ehci); ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (unlikely (list_empty (&stream->td_list))) { @@ -1645,8 +1647,15 @@ itd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); + /* OK to recycle this ITD now that its completion callback ran. */ +done: + usb_put_urb(urb); + itd->urb = NULL; + itd->stream = NULL; + list_move(&itd->itd_list, &stream->free_list); + iso_stream_put(ehci, stream); - return 1; + return retval; } /*-------------------------------------------------------------------------*/ @@ -1712,8 +1721,6 @@ done: return status; } -#ifdef CONFIG_USB_EHCI_SPLIT_ISO - /*-------------------------------------------------------------------------*/ /* @@ -1950,6 +1957,16 @@ sitd_link_urb ( #define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ | SITD_STS_XACT | SITD_STS_MMF) +/* Process and recycle a completed SITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ static unsigned sitd_complete ( struct ehci_hcd *ehci, @@ -1961,6 +1978,7 @@ sitd_complete ( int urb_index = -1; struct ehci_iso_stream *stream = sitd->stream; struct usb_device *dev; + unsigned retval = false; urb_index = sitd->index; desc = &urb->iso_frame_desc [urb_index]; @@ -1981,32 +1999,23 @@ sitd_complete ( desc->status = 0; desc->actual_length = desc->length - SITD_LENGTH (t); } - - usb_put_urb (urb); - sitd->urb = NULL; - sitd->stream = NULL; - list_move (&sitd->sitd_list, &stream->free_list); stream->depth -= stream->interval << 3; - iso_stream_put (ehci, stream); /* handle completion now? */ if ((urb_index + 1) != urb->number_of_packets) - return 0; + goto done; /* ASSERT: it's really the last sitd for this urb list_for_each_entry (sitd, &stream->td_list, sitd_list) BUG_ON (sitd->urb == urb); */ - /* give urb back to the driver */ + /* give urb back to the driver; completion often (re)submits */ dev = urb->dev; ehci_urb_done(ehci, urb, 0); + retval = true; urb = NULL; - - /* defer stopping schedule; completion can submit */ ehci->periodic_sched--; - if (!ehci->periodic_sched) - (void) disable_periodic (ehci); ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (list_empty (&stream->td_list)) { @@ -2018,8 +2027,15 @@ sitd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); + /* OK to recycle this SITD now that its completion callback ran. */ +done: + usb_put_urb(urb); + sitd->urb = NULL; + sitd->stream = NULL; + list_move(&sitd->sitd_list, &stream->free_list); + iso_stream_put(ehci, stream); - return 1; + return retval; } @@ -2082,26 +2098,6 @@ done: return status; } -#else - -static inline int -sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags) -{ - ehci_dbg (ehci, "split iso support is disabled\n"); - return -ENOSYS; -} - -static inline unsigned -sitd_complete ( - struct ehci_hcd *ehci, - struct ehci_sitd *sitd -) { - ehci_err (ehci, "sitd_complete %p?\n", sitd); - return 0; -} - -#endif /* USB_EHCI_SPLIT_ISO */ - /*-------------------------------------------------------------------------*/ static void @@ -2127,17 +2123,9 @@ scan_periodic (struct ehci_hcd *ehci) for (;;) { union ehci_shadow q, *q_p; __hc32 type, *hw_p; - unsigned uframes; + unsigned incomplete = false; - /* don't scan past the live uframe */ frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { - /* safe to scan the whole frame at once */ - now_uframe |= 0x07; - uframes = 8; - } restart: /* scan each element in frame's queue for completions */ @@ -2175,12 +2163,15 @@ restart: q = q.fstn->fstn_next; break; case Q_TYPE_ITD: - /* skip itds for later in the frame */ + /* If this ITD is still active, leave it for + * later processing ... check the next entry. + */ rmb (); - for (uf = live ? uframes : 8; uf < 8; uf++) { + for (uf = 0; uf < 8 && live; uf++) { if (0 == (q.itd->hw_transaction [uf] & ITD_ACTIVE(ehci))) continue; + incomplete = true; q_p = &q.itd->itd_next; hw_p = &q.itd->hw_next; type = Q_NEXT_TYPE(ehci, @@ -2188,10 +2179,12 @@ restart: q = *q_p; break; } - if (uf != 8) + if (uf < 8 && live) break; - /* this one's ready ... HC won't cache the + /* Take finished ITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. HC won't cache the * pointer for much longer, if at all. */ *q_p = q.itd->itd_next; @@ -2202,8 +2195,12 @@ restart: q = *q_p; break; case Q_TYPE_SITD: + /* If this SITD is still active, leave it for + * later processing ... check the next entry. + */ if ((q.sitd->hw_results & SITD_ACTIVE(ehci)) && live) { + incomplete = true; q_p = &q.sitd->sitd_next; hw_p = &q.sitd->hw_next; type = Q_NEXT_TYPE(ehci, @@ -2211,6 +2208,11 @@ restart: q = *q_p; break; } + + /* Take finished SITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. + */ *q_p = q.sitd->sitd_next; *hw_p = q.sitd->hw_next; type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); @@ -2226,11 +2228,24 @@ restart: } /* assume completion callbacks modify the queue */ - if (unlikely (modified)) - goto restart; + if (unlikely (modified)) { + if (likely(ehci->periodic_sched > 0)) + goto restart; + /* maybe we can short-circuit this scan! */ + disable_periodic(ehci); + now_uframe = clock; + break; + } } - /* stop when we catch up to the HC */ + /* If we can tell we caught up to the hardware, stop now. + * We can't advance our scan without collecting the ISO + * transfers that are still pending in this frame. + */ + if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { + ehci->next_uframe = now_uframe; + break; + } // FIXME: this assumes we won't get lapped when // latencies climb; that should be rare, but... @@ -2243,7 +2258,8 @@ restart: if (now_uframe == clock) { unsigned now; - if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) + if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) + || ehci->periodic_sched == 0) break; ehci->next_uframe = now_uframe; now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 951d69fec51..bf92d209a1a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -74,7 +74,6 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -105,6 +104,7 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ + struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -127,6 +127,14 @@ struct ehci_hcd { /* one per controller */ #else # define COUNT(x) do {} while (0) #endif + + /* debug files */ +#ifdef DEBUG + struct dentry *debug_dir; + struct dentry *debug_async; + struct dentry *debug_periodic; + struct dentry *debug_registers; +#endif }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ @@ -140,9 +148,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } +static inline void +iaa_watchdog_start(struct ehci_hcd *ehci) +{ + WARN_ON(timer_pending(&ehci->iaa_watchdog)); + mod_timer(&ehci->iaa_watchdog, + jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); +} + +static inline void iaa_watchdog_done(struct ehci_hcd *ehci) +{ + del_timer(&ehci->iaa_watchdog); +} + enum ehci_timer_action { TIMER_IO_WATCHDOG, - TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -160,9 +180,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { - case TIMER_IAA_WATCHDOG: - t = EHCI_IAA_JIFFIES; - break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -179,8 +196,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (action != TIMER_IAA_WATCHDOG - && t > ehci->watchdog.expires + if (time_before_eq(t, ehci->watchdog.expires) && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); @@ -534,8 +550,8 @@ struct ehci_iso_stream { * trusting urb->interval == f(epdesc->bInterval) and * including the extra info for hw_bufp[0..2] */ - u8 interval; u8 usecs, c_usecs; + u16 interval; u16 tt_usecs; u16 maxp; u16 raw_mask; @@ -586,7 +602,6 @@ struct ehci_itd { unsigned frame; /* where scheduled */ unsigned pg; unsigned index[8]; /* in urb->iso_frame_desc */ - u8 usecs[8]; } __attribute__ ((aligned (32))); /*-------------------------------------------------------------------------*/ @@ -725,11 +740,16 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) * definition below can die once the 4xx support is * finally ported over. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) #define readl_be(addr) in_be32((__force unsigned *)addr) #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) #endif +#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX) +#define readl_be(addr) __raw_readl((__force unsigned *)addr) +#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr) +#endif + static inline unsigned int ehci_readl(const struct ehci_hcd *ehci, __u32 __iomem * regs) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c27417f5b9d..0130fd8571e 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -918,7 +918,6 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf) | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; buf[0] |= 1 << (i + 1); - continue; } } spin_unlock_irqrestore(&isp116x->lock, flags); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index d849c809acb..126fcbdd640 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -17,6 +17,8 @@ #include <asm/mach-types.h> #include <asm/hardware.h> +#include <asm/gpio.h> + #include <asm/arch/board.h> #include <asm/arch/cpu.h> @@ -271,12 +273,41 @@ static const struct hc_driver ohci_at91_hc_driver = { static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int i; + + if (pdata) { + /* REVISIT make the driver support per-port power switching, + * and also overcurrent detection. Here we assume the ports + * are always powered while this driver is active, and use + * active-low power switches. + */ + for (i = 0; i < pdata->ports; i++) { + if (pdata->vbus_pin[i] <= 0) + continue; + gpio_request(pdata->vbus_pin[i], "ohci_vbus"); + gpio_direction_output(pdata->vbus_pin[i], 0); + } + } + device_init_wakeup(&pdev->dev, 1); return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); } static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) { + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int i; + + if (pdata) { + for (i = 0; i < pdata->ports; i++) { + if (pdata->vbus_pin[i] <= 0) + continue; + gpio_direction_output(pdata->vbus_pin[i], 1); + gpio_free(pdata->vbus_pin[i]); + } + } + device_init_wakeup(&pdev->dev, 0); return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev); } diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index ebab5ce8f5c..a22c30aa745 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -401,6 +401,42 @@ static inline void remove_debug_files (struct ohci_hcd *bus) { } #else +static int debug_async_open(struct inode *, struct file *); +static int debug_periodic_open(struct inode *, struct file *); +static int debug_registers_open(struct inode *, struct file *); +static int debug_async_open(struct inode *, struct file *); +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, +}; + +static struct dentry *ohci_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct device *dev; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *page; +}; + static ssize_t show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) { @@ -467,8 +503,7 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) return count - size; } -static ssize_t -show_async (struct class_device *class_dev, char *buf) +static ssize_t fill_async_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -476,25 +511,23 @@ show_async (struct class_device *class_dev, char *buf) size_t temp; unsigned long flags; - bus = class_get_devdata(class_dev); + bus = dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); /* display control and bulk lists together, for simplicity */ spin_lock_irqsave (&ohci->lock, flags); - temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail); - temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail); + temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail); + temp += show_list(ohci, buf->page + temp, buf->count - temp, + ohci->ed_bulktail); spin_unlock_irqrestore (&ohci->lock, flags); return temp; } -static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL); - #define DBG_SCHED_LIMIT 64 -static ssize_t -show_periodic (struct class_device *class_dev, char *buf) +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -509,10 +542,10 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = class_get_devdata(class_dev); + bus = (struct usb_bus *)dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; temp = scnprintf (next, size, "size = %d\n", NUM_INTS); @@ -589,13 +622,9 @@ show_periodic (struct class_device *class_dev, char *buf) return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); - - #undef DBG_SCHED_LIMIT -static ssize_t -show_registers (struct class_device *class_dev, char *buf) +static ssize_t fill_registers_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -606,11 +635,11 @@ show_registers (struct class_device *class_dev, char *buf) char *next; u32 rdata; - bus = class_get_devdata(class_dev); + bus = (struct usb_bus *)dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); regs = ohci->regs; - next = buf; + next = buf->page; size = PAGE_SIZE; spin_lock_irqsave (&ohci->lock, flags); @@ -677,29 +706,155 @@ show_registers (struct class_device *class_dev, char *buf) done: spin_unlock_irqrestore (&ohci->lock, flags); + return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); +static struct debug_buffer *alloc_buffer(struct device *dev, + ssize_t (*fill_func)(struct debug_buffer *)) +{ + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + if (buf) { + buf->dev = dev; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + } + + return buf; +} + +static int fill_buffer(struct debug_buffer *buf) +{ + int ret = 0; + + if (!buf->page) + buf->page = (char *)get_zeroed_page(GFP_KERNEL); + + if (!buf->page) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); + + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; +} + +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->page, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + + if (buf) { + if (buf->page) + free_page((unsigned long)buf->page); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_periodic_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} static inline void create_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; - int retval; + struct usb_bus *bus = &ohci_to_hcd(ohci)->self; + struct device *dev = bus->dev; + + ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root); + if (!ohci->debug_dir) + goto dir_error; + + ohci->debug_async = debugfs_create_file("async", S_IRUGO, + ohci->debug_dir, dev, + &debug_async_fops); + if (!ohci->debug_async) + goto async_error; + + ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, + ohci->debug_dir, dev, + &debug_periodic_fops); + if (!ohci->debug_periodic) + goto periodic_error; + + ohci->debug_registers = debugfs_create_file("registers", S_IRUGO, + ohci->debug_dir, dev, + &debug_registers_fops); + if (!ohci->debug_registers) + goto registers_error; - retval = class_device_create_file(cldev, &class_device_attr_async); - retval = class_device_create_file(cldev, &class_device_attr_periodic); - retval = class_device_create_file(cldev, &class_device_attr_registers); ohci_dbg (ohci, "created debug files\n"); + return; + +registers_error: + debugfs_remove(ohci->debug_periodic); +periodic_error: + debugfs_remove(ohci->debug_async); +async_error: + debugfs_remove(ohci->debug_dir); +dir_error: + ohci->debug_periodic = NULL; + ohci->debug_async = NULL; + ohci->debug_dir = NULL; } static inline void remove_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; - - class_device_remove_file(cldev, &class_device_attr_async); - class_device_remove_file(cldev, &class_device_attr_periodic); - class_device_remove_file(cldev, &class_device_attr_registers); + debugfs_remove(ohci->debug_registers); + debugfs_remove(ohci->debug_periodic); + debugfs_remove(ohci->debug_async); + debugfs_remove(ohci->debug_dir); } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ddd4ee1f241..dd4798ee028 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -36,6 +36,7 @@ #include <linux/dmapool.h> #include <linux/reboot.h> #include <linux/workqueue.h> +#include <linux/debugfs.h> #include <asm/io.h> #include <asm/irq.h> @@ -809,13 +810,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) } if (ints & OHCI_INTR_WDH) { - if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); spin_lock (&ohci->lock); dl_done_list (ohci); spin_unlock (&ohci->lock); - if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { @@ -1032,6 +1029,13 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER usb_hcd_pnx4008_driver #endif +#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) +#include "ohci-sh.c" +#define PLATFORM_DRIVER ohci_hcd_sh_driver +#endif + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" @@ -1048,6 +1052,11 @@ MODULE_LICENSE ("GPL"); #define SSB_OHCI_DRIVER ssb_ohci_driver #endif +#ifdef CONFIG_MFD_SM501 +#include "ohci-sm501.c" +#define PLATFORM_DRIVER ohci_hcd_sm501_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ @@ -1068,6 +1077,14 @@ static int __init ohci_hcd_mod_init(void) pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); +#ifdef DEBUG + ohci_debug_root = debugfs_create_dir("ohci", NULL); + if (!ohci_debug_root) { + retval = -ENOENT; + goto error_debug; + } +#endif + #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); if (retval < 0) @@ -1130,6 +1147,12 @@ static int __init ohci_hcd_mod_init(void) ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif +#ifdef DEBUG + debugfs_remove(ohci_debug_root); + ohci_debug_root = NULL; + error_debug: +#endif + return retval; } module_init(ohci_hcd_mod_init); @@ -1154,6 +1177,9 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif +#ifdef DEBUG + debugfs_remove(ohci_debug_root); +#endif } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c new file mode 100644 index 00000000000..5309ac039e1 --- /dev/null +++ b/drivers/usb/host/ohci-sh.c @@ -0,0 +1,143 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * Copyright (C) 2008 Renesas Solutions Corp. + * + * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/platform_device.h> + +static int ohci_sh_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + ohci_init(ohci); + ohci_run(ohci); + hcd->state = HC_STATE_RUNNING; + return 0; +} + +static const struct hc_driver ohci_sh_hc_driver = { + .description = hcd_name, + .product_desc = "SuperH OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_sh_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +#define resource_len(r) (((r)->end - (r)->start) + 1) +static int ohci_hcd_sh_probe(struct platform_device *pdev) +{ + struct resource *res = NULL; + struct usb_hcd *hcd = NULL; + int irq = -1; + int ret; + + if (usb_disabled()) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err("platform_get_resource error."); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + err("platform_get_irq error."); + return -ENODEV; + } + + /* initialize hcd */ + hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); + if (!hcd) { + err("Failed to create hcd"); + return -ENOMEM; + } + + hcd->regs = (void __iomem *)res->start; + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_len(res); + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED); + if (ret != 0) { + err("Failed to add hcd"); + usb_put_hcd(hcd); + return ret; + } + + return ret; +} + +static int ohci_hcd_sh_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + + return 0; +} + +static struct platform_driver ohci_hcd_sh_driver = { + .probe = ohci_hcd_sh_probe, + .remove = ohci_hcd_sh_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "sh_ohci", + .owner = THIS_MODULE, + }, +}; + diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c new file mode 100644 index 00000000000..a9707014286 --- /dev/null +++ b/drivers/usb/host/ohci-sm501.c @@ -0,0 +1,264 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2005 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2008 Magnus Damm + * + * SM501 Bus Glue - based on ohci-omap.c + * + * This file is licenced under the GPL. + */ + +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/sm501.h> +#include <linux/sm501-regs.h> + +static int ohci_sm501_init(struct usb_hcd *hcd) +{ + return ohci_init(hcd_to_ohci(hcd)); +} + +static int ohci_sm501_start(struct usb_hcd *hcd) +{ + struct device *dev = hcd->self.controller; + int ret; + + ret = ohci_run(hcd_to_ohci(hcd)); + if (ret < 0) { + dev_err(dev, "can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + } + + return ret; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_sm501_hc_driver = { + .description = hcd_name, + .product_desc = "SM501 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, + + /* + * basic lifecycle operations + */ + .reset = ohci_sm501_init, + .start = ohci_sm501_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) +{ + const struct hc_driver *driver = &ohci_sm501_hc_driver; + struct device *dev = &pdev->dev; + struct resource *res, *mem; + int retval, irq; + struct usb_hcd *hcd = 0; + + irq = retval = platform_get_irq(pdev, 0); + if (retval < 0) + goto err0; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (mem == NULL) { + dev_err(dev, "no resource definition for memory\n"); + retval = -ENOENT; + goto err0; + } + + if (!request_mem_region(mem->start, mem->end - mem->start + 1, + pdev->name)) { + dev_err(dev, "request_mem_region failed\n"); + retval = -EBUSY; + goto err0; + } + + /* The sm501 chip is equipped with local memory that may be used + * by on-chip devices such as the video controller and the usb host. + * This driver uses dma_declare_coherent_memory() to make sure + * usb allocations with dma_alloc_coherent() allocate from + * this local memory. The dma_handle returned by dma_alloc_coherent() + * will be an offset starting from 0 for the first local memory byte. + * + * So as long as data is allocated using dma_alloc_coherent() all is + * fine. This is however not always the case - buffers may be allocated + * using kmalloc() - so the usb core needs to be told that it must copy + * data into our local memory if the buffers happen to be placed in + * regular memory. The HCD_LOCAL_MEM flag does just that. + */ + + if (!dma_declare_coherent_memory(dev, mem->start, + mem->start - mem->parent->start, + (mem->end - mem->start) + 1, + DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)) { + dev_err(dev, "cannot declare coherent memory\n"); + retval = -ENXIO; + goto err1; + } + + /* allocate, reserve and remap resources for registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "no resource definition for registers\n"); + retval = -ENOENT; + goto err2; + } + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto err2; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) { + dev_err(dev, "request_mem_region failed\n"); + retval = -EBUSY; + goto err3; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (hcd->regs == NULL) { + dev_err(dev, "cannot remap registers\n"); + retval = -ENXIO; + goto err4; + } + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (retval) + goto err4; + + /* enable power and unmask interrupts */ + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); + sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0); + + return 0; +err4: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err3: + usb_put_hcd(hcd); +err2: + dma_release_declared_memory(dev); +err1: + release_mem_region(mem->start, mem->end - mem->start + 1); +err0: + return retval; +} + +static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct resource *mem; + + usb_remove_hcd(hcd); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + dma_release_declared_memory(&pdev->dev); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(mem->start, mem->end - mem->start + 1); + + /* mask interrupts and disable power */ + + sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6); + sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM +static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct device *dev = &pdev->dev; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->power.power_state = PMSG_SUSPEND; + return 0; +} + +static int ohci_sm501_resume(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); + dev->power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(platform_get_drvdata(pdev)); + return 0; +} +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * Driver definition to register with the SM501 bus + */ +static struct platform_driver ohci_hcd_sm501_driver = { + .probe = ohci_hcd_sm501_drv_probe, + .remove = ohci_hcd_sm501_drv_remove, + .shutdown = usb_hcd_platform_shutdown, +#ifdef CONFIG_PM + .suspend = ohci_sm501_suspend, + .resume = ohci_sm501_resume, +#endif + .driver = { + .owner = THIS_MODULE, + .name = "sm501-usb", + }, +}; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 47c5c66a282..dc544ddc784 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -408,6 +408,13 @@ struct ohci_hcd { unsigned eds_scheduled; struct ed *ed_to_check; unsigned zf_delay; + +#ifdef DEBUG + struct dentry *debug_dir; + struct dentry *debug_async; + struct dentry *debug_periodic; + struct dentry *debug_registers; +#endif }; #ifdef CONFIG_PCI diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c225159ca3d..0ee694f043c 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -190,9 +190,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) msleep(10); } if (wait_time <= 0) - printk(KERN_WARNING "%s %s: BIOS handoff " - "failed (BIOS bug ?) %08x\n", - pdev->dev.bus_id, "OHCI", + dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" + " (BIOS bug?) %08x\n", readl(base + OHCI_CONTROL)); /* reset controller, preserving RWC */ @@ -243,8 +242,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) switch (cap & 0xff) { case 1: /* BIOS/SMM/... handoff support */ if ((cap & EHCI_USBLEGSUP_BIOS)) { - pr_debug("%s %s: BIOS handoff\n", - pdev->dev.bus_id, "EHCI"); + dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n"); #if 0 /* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on, @@ -285,9 +283,8 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) /* well, possibly buggy BIOS... try to shut * it down, and hope nothing goes too wrong */ - printk(KERN_WARNING "%s %s: BIOS handoff " - "failed (BIOS bug ?) %08x\n", - pdev->dev.bus_id, "EHCI", cap); + dev_warn(&pdev->dev, "EHCI: BIOS handoff failed" + " (BIOS bug?) %08x\n", cap); pci_write_config_byte(pdev, offset + 2, 0); } @@ -306,17 +303,14 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) cap = 0; /* FALLTHROUGH */ default: - printk(KERN_WARNING "%s %s: unrecognized " - "capability %02x\n", - pdev->dev.bus_id, "EHCI", - cap & 0xff); + dev_warn(&pdev->dev, "EHCI: unrecognized capability " + "%02x\n", cap & 0xff); break; } offset = (cap >> 8) & 0xff; } if (!count) - printk(KERN_DEBUG "%s %s: capability loop?\n", - pdev->dev.bus_id, "EHCI"); + dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n"); /* * halt EHCI & disable its interrupts in any case diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index fe9ceb077d9..57388252b69 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -405,7 +405,7 @@ struct r8a66597_pipe_info { u16 pipenum; - u16 address; /* R8A66597 HCD usb addres */ + u16 address; /* R8A66597 HCD usb address */ u16 epnum; u16 maxpacket; u16 type; diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index d1131a87a5b..0fb114ca1eb 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -478,8 +478,6 @@ static int mdc800_usb_probe (struct usb_interface *intf, { irq_interval=intf_desc->endpoint [j].desc.bInterval; } - - continue; } } if (mdc800->endpoint[i] == -1) diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index d721380b242..937940404b7 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -1,7 +1,7 @@ /* * cypress_cy7c63.c * -* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de) +* Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de) * * This driver is based on the Cypress USB Driver by Marcus Maul * (cyport) and the 2.0 version of Greg Kroah-Hartman's @@ -21,6 +21,9 @@ * Supported functions: Read/Write Ports * * +* For up-to-date information please visit: +* http://www.obock.de/kernel/cypress +* * 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, version 2. @@ -31,7 +34,7 @@ #include <linux/kernel.h> #include <linux/usb.h> -#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)" +#define DRIVER_AUTHOR "Oliver Bock (bock@tfh-berlin.de)" #define DRIVER_DESC "Cypress CY7C63xxx USB driver" #define CYPRESS_VENDOR_ID 0xa2c diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 764696ff1e8..801070502cc 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -715,7 +715,7 @@ static unsigned iowarrior_poll(struct file *file, poll_table * wait) * would use "struct net_driver" instead, and a serial * device would use "struct tty_driver". */ -static struct file_operations iowarrior_fops = { +static const struct file_operations iowarrior_fops = { .owner = THIS_MODULE, .write = iowarrior_write, .read = iowarrior_read, diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index aab320085eb..6664043f464 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -205,7 +205,7 @@ static DEFINE_MUTEX(open_disc_mutex); /* Structure to hold all of our device specific stuff */ struct lego_usb_tower { - struct semaphore sem; /* locks this structure */ + struct mutex lock; /* locks this structure */ struct usb_device* udev; /* save off the usb device pointer */ unsigned char minor; /* the starting minor number for this device */ @@ -361,7 +361,7 @@ static int tower_open (struct inode *inode, struct file *file) } /* lock this device */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { mutex_unlock(&open_disc_mutex); retval = -ERESTARTSYS; goto exit; @@ -421,7 +421,7 @@ static int tower_open (struct inode *inode, struct file *file) file->private_data = dev; unlock_exit: - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); @@ -448,7 +448,7 @@ static int tower_release (struct inode *inode, struct file *file) } mutex_lock(&open_disc_mutex); - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -460,7 +460,9 @@ static int tower_release (struct inode *inode, struct file *file) } if (dev->udev == NULL) { /* the device was unplugged before the file was released */ - up (&dev->sem); /* unlock here as tower_delete frees dev */ + + /* unlock here as tower_delete frees dev */ + mutex_unlock(&dev->lock); tower_delete (dev); goto exit; } @@ -473,7 +475,7 @@ static int tower_release (struct inode *inode, struct file *file) dev->open_count = 0; unlock_exit: - up (&dev->sem); + mutex_unlock(&dev->lock); exit: mutex_unlock(&open_disc_mutex); @@ -586,7 +588,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, dev = (struct lego_usb_tower *)file->private_data; /* lock this object */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -653,7 +655,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, unlock_exit: /* unlock the device */ - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); @@ -675,7 +677,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t dev = (struct lego_usb_tower *)file->private_data; /* lock this object */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -737,7 +739,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t unlock_exit: /* unlock the device */ - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); @@ -862,7 +864,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device goto exit; } - init_MUTEX (&dev->sem); + mutex_init(&dev->lock); dev->udev = udev; dev->open_count = 0; @@ -1007,16 +1009,16 @@ static void tower_disconnect (struct usb_interface *interface) /* give back our minor */ usb_deregister_dev (interface, &tower_class); - down (&dev->sem); + mutex_lock(&dev->lock); mutex_unlock(&open_disc_mutex); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { - up (&dev->sem); + mutex_unlock(&dev->lock); tower_delete (dev); } else { dev->udev = NULL; - up (&dev->sem); + mutex_unlock(&dev->lock); } info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE)); diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 9244d067cec..cb7fa0eaf3a 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -323,7 +323,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, usb_kill_urb(urb); retval = -ETIMEDOUT; } else { - /* URB completed within timout */ + /* URB completed within timeout */ retval = urb->status; readbytes = urb->actual_length; } @@ -3195,20 +3195,6 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->present = 1; -#ifdef SISUSB_OLD_CONFIG_COMPAT - { - int ret; - /* Our ioctls are all "32/64bit compatible" */ - ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL); - ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); - ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); - if (ret) - dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); - else - sisusb->ioctl32registered = 1; - } -#endif - if (dev->speed == USB_SPEED_HIGH) { int initscreen = 1; #ifdef INCL_SISUSB_CON @@ -3271,19 +3257,6 @@ static void sisusb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); -#ifdef SISUSB_OLD_CONFIG_COMPAT - if (sisusb->ioctl32registered) { - int ret; - sisusb->ioctl32registered = 0; - ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE); - ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); - ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); - if (ret) { - dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); - } - } -#endif - sisusb->present = 0; sisusb->ready = 0; diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index d2d7872cd02..cf0b4a5883f 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -120,9 +120,6 @@ struct sisusb_usb_data { int isopen; /* !=0 if open */ int present; /* !=0 if device is present on the bus */ int ready; /* !=0 if device is ready for userland */ -#ifdef SISUSB_OLD_CONFIG_COMPAT - int ioctl32registered; -#endif int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index ea316214648..da922dfc0dc 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/scatterlist.h> +#include <linux/mutex.h> #include <linux/usb.h> @@ -64,7 +65,7 @@ struct usbtest_dev { int in_iso_pipe; int out_iso_pipe; struct usb_endpoint_descriptor *iso_in, *iso_out; - struct semaphore sem; + struct mutex lock; #define TBUF_SIZE 256 u8 *buf; @@ -1151,6 +1152,7 @@ static int verify_halted (int ep, struct urb *urb) dbg ("ep %02x couldn't get halt status, %d", ep, retval); return retval; } + le16_to_cpus(&status); if (status != 1) { dbg ("ep %02x bogus status: %04x != 1", ep, status); return -EINVAL; @@ -1310,7 +1312,7 @@ static int ctrl_out (struct usbtest_dev *dev, len += vary; /* [real world] the "zero bytes IN" case isn't really used. - * hardware can easily trip up in this wierd case, since its + * hardware can easily trip up in this weird case, since its * status stage is IN, not OUT like other ep0in transfers. */ if (len > length) @@ -1558,11 +1560,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) || param->sglen < 0 || param->vary < 0) return -EINVAL; - if (down_interruptible (&dev->sem)) + if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; if (intf->dev.power.power_state.event != PM_EVENT_ON) { - up (&dev->sem); + mutex_unlock(&dev->lock); return -EHOSTUNREACH; } @@ -1574,7 +1576,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) int res; if (intf->altsetting->desc.bInterfaceNumber) { - up (&dev->sem); + mutex_unlock(&dev->lock); return -ENODEV; } res = set_altsetting (dev, dev->info->alt); @@ -1582,7 +1584,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) dev_err (&intf->dev, "set altsetting to %d failed, %d\n", dev->info->alt, res); - up (&dev->sem); + mutex_unlock(&dev->lock); return res; } } @@ -1855,7 +1857,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) param->duration.tv_usec += 1000 * 1000; param->duration.tv_sec -= 1; } - up (&dev->sem); + mutex_unlock(&dev->lock); return retval; } @@ -1905,7 +1907,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) return -ENOMEM; info = (struct usbtest_info *) id->driver_info; dev->info = info; - init_MUTEX (&dev->sem); + mutex_init(&dev->lock); dev->intf = intf; @@ -1990,8 +1992,6 @@ static void usbtest_disconnect (struct usb_interface *intf) { struct usbtest_dev *dev = usb_get_intfdata (intf); - down (&dev->sem); - usb_set_intfdata (intf, NULL); dev_dbg (&intf->dev, "disconnect\n"); kfree (dev); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f06e4e2b49d..1774ba5c4c3 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1026,6 +1026,8 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait) return mask; } +#if 0 + /* * open and close: just keep track of how many times the device is * mapped, to use the proper memory allocation function. @@ -1045,33 +1047,31 @@ static void mon_bin_vma_close(struct vm_area_struct *vma) /* * Map ring pages to user space. */ -struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct mon_reader_bin *rp = vma->vm_private_data; unsigned long offset, chunk_idx; struct page *pageptr; - offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= rp->b_size) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); - if (type) - *type = VM_FAULT_MINOR; - return pageptr; + vmf->page = pageptr; + return 0; } struct vm_operations_struct mon_bin_vm_ops = { .open = mon_bin_vma_open, .close = mon_bin_vma_close, - .nopage = mon_bin_vma_nopage, + .fault = mon_bin_vma_fault, }; int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) { - /* don't do anything here: "nopage" will set up page table entries */ + /* don't do anything here: "fault" will set up page table entries */ vma->vm_ops = &mon_bin_vm_ops; vma->vm_flags |= VM_RESERVED; vma->vm_private_data = filp->private_data; @@ -1079,7 +1079,9 @@ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } -struct file_operations mon_fops_binary = { +#endif /* 0 */ + +static const struct file_operations mon_fops_binary = { .owner = THIS_MODULE, .open = mon_bin_open, .llseek = no_llseek, diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 4a86696e6c7..c1e65dfd935 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -2,10 +2,7 @@ # USB Serial device configuration # -menu "USB Serial Converter support" - depends on USB!=n - -config USB_SERIAL +menuconfig USB_SERIAL tristate "USB Serial Converter support" depends on USB ---help--- @@ -20,6 +17,8 @@ config USB_SERIAL To compile this driver as a module, choose M here: the module will be called usbserial. +if USB_SERIAL + config USB_SERIAL_CONSOLE bool "USB Serial Console device support (EXPERIMENTAL)" depends on USB_SERIAL=y && EXPERIMENTAL @@ -43,6 +42,12 @@ config USB_SERIAL_CONSOLE If unsure, say N. +config USB_EZUSB + bool "Functions for loading firmware on EZUSB chips" + depends on USB_SERIAL + help + Say Y here if you need EZUSB device support. + config USB_SERIAL_GENERIC bool "USB Generic Serial Driver" depends on USB_SERIAL @@ -105,6 +110,7 @@ config USB_SERIAL_CH341 config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a ConnectTech WhiteHEAT 4 port USB to serial converter device. @@ -282,9 +288,21 @@ config USB_SERIAL_IPW To compile this driver as a module, choose M here: the module will be called ipw. +config USB_SERIAL_IUU + tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)" + depends on USB_SERIAL && EXPERIMENTAL + help + Say Y here if you want to use a IUU in phoenix mode and get + an extra ttyUSBx device. More information available on + http://eczema.ecze.com/iuu_phoenix.html + + To compile this driver as a module, choose M here: the + module will be called iuu_phoenix.o + config USB_SERIAL_KEYSPAN_PDA tristate "USB Keyspan PDA Single Port Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a Keyspan PDA single port USB to serial converter device. This driver makes use of firmware @@ -296,6 +314,7 @@ config USB_SERIAL_KEYSPAN_PDA config USB_SERIAL_KEYSPAN tristate "USB Keyspan USA-xxx Serial Driver" depends on USB_SERIAL + select USB_EZUSB ---help--- Say Y here if you want to use Keyspan USB to serial converter devices. This driver makes use of Keyspan's official firmware @@ -538,6 +557,7 @@ config USB_SERIAL_CYBERJACK config USB_SERIAL_XIRCOM tristate "USB Xircom / Entregra Single Port Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a Xircom or Entregra single port USB to serial converter device. This driver makes use of firmware @@ -585,11 +605,4 @@ config USB_SERIAL_DEBUG To compile this driver as a module, choose M here: the module will be called usb-debug. -config USB_EZUSB - bool - depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT - default y - - -endmenu - +endif # USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index d6fb384e52b..0db109a54d1 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o +obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 77bb893bf2e..f156dba0300 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -217,7 +217,10 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) priv->rts_state = 0; priv->dtr_state = 0; - airprime_send_setup(port); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + airprime_send_setup(port); + mutex_lock(&port->serial->disc_mutex); for (i = 0; i < NUM_READ_URBS; ++i) { usb_kill_urb (priv->read_urbp[i]); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index ddfee918000..fe2bfd67ba8 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -151,8 +151,10 @@ static int ark3116_attach(struct usb_serial *serial) return 0; cleanup: - for (--i; i >= 0; --i) + for (--i; i >= 0; --i) { + kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); + } return -ENOMEM; } diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 86724e88570..df0a2b3b029 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -350,14 +350,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios unsigned long control_state; int bad_flow_control; speed_t baud; + struct ktermios *termios = port->tty->termios; - if ((!port->tty) || (!port->tty->termios)) { - dbg ("%s - no tty or termios structure", __FUNCTION__); - return; - } + iflag = termios->c_iflag; + cflag = termios->c_cflag; - iflag = port->tty->termios->c_iflag; - cflag = port->tty->termios->c_cflag; + termios->c_cflag &= ~CMSPAR; /* get a local copy of the current port settings */ spin_lock_irqsave(&priv->lock, flags); @@ -369,33 +367,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios old_cflag = old_termios->c_cflag; /* Set the baud rate */ - if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { + if ((cflag & CBAUD) != (old_cflag & CBAUD)) { /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag&CBAUD) == B0 ) { control_state |= (TIOCM_DTR|TIOCM_RTS); if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) err("Set DTR error"); /* don't set RTS if using hardware flow control */ - if (!(old_cflag&CRTSCTS) ) + if (!(old_cflag & CRTSCTS)) if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0) err("Set RTS error"); } } baud = tty_get_baud_rate(port->tty); - if (baud == 0) { - dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__); - return; - } - urb_value = BELKIN_SA_BAUD(baud); - /* Clip to maximum speed */ - if (urb_value == 0) - urb_value = 1; - /* Turn it back into a resulting real baud rate */ - baud = BELKIN_SA_BAUD(urb_value); - /* FIXME: Once the tty updates are done then push this back to the tty */ - - if ((cflag & CBAUD) != B0 ) { + if (baud) { + urb_value = BELKIN_SA_BAUD(baud); + /* Clip to maximum speed */ + if (urb_value == 0) + urb_value = 1; + /* Turn it back into a resulting real baud rate */ + baud = BELKIN_SA_BAUD(urb_value); + + /* Report the actual baud rate back to the caller */ + tty_encode_baud_rate(port->tty, baud, baud); if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) err("Set baudrate error"); } else { diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 0362654d3b5..66ce30c1b75 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -64,8 +64,8 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial *serial; struct usb_serial_port *port; int retval = 0; - struct tty_struct *tty; - struct ktermios *termios; + struct tty_struct *tty = NULL; + struct ktermios *termios = NULL, dummy; dbg ("%s", __FUNCTION__); @@ -133,11 +133,14 @@ static int usb_console_setup(struct console *co, char *options) } co->cflag = cflag; - /* grab the first serial port that happens to be connected */ - serial = usb_serial_get_by_index(0); + /* + * no need to check the index here: if the index is wrong, console + * code won't call us + */ + serial = usb_serial_get_by_index(co->index); if (serial == NULL) { /* no device is connected yet, sorry :( */ - err ("No USB device connected to ttyUSB0"); + err ("No USB device connected to ttyUSB%i", co->index); return -ENODEV; } @@ -148,49 +151,64 @@ static int usb_console_setup(struct console *co, char *options) ++port->open_count; if (port->open_count == 1) { + if (serial->type->set_termios) { + /* + * allocate a fake tty so the driver can initialize + * the termios structure, then later call set_termios to + * configure according to command line arguments + */ + tty = kzalloc(sizeof(*tty), GFP_KERNEL); + if (!tty) { + retval = -ENOMEM; + err("no more memory"); + goto reset_open_count; + } + termios = kzalloc(sizeof(*termios), GFP_KERNEL); + if (!termios) { + retval = -ENOMEM; + err("no more memory"); + goto free_tty; + } + memset(&dummy, 0, sizeof(struct ktermios)); + tty->termios = termios; + port->tty = tty; + } + /* only call the device specific open if this * is the first time the port is opened */ if (serial->type->open) retval = serial->type->open(port, NULL); else retval = usb_serial_generic_open(port, NULL); - if (retval) - port->open_count = 0; - } - if (retval) { - err ("could not open USB console port"); - return retval; - } - - if (serial->type->set_termios) { - struct ktermios dummy; - /* build up a fake tty structure so that the open call has something - * to look at to get the cflag value */ - tty = kzalloc(sizeof(*tty), GFP_KERNEL); - if (!tty) { - err ("no more memory"); - return -ENOMEM; + if (retval) { + err("could not open USB console port"); + goto free_termios; } - termios = kzalloc(sizeof(*termios), GFP_KERNEL); - if (!termios) { - err ("no more memory"); - kfree (tty); - return -ENOMEM; - } - memset(&dummy, 0, sizeof(struct ktermios)); - termios->c_cflag = cflag; - tty->termios = termios; - port->tty = tty; - /* set up the initial termios settings */ - serial->type->set_termios(port, &dummy); - port->tty = NULL; - kfree (termios); - kfree (tty); + if (serial->type->set_termios) { + termios->c_cflag = cflag; + serial->type->set_termios(port, &dummy); + + port->tty = NULL; + kfree(termios); + kfree(tty); + } } + port->console = 1; + retval = 0; + +out: return retval; +free_termios: + kfree(termios); + port->tty = NULL; +free_tty: + kfree(tty); +reset_open_count: + port->open_count = 0; +goto out; } static void usb_console_write(struct console *co, const char *buf, unsigned count) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 22833589c4b..f3ca66017a0 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ @@ -76,8 +77,13 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ + { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ + { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; @@ -342,7 +348,10 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp) usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); - cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); + mutex_unlock(&port->serial->disc_mutex); } /* diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 4353df92487..8d9b045aa7e 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -319,7 +319,6 @@ static void cyberjack_read_int_callback( struct urb *urb ) /* React only to interrupts signaling a bulk_in transfer */ if( (urb->actual_length==4) && (data[0]==0x01) ) { short old_rdtodo; - int result; /* This is a announcement of coming bulk_ins. */ unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 163386336a5..08c65c1a377 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) { struct cypress_private *priv = usb_get_serial_port_data(port); unsigned int c_cflag; - unsigned long flags; int bps; long timeout; wait_queue_t wait; @@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); /* wait for data to drain from buffer */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); timeout = CYPRESS_CLOSING_WAIT; init_waitqueue_entry(&wait, current); add_wait_queue(&port->tty->write_wait, &wait); @@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) set_current_state(TASK_INTERRUPTIBLE); if (cypress_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->serial->interface)) + /* without mutex, allowed due to harmless failure mode */ + || port->serial->disconnected) break; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&port->tty->write_wait, &wait); /* clear out any remaining data in the buffer */ cypress_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - + spin_unlock_irq(&priv->lock); + + /* writing is potentially harmful, lock must be taken */ + mutex_lock(&port->serial->disc_mutex); + if (port->serial->disconnected) { + mutex_unlock(&port->serial->disc_mutex); + return; + } /* wait for characters to drain from device */ bps = tty_get_baud_rate(port->tty); if (bps > 1200) @@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) if (c_cflag & HUPCL) { /* drop dtr and rts */ priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->line_control = 0; priv->cmd_ctrl = 1; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); cypress_write(port, NULL, 0); } } @@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) if (stats) dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); + mutex_unlock(&port->serial->disc_mutex); } /* cypress_close */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index ae410c4678e..5f9c6e46bee 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) unsigned char buf[32]; struct tty_struct *tty = port->tty; struct digi_port *priv = usb_get_serial_port_data(port); - unsigned long flags = 0; dbg("digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count); + mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ - if (!usb_get_intfdata(port->serial->interface)) + if (port->serial->disconnected) goto exit; /* do cleanup only after final close on this port */ - spin_lock_irqsave(&priv->dp_port_lock, flags); + spin_lock_irq(&priv->dp_port_lock); priv->dp_in_close = 1; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); + spin_unlock_irq(&priv->dp_port_lock); /* tell line discipline to process only XON/XOFF */ tty->closing = 1; @@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) } tty->closing = 0; exit: - spin_lock_irqsave(&priv->dp_port_lock, flags); + spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; wake_up_interruptible(&priv->dp_close_wait); - spin_unlock_irqrestore(&priv->dp_port_lock, flags); + spin_unlock_irq(&priv->dp_port_lock); + mutex_unlock(&port->serial->disc_mutex); dbg("digi_close: done"); } diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index 97ee718b1da..3f698baa0ab 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -53,6 +53,6 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) } -EXPORT_SYMBOL(ezusb_writememory); -EXPORT_SYMBOL(ezusb_set_reset); +EXPORT_SYMBOL_GPL(ezusb_writememory); +EXPORT_SYMBOL_GPL(ezusb_set_reset); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c40e77dccf8..90dcc625f70 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,226 +17,8 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * - * (21/Jul/2004) Ian Abbott - * Incorporated Steven Turner's code to add support for the FT2232C chip. - * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have - * fixed a couple of things. - * - * (27/May/2004) Ian Abbott - * Improved throttling code, mostly stolen from the WhiteHEAT driver. - * - * (26/Mar/2004) Jan Capek - * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc. - * - * (09/Feb/2004) Ian Abbott - * Changed full name of USB-UIRT device to avoid "/" character. - * Added FTDI's alternate PID (0x6006) for FT232/245 devices. - * Added PID for "ELV USB Module UO100" from Stefan Frings. - * - * (21/Oct/2003) Ian Abbott - * Renamed some VID/PID macros for Matrix Orbital and Perle Systems - * devices. Removed Matrix Orbital and Perle Systems devices from the - * 8U232AM device table, but left them in the FT232BM table, as they are - * known to use only FT232BM. - * - * (17/Oct/2003) Scott Allen - * Added vid/pid for Perle Systems UltraPort USB serial converters - * - * (21/Sep/2003) Ian Abbott - * Added VID/PID for Omnidirectional Control Technology US101 USB to - * RS-232 adapter (also rebadged as Dick Smith Electronics XH6381). - * VID/PID supplied by Donald Gordon. - * - * (19/Aug/2003) Ian Abbott - * Freed urb's transfer buffer in write bulk callback. - * Omitted some paranoid checks in write bulk callback that don't matter. - * Scheduled work in write bulk callback regardless of port's open count. - * - * (05/Aug/2003) Ian Abbott - * Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter. - * VID/PID provided by Steve Briggs. - * - * (23/Jul/2003) Ian Abbott - * Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from - * Wayne Wylupski. - * - * (10/Jul/2003) David Glance - * Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800. - * - * (27/Jun/2003) Ian Abbott - * Reworked the urb handling logic. We have no more pool, but dynamically - * allocate the urb and the transfer buffer on the fly. In testing this - * does not incure any measurable overhead. This also relies on the fact - * that we have proper reference counting logic for urbs. I nicked this - * from Greg KH's Visor driver. - * - * (23/Jun/2003) Ian Abbott - * Reduced flip buffer pushes and corrected a data length test in - * ftdi_read_bulk_callback. - * Defererence pointers after any paranoid checks, not before. - * - * (21/Jun/2003) Erik Nygren - * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. - * See <http://www.home-electro.com/tira1.htm>. Only operates properly - * at 100000 and RTS-CTS, so set custom divisor mode on startup. - * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. - * - * (18/Jun/2003) Ian Abbott - * Added Device ID of the USB relais from Rudolf Gugler (backported from - * Philipp Gühring's patch for 2.5.x kernel). - * Moved read transfer buffer reallocation into startup function. - * Free existing write urb and transfer buffer in startup function. - * Only use urbs in write urb pool that were successfully allocated. - * Moved some constant macros out of functions. - * Minor whitespace and comment changes. - * - * (12/Jun/2003) David Norwood - * Added support for USB-UIRT IR transceiver using 8U232AM chip. - * See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>. Only - * operates properly at 312500, so set custom divisor mode on startup. - * - * (12/Jun/2003) Ian Abbott - * Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang - * - I've eliminated some that don't seem to exist! - * Added Home Electronics Tira-1 IR transceiver pid from Chris Horn - * Some whitespace/coding-style cleanups - * - * (11/Jun/2003) Ian Abbott - * Fixed unsafe spinlock usage in ftdi_write - * - * (24/Feb/2003) Richard Shooter - * Increase read buffer size to improve read speeds at higher baud rates - * (specifically tested with up to 1Mb/sec at 1.5M baud) - * - * (23/Feb/2003) John Wilkins - * Added Xon/xoff flow control (activating support in the ftdi device) - * Added vid/pid for Videonetworks/Homechoice (UK ISP) - * - * (23/Feb/2003) Bill Ryder - * Added matrix orb device vid/pids from Wayne Wylupski - * - * (19/Feb/2003) Ian Abbott - * For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has - * changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI, - * ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in - * force, don't bother changing baud rate when custom_divisor has changed. - * - * (18/Feb/2003) Ian Abbott - * Fixed TIOCMGET handling to include state of DTR and RTS, the state - * of which are now saved by set_dtr() and set_rts(). - * Fixed improper storage class for buf in set_dtr() and set_rts(). - * Added FT232BM chip type and support for its extra baud rates (compared - * to FT8U232AM). - * Took account of special case divisor values for highest baud rates of - * FT8U232AM and FT232BM. - * For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used, - * as previous alt_speed setting is now stale. - * Moved startup code common between the startup routines for the - * different chip types into a common subroutine. - * - * (17/Feb/2003) Bill Ryder - * Added write urb buffer pool on a per device basis - * Added more checking for open file on callbacks (fixed OOPS) - * Added CrystalFontz 632 and 634 PIDs - * (thanx to CrystalFontz for the sample devices - they flushed out - * some driver bugs) - * Minor debugging message changes - * Added throttle, unthrottle and chars_in_buffer functions - * Fixed FTDI_SIO (the original device) bug - * Fixed some shutdown handling - * - * - * - * - * (07/Jun/2002) Kuba Ober - * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor - * function. It was getting too complex. - * Fix the divisor calculation logic which was setting divisor of 0.125 - * instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8. - * Also make it bump up the divisor to next integer in case of 7/8 - it's - * a better approximation. - * - * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch - * Not tested by me but it doesn't break anything I use. - * - * (04/Jan/2002) Kuba Ober - * Implemented 38400 baudrate kludge, where it can be substituted with other - * values. That's the only way to set custom baudrates. - * Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy. - * FIXME: both baudrate things should eventually go to usbserial.c as other - * devices may need that functionality too. Actually, it can probably be - * merged in serial.c somehow - too many drivers repeat this code over - * and over. - * Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time. - * Divisors for baudrates are calculated by a macro. - * Small code cleanups. Ugly whitespace changes for Plato's sake only ;-]. - * - * (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. - * - * (23/May/2001) Bill Ryder - * Added runtime debug patch (thanx Tyson D Sawyer). - * Cleaned up comments for 8U232 - * Added parity, framing and overrun error handling - * Added receive break handling. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (18/March/2001) Bill Ryder - * (Not released) - * Added send break handling. (requires kernel patch too) - * Fixed 8U232AM hardware RTS/CTS etc status reporting. - * Added flipbuf fix copied from generic device - * - * (12/3/2000) Bill Ryder - * Added support for 8U232AM device. - * Moved PID and VIDs into header file only. - * Turned on low-latency for the tty (device will do high baudrates) - * Added shutdown routine to close files when device removed. - * More debug and error message cleanups. - * - * (11/13/2000) Bill Ryder - * Added spinlock protected open code and close code. - * Multiple opens work (sort of - see webpage mentioned above). - * Cleaned up comments. Removed multiple PID/VID definitions. - * Factorised cts/dtr code - * Made use of __FUNCTION__ in dbg's - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * - * (04/04/2000) Bill Ryder - * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are - * handled elsewhere in the tty io driver chain). - * - * (03/30/2000) Bill Ryder - * Implemented lots of ioctls - * Fixed a race condition in write - * Changed some dbg's to errs - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. + * Change entries from 2004 and earlier can be found in versions of this + * file in kernel versions prior to the 2.6.24 release. * */ @@ -309,12 +91,12 @@ struct ftdi_sio_quirk { void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */ }; -static int ftdi_olimex_probe (struct usb_serial *serial); +static int ftdi_jtag_probe (struct usb_serial *serial); static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); -static struct ftdi_sio_quirk ftdi_olimex_quirk = { - .probe = ftdi_olimex_probe, +static struct ftdi_sio_quirk ftdi_jtag_quirk = { + .probe = ftdi_jtag_probe, }; static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { @@ -471,30 +253,28 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, /* - * These will probably use user-space drivers. Uncomment them if - * you need them or use the user-specified vendor/product module - * parameters (see ftdi_sio.h for the numbers). Make a fuss if - * you think the driver should recognize any of them by default. + * Due to many user requests for multiple ELV devices we enable + * them by default. */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ + { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, @@ -545,6 +325,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, @@ -569,8 +350,13 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), - .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk }, + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -1283,10 +1069,11 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv) } /* ftdi_HE_TIRA1_setup */ /* - * First port on Olimex arm-usb-ocd is reserved for JTAG interface - * and can be accessed from userspace using openocd. + * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko + * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from + * userspace using openocd. */ -static int ftdi_olimex_probe(struct usb_serial *serial) +static int ftdi_jtag_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; @@ -1294,7 +1081,7 @@ static int ftdi_olimex_probe(struct usb_serial *serial) dbg("%s",__FUNCTION__); if (interface == udev->actconfig->interface[0]) { - info("Ignoring reserved serial port on Olimex arm-usb-ocd\n"); + info("Ignoring serial port reserved for JTAG"); return -ENODEV; } @@ -1411,7 +1198,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) dbg("%s", __FUNCTION__); - if (c_cflag & HUPCL){ + mutex_lock(&port->serial->disc_mutex); + if (c_cflag & HUPCL && !port->serial->disconnected){ /* Disable flow control */ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1425,6 +1213,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) /* drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Note change no line if hupcl is off */ + mutex_unlock(&port->serial->disc_mutex); /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index b51cbb0eaa0..6eee2ab914e 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -98,6 +98,10 @@ #define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ #define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ +/* OOCDlink by Joern Kaipf <joernk@web.de> + * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */ +#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 @@ -245,6 +249,7 @@ #define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ #define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ #define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ +#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */ /* * Definitions for ID TECH (www.idt-net.com) devices @@ -278,6 +283,7 @@ #define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ #define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ #define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ +#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ /* * Protego product ids @@ -534,6 +540,8 @@ #define OLIMEX_VID 0x15BA #define OLIMEX_ARM_USB_OCD_PID 0x0003 +/* www.elsterelectricity.com Elster Unicom III Optical Probe */ +#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ /* * The Mobility Lab (TML) @@ -556,6 +564,13 @@ /* + * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 + * Submitted by Harald Welte <laforge@openmoko.org> + */ +#define FIC_VID 0x1457 +#define FIC_NEO1973_DEBUG_PID 0x5118 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index f1c90cfe725..d74e43d6923 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1020,19 +1020,26 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp) if (!serial) return; - garmin_clear(garmin_data_p); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + garmin_clear(garmin_data_p); /* shutdown our urbs */ usb_kill_urb (port->read_urb); usb_kill_urb (port->write_urb); - if (noResponseFromAppLayer(garmin_data_p) || - ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) { - process_resetdev_request(port); - garmin_data_p->state = STATE_RESET; + if (!port->serial->disconnected) { + if (noResponseFromAppLayer(garmin_data_p) || + ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) { + process_resetdev_request(port); + garmin_data_p->state = STATE_RESET; + } else { + garmin_data_p->state = STATE_DISCONNECTED; + } } else { garmin_data_p->state = STATE_DISCONNECTED; } + mutex_unlock(&port->serial->disc_mutex); } diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index d41531139c5..97fa3c42843 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb_serial *serial) struct usb_serial_port *port; int i, c = 0, r; +#ifdef CONFIG_PM + /* + * If this is an autoresume, don't submit URBs. + * They will be submitted in the open function instead. + */ + if (serial->dev->auto_pm) + return 0; +#endif for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; if (port->open_count && port->read_urb) { diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index a5d2e115e16..3428ccc28da 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -959,7 +959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) * * This function will block the close until one of the following: * 1. Response to our Chase comes from Edgeport - * 2. A timout of 10 seconds without activity has expired + * 2. A timeout of 10 seconds without activity has expired * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/ @@ -999,7 +999,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) return; } } else { - // Reset timout value back to 10 seconds + // Reset timeout value back to 10 seconds dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits); loop = 10; } @@ -1014,7 +1014,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) * This function will block the close until one of the following: * 1. TX count are 0 * 2. The edgeport has stopped - * 3. A timout of 3 seconds without activity has expired + * 3. A timeout of 3 seconds without activity has expired * ************************************************************************/ static void block_until_tx_empty (struct edgeport_port *edge_port) @@ -1050,7 +1050,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port) return; } } else { - // Reset timout value back to seconds + // Reset timeout value back to seconds loop = 30; } } diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b8670905bc3..cd3405953f7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -34,6 +34,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/serial.h> #include <linux/ioctl.h> #include <asm/uaccess.h> @@ -133,7 +134,7 @@ struct edgeport_serial { struct product_info product_info; u8 TI_I2C_Type; // Type of I2C in UMP u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode - struct semaphore es_sem; + struct mutex es_lock; int num_ports_open; struct usb_serial *serial; }; @@ -1978,7 +1979,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) } /* set up the port settings */ - edge_set_termios (port, NULL); + edge_set_termios (port, port->tty->termios); /* open up the port */ @@ -2044,7 +2045,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr); edge_serial = edge_port->edge_serial; - if (down_interruptible(&edge_serial->es_sem)) + if (mutex_lock_interruptible(&edge_serial->es_lock)) return -ERESTARTSYS; if (edge_serial->num_ports_open == 0) { /* we are the first port to be opened, let's post the interrupt urb */ @@ -2052,7 +2053,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) if (!urb) { dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__); status = -EINVAL; - goto up_es_sem; + goto release_es_lock; } urb->complete = edge_interrupt_callback; urb->context = edge_serial; @@ -2060,7 +2061,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) status = usb_submit_urb (urb, GFP_KERNEL); if (status) { dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); - goto up_es_sem; + goto release_es_lock; } } @@ -2092,13 +2093,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) dbg("%s - exited", __FUNCTION__); - goto up_es_sem; + goto release_es_lock; unlink_int_urb: if (edge_port->edge_serial->num_ports_open == 0) usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -up_es_sem: - up(&edge_serial->es_sem); +release_es_lock: + mutex_unlock(&edge_serial->es_lock); return status; } @@ -2137,14 +2138,14 @@ static void edge_close (struct usb_serial_port *port, struct file *filp) 0, NULL, 0); - down(&edge_serial->es_sem); + mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { /* last port is now closed, let's shut down our interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); edge_port->edge_serial->num_ports_open = 0; } - up(&edge_serial->es_sem); + mutex_unlock(&edge_serial->es_lock); edge_port->close_pending = 0; dbg("%s - exited", __FUNCTION__); @@ -2393,11 +2394,6 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi dbg("%s - port %d", __FUNCTION__, edge_port->port->number); tty = edge_port->port->tty; - if ((!tty) || - (!tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { @@ -2492,15 +2488,21 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi } } + tty->termios->c_cflag &= ~CMSPAR; + /* Round the baud rate */ baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */ baud = 9600; - } + } else + tty_encode_baud_rate(tty, baud, baud); + edge_port->baud_rate = baud; config->wBaudRate = (__u16)((461550L + baud/2) / baud); + /* FIXME: Recompute actual baud from divisor here */ + dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate); dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate)); @@ -2538,19 +2540,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old struct tty_struct *tty = port->tty; unsigned int cflag; - if (!port->tty || !port->tty->termios) { - dbg ("%s - no tty or termios", __FUNCTION__); - return; - } - cflag = tty->termios->c_cflag; dbg("%s - clfag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, tty->termios->c_iflag); - if (old_termios) { - dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, - old_termios->c_cflag, old_termios->c_iflag); - } + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, old_termios->c_iflag); dbg("%s - port %d", __FUNCTION__, port->number); @@ -2743,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial) dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - sema_init(&edge_serial->es_sem, 1); + mutex_init(&edge_serial->es_lock); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c new file mode 100644 index 00000000000..fde188e23ce --- /dev/null +++ b/drivers/usb/serial/iuu_phoenix.c @@ -0,0 +1,1217 @@ +/* + * Infinity Unlimited USB Phoenix driver + * + * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) + * + * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás) + * + * 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. + * + * And tested with help of WB Electronics + * + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include "iuu_phoenix.h" +#include <linux/random.h> + + +#ifdef CONFIG_USB_SERIAL_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.5" +#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" + +static struct usb_device_id id_table[] = { + {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver iuu_driver = { + .name = "iuu_phoenix", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +/* turbo parameter */ +static int boost = 100; +static int clockmode = 1; +static int cdmode = 1; +static int iuu_cardin; +static int iuu_cardout; +static int xmas; + +static void read_rxcmd_callback(struct urb *urb); + +struct iuu_private { + spinlock_t lock; /* store irq state */ + wait_queue_head_t delta_msr_wait; + u8 line_control; + u8 line_status; + u8 termios_initialized; + int tiostatus; /* store IUART SIGNAL for tiocmget call */ + u8 reset; /* if 1 reset is needed */ + int poll; /* number of poll */ + u8 *writebuf; /* buffer for writing to device */ + int writelen; /* num of byte to write to device */ + u8 *buf; /* used for initialize speed */ + u8 *dbgbuf; /* debug buffer */ + u8 len; +}; + + +static void iuu_free_buf(struct iuu_private *priv) +{ + kfree(priv->buf); + kfree(priv->dbgbuf); + kfree(priv->writebuf); +} + +static int iuu_alloc_buf(struct iuu_private *priv) +{ + priv->buf = kzalloc(256, GFP_KERNEL); + priv->dbgbuf = kzalloc(256, GFP_KERNEL); + priv->writebuf = kzalloc(256, GFP_KERNEL); + if (!priv->buf || !priv->dbgbuf || !priv->writebuf) { + iuu_free_buf(priv); + dbg("%s problem allocation buffer", __FUNCTION__); + return -ENOMEM; + } + dbg("%s - Privates buffers allocation success", __FUNCTION__); + return 0; +} + +static int iuu_startup(struct usb_serial *serial) +{ + struct iuu_private *priv; + priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); + dbg("%s- priv allocation success", __FUNCTION__); + if (!priv) + return -ENOMEM; + if (iuu_alloc_buf(priv)) { + kfree(priv); + return -ENOMEM; + } + spin_lock_init(&priv->lock); + init_waitqueue_head(&priv->delta_msr_wait); + usb_set_serial_port_data(serial->port[0], priv); + return 0; +} + +/* Shutdown function */ +static void iuu_shutdown(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + struct iuu_private *priv = usb_get_serial_port_data(port); + if (!port) + return; + + dbg("%s", __FUNCTION__); + + if (priv) { + iuu_free_buf(priv); + dbg("%s - I will free all", __FUNCTION__); + usb_set_serial_port_data(port, NULL); + + dbg("%s - priv is not anymore in port structure", __FUNCTION__); + kfree(priv); + + dbg("%s priv is now kfree", __FUNCTION__); + } +} + +static int iuu_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; + tty = port->tty; + + dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__, + port->number, set, clear); + if (set & TIOCM_RTS) + priv->tiostatus = TIOCM_RTS; + + if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) { + dbg("%s TIOCMSET RESET called !!!", __FUNCTION__); + priv->reset = 1; + return 0; + } + + return 0; +} + +/* This is used to provide a carrier detect mechanism + * When a card is present, the response is 0x00 + * When no card , the reader respond with TIOCM_CD + * This is known as CD autodetect mechanism + */ +static int iuu_tiocmget(struct usb_serial_port *port, struct file *file) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + return priv->tiostatus; +} + +static void iuu_rxcmd(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + + memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + read_rxcmd_callback, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + +static int iuu_reset(struct usb_serial_port *port, u8 wt) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + + /* Prepare the reset sequence */ + + *buf_ptr++ = IUU_RST_SET; + *buf_ptr++ = IUU_DELAY_MS; + *buf_ptr++ = wt; + *buf_ptr = IUU_RST_CLEAR; + + /* send the sequence */ + + usb_fill_bulk_urb(port->write_urb, + port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 4, iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + priv->reset = 0; + return result; +} + +/* Status Function + * Return value is + * 0x00 = no card + * 0x01 = smartcard + * 0x02 = sim card + */ +static void iuu_update_status_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct iuu_private *priv = usb_get_serial_port_data(port); + u8 *st; + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + st = urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + if (urb->actual_length == 1) { + switch (st[0]) { + case 0x1: + priv->tiostatus = iuu_cardout; + break; + case 0x0: + priv->tiostatus = iuu_cardin; + break; + default: + priv->tiostatus = iuu_cardin; + } + } + iuu_rxcmd(urb); +} + +static void iuu_status_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, 256, + iuu_update_status_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); +} + +static int iuu_status(struct usb_serial_port *port) +{ + int result; + + dbg("%s - enter", __FUNCTION__); + + memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + iuu_status_callback, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + return result; + +} + +static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) +{ + int status; + struct usb_serial *serial = port->serial; + int actual = 0; + + dbg("%s - enter", __FUNCTION__); + + /* send the data out the bulk port */ + + status = + usb_bulk_msg(serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), buf, + count, &actual, HZ * 1); + + if (status != IUU_OPERATION_OK) { + dbg("%s - error = %2x", __FUNCTION__, status); + } else { + dbg("%s - write OK !", __FUNCTION__); + } + return status; +} + +static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) +{ + int status; + struct usb_serial *serial = port->serial; + int actual = 0; + + dbg("%s - enter", __FUNCTION__); + + /* send the data out the bulk port */ + + status = + usb_bulk_msg(serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), buf, + count, &actual, HZ * 1); + + if (status != IUU_OPERATION_OK) { + dbg("%s - error = %2x", __FUNCTION__, status); + } else { + dbg("%s - read OK !", __FUNCTION__); + } + + return status; +} + +static int iuu_led(struct usb_serial_port *port, unsigned int R, + unsigned int G, unsigned int B, u8 f) +{ + int status; + u8 *buf; + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dbg("%s - enter", __FUNCTION__); + + buf[0] = IUU_SET_LED; + buf[1] = R & 0xFF; + buf[2] = (R >> 8) & 0xFF; + buf[3] = G & 0xFF; + buf[4] = (G >> 8) & 0xFF; + buf[5] = B & 0xFF; + buf[6] = (B >> 8) & 0xFF; + buf[7] = f; + status = bulk_immediate(port, buf, 8); + kfree(buf); + if (status != IUU_OPERATION_OK) + dbg("%s - led error status = %2x", __FUNCTION__, status); + else + dbg("%s - led OK !", __FUNCTION__); + return IUU_OPERATION_OK; +} + +static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1, + u8 b2, u8 freq) +{ + *buf++ = IUU_SET_LED; + *buf++ = r1; + *buf++ = r2; + *buf++ = g1; + *buf++ = g2; + *buf++ = b1; + *buf++ = b2; + *buf = freq; +} + +static void iuu_led_activity_on(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + *buf_ptr++ = IUU_SET_LED; + if (xmas == 1) { + get_random_bytes(buf_ptr, 6); + *(buf_ptr+7) = 1; + } else { + iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255); + } + + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 8 , + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + +static void iuu_led_activity_off(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + if (xmas == 1) { + iuu_rxcmd(urb); + return; + } else { + *buf_ptr++ = IUU_SET_LED; + iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); + } + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 8 , + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + + + +static int iuu_clk(struct usb_serial_port *port, int dwFrq) +{ + int status; + struct iuu_private *priv = usb_get_serial_port_data(port); + int Count = 0; + u8 FrqGenAdr = 0x69; + u8 DIV = 0; /* 8bit */ + u8 XDRV = 0; /* 8bit */ + u8 PUMP = 0; /* 3bit */ + u8 PBmsb = 0; /* 2bit */ + u8 PBlsb = 0; /* 8bit */ + u8 PO = 0; /* 1bit */ + u8 Q = 0; /* 7bit */ + /* 24bit = 3bytes */ + unsigned int P = 0; + unsigned int P2 = 0; + int frq = (int)dwFrq; + + dbg("%s - enter", __FUNCTION__); + + if (frq == 0) { + priv->buf[Count++] = IUU_UART_WRITE_I2C; + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x09; + priv->buf[Count++] = 0x00; + + status = bulk_immediate(port, (u8 *) priv->buf, Count); + if (status != 0) { + dbg("%s - write error ", __FUNCTION__); + return status; + } + } else if (frq == 3579000) { + DIV = 100; + P = 1193; + Q = 40; + XDRV = 0; + } else if (frq == 3680000) { + DIV = 105; + P = 161; + Q = 5; + XDRV = 0; + } else if (frq == 6000000) { + DIV = 66; + P = 66; + Q = 2; + XDRV = 0x28; + } else { + unsigned int result = 0; + unsigned int tmp = 0; + unsigned int check; + unsigned int check2; + char found = 0x00; + unsigned int lQ = 2; + unsigned int lP = 2055; + unsigned int lDiv = 4; + + for (lQ = 2; lQ <= 47 && !found; lQ++) + for (lP = 2055; lP >= 8 && !found; lP--) + for (lDiv = 4; lDiv <= 127 && !found; lDiv++) { + tmp = (12000000 / lDiv) * (lP / lQ); + if (abs((int)(tmp - frq)) < + abs((int)(frq - result))) { + check2 = (12000000 / lQ); + if (check2 < 250000) + continue; + check = (12000000 / lQ) * lP; + if (check > 400000000) + continue; + if (check < 100000000) + continue; + if (lDiv < 4 || lDiv > 127) + continue; + result = tmp; + P = lP; + DIV = lDiv; + Q = lQ; + if (result == frq) + found = 0x01; + } + } + } + P2 = ((P - PO) / 2) - 4; + DIV = DIV; + PUMP = 0x04; + PBmsb = (P2 >> 8 & 0x03); + PBlsb = P2 & 0xFF; + PO = (P >> 10) & 0x01; + Q = Q - 2; + + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x09; + priv->buf[Count++] = 0x20; /* Adr = 0x09 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x0C; + priv->buf[Count++] = DIV; /* Adr = 0x0C */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x12; + priv->buf[Count++] = XDRV; /* Adr = 0x12 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x13; + priv->buf[Count++] = 0x6B; /* Adr = 0x13 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x40; + priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) | + (PBmsb & 0x03); /* Adr = 0x40 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x41; + priv->buf[Count++] = PBlsb; /* Adr = 0x41 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x42; + priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x44; + priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x45; + priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x46; + priv->buf[Count++] = 0x7F; /* Adr = 0x46 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x47; + priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */ + + status = bulk_immediate(port, (u8 *) priv->buf, Count); + if (status != IUU_OPERATION_OK) + dbg("%s - write error ", __FUNCTION__); + return status; +} + +static int iuu_uart_flush(struct usb_serial_port *port) +{ + int i; + int status; + u8 rxcmd = IUU_UART_RX; + struct iuu_private *priv = usb_get_serial_port_data(port); + + dbg("%s - enter", __FUNCTION__); + + if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) + return -EIO; + + for (i = 0; i < 2; i++) { + status = bulk_immediate(port, &rxcmd, 1); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_write error", __FUNCTION__); + return status; + } + + status = read_immediate(port, &priv->len, 1); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_read error", __FUNCTION__); + return status; + } + + if (priv->len > 0) { + dbg("%s - uart_flush datalen is : %i ", __FUNCTION__, + priv->len); + status = read_immediate(port, priv->buf, priv->len); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_read error", __FUNCTION__); + return status; + } + } + } + dbg("%s - uart_flush_read OK!", __FUNCTION__); + iuu_led(port, 0, 0xF000, 0, 0xFF); + return status; +} + +static void read_buf_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + if (urb->status == -EPROTO) { + /* reschedule needed */ + } + return; + } + + dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length); + tty = port->tty; + if (data == NULL) + dbg("%s - data is NULL !!!", __FUNCTION__); + if (tty && urb->actual_length && data) { + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + iuu_led_activity_on(urb); +} + +static int iuu_bulk_write(struct usb_serial_port *port) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + int result; + int i; + char *buf_ptr = port->write_urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + + *buf_ptr++ = IUU_UART_ESC; + *buf_ptr++ = IUU_UART_TX; + *buf_ptr++ = priv->writelen; + + memcpy(buf_ptr, priv->writebuf, + priv->writelen); + if (debug == 1) { + for (i = 0; i < priv->writelen; i++) + sprintf(priv->dbgbuf + i*2 , + "%02X", priv->writebuf[i]); + priv->dbgbuf[priv->writelen+i*2] = 0; + dbg("%s - writing %i chars : %s", __FUNCTION__, + priv->writelen, priv->dbgbuf); + } + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, priv->writelen + 3, + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + spin_lock_irqsave(&priv->lock, flags); + priv->writelen = 0; + spin_unlock_irqrestore(&priv->lock, flags); + usb_serial_port_softint(port); + return result; +} + +static int iuu_read_buf(struct usb_serial_port *port, int len) +{ + int result; + dbg("%s - enter", __FUNCTION__); + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, len, + read_buf_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + return result; +} + +static void iuu_uart_read_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + int status; + int error = 0; + int len = 0; + unsigned char *data = urb->transfer_buffer; + priv->poll++; + + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + if (data == NULL) + dbg("%s - data is NULL !!!", __FUNCTION__); + + if (urb->actual_length == 1 && data != NULL) + len = (int) data[0]; + + if (urb->actual_length > 1) { + dbg("%s - urb->actual_length = %i", __FUNCTION__, + urb->actual_length); + error = 1; + return; + } + /* if len > 0 call readbuf */ + + if (len > 0 && error == 0) { + dbg("%s - call read buf - len to read is %i ", + __FUNCTION__, len); + status = iuu_read_buf(port, len); + return; + } + /* need to update status ? */ + if (priv->poll > 99) { + status = iuu_status(port); + priv->poll = 0; + return; + } + + /* reset waiting ? */ + + if (priv->reset == 1) { + status = iuu_reset(port, 0xC); + return; + } + /* Writebuf is waiting */ + spin_lock_irqsave(&priv->lock, flags); + if (priv->writelen > 0) { + spin_unlock_irqrestore(&priv->lock, flags); + status = iuu_bulk_write(port); + return; + } + spin_unlock_irqrestore(&priv->lock, flags); + /* if nothing to write call again rxcmd */ + dbg("%s - rxcmd recall", __FUNCTION__); + iuu_led_activity_off(urb); + return; +} + +static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf, + int count) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + dbg("%s - enter", __FUNCTION__); + + if (count > 256) + return -ENOMEM; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->writelen > 0) { + /* buffer already filled but not commited */ + spin_unlock_irqrestore(&priv->lock, flags); + return (0); + } + /* fill the buffer */ + memcpy(priv->writebuf, buf, count); + priv->writelen = count; + spin_unlock_irqrestore(&priv->lock, flags); + + return (count); +} + +static void read_rxcmd_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, 256, + iuu_uart_read_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + dbg("%s - submit result = %d", __FUNCTION__, result); + return; +} + +static int iuu_uart_on(struct usb_serial_port *port) +{ + int status; + u8 *buf; + + buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + buf[0] = IUU_UART_ENABLE; + buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF); + buf[2] = (u8) (0x00FF & IUU_BAUD_9600); + buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN); + + status = bulk_immediate(port, buf, 4); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_on error", __FUNCTION__); + goto uart_enable_failed; + } + /* iuu_reset() the card after iuu_uart_on() */ + status = iuu_uart_flush(port); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_flush error", __FUNCTION__); +uart_enable_failed: + kfree(buf); + return status; +} + +/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */ +static int iuu_uart_off(struct usb_serial_port *port) +{ + int status; + u8 *buf; + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = IUU_UART_DISABLE; + + status = bulk_immediate(port, buf, 1); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_off error", __FUNCTION__); + + kfree(buf); + return status; +} + +static int iuu_uart_baud(struct usb_serial_port *port, u32 baud, + u32 *actual, u8 parity) +{ + int status; + u8 *dataout; + u8 DataCount = 0; + u8 T1Frekvens = 0; + u8 T1reload = 0; + unsigned int T1FrekvensHZ = 0; + + dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); + + if (!dataout) + return -ENOMEM; + + if (baud < 1200 || baud > 230400) { + kfree(dataout); + return IUU_INVALID_PARAMETER; + } + if (baud > 977) { + T1Frekvens = 3; + T1FrekvensHZ = 500000; + } + + if (baud > 3906) { + T1Frekvens = 2; + T1FrekvensHZ = 2000000; + } + + if (baud > 11718) { + T1Frekvens = 1; + T1FrekvensHZ = 6000000; + } + + if (baud > 46875) { + T1Frekvens = 0; + T1FrekvensHZ = 24000000; + } + + T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2)); + + /* magic number here: ENTER_FIRMWARE_UPDATE; */ + dataout[DataCount++] = IUU_UART_ESC; + /* magic number here: CHANGE_BAUD; */ + dataout[DataCount++] = IUU_UART_CHANGE; + dataout[DataCount++] = T1Frekvens; + dataout[DataCount++] = T1reload; + + *actual = (T1FrekvensHZ / (256 - T1reload)) / 2; + + switch (parity & 0x0F) { + case IUU_PARITY_NONE: + dataout[DataCount++] = 0x00; + break; + case IUU_PARITY_EVEN: + dataout[DataCount++] = 0x01; + break; + case IUU_PARITY_ODD: + dataout[DataCount++] = 0x02; + break; + case IUU_PARITY_MARK: + dataout[DataCount++] = 0x03; + break; + case IUU_PARITY_SPACE: + dataout[DataCount++] = 0x04; + break; + default: + kfree(dataout); + return IUU_INVALID_PARAMETER; + break; + } + + switch (parity & 0xF0) { + case IUU_ONE_STOP_BIT: + dataout[DataCount - 1] |= IUU_ONE_STOP_BIT; + break; + + case IUU_TWO_STOP_BITS: + dataout[DataCount - 1] |= IUU_TWO_STOP_BITS; + break; + default: + kfree(dataout); + return IUU_INVALID_PARAMETER; + break; + } + + status = bulk_immediate(port, dataout, DataCount); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_off error", __FUNCTION__); + kfree(dataout); + return status; +} + +static int set_control_lines(struct usb_device *dev, u8 value) +{ + return 0; +} + +static void iuu_close(struct usb_serial_port *port, struct file *filp) +{ + /* iuu_led (port,255,0,0,0); */ + struct usb_serial *serial; + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + unsigned int c_cflag; + + serial = port->serial; + if (!serial) + return; + + dbg("%s - port %d", __FUNCTION__, port->number); + + iuu_uart_off(port); + if (serial->dev) { + if (port->tty) { + c_cflag = port->tty->termios->c_cflag; + if (c_cflag & HUPCL) { + /* drop DTR and RTS */ + priv = usb_get_serial_port_data(port); + spin_lock_irqsave(&priv->lock, flags); + priv->line_control = 0; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, 0); + } + } + /* free writebuf */ + /* shutdown our urbs */ + dbg("%s - shutting down urbs", __FUNCTION__); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); + msleep(1000); + /* wait one second to free all buffers */ + iuu_led(port, 0, 0, 0xF000, 0xFF); + msleep(1000); + usb_reset_device(port->serial->dev); + } +} + +static int iuu_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + u8 *buf; + int result; + u32 actual; + unsigned long flags; + struct iuu_private *priv = usb_get_serial_port_data(port); + + dbg("%s - port %d", __FUNCTION__, port->number); + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + + buf = kmalloc(10, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + /* fixup the endpoint buffer size */ + kfree(port->bulk_out_buffer); + port->bulk_out_buffer = kmalloc(512, GFP_KERNEL); + port->bulk_out_size = 512; + kfree(port->bulk_in_buffer); + port->bulk_in_buffer = kmalloc(512, GFP_KERNEL); + port->bulk_in_size = 512; + + if (!port->bulk_out_buffer || !port->bulk_in_buffer) { + kfree(port->bulk_out_buffer); + kfree(port->bulk_in_buffer); + kfree(buf); + return -ENOMEM; + } + + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->bulk_out_buffer, 512, + NULL, NULL); + + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, 512, + NULL, NULL); + + /* set the termios structure */ + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(port->tty->termios) = tty_std_termios; + port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + | TIOCM_CTS | CSTOPB | PARENB; + port->tty->termios->c_lflag = 0; + port->tty->termios->c_oflag = 0; + port->tty->termios->c_iflag = 0; + priv->termios_initialized = 1; + port->tty->low_latency = 1; + priv->poll = 0; + } + spin_unlock_irqrestore(&priv->lock, flags); + + /* initialize writebuf */ +#define FISH(a, b, c, d) do { \ + result = usb_control_msg(port->serial->dev, \ + usb_rcvctrlpipe(port->serial->dev, 0), \ + b, a, c, d, buf, 1, 1000); \ + dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \ + buf[0]); } while (0); + +#define SOUP(a, b, c, d) do { \ + result = usb_control_msg(port->serial->dev, \ + usb_sndctrlpipe(port->serial->dev, 0), \ + b, a, c, d, NULL, 0, 1000); \ + dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0) + + /* This is not UART related but IUU USB driver related or something */ + /* like that. Basically no IUU will accept any commands from the USB */ + /* host unless it has received the following message */ + /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ + + SOUP(0x03, 0x02, 0x02, 0x0); + kfree(buf); + iuu_led(port, 0xF000, 0xF000, 0, 0xFF); + iuu_uart_on(port); + if (boost < 100) + boost = 100; + switch (clockmode) { + case 2: /* 3.680 Mhz */ + iuu_clk(port, IUU_CLK_3680000 * boost / 100); + result = + iuu_uart_baud(port, 9600 * boost / 100, &actual, + IUU_PARITY_EVEN); + break; + case 3: /* 6.00 Mhz */ + iuu_clk(port, IUU_CLK_6000000 * boost / 100); + result = + iuu_uart_baud(port, 16457 * boost / 100, &actual, + IUU_PARITY_EVEN); + break; + default: /* 3.579 Mhz */ + iuu_clk(port, IUU_CLK_3579000 * boost / 100); + result = + iuu_uart_baud(port, 9600 * boost / 100, &actual, + IUU_PARITY_EVEN); + } + + /* set the cardin cardout signals */ + switch (cdmode) { + case 0: + iuu_cardin = 0; + iuu_cardout = 0; + break; + case 1: + iuu_cardin = TIOCM_CD; + iuu_cardout = 0; + break; + case 2: + iuu_cardin = 0; + iuu_cardout = TIOCM_CD; + break; + case 3: + iuu_cardin = TIOCM_DSR; + iuu_cardout = 0; + break; + case 4: + iuu_cardin = 0; + iuu_cardout = TIOCM_DSR; + break; + case 5: + iuu_cardin = TIOCM_CTS; + iuu_cardout = 0; + break; + case 6: + iuu_cardin = 0; + iuu_cardout = TIOCM_CTS; + break; + case 7: + iuu_cardin = TIOCM_RNG; + iuu_cardout = 0; + break; + case 8: + iuu_cardin = 0; + iuu_cardout = TIOCM_RNG; + } + + iuu_uart_flush(port); + + dbg("%s - initialization done", __FUNCTION__); + + memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + read_rxcmd_callback, port); + result = usb_submit_urb(port->write_urb, GFP_KERNEL); + + if (result) { + dev_err(&port->dev, "%s - failed submitting read urb," + " error %d\n", __FUNCTION__, result); + iuu_close(port, NULL); + return -EPROTO; + } else { + dbg("%s - rxcmd OK", __FUNCTION__); + } + return result; +} + +static struct usb_serial_driver iuu_device = { + .driver = { + .owner = THIS_MODULE, + .name = "iuu_phoenix", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = iuu_open, + .close = iuu_close, + .write = iuu_uart_write, + .read_bulk_callback = iuu_uart_read_callback, + .tiocmget = iuu_tiocmget, + .tiocmset = iuu_tiocmset, + .attach = iuu_startup, + .shutdown = iuu_shutdown, +}; + +static int __init iuu_init(void) +{ + int retval; + retval = usb_serial_register(&iuu_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&iuu_driver); + if (retval) + goto failed_usb_register; + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +failed_usb_register: + usb_serial_deregister(&iuu_device); +failed_usb_serial_register: + return retval; +} + +static void __exit iuu_exit(void) +{ + usb_deregister(&iuu_driver); + usb_serial_deregister(&iuu_device); +} + +module_init(iuu_init); +module_exit(iuu_exit); + +MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(DRIVER_VERSION); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +module_param(xmas, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(xmas, "xmas color enabled or not"); + +module_param(boost, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500"); + +module_param(clockmode, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz"); + +module_param(cdmode, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, " + "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING"); diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h new file mode 100644 index 00000000000..b82630a3b8f --- /dev/null +++ b/drivers/usb/serial/iuu_phoenix.h @@ -0,0 +1,122 @@ +/* + * Infinity Unlimited USB Phoenix driver + * + * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) + * + * + * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás ) + * + * 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. + * + * And tested with help of WB Electronics + * + */ + +#define IUU_USB_VENDOR_ID 0x104f +#define IUU_USB_PRODUCT_ID 0x0004 +#define IUU_USB_OP_TIMEOUT 0x0200 + +/* Programmer commands */ + +#define IUU_NO_OPERATION 0x00 +#define IUU_GET_FIRMWARE_VERSION 0x01 +#define IUU_GET_PRODUCT_NAME 0x02 +#define IUU_GET_STATE_REGISTER 0x03 +#define IUU_SET_LED 0x04 +#define IUU_WAIT_MUS 0x05 +#define IUU_WAIT_MS 0x06 +#define IUU_GET_LOADER_VERSION 0x50 +#define IUU_RST_SET 0x52 +#define IUU_RST_CLEAR 0x53 +#define IUU_SET_VCC 0x59 +#define IUU_UART_ENABLE 0x49 +#define IUU_UART_DISABLE 0x4A +#define IUU_UART_WRITE_I2C 0x4C +#define IUU_UART_ESC 0x5E +#define IUU_UART_TRAP 0x54 +#define IUU_UART_TRAP_BREAK 0x5B +#define IUU_UART_RX 0x56 +#define IUU_AVR_ON 0x21 +#define IUU_AVR_OFF 0x22 +#define IUU_AVR_1CLK 0x23 +#define IUU_AVR_RESET 0x24 +#define IUU_AVR_RESET_PC 0x25 +#define IUU_AVR_INC_PC 0x26 +#define IUU_AVR_INCN_PC 0x27 +#define IUU_AVR_PREAD 0x29 +#define IUU_AVR_PREADN 0x2A +#define IUU_AVR_PWRITE 0x28 +#define IUU_AVR_DREAD 0x2C +#define IUU_AVR_DREADN 0x2D +#define IUU_AVR_DWRITE 0x2B +#define IUU_AVR_PWRITEN 0x2E +#define IUU_EEPROM_ON 0x37 +#define IUU_EEPROM_OFF 0x38 +#define IUU_EEPROM_WRITE 0x39 +#define IUU_EEPROM_WRITEX 0x3A +#define IUU_EEPROM_WRITE8 0x3B +#define IUU_EEPROM_WRITE16 0x3C +#define IUU_EEPROM_WRITEX32 0x3D +#define IUU_EEPROM_WRITEX64 0x3E +#define IUU_EEPROM_READ 0x3F +#define IUU_EEPROM_READX 0x40 +#define IUU_EEPROM_BREAD 0x41 +#define IUU_EEPROM_BREADX 0x42 +#define IUU_PIC_CMD 0x0A +#define IUU_PIC_CMD_LOAD 0x0B +#define IUU_PIC_CMD_READ 0x0C +#define IUU_PIC_ON 0x0D +#define IUU_PIC_OFF 0x0E +#define IUU_PIC_RESET 0x16 +#define IUU_PIC_INC_PC 0x0F +#define IUU_PIC_INCN_PC 0x10 +#define IUU_PIC_PWRITE 0x11 +#define IUU_PIC_PREAD 0x12 +#define IUU_PIC_PREADN 0x13 +#define IUU_PIC_DWRITE 0x14 +#define IUU_PIC_DREAD 0x15 +#define IUU_UART_NOP 0x00 +#define IUU_UART_CHANGE 0x02 +#define IUU_UART_TX 0x04 +#define IUU_DELAY_MS 0x06 + +#define IUU_OPERATION_OK 0x00 +#define IUU_DEVICE_NOT_FOUND 0x01 +#define IUU_INVALID_HANDLE 0x02 +#define IUU_INVALID_PARAMETER 0x03 +#define IUU_INVALID_voidERFACE 0x04 +#define IUU_INVALID_REQUEST_LENGTH 0x05 +#define IUU_UART_NOT_ENABLED 0x06 +#define IUU_WRITE_ERROR 0x07 +#define IUU_READ_ERROR 0x08 +#define IUU_TX_ERROR 0x09 +#define IUU_RX_ERROR 0x0A + +#define IUU_PARITY_NONE 0x00 +#define IUU_PARITY_EVEN 0x01 +#define IUU_PARITY_ODD 0x02 +#define IUU_PARITY_MARK 0x03 +#define IUU_PARITY_SPACE 0x04 +#define IUU_SC_INSERTED 0x01 +#define IUU_VERIFY_ERROR 0x02 +#define IUU_SIM_INSERTED 0x04 +#define IUU_TWO_STOP_BITS 0x00 +#define IUU_ONE_STOP_BIT 0x20 +#define IUU_BAUD_2400 0x0398 +#define IUU_BAUD_9600 0x0298 +#define IUU_BAUD_19200 0x0164 +#define IUU_BAUD_28800 0x0198 +#define IUU_BAUD_38400 0x01B2 +#define IUU_BAUD_57600 0x0030 +#define IUU_BAUD_115200 0x0098 +#define IUU_CLK_3579000 3579000 +#define IUU_CLK_3680000 3680000 +#define IUU_CLK_6000000 6000000 +#define IUU_FULLCARD_IN 0x01 +#define IUU_DEV_ERROR 0x02 +#define IUU_MINICARD_IN 0x04 +#define IUU_VCC_5V 0x00 +#define IUU_VCC_3V 0x01 diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7c069a02c1d..ea7bba69f4d 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -838,7 +838,7 @@ static void usa49_indat_callback(struct urb *urb) port = (struct usb_serial_port *) urb->context; tty = port->tty; - if (urb->actual_length) { + if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no error on any byte */ diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index be9ac20a8f1..b1fa5a376e9 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -303,7 +303,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port) } -static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) +static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud) { int rc; int bindex; @@ -319,7 +319,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) case 38400: bindex = 7; break; case 57600: bindex = 8; break; case 115200: bindex = 9; break; - default: return -EINVAL; + default: + bindex = 5; /* Default to 9600 */ + baud = 9600; } /* rather than figure out how to sleep while waiting for this @@ -334,7 +336,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) NULL, /* &data */ 0, /* size */ 2000); /* timeout */ - return(rc); + if (rc < 0) + return 0; + return baud; } @@ -366,7 +370,7 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; - unsigned int cflag = port->tty->termios->c_cflag; + speed_t speed; /* cflag specifies lots of stuff: number of stop bits, parity, number of data bits, baud. What can the device actually handle?: @@ -388,22 +392,18 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port, For now, just do baud. */ - switch (cflag & CBAUD) { - /* we could support more values here, just need to calculate - the necessary divisors in the firmware. <asm/termbits.h> - has the Bnnn constants. */ - case B110: keyspan_pda_setbaud(serial, 110); break; - case B300: keyspan_pda_setbaud(serial, 300); break; - case B1200: keyspan_pda_setbaud(serial, 1200); break; - case B2400: keyspan_pda_setbaud(serial, 2400); break; - case B4800: keyspan_pda_setbaud(serial, 4800); break; - case B9600: keyspan_pda_setbaud(serial, 9600); break; - case B19200: keyspan_pda_setbaud(serial, 19200); break; - case B38400: keyspan_pda_setbaud(serial, 38400); break; - case B57600: keyspan_pda_setbaud(serial, 57600); break; - case B115200: keyspan_pda_setbaud(serial, 115200); break; - default: dbg("can't handle requested baud rate"); break; + speed = tty_get_baud_rate(port->tty); + speed = keyspan_pda_setbaud(serial, speed); + + if (speed == 0) { + dbg("can't handle requested baud rate"); + /* It hasn't changed so.. */ + speed = tty_termios_baud_rate(old_termios); } + /* Only speed can change so copy the old h/w parameters + then encode the new speed */ + tty_termios_copy_hw(port->tty->termios, old_termios); + tty_encode_baud_rate(port->tty, speed, speed); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 90e3216abd1..55736df7d2f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -461,17 +461,21 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp) dbg("%s port %d", __FUNCTION__, port->number); - /* send READ_OFF */ - rc = usb_control_msg (port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR | USB_DIR_OUT, - KL5KUSB105A_SIO_CONFIGURE_READ_OFF, - 0, /* index */ - NULL, 0, - KLSI_TIMEOUT); - if (rc < 0) - err("Disabling read failed (error = %d)", rc); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* send READ_OFF */ + rc = usb_control_msg (port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR | USB_DIR_OUT, + KL5KUSB105A_SIO_CONFIGURE_READ_OFF, + 0, /* index */ + NULL, 0, + KLSI_TIMEOUT); + if (rc < 0) + err("Disabling read failed (error = %d)", rc); + } + mutex_unlock(&port->serial->disc_mutex); /* shutdown our bulk reads and writes */ usb_kill_urb(port->write_urb); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index aee450246bf..17b3baead4a 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -114,6 +114,7 @@ static struct usb_serial_driver kobil_device = { .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = 0, .num_bulk_out = 0, .num_ports = 1, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 0dc99f75bb0..fc1cea4aba1 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -182,10 +182,11 @@ struct mct_u232_private { /* * Later day 2.6.0-test kernels have new baud rates like B230400 which * we do not know how to support. We ignore them for the moment. - * XXX Rate-limit the error message, it's user triggerable. */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value) +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result) { + *result = value; + if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) { switch (value) { @@ -200,11 +201,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value case 57600: return 0x0b; case 115200: return 0x0c; default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); + *result = 9600; return 0x08; } } else { + /* FIXME: Can we use any divider - should we do + divider = 115200/value; + real baud = 115200/divider */ switch (value) { case 300: break; case 600: break; @@ -217,9 +220,8 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value case 57600: break; case 115200: break; default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); value = 9600; + *result = 9600; } return 115200/value; } @@ -232,16 +234,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_p int rc; unsigned char zero_byte = 0; unsigned char cts_enable_byte = 0; + speed_t speed; - divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value)); + divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed)); rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_BAUD_RATE_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE, WDR_TIMEOUT); - if (rc < 0) + if (rc < 0) /*FIXME: What value speed results */ err("Set BAUD RATE %d failed (error = %d)", value, rc); + else + tty_encode_baud_rate(port->tty, speed, speed); dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor); /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which @@ -482,21 +487,22 @@ error: static void mct_u232_close (struct usb_serial_port *port, struct file *filp) { unsigned int c_cflag; - unsigned long flags; unsigned int control_state; struct mct_u232_private *priv = usb_get_serial_port_data(port); dbg("%s port %d", __FUNCTION__, port->number); if (port->tty) { c_cflag = port->tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_modem_ctrl(port->serial, control_state); + mutex_lock(&port->serial->disc_mutex); + if (c_cflag & HUPCL && !port->serial->disconnected) { + /* drop DTR and RTS */ + spin_lock_irq(&priv->lock); + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + control_state = priv->control_state; + spin_unlock_irq(&priv->lock); + mct_u232_set_modem_ctrl(port->serial, control_state); } + mutex_unlock(&port->serial->disc_mutex); } @@ -608,7 +614,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port, { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = port->tty->termios->c_cflag; + struct ktermios *termios = port->tty->termios; + unsigned int cflag = termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; unsigned int control_state; @@ -670,6 +677,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port, break; } + termios->c_cflag &= ~CMSPAR; + /* set the number of stop bits */ last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h index aae10c8174d..07b6bec31dc 100644 --- a/drivers/usb/serial/mct_u232.h +++ b/drivers/usb/serial/mct_u232.h @@ -79,7 +79,7 @@ * and "Intel solution". They are the regular MCT and "Sitecom" for us. * This is pointless to document in the header, see the code for the bits. */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value); +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result); /* * Line Control Register (LCR) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e02c198016b..40f3a018880 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp) } /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists */ - if (serial->dev) { - dbg("Shutdown bulk write"); - usb_kill_urb(port->write_urb); - dbg("Shutdown bulk read"); - usb_kill_urb(port->read_urb); + * and interrupt read if they exists, otherwise nop */ + dbg("Shutdown bulk write"); + usb_kill_urb(port->write_urb); + dbg("Shutdown bulk read"); + usb_kill_urb(port->read_urb); + + mutex_lock(&serial->disc_mutex); + /* these commands must not be issued if the device has + * been disconnected */ + if (!serial->disconnected) { + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x01, &data); } - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - 0x04, &data); - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - 0x01, &data); - + mutex_unlock(&serial->disc_mutex); mos7720_port->open = 0; dbg("Leaving %s", __FUNCTION__); @@ -1040,11 +1043,6 @@ static void change_port_settings(struct moschip_port *mos7720_port, tty = mos7720_port->port->tty; - if ((!tty) || (!tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - dbg("%s: Entering ..........", __FUNCTION__); lData = UART_LCR_WLEN8; @@ -1175,7 +1173,10 @@ static void change_port_settings(struct moschip_port *mos7720_port, dbg("%s - baud rate = %d", __FUNCTION__, baud); status = send_cmd_write_baud_rate(mos7720_port, baud); - + /* FIXME: needs to write actual resulting baud back not just + blindly do so */ + if (cflag & CBAUD) + tty_encode_baud_rate(tty, baud, baud); /* Enable Interrupts */ data = 0x0c; send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); @@ -1214,10 +1215,6 @@ static void mos7720_set_termios(struct usb_serial_port *port, tty = port->tty; - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty or termios", __FUNCTION__); - return; - } if (!mos7720_port->open) { dbg("%s - port not opened", __FUNCTION__); @@ -1228,19 +1225,13 @@ static void mos7720_set_termios(struct usb_serial_port *port, cflag = tty->termios->c_cflag; - if (!cflag) { - printk("%s %s\n",__FUNCTION__,"cflag is NULL"); - return; - } - - dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + dbg("%s - cflag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); - if (old_termios) - dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, - old_termios->c_cflag, - RELEVANT_IFLAG(old_termios->c_iflag)); + dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); dbg("%s - port %d", __FUNCTION__, port->number); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c29c9127113..869ecd374cb 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1133,7 +1133,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port) * This function will block the close until one of the following: * 1. TX count are 0 * 2. The mos7840 has stopped - * 3. A timout of 3 seconds without activity has expired + * 3. A timeout of 3 seconds without activity has expired * ************************************************************************/ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port) @@ -1161,7 +1161,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port) dbg("%s - TIMEOUT", __FUNCTION__); return; } else { - /* Reset timout value back to seconds */ + /* Reset timeout value back to seconds */ wait = 30; } } @@ -1275,7 +1275,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp) * * This function will block the close until one of the following: * 1. Response to our Chase comes from mos7840 - * 2. A timout of 10 seconds without activity has expired + * 2. A timeout of 10 seconds without activity has expired * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/ @@ -1304,7 +1304,7 @@ static void mos7840_block_until_chase_response(struct moschip_port dbg("%s - TIMEOUT", __FUNCTION__); return; } else { - /* Reset timout value back to seconds */ + /* Reset timeout value back to seconds */ wait = 10; } } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d1185f53447..5e8bf1bc1e5 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -180,6 +180,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */ + { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */ { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, @@ -640,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp) portdata->dtr_state = 0; if (serial->dev) { - option_send_setup(port); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + option_send_setup(port); + mutex_unlock(&serial->disc_mutex); /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index eea226ae37b..a3847d6c946 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -79,7 +79,7 @@ static int debug; #define PL2303_BUF_SIZE 1024 #define PL2303_TMP_BUF_SIZE 1024 -struct pl2303_buf { +struct oti6858_buf { unsigned int buf_size; char *buf_buf; char *buf_get; @@ -161,14 +161,14 @@ static int oti6858_startup(struct usb_serial *serial); static void oti6858_shutdown(struct usb_serial *serial); /* functions operating on buffers */ -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size); -static void pl2303_buf_free(struct pl2303_buf *pb); -static void pl2303_buf_clear(struct pl2303_buf *pb); -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, +static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); +static void oti6858_buf_free(struct oti6858_buf *pb); +static void oti6858_buf_clear(struct oti6858_buf *pb); +static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb); +static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb); +static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, unsigned int count); -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, +static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, unsigned int count); @@ -203,7 +203,7 @@ static struct usb_serial_driver oti6858_device = { struct oti6858_private { spinlock_t lock; - struct pl2303_buf *buf; + struct oti6858_buf *buf; struct oti6858_control_pkt status; struct { @@ -316,7 +316,7 @@ void send_data(struct work_struct *work) } priv->flags.write_urb_in_use = 1; - count = pl2303_buf_data_avail(priv->buf); + count = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); if (count > port->bulk_out_size) count = port->bulk_out_size; @@ -345,7 +345,7 @@ void send_data(struct work_struct *work) } spin_lock_irqsave(&priv->lock, flags); - pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count); + oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count); spin_unlock_irqrestore(&priv->lock, flags); port->write_urb->transfer_buffer_length = count; @@ -370,7 +370,7 @@ static int oti6858_startup(struct usb_serial *serial) priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); if (!priv) break; - priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); + priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE); if (priv->buf == NULL) { kfree(priv); break; @@ -391,7 +391,7 @@ static int oti6858_startup(struct usb_serial *serial) for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); - pl2303_buf_free(priv->buf); + oti6858_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -410,7 +410,7 @@ static int oti6858_write(struct usb_serial_port *port, return count; spin_lock_irqsave(&priv->lock, flags); - count = pl2303_buf_put(priv->buf, buf, count); + count = oti6858_buf_put(priv->buf, buf, count); spin_unlock_irqrestore(&priv->lock, flags); return count; @@ -425,7 +425,7 @@ static int oti6858_write_room(struct usb_serial_port *port) dbg("%s(port = %d)", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); - room = pl2303_buf_space_avail(priv->buf); + room = oti6858_buf_space_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); return room; @@ -440,7 +440,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port) dbg("%s(port = %d)", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); - chars = pl2303_buf_data_avail(priv->buf); + chars = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); return chars; @@ -458,7 +458,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, dbg("%s(port = %d)", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s(): no tty structures", __FUNCTION__); return; } @@ -468,6 +468,8 @@ static void oti6858_set_termios(struct usb_serial_port *port, *(port->tty->termios) = tty_std_termios; port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; priv->flags.termios_initialized = 1; + port->tty->termios->c_ispeed = 38400; + port->tty->termios->c_ospeed = 38400; } spin_unlock_irqrestore(&priv->lock, flags); @@ -504,19 +506,14 @@ static void oti6858_set_termios(struct usb_serial_port *port, br = tty_get_baud_rate(port->tty); if (br == 0) { divisor = 0; - } else if (br <= OTI6858_MAX_BAUD_RATE) { + } else { int real_br; + br = min(br, OTI6858_MAX_BAUD_RATE); divisor = (96000000 + 8 * br) / (16 * br); real_br = 96000000 / (16 * divisor); - if ((((real_br - br) * 100 + br - 1) / br) > 2) { - dbg("%s(): baud rate %d is invalid", __FUNCTION__, br); - return; - } divisor = cpu_to_le16(divisor); - } else { - dbg("%s(): baud rate %d is too high", __FUNCTION__, br); - return; + tty_encode_baud_rate(port->tty, real_br, real_br); } frame_fmt &= ~FMT_STOP_BITS_MASK; @@ -650,9 +647,9 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) dbg("%s(): entering wait loop", __FUNCTION__); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (pl2303_buf_data_avail(priv->buf) == 0 + if (oti6858_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->serial->interface)) /* disconnect */ + || port->serial->disconnected) break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); @@ -663,7 +660,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) dbg("%s(): after wait loop", __FUNCTION__); /* clear out any remaining data in the buffer */ - pl2303_buf_clear(priv->buf); + oti6858_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); /* wait for characters to drain from the device */ @@ -831,21 +828,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, return -EFAULT; return oti6858_tiocmset(port, NULL, 0, x); - case TIOCGSERIAL: - if (copy_to_user(user_arg, port->tty->termios, - sizeof(struct ktermios))) { - return -EFAULT; - } - return 0; - - case TIOCSSERIAL: - if (copy_from_user(port->tty->termios, user_arg, - sizeof(struct ktermios))) { - return -EFAULT; - } - oti6858_set_termios(port, NULL); - return 0; - case TIOCMIWAIT: dbg("%s(): TIOCMIWAIT", __FUNCTION__); return wait_modem_info(port, arg); @@ -887,7 +869,7 @@ static void oti6858_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); if (priv) { - pl2303_buf_free(priv->buf); + oti6858_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -987,7 +969,7 @@ static void oti6858_read_int_callback(struct urb *urb) spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use == 0 - && pl2303_buf_data_avail(priv->buf) != 0) { + && oti6858_buf_data_avail(priv->buf) != 0) { schedule_delayed_work(&priv->delayed_write_work,0); resubmit = 0; } @@ -1015,9 +997,8 @@ static void oti6858_read_bulk_callback(struct urb *urb) struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; - int i, result; int status = urb->status; - char tty_flag; + int result; dbg("%s(port = %d, status = %d)", __FUNCTION__, port->number, status); @@ -1045,27 +1026,9 @@ static void oti6858_read_bulk_callback(struct urb *urb) return; } - // get tty_flag from status - tty_flag = TTY_NORMAL; - -/* FIXME: probably, errors will be signalled using interrupt pipe! */ -/* - // break takes precedence over parity, - // which takes precedence over framing errors - if (status & UART_BREAK_ERROR ) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag); -*/ - tty = port->tty; if (tty != NULL && urb->actual_length > 0) { - tty_buffer_request_room(tty, urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) - tty_insert_flip_char(tty, data[i], tty_flag); + tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } @@ -1133,18 +1096,18 @@ static void oti6858_write_bulk_callback(struct urb *urb) /* - * pl2303_buf_alloc + * oti6858_buf_alloc * * Allocate a circular buffer and all associated memory. */ -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) +static struct oti6858_buf *oti6858_buf_alloc(unsigned int size) { - struct pl2303_buf *pb; + struct oti6858_buf *pb; if (size == 0) return NULL; - pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL); if (pb == NULL) return NULL; @@ -1161,11 +1124,11 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) } /* - * pl2303_buf_free + * oti6858_buf_free * * Free the buffer and all associated memory. */ -static void pl2303_buf_free(struct pl2303_buf *pb) +static void oti6858_buf_free(struct oti6858_buf *pb) { if (pb) { kfree(pb->buf_buf); @@ -1174,11 +1137,11 @@ static void pl2303_buf_free(struct pl2303_buf *pb) } /* - * pl2303_buf_clear + * oti6858_buf_clear * * Clear out all data in the circular buffer. */ -static void pl2303_buf_clear(struct pl2303_buf *pb) +static void oti6858_buf_clear(struct oti6858_buf *pb) { if (pb != NULL) { /* equivalent to a get of all data available */ @@ -1187,12 +1150,12 @@ static void pl2303_buf_clear(struct pl2303_buf *pb) } /* - * pl2303_buf_data_avail + * oti6858_buf_data_avail * * Return the number of bytes of data available in the circular * buffer. */ -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) +static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb) { if (pb == NULL) return 0; @@ -1200,12 +1163,12 @@ static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) } /* - * pl2303_buf_space_avail + * oti6858_buf_space_avail * * Return the number of bytes of space available in the circular * buffer. */ -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) +static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb) { if (pb == NULL) return 0; @@ -1213,14 +1176,14 @@ static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) } /* - * pl2303_buf_put + * oti6858_buf_put * * Copy data data from a user buffer and put it into the circular buffer. * Restrict to the amount of space available. * * Return the number of bytes copied. */ -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, +static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, unsigned int count) { unsigned int len; @@ -1228,7 +1191,7 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, if (pb == NULL) return 0; - len = pl2303_buf_space_avail(pb); + len = oti6858_buf_space_avail(pb); if (count > len) count = len; @@ -1252,14 +1215,14 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, } /* - * pl2303_buf_get + * oti6858_buf_get * * Get data from the circular buffer and copy to the given buffer. * Restrict to the amount of data available. * * Return the number of bytes copied. */ -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, +static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, unsigned int count) { unsigned int len; @@ -1267,7 +1230,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, if (pb == NULL) return 0; - len = pl2303_buf_data_avail(pb); + len = oti6858_buf_data_avail(pb); if (count > len) count = len; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 0da1df9c79b..ae3ec1a6400 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, @@ -84,9 +85,10 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -97,7 +99,10 @@ static struct usb_driver pl2303_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, .no_dynamic_id = 1, + .supports_autosuspend = 1, }; #define SET_LINE_REQUEST_TYPE 0x21 @@ -310,12 +315,39 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, return count; } +static int pl2303_vendor_read(__u16 value, __u16 index, + struct usb_serial *serial, unsigned char *buf) +{ + int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, + value, index, buf, 1, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, + VENDOR_READ_REQUEST, value, index, res, buf[0]); + return res; +} + +static int pl2303_vendor_write(__u16 value, __u16 index, + struct usb_serial *serial) +{ + int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, + value, index, NULL, 0, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, + VENDOR_WRITE_REQUEST, value, index, res); + return res; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_private *priv; enum pl2303_type type = type_0; + unsigned char *buf; int i; + buf = kmalloc(10, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + if (serial->dev->descriptor.bDeviceClass == 0x02) type = type_0; else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) @@ -340,9 +372,27 @@ static int pl2303_startup(struct usb_serial *serial) priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } + + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 0, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 1, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_write(0, 1, serial); + pl2303_vendor_write(1, 0, serial); + if (type == HX) + pl2303_vendor_write(2, 0x44, serial); + else + pl2303_vendor_write(2, 0x24, serial); + + kfree(buf); return 0; cleanup: + kfree(buf); for (--i; i>=0; --i) { priv = usb_get_serial_port_data(serial->port[i]); pl2303_buf_free(priv->buf); @@ -582,24 +632,12 @@ static void pl2303_set_termios(struct usb_serial_port *port, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { - __u16 index; if (priv->type == HX) - index = 0x61; + pl2303_vendor_write(0x0, 0x61, serial); else - index = 0x41; - i = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, - VENDOR_WRITE_REQUEST_TYPE, - 0x0, index, NULL, 0, 100); - dbg("0x40:0x1:0x0:0x%x %d", index, i); + pl2303_vendor_write(0x0, 0x41, serial); } else { - i = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, - VENDOR_WRITE_REQUEST_TYPE, - 0x0, 0x0, NULL, 0, 100); - dbg ("0x40:0x1:0x0:0x0 %d", i); + pl2303_vendor_write(0x0, 0x0, serial); } /* FIXME: Need to read back resulting baud rate */ @@ -629,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp) set_current_state(TASK_INTERRUPTIBLE); if (pl2303_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) || - !usb_get_intfdata(port->serial->interface)) /* disconnect */ + port->serial->disconnected) break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); @@ -678,7 +716,6 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp) struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned char *buf; int result; dbg("%s - port %d", __FUNCTION__, port->number); @@ -686,45 +723,12 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp) if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - } - - buf = kmalloc(10, GFP_KERNEL); - if (buf==NULL) - return -ENOMEM; - -#define FISH(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ - b, a, c, d, buf, 1, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]); - -#define SOUP(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ - b, a, c, d, NULL, 0, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); - - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); - - if (priv->type == HX) { - /* HX chip */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); - /* reset upstream data pipes */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); } else { - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); + /* reset upstream data pipes */ + pl2303_vendor_write(8, 0, serial); + pl2303_vendor_write(9, 0, serial); } - kfree(buf); - /* Setup termios */ if (port->tty) { pl2303_set_termios(port, &tmp_termios); diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index d31f5d29998..237a41f6638 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -35,6 +35,7 @@ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID 0xb000 +#define RATOC_PRODUCT_ID_USB60F 0xb020 #define TRIPP_VENDOR_ID 0x2478 #define TRIPP_PRODUCT_ID 0x2008 @@ -96,10 +97,6 @@ #define ALCOR_VENDOR_ID 0x058F #define ALCOR_PRODUCT_ID 0x9720 -/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */ -#define HUAWEI_VENDOR_ID 0x12d1 -#define HUAWEI_PRODUCT_ID 0x1001 - /* Willcom WS002IN Data Driver (by NetIndex Inc.) */ #define WS002IN_VENDOR_ID 0x11f6 #define WS002IN_PRODUCT_ID 0x2001 @@ -107,3 +104,11 @@ /* Corega CG-USBRS232R Serial Adapter */ #define COREGA_VENDOR_ID 0x07aa #define COREGA_PRODUCT_ID 0x002a + +/* HL HL-340 (ID: 4348:5523) */ +#define HL340_VENDOR_ID 0x4348 +#define HL340_PRODUCT_ID 0x5523 + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index c295d0495f9..4c925e3e8a6 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,7 +1,7 @@ /* USB Driver for Sierra Wireless - Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com> + Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com> IMPORTANT DISCLAIMER: This driver is not commercially supported by Sierra Wireless. Use at your own risk. @@ -14,7 +14,7 @@ Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> */ -#define DRIVER_VERSION "v.1.2.5b" +#define DRIVER_VERSION "v.1.2.7" #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -26,10 +26,12 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/usb/ch9.h> +#define SWIMS_USB_REQUEST_SetPower 0x00 +#define SWIMS_USB_REQUEST_SetNmea 0x07 #define SWIMS_USB_REQUEST_SetMode 0x0B -#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40 -#define SWIMS_USB_INDEX_SetMode 0x0000 +#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40 #define SWIMS_SET_MODE_Modem 0x0001 /* per port private data */ @@ -38,6 +40,8 @@ #define IN_BUFLEN 4096 static int debug; +static int nmea; +static int truinstall = 1; enum devicetype { DEVICE_3_PORT = 0, @@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) int result; dev_dbg(&udev->dev, "%s", "SET POWER STATE\n"); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x00, /* __u8 request */ - 0x40, /* __u8 request type */ - swiState, /* __u16 value */ - 0, /* __u16 index */ - NULL, /* void *data */ - 0, /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ + SWIMS_USB_REQUEST_SetPower, /* __u8 request */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + swiState, /* __u16 value */ + 0, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ return result; } -static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode) +static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode) { int result; dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n"); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetMode, /* __u8 request */ - SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */ - eSocMode, /* __u16 value */ - SWIMS_USB_INDEX_SetMode, /* __u16 index */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + eSWocMode, /* __u16 value */ + 0x0000, /* __u16 index */ NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ return result; } -static int sierra_probe(struct usb_interface *iface, - const struct usb_device_id *id) +static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) +{ + int result; + dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n"); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + enable, /* __u16 value */ + 0x0000, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ + return result; +} + +static int sierra_calc_num_ports(struct usb_serial *serial) { int result; + int *num_ports = usb_get_serial_data(serial); + + result = *num_ports; + + if (result) { + kfree(num_ports); + usb_set_serial_data(serial, NULL); + } + + return result; +} + +static int sierra_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + int result = 0; struct usb_device *udev; + int *num_ports; + u8 ifnum; + + num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL); + if (!num_ports) + return -ENOMEM; - udev = usb_get_dev(interface_to_usbdev(iface)); + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + udev = serial->dev; /* Check if in installer mode */ - if (id->driver_info == DEVICE_INSTALLER) { - dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n"); + if (truinstall && id->driver_info == DEVICE_INSTALLER) { + dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n"); result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); - /*We do not want to bind to the device when in installer mode*/ + /* Don't bind to the device when in installer mode */ + kfree(num_ports); return -EIO; - } + } else if (id->driver_info == DEVICE_1_PORT) + *num_ports = 1; + else if (ifnum == 0x99) + *num_ports = 0; + else + *num_ports = 3; + /* + * save off our num_ports info so that we can use it in the + * calc_num_ports callback + */ + usb_set_serial_data(serial, (void *)num_ports); - return usb_serial_probe(iface, id); + return result; } static struct usb_device_id id_table [] = { @@ -104,6 +156,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ + { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ @@ -117,56 +170,29 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */ + { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */ + { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */ + + { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */ + { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */ { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */ { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */ + { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */ { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER}, { } }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_device_id id_table_1port [] = { - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ - { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ - { } -}; - -static struct usb_device_id id_table_3port [] = { - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ - { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/ - - { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ - { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */ - { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ - { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ - { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ - { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ - { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */ - { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */ - { } -}; - static struct usb_driver sierra_driver = { .name = "sierra", - .probe = sierra_probe, + .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, .no_dynamic_id = 1, }; - struct sierra_port_private { spinlock_t lock; /* lock the structure */ int outstanding_urbs; /* number of out urbs in flight */ @@ -188,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; + __u16 interface = 0; dbg("%s", __FUNCTION__); @@ -200,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port) if (portdata->rts_state) val |= 0x02; + /* Determine which port is targeted */ + if (port->bulk_out_endpointAddress == 2) + interface = 0; + else if (port->bulk_out_endpointAddress == 4) + interface = 1; + else if (port->bulk_out_endpointAddress == 5) + interface = 2; + return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + 0x22, 0x21, val, interface, + NULL, 0, USB_CTRL_SET_TIMEOUT); } return 0; @@ -561,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp) portdata->dtr_state = 0; if (serial->dev) { - sierra_send_setup(port); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + sierra_send_setup(port); + mutex_unlock(&serial->disc_mutex); /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) @@ -583,9 +622,13 @@ static int sierra_startup(struct usb_serial *serial) dbg("%s", __FUNCTION__); - /*Set Device mode to D0 */ + /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); + /* Check NMEA and set */ + if (nmea) + sierra_vsc_set_nmea(serial->dev, 1); + /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -646,47 +689,19 @@ static void sierra_shutdown(struct usb_serial *serial) } } -static struct usb_serial_driver sierra_1port_device = { +static struct usb_serial_driver sierra_device = { .driver = { .owner = THIS_MODULE, .name = "sierra1", }, - .description = "Sierra USB modem (1 port)", - .id_table = id_table_1port, - .usb_driver = &sierra_driver, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = sierra_open, - .close = sierra_close, - .write = sierra_write, - .write_room = sierra_write_room, - .chars_in_buffer = sierra_chars_in_buffer, - .throttle = sierra_rx_throttle, - .unthrottle = sierra_rx_unthrottle, - .ioctl = sierra_ioctl, - .set_termios = sierra_set_termios, - .break_ctl = sierra_break_ctl, - .tiocmget = sierra_tiocmget, - .tiocmset = sierra_tiocmset, - .attach = sierra_startup, - .shutdown = sierra_shutdown, - .read_int_callback = sierra_instat_callback, -}; - -static struct usb_serial_driver sierra_3port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sierra3", - }, - .description = "Sierra USB modem (3 port)", - .id_table = id_table_3port, + .description = "Sierra USB modem", + .id_table = id_table, .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 3, - .num_bulk_out = 3, - .num_ports = 3, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .calc_num_ports = sierra_calc_num_ports, + .probe = sierra_probe, .open = sierra_open, .close = sierra_close, .write = sierra_write, @@ -708,12 +723,9 @@ static struct usb_serial_driver sierra_3port_device = { static int __init sierra_init(void) { int retval; - retval = usb_serial_register(&sierra_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_serial_register(&sierra_3port_device); + retval = usb_serial_register(&sierra_device); if (retval) - goto failed_3port_device_register; + goto failed_device_register; retval = usb_register(&sierra_driver); @@ -725,18 +737,15 @@ static int __init sierra_init(void) return 0; failed_driver_register: - usb_serial_deregister(&sierra_3port_device); -failed_3port_device_register: - usb_serial_deregister(&sierra_1port_device); -failed_1port_device_register: + usb_serial_deregister(&sierra_device); +failed_device_register: return retval; } static void __exit sierra_exit(void) { usb_deregister (&sierra_driver); - usb_serial_deregister(&sierra_1port_device); - usb_serial_deregister(&sierra_3port_device); + usb_serial_deregister(&sierra_device); } module_init(sierra_init); @@ -747,6 +756,12 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); +module_param(truinstall, bool, 0); +MODULE_PARM_DESC(truinstall, "TRU-Install support"); + +module_param(nmea, bool, 0); +MODULE_PARM_DESC(nmea, "NMEA streaming"); + #ifdef CONFIG_USB_DEBUG module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 1f0149495fb..b517f93352e 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -80,6 +80,7 @@ #include <linux/ioctl.h> #include <linux/serial.h> #include <linux/circ_buf.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #include <linux/usb.h> @@ -139,7 +140,7 @@ struct ti_port { }; struct ti_device { - struct semaphore td_open_close_sem; + struct mutex td_open_close_lock; int td_open_port_count; struct usb_serial *td_serial; int td_is_3410; @@ -424,7 +425,7 @@ static int ti_startup(struct usb_serial *serial) dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } - sema_init(&tdev->td_open_close_sem, 1); + mutex_init(&tdev->td_open_close_lock); tdev->td_serial = serial; usb_set_serial_data(serial, tdev); @@ -547,7 +548,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) tdev = tport->tp_tdev; /* only one open on any port on a device at a time */ - if (down_interruptible(&tdev->td_open_close_sem)) + if (mutex_lock_interruptible(&tdev->td_open_close_lock)) return -ERESTARTSYS; if (port->tty) @@ -568,7 +569,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) if (!urb) { dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__); status = -EINVAL; - goto up_sem; + goto release_lock; } urb->complete = ti_interrupt_callback; urb->context = tdev; @@ -576,11 +577,11 @@ static int ti_open(struct usb_serial_port *port, struct file *file) status = usb_submit_urb(urb, GFP_KERNEL); if (status) { dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status); - goto up_sem; + goto release_lock; } } - ti_set_termios(port, NULL); + ti_set_termios(port, port->tty->termios); dbg("%s - sending TI_OPEN_PORT", __FUNCTION__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -617,7 +618,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) usb_clear_halt(dev, port->write_urb->pipe); usb_clear_halt(dev, port->read_urb->pipe); - ti_set_termios(port, NULL); + ti_set_termios(port, port->tty->termios); dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -656,13 +657,13 @@ static int ti_open(struct usb_serial_port *port, struct file *file) tport->tp_is_open = 1; ++tdev->td_open_port_count; - goto up_sem; + goto release_lock; unlink_int_urb: if (tdev->td_open_port_count == 0) usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -up_sem: - up(&tdev->td_open_close_sem); +release_lock: + mutex_unlock(&tdev->td_open_close_lock); dbg("%s - exit %d", __FUNCTION__, status); return status; } @@ -674,7 +675,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file) struct ti_port *tport; int port_number; int status; - int do_up; + int do_unlock; dbg("%s - port %d", __FUNCTION__, port->number); @@ -699,16 +700,16 @@ static void ti_close(struct usb_serial_port *port, struct file *file) if (status) dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status); - /* if down is interrupted, continue anyway */ - do_up = !down_interruptible(&tdev->td_open_close_sem); + /* if mutex_lock is interrupted, continue anyway */ + do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); --tport->tp_tdev->td_open_port_count; if (tport->tp_tdev->td_open_port_count <= 0) { /* last port is closed, shut down interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); tport->tp_tdev->td_open_port_count = 0; } - if (do_up) - up(&tdev->td_open_close_sem); + if (do_unlock) + mutex_unlock(&tdev->td_open_close_lock); dbg("%s - exit", __FUNCTION__); } @@ -896,24 +897,11 @@ static void ti_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!tty || !tty->termios) { - dbg("%s - no tty or termios", __FUNCTION__); - return; - } - cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; - if (old_termios && cflag == old_termios->c_cflag - && iflag == old_termios->c_iflag) { - dbg("%s - nothing to change", __FUNCTION__); - return; - } - - dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag); - - if (old_termios) - dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag); + dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag); + dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag); if (tport == NULL) return; @@ -947,6 +935,9 @@ static void ti_set_termios(struct usb_serial_port *port, break; } + /* CMSPAR isn't supported by this driver */ + tty->termios->c_cflag &= ~CMSPAR; + if (cflag & PARENB) { if (cflag & PARODD) { config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; @@ -989,12 +980,17 @@ static void ti_set_termios(struct usb_serial_port *port, } baud = tty_get_baud_rate(tty); - if (!baud) baud = 9600; + if (!baud) + baud = 9600; if (tport->tp_tdev->td_is_3410) config->wBaudRate = (__u16)((923077 + baud/2) / baud); else config->wBaudRate = (__u16)((461538 + baud/2) / baud); + /* FIXME: Should calculate resulting baud here and report it back */ + if ((cflag & CBAUD) != B0) + tty_encode_baud_rate(tty, baud, baud); + dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", __FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); @@ -1497,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) struct ti_device *tdev = tport->tp_tdev; struct usb_serial_port *port = tport->tp_port; wait_queue_t wait; - unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); - spin_lock_irqsave(&tport->tp_lock, flags); + spin_lock_irq(&tport->tp_lock); /* wait for data to drain from the buffer */ tdev->td_urb_error = 0; @@ -1512,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) if (ti_buf_data_avail(tport->tp_write_buf) == 0 || timeout == 0 || signal_pending(current) || tdev->td_urb_error - || !usb_get_intfdata(port->serial->interface)) /* disconnect */ + || port->serial->disconnected) /* disconnect */ break; - spin_unlock_irqrestore(&tport->tp_lock, flags); + spin_unlock_irq(&tport->tp_lock); timeout = schedule_timeout(timeout); - spin_lock_irqsave(&tport->tp_lock, flags); + spin_lock_irq(&tport->tp_lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&tport->tp_write_wait, &wait); @@ -1525,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) if (flush) ti_buf_clear(tport->tp_write_buf); - spin_unlock_irqrestore(&tport->tp_lock, flags); + spin_unlock_irq(&tport->tp_lock); + mutex_lock(&port->serial->disc_mutex); /* wait for data to drain from the device */ /* wait for empty tx register, plus 20 ms */ timeout += jiffies; tport->tp_lsr &= ~TI_LSR_TX_EMPTY; while ((long)(jiffies - timeout) < 0 && !signal_pending(current) && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error - && usb_get_intfdata(port->serial->interface)) { /* not disconnected */ + && !port->serial->disconnected) { if (ti_get_lsr(tport)) break; + mutex_unlock(&port->serial->disc_mutex); msleep_interruptible(20); + mutex_lock(&port->serial->disc_mutex); } + mutex_unlock(&port->serial->disc_mutex); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 497e29a700c..3ce98e8d7bc 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp) goto bailout_mutex_unlock; } + retval = usb_autopm_get_interface(serial->interface); + if (retval) + goto bailout_module_put; /* only call the device specific open if this * is the first time the port is opened */ retval = serial->type->open(port, filp); if (retval) - goto bailout_module_put; + goto bailout_interface_put; } mutex_unlock(&port->mutex); return 0; +bailout_interface_put: + usb_autopm_put_interface(serial->interface); bailout_module_put: module_put(serial->type->driver.owner); bailout_mutex_unlock: @@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp) } --port->open_count; - if (port->open_count == 0) { + if (port->open_count == 0) /* only call the device specific close if this * port is being closed by the last owner */ port->serial->type->close(port, filp); + if (port->open_count == (port->console? 1 : 0)) { if (port->tty) { if (port->tty->driver_data) port->tty->driver_data = NULL; port->tty = NULL; } + } + if (port->open_count == 0) { + usb_autopm_put_interface(port->serial->interface); module_put(port->serial->type->driver.owner); } @@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, serial->type = driver; serial->interface = interface; kref_init(&serial->kref); + mutex_init(&serial->disc_mutex); return serial; } @@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface) usb_serial_console_disconnect(serial); dbg ("%s", __FUNCTION__); + mutex_lock(&serial->disc_mutex); usb_set_intfdata (interface, NULL); - if (serial) { - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - if (port->tty) - tty_hangup(port->tty); - kill_traffic(port); - } + /* must set a flag, to signal subdrivers */ + serial->disconnected = 1; + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); } - /* let the last holder of this object - * cause it to be cleaned up */ - usb_serial_put(serial); } + /* let the last holder of this object + * cause it to be cleaned up */ + mutex_unlock(&serial->disc_mutex); + usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } @@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) struct usb_serial_port *port; int i, r = 0; - if (!serial) /* device has been disconnected */ - return 0; - for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) @@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); set_to_generic_if_null(device, shutdown); + set_to_generic_if_null(device, resume); } int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 7ee087fed91..22b3f78a388 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); - /* Try to send shutdown message, if the device is gone, this will just fail. */ - transfer_buffer = kmalloc (0x12, GFP_KERNEL); - if (transfer_buffer) { - usb_control_msg (port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - VISOR_CLOSE_NOTIFICATION, 0xc2, - 0x0000, 0x0000, - transfer_buffer, 0x12, 300); - kfree (transfer_buffer); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Try to send shutdown message, unless the device is gone */ + transfer_buffer = kmalloc (0x12, GFP_KERNEL); + if (transfer_buffer) { + usb_control_msg (port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0), + VISOR_CLOSE_NOTIFICATION, 0xc2, + 0x0000, 0x0000, + transfer_buffer, 0x12, 300); + kfree (transfer_buffer); + } } + mutex_unlock(&port->serial->disc_mutex); if (stats) dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n", diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index ee5dd8b5a71..38726ef3132 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -610,8 +610,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) if (retval) goto exit; - if (port->tty) - port->tty->low_latency = 1; + port->tty->low_latency = 1; /* send an open port command */ retval = firm_open(port); @@ -659,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) struct list_head *tmp2; dbg("%s - port %d", __FUNCTION__, port->number); - + + mutex_lock(&port->serial->disc_mutex); /* filp is NULL when called from usb_serial_disconnect */ - if (filp && (tty_hung_up_p(filp))) { + if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) { + mutex_unlock(&port->serial->disc_mutex); return; } + mutex_unlock(&port->serial->disc_mutex); port->tty->closing = 1; diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index ee5b42aa536..187dd1e0109 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -66,7 +66,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf; - int res, partial; + int res; + unsigned int partial; static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS"; US_DEBUGP("Sending UCR-61S2B initialization packet...\n"); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 0db488624ab..2ae1e8673b1 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -48,7 +48,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/hdreg.h> -#include <linux/ide.h> #include <linux/scatterlist.h> #include <scsi/scsi.h> @@ -110,6 +109,12 @@ #define REG_STATUS 0x80 #define REG_COMMAND 0x80 +/* ATA registers offset definitions */ +#define ATA_REG_ERROR_OFFSET 1 +#define ATA_REG_LCYL_OFFSET 4 +#define ATA_REG_HCYL_OFFSET 5 +#define ATA_REG_STATUS_OFFSET 7 + /* ATA error definitions not in <linux/hdreg.h> */ #define ATA_ERROR_MEDIA_CHANGE 0x20 @@ -360,7 +365,7 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; - unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; + unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET]; if(error & ATA_ERROR_MEDIA_CHANGE) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; @@ -549,8 +554,8 @@ static int isd200_read_regs( struct us_data *us ) retStatus = ISD200_ERROR; } else { memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); - US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", - info->ATARegs[IDE_ERROR_OFFSET]); + US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", + info->ATARegs[ATA_REG_ERROR_OFFSET]); } return retStatus; @@ -892,7 +897,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, break; if (!detect) { - if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) { + if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) { US_DEBUGP(" %s status is still BSY, try again...\n",mstr); } else { US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); @@ -902,12 +907,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* check for BUSY_STAT and */ /* WRERR_STAT (workaround ATA Zip drive) and */ /* ERR_STAT (workaround for Archos CD-ROM) */ - else if (regs[IDE_STATUS_OFFSET] & + else if (regs[ATA_REG_STATUS_OFFSET] & (BUSY_STAT | WRERR_STAT | ERR_STAT )) { US_DEBUGP(" Status indicates it is not ready, try again...\n"); } /* check for DRDY, ATA devices set DRDY after SRST */ - else if (regs[IDE_STATUS_OFFSET] & READY_STAT) { + else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) { US_DEBUGP(" Identified ATA device\n"); info->DeviceFlags |= DF_ATA_DEVICE; info->DeviceHead = master_slave; @@ -916,8 +921,8 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* check Cylinder High/Low to determine if it is an ATAPI device */ - else if ((regs[IDE_HCYL_OFFSET] == 0xEB) && - (regs[IDE_LCYL_OFFSET] == 0x14)) { + else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && + regs[ATA_REG_LCYL_OFFSET] == 0x14) { /* It seems that the RICOH MP6200A CD/RW drive will report itself okay as a @@ -1001,12 +1006,6 @@ static int isd200_manual_enum(struct us_data *us) return(retStatus); } -/* - * We are the last non IDE user of the legacy IDE ident structures - * and we thus want to keep a private copy of this function so the - * driver can be used without the obsolete drivers/ide layer - */ - static void isd200_fix_driveid (struct hd_driveid *id) { #ifndef __LITTLE_ENDIAN diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 6d6108b3993..fe12737e0e2 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -86,6 +86,14 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, US_SC_8070, US_PR_USBAT, init_usbat_cd, 0), #endif +/* Reported by Grant Grundler <grundler@parisc-linux.org> + * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware. + */ +UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001, + "HP", + "PhotoSmart R707", + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), + /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product) * for USB floppies that need the SINGLE_LUN enforcement. diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index d53bf6945f0..9b05da6268f 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -39,12 +39,7 @@ #include <linux/spinlock.h> #ifdef CONFIG_COMPAT -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10) -#include <linux/ioctl32.h> -#define SIS_OLD_CONFIG_COMPAT -#else #define SIS_NEW_CONFIG_COMPAT -#endif #endif /* CONFIG_COMPAT */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) @@ -607,9 +602,6 @@ struct sis_video_info { int haveXGIROM; int registered; int warncount; -#ifdef SIS_OLD_CONFIG_COMPAT - int ioctl32registered; -#endif int sisvga_engine; int hwcursor_size; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 37bd24b8d83..93ae747440c 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -5805,9 +5805,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ivideo->pcifunc = PCI_FUNC(pdev->devfn); ivideo->subsysvendor = pdev->subsystem_vendor; ivideo->subsysdevice = pdev->subsystem_device; -#ifdef SIS_OLD_CONFIG_COMPAT - ivideo->ioctl32registered = 0; -#endif #ifndef MODULE if(sisfb_mode_idx == -1) { @@ -6420,30 +6417,6 @@ error_3: vfree(ivideo->bios_abase); ivideo->next = card_list; card_list = ivideo; -#ifdef SIS_OLD_CONFIG_COMPAT - { - int ret; - /* Our ioctls are all "32/64bit compatible" */ - ret = register_ioctl32_conversion(FBIO_ALLOC, NULL); - ret |= register_ioctl32_conversion(FBIO_FREE, NULL); - ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL); - if(ret) - printk(KERN_ERR - "sisfb: Error registering ioctl32 translations\n"); - else - ivideo->ioctl32registered = 1; - } -#endif - printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n", ivideo->sisfb_accel ? "enabled" : "disabled", ivideo->sisfb_ypan ? @@ -6473,27 +6446,6 @@ static void __devexit sisfb_remove(struct pci_dev *pdev) int registered = ivideo->registered; int modechanged = ivideo->modechanged; -#ifdef SIS_OLD_CONFIG_COMPAT - if(ivideo->ioctl32registered) { - int ret; - ret = unregister_ioctl32_conversion(FBIO_ALLOC); - ret |= unregister_ioctl32_conversion(FBIO_FREE); - ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK); - ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE); - ret |= unregister_ioctl32_conversion(SISFB_GET_INFO); - ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET); - ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET); - ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK); - ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS); - ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE); - ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE); - ret |= unregister_ioctl32_conversion(SISFB_COMMAND); - if(ret) - printk(KERN_ERR - "sisfb: Error unregistering ioctl32 translations\n"); - } -#endif - /* Unmap */ iounmap(ivideo->mmio_vbase); iounmap(ivideo->video_vbase); diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h index 55b07bd5316..dc189f01c5b 100644 --- a/include/asm-arm/arch-at91/board.h +++ b/include/asm-arm/arch-at91/board.h @@ -40,7 +40,8 @@ /* USB Device */ struct at91_udc_data { u8 vbus_pin; /* high == host powering us */ - u8 pullup_pin; /* high == D+ pulled up */ + u8 pullup_pin; /* active == D+ pulled up */ + u8 pullup_active_low; /* true == pullup_pin is active low */ }; extern void __init at91_add_device_udc(struct at91_udc_data *data); diff --git a/include/asm-arm/mach/udc_pxa2xx.h b/include/asm-arm/mach/udc_pxa2xx.h index ff0a95715a0..f191e147ea9 100644 --- a/include/asm-arm/mach/udc_pxa2xx.h +++ b/include/asm-arm/mach/udc_pxa2xx.h @@ -19,7 +19,9 @@ struct pxa2xx_udc_mach_info { * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane * VBUS IRQ and omit the methods above. Store the GPIO number * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits. + * Note that sometimes the signals go through inverters... */ + bool gpio_vbus_inverted; u16 gpio_vbus; /* high == vbus present */ u16 gpio_pullup; /* high == pullup activated */ }; diff --git a/include/linux/aspm.h b/include/linux/aspm.h new file mode 100644 index 00000000000..f41a6989548 --- /dev/null +++ b/include/linux/aspm.h @@ -0,0 +1,44 @@ +/* + * aspm.h + * + * PCI Express ASPM defines and function prototypes + * + * Copyright (C) 2007 Intel Corp. + * Zhang Yanmin (yanmin.zhang@intel.com) + * Shaohua Li (shaohua.li@intel.com) + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI Express Specification + */ + +#ifndef LINUX_ASPM_H +#define LINUX_ASPM_H + +#include <linux/pci.h> + +#define PCIE_LINK_STATE_L0S 1 +#define PCIE_LINK_STATE_L1 2 +#define PCIE_LINK_STATE_CLKPM 4 + +#ifdef CONFIG_PCIEASPM +extern void pcie_aspm_init_link_state(struct pci_dev *pdev); +extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); +extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); +extern void pci_disable_link_state(struct pci_dev *pdev, int state); +#else +#define pcie_aspm_init_link_state(pdev) do {} while (0) +#define pcie_aspm_exit_link_state(pdev) do {} while (0) +#define pcie_aspm_pm_state_change(pdev) do {} while (0) +#define pci_disable_link_state(pdev, state) do {} while (0) +#endif + +#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */ +extern void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev); +extern void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev); +#else +#define pcie_aspm_create_sysfs_dev_files(pdev) do {} while (0) +#define pcie_aspm_remove_sysfs_dev_files(pdev) do {} while (0) +#endif +#endif /* LINUX_ASPM_H */ diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 936ef82ed76..3ba25065fa9 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -48,7 +48,15 @@ #ifdef CONFIG_ACPI extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags); -extern acpi_status pci_osc_support_set(u32 flags); +extern acpi_status __pci_osc_support_set(u32 flags, const char *hid); +static inline acpi_status pci_osc_support_set(u32 flags) +{ + return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING); +} +static inline acpi_status pcie_osc_support_set(u32 flags) +{ + return __pci_osc_support_set(flags, PCI_EXPRESS_ROOT_HID_STRING); +} #else #if !defined(AE_ERROR) typedef u32 acpi_status; @@ -57,6 +65,7 @@ typedef u32 acpi_status; static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) {return AE_ERROR;} static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} +static inline acpi_status pcie_osc_support_set(u32 flags) {return AE_ERROR;} #endif #endif /* _PCI_ACPI_H_ */ diff --git a/include/linux/pci.h b/include/linux/pci.h index ae1006322f8..4f96f1d94ac 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -28,7 +28,7 @@ * 7:3 = slot * 2:0 = function */ -#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) @@ -66,7 +66,6 @@ enum pci_mmap_state { #define PCI_DMA_FROMDEVICE 2 #define PCI_DMA_NONE 3 -#define DEVICE_COUNT_COMPATIBLE 4 #define DEVICE_COUNT_RESOURCE 12 typedef int __bitwise pci_power_t; @@ -129,6 +128,7 @@ struct pci_cap_saved_state { u32 data[0]; }; +struct pcie_link_state; /* * The pci_dev structure is used to describe PCI devices. */ @@ -164,13 +164,13 @@ struct pci_dev { this is D0-D3, D0 being fully functional, and D3 being off. */ +#ifdef CONFIG_PCIEASPM + struct pcie_link_state *link_state; /* ASPM link state. */ +#endif + pci_channel_state_t error_state; /* current connectivity state */ struct device dev; /* Generic device interface */ - /* device is compatible with these IDs */ - unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; - unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; - int cfg_size; /* Size of configuration space */ /* @@ -219,7 +219,7 @@ static inline int pci_channel_offline(struct pci_dev *pdev) } static inline struct pci_cap_saved_state *pci_find_saved_cap( - struct pci_dev *pci_dev,char cap) + struct pci_dev *pci_dev, char cap) { struct pci_cap_saved_state *tmp; struct hlist_node *pos; @@ -278,13 +278,13 @@ struct pci_bus { unsigned short bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */ pci_bus_flags_t bus_flags; /* Inherited by child busses */ struct device *bridge; - struct class_device class_dev; + struct device dev; struct bin_attribute *legacy_io; /* legacy I/O for this bus */ struct bin_attribute *legacy_mem; /* legacy mem */ }; #define pci_bus_b(n) list_entry(n, struct pci_bus, node) -#define to_pci_bus(n) container_of(n, struct pci_bus, class_dev) +#define to_pci_bus(n) container_of(n, struct pci_bus, dev) /* * Error values that may be returned by PCI functions. @@ -314,8 +314,8 @@ struct pci_raw_ops { extern struct pci_raw_ops *raw_pci_ops; struct pci_bus_region { - unsigned long start; - unsigned long end; + resource_size_t start; + resource_size_t end; }; struct pci_dynids { @@ -351,11 +351,10 @@ enum pci_ers_result { }; /* PCI bus error event callbacks */ -struct pci_error_handlers -{ +struct pci_error_handlers { /* PCI bus error detected on this device */ pci_ers_result_t (*error_detected)(struct pci_dev *dev, - enum pci_channel_state error); + enum pci_channel_state error); /* MMIO has been re-enabled, but not DMA */ pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev); @@ -390,7 +389,7 @@ struct pci_driver { struct pci_dynids dynids; }; -#define to_pci_driver(drv) container_of(drv,struct pci_driver, driver) +#define to_pci_driver(drv) container_of(drv, struct pci_driver, driver) /** * PCI_DEVICE - macro used to describe a specific pci device @@ -448,7 +447,7 @@ extern int no_pci_devices(void); void pcibios_fixup_bus(struct pci_bus *); int __must_check pcibios_enable_device(struct pci_dev *, int mask); -char *pcibios_setup (char *str); +char *pcibios_setup(char *str); /* Used only when drivers/pci/setup.c is used */ void pcibios_align_resource(void *, struct resource *, resource_size_t, @@ -459,8 +458,10 @@ void pcibios_update_irq(struct pci_dev *, int irq); extern struct pci_bus *pci_find_bus(int domain, int busnr); void pci_bus_add_devices(struct pci_bus *bus); -struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); -static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) +struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata); +static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, + void *sysdata) { struct pci_bus *root_bus; root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata); @@ -468,15 +469,18 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s pci_bus_add_devices(root_bus); return root_bus; } -struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); -struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); +struct pci_bus *pci_create_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata); +struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, + int busnr); int pci_scan_slot(struct pci_bus *bus, int devfn); -struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); +struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); unsigned int pci_scan_child_bus(struct pci_bus *bus); int __must_check pci_bus_add_device(struct pci_dev *dev); void pci_read_bridge_bases(struct pci_bus *child); -struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); +struct resource *pci_find_parent_resource(const struct pci_dev *dev, + struct resource *res); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); extern struct pci_dev *pci_dev_get(struct pci_dev *dev); extern void pci_dev_put(struct pci_dev *dev); @@ -489,15 +493,19 @@ extern void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ #ifdef CONFIG_PCI_LEGACY -struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); -struct pci_dev __deprecated *pci_find_slot (unsigned int bus, unsigned int devfn); +struct pci_dev __deprecated *pci_find_device(unsigned int vendor, + unsigned int device, + const struct pci_dev *from); +struct pci_dev __deprecated *pci_find_slot(unsigned int bus, + unsigned int devfn); #endif /* CONFIG_PCI_LEGACY */ -int pci_find_capability (struct pci_dev *dev, int cap); -int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); -int pci_find_ext_capability (struct pci_dev *dev, int cap); -int pci_find_ht_capability (struct pci_dev *dev, int ht_cap); -int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap); +int pci_find_capability(struct pci_dev *dev, int cap); +int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); +int pci_find_ext_capability(struct pci_dev *dev, int cap); +int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); +int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); +void pcie_wait_pending_transaction(struct pci_dev *dev); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, @@ -505,49 +513,58 @@ struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from); -struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, +struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); -struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn); -struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn); -struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from); +struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); +struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn); +struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); int pci_dev_present(const struct pci_device_id *ids); const struct pci_device_id *pci_find_present(const struct pci_device_id *ids); -int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); -int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); -int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val); -int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val); -int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val); -int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val); +int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, + int where, u8 *val); +int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, + int where, u16 *val); +int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, u32 *val); +int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, + int where, u8 val); +int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, + int where, u16 val); +int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, u32 val); static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) { - return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val); + return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val); } static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val) { - return pci_bus_read_config_word (dev->bus, dev->devfn, where, val); + return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); } -static inline int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val) +static inline int pci_read_config_dword(struct pci_dev *dev, int where, + u32 *val) { - return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val); + return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val); } static inline int pci_write_config_byte(struct pci_dev *dev, int where, u8 val) { - return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val); + return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val); } static inline int pci_write_config_word(struct pci_dev *dev, int where, u16 val) { - return pci_bus_write_config_word (dev->bus, dev->devfn, where, val); + return pci_bus_write_config_word(dev->bus, dev->devfn, where, val); } -static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val) +static inline int pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) { - return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); + return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); } int __must_check pci_enable_device(struct pci_dev *dev); -int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask); +int __must_check pci_enable_device_io(struct pci_dev *dev); +int __must_check pci_enable_device_mem(struct pci_dev *dev); int __must_check pci_reenable_device(struct pci_dev *); int __must_check pcim_enable_device(struct pci_dev *pdev); void pcim_pin_device(struct pci_dev *pdev); @@ -576,14 +593,11 @@ int pcie_set_readrq(struct pci_dev *dev, int rq); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i); -void pci_restore_bars(struct pci_dev *dev); int pci_select_bars(struct pci_dev *dev, unsigned long flags); /* ROM control related routines */ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); -void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); -void pci_remove_rom(struct pci_dev *pdev); size_t pci_get_rom_size(void __iomem *rom, size_t size); /* Power management related routines */ @@ -594,7 +608,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); /* Functions for PCI Hotplug drivers to use */ -int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); +int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ void pci_bus_assign_resources(struct pci_bus *bus); @@ -631,16 +645,18 @@ static inline int __must_check pci_register_driver(struct pci_driver *driver) return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); } -void pci_unregister_driver(struct pci_driver *); -void pci_remove_behind_bridge(struct pci_dev *); -struct pci_driver *pci_dev_driver(const struct pci_dev *); -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev); -int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); +void pci_unregister_driver(struct pci_driver *dev); +void pci_remove_behind_bridge(struct pci_dev *dev); +struct pci_driver *pci_dev_driver(const struct pci_dev *dev); +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev); +int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, + int pass); void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), void *userdata); int pci_cfg_space_size(struct pci_dev *dev); -unsigned char pci_bus_max_busnr(struct pci_bus* bus); +unsigned char pci_bus_max_busnr(struct pci_bus *bus); /* kmem_cache style wrapper around pci_alloc_consistent() */ @@ -669,19 +685,36 @@ struct msix_entry { #ifndef CONFIG_PCI_MSI -static inline int pci_enable_msi(struct pci_dev *dev) {return -1;} -static inline void pci_disable_msi(struct pci_dev *dev) {} -static inline int pci_enable_msix(struct pci_dev* dev, - struct msix_entry *entries, int nvec) {return -1;} -static inline void pci_disable_msix(struct pci_dev *dev) {} -static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} +static inline int pci_enable_msi(struct pci_dev *dev) +{ + return -1; +} + +static inline void pci_disable_msi(struct pci_dev *dev) +{ } + +static inline int pci_enable_msix(struct pci_dev *dev, + struct msix_entry *entries, int nvec) +{ + return -1; +} + +static inline void pci_disable_msix(struct pci_dev *dev) +{ } + +static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) +{ } + +static inline void pci_restore_msi_state(struct pci_dev *dev) +{ } #else extern int pci_enable_msi(struct pci_dev *dev); extern void pci_disable_msi(struct pci_dev *dev); -extern int pci_enable_msix(struct pci_dev* dev, +extern int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec); extern void pci_disable_msix(struct pci_dev *dev); extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); +extern void pci_restore_msi_state(struct pci_dev *dev); #endif #ifdef CONFIG_HT_IRQ @@ -702,7 +735,11 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev); extern int pci_domains_supported; #else enum { pci_domains_supported = 0 }; -static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } +static inline int pci_domain_nr(struct pci_bus *bus) +{ + return 0; +} + static inline int pci_proc_domain(struct pci_bus *bus) { return 0; @@ -716,67 +753,161 @@ static inline int pci_proc_domain(struct pci_bus *bus) * these as simple inline functions to avoid hair in drivers. */ -#define _PCI_NOP(o,s,t) \ - static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \ +#define _PCI_NOP(o, s, t) \ + static inline int pci_##o##_config_##s(struct pci_dev *dev, \ + int where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } -#define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ - _PCI_NOP(o,word,u16 x) \ - _PCI_NOP(o,dword,u32 x) + +#define _PCI_NOP_ALL(o, x) _PCI_NOP(o, byte, u8 x) \ + _PCI_NOP(o, word, u16 x) \ + _PCI_NOP(o, dword, u32 x) _PCI_NOP_ALL(read, *) _PCI_NOP_ALL(write,) -static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) -{ return NULL; } +static inline struct pci_dev *pci_find_device(unsigned int vendor, + unsigned int device, + const struct pci_dev *from) +{ + return NULL; +} -static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) -{ return NULL; } +static inline struct pci_dev *pci_find_slot(unsigned int bus, + unsigned int devfn) +{ + return NULL; +} static inline struct pci_dev *pci_get_device(unsigned int vendor, - unsigned int device, struct pci_dev *from) -{ return NULL; } + unsigned int device, + struct pci_dev *from) +{ + return NULL; +} static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor, - unsigned int device, struct pci_dev *from) -{ return NULL; } + unsigned int device, + struct pci_dev *from) +{ + return NULL; +} -static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, -unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from) -{ return NULL; } +static inline struct pci_dev *pci_get_subsys(unsigned int vendor, + unsigned int device, + unsigned int ss_vendor, + unsigned int ss_device, + struct pci_dev *from) +{ + return NULL; +} -static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) -{ return NULL; } +static inline struct pci_dev *pci_get_class(unsigned int class, + struct pci_dev *from) +{ + return NULL; +} #define pci_dev_present(ids) (0) #define no_pci_devices() (1) #define pci_find_present(ids) (NULL) #define pci_dev_put(dev) do { } while (0) -static inline void pci_set_master(struct pci_dev *dev) { } -static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -static inline void pci_disable_device(struct pci_dev *dev) { } -static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} -static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;} -static inline int pci_register_driver(struct pci_driver *drv) { return 0;} -static inline void pci_unregister_driver(struct pci_driver *drv) { } -static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } -static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; } -static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; } +static inline void pci_set_master(struct pci_dev *dev) +{ } + +static inline int pci_enable_device(struct pci_dev *dev) +{ + return -EIO; +} + +static inline void pci_disable_device(struct pci_dev *dev) +{ } + +static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) +{ + return -EIO; +} + +static inline int pci_assign_resource(struct pci_dev *dev, int i) +{ + return -EBUSY; +} + +static inline int __pci_register_driver(struct pci_driver *drv, + struct module *owner) +{ + return 0; +} + +static inline int pci_register_driver(struct pci_driver *drv) +{ + return 0; +} + +static inline void pci_unregister_driver(struct pci_driver *drv) +{ } + +static inline int pci_find_capability(struct pci_dev *dev, int cap) +{ + return 0; +} + +static inline int pci_find_next_capability(struct pci_dev *dev, u8 post, + int cap) +{ + return 0; +} + +static inline int pci_find_ext_capability(struct pci_dev *dev, int cap) +{ + return 0; +} + +static inline void pcie_wait_pending_transaction(struct pci_dev *dev) +{ } /* Power management related routines */ -static inline int pci_save_state(struct pci_dev *dev) { return 0; } -static inline int pci_restore_state(struct pci_dev *dev) { return 0; } -static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { return 0; } -static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; } -static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; } +static inline int pci_save_state(struct pci_dev *dev) +{ + return 0; +} + +static inline int pci_restore_state(struct pci_dev *dev) +{ + return 0; +} + +static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) +{ + return 0; +} + +static inline pci_power_t pci_choose_state(struct pci_dev *dev, + pm_message_t state) +{ + return PCI_D0; +} + +static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, + int enable) +{ + return 0; +} + +static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) +{ + return -EIO; +} -static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; } -static inline void pci_release_regions(struct pci_dev *dev) { } +static inline void pci_release_regions(struct pci_dev *dev) +{ } #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) -static inline void pci_block_user_cfg_access(struct pci_dev *dev) { } -static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { } +static inline void pci_block_user_cfg_access(struct pci_dev *dev) +{ } + +static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) +{ } static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) { return NULL; } @@ -797,27 +928,27 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, /* these helpers provide future and backwards compatibility * for accessing popular PCI BAR info */ -#define pci_resource_start(dev,bar) ((dev)->resource[(bar)].start) -#define pci_resource_end(dev,bar) ((dev)->resource[(bar)].end) -#define pci_resource_flags(dev,bar) ((dev)->resource[(bar)].flags) +#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) +#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end) +#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags) #define pci_resource_len(dev,bar) \ - ((pci_resource_start((dev),(bar)) == 0 && \ - pci_resource_end((dev),(bar)) == \ - pci_resource_start((dev),(bar))) ? 0 : \ - \ - (pci_resource_end((dev),(bar)) - \ - pci_resource_start((dev),(bar)) + 1)) + ((pci_resource_start((dev), (bar)) == 0 && \ + pci_resource_end((dev), (bar)) == \ + pci_resource_start((dev), (bar))) ? 0 : \ + \ + (pci_resource_end((dev), (bar)) - \ + pci_resource_start((dev), (bar)) + 1)) /* Similar to the helpers above, these manipulate per-pci_dev * driver-specific data. They are really just a wrapper around * the generic device structure functions of these calls. */ -static inline void *pci_get_drvdata (struct pci_dev *pdev) +static inline void *pci_get_drvdata(struct pci_dev *pdev) { return dev_get_drvdata(&pdev->dev); } -static inline void pci_set_drvdata (struct pci_dev *pdev, void *data) +static inline void pci_set_drvdata(struct pci_dev *pdev, void *data) { dev_set_drvdata(&pdev->dev, data); } @@ -836,7 +967,7 @@ static inline char *pci_name(struct pci_dev *pdev) */ #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, resource_size_t *start, + const struct resource *rsrc, resource_size_t *start, resource_size_t *end) { *start = rsrc->start; @@ -888,9 +1019,9 @@ enum pci_fixup_pass { void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); -void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); +void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); -void __iomem * const * pcim_iomap_table(struct pci_dev *pdev); +void __iomem * const *pcim_iomap_table(struct pci_dev *pdev); int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name); void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index c1914a8b94a..c0c1223c919 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -395,9 +395,17 @@ #define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ #define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ +#define PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */ +#define PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */ +#define PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */ +#define PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */ #define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_RL 0x20 /* Retrain Link */ +#define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */ #define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ #define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */ +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCTL 24 /* Slot Control */ #define PCI_EXP_SLTSTA 26 /* Slot Status */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 5fc8ff73b7b..2372e2e6b52 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -162,19 +162,19 @@ struct usb_interface { unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ struct device dev; /* interface specific device info */ - struct device *usb_dev; /* pointer to the usb class's device, if any */ + struct device *usb_dev; int pm_usage_cnt; /* usage counter for autosuspend */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ container_of(intf->dev.parent, struct usb_device, dev) -static inline void *usb_get_intfdata (struct usb_interface *intf) +static inline void *usb_get_intfdata(struct usb_interface *intf) { - return dev_get_drvdata (&intf->dev); + return dev_get_drvdata(&intf->dev); } -static inline void usb_set_intfdata (struct usb_interface *intf, void *data) +static inline void usb_set_intfdata(struct usb_interface *intf, void *data) { dev_set_drvdata(&intf->dev, data); } @@ -275,9 +275,10 @@ struct usb_host_config { int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr); -#define usb_get_extra_descriptor(ifpoint,type,ptr)\ - __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\ - type,(void**)ptr) +#define usb_get_extra_descriptor(ifpoint, type, ptr) \ + __usb_get_extra_descriptor((ifpoint)->extra, \ + (ifpoint)->extralen, \ + type, (void **)ptr) /* ----------------------------------------------------------------------- */ @@ -318,7 +319,7 @@ struct usb_bus { #ifdef CONFIG_USB_DEVICEFS struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ #endif - struct class_device *class_dev; /* class device for this bus */ + struct device *dev; /* device for this bus */ #if defined(CONFIG_USB_MON) struct mon_bus *mon_bus; /* non-null when associated */ @@ -388,7 +389,7 @@ struct usb_device { unsigned can_submit:1; /* URBs may be submitted */ unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ - unsigned authorized:1; /* Policy has determined we can use it */ + unsigned authorized:1; /* Policy has said we can use it */ unsigned wusb:1; /* Device is Wireless USB */ int string_langid; /* language ID for strings */ @@ -417,7 +418,10 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ u32 quirks; /* quirks of the whole device */ - atomic_t urbnum; /* number of URBs submitted for the whole device */ + atomic_t urbnum; /* number of URBs submitted for + the whole device */ + + unsigned long active_duration; /* total time device is not suspended */ #ifdef CONFIG_PM struct delayed_work autosuspend; /* for delayed autosuspends */ @@ -425,6 +429,7 @@ struct usb_device { unsigned long last_busy; /* time of last use */ int autosuspend_delay; /* in jiffies */ + unsigned long connect_time; /* time device was first connected */ unsigned auto_pm:1; /* autosuspend/resume in progress */ unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */ @@ -498,11 +503,11 @@ static inline void usb_mark_last_busy(struct usb_device *udev) /*-------------------------------------------------------------------------*/ /* for drivers using iso endpoints */ -extern int usb_get_current_frame_number (struct usb_device *usb_dev); +extern int usb_get_current_frame_number(struct usb_device *usb_dev); /* used these for multi-interface device registration */ extern int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void* priv); + struct usb_interface *iface, void *priv); /** * usb_interface_claimed - returns true iff an interface is claimed @@ -514,7 +519,8 @@ extern int usb_driver_claim_interface(struct usb_driver *driver, * may need to explicitly claim that lock. * */ -static inline int usb_interface_claimed(struct usb_interface *iface) { +static inline int usb_interface_claimed(struct usb_interface *iface) +{ return (iface->dev.driver != NULL); } @@ -557,12 +563,11 @@ extern struct usb_host_interface *usb_altnum_to_altsetting( * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are * high speed, and a different one if they are full or low speed. */ -static inline int usb_make_path (struct usb_device *dev, char *buf, - size_t size) +static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) { int actual; - actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, - dev->devpath); + actual = snprintf(buf, size, "usb-%s-%s", dev->bus->bus_name, + dev->devpath); return (actual >= (int)size) ? -1 : actual; } @@ -608,7 +613,8 @@ static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) * * Returns true if the endpoint is of type OUT, otherwise it returns false. */ -static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_dir_out( + const struct usb_endpoint_descriptor *epd) { return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); } @@ -619,7 +625,8 @@ static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd * * Returns true if the endpoint is of type bulk, otherwise it returns false. */ -static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_xfer_bulk( + const struct usb_endpoint_descriptor *epd) { return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK); @@ -631,7 +638,8 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e * * Returns true if the endpoint is of type control, otherwise it returns false. */ -static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_xfer_control( + const struct usb_endpoint_descriptor *epd) { return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL); @@ -644,7 +652,8 @@ static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor * Returns true if the endpoint is of type interrupt, otherwise it returns * false. */ -static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_xfer_int( + const struct usb_endpoint_descriptor *epd) { return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT); @@ -657,7 +666,8 @@ static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *ep * Returns true if the endpoint is of type isochronous, otherwise it returns * false. */ -static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_xfer_isoc( + const struct usb_endpoint_descriptor *epd) { return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC); @@ -670,7 +680,8 @@ static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *e * Returns true if the endpoint has bulk transfer type and IN direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_bulk_in( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); } @@ -682,7 +693,8 @@ static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor * * Returns true if the endpoint has bulk transfer type and OUT direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_bulk_out( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); } @@ -694,7 +706,8 @@ static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor * Returns true if the endpoint has interrupt transfer type and IN direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_int_in( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); } @@ -706,7 +719,8 @@ static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *e * Returns true if the endpoint has interrupt transfer type and OUT direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_int_out( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); } @@ -718,7 +732,8 @@ static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor * * Returns true if the endpoint has isochronous transfer type and IN direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_isoc_in( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); } @@ -730,7 +745,8 @@ static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor * * Returns true if the endpoint has isochronous transfer type and OUT direction, * otherwise it returns false. */ -static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) +static inline int usb_endpoint_is_isoc_out( + const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); } @@ -761,8 +777,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * specific device. */ #define USB_DEVICE(vend,prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \ - .idProduct = (prod) + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod) /** * USB_DEVICE_VER - macro used to describe a specific usb device with a * version range @@ -774,10 +791,12 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * This macro is used to create a struct usb_device_id that matches a * specific device, with a version range. */ -#define USB_DEVICE_VER(vend,prod,lo,hi) \ +#define USB_DEVICE_VER(vend, prod, lo, hi) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \ - .idVendor = (vend), .idProduct = (prod), \ - .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) + .idVendor = (vend), \ + .idProduct = (prod), \ + .bcdDevice_lo = (lo), \ + .bcdDevice_hi = (hi) /** * USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb @@ -789,8 +808,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * This macro is used to create a struct usb_device_id that matches a * specific interface protocol of devices. */ -#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ +#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ .idVendor = (vend), \ .idProduct = (prod), \ .bInterfaceProtocol = (pr) @@ -804,12 +824,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * This macro is used to create a struct usb_device_id that matches a * specific class of devices. */ -#define USB_DEVICE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \ - .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) +#define USB_DEVICE_INFO(cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \ + .bDeviceClass = (cl), \ + .bDeviceSubClass = (sc), \ + .bDeviceProtocol = (pr) /** - * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces + * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces * @cl: bInterfaceClass value * @sc: bInterfaceSubClass value * @pr: bInterfaceProtocol value @@ -817,9 +839,11 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * This macro is used to create a struct usb_device_id that matches a * specific class of interfaces. */ -#define USB_INTERFACE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) +#define USB_INTERFACE_INFO(cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \ + .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), \ + .bInterfaceProtocol = (pr) /** * USB_DEVICE_AND_INTERFACE_INFO - macro used to describe a specific usb device @@ -836,12 +860,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor * This is especially useful when explicitly matching devices that have * vendor specific bDeviceClass values, but standards-compliant interfaces. */ -#define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \ +#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ | USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), .idProduct = (prod), \ + .idVendor = (vend), \ + .idProduct = (prod), \ .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) + .bInterfaceSubClass = (sc), \ + .bInterfaceProtocol = (pr) /* ----------------------------------------------------------------------- */ @@ -1119,7 +1145,7 @@ typedef void (*usb_complete_t)(struct urb *); * transferred. It will normally be the same as requested, unless * either an error was reported or a short read was performed. * The URB_SHORT_NOT_OK transfer flag may be used to make such - * short reads be reported as errors. + * short reads be reported as errors. * @setup_packet: Only used for control transfers, this points to eight bytes * of setup data. Control transfers always start by sending this data * to the device. Then transfer_buffer is read or written, if needed. @@ -1138,7 +1164,7 @@ typedef void (*usb_complete_t)(struct urb *); * @complete: Completion handler. This URB is passed as the parameter to the * completion function. The completion function may then do what * it likes with the URB, including resubmitting or freeing it. - * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to + * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to * collect the transfer status for each buffer. * * This structure identifies USB transfer requests. URBs must be allocated by @@ -1242,8 +1268,7 @@ typedef void (*usb_complete_t)(struct urb *); * when the urb is owned by the hcd, that is, since the call to * usb_submit_urb() till the entry into the completion routine. */ -struct urb -{ +struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ void *hcpriv; /* private data for host controller */ @@ -1254,10 +1279,10 @@ struct urb /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's * current owner */ - struct list_head anchor_list; /* the URB may be anchored by the driver */ + struct list_head anchor_list; /* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ - struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */ + struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ @@ -1294,14 +1319,14 @@ struct urb * Initializes a control urb with the proper information needed to submit * it to a device. */ -static inline void usb_fill_control_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - unsigned char *setup_packet, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete_fn, - void *context) +static inline void usb_fill_control_urb(struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + unsigned char *setup_packet, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete_fn, + void *context) { urb->dev = dev; urb->pipe = pipe; @@ -1325,13 +1350,13 @@ static inline void usb_fill_control_urb (struct urb *urb, * Initializes a bulk urb with the proper information needed to submit it * to a device. */ -static inline void usb_fill_bulk_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete_fn, - void *context) +static inline void usb_fill_bulk_urb(struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete_fn, + void *context) { urb->dev = dev; urb->pipe = pipe; @@ -1359,14 +1384,14 @@ static inline void usb_fill_bulk_urb (struct urb *urb, * the endpoint interval, and express polling intervals in microframes * (eight per millisecond) rather than in frames (one per millisecond). */ -static inline void usb_fill_int_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete_fn, - void *context, - int interval) +static inline void usb_fill_int_urb(struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete_fn, + void *context, + int interval) { urb->dev = dev; urb->pipe = pipe; @@ -1419,15 +1444,15 @@ static inline int usb_urb_dir_out(struct urb *urb) return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; } -void *usb_buffer_alloc (struct usb_device *dev, size_t size, +void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); -void usb_buffer_free (struct usb_device *dev, size_t size, +void usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); #if 0 -struct urb *usb_buffer_map (struct urb *urb); -void usb_buffer_dmasync (struct urb *urb); -void usb_buffer_unmap (struct urb *urb); +struct urb *usb_buffer_map(struct urb *urb); +void usb_buffer_dmasync(struct urb *urb); +void usb_buffer_unmap(struct urb *urb); #endif struct scatterlist; @@ -1499,7 +1524,7 @@ struct usb_sg_request { int status; size_t bytes; - /* + /* * members below are private: to usbcore, * and are not provided for driver access! */ @@ -1517,18 +1542,18 @@ struct usb_sg_request { struct completion complete; }; -int usb_sg_init ( +int usb_sg_init( struct usb_sg_request *io, struct usb_device *dev, - unsigned pipe, + unsigned pipe, unsigned period, struct scatterlist *sg, int nents, size_t length, gfp_t mem_flags ); -void usb_sg_cancel (struct usb_sg_request *io); -void usb_sg_wait (struct usb_sg_request *io); +void usb_sg_cancel(struct usb_sg_request *io); +void usb_sg_wait(struct usb_sg_request *io); /* ----------------------------------------------------------------------- */ @@ -1585,21 +1610,21 @@ static inline unsigned int __create_pipe(struct usb_device *dev, /* Create various pipes... */ #define usb_sndctrlpipe(dev,endpoint) \ - ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint)) + ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint)) #define usb_rcvctrlpipe(dev,endpoint) \ - ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) + ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) #define usb_sndisocpipe(dev,endpoint) \ - ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint)) + ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint)) #define usb_rcvisocpipe(dev,endpoint) \ - ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) + ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) #define usb_sndbulkpipe(dev,endpoint) \ - ((PIPE_BULK << 30) | __create_pipe(dev,endpoint)) + ((PIPE_BULK << 30) | __create_pipe(dev, endpoint)) #define usb_rcvbulkpipe(dev,endpoint) \ - ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) + ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) #define usb_sndintpipe(dev,endpoint) \ - ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) + ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint)) #define usb_rcvintpipe(dev,endpoint) \ - ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) + ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild index 6ce42bf9f74..b8cba1dcb2c 100644 --- a/include/linux/usb/Kbuild +++ b/include/linux/usb/Kbuild @@ -1,6 +1,7 @@ -unifdef-y += audio.h -unifdef-y += cdc.h -unifdef-y += ch9.h -unifdef-y += gadgetfs.h -unifdef-y += midi.h +header-y += audio.h +header-y += cdc.h +header-y += ch9.h +header-y += gadgetfs.h +header-y += midi.h +unifdef-y += g_printer.h diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 6bd235994dc..2dfeef16b22 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -27,13 +27,13 @@ /* 4.3.2 Class-Specific AC Interface Descriptor */ struct usb_ac_header_descriptor { - __u8 bLength; // 8+n - __u8 bDescriptorType; // USB_DT_CS_INTERFACE - __u8 bDescriptorSubtype; // USB_MS_HEADER - __le16 bcdADC; // 0x0100 - __le16 wTotalLength; // includes Unit and Terminal desc. - __u8 bInCollection; // n - __u8 baInterfaceNr[]; // [n] + __u8 bLength; /* 8+n */ + __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ + __u8 bDescriptorSubtype; /* USB_MS_HEADER */ + __le16 bcdADC; /* 0x0100 */ + __le16 wTotalLength; /* includes Unit and Terminal desc. */ + __u8 bInCollection; /* n */ + __u8 baInterfaceNr[]; /* [n] */ } __attribute__ ((packed)); #define USB_DT_AC_HEADER_SIZE(n) (8+(n)) diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h index 2204ae22c38..94ee4ecf056 100644 --- a/include/linux/usb/cdc.h +++ b/include/linux/usb/cdc.h @@ -29,16 +29,16 @@ * Class-Specific descriptors ... there are a couple dozen of them */ -#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ -#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ -#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ -#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ +#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ #define USB_CDC_COUNTRY_TYPE 0x07 -#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ -#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ +#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ +#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ #define USB_CDC_WHCM_TYPE 0x11 -#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ -#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ +#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ +#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ #define USB_CDC_DMM_TYPE 0x14 #define USB_CDC_OBEX_TYPE 0x15 diff --git a/include/linux/usb/g_printer.h b/include/linux/usb/g_printer.h new file mode 100644 index 00000000000..0c5ea1e3eb9 --- /dev/null +++ b/include/linux/usb/g_printer.h @@ -0,0 +1,31 @@ +/* + * g_printer.h -- Header file for USB Printer gadget driver + * + * Copyright (C) 2007 Craig W. Nadler + * + * 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 + */ + + +#define PRINTER_NOT_ERROR 0x08 +#define PRINTER_SELECTED 0x10 +#define PRINTER_PAPER_EMPTY 0x20 + +/* The 'g' code is also used by gadgetfs ioctl requests. + * Don't add any colliding codes to either driver, and keep + * them in unique ranges (size 0x20 for now). + */ +#define GADGET_GET_PRINTER_STATUS _IOR('g', 0x21, unsigned char) +#define GADGET_SET_PRINTER_STATUS _IOWR('g', 0x22, unsigned char) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c1527c2ef3c..aa3047ff00d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -70,9 +70,10 @@ struct usb_ep; * * Bulk endpoints can use any size buffers, and can also be used for interrupt * transfers. interrupt-only endpoints can be much less functional. + * + * NOTE: this is analagous to 'struct urb' on the host side, except that + * it's thinner and promotes more pre-allocation. */ - // NOTE this is analagous to 'struct urb' on the host side, - // except that it's thinner and promotes more pre-allocation. struct usb_request { void *buf; @@ -168,10 +169,10 @@ struct usb_ep { * * returns zero, or a negative error code. */ -static inline int -usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +static inline int usb_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) { - return ep->ops->enable (ep, desc); + return ep->ops->enable(ep, desc); } /** @@ -186,10 +187,9 @@ usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) * * returns zero, or a negative error code. */ -static inline int -usb_ep_disable (struct usb_ep *ep) +static inline int usb_ep_disable(struct usb_ep *ep) { - return ep->ops->disable (ep); + return ep->ops->disable(ep); } /** @@ -206,10 +206,10 @@ usb_ep_disable (struct usb_ep *ep) * * Returns the request, or null if one could not be allocated. */ -static inline struct usb_request * -usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) +static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) { - return ep->ops->alloc_request (ep, gfp_flags); + return ep->ops->alloc_request(ep, gfp_flags); } /** @@ -221,10 +221,10 @@ usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) * Caller guarantees the request is not queued, and that it will * no longer be requeued (or otherwise used). */ -static inline void -usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) +static inline void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) { - ep->ops->free_request (ep, req); + ep->ops->free_request(ep, req); } /** @@ -281,10 +281,10 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) * report errors; errors will also be * reported when the usb peripheral is disconnected. */ -static inline int -usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) +static inline int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req, gfp_t gfp_flags) { - return ep->ops->queue (ep, req, gfp_flags); + return ep->ops->queue(ep, req, gfp_flags); } /** @@ -301,9 +301,9 @@ usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) * restrictions prevent drivers from supporting configuration changes, * even to configuration zero (a "chapter 9" requirement). */ -static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) +static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { - return ep->ops->dequeue (ep, req); + return ep->ops->dequeue(ep, req); } /** @@ -327,10 +327,9 @@ static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) * transfer requests are still queued, or if the controller hardware * (usually a FIFO) still holds bytes that the host hasn't collected. */ -static inline int -usb_ep_set_halt (struct usb_ep *ep) +static inline int usb_ep_set_halt(struct usb_ep *ep) { - return ep->ops->set_halt (ep, 1); + return ep->ops->set_halt(ep, 1); } /** @@ -346,10 +345,9 @@ usb_ep_set_halt (struct usb_ep *ep) * Note that some hardware can't support this request (like pxa2xx_udc), * and accordingly can't correctly implement interface altsettings. */ -static inline int -usb_ep_clear_halt (struct usb_ep *ep) +static inline int usb_ep_clear_halt(struct usb_ep *ep) { - return ep->ops->set_halt (ep, 0); + return ep->ops->set_halt(ep, 0); } /** @@ -367,11 +365,10 @@ usb_ep_clear_halt (struct usb_ep *ep) * errno if the endpoint doesn't use a FIFO or doesn't support such * precise handling. */ -static inline int -usb_ep_fifo_status (struct usb_ep *ep) +static inline int usb_ep_fifo_status(struct usb_ep *ep) { if (ep->ops->fifo_status) - return ep->ops->fifo_status (ep); + return ep->ops->fifo_status(ep); else return -EOPNOTSUPP; } @@ -385,11 +382,10 @@ usb_ep_fifo_status (struct usb_ep *ep) * must never be used except when endpoint is not being used for any * protocol translation. */ -static inline void -usb_ep_fifo_flush (struct usb_ep *ep) +static inline void usb_ep_fifo_flush(struct usb_ep *ep) { if (ep->ops->fifo_flush) - ep->ops->fifo_flush (ep); + ep->ops->fifo_flush(ep); } @@ -469,10 +465,10 @@ struct usb_gadget { struct device dev; }; -static inline void set_gadget_data (struct usb_gadget *gadget, void *data) - { dev_set_drvdata (&gadget->dev, data); } -static inline void *get_gadget_data (struct usb_gadget *gadget) - { return dev_get_drvdata (&gadget->dev); } +static inline void set_gadget_data(struct usb_gadget *gadget, void *data) + { dev_set_drvdata(&gadget->dev, data); } +static inline void *get_gadget_data(struct usb_gadget *gadget) + { return dev_get_drvdata(&gadget->dev); } /* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ #define gadget_for_each_ep(tmp,gadget) \ @@ -511,7 +507,6 @@ static inline int gadget_is_otg(struct usb_gadget *g) #endif } - /** * usb_gadget_frame_number - returns the current frame number * @gadget: controller that reports the frame number @@ -519,9 +514,9 @@ static inline int gadget_is_otg(struct usb_gadget *g) * Returns the usb frame number, normally eleven bits from a SOF packet, * or negative errno if this device doesn't support this capability. */ -static inline int usb_gadget_frame_number (struct usb_gadget *gadget) +static inline int usb_gadget_frame_number(struct usb_gadget *gadget) { - return gadget->ops->get_frame (gadget); + return gadget->ops->get_frame(gadget); } /** @@ -537,11 +532,11 @@ static inline int usb_gadget_frame_number (struct usb_gadget *gadget) * even if OTG isn't otherwise in use. OTG devices may also start * remote wakeup even when hosts don't explicitly enable it. */ -static inline int usb_gadget_wakeup (struct usb_gadget *gadget) +static inline int usb_gadget_wakeup(struct usb_gadget *gadget) { if (!gadget->ops->wakeup) return -EOPNOTSUPP; - return gadget->ops->wakeup (gadget); + return gadget->ops->wakeup(gadget); } /** @@ -553,12 +548,11 @@ static inline int usb_gadget_wakeup (struct usb_gadget *gadget) * * returns zero on success, else negative errno. */ -static inline int -usb_gadget_set_selfpowered (struct usb_gadget *gadget) +static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget) { if (!gadget->ops->set_selfpowered) return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 1); + return gadget->ops->set_selfpowered(gadget, 1); } /** @@ -571,12 +565,11 @@ usb_gadget_set_selfpowered (struct usb_gadget *gadget) * * returns zero on success, else negative errno. */ -static inline int -usb_gadget_clear_selfpowered (struct usb_gadget *gadget) +static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) { if (!gadget->ops->set_selfpowered) return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 0); + return gadget->ops->set_selfpowered(gadget, 0); } /** @@ -591,12 +584,11 @@ usb_gadget_clear_selfpowered (struct usb_gadget *gadget) * * Returns zero on success, else negative errno. */ -static inline int -usb_gadget_vbus_connect(struct usb_gadget *gadget) +static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) { if (!gadget->ops->vbus_session) return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 1); + return gadget->ops->vbus_session(gadget, 1); } /** @@ -611,12 +603,11 @@ usb_gadget_vbus_connect(struct usb_gadget *gadget) * * Returns zero on success, else negative errno. */ -static inline int -usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; - return gadget->ops->vbus_draw (gadget, mA); + return gadget->ops->vbus_draw(gadget, mA); } /** @@ -629,12 +620,11 @@ usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) * * Returns zero on success, else negative errno. */ -static inline int -usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) { if (!gadget->ops->vbus_session) return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 0); + return gadget->ops->vbus_session(gadget, 0); } /** @@ -648,12 +638,11 @@ usb_gadget_vbus_disconnect(struct usb_gadget *gadget) * * Returns zero on success, else negative errno. */ -static inline int -usb_gadget_connect (struct usb_gadget *gadget) +static inline int usb_gadget_connect(struct usb_gadget *gadget) { if (!gadget->ops->pullup) return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 1); + return gadget->ops->pullup(gadget, 1); } /** @@ -671,16 +660,14 @@ usb_gadget_connect (struct usb_gadget *gadget) * * Returns zero on success, else negative errno. */ -static inline int -usb_gadget_disconnect (struct usb_gadget *gadget) +static inline int usb_gadget_disconnect(struct usb_gadget *gadget) { if (!gadget->ops->pullup) return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 0); + return gadget->ops->pullup(gadget, 0); } - /*-------------------------------------------------------------------------*/ /** @@ -764,7 +751,7 @@ struct usb_gadget_driver { void (*suspend)(struct usb_gadget *); void (*resume)(struct usb_gadget *); - // FIXME support safe rmmod + /* FIXME support safe rmmod */ struct device_driver driver; }; @@ -790,7 +777,7 @@ struct usb_gadget_driver { * the bind() functions will be in init sections. * This function must be called in a context that can sleep. */ -int usb_gadget_register_driver (struct usb_gadget_driver *driver); +int usb_gadget_register_driver(struct usb_gadget_driver *driver); /** * usb_gadget_unregister_driver - unregister a gadget driver @@ -805,7 +792,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver); * will in in exit sections, so may not be linked in some kernels. * This function must be called in a context that can sleep. */ -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); /*-------------------------------------------------------------------------*/ @@ -838,7 +825,7 @@ struct usb_gadget_strings { }; /* put descriptor for string with that id into buf (buflen >= 256) */ -int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); +int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf); /*-------------------------------------------------------------------------*/ @@ -856,10 +843,10 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, /* utility wrapping a simple endpoint selection policy */ -extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, +extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *, struct usb_endpoint_descriptor *) __devinit; -extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; +extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit; #endif /* __KERNEL__ */ diff --git a/include/linux/usb/gadgetfs.h b/include/linux/usb/gadgetfs.h index e8654c33872..c291ab1af74 100644 --- a/include/linux/usb/gadgetfs.h +++ b/include/linux/usb/gadgetfs.h @@ -36,7 +36,7 @@ enum usb_gadgetfs_event_type { GADGETFS_DISCONNECT, GADGETFS_SETUP, GADGETFS_SUSPEND, - // and likely more ! + /* and likely more ! */ }; /* NOTE: this structure must stay the same size and layout on @@ -44,21 +44,28 @@ enum usb_gadgetfs_event_type { */ struct usb_gadgetfs_event { union { - // NOP, DISCONNECT, SUSPEND: nothing - // ... some hardware can't report disconnection + /* NOP, DISCONNECT, SUSPEND: nothing + * ... some hardware can't report disconnection + */ - // CONNECT: just the speed + /* CONNECT: just the speed */ enum usb_device_speed speed; - // SETUP: packet; DATA phase i/o precedes next event - // (setup.bmRequestType & USB_DIR_IN) flags direction - // ... includes SET_CONFIGURATION, SET_INTERFACE + /* SETUP: packet; DATA phase i/o precedes next event + *(setup.bmRequestType & USB_DIR_IN) flags direction + * ... includes SET_CONFIGURATION, SET_INTERFACE + */ struct usb_ctrlrequest setup; } u; enum usb_gadgetfs_event_type type; }; +/* The 'g' code is also used by printer gadget ioctl requests. + * Don't add any colliding codes to either driver, and keep + * them in unique ranges (size 0x20 for now). + */ + /* endpoint ioctls */ /* IN transfers may be reported to the gadget driver as complete @@ -68,14 +75,14 @@ struct usb_gadgetfs_event { * THIS returns how many bytes are "unclaimed" in the endpoint fifo * (needed for precise fault handling, when the hardware allows it) */ -#define GADGETFS_FIFO_STATUS _IO('g',1) +#define GADGETFS_FIFO_STATUS _IO('g', 1) /* discards any unclaimed data in the fifo. */ -#define GADGETFS_FIFO_FLUSH _IO('g',2) +#define GADGETFS_FIFO_FLUSH _IO('g', 2) /* resets endpoint halt+toggle; used to implement set_interface. * some hardware (like pxa2xx) can't support this. */ -#define GADGETFS_CLEAR_HALT _IO('g',3) +#define GADGETFS_CLEAR_HALT _IO('g', 3) #endif /* __LINUX_USB_GADGETFS_H */ diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h index cbbe020a4f5..de6f380e17a 100644 --- a/include/linux/usb/iowarrior.h +++ b/include/linux/usb/iowarrior.h @@ -14,14 +14,23 @@ this information. */ struct iowarrior_info { - __u32 vendor; /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */ - __u32 product; /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */ - __u8 serial[9]; /* the serial number of our chip (if a serial-number is not available this is empty string) */ - __u32 revision; /* revision number of the chip */ - __u32 speed; /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */ - __u32 power; /* power consumption of the device in mA */ - __u32 if_num; /* the number of the endpoint */ - __u32 report_size; /* size of the data-packets on this interface */ + /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */ + __u32 vendor; + /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_X) */ + __u32 product; + /* the serial number of our chip (if a serial-number is not available + * this is empty string) */ + __u8 serial[9]; + /* revision number of the chip */ + __u32 revision; + /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */ + __u32 speed; + /* power consumption of the device in mA */ + __u32 power; + /* the number of the endpoint */ + __u32 if_num; + /* size of the data-packets on this interface */ + __u32 report_size; }; /* diff --git a/include/linux/usb/isp116x.h b/include/linux/usb/isp116x.h index 436dd8a2b64..67d2826f34f 100644 --- a/include/linux/usb/isp116x.h +++ b/include/linux/usb/isp116x.h @@ -25,5 +25,5 @@ struct isp116x_platform_data { 300ns delay between access to ADDR_REG and DATA_REG OE, WE MUST NOT be changed during these intervals */ - void (*delay) (struct device * dev, int delay); + void (*delay) (struct device *dev, int delay); }; diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h index 11a97d5ffd3..80624c56292 100644 --- a/include/linux/usb/midi.h +++ b/include/linux/usb/midi.h @@ -47,9 +47,9 @@ struct usb_ms_header_descriptor { /* 6.1.2.2 MIDI IN Jack Descriptor */ struct usb_midi_in_jack_descriptor { __u8 bLength; - __u8 bDescriptorType; // USB_DT_CS_INTERFACE - __u8 bDescriptorSubtype; // USB_MS_MIDI_IN_JACK - __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL + __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ + __u8 bDescriptorSubtype; /* USB_MS_MIDI_IN_JACK */ + __u8 bJackType; /* USB_MS_EMBEDDED/EXTERNAL */ __u8 bJackID; __u8 iJack; } __attribute__ ((packed)); @@ -64,12 +64,12 @@ struct usb_midi_source_pin { /* 6.1.2.3 MIDI OUT Jack Descriptor */ struct usb_midi_out_jack_descriptor { __u8 bLength; - __u8 bDescriptorType; // USB_DT_CS_INTERFACE - __u8 bDescriptorSubtype; // USB_MS_MIDI_OUT_JACK - __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL + __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ + __u8 bDescriptorSubtype; /* USB_MS_MIDI_OUT_JACK */ + __u8 bJackType; /* USB_MS_EMBEDDED/EXTERNAL */ __u8 bJackID; - __u8 bNrInputPins; // p - struct usb_midi_source_pin pins[]; // [p] + __u8 bNrInputPins; /* p */ + struct usb_midi_source_pin pins[]; /* [p] */ /*__u8 iJack; -- ommitted due to variable-sized pins[] */ } __attribute__ ((packed)); @@ -90,11 +90,11 @@ struct usb_midi_out_jack_descriptor_##p { \ /* 6.2.2 Class-Specific MS Bulk Data Endpoint Descriptor */ struct usb_ms_endpoint_descriptor { - __u8 bLength; // 4+n - __u8 bDescriptorType; // USB_DT_CS_ENDPOINT - __u8 bDescriptorSubtype; // USB_MS_GENERAL - __u8 bNumEmbMIDIJack; // n - __u8 baAssocJackID[]; // [n] + __u8 bLength; /* 4+n */ + __u8 bDescriptorType; /* USB_DT_CS_ENDPOINT */ + __u8 bDescriptorSubtype; /* USB_MS_GENERAL */ + __u8 bNumEmbMIDIJack; /* n */ + __u8 baAssocJackID[]; /* [n] */ } __attribute__ ((packed)); #define USB_DT_MS_ENDPOINT_SIZE(n) (4 + (n)) diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h index c602f884f18..ec897cb844a 100644 --- a/include/linux/usb/net2280.h +++ b/include/linux/usb/net2280.h @@ -37,7 +37,7 @@ /* main registers, BAR0 + 0x0000 */ struct net2280_regs { - // offset 0x0000 + /* offset 0x0000 */ u32 devinit; #define LOCAL_CLOCK_FREQUENCY 8 #define FORCE_PCI_RESET 7 @@ -61,7 +61,7 @@ struct net2280_regs { #define EEPROM_WRITE_DATA 0 u32 eeclkfreq; u32 _unused0; - // offset 0x0010 + /* offset 0x0010 */ u32 pciirqenb0; /* interrupt PCI master ... */ #define SETUP_PACKET_INTERRUPT_ENABLE 7 @@ -131,7 +131,7 @@ struct net2280_regs { #define RESUME_INTERRUPT_ENABLE 1 #define SOF_INTERRUPT_ENABLE 0 - // offset 0x0020 + /* offset 0x0020 */ u32 _unused1; u32 usbirqenb1; #define USB_INTERRUPT_ENABLE 31 @@ -195,7 +195,7 @@ struct net2280_regs { #define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 #define RESUME_INTERRUPT 1 #define SOF_INTERRUPT 0 - // offset 0x0030 + /* offset 0x0030 */ u32 idxaddr; u32 idxdata; u32 fifoctl; @@ -204,7 +204,7 @@ struct net2280_regs { #define PCI_BASE2_SELECT 2 #define FIFO_CONFIGURATION_SELECT 0 u32 _unused2; - // offset 0x0040 + /* offset 0x0040 */ u32 memaddr; #define START 28 #define DIRECTION 27 @@ -213,7 +213,7 @@ struct net2280_regs { u32 memdata0; u32 memdata1; u32 _unused3; - // offset 0x0050 + /* offset 0x0050 */ u32 gpioctl; #define GPIO3_LED_SELECT 12 #define GPIO3_INTERRUPT_ENABLE 11 @@ -237,7 +237,7 @@ struct net2280_regs { /* usb control, BAR0 + 0x0080 */ struct net2280_usb_regs { - // offset 0x0080 + /* offset 0x0080 */ u32 stdrsp; #define STALL_UNSUPPORTED_REQUESTS 31 #define SET_TEST_MODE 16 @@ -275,7 +275,7 @@ struct net2280_usb_regs { #define PME_WAKEUP_ENABLE 2 #define DEVICE_REMOTE_WAKEUP_ENABLE 1 #define SELF_POWERED_STATUS 0 - // offset 0x0090 + /* offset 0x0090 */ u32 usbstat; #define HIGH_SPEED 7 #define FULL_SPEED 6 @@ -291,7 +291,7 @@ struct net2280_usb_regs { #define TERMINATION_SELECT 0 u32 setup0123; u32 setup4567; - // offset 0x0090 + /* offset 0x0090 */ u32 _unused0; u32 ouraddr; #define FORCE_IMMEDIATE 7 @@ -301,7 +301,7 @@ struct net2280_usb_regs { /* pci control, BAR0 + 0x0100 */ struct net2280_pci_regs { - // offset 0x0100 + /* offset 0x0100 */ u32 pcimstctl; #define PCI_ARBITER_PARK_SELECT 13 #define PCI_MULTI LEVEL_ARBITER 12 @@ -331,7 +331,7 @@ struct net2280_pci_regs { * that can be loaded into some of these registers. */ struct net2280_dma_regs { /* [11.7] */ - // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, + /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */ u32 dmactl; #define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 #define DMA_CLEAR_COUNT_ENABLE 21 @@ -355,7 +355,7 @@ struct net2280_dma_regs { /* [11.7] */ #define DMA_ABORT 1 #define DMA_START 0 u32 _unused0 [2]; - // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, + /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */ u32 dmacount; #define VALID_BIT 31 #define DMA_DIRECTION 30 @@ -371,9 +371,9 @@ struct net2280_dma_regs { /* [11.7] */ /* dedicated endpoint registers, BAR0 + 0x0200 */ struct net2280_dep_regs { /* [11.8] */ - // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 + /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */ u32 dep_cfg; - // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 + /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */ u32 dep_rsp; u32 _unused [2]; } __attribute__ ((packed)); @@ -383,7 +383,7 @@ struct net2280_dep_regs { /* [11.8] */ * ep0 reserved for control; E and F have only 64 bytes of fifo */ struct net2280_ep_regs { /* [11.9] */ - // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 + /* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */ u32 ep_cfg; #define ENDPOINT_BYTE_COUNT 16 #define ENDPOINT_ENABLE 10 @@ -435,7 +435,7 @@ struct net2280_ep_regs { /* [11.9] */ #define DATA_PACKET_TRANSMITTED_INTERRUPT 2 #define DATA_OUT_PING_TOKEN_INTERRUPT 1 #define DATA_IN_TOKEN_INTERRUPT 0 - // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 + /* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */ u32 ep_avail; u32 ep_data; u32 _unused0 [2]; diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 9897f7a818c..e007074ebe4 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -1,4 +1,4 @@ -// include/linux/usb/otg.h +/* USB OTG (On The Go) defines */ /* * These APIs may be used between USB controllers. USB device drivers diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 488ce128885..21b4a1c6f58 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -20,7 +20,8 @@ #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 255 /* loads of devices :) */ -#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ +/* The maximum number of ports one device can grab at once */ +#define MAX_NUM_PORTS 8 /* parity check flag */ #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) @@ -61,29 +62,29 @@ * ports of a device. */ struct usb_serial_port { - struct usb_serial * serial; - struct tty_struct * tty; + struct usb_serial *serial; + struct tty_struct *tty; spinlock_t lock; struct mutex mutex; unsigned char number; - unsigned char * interrupt_in_buffer; - struct urb * interrupt_in_urb; + unsigned char *interrupt_in_buffer; + struct urb *interrupt_in_urb; __u8 interrupt_in_endpointAddress; - unsigned char * interrupt_out_buffer; + unsigned char *interrupt_out_buffer; int interrupt_out_size; - struct urb * interrupt_out_urb; + struct urb *interrupt_out_urb; __u8 interrupt_out_endpointAddress; - unsigned char * bulk_in_buffer; + unsigned char *bulk_in_buffer; int bulk_in_size; - struct urb * read_urb; + struct urb *read_urb; __u8 bulk_in_endpointAddress; - unsigned char * bulk_out_buffer; + unsigned char *bulk_out_buffer; int bulk_out_size; - struct urb * write_urb; + struct urb *write_urb; int write_urb_busy; __u8 bulk_out_endpointAddress; @@ -92,17 +93,19 @@ struct usb_serial_port { int open_count; char throttled; char throttle_req; + char console; struct device dev; }; #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) /* get and set the port private data pointer helper functions */ -static inline void *usb_get_serial_port_data (struct usb_serial_port *port) +static inline void *usb_get_serial_port_data(struct usb_serial_port *port) { return dev_get_drvdata(&port->dev); } -static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data) +static inline void usb_set_serial_port_data(struct usb_serial_port *port, + void *data) { dev_set_drvdata(&port->dev, data); } @@ -125,9 +128,10 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void * usb_set_serial_data() to access this. */ struct usb_serial { - struct usb_device * dev; - struct usb_serial_driver * type; - struct usb_interface * interface; + struct usb_device *dev; + struct usb_serial_driver *type; + struct usb_interface *interface; + unsigned char disconnected; unsigned char minor; unsigned char num_ports; unsigned char num_port_pointers; @@ -135,29 +139,30 @@ struct usb_serial { char num_interrupt_out; char num_bulk_in; char num_bulk_out; - struct usb_serial_port * port[MAX_NUM_PORTS]; + struct usb_serial_port *port[MAX_NUM_PORTS]; struct kref kref; - void * private; + struct mutex disc_mutex; + void *private; }; #define to_usb_serial(d) container_of(d, struct usb_serial, kref) #define NUM_DONT_CARE 99 /* get and set the serial private data pointer helper functions */ -static inline void *usb_get_serial_data (struct usb_serial *serial) +static inline void *usb_get_serial_data(struct usb_serial *serial) { return serial->private; } -static inline void usb_set_serial_data (struct usb_serial *serial, void *data) +static inline void usb_set_serial_data(struct usb_serial *serial, void *data) { serial->private = data; } /** * usb_serial_driver - describes a usb serial driver - * @description: pointer to a string that describes this driver. This string used - * in the syslog messages when a device is inserted or removed. + * @description: pointer to a string that describes this driver. This string + * used in the syslog messages when a device is inserted or removed. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. * @num_interrupt_in: If a device doesn't have this many interrupt-in @@ -218,82 +223,91 @@ struct usb_serial_driver { struct usb_driver *usb_driver; struct usb_dynids dynids; - int (*probe) (struct usb_serial *serial, const struct usb_device_id *id); - int (*attach) (struct usb_serial *serial); + int (*probe)(struct usb_serial *serial, const struct usb_device_id *id); + int (*attach)(struct usb_serial *serial); int (*calc_num_ports) (struct usb_serial *serial); - void (*shutdown) (struct usb_serial *serial); + void (*shutdown)(struct usb_serial *serial); - int (*port_probe) (struct usb_serial_port *port); - int (*port_remove) (struct usb_serial_port *port); + int (*port_probe)(struct usb_serial_port *port); + int (*port_remove)(struct usb_serial_port *port); - int (*suspend) (struct usb_serial *serial, pm_message_t message); - int (*resume) (struct usb_serial *serial); + int (*suspend)(struct usb_serial *serial, pm_message_t message); + int (*resume)(struct usb_serial *serial); /* serial function calls */ - int (*open) (struct usb_serial_port *port, struct file * filp); - void (*close) (struct usb_serial_port *port, struct file * filp); - int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count); - int (*write_room) (struct usb_serial_port *port); - int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios) (struct usb_serial_port *port, struct ktermios * old); - void (*break_ctl) (struct usb_serial_port *port, int break_state); - int (*chars_in_buffer) (struct usb_serial_port *port); - void (*throttle) (struct usb_serial_port *port); - void (*unthrottle) (struct usb_serial_port *port); - int (*tiocmget) (struct usb_serial_port *port, struct file *file); - int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); + int (*open)(struct usb_serial_port *port, struct file *filp); + void (*close)(struct usb_serial_port *port, struct file *filp); + int (*write)(struct usb_serial_port *port, const unsigned char *buf, + int count); + int (*write_room)(struct usb_serial_port *port); + int (*ioctl)(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg); + void (*set_termios)(struct usb_serial_port *port, struct ktermios *old); + void (*break_ctl)(struct usb_serial_port *port, int break_state); + int (*chars_in_buffer)(struct usb_serial_port *port); + void (*throttle)(struct usb_serial_port *port); + void (*unthrottle)(struct usb_serial_port *port); + int (*tiocmget)(struct usb_serial_port *port, struct file *file); + int (*tiocmset)(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear); void (*read_int_callback)(struct urb *urb); void (*write_int_callback)(struct urb *urb); void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); }; -#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver) +#define to_usb_serial_driver(d) \ + container_of(d, struct usb_serial_driver, driver) extern int usb_serial_register(struct usb_serial_driver *driver); extern void usb_serial_deregister(struct usb_serial_driver *driver); extern void usb_serial_port_softint(struct usb_serial_port *port); -extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); +extern int usb_serial_probe(struct usb_interface *iface, + const struct usb_device_id *id); extern void usb_serial_disconnect(struct usb_interface *iface); extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message); extern int usb_serial_resume(struct usb_interface *intf); -extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest); -extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); +extern int ezusb_writememory(struct usb_serial *serial, int address, + unsigned char *data, int length, __u8 bRequest); +extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit); /* USB Serial console functions */ #ifdef CONFIG_USB_SERIAL_CONSOLE -extern void usb_serial_console_init (int debug, int minor); -extern void usb_serial_console_exit (void); +extern void usb_serial_console_init(int debug, int minor); +extern void usb_serial_console_exit(void); extern void usb_serial_console_disconnect(struct usb_serial *serial); #else -static inline void usb_serial_console_init (int debug, int minor) { } -static inline void usb_serial_console_exit (void) { } +static inline void usb_serial_console_init(int debug, int minor) { } +static inline void usb_serial_console_exit(void) { } static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} #endif /* Functions needed by other parts of the usbserial core */ -extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); +extern struct usb_serial *usb_serial_get_by_index(unsigned int minor); extern void usb_serial_put(struct usb_serial *serial); -extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); -extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); -extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); -extern int usb_serial_generic_resume (struct usb_serial *serial); -extern int usb_serial_generic_write_room (struct usb_serial_port *port); -extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port); -extern void usb_serial_generic_read_bulk_callback (struct urb *urb); -extern void usb_serial_generic_write_bulk_callback (struct urb *urb); -extern void usb_serial_generic_throttle (struct usb_serial_port *port); -extern void usb_serial_generic_unthrottle (struct usb_serial_port *port); -extern void usb_serial_generic_shutdown (struct usb_serial *serial); -extern int usb_serial_generic_register (int debug); -extern void usb_serial_generic_deregister (void); - -extern int usb_serial_bus_register (struct usb_serial_driver *device); -extern void usb_serial_bus_deregister (struct usb_serial_driver *device); +extern int usb_serial_generic_open(struct usb_serial_port *port, + struct file *filp); +extern int usb_serial_generic_write(struct usb_serial_port *port, + const unsigned char *buf, int count); +extern void usb_serial_generic_close(struct usb_serial_port *port, + struct file *filp); +extern int usb_serial_generic_resume(struct usb_serial *serial); +extern int usb_serial_generic_write_room(struct usb_serial_port *port); +extern int usb_serial_generic_chars_in_buffer(struct usb_serial_port *port); +extern void usb_serial_generic_read_bulk_callback(struct urb *urb); +extern void usb_serial_generic_write_bulk_callback(struct urb *urb); +extern void usb_serial_generic_throttle(struct usb_serial_port *port); +extern void usb_serial_generic_unthrottle(struct usb_serial_port *port); +extern void usb_serial_generic_shutdown(struct usb_serial *serial); +extern int usb_serial_generic_register(int debug); +extern void usb_serial_generic_deregister(void); + +extern int usb_serial_bus_register(struct usb_serial_driver *device); +extern void usb_serial_bus_deregister(struct usb_serial_driver *device); extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; @@ -307,16 +321,22 @@ static inline void usb_serial_debug_data(int debug, int i; if (debug) { - dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size); + dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", + function, size); for (i = 0; i < size; ++i) - printk ("%.2x ", data[i]); - printk ("\n"); + printk("%.2x ", data[i]); + printk("\n"); } } /* Use our own dbg macro */ #undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0) +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \ + ## arg); \ + } while (0) diff --git a/include/linux/usb/sl811.h b/include/linux/usb/sl811.h index 397ee3b3d7f..877373da410 100644 --- a/include/linux/usb/sl811.h +++ b/include/linux/usb/sl811.h @@ -19,8 +19,8 @@ struct sl811_platform_data { /* pulse sl811 nRST (probably with a GPIO) */ void (*reset)(struct device *dev); - // some boards need something like these: - // int (*check_overcurrent)(struct device *dev); - // void (*clock_enable)(struct device *dev, int is_on); + /* some boards need something like these: */ + /* int (*check_overcurrent)(struct device *dev); */ + /* void (*clock_enable)(struct device *dev, int is_on); */ }; diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index a417b09b8b3..cee0623b3c7 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -80,10 +80,9 @@ enum { US_DO_ALL_FLAGS }; #define US_SC_UFI 0x04 /* Floppy */ #define US_SC_8070 0x05 /* Removable media */ #define US_SC_SCSI 0x06 /* Transparent */ -#define US_SC_ISD200 0x07 /* ISD200 ATA */ -#define US_SC_MIN US_SC_RBC -#define US_SC_MAX US_SC_ISD200 +#define US_SC_LOCKABLE 0x07 /* Password-protected */ +#define US_SC_ISD200 0xf0 /* ISD200 ATA */ #define US_SC_DEVICE 0xff /* Use device's value */ /* Protocols */ diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index 8ca5a7fbc9e..17cb108b7db 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -104,7 +104,7 @@ struct usbdevfs_urb { int error_count; unsigned int signr; /* signal to be sent on completion, or 0 if none should be sent. */ - void *usercontext; + void __user *usercontext; struct usbdevfs_iso_packet_desc iso_frame_desc[0]; }; diff --git a/kernel/softlockup.c b/kernel/softlockup.c index c1d76552446..7c2da88db4e 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -101,6 +101,10 @@ void softlockup_tick(void) now = get_timestamp(this_cpu); + /* Wake up the high-prio watchdog task every second: */ + if (now > (touch_timestamp + 1)) + wake_up_process(per_cpu(watchdog_task, this_cpu)); + /* Warn about unreasonable delays: */ if (now <= (touch_timestamp + softlockup_thresh)) return; @@ -191,11 +195,11 @@ static void check_hung_uninterruptible_tasks(int this_cpu) read_lock(&tasklist_lock); do_each_thread(g, t) { if (!--max_count) - break; + goto unlock; if (t->state & TASK_UNINTERRUPTIBLE) check_hung_task(t, now); } while_each_thread(g, t); - + unlock: read_unlock(&tasklist_lock); } @@ -218,14 +222,19 @@ static int watchdog(void *__bind_cpu) * debug-printout triggers in softlockup_tick(). */ while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); touch_softlockup_watchdog(); - msleep_interruptible(10000); + schedule(); + + if (kthread_should_stop()) + break; if (this_cpu != check_cpu) continue; if (sysctl_hung_task_timeout_secs) check_hung_uninterruptible_tasks(this_cpu); + } return 0; @@ -259,13 +268,6 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) wake_up_process(per_cpu(watchdog_task, hotcpu)); break; #ifdef CONFIG_HOTPLUG_CPU - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - if (!per_cpu(watchdog_task, hotcpu)) - break; - /* Unbind so it can run. Fall thru. */ - kthread_bind(per_cpu(watchdog_task, hotcpu), - any_online_cpu(cpu_online_map)); case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: if (hotcpu == check_cpu) { @@ -275,6 +277,14 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) check_cpu = any_online_cpu(temp_cpu_online_map); } break; + + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + if (!per_cpu(watchdog_task, hotcpu)) + break; + /* Unbind so it can run. Fall thru. */ + kthread_bind(per_cpu(watchdog_task, hotcpu), + any_online_cpu(cpu_online_map)); case CPU_DEAD: case CPU_DEAD_FROZEN: p = per_cpu(watchdog_task, hotcpu); diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index d802b5afae8..9ddf944cce2 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -155,7 +155,7 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) * Some modules (visor) have empty slots as placeholder for * run-time specification that results in catch-all alias */ - if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass)) + if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass)) return; /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ |