forked from Minki/linux
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (128 commits) USB: fix codingstyle issues in drivers/usb/core/*.c USB: fix codingstyle issues in drivers/usb/core/message.c USB: fix codingstyle issues in drivers/usb/core/hcd-pci.c USB: fix codingstyle issues in drivers/usb/core/devio.c USB: fix codingstyle issues in drivers/usb/core/devices.c USB: fix codingstyle issues in drivers/usb/core/*.h USB: fix codingstyle issues in include/linux/usb/ USB: fix codingstyle issues in include/linux/usb.h USB: mark USB drivers as being GPL only USB: use a real vendor and product id for root hubs USB: mount options: fix usbfs USB: Fix usb_serial_driver structure for Kobil cardreader driver. usb: ehci should use u16 for isochronous intervals usb: ehci, remove false clear-reset path USB: Use menuconfig objects usb: ohci-sm501 driver usb: dma bounce buffer support USB: last abuses of intfdata in close for usb-serial drivers USB: kl5kusb105 don't flush to logically disconnected devices USB: oti6858: cleanup ...
This commit is contained in:
commit
b6cf160c4b
@ -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/
|
||||
|
@ -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
|
||||
|
510
Documentation/usb/gadget_printer.txt
Normal file
510
Documentation/usb/gadget_printer.txt
Normal file
@ -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);
|
||||
}
|
84
Documentation/usb/iuu_phoenix.txt
Normal file
84
Documentation/usb/iuu_phoenix.txt
Normal file
@ -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
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
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;
|
||||
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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
if (urb->transfer_buffer_length != 0
|
||||
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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 ()
|
||||
* 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)
|
||||
*
|
||||
* 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.
|
||||
* Context: !in_interrupt ()
|
||||
*
|
||||
* 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.
|
||||
* 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 ()
|
||||
* 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)
|
||||
*
|
||||
* 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.
|
||||
* Context: !in_interrupt ()
|
||||
*
|
||||
* 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.
|
||||
* This function sends a simple bulk message to a specified endpoint
|
||||
* and waits for the message to complete, or timeout.
|
||||
*
|
||||
* 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.
|
||||
* 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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) &&
|
||||
|
@ -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 */
|
||||
@ -248,6 +248,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)
|
||||
{
|
||||
@ -365,12 +400,26 @@ 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;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
1592
drivers/usb/gadget/printer.c
Normal file
1592
drivers/usb/gadget/printer.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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 struct debug_buffer *alloc_buffer(struct usb_bus *bus,
|
||||
ssize_t (*fill_func)(struct debug_buffer *))
|
||||
{
|
||||
struct debug_buffer *buf;
|
||||
|
||||
buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
|
||||
|
||||
if (buf) {
|
||||
buf->bus = bus;
|
||||
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 ehci_hcd *ehci)
|
||||
{
|
||||
struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
|
||||
int retval;
|
||||
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct class_device *cldev = ehci_to_hcd(ehci)->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(ehci->debug_registers);
|
||||
debugfs_remove(ehci->debug_periodic);
|
||||
debugfs_remove(ehci->debug_async);
|
||||
debugfs_remove(ehci->debug_dir);
|
||||
}
|
||||
|
||||
#endif /* STUB_DEBUG_FILES */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
#endif
|
||||
#ifdef PCI_DRIVER
|
||||
pci_unregister_driver(&PCI_DRIVER);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
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);
|
||||
clean1:
|
||||
#endif
|
||||
#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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
152
drivers/usb/host/ehci-ixp4xx.c
Normal file
152
drivers/usb/host/ehci-ixp4xx.c
Normal file
@ -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
|
||||
},
|
||||
};
|
272
drivers/usb/host/ehci-orion.c
Normal file
272
drivers/usb/host/ehci-orion.c
Normal file
@ -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",
|
||||
};
|
@ -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,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
238
drivers/usb/host/ehci-ppc-of.c
Normal file
238
drivers/usb/host/ehci-ppc-of.c
Normal file
@ -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,
|
||||
},
|
||||
};
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
@ -126,6 +126,14 @@ struct ehci_hcd { /* one per controller */
|
||||
# define COUNT(x) do { (x)++; } while (0)
|
||||
#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
|
||||
};
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
143
drivers/usb/host/ohci-sh.c
Normal file
143
drivers/usb/host/ohci-sh.c
Normal file
@ -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,
|
||||
},
|
||||
};
|
||||
|
264
drivers/usb/host/ohci-sm501.c
Normal file
264
drivers/usb/host/ohci-sm501.c
Normal file
@ -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",
|
||||
},
|
||||
};
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 (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);
|
||||
|
||||
if ((cflag & CBAUD) != B0 ) {
|
||||
/* 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 {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user