Commit eba9fb15 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

merge

parents 52d820cb 118d79a8
......@@ -454,6 +454,7 @@ but some optional utilities are provided to simplify common tasks.
</para>
!Edrivers/usb/gadget/usbstring.c
!Edrivers/usb/gadget/config.c
</sect1>
</chapter>
......
......@@ -70,7 +70,9 @@ one or more packets could finish before an error stops further endpoint I/O.
(That is, if drivers see this it's a bug.)
-EPROTO (*) a) bitstuff error
b) unknown USB error
b) no response packet received within the
prescribed bus turn-around time
c) unknown USB error
-EILSEQ (*) CRC mismatch
......
CHANGES
- Created based off of scanner & INSTALL from the original touchscreen
driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
- Amended for linux-2.4.18, then 2.4.19
- Complete rewrite using Linux Input in 2.6.3
Unfortunately no calibration support at this time
DRIVER NOTES:
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
If you have another MicroTouch device that you wish to experiment with
or try using this driver with, but the Vendor and Product ID's are not
coded in, don't despair. If the driver was compiled as a module, you can
pass options to the driver. Simply try:
/sbin/modprobe mtouchusb vendor=0x#### product=0x****
If it works, send me the iVendor & iProduct (or a patch) and I will add...
This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for
download, I persist in updating this driver since I would like to use the
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput.
A little info about the MicroTouch USB controller (14-206):
Y is inverted, and the device has a total possible resolution of 0 - 65535.
Y is inverted by the driver by:
input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
absmin & absmax are also used to scale the data, sine it is rather high
resolution.
---------------touch screen area-----------------
I MicroTouch (xmax,ymax) @I
I X I
I ########visible monitor area############## I
I #@ (xmin,ymin) # I
I # # I
I # # I
I # # I
I # # I
I # # I
I Y # # I
I # # I
I # # I
I # # I
I # # I
I # # I
I # (xmax,ymax) @# I
I ########################################## I
I I
I@ MicroTouch (xmin,ymin) I
-------------------------------------------------
Currently there is no way to calibrate the device via this driver. Perhaps
at some point an abstract function will be placed into evdev so generic
functions like calibrations, resets, and vendor information can be requested
(And the drivers would handle the vendor specific tasks).
ADDITIONAL INFORMATION/UPDATES:
http://groomlakelabs.com/grandamp/code/microtouch/
TODO:
Implement a control urb again to handle requests to and from the device
such as calibration, etc.
DISCLAMER:
I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support
this driver! If you want touch drivers only supported within X, please go to:
http://www.3m.com/3MTouchSystems/downloads/
Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>
Updated 2003 by Henning Meier-Geinitz <henning@meier-geinitz.de>
OVERVIEW
This README addresses issues regarding how to configure the kernel to access a
USB scanner. Although the driver was originally conceived for USB HP
scanners, it's general enough so that it can be used with most other USB
scanners. Also, one can pass the USB Vendor and Product IDs using module
parameters for unknown scanners.
There are two drivers for SCSI-over-USB scanners:
* The "hpusbscsi" module for Hewlett-Packard 53xx series, Hewlett-Packard 7400,
Minolta Scan Dual II, Minolta Elite II
* The "microtek" module for the Microtek Scanmaker X6
In addition to the kernel driver, user-space tools like SANE are necessary to
actually use the scanner. SANE ("Scanner Access Now Easy") provides drivers
for a variety of USB scanners. See the appropriate SANE man page for details,
e.g. man sane-usb and man sane-hp (for HP scanners).
NOTE: Just because a product is detected by this driver does not mean that
applications exist that support the product. It's in the hopes that this will
allow developers a means to produce applications that will support the listed
USB products.
ADDITIONAL INFORMATION
http://www.linux-usb.org/ (General information, mailing lists, links)
http://www.mostang.com/sane/ (SANE user-space tools)
http://www.meier-geinitz.de/kernel/ (USB scanner driver information and patches)
REQUIREMENTS
A host with a USB port. Ideally, either a UHCI (Intel), OHCI (Compaq and
others) or EHCI hardware should work.
Using "make menuconfig" or your preferred method for configuring the kernel,
select "Support for USB", "OHCI HCD/UHCI HCD/EHCI HCD" depending on your
hardware, "USB Scanner support", and "USB device filesystem". Compile and
install the modules (you may need to execute "depmod -a" to update the module
dependencies). If any of the USB sections were compiled into the kernel, a
reboot is necessary. NOTE: Updating the boot disk with "lilo" may also be
required. Testing was performed only as modules, YMMV.
Up to 16 scanners can be connected/used simultaneously. If devfs support is
enabled, see next section. Otherwise, the device files must be created
manually if they don't exist yet, either by MAKEDEV or mknod.
MAKEDEV method:
cd /dev
MAKEDEV usb
Check that the device files "/dev/usb/scanner0" - "/dev/usb/scanner15" have
been created.
mknod method:
mknod /dev/usb/scanner0 c 180 48
mknod /dev/usb/scanner1 c 180 49
.
.
mknod /dev/usb/scanner15 c 180 63
Set appropriate permissions for /dev/usb/scanner[0-15] (don't forget
about group and world permissions). Both read and write permissions
are required for proper operation. For example:
chmod 666 /dev/usb/scanner0
Load the appropriate modules (if compiled as modules):
modprobe ohci-hcd (or uhci-hcd, ehci-hcd)
modprobe scanner
DEVFS
The later versions of the Linux kernel (2.4.8'ish) included a dynamic
device filesystem call "devfs". With devfs, there is no need to
create the device files as explained above; instead, they are
dynamically created for you. For USB Scanner, the device is created
in /dev/usb/scannerX where X can range from 0 to 15 depending on the
number of scanners connected to the system.
To see if you have devfs, issue the command "cat /proc/filesytems".
If devfs is listed you should be ready to go. You should also have a
process running called "devfsd". In order to make sure, issue the
command "ps aux | grep '[d]evfsd'".
CONCLUSION
That's it. SANE should now be able to access the device. To make sure the
device was detected, use "cat /proc/bus/usb/devices". Your scanner should be
listed and the line starting with "I:" should look similar to this example:
I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=usbscanner
The important part is "Driver=usbscanner". If it reads "Driver=(none)", the
USB scanner driver didn't recognize the scanner. Have a look at the MODULE
PARAMETERS section for what to do in this case.
For more details on the format of "/proc/bus/usb/devices" see
Documentation/usb/proc_usb_info.txt.
MESSAGES
usb_control/bulk_msg: timeout -- On occasions this message will appear
in "/var/adm/messages", on the console, or both depending on how
your system is configured. This is a side effect that scanners are
sometimes very slow at warming up and/or initializing. In most cases,
however, only several of these messages should appear and is generally
considered to be normal.
excessive NAK's received -- This message should be considered abnormal
and generally indicates that the USB system is unable to communicate
with the scanner for some particular reason.
probe_scanner: Undetected endpoint -- The USB Scanner driver is fairly
general when it comes to communicating to scanners. Unfortunately,
some vendors have designed their scanners in one way or another that
this driver doesn't account for.
probe_scanner: Endpoint determination failed -- This means that the
driver is unable to detect a supported configuration for means to
communicate with the scanner. See also "probe_scanner: Undetected
endpoint".
funky result -- Most of the time the data flow between the computer
and the scanner goes smoothly. However, due to whatever reason,
whether it be solar flares or stray neutrons, sometimes the
communications don't work as expected. The driver tries to handle
most types of errors but not all. When this message is seen,
something weird happened. Please contact the mailing list (see
CONTACT section for details).
MODULE PARAMETERS
If you have a device that you wish to experiment with or try using
this driver with, but the Vendor and Product IDs are not coded in,
don't despair. If the driver was compiled as a module, you can pass
options to the driver. Simply add
options scanner vendor=0x#### product=0x****
to the /etc/modprobe.conf file replacing the #'s and the *'s with the
correct IDs. The IDs can be retrieved from the messages file or
using "cat /proc/bus/usb/devices".
If the default timeout is too low, i.e. there are frequent "timeout" messages,
you may want to increase the timeout manually by using the parameter
"read_timeout". The time is given in seconds. This is an example for
modprobe.conf with a timeout of 60 seconds:
options scanner read_timeout=60
If the "scanner" module is already loaded into memory, it must be reloaded for
the module parameters to take effect. In essence, "rmmod scanner; modprobe
scanner" must be performed.
BUGS
Just look at the list of fixes in the source files.
CONTACT
For asking about problems and fixes, use the linux-usb-users mailing list. For
patches, linux-usb-devel should be used. Information on both lists can be
found on http://www.linux-usb.org/.
CHANGES
- Amended for linux-2.5.54
- Added information about read_timeout
- Added more details about /proc/bus/usb/devices
- Added/updated links
- Added pointers two "special" scanner drivers
- Reordering, spell-checking, formatting
- Used /dev/usb/scanner[0-15] instead of /dev/usbscanner[0-15]
- Removed some basic USB configuration stuff
- Added EHCI
- Removed some more references to HP
- Amended for linux-2.4.12
- Updated devfs support
- Amended for linux-2.3.99-pre6-3
- Appended hp_scan.c to end of this README
- Removed most references to HP
- Updated uhci/ohci host controller info
- Updated support for multiple scanner support
- Updated supported scanners list
- Updated usbdevfs info
- Spellcheck
HP TEST PROGRAM
There is a small test program (hp_scan.c -- appended below) that can
be used to test the scanner device if it's an HP scanner that supports
SCL (Scanner Control Language). Known HP scanner that support SCL are
the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
supported since it does not understand SCL; it's also strongly
suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
Hp_scan.c's purpose is to test the driver without having to
retrieve/configure SANE. Hp_scan.c will scan the entire bed and put
the output into a file called "out.dat" in the current directory. The
data in the file is raw data so it's not very useful for imaging.
--------------- snip -- hp_scan.c -- snip ---------------
/*
This is a really crude attempt at writing a short test program. It's
mostly only to be used to test connectivity with USB HP scanners that
understand SCL. Currently, the supported models are 4100C, 5200C,
6200C, and the 6300C. Note that the 4200C is *NOT* acceptable.
Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <fcntl.h>
/*
Gray Output produces about a 8945400 byte file.
Color Output produces a 26836200 byte file.
To compile: gcc -o hp_scan hp_scan.c
*/
// #define COLOR /* Undef to scan GrayScale */
int send_cmd(int, const char *, int);
int read_cmd(int, char *, int);
int
main(void) {
ssize_t cnt = 0, total_cnt = 0;
FILE *fpout;
int fp;
int data_size = 32768;
char *data;
static char reset_cmd[] = {'\x1b','E'};
#ifdef COLOR
static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
#else
static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
#endif
static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
if(!(data=malloc(data_size))) {
perror("malloc failed");
exit (1);
}
if((fp=open("/dev/usb/scanner0", O_RDWR)) < 0) {
perror("Unable to open scanner device");
exit (1);
}
if((fpout=fopen("out.dat", "w+")) == NULL) {
perror("Unable to open output file");
exit(1);
}
send_cmd(fp, reset_cmd, sizeof(reset_cmd));
send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
while ((cnt = read(fp, data, data_size)) > 0) {
printf("Read: %u\n", cnt);
if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
perror("Write to output file failed");
exit (1);
}
total_cnt += cnt;
}
if (cnt < 0) {
perror("Read from scanner failed");
exit (1);
}
printf("\nRead %lu bytes.\n", total_cnt);
send_cmd(fp, reset_cmd, sizeof(reset_cmd));
close(fp);
fclose(fpout);
return (0);
}
int
send_cmd(int fp, const char * cmd, int length) {
int result;
int x;
if((result = write(fp, cmd, length)) != length) {
printf ("Write warning: %d bytes requested, %d written\n");
} else if (result < 0) {
perror ("send_cmd failure");
exit (1);
}
return (result);
}
int
read_cmd(int fp, char * response, int length) {
return read(fp, response, length);
}
......@@ -135,7 +135,7 @@ static int iforce_usb_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *epirq, *epout;
struct iforce *iforce;
interface = &intf->altsetting[intf->act_altsetting];
interface = intf->cur_altsetting;
epirq = &interface->endpoint[0].desc;
epout = &interface->endpoint[1].desc;
......
......@@ -1040,6 +1040,52 @@ static struct net_device_stats *stir_net_get_stats(struct net_device *dev)
return &stir->stats;
}
/*
* Parse the various endpoints and find the one we need.
*
* The endpoint are the pipes used to communicate with the USB device.
* The spec defines 2 endpoints of type bulk transfer, one in, and one out.
* These are used to pass frames back and forth with the dongle.
*/
static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf)
{
struct usb_device *usbdev = interface_to_usbdev(intf);
const struct usb_host_interface *interface = intf->cur_altsetting;
const struct usb_endpoint_descriptor *ep_in = NULL;
const struct usb_endpoint_descriptor *ep_out = NULL;
int i;
if (interface->desc.bNumEndpoints != 2) {
WARNING("%s: expected two endpoints\n", __FUNCTION__);
return -ENODEV;
}
for(i = 0; i < interface->desc.bNumEndpoints; i++) {
const struct usb_endpoint_descriptor *ep
= &interface->endpoint[i].desc;
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* We need to find an IN and an OUT */
if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
} else
WARNING("%s: unknown endpoint type 0x%x\n",
__FUNCTION__, ep->bmAttributes);
}
if (!ep_in || !ep_out)
return -EIO;
stir->tx_bulkpipe = usb_sndbulkpipe(usbdev,
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
stir->rx_intpipe = usb_rcvintpipe(usbdev,
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
return 0;
}
/*
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
......
......@@ -20,10 +20,15 @@ obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB_AIPTEK) += input/
obj-$(CONFIG_USB_ATI_REMOTE) += input/
obj-$(CONFIG_USB_HID) += input/
obj-$(CONFIG_USB_KBD) += input/
obj-$(CONFIG_USB_KBTAB) += input/
obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_WACOM) += input/
obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_DABUSB) += media/
obj-$(CONFIG_USB_DSBR) += media/
......
......@@ -3,7 +3,7 @@
/*
* audio.c -- USB Audio Class driver
*
* Copyright (C) 1999, 2000, 2001
* Copyright (C) 1999, 2000, 2001, 2003, 2004
* Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
......@@ -101,6 +101,8 @@
* Fix SNDCTL_DSP_STEREO API violation
* 2003-04-08: Oliver Neukum (oliver@neukum.name):
* Setting a configuration is done by usbcore and must not be overridden
* 2004-02-27: Workaround for broken synch descriptors
*
*/
/*
......@@ -1542,12 +1544,13 @@ static int set_format_in(struct usb_audiodev *as)
alts->endpoint[1].desc.bmAttributes != 0x01 ||
alts->endpoint[1].desc.bSynchAddress != 0 ||
alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
"but has invalid synch pipe; treating as asynchronous in\n",
dev->devnum, u->interface, fmt->altsetting);
return -1;
} else {
u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
u->syncinterval = alts->endpoint[1].desc.bRefresh;
}
u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
u->syncinterval = alts->endpoint[1].desc.bRefresh;
}
if (d->srate < fmt->sratelo)
d->srate = fmt->sratelo;
......@@ -1637,12 +1640,13 @@ static int set_format_out(struct usb_audiodev *as)
alts->endpoint[1].desc.bmAttributes != 0x01 ||
alts->endpoint[1].desc.bSynchAddress != 0 ||
alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) {
printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
"but has invalid synch pipe; treating as adaptive out\n",
dev->devnum, u->interface, fmt->altsetting);
return -1;
} else {
u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
u->syncinterval = alts->endpoint[1].desc.bRefresh;
}
u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
u->syncinterval = alts->endpoint[1].desc.bRefresh;
}
if (d->srate < fmt->sratelo)
d->srate = fmt->sratelo;
......
......@@ -72,13 +72,10 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char
return buffer - buffer0;
}
static void usb_release_intf(struct device *dev)
static void usb_free_intf(struct usb_interface *intf)
{
struct usb_interface *intf;
int j;
intf = to_usb_interface(dev);
if (intf->altsetting) {
for (j = 0; j < intf->num_altsetting; j++) {
struct usb_host_interface *as = &intf->altsetting[j];
......@@ -235,8 +232,6 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer, int si
return -ENOMEM;
}
memset(interface, 0, sizeof(struct usb_interface));
interface->dev.release = usb_release_intf;
device_initialize(&interface->dev);
}
/* Go through the descriptors, checking their length and counting the
......@@ -374,7 +369,7 @@ void usb_destroy_configuration(struct usb_device *dev)
struct usb_interface *ifp = cf->interface[i];
if (ifp)
put_device(&ifp->dev);
usb_free_intf(ifp);
}
}
kfree(dev->config);
......
......@@ -430,19 +430,14 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
static int findintfif(struct usb_device *dev, unsigned int ifn)
{
unsigned int i, j;
struct usb_interface *iface;
struct usb_host_interface *alts;
unsigned int i;
if (ifn & ~0xff)
return -EINVAL;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
iface = dev->actconfig->interface[i];
for (j = 0; j < iface->num_altsetting; j++) {
alts = &iface->altsetting[j];
if (alts->desc.bInterfaceNumber == ifn)
return i;
}
if (dev->actconfig->interface[i]->
altsetting[0].desc.bInterfaceNumber == ifn)
return i;
}
return -ENOENT;
}
......@@ -688,9 +683,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
return -EFAULT;
if ((ret = findintfif(ps->dev, gd.interface)) < 0)
return ret;
interface = usb_ifnum_to_if(ps->dev, gd.interface);
if (!interface)
return -EINVAL;
interface = ps->dev->actconfig->interface[ret];
if (!interface->driver)
return -ENODATA;
strcpy(gd.driver, interface->driver->name);
......@@ -744,9 +737,7 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)
return -EFAULT;
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
return ret;
interface = usb_ifnum_to_if(ps->dev, setintf.interface);
if (!interface)
return -EINVAL;
interface = ps->dev->actconfig->interface[ret];
if (interface->driver) {
if ((ret = checkintf(ps, ret)))
return ret;
......
......@@ -166,13 +166,9 @@ void usb_create_driverfs_dev_files (struct usb_device *udev)
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
struct usb_interface *intf; \
int alt; \
struct usb_interface *intf = to_usb_interface (dev); \
\
intf = to_usb_interface (dev); \
alt = intf->act_altsetting; \
\
return sprintf (buf, format_string, intf->altsetting[alt].desc.field); \
return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
......
......@@ -147,8 +147,12 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
hcd->driver = driver;
hcd->description = driver->description;
hcd->self.bus_name = pci_name(dev);
#ifdef CONFIG_PCI_NAMES
hcd->product_desc = dev->pretty_name;
#else
if (hcd->product_desc == NULL)
hcd->product_desc = "USB Host Controller";
#endif
hcd->self.controller = &dev->dev;
if ((retval = hcd_buffer_create (hcd)) != 0) {
......
......@@ -560,7 +560,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_hub *hub;
unsigned long flags;
desc = intf->altsetting + intf->act_altsetting;
desc = intf->cur_altsetting;
dev = interface_to_usbdev(intf);
/* Some hubs have a subclass of 1, which AFAICT according to the */
......@@ -1344,15 +1344,15 @@ int usb_physical_reset_device(struct usb_device *dev)
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf = dev->actconfig->interface[i];
struct usb_interface_descriptor *as;
struct usb_interface_descriptor *desc;
as = &intf->altsetting[intf->act_altsetting].desc;
ret = usb_set_interface(dev, as->bInterfaceNumber,
as->bAlternateSetting);
desc = &intf->cur_altsetting->desc;
ret = usb_set_interface(dev, desc->bInterfaceNumber,
desc->bAlternateSetting);
if (ret < 0) {
err("failed to set active alternate setting "
"for dev %s interface %d (error=%d)",
dev->devpath, i, ret);
dev->devpath, desc->bInterfaceNumber, ret);
return ret;
}
}
......
......@@ -783,16 +783,22 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
*/
void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
{
struct usb_host_interface *hintf =
&intf->altsetting[intf->act_altsetting];
struct usb_host_interface *alt = intf->cur_altsetting;
int i;
for (i = 0; i < hintf->desc.bNumEndpoints; ++i) {
for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
usb_disable_endpoint(dev,
hintf->endpoint[i].desc.bEndpointAddress);
alt->endpoint[i].desc.bEndpointAddress);
}
}
static void release_interface(struct device *dev)
{
struct usb_interface *interface = to_usb_interface(dev);
complete(interface->released);
}
/*
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
......@@ -822,12 +828,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *interface;
struct completion intf_completion;
/* remove this interface */
interface = dev->actconfig->interface[i];
dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
device_del(&interface->dev);
init_completion (&intf_completion);
interface->released = &intf_completion;
device_unregister (&interface->dev);
wait_for_completion (&intf_completion);
}
dev->actconfig = 0;
if (dev->state == USB_STATE_CONFIGURED)
......@@ -876,12 +886,11 @@ void usb_enable_endpoint(struct usb_device *dev,
void usb_enable_interface(struct usb_device *dev,
struct usb_interface *intf)
{
struct usb_host_interface *hintf =
&intf->altsetting[intf->act_altsetting];
struct usb_host_interface *alt = intf->cur_altsetting;
int i;
for (i = 0; i < hintf->desc.bNumEndpoints; ++i)
usb_enable_endpoint(dev, &hintf->endpoint[i].desc);
for (i = 0; i < alt->desc.bNumEndpoints; ++i)
usb_enable_endpoint(dev, &alt->endpoint[i].desc);
}
/**
......@@ -920,6 +929,7 @@ void usb_enable_interface(struct usb_device *dev,
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
struct usb_interface *iface;
struct usb_host_interface *alt;
int ret;
int manual = 0;
......@@ -929,14 +939,15 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
return -EINVAL;
}
if (alternate < 0 || alternate >= iface->num_altsetting)
alt = usb_altnum_to_altsetting(iface, alternate);
if (!alt) {
warn("selecting invalid altsetting %d", alternate);
return -EINVAL;
}
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
iface->altsetting[alternate]
.desc.bAlternateSetting,
interface, NULL, 0, HZ * 5);
alternate, interface, NULL, 0, HZ * 5);
/* 9.4.10 says devices don't need this and are free to STALL the
* request if the interface only has one alternate setting.
......@@ -957,7 +968,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
/* prevent submissions using previous endpoint settings */
usb_disable_interface(dev, iface);
iface->act_altsetting = alternate;
iface->cur_altsetting = alt;
/* If the interface only has one altsetting and the device didn't
* accept the request, we attempt to carry out the equivalent action
......@@ -965,13 +976,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* new altsetting.
*/
if (manual) {
struct usb_host_interface *iface_as =
&iface->altsetting[alternate];
int i;
for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
unsigned int epaddr =
iface_as->endpoint[i].desc.bEndpointAddress;
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);
......@@ -1045,8 +1054,19 @@ int usb_reset_configuration(struct usb_device *dev)
/* re-init hc/hcd interface/endpoint state */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt;
alt = usb_altnum_to_altsetting(intf, 0);
intf->act_altsetting = 0;
/* No altsetting 0? We'll assume the first altsetting.
* We could use a GetInterface call, but if a device is
* so non-compliant that it doesn't have altsetting 0
* then I wouldn't trust its reply anyway.
*/
if (!alt)
alt = &intf->altsetting[0];
intf->cur_altsetting = alt;
usb_enable_interface(dev, intf);
}
return 0;
......@@ -1135,25 +1155,34 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
*/
for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
struct usb_interface *intf = cp->interface[i];
struct usb_interface_descriptor *desc;
struct usb_host_interface *alt;
intf->act_altsetting = 0;
desc = &intf->altsetting [0].desc;
usb_enable_interface(dev, intf);
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
* We could use a GetInterface call, but if a device is
* so non-compliant that it doesn't have altsetting 0
* then I wouldn't trust its reply anyway.
*/
if (!alt)
alt = &intf->altsetting[0];
intf->cur_altsetting = alt;
usb_enable_interface(dev, intf);
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.dma_mask = dev->dev.dma_mask;
intf->dev.release = release_interface;
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration,
desc->bInterfaceNumber);
alt->desc.bInterfaceNumber);
dev_dbg (&dev->dev,
"registering %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration,
desc->bInterfaceNumber);
device_add (&intf->dev);
alt->desc.bInterfaceNumber);
device_register (&intf->dev);
usb_create_driverfs_intf_files (intf);
}
}
......
......@@ -189,7 +189,7 @@ void usb_deregister(struct usb_driver *driver)
}
/**
* usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
* usb_ifnum_to_if - get the interface object with a given interface number
* @dev: the device whose current configuration is considered
* @ifnum: the desired interface
*
......@@ -219,6 +219,33 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
return NULL;
}
/**
* usb_altnum_to_altsetting - get the altsetting structure with a given
* alternate setting number.
* @intf: the interface containing the altsetting in question
* @altnum: the desired alternate setting number
*
* This searches the altsetting array of the specified interface for
* an entry with the correct bAlternateSetting value and returns a pointer
* to that entry, or null.
*
* Note that altsettings need not be stored sequentially by number, so
* it would be incorrect to assume that the first altsetting entry in
* the array corresponds to altsetting zero. This routine helps device
* drivers avoid such mistakes.
*/
struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
unsigned int altnum)
{
int i;
for (i = 0; i < intf->num_altsetting; i++) {
if (intf->altsetting[i].desc.bAlternateSetting == altnum)
return &intf->altsetting[i];
}
return NULL;
}
/**
* usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
* @dev: the device whose current configuration+altsettings is considered
......@@ -247,7 +274,7 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
/* only endpoints in current altsetting are active */
intf = config->interface[i];
alt = intf->altsetting + intf->act_altsetting;
alt = intf->cur_altsetting;
for (k = 0; k < alt->desc.bNumEndpoints; k++)
if (epnum == alt->endpoint[k].desc.bEndpointAddress)
......@@ -421,7 +448,7 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
if (id == NULL)
return NULL;
intf = &interface->altsetting [interface->act_altsetting];
intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);
/* It is important to check that id->driver_info is nonzero,
......@@ -624,7 +651,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
struct usb_host_interface *alt = intf->cur_altsetting;
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
......@@ -633,9 +660,9 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"INTERFACE=%d/%d/%d",
intf->altsetting[alt].desc.bInterfaceClass,
intf->altsetting[alt].desc.bInterfaceSubClass,
intf->altsetting[alt].desc.bInterfaceProtocol);
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
......@@ -1582,6 +1609,7 @@ EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
EXPORT_SYMBOL(usb_altnum_to_altsetting);
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_disconnect);
......
......@@ -9,7 +9,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o
# USB gadget drivers
#
g_zero-objs := zero.o usbstring.o
g_ether-objs := ether.o usbstring.o
g_ether-objs := ether.o usbstring.o config.o
g_serial-objs := serial.o usbstring.o
gadgetfs-objs := inode.o usbstring.o
g_file_storage-objs := file_storage.o usbstring.o
......
/*
* usb/gadget/config.c -- simplify building config descriptors
*
* Copyright (C) 2003 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/usb_ch9.h>
/**
* usb_descriptor_fillbuf - fill buffer with descriptors
* @buf: Buffer to be filled
* @buflen: Size of buf
* @src: Array of descriptor pointers, terminated by null pointer.
*
* Copies descriptors into the buffer, returning the length or a
* negative error code if they can't all be copied. Useful when
* assembling descriptors for an associated set of interfaces used
* as part of configuring a composite device; or in other cases where
* sets of descriptors need to be marshaled.
*/
int
usb_descriptor_fillbuf(void *buf, unsigned buflen,
const struct usb_descriptor_header **src)
{
u8 *dest = buf;
if (!src)
return -EINVAL;
/* fill buffer from src[] until null descriptor ptr */
for (; 0 != *src; src++) {
unsigned len = (*src)->bLength;
if (len > buflen);
return -EINVAL;
memcpy(dest, *src, len);
buflen -= len;
dest += len;
}
return dest - (u8 *)buf;
}
/**
* usb_gadget_config_buf - builts a complete configuration descriptor
* @config: Header for the descriptor, including characteristics such
* as power requirements and number of interfaces.
* @desc: Null-terminated vector of pointers to the descriptors (interface,
* endpoint, etc) defining all functions in this device configuration.
* @buf: Buffer for the resulting configuration descriptor.
* @length: Length of buffer. If this is not big enough to hold the
* entire configuration descriptor, an error code will be returned.
*
* This copies descriptors into the response buffer, building a descriptor
* for that configuration. It returns the buffer length or a negative
* status code. The config.wTotalLength field is set to match the length
* of the result, but other descriptor fields (including power usage and
* interface count) must be set by the caller.
*
* Gadget drivers could use this when constructing a config descriptor
* in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
* resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
*/
int usb_gadget_config_buf(
const struct usb_config_descriptor *config,
void *buf,
unsigned length,
const struct usb_descriptor_header **desc
)
{
struct usb_config_descriptor *cp = buf;
int len;
/* config descriptor first */
if (length < USB_DT_CONFIG_SIZE || !desc)
return -EINVAL;
*cp = *config;
/* then interface/endpoint/class/vendor/... */
len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
length - USB_DT_CONFIG_SIZE, desc);
if (len < 0)
return len;
len += USB_DT_CONFIG_SIZE;
if (len > 0xffff)
return -EINVAL;
/* patch up the config descriptor */
cp->bLength = USB_DT_CONFIG_SIZE;
cp->bDescriptorType = USB_DT_CONFIG;
cp->wTotalLength = cpu_to_le16(len);
cp->bmAttributes |= USB_CONFIG_ATT_ONE;
return len;
}
......@@ -607,6 +607,25 @@ fs_sink_desc = {
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
static const struct usb_descriptor_header *fs_function [] = {
#ifdef DEV_CONFIG_CDC
/* "cdc" mode descriptors */
(struct usb_descriptor_header *) &control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &union_desc,
(struct usb_descriptor_header *) &ether_desc,
#ifdef EP_STATUS_NUM
(struct usb_descriptor_header *) &fs_status_desc,
#endif
(struct usb_descriptor_header *) &data_nop_intf,
#endif /* DEV_CONFIG_CDC */
/* minimalist core */
(struct usb_descriptor_header *) &data_intf,
(struct usb_descriptor_header *) &fs_source_desc,
(struct usb_descriptor_header *) &fs_sink_desc,
0,
};
#ifdef HIGHSPEED
/*
......@@ -660,6 +679,25 @@ dev_qualifier = {
.bNumConfigurations = 1,
};
static const struct usb_descriptor_header *hs_function [] = {
#ifdef DEV_CONFIG_CDC
/* "cdc" mode descriptors */
(struct usb_descriptor_header *) &control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &union_desc,
(struct usb_descriptor_header *) &ether_desc,
#ifdef EP_STATUS_NUM
(struct usb_descriptor_header *) &hs_status_desc,
#endif
(struct usb_descriptor_header *) &data_nop_intf,
#endif /* DEV_CONFIG_CDC */
/* minimalist core */
(struct usb_descriptor_header *) &data_intf,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
0,
};
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
......@@ -704,86 +742,25 @@ static struct usb_gadget_strings stringtab = {
static int
config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
{
const unsigned config_len = USB_DT_CONFIG_SIZE
#ifdef DEV_CONFIG_CDC
+ 2 * USB_DT_INTERFACE_SIZE
+ sizeof header_desc
+ sizeof union_desc
+ sizeof ether_desc
#ifdef EP_STATUS_NUM
+ USB_DT_ENDPOINT_SIZE
#endif
#endif /* DEV_CONFIG_CDC */
+ USB_DT_INTERFACE_SIZE
+ 2 * USB_DT_ENDPOINT_SIZE;
int len;
const struct usb_descriptor_header **function = fs_function;
#ifdef HIGHSPEED
int hs;
#endif
/* a single configuration must always be index 0 */
if (index > 0)
return -EINVAL;
if (config_len > USB_BUFSIZ)
return -EDOM;
int hs = (speed == USB_SPEED_HIGH);
/* config (or other speed config) */
memcpy (buf, &eth_config, USB_DT_CONFIG_SIZE);
buf [1] = type;
((struct usb_config_descriptor *) buf)->wTotalLength
= __constant_cpu_to_le16 (config_len);
buf += USB_DT_CONFIG_SIZE;
#ifdef HIGHSPEED
hs = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
#endif
#ifdef DEV_CONFIG_CDC
/* control interface, class descriptors, optional status endpoint */
memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE);
buf += USB_DT_INTERFACE_SIZE;
memcpy (buf, &header_desc, sizeof header_desc);
buf += sizeof header_desc;
memcpy (buf, &union_desc, sizeof union_desc);
buf += sizeof union_desc;
memcpy (buf, &ether_desc, sizeof ether_desc);
buf += sizeof ether_desc;
#ifdef EP_STATUS_NUM
#ifdef HIGHSPEED
if (hs)
memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE);
else
#endif /* HIGHSPEED */
memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
#endif /* EP_STATUS_NUM */
/* default data altsetting has no endpoints */
memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE);
buf += USB_DT_INTERFACE_SIZE;
#endif /* DEV_CONFIG_CDC */
/* the "real" data interface has two endpoints */
memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE);
buf += USB_DT_INTERFACE_SIZE;
#ifdef HIGHSPEED
if (hs) {
memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
} else
function = hs_function;
#endif
{
memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
}
return config_len;
/* a single configuration must always be index 0 */
if (index > 0)
return -EINVAL;
len = usb_gadget_config_buf (&eth_config, buf, USB_BUFSIZ, function);
if (len < 0)
return len;
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
}
/*-------------------------------------------------------------------------*/
......
......@@ -16,24 +16,89 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include <asm/unaligned.h>
static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
{
int count = 0;
u8 c;
u16 uchar;
/* this insists on correct encodings, though not minimal ones.
* BUT it currently rejects legit 4-byte UTF-8 code points,
* which need surrogate pairs. (Unicode 3.1 can use them.)
*/
while (len != 0 && (c = (u8) *s++) != 0) {
if (unlikely(c & 0x80)) {
// 2-byte sequence:
// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
if ((c & 0xe0) == 0xc0) {
uchar = (c & 0x1f) << 6;
c = (u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c;
// 3-byte sequence (most CJKV characters):
// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
} else if ((c & 0xf0) == 0xe0) {
uchar = (c & 0x0f) << 12;
c = (u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c << 6;
c = (u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c;
/* no bogus surrogates */
if (0xd800 <= uchar && uchar <= 0xdfff)
goto fail;
// 4-byte sequence (surrogate pairs, currently rare):
// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
// = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
// (uuuuu = wwww + 1)
// FIXME accept the surrogate code points (only)
} else
goto fail;
} else
uchar = c;
put_unaligned (cpu_to_le16 (uchar), cp++);
count++;
len--;
}
return count;
fail:
return -1;
}
/**
* usb_gadget_get_string - fill out a string descriptor
* @table: of c strings using iso latin/1 characters
* @table: of c strings encoded using UTF-8
* @id: string id, from low byte of wValue in get string descriptor
* @buf: at least 256 bytes
*
* Finds the iso latin/1 string matching the ID, and converts it into a
* Finds the UTF-8 string matching the ID, and converts it into a
* string descriptor in utf16-le.
* Returns length of descriptor (always even) or negative errno
*
* If your driver needs stings in multiple languages, you'll need to
* to use some alternate solution for languages where the ISO 8859/1
* (latin/1) character set can't be used. For example, they can't be
* used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other
* languages. You'd likely "switch (wIndex) { ... }" in your ep0
* string descriptor logic, using this routine in cases where "western
* european" characters suffice for the strings being returned.
* If your driver needs stings in multiple languages, you'll probably
* "switch (wIndex) { ... }" in your ep0 string descriptor logic,
* using this routine after choosing which set of UTF-8 strings to use.
* Note that US-ASCII is a strict subset of UTF-8; any string bytes with
* the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
* characters (which are also widely used in C strings).
*/
int
usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
......@@ -59,13 +124,12 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
/* string descriptors have length, tag, then UTF16-LE text */
len = min ((size_t) 126, strlen (s->s));
memset (buf + 2, 0, 2 * len); /* zero all the bytes */
len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
if (len < 0)
return -EINVAL;
buf [0] = (len + 1) * 2;
buf [1] = USB_DT_STRING;
memset (buf + 2, 0, 2 * len); /* zero all the high bytes */
while (len) {
buf [2 * len] = s->s [len - 1];
len--;
}
return buf [0];
}
......@@ -29,6 +29,15 @@ 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_OHCI_HCD
tristate "OHCI HCD support"
depends on USB
......
......@@ -579,7 +579,11 @@ show_periodic (struct class_device *class_dev, char *buf)
break;
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd/%p", p.sitd);
" sitd%d-%04x/%p",
p.sitd->stream->interval,
le32_to_cpup (&p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
tag = Q_NEXT_TYPE (p.sitd->hw_next);
p = p.sitd->sitd_next;
break;
......
......@@ -106,8 +106,6 @@ static const char hcd_name [] = "ehci_hcd";
#undef EHCI_VERBOSE_DEBUG
#undef EHCI_URB_TRACE
// #define have_split_iso
#ifdef DEBUG
#define EHCI_STATS
#endif
......@@ -676,6 +674,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
/* the IO watchdog guards against hardware or driver bugs that
* misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235.
*/
if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG);
......@@ -796,13 +795,8 @@ static int ehci_urb_enqueue (
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
return itd_submit (ehci, urb, mem_flags);
#ifdef have_split_iso
else
return sitd_submit (ehci, urb, mem_flags);
#else
dbg ("no split iso support yet");
return -ENOSYS;
#endif /* have_split_iso */
}
}
......
......@@ -53,14 +53,10 @@ periodic_next_shadow (union ehci_shadow *periodic, int tag)
return &periodic->fstn->fstn_next;
case Q_TYPE_ITD:
return &periodic->itd->itd_next;
#ifdef have_split_iso
case Q_TYPE_SITD:
// case Q_TYPE_SITD:
default:
return &periodic->sitd->sitd_next;
#endif /* have_split_iso */
}
dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
// BUG ();
return 0;
}
/* returns true after successful unlink */
......@@ -133,7 +129,6 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
break;
#ifdef have_split_iso
case Q_TYPE_SITD:
/* is it in the S-mask? (count SPLIT, DATA) */
if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
......@@ -154,7 +149,6 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
hw_p = &q->sitd->hw_next;
q = &q->sitd->sitd_next;
break;
#endif /* have_split_iso */
default:
BUG ();
}
......@@ -229,7 +223,8 @@ static int tt_no_collision (
if (same_tt (dev, here.itd->urb->dev)) {
u16 mask;
mask = le32_to_cpu (here.sitd->hw_uframe);
mask = le32_to_cpu (here.sitd
->hw_uframe);
/* FIXME assumes no gap for IN! */
mask |= mask >> 8;
if (mask & uf_mask)
......@@ -237,7 +232,7 @@ static int tt_no_collision (
}
type = Q_NEXT_TYPE (here.qh->hw_next);
here = here.sitd->sitd_next;
break;
continue;
// case Q_TYPE_FSTN:
default:
ehci_dbg (ehci,
......@@ -698,12 +693,27 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
// BUG_ON (!list_empty(&stream->td_list));
while (!list_empty (&stream->free_list)) {
struct ehci_itd *itd;
itd = list_entry (stream->free_list.next,
struct ehci_itd, itd_list);
list_del (&itd->itd_list);
dma_pool_free (ehci->itd_pool, itd, itd->itd_dma);
struct list_head *entry;
entry = stream->free_list.next;
list_del (entry);
/* knows about ITD vs SITD */
if (stream->highspeed) {
struct ehci_itd *itd;
itd = list_entry (entry, struct ehci_itd,
itd_list);
dma_pool_free (ehci->itd_pool, itd,
itd->itd_dma);
} else {
struct ehci_sitd *sitd;
sitd = list_entry (entry, struct ehci_sitd,
sitd_list);
dma_pool_free (ehci->sitd_pool, sitd,
sitd->sitd_dma);
}
}
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
......@@ -858,6 +868,7 @@ itd_urb_transaction (
int i;
unsigned num_itds;
struct ehci_iso_sched *sched;
unsigned long flags;
sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
if (unlikely (sched == 0))
......@@ -871,6 +882,7 @@ itd_urb_transaction (
num_itds = urb->number_of_packets;
/* allocate/init ITDs */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < num_itds; i++) {
/* free_list.next might be cache-hot ... but maybe
......@@ -884,8 +896,14 @@ itd_urb_transaction (
list_del (&itd->itd_list);
itd_dma = itd->itd_dma;
} else
itd = 0;
if (!itd) {
spin_unlock_irqrestore (&ehci->lock, flags);
itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
&itd_dma);
spin_lock_irqsave (&ehci->lock, flags);
}
if (unlikely (0 == itd)) {
iso_sched_free (stream, sched);
......@@ -895,6 +913,7 @@ itd_urb_transaction (
itd->itd_dma = itd_dma;
list_add (&itd->itd_list, &sched->td_list);
}
spin_unlock_irqrestore (&ehci->lock, flags);
/* temporarily store schedule info in hcpriv */
urb->hcpriv = sched;
......@@ -909,11 +928,11 @@ itd_slot_ok (
struct ehci_hcd *ehci,
u32 mod,
u32 uframe,
u32 end,
u8 usecs,
u32 period
)
{
uframe %= period;
do {
/* can't commit more than 80% periodic == 100 usec */
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
......@@ -922,8 +941,7 @@ itd_slot_ok (
/* we know urb->interval is 2^N uframes */
uframe += period;
uframe %= mod;
} while (uframe != end);
} while (uframe < mod);
return 1;
}
......@@ -933,7 +951,6 @@ sitd_slot_ok (
u32 mod,
struct ehci_iso_stream *stream,
u32 uframe,
u32 end,
struct ehci_iso_sched *sched,
u32 period_uframes
)
......@@ -952,12 +969,20 @@ sitd_slot_ok (
*/
/* check bandwidth */
uframe %= period_uframes;
do {
u32 max_used;
frame = uframe >> 3;
uf = uframe & 7;
/* tt must be idle for start(s), any gap, and csplit.
* assume scheduling slop leaves 10+% for control/bulk.
*/
if (!tt_no_collision (ehci, period_uframes << 3,
stream->udev, frame, mask))
return 0;
/* check starts (OUT uses more than one) */
max_used = 100 - stream->usecs;
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
......@@ -969,25 +994,19 @@ sitd_slot_ok (
if (stream->c_usecs) {
max_used = 100 - stream->c_usecs;
do {
/* tt is busy in the gap before CSPLIT */
tmp = 1 << uf;
mask |= tmp;
tmp <<= 8;
if (stream->raw_mask & tmp)
break;
if ((stream->raw_mask & tmp) == 0)
continue;
if (periodic_usecs (ehci, frame, uf)
> max_used)
return 0;
} while (++uf < 8);
if (periodic_usecs (ehci, frame, uf) > max_used)
return 0;
}
/* we know urb->interval is 2^N uframes */
uframe += period_uframes;
uframe %= mod;
} while (uframe != end);
/* tt must be idle for start(s), any gap, and csplit */
if (!tt_no_collision (ehci, period_uframes, stream->udev, frame, mask))
return 0;
} while (uframe < mod);
stream->splits = stream->raw_mask << (uframe & 7);
cpu_to_le32s (&stream->splits);
......@@ -1014,7 +1033,7 @@ iso_stream_schedule (
struct ehci_iso_stream *stream
)
{
u32 now, start, end, max, period;
u32 now, start, max, period;
int status;
unsigned mod = ehci->periodic_size << 3;
struct ehci_iso_sched *sched = urb->hcpriv;
......@@ -1036,8 +1055,6 @@ iso_stream_schedule (
/* when's the last uframe this urb could start? */
max = now + mod;
max -= sched->span;
max -= 8 * SCHEDULE_SLOP;
/* typical case: reuse current schedule. stream is still active,
* and no gaps from host falling behind (irq delays etc)
......@@ -1046,9 +1063,11 @@ iso_stream_schedule (
start = stream->next_uframe;
if (start < now)
start += mod;
if (likely (start < max))
if (likely ((start + sched->span) < max))
goto ready;
/* else fell behind; try to reschedule */
/* else fell behind; someday, try to reschedule */
status = -EL2NSYNC;
goto fail;
}
/* need to schedule; when's the next (u)frame we could start?
......@@ -1059,63 +1078,40 @@ iso_stream_schedule (
*/
start = SCHEDULE_SLOP * 8 + (now & ~0x07);
start %= mod;
end = start;
stream->next_uframe = start;
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
period = urb->interval;
if (!stream->highspeed)
period <<= 3;
if (max > (start + period))
max = start + period;
/* hack: account for itds already scheduled to this endpoint */
if (list_empty (&stream->td_list))
end = max;
/* within [start..max] find a uframe slot with enough bandwidth */
end %= mod;
do {
/* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) {
int enough_space;
/* check schedule: enough space? */
if (stream->highspeed)
enough_space = itd_slot_ok (ehci, mod, start, end,
enough_space = itd_slot_ok (ehci, mod, start,
stream->usecs, period);
else {
if ((start % 8) >= 6)
continue;
enough_space = sitd_slot_ok (ehci, mod, stream,
start, end, sched, period);
start, sched, period);
}
/* (re)schedule it here if there's enough bandwidth */
/* schedule it here if there's enough bandwidth */
if (enough_space) {
start %= mod;
if (unlikely (!list_empty (&stream->td_list))) {
/* host fell behind ... maybe irq latencies
* delayed this request queue for too long.
*/
stream->rescheduled++;
dev_dbg (&urb->dev->dev,
"iso%d%s %d.%d skip %d.%d\n",
stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN)
? "in" : "out",
stream->next_uframe >> 3,
stream->next_uframe & 0x7,
start >> 3, start & 0x7);
}
stream->next_uframe = start;
stream->next_uframe = start % mod;
goto ready;
}
} while (++start < max);
}
/* no room in the schedule */
ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n",
ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n",
list_empty (&stream->td_list) ? "" : "re",
urb, now, end, max);
urb, now, max);
status = -ENOSPC;
fail:
......@@ -1260,6 +1256,7 @@ itd_link_urb (
iso_sched_free (stream, iso_sched);
urb->hcpriv = 0;
timer_action (ehci, TIMER_IO_WATCHDOG);
if (unlikely (!ehci->periodic_sched++))
return enable_periodic (ehci);
return 0;
......@@ -1404,18 +1401,392 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
return status;
}
#ifdef have_split_iso
#ifdef CONFIG_USB_EHCI_SPLIT_ISO
/*-------------------------------------------------------------------------*/
/*
* "Split ISO TDs" ... used for USB 1.1 devices going through
* the TTs in USB 2.0 hubs.
*
* FIXME not yet implemented
* "Split ISO TDs" ... used for USB 1.1 devices going through the
* TTs in USB 2.0 hubs. These need microframe scheduling.
*/
#endif /* have_split_iso */
static inline void
sitd_sched_init (
struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream,
struct urb *urb
)
{
unsigned i;
dma_addr_t dma = urb->transfer_dma;
/* how many frames are needed for these transfers */
iso_sched->span = urb->number_of_packets * stream->interval;
/* figure out per-frame sitd fields that we'll need later
* when we fit new sitds into the schedule.
*/
for (i = 0; i < urb->number_of_packets; i++) {
struct ehci_iso_packet *packet = &iso_sched->packet [i];
unsigned length;
dma_addr_t buf;
u32 trans;
length = urb->iso_frame_desc [i].length & 0x03ff;
buf = dma + urb->iso_frame_desc [i].offset;
trans = SITD_STS_ACTIVE;
if (((i + 1) == urb->number_of_packets)
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= SITD_IOC;
trans |= length << 16;
packet->transaction = cpu_to_le32 (trans);
/* might need to cross a buffer page within a td */
packet->bufp = buf;
buf += length;
packet->buf1 = buf & ~0x0fff;
if (packet->buf1 != (buf & ~(u64)0x0fff))
packet->cross = 1;
/* OUT uses multiple start-splits */
if (stream->bEndpointAddress & USB_DIR_IN)
continue;
length = 1 + (length / 188);
packet->buf1 |= length;
if (length > 1) /* BEGIN vs ALL */
packet->buf1 |= 1 << 3;
}
}
static int
sitd_urb_transaction (
struct ehci_iso_stream *stream,
struct ehci_hcd *ehci,
struct urb *urb,
int mem_flags
)
{
struct ehci_sitd *sitd;
dma_addr_t sitd_dma;
int i;
struct ehci_iso_sched *iso_sched;
unsigned long flags;
iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
if (iso_sched == 0)
return -ENOMEM;
sitd_sched_init (iso_sched, stream, urb);
/* allocate/init sITDs */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < urb->number_of_packets; i++) {
/* NOTE: for now, we don't try to handle wraparound cases
* for IN (using sitd->hw_backpointer, like a FSTN), which
* means we never need two sitds for full speed packets.
*/
/* free_list.next might be cache-hot ... but maybe
* the HC caches it too. avoid that issue for now.
*/
/* prefer previously-allocated sitds */
if (!list_empty(&stream->free_list)) {
sitd = list_entry (stream->free_list.prev,
struct ehci_sitd, sitd_list);
list_del (&sitd->sitd_list);
sitd_dma = sitd->sitd_dma;
} else
sitd = 0;
if (!sitd) {
spin_unlock_irqrestore (&ehci->lock, flags);
sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
&sitd_dma);
spin_lock_irqsave (&ehci->lock, flags);
}
if (!sitd) {
iso_sched_free (stream, iso_sched);
spin_unlock_irqrestore (&ehci->lock, flags);
return -ENOMEM;
}
memset (sitd, 0, sizeof *sitd);
sitd->sitd_dma = sitd_dma;
list_add (&sitd->sitd_list, &iso_sched->td_list);
}
/* temporarily store schedule info in hcpriv */
urb->hcpriv = iso_sched;
urb->error_count = 0;
spin_unlock_irqrestore (&ehci->lock, flags);
return 0;
}
/*-------------------------------------------------------------------------*/
static inline void
sitd_patch (
struct ehci_iso_stream *stream,
struct ehci_sitd *sitd,
struct ehci_iso_sched *iso_sched,
unsigned index
)
{
struct ehci_iso_packet *uf = &iso_sched->packet [index];
u64 bufp = uf->bufp;
sitd->hw_next = EHCI_LIST_END;
sitd->hw_fullspeed_ep = stream->address;
sitd->hw_uframe = stream->splits;
sitd->hw_results = uf->transaction;
sitd->hw_backpointer = EHCI_LIST_END;
bufp = uf->bufp;
sitd->hw_buf [0] = cpu_to_le32 (bufp);
sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
if (uf->cross) {
bufp += 4096;
sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
}
sitd->index = index;
}
static inline void
sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
{
/* note: sitd ordering could matter (CSPLIT then SSPLIT) */
sitd->sitd_next = ehci->pshadow [frame];
sitd->hw_next = ehci->periodic [frame];
ehci->pshadow [frame].sitd = sitd;
sitd->frame = frame;
wmb ();
ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
}
/* fit urb's sitds into the selected schedule slot; activate as needed */
static int
sitd_link_urb (
struct ehci_hcd *ehci,
struct urb *urb,
unsigned mod,
struct ehci_iso_stream *stream
)
{
int packet;
unsigned next_uframe;
struct ehci_iso_sched *sched = urb->hcpriv;
struct ehci_sitd *sitd;
next_uframe = stream->next_uframe;
if (list_empty(&stream->td_list)) {
/* usbfs ignores TT bandwidth */
hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+= stream->bandwidth;
ehci_vdbg (ehci,
"sched dev%s ep%d%s-iso [%d] %dms/%04x\n",
urb->dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
(next_uframe >> 3) % ehci->periodic_size,
stream->interval, le32_to_cpu (stream->splits));
stream->start = jiffies;
}
hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++;
/* fill sITDs frame by frame */
for (packet = 0, sitd = 0;
packet < urb->number_of_packets;
packet++) {
/* ASSERT: we have all necessary sitds */
BUG_ON (list_empty (&sched->td_list));
/* ASSERT: no itds for this endpoint in this frame */
sitd = list_entry (sched->td_list.next,
struct ehci_sitd, sitd_list);
list_move_tail (&sitd->sitd_list, &stream->td_list);
sitd->stream = iso_stream_get (stream);
sitd->urb = usb_get_urb (urb);
sitd_patch (stream, sitd, sched, packet);
sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
sitd);
next_uframe += stream->interval << 3;
stream->depth += stream->interval << 3;
}
stream->next_uframe = next_uframe % mod;
/* don't need that schedule data any more */
iso_sched_free (stream, sched);
urb->hcpriv = 0;
timer_action (ehci, TIMER_IO_WATCHDOG);
if (!ehci->periodic_sched++)
return enable_periodic (ehci);
return 0;
}
/*-------------------------------------------------------------------------*/
#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
| SITD_STS_XACT | SITD_STS_MMF | SITD_STS_STS)
static unsigned
sitd_complete (
struct ehci_hcd *ehci,
struct ehci_sitd *sitd,
struct pt_regs *regs
) {
struct urb *urb = sitd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
int urb_index = -1;
struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
t = le32_to_cpup (&sitd->hw_results);
/* report transfer status */
if (t & SITD_ERRS) {
urb->error_count++;
if (t & SITD_STS_DBE)
desc->status = usb_pipein (urb->pipe)
? -ENOSR /* hc couldn't read */
: -ECOMM; /* hc couldn't write */
else if (t & SITD_STS_BABBLE)
desc->status = -EOVERFLOW;
else /* XACT, MMF, etc */
desc->status = -EPROTO;
} else {
desc->status = 0;
desc->actual_length = desc->length - SITD_LENGTH (t);
}
usb_put_urb (urb);
sitd->urb = 0;
sitd->stream = 0;
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;
/* 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 */
dev = usb_get_dev (urb->dev);
ehci_urb_done (ehci, urb, regs);
urb = 0;
/* defer stopping schedule; completion can submit */
ehci->periodic_sched--;
if (!ehci->periodic_sched)
(void) disable_periodic (ehci);
hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--;
if (list_empty (&stream->td_list)) {
hcd_to_bus (&ehci->hcd)->bandwidth_allocated
-= stream->bandwidth;
ehci_vdbg (ehci,
"deschedule devp %s ep%d%s-iso\n",
dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
usb_put_dev (dev);
return 1;
}
static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
{
int status = -EINVAL;
unsigned long flags;
struct ehci_iso_stream *stream;
// FIXME remove when csplits behave
if (usb_pipein(urb->pipe)) {
ehci_dbg (ehci, "no iso-IN split transactions yet\n");
return -ENOMEM;
}
/* Get iso_stream head */
stream = iso_stream_find (ehci, urb);
if (stream == 0) {
ehci_dbg (ehci, "can't get iso stream\n");
return -ENOMEM;
}
if (urb->interval != stream->interval) {
ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
stream->interval, urb->interval);
goto done;
}
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"submit %p dev%s ep%d%s-iso len %d\n",
urb, urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
urb->transfer_buffer_length);
#endif
/* allocate SITDs */
status = sitd_urb_transaction (stream, ehci, urb, mem_flags);
if (status < 0) {
ehci_dbg (ehci, "can't init sitds\n");
goto done;
}
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
status = iso_stream_schedule (ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
done:
if (status < 0)
iso_stream_put (ehci, stream);
return status;
}
#else
static inline int
sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int 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,
struct pt_regs *regs
) {
ehci_err (ehci, "sitd_complete %p?\n", sitd);
return 0;
}
#endif /* USB_EHCI_SPLIT_ISO */
/*-------------------------------------------------------------------------*/
......@@ -1513,7 +1884,6 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
modified = itd_complete (ehci, q.itd, regs);
q = *q_p;
break;
#ifdef have_split_iso
case Q_TYPE_SITD:
if (q.sitd->hw_results & SITD_ACTIVE) {
q_p = &q.sitd->sitd_next;
......@@ -1529,7 +1899,6 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
modified = sitd_complete (ehci, q.sitd, regs);
q = *q_p;
break;
#endif /* have_split_iso */
default:
dbg ("corrupt type %d frame %d shadow %p",
type, frame, q.ptr);
......
......@@ -492,16 +492,16 @@ struct ehci_itd {
/*
* EHCI Specification 0.95 Section 3.4
* siTD, aka split-transaction isochronous Transfer Descriptor
* ... describe low/full speed iso xfers through TT in hubs
* ... describe full speed iso xfers through TT in hubs
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
*/
struct ehci_sitd {
/* first part defined by EHCI spec */
u32 hw_next;
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
u32 hw_fullspeed_ep; /* see EHCI table 3-9 */
u32 hw_uframe; /* see EHCI table 3-10 */
u32 hw_results; /* see EHCI table 3-11 */
u32 hw_fullspeed_ep; /* EHCI table 3-9 */
u32 hw_uframe; /* EHCI table 3-10 */
u32 hw_results; /* EHCI table 3-11 */
#define SITD_IOC (1 << 31) /* interrupt on completion */
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
......@@ -515,8 +515,8 @@ struct ehci_sitd {
#define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE)
u32 hw_buf [2]; /* see EHCI table 3-12 */
u32 hw_backpointer; /* see EHCI table 3-13 */
u32 hw_buf [2]; /* EHCI table 3-12 */
u32 hw_backpointer; /* EHCI table 3-13 */
u32 hw_buf_hi [2]; /* Appendix B */
/* the rest is HCD-private */
......@@ -552,8 +552,6 @@ struct ehci_fstn {
/*-------------------------------------------------------------------------*/
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
......
......@@ -781,7 +781,8 @@ static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
/*
* Map status to standard result codes
*
* <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
* <status> is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)]
* Note: status does not include the TD_CTRL_NAK bit.
* <dir_out> is True for output TDs and False for input TDs.
*/
static int uhci_map_status(int status, int dir_out)
......@@ -792,22 +793,18 @@ static int uhci_map_status(int status, int dir_out)
return -EPROTO;
if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
if (dir_out)
return -ETIMEDOUT;
return -EPROTO;
else
return -EILSEQ;
}
if (status & TD_CTRL_NAK) /* NAK */
return -ETIMEDOUT;
if (status & TD_CTRL_BABBLE) /* Babble */
return -EOVERFLOW;
if (status & TD_CTRL_DBUFERR) /* Buffer error */
return -ENOSR;
if (status & TD_CTRL_STALLED) /* Stalled */
return -EPIPE;
if (status & TD_CTRL_ACTIVE) /* Active */
return 0;
return -EINVAL;
WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
return 0;
}
/*
......@@ -832,7 +829,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
status |= TD_CTRL_LS;
/*
* Build the TD for the control request
* Build the TD for the control request setup packet
*/
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
......@@ -990,13 +987,13 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
if (urbp->short_control_packet) {
tmp = head->prev;
goto status_phase;
goto status_stage;
}
tmp = head->next;
td = list_entry(tmp, struct uhci_td, list);
/* The first TD is the SETUP phase, check the status, but skip */
/* The first TD is the SETUP stage, check the status, but skip */
/* the count */
status = uhci_status_bits(td_status(td));
if (status & TD_CTRL_ACTIVE)
......@@ -1037,10 +1034,10 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
}
}
status_phase:
status_stage:
td = list_entry(tmp, struct uhci_td, list);
/* Control status phase */
/* Control status stage */
status = td_status(td);
#ifdef I_HAVE_BUGGY_APC_BACKUPS
......@@ -1053,10 +1050,11 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
return 0;
#endif
status = uhci_status_bits(status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
if (uhci_status_bits(status))
if (status)
goto td_error;
return 0;
......@@ -1272,12 +1270,6 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
}
/*
* Bulk and interrupt use common result
*/
#define uhci_result_bulk uhci_result_common
#define uhci_result_interrupt uhci_result_common
/*
* Isochronous transfers
*/
......@@ -1403,7 +1395,8 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
urb->iso_frame_desc[i].actual_length = actlength;
urb->actual_length += actlength;
status = uhci_map_status(uhci_status_bits(td_status(td)), usb_pipeout(urb->pipe));
status = uhci_map_status(uhci_status_bits(td_status(td)),
usb_pipeout(urb->pipe));
urb->iso_frame_desc[i].status = status;
if (status) {
urb->error_count++;
......@@ -1508,12 +1501,9 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
struct urb_priv *urbp = urb->hcpriv;
list_del_init(&urbp->urb_list);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
uhci_destroy_urb_priv (uhci, urb);
return ret;
}
ret = 0;
uhci_destroy_urb_priv(uhci, urb);
} else
ret = 0;
out:
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
......@@ -1541,11 +1531,9 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
case PIPE_CONTROL:
ret = uhci_result_control(uhci, urb);
break;
case PIPE_INTERRUPT:
ret = uhci_result_interrupt(uhci, urb);
break;
case PIPE_BULK:
ret = uhci_result_bulk(uhci, urb);
case PIPE_INTERRUPT:
ret = uhci_result_common(uhci, urb);
break;
case PIPE_ISOCHRONOUS:
ret = uhci_result_isochronous(uhci, urb);
......@@ -1649,10 +1637,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
struct urb_priv *urbp = urb->hcpriv;
struct urb_priv *urbp;
spin_lock_irqsave(&uhci->urb_list_lock, flags);
urbp = urb->hcpriv;
if (!urbp) /* URB was never linked! */
goto done;
list_del_init(&urbp->urb_list);
uhci_unlink_generic(uhci, urb);
......@@ -1665,6 +1655,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
spin_unlock(&uhci->urb_remove_list_lock);
done:
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return 0;
}
......@@ -1861,17 +1852,12 @@ static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
{
struct list_head *tmp, *head;
spin_lock(&uhci->urb_remove_list_lock);
head = &uhci->urb_remove_list;
tmp = head->next;
while (tmp != head) {
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
spin_lock(&uhci->complete_list_lock);
tmp = tmp->next;
uhci_moveto_complete(uhci, urbp);
}
/* Splice the urb_remove_list onto the end of the complete_list */
list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
spin_unlock(&uhci->complete_list_lock);
spin_unlock(&uhci->urb_remove_list_lock);
}
......@@ -2471,9 +2457,16 @@ static int uhci_resume(struct usb_hcd *hcd)
pci_set_master(to_pci_dev(uhci_dev(uhci)));
if (uhci->state == UHCI_SUSPENDED)
if (uhci->state == UHCI_SUSPENDED) {
/*
* Some systems clear the Interrupt Enable register during
* PM suspend/resume, so reinitialize it.
*/
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
USBINTR_SP, uhci->io_addr + USBINTR);
uhci->resume_detect = 1;
else {
} else {
reset_hc(uhci);
start_hc(uhci);
}
......
......@@ -141,7 +141,7 @@ struct uhci_qh {
TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xFE0000)
#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000)
#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
/*
......
......@@ -179,6 +179,18 @@ config USB_POWERMATE
To compile this driver as a module, choose M here: the
module will be called powermate.
config USB_MTOUCH
tristate "MicroTouch USB Touchscreen Driver"
depends on USB && INPUT
---help---
Say Y here if you want to use a MicroTouch (Now 3M) USB
Touchscreen controller.
See <file:Documentation/usb/mtouch.txt> for additional information.
To compile this driver as a module, choose M here: the
module will be called mtouchusb.
config USB_XPAD
tristate "X-Box gamepad support"
depends on USB && INPUT
......@@ -192,3 +204,17 @@ config USB_XPAD
To compile this driver as a module, choose M here: the
module will be called xpad.
config USB_ATI_REMOTE
tristate "ATI USB RF remote control"
depends on USB && INPUT
---help---
Say Y here if you want to use one of ATI's USB remote controls.
These are RF remotes with USB receivers. They come with many of ATI's
All-In-Wonder video cards. This driver provides mouse pointer, left
and right mouse buttons, and maps all the other remote buttons to
keypress events.
To compile this driver as a module, choose M here: the module will be
called ati_remote.
......@@ -27,10 +27,12 @@ ifeq ($(CONFIG_HID_FF),y)
endif
obj-$(CONFIG_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_USB_HID) += hid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_KBTAB) += kbtab.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_XPAD) += xpad.o
/*
* USB ATI Remote support
*
* Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
* Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
*
* This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
* porting to the 2.6 kernel interfaces, along with other modification
* to better match the style of the existing usb/input drivers. However, the
* protocol and hardware handling is essentially unchanged from 2.1.1.
*
* The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
* Vojtech Pavlik.
*
* Changes:
*
* Feb 2004: Torrey Hoffman <thoffman@arnor.net>
* Version 2.2.0
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Hardware & software notes
*
* These remote controls are distributed by ATI as part of their
* "All-In-Wonder" video card packages. The receiver self-identifies as a
* "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
*
* It is possible to use multiple receivers and remotes on multiple computers
* simultaneously by configuring them to use specific channels.
*
* The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
* Actually, it may even support more, at least in some revisions of the
* hardware.
*
* Each remote can be configured to transmit on one channel as follows:
* - Press and hold the "hand icon" button.
* - When the red LED starts to blink, let go of the "hand icon" button.
* - When it stops blinking, input the channel code as two digits, from 01
* to 16, and press the hand icon again.
*
* The timing can be a little tricky. Try loading the module with debug=1
* to have the kernel print out messages about the remote control number
* and mask. Note: debugging prints remote numbers as zero-based hexadecimal.
*
* The driver has a "channel_mask" parameter. This bitmask specifies which
* channels will be ignored by the module. To mask out channels, just add
* all the 2^channel_number values together.
*
* For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
* ignore signals coming from remote controls transmitting on channel 4, but
* accept all other channels.
*
* Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
* ignored.
*
* The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
* parameter are unused.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/usb.h>
/*
* Module and Version Information, Module Parameters
*/
#define ATI_REMOTE_VENDOR_ID 0x0bc7
#define ATI_REMOTE_PRODUCT_ID 0x004
#define DRIVER_VERSION "2.2.0"
#define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>"
#define DRIVER_DESC "ATI/X10 RF USB Remote Control"
#define NAME_BUFSIZE 80 /* size of product name, path buffers */
#define DATA_BUFSIZE 63 /* size of URB data buffers */
#define ATI_INPUTNUM 1 /* Which input device to register as */
unsigned long channel_mask = 0;
module_param(channel_mask, ulong, 444);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug = 0;
module_param(debug, int, 444);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
static struct usb_device_id ati_remote_table[] = {
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ati_remote_table);
/* Get hi and low bytes of a 16-bits int */
#define HI(a) ((unsigned char)((a) >> 8))
#define LO(a) ((unsigned char)((a) & 0xff))
#define SEND_FLAG_IN_PROGRESS 1
#define SEND_FLAG_COMPLETE 2
/* Device initialization strings */
static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
/* Acceleration curve for directional control pad */
static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
/* Duplicate event filtering time.
* Sequential, identical KIND_FILTERED inputs with less than
* FILTER_TIME jiffies between them are dropped.
* (HZ >> 4) == 1/16th of a second and works well for me.
*/
#define FILTER_TIME (HZ >> 4)
struct ati_remote {
struct input_dev idev;
struct usb_device *udev;
struct usb_interface *interface;
struct urb *irq_urb;
struct urb *out_urb;
struct usb_endpoint_descriptor *endpoint_in;
struct usb_endpoint_descriptor *endpoint_out;
unsigned char *inbuf;
unsigned char *outbuf;
dma_addr_t inbuf_dma;
dma_addr_t outbuf_dma;
int open; /* open counter */
int present; /* device plugged in? */
unsigned char old_data[2]; /* Detect duplicate events */
unsigned long old_jiffies;
unsigned long acc_jiffies; /* handle acceleration */
char name[NAME_BUFSIZE];
char phys[NAME_BUFSIZE];
wait_queue_head_t wait;
int send_flags;
};
/* "Kinds" of messages sent from the hardware to the driver. */
#define KIND_END 0
#define KIND_LITERAL 1 /* Simply pass to input system */
#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */
#define KIND_LU 3 /* Directional keypad diagonals - left up, */
#define KIND_RU 4 /* right up, */
#define KIND_LD 5 /* left down, */
#define KIND_RD 6 /* right down */
#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/
/* Translation table from hardware messages to input events. */
static struct
{
short kind;
unsigned char data1, data2;
int type;
unsigned int code;
int value;
} ati_remote_tbl[] =
{
/* Directional control pad axes */
{KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */
{KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */
{KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */
{KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */
/* Directional control pad diagonals */
{KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */
{KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */
{KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */
{KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */
/* "Mouse button" buttons */
{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
/* Artificial "doubleclick" events are generated by the hardware.
* They are mapped to the "side" and "extra" mouse buttons here. */
{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
/* keyboard. */
{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
/* "special" keys */
{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */
{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */
{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */
{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1}, /* TV */
{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1}, /* DVD */
{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */
{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */
{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */
{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */
{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */
{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */
{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */
{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */
{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */
{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1}, /* "OK" */
{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */
{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */
{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */
{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */
{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1}, /* ( >) */
{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */
{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */
{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */
{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */
{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
};
/* Local function prototypes */
static void ati_remote_dump (unsigned char *data, unsigned int actual_length);
static void ati_remote_delete (struct ati_remote *dev);
static int ati_remote_open (struct input_dev *inputdev);
static void ati_remote_close (struct input_dev *inputdev);
static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs);
static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs);
static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs);
static int ati_remote_initialize (struct ati_remote *ati_remote);
static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void ati_remote_disconnect (struct usb_interface *interface);
/* usb specific object to register with the usb subsystem */
static struct usb_driver ati_remote_driver = {
.owner = THIS_MODULE,
.name = "ati_remote",
.probe = ati_remote_probe,
.disconnect = ati_remote_disconnect,
.id_table = ati_remote_table,
};
/*
* ati_remote_dump_input
*/
static void ati_remote_dump(unsigned char *data, unsigned int len)
{
if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
warn("Weird byte 0x%02x\n", data[0]);
else if (len == 4)
warn("Weird key %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3]);
else
warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
len, data[0], data[1], data[2], data[3], data[4], data[5]);
}
/*
* ati_remote_open
*/
static int ati_remote_open(struct input_dev *inputdev)
{
struct ati_remote *ati_remote = inputdev->private;
if (ati_remote->open++)
return 0;
/* On first open, submit the read urb which was set up previously. */
ati_remote->irq_urb->dev = ati_remote->udev;
if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
dev_err(&ati_remote->interface->dev,
"%s: usb_submit_urb failed!\n", __FUNCTION__);
ati_remote->open--;
return -EIO;
}
return 0;
}
/*
* ati_remote_close
*/
static void ati_remote_close(struct input_dev *inputdev)
{
struct ati_remote *ati_remote = inputdev->private;
if (ati_remote == NULL) {
err("ati_remote: %s: object is NULL!\n", __FUNCTION__);
return;
}
if (ati_remote->open <= 0)
dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__);
else
--ati_remote->open;
/* If still present, disconnect will call delete. */
if (!ati_remote->present && !ati_remote->open)
ati_remote_delete(ati_remote);
}
/*
* ati_remote_irq_out
*/
static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
{
struct ati_remote *ati_remote = urb->context;
if (urb->status) {
dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
__FUNCTION__, urb->status);
return;
}
ati_remote->send_flags |= SEND_FLAG_COMPLETE;
wmb();
if (waitqueue_active(&ati_remote->wait))
wake_up(&ati_remote->wait);
}
/*
* ati_remote_sendpacket
*
* Used to send device initialization strings
*/
static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
{
DECLARE_WAITQUEUE(wait, current);
int timeout = HZ; /* 1 second */
int retval = 0;
/* Set up out_urb */
memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
ati_remote->out_urb->dev = ati_remote->udev;
ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&ati_remote->wait, &wait);
retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL);
if (retval) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&ati_remote->wait, &wait);
dev_dbg(&ati_remote->interface->dev,
"sendpacket: usb_submit_urb failed: %d\n", retval);
return retval;
}
while (timeout && (ati_remote->out_urb->status == -EINPROGRESS)
&& !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) {
timeout = schedule_timeout(timeout);
rmb();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&ati_remote->wait, &wait);
usb_unlink_urb(ati_remote->out_urb);
return retval;
}
/*
* ati_remote_event_lookup
*/
static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
{
int i;
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
/*
* Decide if the table entry matches the remote input.
*/
if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
((((ati_remote_tbl[i].data1 >> 4) -
(d1 >> 4) + rem) & 0x0f) == 0x0f) &&
(ati_remote_tbl[i].data2 == d2))
return i;
}
return -1;
}
/*
* ati_remote_report_input
*/
static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
{
struct ati_remote *ati_remote = urb->context;
unsigned char *data= ati_remote->inbuf;
struct input_dev *dev = &ati_remote->idev;
int index, acc;
int remote_num;
/* Deal with strange looking inputs */
if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
((data[3] & 0x0f) != 0x00) ) {
ati_remote_dump(data, urb->actual_length);
return;
}
/* Mask unwanted remote channels. */
/* note: remote_num is 0-based, channel 1 on remote == 0 here */
remote_num = (data[3] >> 4) & 0x0f;
if (channel_mask & (1 << (remote_num + 1))) {
dbginfo(&ati_remote->interface->dev,
"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
remote_num, data[1], data[2], channel_mask);
return;
}
/* Look up event code index in translation table */
index = ati_remote_event_lookup(remote_num, data[1], data[2]);
if (index < 0) {
dev_warn(&ati_remote->interface->dev,
"Unknown input from channel 0x%02x: data %02x,%02x\n",
remote_num, data[1], data[2]);
return;
}
dbginfo(&ati_remote->interface->dev,
"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
if (ati_remote_tbl[index].kind == KIND_LITERAL) {
input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
ati_remote_tbl[index].value);
input_sync(dev);
ati_remote->old_jiffies = jiffies;
return;
}
if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */
if ((ati_remote->old_data[0] == data[1]) &&
(ati_remote->old_data[1] == data[2]) &&
((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
ati_remote->old_jiffies = jiffies;
return;
}
input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 1);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 0);
input_sync(dev);
ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies;
return;
}
/*
* Other event kinds are from the directional control pad, and have an
* acceleration factor applied to them. Without this acceleration, the
* control pad is mostly unusable.
*
* If elapsed time since last event is > 1/4 second, user "stopped",
* so reset acceleration. Otherwise, user is probably holding the control
* pad down, so we increase acceleration, ramping up over two seconds to
* a maximum speed. The acceleration curve is #defined above.
*/
if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) {
acc = 1;
ati_remote->acc_jiffies = jiffies;
}
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = accel[0];
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = accel[1];
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = accel[2];
else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = accel[3];
else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = accel[4];
else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = accel[5];
else acc = accel[6];
input_regs(dev, regs);
switch (ati_remote_tbl[index].kind) {
case KIND_ACCEL:
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
ati_remote_tbl[index].value * acc);
break;
case KIND_LU:
input_report_rel(dev, REL_X, -acc);
input_report_rel(dev, REL_Y, -acc);
break;
case KIND_RU:
input_report_rel(dev, REL_X, acc);
input_report_rel(dev, REL_Y, -acc);
break;
case KIND_LD:
input_report_rel(dev, REL_X, -acc);
input_report_rel(dev, REL_Y, acc);
break;
case KIND_RD:
input_report_rel(dev, REL_X, acc);
input_report_rel(dev, REL_Y, acc);
break;
default:
dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
ati_remote_tbl[index].kind);
}
input_sync(dev);
ati_remote->old_jiffies = jiffies;
ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2];
}
/*
* ati_remote_irq_in
*/
static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
{
struct ati_remote *ati_remote = urb->context;
int retval;
switch (urb->status) {
case 0: /* success */
ati_remote_input_report(urb, regs);
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
__FUNCTION__);
return;
default: /* error */
dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
__FUNCTION__, urb->status);
}
retval = usb_submit_urb(urb, SLAB_ATOMIC);
if (retval)
dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
__FUNCTION__, retval);
}
/*
* ati_remote_delete
*/
static void ati_remote_delete(struct ati_remote *ati_remote)
{
if (!ati_remote) return;
if (ati_remote->irq_urb)
usb_unlink_urb(ati_remote->irq_urb);
if (ati_remote->out_urb)
usb_unlink_urb(ati_remote->out_urb);
if (ati_remote->irq_urb)
usb_free_urb(ati_remote->irq_urb);
if (ati_remote->out_urb)
usb_free_urb(ati_remote->out_urb);
if (ati_remote->inbuf)
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->inbuf, ati_remote->inbuf_dma);
if (ati_remote->outbuf)
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->inbuf, ati_remote->outbuf_dma);
kfree(ati_remote);
}
static void ati_remote_input_init(struct ati_remote *ati_remote)
{
struct input_dev *idev = &(ati_remote->idev);
int i;
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
if (ati_remote_tbl[i].type == EV_KEY)
set_bit(ati_remote_tbl[i].code, idev->keybit);
idev->private = ati_remote;
idev->open = ati_remote_open;
idev->close = ati_remote_close;
idev->name = ati_remote->name;
idev->phys = ati_remote->phys;
idev->id.bustype = BUS_USB;
idev->id.vendor = ati_remote->udev->descriptor.idVendor;
idev->id.product = ati_remote->udev->descriptor.idProduct;
idev->id.version = ati_remote->udev->descriptor.bcdDevice;
}
static int ati_remote_initialize(struct ati_remote *ati_remote)
{
struct usb_device *udev = ati_remote->udev;
int pipe, maxp;
init_waitqueue_head(&ati_remote->wait);
/* Set up irq_urb */
pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
maxp, ati_remote_irq_in, ati_remote,
ati_remote->endpoint_in->bInterval);
ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* Set up out_urb */
pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
maxp, ati_remote_irq_out, ati_remote,
ati_remote->endpoint_out->bInterval);
ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* send initialization strings */
if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
(ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
dev_err(&ati_remote->interface->dev,
"Initializing ati_remote hardware failed.\n");
return 1;
}
return 0;
}
/*
* ati_remote_probe
*/
static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct ati_remote *ati_remote = NULL;
struct usb_host_interface *iface_host;
int retval = -ENOMEM;
char path[64];
char *buf = NULL;
/* See if the offered device matches what we can accept */
if ((udev->descriptor.idVendor != ATI_REMOTE_VENDOR_ID) ||
(udev->descriptor.idProduct != ATI_REMOTE_PRODUCT_ID)) {
return -ENODEV;
}
/* Allocate and clear an ati_remote struct */
if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL)))
return -ENOMEM;
memset(ati_remote, 0x00, sizeof (struct ati_remote));
iface_host = interface->cur_altsetting;
if (iface_host->desc.bNumEndpoints != 2) {
err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
retval = -ENODEV;
goto error;
}
ati_remote->endpoint_in = &(iface_host->endpoint[0].desc);
ati_remote->endpoint_out = &(iface_host->endpoint[1].desc);
ati_remote->udev = udev;
ati_remote->interface = interface;
if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) {
err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
retval = -ENODEV;
goto error;
}
if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) {
err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
retval = -ENODEV;
goto error;
}
if (ati_remote->endpoint_in->wMaxPacketSize == 0) {
err("%s: endpoint_in message size==0? \n", __FUNCTION__);
retval = -ENODEV;
goto error;
}
if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL)))
goto error;
/* Allocate URB buffers, URBs */
ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
&ati_remote->inbuf_dma);
if (!ati_remote->inbuf)
goto error;
ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
&ati_remote->outbuf_dma);
if (!ati_remote->outbuf)
goto error;
ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ati_remote->irq_urb)
goto error;
ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ati_remote->out_urb)
goto error;
usb_make_path(udev, path, NAME_BUFSIZE);
sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM);
if (udev->descriptor.iManufacturer &&
(usb_string(udev, udev->descriptor.iManufacturer, buf,
NAME_BUFSIZE) > 0))
strcat(ati_remote->name, buf);
if (udev->descriptor.iProduct &&
(usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0))
sprintf(ati_remote->name, "%s %s", ati_remote->name, buf);
if (!strlen(ati_remote->name))
sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
ati_remote->udev->descriptor.idVendor,
ati_remote->udev->descriptor.idProduct);
/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
retval = ati_remote_initialize(ati_remote);
if (retval)
goto error;
/* Set up and register input device */
ati_remote_input_init(ati_remote);
input_register_device(&ati_remote->idev);
dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
ati_remote->name, path);
usb_set_intfdata(interface, ati_remote);
ati_remote->present = 1;
kfree(buf);
return 0;
error:
if (buf)
kfree(buf);
ati_remote_delete(ati_remote);
return retval;
}
/*
* ati_remote_disconnect
*/
static void ati_remote_disconnect(struct usb_interface *interface)
{
struct ati_remote *ati_remote;
ati_remote = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
if (!ati_remote) {
warn("%s - null device?\n", __FUNCTION__);
return;
}
input_unregister_device(&ati_remote->idev);
/* Mark device as unplugged */
ati_remote->present = 0;
/* If device is still open, ati_remote_close will call delete. */
if (!ati_remote->open)
ati_remote_delete(ati_remote);
}
/*
* ati_remote_init
*/
static int __init ati_remote_init(void)
{
int result;
result = usb_register(&ati_remote_driver);
if (result)
err("usb_register error #%d\n", result);
else
info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
return result;
}
/*
* ati_remote_exit
*/
static void __exit ati_remote_exit(void)
{
usb_deregister(&ati_remote_driver);
}
/*
* module specification
*/
module_init(ati_remote_init);
module_exit(ati_remote_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
......@@ -1445,7 +1445,7 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->altsetting + intf->act_altsetting;
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
struct hid_device *hid;
......
......@@ -74,12 +74,15 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
input_report_abs(dev, ABS_X, kbtab->x);
input_report_abs(dev, ABS_Y, kbtab->y);
/*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
if( -1 == kb_pressure_click){
input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
} else {
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
};
input_sync(dev);
......
/******************************************************************************
* mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based upon original work by Radoslaw Garbacz (usb-support@ite.pl)
* (http://freshmeat.net/projects/3mtouchscreendriver)
*
* History
*
* 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com
* Updated to 2.4.18, then 2.4.19
* Old version still relied on stealing a minor
*
* 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com
* Complete rewrite using Linux Input in 2.6.3
* Unfortunately no calibration support at this time
*
*****************************************************************************/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#define MTOUCHUSB_MIN_XC 0xc8
#define MTOUCHUSB_MAX_XC 0xff78
#define MTOUCHUSB_XC_FUZZ 0x0
#define MTOUCHUSB_XC_FLAT 0x0
#define MTOUCHUSB_MIN_YC 0x0
#define MTOUCHUSB_MAX_YC 0xff78
#define MTOUCHUSB_YC_FUZZ 0x0
#define MTOUCHUSB_YC_FLAT 0x0
#define MTOUCHUSB_ASYC_REPORT 1
#define MTOUCHUSB_REPORT_SIZE_DATA 11
#define MTOUCHUSB_REQ_CTRLLR_ID 10
#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3])
#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5])
#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0)
#define DRIVER_VERSION "v0.1"
#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver"
struct mtouch_usb {
unsigned char *data;
dma_addr_t data_dma;
struct urb *irq;
struct usb_device *udev;
struct input_dev input;
int open;
char name[128];
char phys[64];
};
static __s32 vendor=-1, product=-1;
static struct usb_device_id mtouchusb_devices [] = {
{ USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */
{ } /* Terminating entry */
};
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
{
struct mtouch_usb *mtouch = urb->context;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ETIMEDOUT:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__FUNCTION__, urb->status);
goto exit;
}
input_regs(&mtouch->input, regs);
input_report_key(&mtouch->input, BTN_TOUCH,
MTOUCHUSB_GET_TOUCHED(mtouch->data));
input_report_abs(&mtouch->input, ABS_X,
MTOUCHUSB_GET_XC(mtouch->data));
input_report_abs(&mtouch->input, ABS_Y,
MTOUCHUSB_GET_YC(mtouch->data));
input_sync(&mtouch->input);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result: %d",
__FUNCTION__, retval);
}
static int mtouchusb_open (struct input_dev *input)
{
struct mtouch_usb *mtouch = input->private;
if (mtouch->open++)
return 0;
mtouch->irq->dev = mtouch->udev;
if (usb_submit_urb (mtouch->irq, GFP_ATOMIC))
return -EIO;
return 0;
}
static void mtouchusb_close (struct input_dev *input)
{
struct mtouch_usb *mtouch = input->private;
if (!--mtouch->open)
usb_unlink_urb (mtouch->irq);
}
static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
dbg("%s - called", __FUNCTION__);
mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA,
SLAB_ATOMIC, &mtouch->data_dma);
if (!mtouch->data)
return -1;
return 0;
}
static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
dbg("%s - called", __FUNCTION__);
if (mtouch->data)
usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA,
mtouch->data, mtouch->data_dma);
}
static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct mtouch_usb *mtouch;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev (intf);
char path[64];
char *buf;
int nRet;
int ix;
char valid_device = 0;
dbg("%s - called", __FUNCTION__);
if (vendor != -1 && product != -1) {
info("%s - User specified USB Touch -- Vend:Prod - %x:%x",
__FUNCTION__, vendor, product);
}
for (ix = 0; ix < sizeof (mtouchusb_devices) /
sizeof (struct usb_device_id); ix++) {
if ((udev->descriptor.idVendor ==
mtouchusb_devices [ix].idVendor) &&
(udev->descriptor.idProduct ==
mtouchusb_devices [ix].idProduct)) {
valid_device = 1;
break;
}
}
if (udev->descriptor.idVendor == vendor &&
udev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
}
if (!valid_device) {
err("%s - No valid device!", __FUNCTION__);
return -EIO;
}
if (udev->descriptor.bNumConfigurations != 1) {
err("%s - Only one device configuration is supported.",
__FUNCTION__);
return -EIO;
}
dbg("%s - setting interface", __FUNCTION__);
interface = intf->cur_altsetting;
dbg("%s - setting endpoint", __FUNCTION__);
endpoint = &interface->endpoint[0].desc;
if (interface->desc.bNumEndpoints != 1) {
err("%s - Only one endpoint is supported.", __FUNCTION__);
return -EIO;
}
if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
}
memset(mtouch, 0, sizeof(struct mtouch_usb));
mtouch->udev = udev;
dbg("%s - allocating buffers", __FUNCTION__);
if (mtouchusb_alloc_buffers(udev, mtouch)) {
mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch);
return -ENOMEM;
}
mtouch->input.private = mtouch;
mtouch->input.open = mtouchusb_open;
mtouch->input.close = mtouchusb_close;
usb_make_path(udev, path, 64);
sprintf(mtouch->phys, "%s/input0", path);
mtouch->input.name = mtouch->name;
mtouch->input.phys = mtouch->phys;
mtouch->input.id.bustype = BUS_USB;
mtouch->input.id.vendor = udev->descriptor.idVendor;
mtouch->input.id.product = udev->descriptor.idProduct;
mtouch->input.id.version = udev->descriptor.bcdDevice;
mtouch->input.dev = &intf->dev;
mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
/* Used to Scale Compensated Data and Flip Y */
mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC;
mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
if (!(buf = kmalloc(63, GFP_KERNEL))) {
kfree(mtouch);
return -ENOMEM;
}
if (udev->descriptor.iManufacturer &&
usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
strcat(mtouch->name, buf);
if (udev->descriptor.iProduct &&
usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
sprintf(mtouch->name, "%s %s", mtouch->name, buf);
if (!strlen(mtouch->name))
sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
mtouch->input.id.vendor, mtouch->input.id.product);
kfree(buf);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
USB_REQ_GET_CONFIGURATION,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
0,
0x81,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d",
__FUNCTION__, nRet);
dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!mtouch->irq) {
dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch);
return -ENOMEM;
}
dbg("%s - usb_fill_int_urb", __FUNCTION__);
usb_fill_int_urb(mtouch->irq,
mtouch->udev,
usb_rcvintpipe(mtouch->udev, 0x81),
mtouch->data,
MTOUCHUSB_REPORT_SIZE_DATA,
mtouchusb_irq,
mtouch,
endpoint->bInterval);
dbg("%s - input_register_device", __FUNCTION__);
input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
MTOUCHUSB_ASYC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
MTOUCHUSB_ASYC_REPORT,
MTOUCHUSB_ASYC_REPORT,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d",
__FUNCTION__, nRet);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
usb_set_intfdata(intf, mtouch);
return 0;
}
static void mtouchusb_disconnect(struct usb_interface *intf)
{
struct mtouch_usb *mtouch = usb_get_intfdata (intf);
dbg("%s - called", __FUNCTION__);
usb_set_intfdata(intf, NULL);
if (mtouch) {
dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
usb_unlink_urb(mtouch->irq);
input_unregister_device(&mtouch->input);
usb_free_urb(mtouch->irq);
mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
kfree(mtouch);
}
}
MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
static struct usb_driver mtouchusb_driver = {
.owner = THIS_MODULE,
.name = "mtouchusb",
.probe = mtouchusb_probe,
.disconnect = mtouchusb_disconnect,
.id_table = mtouchusb_devices,
};
static int __init mtouchusb_init(void) {
dbg("%s - called", __FUNCTION__);
return usb_register(&mtouchusb_driver);
}
static void __exit mtouchusb_cleanup(void) {
dbg("%s - called", __FUNCTION__);
usb_deregister(&mtouchusb_driver);
}
module_init(mtouchusb_init);
module_exit(mtouchusb_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_PARM(vendor, "i");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
MODULE_PARM(product, "i");
MODULE_PARM_DESC(product, "User specified USB idProduct");
......@@ -240,7 +240,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
char path[64];
char *buf;
interface = &iface->altsetting[iface->act_altsetting];
interface = iface->cur_altsetting;
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
......
......@@ -131,7 +131,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
char path[64];
char *buf;
interface = &intf->altsetting[intf->act_altsetting];
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
......
......@@ -490,7 +490,7 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate)
struct usb_interface *iface = dev->intf;
struct usb_device *udev;
if (alternate < 0 || alternate >= iface->num_altsetting)
if (alternate < 0 || alternate >= 256)
return -EINVAL;
udev = interface_to_usbdev (iface);
......@@ -556,23 +556,19 @@ static int ch9_postconfig (struct usbtest_dev *dev)
{
struct usb_interface *iface = dev->intf;
struct usb_device *udev = interface_to_usbdev (iface);
int i, retval;
int i, alt, retval;
/* [9.2.3] if there's more than one altsetting, we need to be able to
* set and get each one. mostly trusts the descriptors from usbcore.
*/
for (i = 0; i < iface->num_altsetting; i++) {
/* 9.2.3 constrains the range here, and Linux ensures
* they're ordered meaningfully in this array
*/
if (iface->altsetting [i].desc.bAlternateSetting != i) {
/* 9.2.3 constrains the range here */
alt = iface->altsetting [i].desc.bAlternateSetting;
if (alt < 0 || alt >= iface->num_altsetting) {
dev_dbg (&iface->dev,
"invalid alt [%d].bAltSetting = %d\n",
i,
iface->altsetting [i].desc
.bAlternateSetting);
return -EDOM;
i, alt);
}
/* [real world] get/set unimplemented if there's only one */
......@@ -580,18 +576,18 @@ static int ch9_postconfig (struct usbtest_dev *dev)
continue;
/* [9.4.10] set_interface */
retval = set_altsetting (dev, i);
retval = set_altsetting (dev, alt);
if (retval) {
dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
i, retval);
alt, retval);
return retval;
}
/* [9.4.4] get_interface always works */
retval = get_altsetting (dev);
if (retval != i) {
if (retval != alt) {
dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
i, retval);
alt, retval);
return (retval < 0) ? retval : -EDOM;
}
......
......@@ -3009,7 +3009,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
return -ENODEV;
}
xdev = interface_to_usbdev (udev);
interface = &udev->altsetting [udev->act_altsetting];
interface = udev->cur_altsetting;
usb_get_dev (xdev);
......@@ -3314,6 +3314,15 @@ static const struct usb_device_id products [] = {
.bInterfaceSubClass = 0x0a,
.bInterfaceProtocol = 0x00,
.driver_info = (unsigned long) &zaurus_pxa_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9050, /* C-860 */
.bInterfaceClass = 0x02,
.bInterfaceSubClass = 0x0a,
.bInterfaceProtocol = 0x00,
.driver_info = (unsigned long) &zaurus_pxa_info,
},
#endif
......
......@@ -286,6 +286,7 @@ static struct usb_device_id id_table_sio [] = {
static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
......@@ -358,6 +359,7 @@ static struct usb_device_id id_table_8U232AM [] = {
static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
......@@ -451,6 +453,7 @@ static struct usb_device_id id_table_HE_TIRA1 [] = {
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
......
......@@ -30,6 +30,8 @@
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
/* www.irtrans.de device */
#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
/* they use the ftdi chipset for the USB interface and the vendor id is the same */
......
......@@ -273,6 +273,7 @@ static int klsi_105_startup (struct usb_serial *serial)
/* allocate the private data structure */
for (i=0; i<serial->num_ports; i++) {
int j;
priv = kmalloc(sizeof(struct klsi_105_private),
GFP_KERNEL);
if (!priv) {
......@@ -293,10 +294,10 @@ static int klsi_105_startup (struct usb_serial *serial)
usb_set_serial_port_data(serial->port[i], priv);
spin_lock_init (&priv->lock);
for (i=0; i<NUM_URBS; i++) {
for (j=0; j<NUM_URBS; j++) {
struct urb* urb = usb_alloc_urb(0, GFP_KERNEL);
priv->write_urb_pool[i] = urb;
priv->write_urb_pool[j] = urb;
if (urb == NULL) {
err("No more urbs???");
continue;
......
......@@ -239,6 +239,8 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
......@@ -275,6 +277,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
{ }, /* optional parameter entry */
......
......@@ -46,6 +46,7 @@
#define SAMSUNG_VENDOR_ID 0x04E8
#define SAMSUNG_SCH_I330_ID 0x8001
#define SAMSUNG_SPH_I500_ID 0x6601
#define GARMIN_VENDOR_ID 0x091E
#define GARMIN_IQUE_3600_ID 0x0004
......
......@@ -64,8 +64,10 @@ static const char* host_info(struct Scsi_Host *host)
return "SCSI emulation for USB Mass Storage devices";
}
static int slave_configure (struct scsi_device *sdev)
static int slave_configure(struct scsi_device *sdev)
{
struct us_data *us = (struct us_data *) sdev->host->hostdata[0];
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size. Otherwise a data packet
* would end up being short, causing a premature end to the data
......@@ -76,6 +78,16 @@ static int slave_configure (struct scsi_device *sdev)
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
/* Devices using Genesys Logic chips cause a lot of trouble for
* high-speed transfers; they die unpredictably when given more
* than 64 KB of data at a time. If we detect such a device,
* reduce the maximum transfer size to 64 KB = 128 sectors. */
#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location
if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS &&
us->pusb_dev->speed == USB_SPEED_HIGH)
blk_queue_max_sectors(sdev->request_queue, 128);
/* this is to satisify the compiler, tho I don't think the
* return code is ever checked anywhere. */
return 0;
......
......@@ -563,9 +563,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/*
* If we're running the CB transport, which is incapable
* of determining status on its own, we need to auto-sense
* of determining status on its own, we will auto-sense
* unless the operation involved a data-in transfer. Devices
* can signal data-in errors by stalling the bulk-in pipe.
* can signal most data-in errors by stalling the bulk-in pipe.
*/
if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
srb->sc_data_direction != SCSI_DATA_READ) {
......@@ -698,7 +698,11 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* out the sense buffer so the higher layers won't realize
* we did an unsolicited auto-sense. */
if (result == USB_STOR_TRANSPORT_GOOD &&
(srb->sense_buffer[2] & 0xf) == 0x0) {
/* Filemark 0, ignore EOM, ILI 0, no sense */
(srb->sense_buffer[2] & 0xaf) == 0 &&
/* No ASC or ASCQ */
srb->sense_buffer[12] == 0 &&
srb->sense_buffer[13] == 0) {
srb->result = SAM_STAT_GOOD;
srb->sense_buffer[0] = 0x0;
}
......@@ -809,15 +813,19 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
}
/* If not UFI, we interpret the data as a result code
* The first byte should always be a 0x0
* The second byte & 0x0F should be 0x0 for good, otherwise error
* The first byte should always be a 0x0.
*
* Some bogus devices don't follow that rule. They stuff the ASC
* into the first byte -- so if it's non-zero, call it a failure.
*/
if (us->iobuf[0]) {
US_DEBUGP("CBI IRQ data showed reserved bType %d\n",
US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n",
us->iobuf[0]);
return USB_STOR_TRANSPORT_ERROR;
goto Failed;
}
/* The second byte & 0x0F should be 0x0 for good, otherwise error */
switch (us->iobuf[1] & 0x0F) {
case 0x00:
return USB_STOR_TRANSPORT_GOOD;
......
......@@ -261,6 +261,14 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
US_SC_SCSI, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_MODE_XLATE ),
/* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500,
"Sony",
"DSC-T1",
US_SC_8070, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_MODE_XLATE ),
/* Reported by wim@geeks.nl */
UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100,
"Sony",
......@@ -368,7 +376,7 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
"Lexar",
"Jumpshot USB CF Reader",
US_SC_SCSI, US_PR_JUMPSHOT, NULL,
US_SC_DEVICE, US_PR_JUMPSHOT, NULL,
US_FL_MODE_XLATE ),
#endif
......@@ -440,12 +448,6 @@ UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7i",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7Hi",
......@@ -619,6 +621,9 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff,
* are using transport protocol CB.
* - They don't like the INQUIRY command. So we must handle this command
* of the SCSI layer ourselves.
* - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
* bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB).
* So don't remove the US_PR_CB override!
*/
UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
"Casio",
......@@ -649,6 +654,17 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MODE_XLATE ),
/* Entry needed for flags. Moreover, all devices with this ID use
* bulk-only transport, but _some_ falsely report Control/Bulk instead.
* One example is "Trumpion Digital Research MYMP3".
* Submitted by Bjoern Brill <brill(at)fs.math.uni-frankfurt.de>
*/
UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100,
"Trumpion",
"t33520 USB Flash Card Controller",
US_SC_DEVICE, US_PR_BULK, NULL,
US_FL_MODE_XLATE),
/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
"Trumpion",
......@@ -688,15 +704,9 @@ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* This entry from <matthias@ma-c.de> in the Debian mailing list */
UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff,
"Pentax",
"Optio 330GS",
US_SC_8070, US_PR_CB, NULL,
US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ),
/* Submitted by Per Winkvist <per.winkvist@uk.com> */
UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
"Pentax",
"Optio S/S4",
US_SC_DEVICE, US_PR_DEVICE, NULL,
......
......@@ -423,7 +423,7 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->altsetting->desc.bInterfaceNumber;
us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
/* Store our private data in the interface and increment the
* device's reference count */
......@@ -452,7 +452,7 @@ static void get_device_info(struct us_data *us, int id_index)
{
struct usb_device *dev = us->pusb_dev;
struct usb_interface_descriptor *idesc =
&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting].desc;
&us->pusb_intf->cur_altsetting->desc;
struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
struct usb_device_id *id = &storage_usb_ids[id_index];
......@@ -686,7 +686,7 @@ static int get_protocol(struct us_data *us)
static int get_pipes(struct us_data *us)
{
struct usb_host_interface *altsetting =
&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting];
us->pusb_intf->cur_altsetting;
int i;
struct usb_endpoint_descriptor *ep;
struct usb_endpoint_descriptor *ep_in = NULL;
......@@ -877,8 +877,9 @@ static int storage_probe(struct usb_interface *intf,
int result;
US_DEBUGP("USB Mass Storage device detected\n");
US_DEBUGP("act_altsetting is %d, id_index is %d\n",
intf->act_altsetting, id_index);
US_DEBUGP("altsetting is %d, id_index is %d\n",
intf->cur_altsetting->desc.bAlternateSetting,
id_index);
/* Allocate the us_data structure and initialize the mutexes */
us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
......@@ -953,8 +954,6 @@ static int storage_probe(struct usb_interface *intf,
scsi_scan_host(us->host);
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
printk(KERN_DEBUG
"USB Mass Storage device found at %d\n", us->pusb_dev->devnum);
return 0;
......
......@@ -176,6 +176,5 @@ extern void fill_inquiry_response(struct us_data *us,
* single queue element srb for write access */
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
#define sg_address(psg) (page_address((psg).page) + (psg).offset)
#endif
......@@ -72,14 +72,11 @@ struct usb_host_interface {
/**
* struct usb_interface - what usb device drivers talk to
* @altsetting: array of interface descriptors, one for each alternate
* @altsetting: array of interface structures, one for each alternate
* setting that may be selected. Each one includes a set of
* endpoint configurations and will be in numberic order,
* 0..num_altsetting.
* endpoint configurations. They will be in no particular order.
* @num_altsetting: number of altsettings defined.
* @act_altsetting: index of current altsetting. this number is always
* less than num_altsetting. after the device is configured, each
* interface uses its default setting of zero.
* @cur_altsetting: the current altsetting.
* @driver: the USB driver that is bound to this interface.
* @minor: the minor number assigned to this interface, if this
* interface is bound to a driver that uses the USB major number.
......@@ -89,6 +86,8 @@ struct usb_host_interface {
* number from the USB core by calling usb_register_dev().
* @dev: driver model's view of this device
* @class_dev: driver model's class view of this device.
* @released: wait for the interface to be released when changing
* configurations.
*
* USB device drivers attach to interfaces on a physical device. Each
* interface encapsulates a single high level function, such as feeding
......@@ -102,26 +101,33 @@ struct usb_host_interface {
* calls such as dev_get_drvdata() on the dev member of this structure.
*
* Each interface may have alternate settings. The initial configuration
* of a device sets the first of these, but the device driver can change
* of a device sets altsetting 0, but the device driver can change
* that setting using usb_set_interface(). Alternate settings are often
* used to control the the use of periodic endpoints, such as by having
* different endpoints use different amounts of reserved USB bandwidth.
* All standards-conformant USB devices that use isochronous endpoints
* will use them in non-default settings.
*
* The USB specification says that alternate setting numbers must run from
* 0 to one less than the total number of alternate settings. But some
* devices manage to mess this up, and the structures aren't necessarily
* stored in numerical order anyhow. Use usb_altnum_to_altsetting() to
* look up an alternate setting in the altsetting array based on its number.
*/
struct usb_interface {
/* array of alternate settings for this interface.
* these will be in numeric order, 0..num_altsettting
*/
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting;
unsigned act_altsetting; /* active alternate setting */
struct usb_host_interface *cur_altsetting; /* the currently
* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */
struct usb_driver *driver; /* driver */
int minor; /* minor number this interface is bound to */
struct device dev; /* interface specific device info */
struct class_device *class_dev;
struct completion *released; /* wait for release */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define interface_to_usbdev(intf) \
......@@ -140,19 +146,43 @@ static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
/* this maximum is arbitrary */
#define USB_MAXINTERFACES 32
/* USB_DT_CONFIG: Configuration descriptor information.
/**
* struct usb_host_config - representation of a device's configuration
* @desc: the device's configuration descriptor.
* @interface: array of usb_interface structures, one for each interface
* in the configuration. The number of interfaces is stored in
* desc.bNumInterfaces.
* @extra: pointer to buffer containing all extra descriptors associated
* with this configuration (those preceding the first interface
* descriptor).
* @extralen: length of the extra descriptors buffer.
*
* USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
* descriptor type is different. Highspeed-capable devices can look
* different depending on what speed they're currently running. Only
* devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG.
* USB devices may have multiple configurations, but only one can be active
* at any time. Each encapsulates a different operational environment;
* for example, a dual-speed device would have separate configurations for
* full-speed and high-speed operation. The number of configurations
* available is stored in the device descriptor as bNumConfigurations.
*
* A configuration can contain multiple interfaces. Each corresponds to
* a different function of the USB device, and all are available whenever
* the configuration is active. The USB standard says that interfaces
* are supposed to be numbered from 0 to desc.bNumInterfaces-1, but a lot
* of devices get this wrong. In addition, the interface array is not
* guaranteed to be sorted in numerical order. Use usb_ifnum_to_if() to
* look up an interface entry based on its number.
*
* Device drivers should not attempt to activate configurations. The choice
* of which configuration to install is a policy decision based on such
* considerations as available power, functionality provided, and the user's
* desires (expressed through hotplug scripts). However, drivers can call
* usb_reset_configuration() to reinitialize the current configuration and
* all its interfaces.
*/
struct usb_host_config {
struct usb_config_descriptor desc;
/* the interfaces associated with this configuration
* these will be in numeric order, 0..desc.bNumInterfaces
*/
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
......@@ -294,8 +324,12 @@ extern void usb_driver_release_interface(struct usb_driver *driver,
const struct usb_device_id *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id);
extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor);
extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
int minor);
extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev,
unsigned ifnum);
extern struct usb_host_interface *usb_altnum_to_altsetting(
struct usb_interface *intf, unsigned int altnum);
/**
......
......@@ -690,7 +690,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
/**
* struct usb_string - wraps a C string and its USB id
* @id:the (nonzero) ID for this string
* @s:the string, in ISO-8859/1 characters
* @s:the string, in UTF-8 encoding
*
* If you're using usb_gadget_get_string(), use this to wrap a string
* together with its ID.
......@@ -716,6 +716,17 @@ struct usb_gadget_strings {
/* put descriptor for string with that id into buf (buflen >= 256) */
int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
/*-------------------------------------------------------------------------*/
/* utility to simplify managing config descriptors */
/* write vector of descriptors into buffer */
int usb_descriptor_fillbuf(void *, unsigned,
const struct usb_descriptor_header **);
/* build config descriptor from single descriptor vector */
int usb_gadget_config_buf(const struct usb_config_descriptor *config,
void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
#endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment