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

Merge kroah.com:/home/linux/BK/bleed-2.6

into kroah.com:/home/linux/BK/usb-2.6
parents 1b2ed5b7 731ea3e9
......@@ -673,11 +673,6 @@ S: Northampton
S: NN1 3QT
S: United Kingdom
N: Stephane Dalton
E: sdalton@videotron.ca
D: Tieman Voyager USB Braille display driver.
S: Qubec, Canada
N: Uwe Dannowski
E: Uwe.Dannowski@ira.uka.de
W: http://i30www.ira.uka.de/~dannowsk/
......@@ -797,11 +792,6 @@ E: cort@fsmlabs.com
W: http://www.fsmlabs.com/linuxppcbk.html
D: PowerPC
N: Stphane Doyon
E: s.doyon@videotron.ca
D: Tieman Voyager USB Braille display driver.
S: Qubec, Canada
N: Oleg Drokin
E: green@ccssu.crimea.ua
W: http://www.ccssu.crimea.ua/~green
......
......@@ -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>
......
Kernel Driver for the Tieman Voyager Braille Display (USB)
Authors:
Stéphane Dalton <sdalton@videotron.ca>
Stéphane Doyon <s.doyon@videotron.ca>
Version 0.8, April 17, 2002
The brlvger driver supports a Braille display (aka Braille terminal)
model Voyager from Tieman.
The driver has been in heavy use for about six months now (as of April
17th 2002) by a very few users (about 3-4), who say it has worked very
well for them.
We have tested it with a Voyager 44, but it should also support
the Voyager 70.
This driver implements a character device which allows userspace programs
access to the braille displays raw functions. You still need a userspace
program to perform the screen-review functions and control the
display. Get BRLTTY from http://mielke.cc/brltty/ (version 2.99.8 or
later). It has a Voyager driver which interfaces with this kernel driver.
The interface is through a character device, major 180, minor 128, called
"brlvger" under devfs.
Many thanks to the Tieman people: Corand van Strien, Ivar Illing, Daphne
Vogelaar and Ingrid Vogel. They provided us with a Braille display (as
well as programming information) so that we could write this driver. They
replaced the display when it broke and they answered our technical
questions. It is very motivating when companies take an interest in such
projects and are so supportive.
Thanks to Andor Demarteau <ademarte@students.cs.uu.nl> who got this whole
project started and beta-tested all our early buggy attempts.
......@@ -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/
This diff is collapsed.
......@@ -1966,13 +1966,6 @@ P: Romain Lievin
M: roms@lpg.ticalc.org
S: Maintained
TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
P: Stephane Dalton
M: sdalton@videotron.ca
P: Stphane Doyon
M: s.doyon@videotron.ca
S: Maintained
TLAN NETWORK DRIVER
P: Samuel Chessman
M: chessman@tux.org
......@@ -2152,14 +2145,6 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://pegasus2.sourceforge.net/
S: Maintained
USB SCANNER DRIVER
P: Henning Meier-Geinitz
M: henning@meier-geinitz.de
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.meier-geinitz.de/kernel/
S: Maintained
USB SE401 DRIVER
P: Jeroen Vreeken
M: pe1rxq@amsat.org
......
......@@ -589,7 +589,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
}
/* get the active interface descriptor */
iface_desc = &interface->altsetting[interface->act_altsetting];
iface_desc = interface->cur_altsetting;
/* check out that we have a HID device */
if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
......
......@@ -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;
......
......@@ -1349,9 +1349,11 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
{
struct usb_device *dev= interface_to_usbdev(intf);
hfcusb_data *context;
struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting;
struct usb_host_interface *iface = intf->cur_altsetting;
struct usb_host_interface *iface_used = NULL;
struct usb_host_endpoint *ep;
int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
int ifnum = iface->desc.bInterfaceNumber;
int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0;
// usb_show_device(dev);
......@@ -1366,7 +1368,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
#ifdef VERBOSE_USB_DEBUG
printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n",
intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor);
ifnum, iface->desc.bAlternateSetting, intf->minor);
#endif
if (vend_idx != 0xffff) {
......@@ -1374,14 +1376,15 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name);
#endif
/* if vendor and product ID is OK, start probing a matching alternate setting ... */
probe_alt_setting = 0;
alt_idx = 0;
small_match=0xffff;
// default settings
iso_packet_size=16;
packet_size=64;
while(probe_alt_setting < intf->num_altsetting) {
iface = intf->altsetting + probe_alt_setting;
while (alt_idx < intf->num_altsetting) {
iface = intf->altsetting + alt_idx;
probe_alt_setting = iface->desc.bAlternateSetting;
cfg_used=0;
#ifdef VERBOSE_USB_DEBUG
......@@ -1395,7 +1398,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
#ifdef VERBOSE_USB_DEBUG
printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n",
probe_alt_setting, intf->act_altsetting,cfg_used);
ifnum, probe_alt_setting, cfg_used);
#endif
// copy table
memcpy(cmptbl,vcf,16*sizeof(int));
......@@ -1448,6 +1451,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
if (cfg_used < small_match) {
small_match = cfg_used;
alt_used = probe_alt_setting;
iface_used = iface;
}
#ifdef VERBOSE_USB_DEBUG
printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);
......@@ -1457,15 +1461,14 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
cfg_used++;
}
probe_alt_setting++;
} /* (probe_alt_setting < intf->num_altsetting) */
alt_idx++;
} /* (alt_idx < intf->num_altsetting) */
#ifdef VERBOSE_USB_DEBUG
printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);
#endif
// yiipiee, we found a valid config
if (small_match != 0xffff) {
intf->act_altsetting = alt_used;
iface = intf->altsetting + intf->act_altsetting;
iface = iface_used;
if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
return(-ENOMEM); /* got no mem */
......@@ -1542,8 +1545,8 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_
// now share our luck
context->dev = dev; /* save device */
context->if_used = intf->altsetting->desc.bInterfaceNumber; /* save used interface */
context->alt_used = intf->act_altsetting; /* and alternate config */
context->if_used = ifnum; /* save used interface */
context->alt_used = alt_used; /* and alternate config */
context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
context->cfg_used=vcf[16]; // store used config
context->vend_idx=vend_idx; // store found vendor
......
......@@ -6,32 +6,36 @@ menu "USB support"
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
config USB
tristate "Support for USB"
tristate "Support for Host-side USB"
depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610
---help---
Universal Serial Bus (USB) is a specification for a serial bus
subsystem which offers higher speeds and more features than the
traditional PC serial port. The bus supplies power to peripherals
and allows for hot swapping. Up to 127 USB peripherals can be
connected to a single USB port in a tree structure. The USB port is
the root of the tree, the peripherals are the leaves and the inner
nodes are special USB devices called hubs. Many newer PC's have USB
ports and newer peripherals such as scanners, keyboards, mice,
modems, and printers support the USB protocol and can be connected
to the PC via those ports.
Say Y here if your computer has a USB port and you want to use USB
devices. You then need to say Y to at least one of "UHCI HCD support"
or "OHCI HCD support" below (the type of interface that the USB hardware
in your computer provides to the operating system) and then choose
from amongst the drivers for USB peripherals. You may want to check
out the information provided in <file:Documentation/usb/> and
especially the links given in <file:Documentation/usb/usb-help.txt>.
If you have a new USB 2.0 High Speed system, you should also choose
"EHCI HCD (USB 2.0) support" as well as at least one of UHCI or OHCI.
It doesn't normally hurt to select them all if you are not certain.
connected to a single USB host in a tree structure.
The USB host is the root of the tree, the peripherals are the
leaves and the inner nodes are special USB devices called hubs.
Most PCs now have USB host ports, used to connect peripherals
such as scanners, keyboards, mice, modems, cameras, disks,
flash memory, network links, and printers to the PC.
Say Y here if your computer has a host-side USB port and you want
to use USB devices. You then need to say Y to at least one of the
Host Controller Driver (HCD) options below. Choose a USB 1.1
controller, such as "UHCI HCD support" or "OHCI HCD support",
and "EHCI HCD (USB 2.0) support" except for older systems that
do not have USB 2.0 support. It doesn't normally hurt to select
them all if you are not certain.
If your system has a device-side USB port, used in the peripheral
side of the USB protocol, see the "USB Gadget" framework instead.
After choosing your HCD, then select drivers for the USB peripherals
you'll be using. You may want to check out the information provided
in <file:Documentation/usb/> and especially the links given in
<file:Documentation/usb/usb-help.txt>.
To compile this driver as a module, choose M here: the
module will be called usbcore.
......
......@@ -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/
......@@ -50,7 +55,6 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_BRLVGER) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
......
This diff is collapsed.
......@@ -1025,7 +1025,7 @@ static int usb_bluetooth_probe (struct usb_interface *intf,
int num_bulk_in = 0;
int num_bulk_out = 0;
interface = &intf->altsetting[0];
interface = intf->cur_altsetting;
control_out_endpoint = interface->desc.bInterfaceNumber;
/* find the endpoints that we need */
......
......@@ -595,12 +595,12 @@ static int acm_probe (struct usb_interface *intf,
* is there it's not for call management ... so use
* the cdc union descriptor whenever there is one.
*/
ifcom = intf->altsetting + 0;
ifcom = intf->cur_altsetting;
if (intf == cfacm->interface[j]) {
ifdata = cfacm->interface[j + 1]->altsetting + 0;
ifdata = cfacm->interface[j + 1]->cur_altsetting;
data = cfacm->interface[j + 1];
} else if (intf == cfacm->interface[j + 1]) {
ifdata = cfacm->interface[j]->altsetting + 0;
ifdata = cfacm->interface[j]->cur_altsetting;
data = cfacm->interface[j];
} else
continue;
......
......@@ -39,9 +39,6 @@
#include <linux/init.h>
#include <asm/semaphore.h>
/** This declaration is missing from linux/usb.h **/
extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
#include "usb-midi.h"
/* ------------------------------------------------------------------------- */
......@@ -1519,15 +1516,17 @@ static int on_bits( unsigned short v )
static int get_alt_setting( struct usb_device *d, int ifnum )
{
int alts, alt=0;
struct usb_interface *iface;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *ep;
int epin, epout;
int i;
alts = d->actconfig->interface[ifnum]->num_altsetting;
iface = usb_ifnum_to_if( d, ifnum );
alts = iface->num_altsetting;
for ( alt=0 ; alt<alts ; alt++ ) {
interface = &d->actconfig->interface[ifnum]->altsetting[alt];
interface = &iface->altsetting[alt];
epin = -1;
epout = -1;
......@@ -1542,7 +1541,7 @@ static int get_alt_setting( struct usb_device *d, int ifnum )
epout = i;
}
if ( epin >= 0 && epout >= 0 ) {
return alt;
return interface->desc.bAlternateSetting;
}
}
}
......@@ -1780,12 +1779,13 @@ static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s
* Called by usb_midi_probe();
**/
static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
static int detect_yamaha_device( struct usb_device *d,
struct usb_interface *iface, unsigned int ifnum,
struct usb_midi_state *s)
{
struct usb_host_config *c = d->actconfig;
struct usb_host_interface *interface;
struct usb_midi_device *u;
unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
unsigned char *buffer;
int bufSize;
int i;
int alts=-1;
......@@ -1795,13 +1795,13 @@ static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struc
return -EINVAL;
}
for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) {
interface = c->interface[ifnum]->altsetting + i;
for ( i=0 ; i < iface->num_altsetting; i++ ) {
interface = iface->altsetting + i;
if ( interface->desc.bInterfaceClass != 255 ||
interface->desc.bInterfaceSubClass != 0 )
continue;
alts = i;
alts = interface->desc.bAlternateSetting;
}
if ( alts == -1 ) {
return -EINVAL;
......@@ -1810,30 +1810,11 @@ static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struc
printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
if ( ret < 0 ) {
printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
return -EINVAL;
}
if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
printk(KERN_INFO "usb-midi: config not as expected.\n");
return -EINVAL;
}
bufSize = buf[2] | buf[3]<<8;
buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
if ( !buffer ) {
printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
return -EINVAL;
}
ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
if ( ret < 0 ) {
printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
kfree(buffer);
return -EINVAL;
}
i = d->actconfig - d->config;
buffer = d->rawdescriptors[i];
bufSize = d->actconfig->desc.wTotalLength;
u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
kfree(buffer);
if ( u == NULL ) {
return -EINVAL;
}
......@@ -1878,24 +1859,25 @@ static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifn
* Returns 0 on success, negative on failure.
* Called by usb_midi_probe();
**/
static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
static int detect_midi_subclass(struct usb_device *d,
struct usb_interface *iface, unsigned int ifnum,
struct usb_midi_state *s)
{
struct usb_host_config *c = d->actconfig;
struct usb_host_interface *interface;
struct usb_midi_device *u;
unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
unsigned char *buffer;
int bufSize;
int i;
int alts=-1;
int ret;
for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) {
interface = c->interface[ifnum]->altsetting + i;
for ( i=0 ; i < iface->num_altsetting; i++ ) {
interface = iface->altsetting + i;
if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
continue;
alts = i;
alts = interface->desc.bAlternateSetting;
}
if ( alts == -1 ) {
return -EINVAL;
......@@ -1915,30 +1897,11 @@ static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct
descriptor they modify or extend.
*/
ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
if ( ret < 0 ) {
printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
return -EINVAL;
}
if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
printk(KERN_INFO "usb-midi: config not as expected.\n");
return -EINVAL;
}
bufSize = buf[2] | buf[3]<<8;
buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
if ( !buffer ) {
printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
return -EINVAL;
}
ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
if ( ret < 0 ) {
printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
kfree(buffer);
return -EINVAL;
}
i = d->actconfig - d->config;
buffer = d->rawdescriptors[i];
bufSize = d->actconfig->desc.wTotalLength;
u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
kfree(buffer);
if ( u == NULL ) {
return -EINVAL;
}
......@@ -2002,7 +1965,7 @@ static int usb_midi_probe(struct usb_interface *intf,
{
struct usb_midi_state *s;
struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->altsetting->desc.bInterfaceNumber;
int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
if ( !s )
......@@ -2018,9 +1981,9 @@ static int usb_midi_probe(struct usb_interface *intf,
if (
detect_by_hand( dev, ifnum, s ) &&
detect_midi_subclass( dev, ifnum, s ) &&
detect_midi_subclass( dev, intf, ifnum, s ) &&
detect_vendor_specific_device( dev, ifnum, s ) &&
detect_yamaha_device( dev, ifnum, s) ) {
detect_yamaha_device( dev, intf, ifnum, s) ) {
kfree(s);
return -EIO;
}
......
......@@ -133,6 +133,7 @@ struct usblp {
wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */
int ifnum; /* Interface number */
struct usb_interface *intf; /* The interface */
/* Alternate-setting numbers and endpoints for each protocol
* (7/1/{index=1,2,3}) that the device supports: */
struct {
......@@ -609,8 +610,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
while (writecount < count) {
if (!usblp->wcomplete) {
barrier();
if (file->f_flags & O_NONBLOCK)
if (file->f_flags & O_NONBLOCK) {
writecount += transfer_length;
return writecount ? writecount : -EAGAIN;
}
timeout = USBLP_WRITE_TIMEOUT;
add_wait_queue(&usblp->wait, &wait);
......@@ -670,7 +673,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
usblp->writeurb->transfer_buffer_length = transfer_length;
if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) {
if (copy_from_user(usblp->writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
up(&usblp->sem);
return writecount ? writecount : -EFAULT;
}
......@@ -837,7 +841,8 @@ static int usblp_probe(struct usb_interface *intf,
usblp->dev = dev;
init_MUTEX (&usblp->sem);
init_waitqueue_head(&usblp->wait);
usblp->ifnum = intf->altsetting->desc.bInterfaceNumber;
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usblp->intf = intf;
usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->writeurb) {
......@@ -973,7 +978,7 @@ static int usblp_select_alts(struct usblp *usblp)
struct usb_endpoint_descriptor *epd, *epwrite, *epread;
int p, i, e;
if_alt = usblp->dev->actconfig->interface[usblp->ifnum];
if_alt = usblp->intf;
for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
usblp->protocol[p].alt_setting = -1;
......@@ -1022,7 +1027,8 @@ static int usblp_select_alts(struct usblp *usblp)
epread = NULL;
}
usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = i;
usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting =
ifd->desc.bAlternateSetting;
usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite;
usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread;
}
......
......@@ -51,8 +51,8 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
* @hcd: the bus whose buffer pools are to be initialized
* Context: !in_interrupt()
*
* Call this as part of initializing a host controller that uses the pci dma
* memory allocators. It initializes some pools of dma-consistent memory that
* Call this as part of initializing a host controller that uses the dma
* memory allocators. It initializes some pools of dma-coherent memory that
* will be shared by all drivers using that controller, or returns a negative
* errno value on error.
*
......@@ -115,6 +115,12 @@ void *hcd_buffer_alloc (
struct usb_hcd *hcd = bus->hcpriv;
int i;
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask) {
*dma = ~(dma_addr_t) 0;
return kmalloc (size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
......@@ -134,6 +140,12 @@ void hcd_buffer_free (
if (!addr)
return;
if (!bus->controller->dma_mask) {
kfree (addr);
return;
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
dma_pool_free (hcd->pool [i], addr, dma);
......
......@@ -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) {
......
......@@ -1213,7 +1213,7 @@ static int hcd_unlink_urb (struct urb *urb)
break;
}
if (tmp != &urb->urb_list) {
retval = -EINVAL;
retval = -EIDRM;
goto done;
}
......@@ -1294,7 +1294,7 @@ static int hcd_unlink_urb (struct urb *urb)
spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
bye:
if (retval && sys && sys->driver)
if (retval != -EIDRM && sys && sys->driver)
dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
return retval;
}
......
......@@ -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);
}
}
......
......@@ -116,7 +116,8 @@ struct urb * usb_get_urb(struct urb *urb)
* describing that request to the USB subsystem. Request completion will
* be indicated later, asynchronously, by calling the completion handler.
* The three types of completion are success, error, and unlink
* (also called "request cancellation").
* (a software-induced fault, also called "request cancelation").
*
* URBs may be submitted in interrupt context.
*
* The caller must have correctly initialized the URB before submitting
......@@ -127,12 +128,23 @@ struct urb * usb_get_urb(struct urb *urb)
*
* Successful submissions return 0; otherwise this routine returns a
* negative error number. If the submission is successful, the complete()
* callback from the urb will be called exactly once, when the USB core and
* host controller driver are finished with the urb. When the completion
* callback from the URB will be called exactly once, when the USB core and
* Host Controller Driver (HCD) are finished with the URB. When the completion
* function is called, control of the URB is returned to the device
* driver which issued the request. The completion handler may then
* immediately free or reuse that URB.
*
* With few exceptions, USB device drivers should never access URB fields
* provided by usbcore or the HCD until its complete() is called.
* The exceptions relate to periodic transfer scheduling. For both
* interrupt and isochronous urbs, as part of successful URB submission
* urb->interval is modified to reflect the actual transfer period used
* (normally some power of two units). And for isochronous urbs,
* urb->start_frame is modified to reflect when the URB's transfers were
* scheduled to start. Not all isochronous transfer scheduling policies
* will work, but most host controller drivers should easily handle ISO
* queues going from now until 10-200 msec into the future.
*
* For control endpoints, the synchronous usb_control_msg() call is
* often used (in non-interrupt context) instead of this call.
* That is often used through convenience wrappers, for the requests
......@@ -143,15 +155,17 @@ struct urb * usb_get_urb(struct urb *urb)
*
* URBs may be submitted to endpoints before previous ones complete, to
* minimize the impact of interrupt latencies and system overhead on data
* throughput. This is required for continuous isochronous data streams,
* throughput. With that queuing policy, an endpoint's queue would never
* be empty. This is required for continuous isochronous data streams,
* and may also be required for some kinds of interrupt transfers. Such
* queueing also maximizes bandwidth utilization by letting USB controllers
* queuing also maximizes bandwidth utilization by letting USB controllers
* start work on later requests before driver software has finished the
* completion processing for earlier requests.
* completion processing for earlier (successful) requests.
*
* Bulk and Isochronous URBs may always be queued. At this writing, all
* mainstream host controller drivers support queueing for control and
* interrupt transfer requests.
* As of Linux 2.6, all USB endpoint transfer queues support depths greater
* than one. This was previously a HCD-specific behavior, except for ISO
* transfers. Non-isochronous endpoint queues are inactive during cleanup
* after faults (transfer errors or cancelation).
*
* Reserved Bandwidth Transfers:
*
......@@ -389,7 +403,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
* When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this
* request is synchronous. Success is indicated by returning zero,
* at which time the urb will have been unlinked and its completion
* handler will have been called with urb->status -ENOENT. Failure is
* handler will have been called with urb->status == -ENOENT. Failure is
* indicated by any other return value.
*
* The synchronous cancelation mode may not be used
......@@ -400,8 +414,37 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
* When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
* request is asynchronous. Success is indicated by returning -EINPROGRESS,
* at which time the urb will normally not have been unlinked.
* The completion function will see urb->status -ECONNRESET. Failure
* The completion function will see urb->status == -ECONNRESET. Failure
* is indicated by any other return value.
*
* Unlinking and Endpoint Queues:
*
* Host Controller Driver (HCDs) place all the URBs for a particular
* endpoint in a queue. Normally the queue advances as the controller
* hardware processes each request. But when an URB terminates with any
* fault (such as an error, or being unlinked) its queue stops, at least
* until that URB's completion routine returns. It is guaranteed that
* the queue will not restart until all its unlinked URBs have been fully
* retired, with their completion routines run, even if that's not until
* some time after the original completion handler returns.
*
* This means that USB device drivers can safely build deep queues for
* large or complex transfers, and clean them up reliably after any sort
* of aborted transfer by unlinking all pending URBs at the first fault.
*
* Note that an URB terminating early because a short packet was received
* will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
* Also, that all unlinks performed in any URB completion handler must
* be asynchronous.
*
* Queues for isochronous endpoints are treated differently, because they
* advance at fixed rates. Such queues do not stop when an URB is unlinked.
* An unlinked URB may leave a gap in the stream of packets. It is undefined
* whether such gaps can be filled in.
*
* When control URBs terminates with an error, it is likely that the
* status stage of the transfer will not take place, even if it is merely
* a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
*/
int usb_unlink_urb(struct urb *urb)
{
......
......@@ -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;
......@@ -1598,6 +1625,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);
......
......@@ -3,6 +3,15 @@
# (a) a peripheral controller, and
# (b) the gadget driver using it.
#
# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !!
#
# - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
# - Some systems have both kinds of of controller.
#
# With help from a special transceiver and a "Mini-AB" jack, systems with
# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
#
menu "USB Gadget Support"
config USB_GADGET
......@@ -11,7 +20,7 @@ config USB_GADGET
USB is a master/slave protocol, organized with one master
host (such as a PC) controlling up to 127 peripheral devices.
The USB hardware is asymmetric, which makes it easier to set up:
you can't connect two "to-the-host" connectors to each other.
you can't connect a "to-the-host" connector to a peripheral.
Linux can run in the host, or in the peripheral. In both cases
you need a low level bus controller driver, and some software
......@@ -43,6 +52,7 @@ choice
config USB_GADGET_NET2280
boolean "NetChip 2280"
depends on PCI
select USB_GADGET_DUALSPEED
help
NetChip 2280 is a PCI based USB peripheral controller which
supports both full and high speed USB 2.0 data transfers.
......@@ -126,6 +136,13 @@ config USB_SA1100
endchoice
config USB_GADGET_DUALSPEED
bool
depends on USB_GADGET
default n
help
Means that gadget drivers should include extra descriptors
and code to handle dual-speed controllers.
#
# USB Gadget Drivers
......
......@@ -8,8 +8,8 @@ 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_zero-objs := zero.o usbstring.o config.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;
}
......@@ -124,7 +124,6 @@ struct eth_dev {
* DRIVER_VERSION_NUM ... alerts the host side driver to differences
* EP_*_NAME ... which endpoints do we use for which purpose?
* EP_*_NUM ... numbers for them (often limited by hardware)
* HIGHSPEED ... define if ep0 and descriptors need high speed support
* WAKEUP ... if hardware supports remote wakeup AND we will issue the
* usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
*
......@@ -162,7 +161,6 @@ static const char EP_IN_NAME [] = "ep-b";
#define EP_IN_NUM 2
static const char EP_STATUS_NAME [] = "ep-f";
#define EP_STATUS_NUM 3
#define HIGHSPEED
/* supports remote wakeup, but this driver doesn't */
extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
......@@ -311,7 +309,7 @@ static const char EP_IN_NAME[] = "ep2in-bulk";
#define DEFAULT_QLEN 2 /* double buffering by default */
#endif
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
static unsigned qmult = 5;
module_param (qmult, uint, S_IRUGO|S_IWUSR);
......@@ -324,7 +322,7 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
/* also defer IRQs on highspeed TX */
#define TX_DELAY DEFAULT_QLEN
#else /* !HIGHSPEED ... full speed: */
#else /* full speed (low speed doesn't do bulk) */
#define qlen(gadget) DEFAULT_QLEN
#endif
......@@ -607,7 +605,26 @@ fs_sink_desc = {
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
#ifdef HIGHSPEED
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 CONFIG_USB_GADGET_DUALSPEED
/*
* usb 2.0 devices need to expose both high speed and full speed
......@@ -660,6 +677,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))
......@@ -669,7 +705,7 @@ dev_qualifier = {
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs
#endif /* !HIGHSPEED */
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
......@@ -704,86 +740,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;
#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 len;
const struct usb_descriptor_header **function = fs_function;
#ifdef CONFIG_USB_GADGET_DUALSPEED
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;
}
/*-------------------------------------------------------------------------*/
......@@ -992,7 +967,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
switch (gadget->speed) {
case USB_SPEED_FULL: speed = "full"; break;
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_SPEED_HIGH: speed = "high"; break;
#endif
default: speed = "?"; break;
......@@ -1163,15 +1138,19 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (ctrl->wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
break;
// FALLTHROUGH
#endif /* HIGHSPEED */
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget->speed, req->buf,
ctrl->wValue >> 8,
......@@ -1675,7 +1654,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
#endif
req->length = length;
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
......@@ -1798,7 +1777,7 @@ eth_bind (struct usb_gadget *gadget)
#endif
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assumes ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
#endif
......@@ -1894,7 +1873,7 @@ eth_bind (struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver eth_driver = {
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
......
/*
* USB device controllers have lots of quirks. Use these macros in
* gadget drivers or other code that needs to deal with them, and which
* autoconfigures instead of using early binding to the hardware.
*
* This could eventually work like the ARM mach_is_*() stuff, driven by
* some config file that gets updated as new hardware is supported.
*
* NOTE: some of these controller drivers may not be available yet.
*/
#ifdef CONFIG_USB_GADGET_NET2280
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
#else
#define gadget_is_net2280(g) 0
#endif
#ifdef CONFIG_USB_GADGET_PXA
#define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name)
#else
#define gadget_is_pxa(g) 0
#endif
#ifdef CONFIG_USB_GADGET_GOKU
#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name)
#else
#define gadget_is_goku(g) 0
#endif
#ifdef CONFIG_USB_GADGET_SUPERH
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
#else
#define gadget_is_sh(g) 0
#endif
#ifdef CONFIG_USB_GADGET_SA1100
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
#else
#define gadget_is_sa1100(g) 0
#endif
#ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else
#define gadget_is_mq11xx(g) 0
#endif
#ifdef CONFIG_USB_GADGET_OMAP
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
#else
#define gadget_is_omap(g) 0
#endif
// CONFIG_USB_GADGET_AT91RM9200
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
// ...
......@@ -2663,7 +2663,7 @@ static void gadget_release (struct device *_dev)
/* tear down the binding between this driver and the pci device */
static void __exit net2280_remove (struct pci_dev *pdev)
static void net2280_remove (struct pci_dev *pdev)
{
struct net2280 *dev = pci_get_drvdata (pdev);
......@@ -2736,6 +2736,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init (&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &net2280_ops;
dev->gadget.is_dualspeed = 1;
/* the "gadget" abstracts/virtualizes the controller */
strcpy (dev->gadget.dev.bus_id, "gadget");
......@@ -2884,7 +2885,7 @@ static struct pci_driver net2280_pci_driver = {
.id_table = pci_ids,
.probe = net2280_probe,
.remove = __exit_p(net2280_remove),
.remove = net2280_remove,
/* FIXME add power management support */
};
......
......@@ -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];
}
This diff is collapsed.
......@@ -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 */
}
}
......
This diff is collapsed.
......@@ -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);
}
......@@ -2458,9 +2444,11 @@ static int uhci_suspend(struct usb_hcd *hcd, u32 state)
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
/* Don't try to suspend broken motherboards, reset instead */
if (suspend_allowed(uhci))
if (suspend_allowed(uhci)) {
suspend_hc(uhci);
else
uhci->saved_framenumber =
inw(uhci->io_addr + USBFRNUM) & 0x3ff;
} else
reset_hc(uhci);
return 0;
}
......@@ -2471,9 +2459,20 @@ 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 don't maintain the UHCI register values
* during a PM suspend/resume cycle, so reinitialize
* the Frame Number, the Framelist Base Address, and the
* Interrupt Enable registers.
*/
outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
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 */
/*
......@@ -350,6 +350,7 @@ struct uhci_hcd {
enum uhci_state state; /* FIXME: needs a spinlock */
unsigned long state_end; /* Time of next transition */
int resume_detect; /* Need a Global Resume */
unsigned int saved_framenumber; /* Save during PM suspend */
/* Main list of URB's currently controlled by this HC */
spinlock_t urb_list_lock;
......
......@@ -42,7 +42,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *altsetting = intf->altsetting;
struct usb_host_interface *altsetting = intf->cur_altsetting;
struct hpusbscsi *new;
int error = -ENOMEM;
int i;
......
......@@ -431,7 +431,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
err ("probe fails -> wrong Number of Configuration");
return -ENODEV;
}
intf_desc = &intf->altsetting[0];
intf_desc = intf->cur_altsetting;
if (
( intf_desc->desc.bInterfaceClass != 0xff )
......@@ -469,13 +469,6 @@ static int mdc800_usb_probe (struct usb_interface *intf,
}
usb_driver_claim_interface (&mdc800_usb_driver, intf, mdc800);
if (usb_set_interface (dev, intf_desc->desc.bInterfaceNumber, 0) < 0)
{
err ("MDC800 Configuration fails.");
return -ENODEV;
}
info ("Found Mustek MDC800 on USB.");
down (&mdc800->io_lock);
......@@ -551,8 +544,6 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
usb_unlink_urb (mdc800->write_urb);
usb_unlink_urb (mdc800->download_urb);
usb_driver_release_interface (&mdc800_usb_driver, intf);
mdc800->dev=0;
usb_set_intfdata(intf, NULL);
}
......
......@@ -693,7 +693,6 @@ static int mts_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int i;
int result;
int ep_out = -1;
int ep_in_set[3]; /* this will break if we have more than three endpoints
which is why we check */
......@@ -703,7 +702,7 @@ static int mts_usb_probe(struct usb_interface *intf,
struct vendor_product const* p;
struct usb_device *dev = interface_to_usbdev (intf);
/* the altsettting 0 on the interface we're probing */
/* the current altsetting on the interface we're probing */
struct usb_host_interface *altsetting;
MTS_DEBUG_GOT_HERE();
......@@ -724,8 +723,8 @@ static int mts_usb_probe(struct usb_interface *intf,
MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
p->name );
/* the altsettting 0 on the interface we're probing */
altsetting = &(intf->altsetting[0]);
/* the current altsetting on the interface we're probing */
altsetting = intf->cur_altsetting;
/* Check if the config is sane */
......@@ -766,20 +765,6 @@ static int mts_usb_probe(struct usb_interface *intf,
MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
return -ENODEV;
}
result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0);
MTS_DEBUG("usb_set_interface returned %d.\n",result);
switch( result )
{
case 0: /* no error */
break;
default:
MTS_DEBUG( "unknown error %d from usb_set_interface\n",
(int)result );
return -ENODEV;
}
new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
......
......@@ -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
......@@ -43,7 +43,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
/*
* Version Information
*/
......@@ -160,9 +161,9 @@ aiptek_irq(struct urb *urb, struct pt_regs *regs)
proximity = data[5] & 0x01;
input_report_key(dev, BTN_TOOL_PEN, proximity);
x = ((__u32) data[1]) | ((__u32) data[2] << 8);
y = ((__u32) data[3]) | ((__u32) data[4] << 8);
pressure = ((__u32) data[6]) | ((__u32) data[7] << 8);
x = le16_to_cpu(get_unaligned((u16 *) &data[1]));
y = le16_to_cpu(get_unaligned((u16 *) &data[3]));
pressure = le16_to_cpu(*(u16 *) &data[6]);
pressure -= aiptek->features->pressure_min;
if (pressure < 0) {
......@@ -209,8 +210,10 @@ aiptek_open(struct input_dev *dev)
return 0;
aiptek->irq->dev = aiptek->usbdev;
if (usb_submit_urb(aiptek->irq, GFP_KERNEL))
if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) {
aiptek->open--;
return -EIO;
}
return 0;
}
......@@ -234,19 +237,27 @@ usb_set_report(struct usb_device *dev, struct usb_host_interface *inter, unsigne
(type << 8) + id, inter->desc.bInterfaceNumber, buf, size, HZ);
}
static void
static int
aiptek_command(struct usb_device *dev, struct usb_host_interface *inter,
unsigned char command, unsigned char data)
{
__u8 buf[3];
u8 *buf;
int err;
buf = kmalloc(3, GFP_KERNEL);
if (!buf)
return -ENOMEM;
buf[0] = 4;
buf[1] = command;
buf[2] = data;
if (usb_set_report(dev, inter, 3, 2, buf, 3) != 3) {
if ((err = usb_set_report(dev, inter, 3, 2, buf, 3)) != 3) {
dbg("aiptek_command: 0x%x 0x%x\n", command, data);
}
kfree(buf);
return err < 0 ? err : 0;
}
static int
......@@ -257,30 +268,32 @@ aiptek_probe(struct usb_interface *intf,
struct usb_host_interface *interface = intf->altsetting + 0;
struct usb_endpoint_descriptor *endpoint;
struct aiptek *aiptek;
int err = -ENOMEM;
if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL)))
return -ENOMEM;
goto error_out_noalloc;
memset(aiptek, 0, sizeof (struct aiptek));
aiptek->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &aiptek->data_dma);
aiptek->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &aiptek->data_dma);
if (!aiptek->data) {
kfree(aiptek);
return -ENOMEM;
goto error_out_nobuf;
}
aiptek->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!aiptek->irq) {
usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma);
kfree(aiptek);
return -ENOMEM;
goto error_out_nourb;
}
/* Resolution500LPI */
aiptek_command(dev, interface, 0x18, 0x04);
err = aiptek_command(dev, interface, 0x18, 0x04);
if (err)
goto error_out;
/* SwitchToTablet */
aiptek_command(dev, interface, 0x10, 0x01);
err = aiptek_command(dev, interface, 0x10, 0x01);
if (err)
goto error_out;
aiptek->features = aiptek_features + id->driver_info;
......@@ -340,6 +353,16 @@ aiptek_probe(struct usb_interface *intf,
usb_set_intfdata(intf, aiptek);
return 0;
error_out:
usb_free_urb(aiptek->irq);
error_out_nourb:
usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma);
error_out_nobuf:
kfree(aiptek);
error_out_noalloc:
return err;
}
static void
......
This diff is collapsed.
......@@ -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;
......
......@@ -4,6 +4,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
/*
* Version Information
......@@ -65,8 +67,8 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
kbtab->x = (data[2] << 8) + data[1];
kbtab->y = (data[4] << 8) + data[3];
kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1]));
kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3]));
kbtab->pressure = (data[5]);
......@@ -74,12 +76,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);
......@@ -105,8 +110,10 @@ static int kbtab_open(struct input_dev *dev)
return 0;
kbtab->irq->dev = kbtab->usbdev;
if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) {
kbtab->open--;
return -EIO;
}
return 0;
}
......@@ -130,7 +137,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
return -ENOMEM;
memset(kbtab, 0, sizeof(struct kbtab));
kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma);
kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
if (!kbtab->data) {
kfree(kbtab);
return -ENOMEM;
......
This diff is collapsed.
......@@ -200,6 +200,7 @@ static int hid_pid_upload_effect(struct input_dev *dev,
break;
if ( id == FF_EFFECTS_MAX) {
spin_unlock_irqrestore(&pid_private->lock,flags);
// TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) {
dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
return -ENOMEM;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -4,7 +4,6 @@
#
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
obj-$(CONFIG_USB_BRLVGER) += brlvger.o
obj-$(CONFIG_USB_EMI62) += emi62.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_LCD) += usblcd.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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