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

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

into kroah.com:/home/greg/linux/BK/usb-2.6
parents 9e81ab3b 662c60e7
...@@ -2239,8 +2239,8 @@ W: http://www.linux-usb.org ...@@ -2239,8 +2239,8 @@ W: http://www.linux-usb.org
S: Supported S: Supported
USB UHCI DRIVER USB UHCI DRIVER
P: Johannes Erdfelt P: Alan Stern
M: johannes@erdfelt.com M: stern@rowland.harvard.edu
L: linux-usb-users@lists.sourceforge.net L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net
S: Maintained S: Maintained
......
...@@ -204,12 +204,23 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, ...@@ -204,12 +204,23 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
int *result_length, u8 cmd_result[]) int *result_length, u8 cmd_result[])
{ {
int result, actual_len, i; int result, actual_len, i;
u8 b[COMMAND_PACKET_SIZE + 4]; u8 *b;
u8 c[COMMAND_PACKET_SIZE + 4]; u8 *c;
b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
if (!b)
return -ENOMEM;
c = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
if (!c) {
kfree(b);
return -ENOMEM;
}
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
if ((result = down_interruptible(&dec->usb_sem))) { if ((result = down_interruptible(&dec->usb_sem))) {
kfree(b);
kfree(c);
printk("%s: Failed to down usb semaphore.\n", __FUNCTION__); printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
return result; return result;
} }
...@@ -230,22 +241,26 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, ...@@ -230,22 +241,26 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
} }
result = usb_bulk_msg(dec->udev, dec->command_pipe, b, result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
sizeof(b), &actual_len, HZ); COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
if (result) { if (result) {
printk("%s: command bulk message failed: error %d\n", printk("%s: command bulk message failed: error %d\n",
__FUNCTION__, result); __FUNCTION__, result);
up(&dec->usb_sem); up(&dec->usb_sem);
kfree(b);
kfree(c);
return result; return result;
} }
result = usb_bulk_msg(dec->udev, dec->result_pipe, c, result = usb_bulk_msg(dec->udev, dec->result_pipe, c,
sizeof(c), &actual_len, HZ); COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
if (result) { if (result) {
printk("%s: result bulk message failed: error %d\n", printk("%s: result bulk message failed: error %d\n",
__FUNCTION__, result); __FUNCTION__, result);
up(&dec->usb_sem); up(&dec->usb_sem);
kfree(b);
kfree(c);
return result; return result;
} else { } else {
if (debug) { if (debug) {
...@@ -262,6 +277,8 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, ...@@ -262,6 +277,8 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
up(&dec->usb_sem); up(&dec->usb_sem);
kfree(b);
kfree(c);
return 0; return 0;
} }
} }
......
...@@ -46,7 +46,6 @@ obj-$(CONFIG_USB_DC2XX) += image/ ...@@ -46,7 +46,6 @@ obj-$(CONFIG_USB_DC2XX) += image/
obj-$(CONFIG_USB_HPUSBSCSI) += image/ obj-$(CONFIG_USB_HPUSBSCSI) += image/
obj-$(CONFIG_USB_MDC800) += image/ obj-$(CONFIG_USB_MDC800) += image/
obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SCANNER) += image/
obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_SERIAL) += serial/
......
...@@ -399,6 +399,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -399,6 +399,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
{ {
struct acm *acm = tty->driver_data; struct acm *acm = tty->driver_data;
int stat;
if (!ACM_READY(acm)) if (!ACM_READY(acm))
return -EINVAL; return -EINVAL;
...@@ -418,8 +419,12 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c ...@@ -418,8 +419,12 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
acm->writeurb->transfer_buffer_length = count; acm->writeurb->transfer_buffer_length = count;
acm->writeurb->dev = acm->dev; acm->writeurb->dev = acm->dev;
if (usb_submit_urb(acm->writeurb, GFP_KERNEL)) /* GFP_KERNEL probably works if from_user */
stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
if (stat < 0) {
dbg("usb_submit_urb(write bulk) failed"); dbg("usb_submit_urb(write bulk) failed");
return stat;
}
return count; return count;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem # Makefile for USB Core files and filesystem
# #
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \ usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
config.o file.o buffer.o driverfs.o config.o file.o buffer.o driverfs.o
ifeq ($(CONFIG_PCI),y) ifeq ($(CONFIG_PCI),y)
......
...@@ -34,7 +34,10 @@ ...@@ -34,7 +34,10 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/uts.h> /* for UTS_SYSNAME */ #include <linux/uts.h> /* for UTS_SYSNAME */
#include <linux/pci.h> /* for hcd->pdev and dma addressing */ #include <linux/mm.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -1474,16 +1477,16 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs ...@@ -1474,16 +1477,16 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
if (hcd->controller->dma_mask) { if (hcd->controller->dma_mask) {
if (usb_pipecontrol (urb->pipe) if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
pci_unmap_single (hcd->pdev, urb->setup_dma, dma_unmap_single (hcd->controller, urb->setup_dma,
sizeof (struct usb_ctrlrequest), sizeof (struct usb_ctrlrequest),
PCI_DMA_TODEVICE); DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0 if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
pci_unmap_single (hcd->pdev, urb->transfer_dma, dma_unmap_single (hcd->controller, urb->transfer_dma,
urb->transfer_buffer_length, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? PCI_DMA_FROMDEVICE ? DMA_FROM_DEVICE
: PCI_DMA_TODEVICE); : DMA_TO_DEVICE);
} }
/* pass ownership to the completion handler */ /* pass ownership to the completion handler */
...@@ -1513,7 +1516,9 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -1513,7 +1516,9 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
return IRQ_NONE; return IRQ_NONE;
hcd->saw_irq = 1; hcd->saw_irq = 1;
hcd->driver->irq (hcd, r); if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE;
if (hcd->state != start && hcd->state == USB_STATE_HALT) if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd); usb_hc_died (hcd);
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -163,7 +163,7 @@ struct hc_driver { ...@@ -163,7 +163,7 @@ struct hc_driver {
const char *description; /* "ehci-hcd" etc */ const char *description; /* "ehci-hcd" etc */
/* irq handler */ /* irq handler */
void (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
int flags; int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
......
...@@ -179,7 +179,7 @@ static inline int ...@@ -179,7 +179,7 @@ static inline int
hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt) hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)
{ {
return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0), return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),
HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER, HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
devinfo, tt, 0, 0, HZ); devinfo, tt, 0, 0, HZ);
} }
......
/*
* debug.c - USB debug helper routines.
*
* I just want these out of the way where they aren't in your
* face, but so that you can still use them..
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
static void usb_show_endpoint(struct usb_host_endpoint *endpoint)
{
usb_show_endpoint_descriptor(&endpoint->desc);
}
static void usb_show_interface(struct usb_host_interface *altsetting)
{
int i;
usb_show_interface_descriptor(&altsetting->desc);
for (i = 0; i < altsetting->desc.bNumEndpoints; i++)
usb_show_endpoint(altsetting->endpoint + i);
}
static void usb_show_config(struct usb_host_config *config)
{
int i, j;
struct usb_interface *ifp;
usb_show_config_descriptor(&config->desc);
for (i = 0; i < config->desc.bNumInterfaces; i++) {
ifp = config->interface[i];
if (!ifp)
break;
printk("\n Interface: %d\n", i);
for (j = 0; j < ifp->num_altsetting; j++)
usb_show_interface(ifp->altsetting + j);
}
}
void usb_show_device(struct usb_device *dev)
{
int i;
usb_show_device_descriptor(&dev->descriptor);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
usb_show_config(dev->config + i);
}
/*
* Parse and show the different USB descriptors.
*/
void usb_show_device_descriptor(struct usb_device_descriptor *desc)
{
if (!desc)
{
printk("Invalid USB device descriptor (NULL POINTER)\n");
return;
}
printk(" Length = %2d%s\n", desc->bLength,
desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");
printk(" DescriptorType = %02x\n", desc->bDescriptorType);
printk(" USB version = %x.%02x\n",
desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
printk(" Vendor:Product = %04x:%04x\n",
desc->idVendor, desc->idProduct);
printk(" MaxPacketSize0 = %d\n", desc->bMaxPacketSize0);
printk(" NumConfigurations = %d\n", desc->bNumConfigurations);
printk(" Device version = %x.%02x\n",
desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
printk(" Device Class:SubClass:Protocol = %02x:%02x:%02x\n",
desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol);
switch (desc->bDeviceClass) {
case 0:
printk(" Per-interface classes\n");
break;
case USB_CLASS_AUDIO:
printk(" Audio device class\n");
break;
case USB_CLASS_COMM:
printk(" Communications class\n");
break;
case USB_CLASS_HID:
printk(" Human Interface Devices class\n");
break;
case USB_CLASS_PRINTER:
printk(" Printer device class\n");
break;
case USB_CLASS_MASS_STORAGE:
printk(" Mass Storage device class\n");
break;
case USB_CLASS_HUB:
printk(" Hub device class\n");
break;
case USB_CLASS_VENDOR_SPEC:
printk(" Vendor class\n");
break;
default:
printk(" Unknown class\n");
}
}
void usb_show_config_descriptor(struct usb_config_descriptor *desc)
{
printk("Configuration:\n");
printk(" bLength = %4d%s\n", desc->bLength,
desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)");
printk(" bDescriptorType = %02x\n", desc->bDescriptorType);
printk(" wTotalLength = %04x\n", desc->wTotalLength);
printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces);
printk(" bConfigurationValue = %02x\n", desc->bConfigurationValue);
printk(" iConfiguration = %02x\n", desc->iConfiguration);
printk(" bmAttributes = %02x\n", desc->bmAttributes);
printk(" bMaxPower = %4dmA\n", desc->bMaxPower * 2);
}
void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)
{
printk(" Alternate Setting: %2d\n", desc->bAlternateSetting);
printk(" bLength = %4d%s\n", desc->bLength,
desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");
printk(" bDescriptorType = %02x\n", desc->bDescriptorType);
printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber);
printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting);
printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints);
printk(" bInterface Class:SubClass:Protocol = %02x:%02x:%02x\n",
desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);
printk(" iInterface = %02x\n", desc->iInterface);
}
void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
{
char *LengthCommentString = (desc->bLength ==
USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength ==
USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)";
char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
printk(" Endpoint:\n");
printk(" bLength = %4d%s\n",
desc->bLength, LengthCommentString);
printk(" bDescriptorType = %02x\n", desc->bDescriptorType);
printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress,
(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL ? "i/o" :
(desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out");
printk(" bmAttributes = %02x (%s)\n", desc->bmAttributes,
EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]);
printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize);
printk(" bInterval = %02x\n", desc->bInterval);
/* Audio extensions to the endpoint descriptor */
if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) {
printk(" bRefresh = %02x\n", desc->bRefresh);
printk(" bSynchAddress = %02x\n", desc->bSynchAddress);
}
}
void usb_show_string(struct usb_device *dev, char *id, int index)
{
char *buf;
if (!index)
return;
if (!(buf = kmalloc(256, GFP_KERNEL)))
return;
if (usb_string(dev, index, buf, 256) > 0)
dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
kfree(buf);
}
void usb_dump_urb (struct urb *urb)
{
printk ("urb :%p\n", urb);
printk ("dev :%p\n", urb->dev);
printk ("pipe :%08X\n", urb->pipe);
printk ("status :%d\n", urb->status);
printk ("transfer_flags :%08X\n", urb->transfer_flags);
printk ("transfer_buffer :%p\n", urb->transfer_buffer);
printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
printk ("actual_length :%d\n", urb->actual_length);
printk ("setup_packet :%p\n", urb->setup_packet);
printk ("start_frame :%d\n", urb->start_frame);
printk ("number_of_packets :%d\n", urb->number_of_packets);
printk ("interval :%d\n", urb->interval);
printk ("error_count :%d\n", urb->error_count);
printk ("context :%p\n", urb->context);
printk ("complete :%p\n", urb->complete);
}
...@@ -984,6 +984,19 @@ int usb_set_address(struct usb_device *dev) ...@@ -984,6 +984,19 @@ int usb_set_address(struct usb_device *dev)
return retval; return retval;
} }
static inline void usb_show_string(struct usb_device *dev, char *id, int index)
{
char *buf;
if (!index)
return;
if (!(buf = kmalloc(256, GFP_KERNEL)))
return;
if (usb_string(dev, index, buf, 256) > 0)
dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
kfree(buf);
}
/* /*
* By the time we get here, we chose a new device address * By the time we get here, we chose a new device address
* and is in the default state. We need to identify the thing and * and is in the default state. We need to identify the thing and
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
*/ */
#define DEBUG 1 // #define DEBUG 1
// #define VERBOSE // #define VERBOSE
#include <linux/config.h> #include <linux/config.h>
...@@ -885,8 +885,11 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) ...@@ -885,8 +885,11 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
#ifndef DEV_CONFIG_CDC #ifndef DEV_CONFIG_CDC
if (result == 0) { if (result == 0) {
netif_carrier_on (dev->net); netif_carrier_on (dev->net);
if (netif_running (dev->net)) if (netif_running (dev->net)) {
spin_unlock (&dev->lock);
eth_start (dev, GFP_ATOMIC); eth_start (dev, GFP_ATOMIC);
spin_lock (&dev->lock);
}
} else { } else {
(void) usb_ep_disable (dev->in_ep); (void) usb_ep_disable (dev->in_ep);
dev->in_ep = 0; dev->in_ep = 0;
...@@ -1246,8 +1249,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -1246,8 +1249,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
#ifdef EP_STATUS_NUM #ifdef EP_STATUS_NUM
issue_start_status (dev); issue_start_status (dev);
#endif #endif
if (netif_running (dev->net)) if (netif_running (dev->net)) {
spin_unlock (&dev->lock);
eth_start (dev, GFP_ATOMIC); eth_start (dev, GFP_ATOMIC);
spin_lock (&dev->lock);
}
} else { } else {
netif_stop_queue (dev->net); netif_stop_queue (dev->net);
netif_carrier_off (dev->net); netif_carrier_off (dev->net);
...@@ -1414,16 +1420,14 @@ static int ...@@ -1414,16 +1420,14 @@ static int
rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int retval = 0; int retval = -ENOMEM;
size_t size; size_t size;
size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
if ((skb = alloc_skb (size, gfp_flags)) == 0) { if ((skb = alloc_skb (size, gfp_flags)) == 0) {
DEBUG (dev, "no rx skb\n"); DEBUG (dev, "no rx skb\n");
defer_kevent (dev, WORK_RX_MEMORY); goto enomem;
list_add (&req->list, &dev->rx_reqs);
return -ENOMEM;
} }
req->buf = skb->data; req->buf = skb->data;
...@@ -1433,11 +1437,14 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) ...@@ -1433,11 +1437,14 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
retval = usb_ep_queue (dev->out_ep, req, gfp_flags); retval = usb_ep_queue (dev->out_ep, req, gfp_flags);
if (retval == -ENOMEM) if (retval == -ENOMEM)
enomem:
defer_kevent (dev, WORK_RX_MEMORY); defer_kevent (dev, WORK_RX_MEMORY);
if (retval) { if (retval) {
DEBUG (dev, "rx submit --> %d\n", retval); DEBUG (dev, "rx submit --> %d\n", retval);
dev_kfree_skb_any (skb); dev_kfree_skb_any (skb);
spin_lock (&dev->lock);
list_add (&req->list, &dev->rx_reqs); list_add (&req->list, &dev->rx_reqs);
spin_unlock (&dev->lock);
} }
return retval; return retval;
} }
...@@ -1502,6 +1509,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) ...@@ -1502,6 +1509,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
dev_kfree_skb_any (skb); dev_kfree_skb_any (skb);
if (!netif_running (dev->net)) { if (!netif_running (dev->net)) {
clean: clean:
/* nobody reading rx_reqs, so no dev->lock */
list_add (&req->list, &dev->rx_reqs); list_add (&req->list, &dev->rx_reqs);
req = 0; req = 0;
} }
...@@ -1568,19 +1576,26 @@ static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags) ...@@ -1568,19 +1576,26 @@ static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags)
static void rx_fill (struct eth_dev *dev, int gfp_flags) static void rx_fill (struct eth_dev *dev, int gfp_flags)
{ {
struct usb_request *req; struct usb_request *req;
unsigned long flags;
clear_bit (WORK_RX_MEMORY, &dev->todo); clear_bit (WORK_RX_MEMORY, &dev->todo);
/* fill unused rxq slots with some skb */ /* fill unused rxq slots with some skb */
spin_lock_irqsave (&dev->lock, flags);
while (!list_empty (&dev->rx_reqs)) { while (!list_empty (&dev->rx_reqs)) {
req = container_of (dev->rx_reqs.next, req = container_of (dev->rx_reqs.next,
struct usb_request, list); struct usb_request, list);
list_del_init (&req->list); list_del_init (&req->list);
spin_unlock_irqrestore (&dev->lock, flags);
if (rx_submit (dev, req, gfp_flags) < 0) { if (rx_submit (dev, req, gfp_flags) < 0) {
defer_kevent (dev, WORK_RX_MEMORY); defer_kevent (dev, WORK_RX_MEMORY);
return; return;
} }
spin_lock_irqsave (&dev->lock, flags);
} }
spin_unlock_irqrestore (&dev->lock, flags);
} }
static void eth_work (void *_dev) static void eth_work (void *_dev)
...@@ -1616,7 +1631,9 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req) ...@@ -1616,7 +1631,9 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req)
} }
dev->stats.tx_packets++; dev->stats.tx_packets++;
spin_lock (&dev->lock);
list_add (&req->list, &dev->tx_reqs); list_add (&req->list, &dev->tx_reqs);
spin_unlock (&dev->lock);
dev_kfree_skb_any (skb); dev_kfree_skb_any (skb);
atomic_dec (&dev->tx_qlen); atomic_dec (&dev->tx_qlen);
...@@ -1630,11 +1647,14 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1630,11 +1647,14 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
int length = skb->len; int length = skb->len;
int retval; int retval;
struct usb_request *req = 0; struct usb_request *req = 0;
unsigned long flags;
spin_lock_irqsave (&dev->lock, flags);
req = container_of (dev->tx_reqs.next, struct usb_request, list); req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list); list_del (&req->list);
if (list_empty (&dev->tx_reqs)) if (list_empty (&dev->tx_reqs))
netif_stop_queue (net); netif_stop_queue (net);
spin_unlock_irqrestore (&dev->lock, flags);
/* no buffer copies needed, unless the network stack did it /* no buffer copies needed, unless the network stack did it
* or the hardware can't use skb buffers. * or the hardware can't use skb buffers.
...@@ -1675,9 +1695,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1675,9 +1695,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
if (retval) { if (retval) {
dev->stats.tx_dropped++; dev->stats.tx_dropped++;
dev_kfree_skb_any (skb); dev_kfree_skb_any (skb);
spin_lock_irqsave (&dev->lock, flags);
if (list_empty (&dev->tx_reqs)) if (list_empty (&dev->tx_reqs))
netif_start_queue (net); netif_start_queue (net);
list_add (&req->list, &dev->tx_reqs); list_add (&req->list, &dev->tx_reqs);
spin_unlock_irqrestore (&dev->lock, flags);
} }
return 0; return 0;
} }
......
/* /*
* file_storage.c -- File-backed USB Storage Gadget, for USB development * file_storage.c -- File-backed USB Storage Gadget, for USB development
* *
* Copyright (C) 2003 Alan Stern * Copyright (C) 2003, 2004 Alan Stern
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
#define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage" #define DRIVER_NAME "g_file_storage"
#define DRIVER_VERSION "14 January 2004" #define DRIVER_VERSION "26 January 2004"
static const char longname[] = DRIVER_DESC; static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME; static const char shortname[] = DRIVER_NAME;
...@@ -435,7 +435,7 @@ static const char EP_INTR_IN_NAME [] = "ep3-bulk"; ...@@ -435,7 +435,7 @@ static const char EP_INTR_IN_NAME [] = "ep3-bulk";
#define LDBG(lun,fmt,args...) \ #define LDBG(lun,fmt,args...) \
yprintk(lun , KERN_DEBUG , fmt , ## args) yprintk(lun , KERN_DEBUG , fmt , ## args)
#define MDBG(fmt,args...) \ #define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt, ## args) printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else #else
#define DBG(fsg,fmt,args...) \ #define DBG(fsg,fmt,args...) \
do { } while (0) do { } while (0)
...@@ -473,7 +473,7 @@ static const char EP_INTR_IN_NAME [] = "ep3-bulk"; ...@@ -473,7 +473,7 @@ static const char EP_INTR_IN_NAME [] = "ep3-bulk";
yprintk(lun , KERN_INFO , fmt , ## args) yprintk(lun , KERN_INFO , fmt , ## args)
#define MINFO(fmt,args...) \ #define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt, ## args) printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -848,6 +848,7 @@ struct fsg_dev { ...@@ -848,6 +848,7 @@ struct fsg_dev {
unsigned int nluns; unsigned int nluns;
struct lun *luns; struct lun *luns;
struct lun *curlun; struct lun *curlun;
struct completion lun_released;
}; };
typedef void (*fsg_routine_t)(struct fsg_dev *); typedef void (*fsg_routine_t)(struct fsg_dev *);
...@@ -3771,6 +3772,13 @@ static DEVICE_ATTR(file, 0444, show_file, NULL); ...@@ -3771,6 +3772,13 @@ static DEVICE_ATTR(file, 0444, show_file, NULL);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void lun_release(struct device *dev)
{
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
complete(&fsg->lun_released);
}
static void fsg_unbind(struct usb_gadget *gadget) static void fsg_unbind(struct usb_gadget *gadget)
{ {
struct fsg_dev *fsg = get_gadget_data(gadget); struct fsg_dev *fsg = get_gadget_data(gadget);
...@@ -3782,12 +3790,14 @@ static void fsg_unbind(struct usb_gadget *gadget) ...@@ -3782,12 +3790,14 @@ static void fsg_unbind(struct usb_gadget *gadget)
clear_bit(REGISTERED, &fsg->atomic_bitflags); clear_bit(REGISTERED, &fsg->atomic_bitflags);
/* Unregister the sysfs attribute files and the LUNs */ /* Unregister the sysfs attribute files and the LUNs */
init_completion(&fsg->lun_released);
for (i = 0; i < fsg->nluns; ++i) { for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i]; curlun = &fsg->luns[i];
if (curlun->registered) { if (curlun->registered) {
device_remove_file(&curlun->dev, &dev_attr_ro); device_remove_file(&curlun->dev, &dev_attr_ro);
device_remove_file(&curlun->dev, &dev_attr_file); device_remove_file(&curlun->dev, &dev_attr_file);
device_unregister_wait(&curlun->dev); device_unregister(&curlun->dev);
wait_for_completion(&fsg->lun_released);
curlun->registered = 0; curlun->registered = 0;
} }
} }
...@@ -4140,6 +4150,7 @@ static int __init fsg_init(void) ...@@ -4140,6 +4150,7 @@ static int __init fsg_init(void)
INFO(fsg, "failed to register LUN%d: %d\n", i, rc); INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
else { else {
curlun->registered = 1; curlun->registered = 1;
curlun->dev.release = lun_release;
device_create_file(&curlun->dev, &dev_attr_ro); device_create_file(&curlun->dev, &dev_attr_ro);
device_create_file(&curlun->dev, &dev_attr_file); device_create_file(&curlun->dev, &dev_attr_file);
} }
......
...@@ -534,7 +534,10 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) ...@@ -534,7 +534,10 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req)
} }
/* write just one packet at a time */ /* write just one packet at a time */
count = min (ep->ep.maxpacket, total); count = ep->ep.maxpacket;
if (count > total) /* min() cannot be used on a bitfield */
count = total;
VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
ep->ep.name, count, ep->ep.name, count,
(count != ep->ep.maxpacket) ? " (short)" : "", (count != ep->ep.maxpacket) ? " (short)" : "",
...@@ -2197,7 +2200,8 @@ static void handle_ep_small (struct net2280_ep *ep) ...@@ -2197,7 +2200,8 @@ static void handle_ep_small (struct net2280_ep *ep)
unsigned len; unsigned len;
len = req->req.length - req->req.actual; len = req->req.length - req->req.actual;
len = min (ep->ep.maxpacket, len); if (len > ep->ep.maxpacket)
len = ep->ep.maxpacket;
req->req.actual += len; req->req.actual += len;
/* if we wrote it all, we're usually done */ /* if we wrote it all, we're usually done */
......
/* /*
* linux/drivers/usb/gadget/pxa2xx_udc.c * linux/drivers/usb/gadget/pxa2xx_udc.c
* Intel PXA2xx on-chip full speed USB device controllers * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
* *
* Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
* Copyright (C) 2003 Robert Schwebel, Pengutronix * Copyright (C) 2003 Robert Schwebel, Pengutronix
...@@ -59,27 +59,26 @@ ...@@ -59,27 +59,26 @@
#include <asm/arch/udc.h> #include <asm/arch/udc.h>
#include "pxa2xx_udc.h"
/* /*
* This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
* series processors. The UDC for the IXP 4xx series is very similar. * series processors. The UDC for the IXP 4xx series is very similar.
* There are fifteen endpoints, in addition to ep0.
* *
* Such controller drivers work with a gadget driver. The gadget driver * Such controller drivers work with a gadget driver. The gadget driver
* returns descriptors, implements configuration and data protocols used * returns descriptors, implements configuration and data protocols used
* by the host to interact with this device, and allocates endpoints to * by the host to interact with this device, and allocates endpoints to
* the different protocol interfaces. The controller driver virtualizes * the different protocol interfaces. The controller driver virtualizes
* usb hardware so that the gadget drivers will be more portable. * usb hardware so that the gadget drivers will be more portable.
* *
* This UDC hardware wants to implement a bit too much USB protocol, so * This UDC hardware wants to implement a bit too much USB protocol, so
* it constrains the sorts of USB configuration change events that work. * it constrains the sorts of USB configuration change events that work.
* The errata for these chips are misleading; some "fixed" bugs from * The errata for these chips are misleading; some "fixed" bugs from
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there. * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*/ */
#define DRIVER_VERSION "7-Nov-2003" #define DRIVER_VERSION "14-Dec-2003"
#define DRIVER_DESC "PXA 2xx USB Device Controller driver" #define DRIVER_DESC "PXA 2xx USB Device Controller driver"
static const char driver_name [] = "pxa2xx_udc"; static const char driver_name [] = "pxa2xx_udc";
...@@ -95,6 +94,19 @@ static const char ep0name [] = "ep0"; ...@@ -95,6 +94,19 @@ static const char ep0name [] = "ep0";
#define UDC_PROC_FILE #define UDC_PROC_FILE
#endif #endif
#ifdef CONFIG_ARCH_IXP425
#undef USE_DMA
/* cpu-specific register addresses are compiled in to this code */
#ifdef CONFIG_ARCH_PXA
#error "Can't configure both IXP and PXA"
#endif
#endif
#include "pxa2xx_udc.h"
#ifdef CONFIG_EMBEDDED #ifdef CONFIG_EMBEDDED
/* few strings, and little code to use them */ /* few strings, and little code to use them */
#undef DEBUG #undef DEBUG
...@@ -215,7 +227,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, ...@@ -215,7 +227,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
if (!_ep || !desc || ep->desc || _ep->name == ep0name if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT || desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress || ep->bEndpointAddress != desc->bEndpointAddress
|| ep->ep.maxpacket < desc->wMaxPacketSize) { || ep->fifo_size < le16_to_cpu
(desc->wMaxPacketSize)) {
DMSG("%s, bad ep or descriptor\n", __FUNCTION__); DMSG("%s, bad ep or descriptor\n", __FUNCTION__);
return -EINVAL; return -EINVAL;
} }
...@@ -230,7 +243,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, ...@@ -230,7 +243,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
/* hardware _could_ do smaller, but driver doesn't */ /* hardware _could_ do smaller, but driver doesn't */
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& desc->wMaxPacketSize != BULK_FIFO_SIZE) && le16_to_cpu (desc->wMaxPacketSize)
!= BULK_FIFO_SIZE)
|| !desc->wMaxPacketSize) { || !desc->wMaxPacketSize) {
DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
return -ERANGE; return -ERANGE;
...@@ -246,6 +260,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, ...@@ -246,6 +260,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
ep->dma = -1; ep->dma = -1;
ep->stopped = 0; ep->stopped = 0;
ep->pio_irqs = ep->dma_irqs = 0; ep->pio_irqs = ep->dma_irqs = 0;
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
/* flush fifo (mostly for OUT buffers) */ /* flush fifo (mostly for OUT buffers) */
pxa2xx_ep_fifo_flush (_ep); pxa2xx_ep_fifo_flush (_ep);
...@@ -254,18 +269,18 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, ...@@ -254,18 +269,18 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
#ifdef USE_DMA #ifdef USE_DMA
/* for (some) bulk and ISO endpoints, try to get a DMA channel and /* for (some) bulk and ISO endpoints, try to get a DMA channel and
* bind it to the endpoint. otherwise use PIO. * bind it to the endpoint. otherwise use PIO.
*/ */
switch (ep->bmAttributes) { switch (ep->bmAttributes) {
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
if (desc->wMaxPacketSize % 32) if (le16_to_cpu(desc->wMaxPacketSize) % 32)
break; break;
// fall through // fall through
case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_BULK:
if (!use_dma || !ep->reg_drcmr) if (!use_dma || !ep->reg_drcmr)
break; break;
ep->dma = pxa_request_dma ((char *)_ep->name, ep->dma = pxa_request_dma ((char *)_ep->name,
(desc->wMaxPacketSize > 64) (le16_to_cpu (desc->wMaxPacketSize) > 64)
? DMA_PRIO_MEDIUM /* some iso */ ? DMA_PRIO_MEDIUM /* some iso */
: DMA_PRIO_LOW, : DMA_PRIO_LOW,
dma_nodesc_handler, ep); dma_nodesc_handler, ep);
...@@ -437,7 +452,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) ...@@ -437,7 +452,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
{ {
unsigned max; unsigned max;
max = ep->desc->wMaxPacketSize; max = le16_to_cpu(ep->desc->wMaxPacketSize);
do { do {
unsigned count; unsigned count;
int is_last, is_short; int is_last, is_short;
...@@ -454,13 +469,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) ...@@ -454,13 +469,7 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
else else
is_last = 1; is_last = 1;
/* interrupt/iso maxpacket may not fill the fifo */ /* interrupt/iso maxpacket may not fill the fifo */
is_short = unlikely (max < ep->ep.maxpacket); is_short = unlikely (max < ep->fifo_size);
/* FIXME ep.maxpacket should be the current size,
* modified (for periodic endpoints) when the
* ep is enabled. do that, re-init as needed,
* and change maxpacket refs accordingly.
*/
} }
DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n", DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",
...@@ -598,7 +607,7 @@ read_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) ...@@ -598,7 +607,7 @@ read_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
req->req.actual += min (count, bufferspace); req->req.actual += min (count, bufferspace);
} else /* zlp */ } else /* zlp */
count = 0; count = 0;
is_short = (count < ep->desc->wMaxPacketSize); is_short = (count < ep->ep.maxpacket);
DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
ep->ep.name, udccs, count, ep->ep.name, udccs, count,
is_short ? "/S" : "", is_short ? "/S" : "",
...@@ -897,13 +906,14 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) ...@@ -897,13 +906,14 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
* we can report per-packet status. that also helps with dma. * we can report per-packet status. that also helps with dma.
*/ */
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
&& req->req.length > ep->desc->wMaxPacketSize)) && req->req.length > le16_to_cpu
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE; return -EMSGSIZE;
#ifdef USE_DMA #ifdef USE_DMA
// FIXME caller may already have done the dma mapping // FIXME caller may already have done the dma mapping
if (ep->dma >= 0) { if (ep->dma >= 0) {
_req->dma = dma_map_single(&dev->dev.dev, _req->dma = dma_map_single(dev->dev,
_req->buf, _req->length, _req->buf, _req->length,
((ep->bEndpointAddress & USB_DIR_IN) != 0) ((ep->bEndpointAddress & USB_DIR_IN) != 0)
? DMA_TO_DEVICE ? DMA_TO_DEVICE
...@@ -1017,11 +1027,21 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ...@@ -1017,11 +1027,21 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
unsigned long flags; unsigned long flags;
ep = container_of(_ep, struct pxa2xx_ep, ep); ep = container_of(_ep, struct pxa2xx_ep, ep);
req = container_of(_req, struct pxa2xx_request, req); if (!_ep || ep->ep.name == ep0name)
if (!_ep || !_req || ep->ep.name == ep0name)
return -EINVAL; return -EINVAL;
local_irq_save(flags); local_irq_save(flags);
/* make sure it's actually queued on this endpoint */
list_for_each_entry (req, &ep->queue, queue) {
if (&req->req == _req)
break;
}
if (&req->req != _req) {
local_irq_restore(flags);
return -EINVAL;
}
#ifdef USE_DMA #ifdef USE_DMA
if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) { if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
cancel_dma(ep); cancel_dma(ep);
...@@ -1034,13 +1054,10 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ...@@ -1034,13 +1054,10 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
} }
} else } else
#endif #endif
if (!list_empty(&req->queue))
done(ep, req, -ECONNRESET); done(ep, req, -ECONNRESET);
else
req = 0;
local_irq_restore(flags);
return req ? 0 : -EOPNOTSUPP; local_irq_restore(flags);
return 0;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1386,8 +1403,10 @@ static void udc_disable(struct pxa2xx_udc *dev) ...@@ -1386,8 +1403,10 @@ static void udc_disable(struct pxa2xx_udc *dev)
udc_clear_mask_UDCCR(UDCCR_UDE); udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Disable clock for USB device */ /* Disable clock for USB device */
CKEN &= ~CKEN11_USB; CKEN &= ~CKEN11_USB;
#endif
ep0_idle (dev); ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN; dev->gadget.speed = USB_SPEED_UNKNOWN;
...@@ -1430,8 +1449,10 @@ static void udc_enable (struct pxa2xx_udc *dev) ...@@ -1430,8 +1449,10 @@ static void udc_enable (struct pxa2xx_udc *dev)
{ {
udc_clear_mask_UDCCR(UDCCR_UDE); udc_clear_mask_UDCCR(UDCCR_UDE);
#ifdef CONFIG_ARCH_PXA
/* Enable clock for USB device */ /* Enable clock for USB device */
CKEN |= CKEN11_USB; CKEN |= CKEN11_USB;
#endif
/* try to clear these bits before we enable the udc */ /* try to clear these bits before we enable the udc */
udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR); udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
...@@ -1590,9 +1611,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ...@@ -1590,9 +1611,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
local_irq_disable(); local_irq_disable();
udc_disable(dev); udc_disable(dev);
stop_activity(dev, driver); stop_activity(dev, driver);
local_irq_enable();
driver->unbind(&dev->gadget); driver->unbind(&dev->gadget);
dev->driver = 0; dev->driver = 0;
local_irq_enable();
device_del (&dev->gadget.dev); device_del (&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_function); device_remove_file(dev->dev, &dev_attr_function);
...@@ -1776,7 +1798,6 @@ static void handle_ep0 (struct pxa2xx_udc *dev) ...@@ -1776,7 +1798,6 @@ static void handle_ep0 (struct pxa2xx_udc *dev)
* else use AREN (later) not SA|OPR * else use AREN (later) not SA|OPR
* USIR0_IR0 acts edge sensitive * USIR0_IR0 acts edge sensitive
*/ */
dev->req_pending = 0;
} }
break; break;
/* ... and here, even more ... */ /* ... and here, even more ... */
...@@ -1853,6 +1874,7 @@ static void handle_ep0 (struct pxa2xx_udc *dev) ...@@ -1853,6 +1874,7 @@ static void handle_ep0 (struct pxa2xx_udc *dev)
/* pxa210/250 erratum 131 for B0/B1 says RNE lies. /* pxa210/250 erratum 131 for B0/B1 says RNE lies.
* still observed on a pxa255 a0. * still observed on a pxa255 a0.
*/ */
DBG(DBG_VERBOSE, "e131\n");
nuke(ep, -EPROTO); nuke(ep, -EPROTO);
/* read SETUP data, but don't trust it too much */ /* read SETUP data, but don't trust it too much */
...@@ -2043,7 +2065,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) ...@@ -2043,7 +2065,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
stop_activity (dev, dev->driver); stop_activity (dev, dev->driver);
} else { } else {
dev_info(&dev->gadget.dev, "USB reset\n"); INFO("USB reset\n");
dev->gadget.speed = USB_SPEED_FULL; dev->gadget.speed = USB_SPEED_FULL;
LED_CONNECTED_ON; LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats); memset(&dev->stats, 0, sizeof dev->stats);
...@@ -2133,11 +2155,12 @@ static struct pxa2xx_udc memory = { ...@@ -2133,11 +2155,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 1, .bEndpointAddress = USB_DIR_IN | 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1, .reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1, .reg_uddr = &UDDR1,
.reg_drcmr = &DRCMR25, drcmr (25)
}, },
.ep[2] = { .ep[2] = {
.ep = { .ep = {
...@@ -2146,12 +2169,13 @@ static struct pxa2xx_udc memory = { ...@@ -2146,12 +2169,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 2, .bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS2, .reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2, .reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2, .reg_uddr = &UDDR2,
.reg_drcmr = &DRCMR26, drcmr (26)
}, },
#ifndef CONFIG_USB_PXA2XX_SMALL #ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = { .ep[3] = {
...@@ -2161,11 +2185,12 @@ static struct pxa2xx_udc memory = { ...@@ -2161,11 +2185,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 3, .bEndpointAddress = USB_DIR_IN | 3,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3, .reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3, .reg_uddr = &UDDR3,
.reg_drcmr = &DRCMR27, drcmr (27)
}, },
.ep[4] = { .ep[4] = {
.ep = { .ep = {
...@@ -2174,12 +2199,13 @@ static struct pxa2xx_udc memory = { ...@@ -2174,12 +2199,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 4, .bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS4, .reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4, .reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4, .reg_uddr = &UDDR4,
.reg_drcmr = &DRCMR28, drcmr (28)
}, },
.ep[5] = { .ep[5] = {
.ep = { .ep = {
...@@ -2188,6 +2214,7 @@ static struct pxa2xx_udc memory = { ...@@ -2188,6 +2214,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE, .maxpacket = INT_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 5, .bEndpointAddress = USB_DIR_IN | 5,
.bmAttributes = USB_ENDPOINT_XFER_INT, .bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS5, .reg_udccs = &UDCCS5,
...@@ -2202,11 +2229,12 @@ static struct pxa2xx_udc memory = { ...@@ -2202,11 +2229,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 6, .bEndpointAddress = USB_DIR_IN | 6,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6, .reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6, .reg_uddr = &UDDR6,
.reg_drcmr = &DRCMR30, drcmr (30)
}, },
.ep[7] = { .ep[7] = {
.ep = { .ep = {
...@@ -2215,12 +2243,13 @@ static struct pxa2xx_udc memory = { ...@@ -2215,12 +2243,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 7, .bEndpointAddress = 7,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS7, .reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7, .reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7, .reg_uddr = &UDDR7,
.reg_drcmr = &DRCMR31, drcmr (31)
}, },
.ep[8] = { .ep[8] = {
.ep = { .ep = {
...@@ -2229,11 +2258,12 @@ static struct pxa2xx_udc memory = { ...@@ -2229,11 +2258,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 8, .bEndpointAddress = USB_DIR_IN | 8,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8, .reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8, .reg_uddr = &UDDR8,
.reg_drcmr = &DRCMR32, drcmr (32)
}, },
.ep[9] = { .ep[9] = {
.ep = { .ep = {
...@@ -2242,12 +2272,13 @@ static struct pxa2xx_udc memory = { ...@@ -2242,12 +2272,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 9, .bEndpointAddress = 9,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS9, .reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9, .reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9, .reg_uddr = &UDDR9,
.reg_drcmr = &DRCMR33, drcmr (33)
}, },
.ep[10] = { .ep[10] = {
.ep = { .ep = {
...@@ -2256,6 +2287,7 @@ static struct pxa2xx_udc memory = { ...@@ -2256,6 +2287,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE, .maxpacket = INT_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 10, .bEndpointAddress = USB_DIR_IN | 10,
.bmAttributes = USB_ENDPOINT_XFER_INT, .bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS10, .reg_udccs = &UDCCS10,
...@@ -2270,11 +2302,12 @@ static struct pxa2xx_udc memory = { ...@@ -2270,11 +2302,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 11, .bEndpointAddress = USB_DIR_IN | 11,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11, .reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11, .reg_uddr = &UDDR11,
.reg_drcmr = &DRCMR35, drcmr (35)
}, },
.ep[12] = { .ep[12] = {
.ep = { .ep = {
...@@ -2283,12 +2316,13 @@ static struct pxa2xx_udc memory = { ...@@ -2283,12 +2316,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = BULK_FIFO_SIZE, .maxpacket = BULK_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 12, .bEndpointAddress = 12,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS12, .reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12, .reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12, .reg_uddr = &UDDR12,
.reg_drcmr = &DRCMR36, drcmr (36)
}, },
.ep[13] = { .ep[13] = {
.ep = { .ep = {
...@@ -2297,11 +2331,12 @@ static struct pxa2xx_udc memory = { ...@@ -2297,11 +2331,12 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 13, .bEndpointAddress = USB_DIR_IN | 13,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13, .reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13, .reg_uddr = &UDDR13,
.reg_drcmr = &DRCMR37, drcmr (37)
}, },
.ep[14] = { .ep[14] = {
.ep = { .ep = {
...@@ -2310,12 +2345,13 @@ static struct pxa2xx_udc memory = { ...@@ -2310,12 +2345,13 @@ static struct pxa2xx_udc memory = {
.maxpacket = ISO_FIFO_SIZE, .maxpacket = ISO_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 14, .bEndpointAddress = 14,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS14, .reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14, .reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14, .reg_uddr = &UDDR14,
.reg_drcmr = &DRCMR38, drcmr (38)
}, },
.ep[15] = { .ep[15] = {
.ep = { .ep = {
...@@ -2324,6 +2360,7 @@ static struct pxa2xx_udc memory = { ...@@ -2324,6 +2360,7 @@ static struct pxa2xx_udc memory = {
.maxpacket = INT_FIFO_SIZE, .maxpacket = INT_FIFO_SIZE,
}, },
.dev = &memory, .dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 15, .bEndpointAddress = USB_DIR_IN | 15,
.bmAttributes = USB_ENDPOINT_XFER_INT, .bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS15, .reg_udccs = &UDCCS15,
...@@ -2333,8 +2370,15 @@ static struct pxa2xx_udc memory = { ...@@ -2333,8 +2370,15 @@ static struct pxa2xx_udc memory = {
}; };
#define CP15R0_VENDOR_MASK 0xffffe000 #define CP15R0_VENDOR_MASK 0xffffe000
#if defined(CONFIG_ARCH_PXA)
#define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */ #define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */
#elif defined(CONFIG_ARCH_IXP425)
#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp425 */
#endif
#define CP15R0_PROD_MASK 0x000003f0 #define CP15R0_PROD_MASK 0x000003f0
#define PXA25x 0x00000100 /* and PXA26x */ #define PXA25x 0x00000100 /* and PXA26x */
#define PXA210 0x00000120 #define PXA210 0x00000120
...@@ -2355,6 +2399,7 @@ static struct pxa2xx_udc memory = { ...@@ -2355,6 +2399,7 @@ static struct pxa2xx_udc memory = {
#define PXA210_B2 0x00000124 #define PXA210_B2 0x00000124
#define PXA210_B1 0x00000123 #define PXA210_B1 0x00000123
#define PXA210_B0 0x00000122 #define PXA210_B0 0x00000122
#define IXP425_A0 0x000001c1
/* /*
* probe - binds to the platform device * probe - binds to the platform device
...@@ -2374,6 +2419,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) ...@@ -2374,6 +2419,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
/* trigger chiprev-specific logic */ /* trigger chiprev-specific logic */
switch (chiprev & CP15R0_PRODREV_MASK) { switch (chiprev & CP15R0_PRODREV_MASK) {
#if defined(CONFIG_ARCH_PXA)
case PXA255_A0: case PXA255_A0:
dev->has_cfr = 1; dev->has_cfr = 1;
break; break;
...@@ -2388,6 +2434,11 @@ static int __init pxa2xx_udc_probe(struct device *_dev) ...@@ -2388,6 +2434,11 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
/* fall through */ /* fall through */
case PXA250_C0: case PXA210_C0: case PXA250_C0: case PXA210_C0:
break; break;
#elif defined(CONFIG_ARCH_IXP425)
case IXP425_A0:
out_dma = 0;
break;
#endif
default: default:
out_dma = 0; out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n", printk(KERN_ERR "%s: unrecognized processor: %08x\n",
...@@ -2443,6 +2494,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) ...@@ -2443,6 +2494,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
} }
dev->got_irq = 1; dev->got_irq = 1;
#ifdef CONFIG_ARCH_LUBBOCK
if (machine_is_lubbock()) { if (machine_is_lubbock()) {
disable_irq(LUBBOCK_USB_DISC_IRQ); disable_irq(LUBBOCK_USB_DISC_IRQ);
retval = request_irq(LUBBOCK_USB_DISC_IRQ, retval = request_irq(LUBBOCK_USB_DISC_IRQ,
...@@ -2457,7 +2509,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) ...@@ -2457,7 +2509,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
} }
dev->got_disc = 1; dev->got_disc = 1;
} }
#endif
create_proc_files(); create_proc_files();
return 0; return 0;
......
...@@ -52,14 +52,15 @@ struct pxa2xx_ep { ...@@ -52,14 +52,15 @@ struct pxa2xx_ep {
struct list_head queue; struct list_head queue;
unsigned long pio_irqs; unsigned long pio_irqs;
unsigned long dma_irqs; unsigned long dma_irqs;
int dma; short dma;
unsigned short fifo_size;
u8 bEndpointAddress; u8 bEndpointAddress;
u8 bmAttributes; u8 bmAttributes;
unsigned stopped : 1; unsigned stopped : 1;
unsigned dma_fixup : 1; unsigned dma_fixup : 1;
/* UDCCS = UDC Control/Status for this EP /* UDCCS = UDC Control/Status for this EP
* UBCR = UDC Byte Count Remaining (contents of OUT fifo) * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
* UDDR = UDC Endpoint Data Register (the fifo) * UDDR = UDC Endpoint Data Register (the fifo)
...@@ -68,7 +69,12 @@ struct pxa2xx_ep { ...@@ -68,7 +69,12 @@ struct pxa2xx_ep {
volatile u32 *reg_udccs; volatile u32 *reg_udccs;
volatile u32 *reg_ubcr; volatile u32 *reg_ubcr;
volatile u32 *reg_uddr; volatile u32 *reg_uddr;
#ifdef USE_DMA
volatile u32 *reg_drcmr; volatile u32 *reg_drcmr;
#define drcmr(n) .reg_drcmr = & DRCMR ## n ,
#else
#define drcmr(n)
#endif
}; };
struct pxa2xx_request { struct pxa2xx_request {
...@@ -76,7 +82,7 @@ struct pxa2xx_request { ...@@ -76,7 +82,7 @@ struct pxa2xx_request {
struct list_head queue; struct list_head queue;
}; };
enum ep0_state { enum ep0_state {
EP0_IDLE, EP0_IDLE,
EP0_IN_DATA_PHASE, EP0_IN_DATA_PHASE,
EP0_OUT_DATA_PHASE, EP0_OUT_DATA_PHASE,
...@@ -181,14 +187,14 @@ static inline void make_usb_disappear(void) ...@@ -181,14 +187,14 @@ static inline void make_usb_disappear(void)
{ {
if (!the_controller->mach->udc_command) if (!the_controller->mach->udc_command)
return; return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
} }
static inline void let_usb_appear(void) static inline void let_usb_appear(void)
{ {
if (!the_controller->mach->udc_command) if (!the_controller->mach->udc_command)
return; return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -305,7 +311,7 @@ dump_state(struct pxa2xx_udc *dev) ...@@ -305,7 +311,7 @@ dump_state(struct pxa2xx_udc *dev)
#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) #define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
#endif /* __LINUX_USB_GADGET_PXA2XX_H */ #endif /* __LINUX_USB_GADGET_PXA2XX_H */
...@@ -680,7 +680,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -680,7 +680,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status; u32 status;
...@@ -690,6 +690,12 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -690,6 +690,12 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
status = readl (&ehci->regs->status); status = readl (&ehci->regs->status);
/* shared irq */
if (status == 0) {
spin_unlock (&ehci->lock);
return IRQ_NONE;
}
/* e.g. cardbus physical eject */ /* e.g. cardbus physical eject */
if (status == ~(u32) 0) { if (status == ~(u32) 0) {
ehci_dbg (ehci, "device removed\n"); ehci_dbg (ehci, "device removed\n");
...@@ -743,6 +749,7 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -743,6 +749,7 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
ehci_work (ehci, regs); ehci_work (ehci, regs);
done: done:
spin_unlock (&ehci->lock); spin_unlock (&ehci->lock);
return IRQ_HANDLED;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -545,7 +545,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -545,7 +545,7 @@ static int hc_start (struct ohci_hcd *ohci)
/* an interrupt happens */ /* an interrupt happens */
static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs *regs = ohci->regs; struct ohci_regs *regs = ohci->regs;
...@@ -560,11 +560,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -560,11 +560,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) { } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
disable (ohci); disable (ohci);
ohci_dbg (ohci, "device removed!\n"); ohci_dbg (ohci, "device removed!\n");
return; return IRQ_HANDLED;
/* interrupt for some other device? */ /* interrupt for some other device? */
} else if ((ints &= readl (&regs->intrenable)) == 0) { } else if ((ints &= readl (&regs->intrenable)) == 0) {
return; return IRQ_NONE;
} }
if (ints & OHCI_INTR_UE) { if (ints & OHCI_INTR_UE) {
...@@ -604,6 +604,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -604,6 +604,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
// flush those pci writes // flush those pci writes
(void) readl (&ohci->regs->control); (void) readl (&ohci->regs->control);
} }
return IRQ_HANDLED;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -134,7 +134,7 @@ static int omap_ohci_clock_power(int on) ...@@ -134,7 +134,7 @@ static int omap_ohci_clock_power(int on)
writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_REQ, writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_REQ,
ULPD_SOFT_REQ_REG); ULPD_SOFT_REQ_REG);
outl(inl(ULPD_STATUS_REQ_REG) | USB_HOST_DPLL_REQ, writel(readl(ULPD_STATUS_REQ_REG) | USB_HOST_DPLL_REQ,
ULPD_STATUS_REQ_REG); ULPD_STATUS_REQ_REG);
} }
...@@ -248,7 +248,7 @@ static int omap_1610_usb_init(int mode) ...@@ -248,7 +248,7 @@ static int omap_1610_usb_init(int mode)
val |= (1 << 2); /* Disable pulldown on integrated transceiver DM */ val |= (1 << 2); /* Disable pulldown on integrated transceiver DM */
val |= (1 << 1); /* Disable pulldown on integraded transceiver DP */ val |= (1 << 1); /* Disable pulldown on integraded transceiver DP */
outl(val, USB_TRANSCEIVER_CTRL); writel(val, USB_TRANSCEIVER_CTRL);
/* Set the USB0_TRX_MODE */ /* Set the USB0_TRX_MODE */
val = 0; val = 0;
...@@ -256,7 +256,7 @@ static int omap_1610_usb_init(int mode) ...@@ -256,7 +256,7 @@ static int omap_1610_usb_init(int mode)
val &= ~DEV_IDLE_EN; val &= ~DEV_IDLE_EN;
val &= ~(7 << 16); /* Clear USB0_TRX_MODE */ val &= ~(7 << 16); /* Clear USB0_TRX_MODE */
val |= (3 << 16); /* 0 or 3, 6-wire DAT/SE0, TRM p 15-159 */ val |= (3 << 16); /* 0 or 3, 6-wire DAT/SE0, TRM p 15-159 */
outl(val, OTG_SYSCON_1); writel(val, OTG_SYSCON_1);
/* /*
* Control via OTG, see TRM p 15-163 * Control via OTG, see TRM p 15-163
...@@ -275,10 +275,10 @@ static int omap_1610_usb_init(int mode) ...@@ -275,10 +275,10 @@ static int omap_1610_usb_init(int mode)
val |= (4 << 16); /* Must be 4 */ val |= (4 << 16); /* Must be 4 */
val |= USBX_SYNCHRO; /* Must be set */ val |= USBX_SYNCHRO; /* Must be set */
val |= SRP_VBUS; val |= SRP_VBUS;
outl(val, OTG_SYSCON_2); writel(val, OTG_SYSCON_2);
/* Enable OTG idle */ /* Enable OTG idle */
//outl(inl(OTG_SYSCON_1) | OTG_IDLE_EN, OTG_SYSCON_1); //writel(readl(OTG_SYSCON_1) | OTG_IDLE_EN, OTG_SYSCON_1);
return 0; return 0;
} }
...@@ -631,7 +631,7 @@ static struct omap_dev ohci_hcd_omap_device = { ...@@ -631,7 +631,7 @@ static struct omap_dev ohci_hcd_omap_device = {
.end = OMAP_OHCI_BASE + OMAP_OHCI_SIZE, .end = OMAP_OHCI_BASE + OMAP_OHCI_SIZE,
}, },
.irq = { .irq = {
INT_OHCI, INT_USB_HHC_1,
}, },
}; };
......
...@@ -254,8 +254,6 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev) ...@@ -254,8 +254,6 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
hcd_buffer_destroy (hcd); hcd_buffer_destroy (hcd);
usb_deregister_bus (&hcd->self); usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1)
err ("%s: %s, count != 1", __FUNCTION__, hcd->self.bus_name);
base = hcd->regs; base = hcd->regs;
hcd->driver->hcd_free (hcd); hcd->driver->hcd_free (hcd);
......
/* /*
* Universal Host Controller Interface driver for USB. * Universal Host Controller Interface driver for USB.
* *
* Maintainer: Johannes Erdfelt <johannes@erdfelt.com> * Maintainer: Alan Stern <stern@rowland.harvard.edu>
* *
* (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
...@@ -1909,7 +1909,7 @@ static void uhci_remove_pending_qhs(struct uhci_hcd *uhci) ...@@ -1909,7 +1909,7 @@ static void uhci_remove_pending_qhs(struct uhci_hcd *uhci)
spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
} }
static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
...@@ -1922,7 +1922,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1922,7 +1922,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
*/ */
status = inw(io_addr + USBSTS); status = inw(io_addr + USBSTS);
if (!status) /* shared interrupt, not mine */ if (!status) /* shared interrupt, not mine */
return; return IRQ_NONE;
outw(status, io_addr + USBSTS); /* Clear it */ outw(status, io_addr + USBSTS); /* Clear it */
if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
...@@ -1963,6 +1963,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1963,6 +1963,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
spin_unlock(&uhci->urb_list_lock); spin_unlock(&uhci->urb_list_lock);
uhci_finish_completion(hcd, regs); uhci_finish_completion(hcd, regs);
return IRQ_HANDLED;
} }
static void reset_hc(struct uhci_hcd *uhci) static void reset_hc(struct uhci_hcd *uhci)
......
...@@ -17,19 +17,6 @@ config USB_MDC800 ...@@ -17,19 +17,6 @@ config USB_MDC800
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called mdc800. module will be called mdc800.
config USB_SCANNER
tristate "USB Scanner support (OBSOLETE)"
depends on USB
help
Say Y here if you want to connect a USB scanner to your computer's
USB port. Please read <file:Documentation/usb/scanner.txt> for more
information.
This driver has been obsoleted by support via libusb.
To compile this driver as a module, choose M here: the
module will be called scanner.
config USB_MICROTEK config USB_MICROTEK
tristate "Microtek X6USB scanner support" tristate "Microtek X6USB scanner support"
depends on USB && SCSI depends on USB && SCSI
......
...@@ -5,4 +5,3 @@ ...@@ -5,4 +5,3 @@
obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o
obj-$(CONFIG_USB_MICROTEK) += microtek.o obj-$(CONFIG_USB_MICROTEK) += microtek.o
obj-$(CONFIG_USB_SCANNER) += scanner.o
/* -*- linux-c -*- */
/*
* Driver for USB Scanners (linux-2.6)
*
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Copyright (C) 2002, 2003 Henning Meier-Geinitz
*
* Portions may be copyright Brad Keryan and Michael Gee.
*
* Previously maintained by Brian Beattie
*
* Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
*
* 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.
*
* Originally based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
*
* History
*
* 0.1 8/31/1999
*
* Developed/tested using linux-2.3.15 with minor ohci.c changes to
* support short packets during bulk xfer mode. Some testing was
* done with ohci-hcd but the performance was low. Very limited
* testing was performed with uhci but I was unable to get it to
* work. Initial relase to the linux-usb development effort.
*
*
* 0.2 10/16/1999
*
* - Device can't be opened unless a scanner is plugged into the USB.
* - Finally settled on a reasonable value for the I/O buffer's.
* - Cleaned up write_scanner()
* - Disabled read/write stats
* - A little more code cleanup
*
*
* 0.3 10/18/1999
*
* - Device registration changed to reflect new device
* allocation/registration for linux-2.3.22+.
* - Adopted David Brownell's <david-b@pacbell.net> technique for
* assigning bulk endpoints.
* - Removed unnecessary #include's
* - Scanner model now reported via syslog INFO after being detected
* *and* configured.
* - Added user specified vendor:product USB ID's which can be passed
* as module parameters.
*
*
* 0.3.1
*
* - Applied patches for linux-2.3.25.
* - Error number reporting changed to reflect negative return codes.
*
*
* 0.3.2
*
* - Applied patches for linux-2.3.26 to scanner_init().
* - Debug read/write stats now report values as signed decimal.
*
*
* 0.3.3
*
* - Updated the bulk_msg() calls to usb usb_bulk_msg().
* - Added a small delay in the write_scanner() method to aid in
* avoiding NULL data reads on HP scanners. We'll see how this works.
* - Return values from usb_bulk_msg() now ignore positive values for
* use with the ohci driver.
* - Added conditional debugging instead of commenting/uncommenting
* all over the place.
* - kfree()'d the pointer after using usb_string() as documented in
* linux-usb-api.txt.
* - Added usb_set_configuration(). It got lost in version 0.3 -- ack!
* - Added the HP 5200C USB Vendor/Product ID's.
*
*
* 0.3.4 1/23/2000
*
* - Added Greg K-H's <greg@kroah.com> patch for better handling of
* Product/Vendor detection.
* - The driver now autoconfigures its endpoints including interrupt
* endpoints if one is detected. The concept was originally based
* upon David Brownell's method.
* - Added some Seiko/Epson ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
* - Added some preliminary ioctl() calls for the PV8630 which is used
* by the HP4200. The ioctl()'s still have to be registered. Thanks
* to Adrian Perez Jorge <adrianpj@easynews.com>.
* - Moved/migrated stuff to scanner.h
* - Removed the usb_set_configuration() since this is handled by
* the usb_new_device() routine in usb.c.
* - Added the HP 3300C. Thanks to Bruce Tenison.
* - Changed user specified vendor/product id so that root hub doesn't
* get falsely attached to. Thanks to Greg K-H.
* - Added some Mustek ID's. Thanks to Gernot Hoyler
* <Dr.Hoyler@t-online.de>.
* - Modified the usb_string() reporting. See kfree() comment above.
* - Added Umax Astra 2000U. Thanks to Doug Alcorn <doug@lathi.net>.
* - Updated the printk()'s to use the info/warn/dbg macros.
* - Updated usb_bulk_msg() argument types to fix gcc warnings.
*
*
* 0.4 2/4/2000
*
* - Removed usb_string() from probe_scanner since the core now does a
* good job of reporting what was connnected.
* - Finally, simultaneous multiple device attachment!
* - Fixed some potential memory freeing issues should memory allocation
* fail in probe_scanner();
* - Some fixes to disconnect_scanner().
* - Added interrupt endpoint support.
* - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh
* <jan.vandenbergh@cs.kuleuven.ac.be>.
* - Added Umax 1220U ID's. Thanks to Maciek Klimkowski
* <mac@nexus.carleton.ca>.
* - Fixed bug in write_scanner(). The buffer was not being properly
* updated for writes larger than OBUF_SIZE. Thanks to Henrik
* Johansson <henrikjo@post.utfors.se> for identifying it.
* - Added Microtek X6 ID's. Thanks to Oliver Neukum
* <Oliver.Neukum@lrz.uni-muenchen.de>.
*
*
* 0.4.1 2/15/2000
*
* - Fixed 'count' bug in read_scanner(). Thanks to Henrik
* Johansson <henrikjo@post.utfors.se> for identifying it. Amazing
* it has worked this long.
* - Fixed '>=' bug in both read/write_scanner methods.
* - Cleaned up both read/write_scanner() methods so that they are
* a little more readable.
* - Added a lot of Microtek ID's. Thanks to Adrian Perez Jorge.
* - Adopted the __initcall().
* - Added #include <linux/init.h> to scanner.h for __initcall().
* - Added one liner in irq_scanner() to keep gcc from complaining
* about an unused variable (data) if debugging was disabled
* in scanner.c.
* - Increased the timeout parameter in read_scanner() to 120 Secs.
*
*
* 0.4.2 3/23/2000
*
* - Added Umax 1236U ID. Thanks to Philipp Baer <ph_baer@npw.net>.
* - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
* Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
* - Fixed error number reported for non-existant devices. Thanks to
* Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
* - Added Acer Prisascan 620U ID's. Thanks to Joao <joey@knoware.nl>.
* - Replaced __initcall() with module_init()/module_exit(). Updates
* from patch-2.3.48.
* - Replaced file_operations structure with new syntax. Updates
* from patch-2.3.49.
* - Changed #include "usb.h" to #include <linux/usb.h>
* - Added #define SCN_IOCTL to exclude development areas
* since 2.4.x is about to be released. This mainly affects the
* ioctl() stuff. See scanner.h for more details.
* - Changed the return value for signal_pending() from -ERESTARTSYS to
* -EINTR.
*
*
* 0.4.3 4/30/2000
*
* - Added Umax Astra 2200 ID. Thanks to Flynn Marquardt
* <flynn@isr.uni-stuttgart.de>.
* - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
* - Added access time update for the device file courtesy of Paul
* Mackerras <paulus@samba.org>. This allows a user space daemon
* to turn the lamp off for a Umax 1220U scanner after a prescribed
* time.
* - Fixed HP S20 ID's. Thanks to Ruud Linders <rlinders@xs4all.nl>.
* - Added Acer ScanPrisa 620U ID. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
* - Fixed bug in read_scanner for copy_to_user() function. The returned
* value should be 'partial' not 'this_read'.
* - Fixed bug in read_scanner. 'count' should be decremented
* by 'this_read' and not by 'partial'. This resulted in twice as many
* calls to read_scanner() for small amounts of data and possibly
* unexpected returns of '0'. Thanks to Karl Heinz
* Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
* for discovering this.
* - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
* scanner lookup/ident table. Thanks Randy.
* - Documentation updates.
* - Added wait queues to read_scanner().
*
*
* 0.4.3.1
*
* - Fixed HP S20 ID's...again..sigh. Thanks to Ruud
* Linders <rlinders@xs4all.nl>.
*
* 0.4.4
* - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB,
* and 1200 UB. Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
* - Added the Vuego Scan Brisa 340U ID's. Apparently this scanner is
* marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to
* David Gundersen <gundersd@paradise.net.nz>.
* - Added the Epson Expression1600 ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
*
* 0.4.5 2/28/2001
* - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F).
* Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
* - Added read_timeout module parameter to override RD_NAK_TIMEOUT
* when read()'ing from devices.
* - Stalled pipes are now checked and cleared with
* usb_clear_halt() for the read_scanner() function. This should
* address the "funky result: -32" error messages.
* - Removed Microtek scanner ID's. Microtek scanners are now
* supported via the drivers/usb/microtek.c driver.
* - Added scanner specific read timeout's.
* - Return status errors are NEGATIVE!!! This should address the
* "funky result: -110" error messages.
* - Replaced USB_ST_TIMEOUT with ETIMEDOUT.
* - rd_nak was still defined in MODULE_PARM. It's been updated with
* read_timeout. Thanks to Mark W. Webb <markwebb@adelphia.net> for
* reporting this bug.
* - Added Epson Perfection 1640SU and 1640SU Photo. Thanks to
* Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
* Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
*
* 0.4.6 9/27/2001
* - Added IOCTL's to report back scanner USB ID's. Thanks to
* Karl Heinz <khk@lynx.phpwebhosting.com>
* - Added Umax Astra 2100U ID's. Thanks to Ron
* Wellsted <ron@wellsted.org.uk>.
* and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
* - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
* and Bertrik Sikken <bertrik@zonnet.nl>. Reported to work at
* htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
* - Added Minolta Dimage Scan Dual II ID's. Thanks to Jose Paulo
* Moitinho de Almeida <moitinho@civil.ist.utl.pt>
* - Confirmed addition for SnapScan E20. Thanks to Steffen Hübner
* <hueb_s@gmx.de>.
* - Added Lifetec LT9385 ID's. Thanks to Van Bruwaene Kris
* <krvbr@yahoo.co.uk>
* - Added Agfa SnapScan e26 ID's. Reported to work with SANE
* 1.0.5. Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
* - Added HP 4300 ID's. Thanks to Stefan Schlosser
* <castla@grmmbl.org>.
* - Added Relisis Episode ID's. Thanks to Manfred
* Morgner <odb-devel@gmx.net>.
* - Added many Acer ID's. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de>.
* - Added Snapscan e40 ID's. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de>.
* - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
* for helping with races.
* - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
* - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
* market). Thanks to Karl Heinz Kremer <khk@khk.net>.
* - Added Mustek 600 USB ID's. Thanks to Marcus
* Alanen <maalanen@ra.abo.fi>.
* - Added Acer ScanPrisa 1240UT ID's. Thanks to Morgan
* Collins <sirmorcant@morcant.org>.
* - Incorporated devfs patches!! Thanks to Tom Rini
* <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
* Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
* Flavio Stanchina <flavio.stanchina@tin.it>.
* - Removed Minolta ScanImage II. This scanner uses USB SCSI. Thanks
* to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
* this out.
* - Added additional SMP locking. Thanks to David Brownell and
* Oliver Neukum for their help.
* - Added version reporting - reports for both module load and modinfo
* - Started path to hopefully straighten/clean out ioctl()'s.
* - Users are now notified to consult the Documentation/usb/scanner.txt
* for common error messages rather than the maintainer.
*
* 0.4.7 11/28/2001
* - Fixed typo in Documentation/usb/scanner.txt. Thanks to
* Karel <karel.vervaeke@pandora.be> for pointing it out.
* - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
* Valenzuela" <agaspard@utsi.edu>.
* - Added ID's for Agfa e25. Thanks to Heinrich
* Rust <Heinrich.Rust@gmx.de>. Also reported to work with
* Linux and SANE (?).
* - Added Canon FB620U, D646U, and 1220U ID's. Thanks to Paul
* Rensing <Paul_Rensing@StanfordAlumni.org>. For more info
* on Linux support for these models, contact
* salvestrini@users.sourceforge.net.
* - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
* ColorPage-HR6 V2 ID's in addition to many "Unknown" models
* under those vendors. Thanks to
* Jaeger, Gerhard" <g.jaeger@earthling.net>. These scanner are
* apparently based upon the LM983x IC's.
* - Applied Frank's patch that addressed some locking and module
* referencing counts. Thanks to both
* Frank Zago <fzago@greshamstorage.com> and
* Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
*
* 0.4.8 5/30/2002
* - Added Mustek BearPaw 2400 TA. Thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>.
* - Added Mustek 1200UB Plus and Mustek BearPaw 1200 CU ID's. These use
* the Grandtech GT-6801 chip. Thanks to Henning
* Meier-Geinitz <henning@meier-geinitz.de>.
* - Increased Epson timeout to 60 secs as requested from
* Karl Heinz Kremer <khk@khk.net>.
* - Changed maintainership from David E. Nelson to Brian
* Beattie <beattie@beattie-home.net>.
*
* 0.4.9 12/19/2002
* - Added vendor/product ids for Nikon, Mustek, Plustek, Genius, Epson,
* Canon, Umax, Hewlett-Packard, Benq, Agfa, Minolta scanners.
* Thanks to Dieter Faulbaum <faulbaum@mail.bessy.de>, Stian Jordet
* <liste@jordet.nu>, "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>,
* "Jaeger, Gerhard" <gerhard@gjaeger.de>, Ira Childress
* <ichildress@mn.rr.com>, Till Kamppeter <till.kamppeter@gmx.net>,
* Ed Hamrick <EdHamrick@aol.com>, Oliver Schwartz
* <Oliver.Schwartz@gmx.de> and everyone else who sent ids.
* - Some Benq, Genius and Plustek ids are identified now.
* - Accept scanners with only one bulk (in) endpoint (thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>).
* - Accept devices with more than one interface. Only use interfaces that
* look like belonging to scanners.
* - Fix compilation error when debugging is enabled.
* - Add locking to ioctl_scanner(). Thanks to Oliver Neukum
* <oliver@neukum.name>.
*
* 0.4.10 01/07/2003
* - Added vendor/product ids for Artec, Canon, Compaq, Epson, HP, Microtek
* and Visioneer scanners. Thanks to William Lam <wklam@triad.rr.com>,
* Till Kamppeter <till.kamppeter@gmx.net> and others for all the ids.
* - Cleaned up list of vendor/product ids.
* - Print information about user-supplied ids only once at startup instead
* of every time any USB device is plugged in.
* - Removed PV8630 ioctls. Use the standard ioctls instead.
* - Made endpoint detection more generic. Basically, only one bulk-in
* endpoint is required, everything else is optional.
* - New maintainer: Henning Meier-Geinitz.
* - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy.
*
* 0.4.11 2003-02-25
* - Added vendor/product ids for Artec, Avision, Brother, Canon, Compaq,
* Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek,
* Primax, Prolink, Plustek, SYSCAN, Trust and UMAX scanners.
* - Fixed generation of devfs names if dynamic minors are disabled.
* - Used kobject reference counting to free the scn struct when the device
* is closed and disconnected. Avoids crashes when writing to a
* disconnected device. (Thanks to Greg KH).
*
* 0.4.12 2003-04-11
* - Fixed endpoint detection. The endpoints were numbered from 1 to n but
* that assumption is not correct in all cases.
*
* 0.4.13 2003-05-30
* - Added vendor/product ids for Genius, Hewlett-Packard, Microtek,
* Mustek, Pacific Image Electronics, Plustek, and Visioneer scanners.
* Fixed names of some other scanners.
*
* 0.4.14 2003-07-15
* - Fixed race between open and probe (Oliver Neukum).
* - Added vendor/product ids for Avision, Canon, HP, Microtek and Relisys scanners.
* - Clean up irq urb when not enough memory is available.
*
* 0.4.15 2003-09-22
* - Use static declarations for usb_scanner_init/usb_scanner_exit
* (Daniele Bellucci).
* - Report back return codes of usb_register and usb_usbmit_urb instead of -1 or
* -ENONMEM (Daniele Bellucci).
* - Balancing usb_register_dev/usb_deregister_dev in probe_scanner when a fail
* condition occours (Daniele Bellucci).
* - Added vendor/product ids for Canon, HP, Microtek, Mustek, Siemens, UMAX, and
* Visioneer scanners.
* - Added test for USB_CLASS_CDC_DATA which is used by some fingerprint scanners.
*
* 0.4.16 2003-11-04
* - Added vendor/product ids for Epson, Genius, Microtek, Plustek, Reflecta, and
* Visioneer scanners. Removed ids for HP PSC devices as these are supported by
* the hpoj userspace driver.
*
* TODO
* - Performance
* - Select/poll methods
* - More testing
* - More general usage ioctl's
*
*
* Thanks to:
*
* - All the folks on the linux-usb list who put up with me. :) This
* has been a great learning experience for me.
* - To Linus Torvalds for this great OS.
* - The GNU folks.
* - The folks that forwarded Vendor:Product ID's to me.
* - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
* issue with HP-4100 and uhci.
* - Adolfo Montero for his assistance.
* - All the folks who chimed in with reports and suggestions.
* - All the developers that are working on USB SANE backends or other
* applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* and Henning Meier-Geinitz to be the new USB Scanner maintainer.
*
* Performance:
*
* System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
* 300 dpi scan of the entire bed
* 24 Bit Color ~ 70 secs - 3.6 Mbit/sec
* 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
#include <asm/byteorder.h>
/*
* Scanner definitions, macros, module info,
* debug/ioctl/data_dump enable, and other constants.
*/
#include "scanner.h"
static void
irq_scanner(struct urb *urb, struct pt_regs *regs)
{
/*
* For the meantime, this is just a placeholder until I figure out what
* all I want to do with it -- or somebody else for that matter.
*/
struct scn_usb_data *scn;
unsigned char *data;
int status;
scn = urb->context;
data = &scn->button;
data += 0; /* Keep gcc from complaining about unused var */
switch (urb->status) {
case 0:
/* success */
break;
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);
return;
}
dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("%s - usb_submit_urb failed with result %d",
__FUNCTION__, status);
}
static int
open_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn;
struct usb_device *dev;
struct usb_interface *intf;
int scn_minor;
int err=0;
down(&scn_mutex);
scn_minor = USB_SCN_MINOR(inode);
dbg("open_scanner: scn_minor:%d", scn_minor);
intf = usb_find_interface(&scanner_driver, scn_minor);
if (!intf) {
up(&scn_mutex);
err("open_scanner(%d): Unable to access minor data", scn_minor);
return -ENODEV;
}
scn = usb_get_intfdata(intf);
kobject_get(&scn->kobj);
dev = scn->scn_dev;
down(&(scn->sem)); /* Now protect the scn_usb_data structure */
up(&scn_mutex); /* Now handled by the above */
if (!dev) {
err("open_scanner(%d): Scanner device not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (!scn->present) {
err("open_scanner(%d): Scanner is not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (scn->isopen) {
dbg("open_scanner(%d): Scanner device is already open", scn_minor);
err = -EBUSY;
goto out_error;
}
init_waitqueue_head(&scn->rd_wait_q);
scn->isopen = 1;
file->private_data = scn; /* Used by the read and write methods */
out_error:
up(&(scn->sem)); /* Wake up any possible contending processes */
return err;
}
static int
close_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn = file->private_data;
int scn_minor;
scn_minor = USB_SCN_MINOR (inode);
dbg("close_scanner: scn_minor:%d", scn_minor);
down(&scn_mutex);
down(&(scn->sem));
scn->isopen = 0;
file->private_data = NULL;
up(&scn_mutex);
up(&(scn->sem));
kobject_put(&scn->kobj);
return 0;
}
static ssize_t
write_scanner(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
int scn_minor;
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
int result = 0;
char *obuf;
scn = file->private_data;
down(&(scn->sem));
if (!scn->bulk_out_ep) {
/* This scanner does not have a bulk-out endpoint */
up(&(scn->sem));
return -EINVAL;
}
scn_minor = scn->scn_minor;
obuf = scn->obuf;
dev = scn->scn_dev;
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
if (copy_from_user(scn->obuf, buffer, this_write)) {
ret = -EFAULT;
break;
}
result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK received.");
ret = result;
break;
} else if (result < 0) { /* We should not get any I/O errors */
warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
ret = -EIO;
break;
}
#ifdef WR_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", obuf[cnt]);
}
printk("\n");
}
#endif
if (partial != this_write) { /* Unable to write all contents of obuf */
ret = -EIO;
break;
}
if (partial) { /* Data written */
buffer += partial;
count -= partial;
bytes_written += partial;
} else { /* No data written */
ret = 0;
break;
}
}
up(&(scn->sem));
mdelay(5); /* This seems to help with SANE queries */
return ret ? ret : bytes_written;
}
static ssize_t
read_scanner(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_read; /* Overall count of bytes_read */
ssize_t ret;
int scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
int result;
int rd_expire = RD_EXPIRE;
char *ibuf;
scn = file->private_data;
down(&(scn->sem));
scn_minor = scn->scn_minor;
ibuf = scn->ibuf;
dev = scn->scn_dev;
bytes_read = 0;
ret = 0;
file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
atime of
the device
node */
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
/*
* Scanners are sometimes inheriently slow since they are mechanical
* in nature. USB bulk reads tend to timeout while the scanner is
* positioning, resetting, warming up the lamp, etc if the timeout is
* set too low. A very long timeout parameter for bulk reads was used
* to overcome this limitation, but this sometimes resulted in folks
* having to wait for the timeout to expire after pressing Ctrl-C from
* an application. The user was sometimes left with the impression
* that something had hung or crashed when in fact the USB read was
* just waiting on data. So, the below code retains the same long
* timeout period, but splits it up into smaller parts so that
* Ctrl-C's are acted upon in a reasonable amount of time.
*/
if (result == -ETIMEDOUT) { /* NAK */
if (!partial) { /* No data */
if (--rd_expire <= 0) { /* Give it up */
warn("read_scanner(%d): excessive NAK's received", scn_minor);
ret = result;
break;
} else { /* Keep trying to read data */
interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
continue;
}
} else { /* Timeout w/ some data */
goto data_recvd;
}
}
if (result == -EPIPE) { /* No hope */
if(usb_clear_halt(dev, scn->bulk_in_ep)) {
err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
}
ret = result;
break;
} else if ((result < 0) && (result != -EREMOTEIO)) {
warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
ret = -EIO;
break;
}
data_recvd:
#ifdef RD_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", ibuf[cnt]);
}
printk("\n");
}
#endif
if (partial) { /* Data returned */
if (copy_to_user(buffer, ibuf, partial)) {
ret = -EFAULT;
break;
}
count -= this_read; /* Compensate for short reads */
bytes_read += partial; /* Keep tally of what actually was read */
buffer += partial;
} else {
ret = 0;
break;
}
}
up(&(scn->sem));
return ret ? ret : bytes_read;
}
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct usb_device *dev;
struct scn_usb_data *scn = file->private_data;
int retval = -ENOTTY;
int scn_minor;
scn_minor = USB_SCN_MINOR(inode);
down(&(scn->sem));
dev = scn->scn_dev;
switch (cmd)
{
case SCANNER_IOCTL_VENDOR :
retval = (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
break;
case SCANNER_IOCTL_PRODUCT :
retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
break;
case SCANNER_IOCTL_CTRLMSG:
{
struct ctrlmsg_ioctl {
struct usb_ctrlrequest req;
void *data;
} cmsg;
int pipe, nb, ret;
unsigned char buf[64];
retval = 0;
if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) {
retval = -EFAULT;
break;
}
nb = cmsg.req.wLength;
if (nb > sizeof(buf)) {
retval = -EINVAL;
break;
}
if ((cmsg.req.bRequestType & 0x80) == 0) {
pipe = usb_sndctrlpipe(dev, 0);
if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) {
retval = -EFAULT;
break;
}
} else {
pipe = usb_rcvctrlpipe(dev, 0);
}
ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
cmsg.req.bRequestType,
cmsg.req.wValue,
cmsg.req.wIndex,
buf, nb, HZ);
if (ret < 0) {
err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
retval = -EIO;
break;
}
if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
retval = -EFAULT;
break;
}
default:
break;
}
up(&(scn->sem));
return retval;
}
static void destroy_scanner (struct kobject *kobj)
{
struct scn_usb_data *scn;
dbg ("%s", __FUNCTION__);
scn = to_scanner(kobj);
down (&scn_mutex);
down (&(scn->sem));
usb_driver_release_interface(&scanner_driver,
scn->scn_dev->actconfig->interface[scn->ifnum]);
kfree(scn->ibuf);
kfree(scn->obuf);
usb_free_urb(scn->scn_irq);
usb_put_dev(scn->scn_dev);
up (&(scn->sem));
kfree (scn);
up (&scn_mutex);
}
static struct kobj_type scanner_kobj_type = {
.release = destroy_scanner,
};
static struct
file_operations usb_scanner_fops = {
.owner = THIS_MODULE,
.read = read_scanner,
.write = write_scanner,
.ioctl = ioctl_scanner,
.open = open_scanner,
.release = close_scanner,
};
static struct usb_class_driver scanner_class = {
.name = "usb/scanner%d",
.fops = &usb_scanner_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
.minor_base = SCN_BASE_MNR,
};
static int
probe_scanner(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (intf);
struct scn_usb_data *scn;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int ep_cnt;
int ix;
int retval;
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
char name[14];
dbg("probe_scanner: USB dev address:%p", dev);
/*
* 1. Check Vendor/Product
* 2. Determine/Assign Bulk Endpoints
* 3. Determine/Assign Intr Endpoint
*/
/*
* There doesn't seem to be an imaging class defined in the USB
* Spec. (yet). If there is, HP isn't following it and it doesn't
* look like anybody else is either. Therefore, we have to test the
* Vendor and Product ID's to see what we have. Also, other scanners
* may be able to use this driver by specifying both vendor and
* product ID's as options to the scanner module in conf.modules.
*
* NOTE: Just because a product is supported here 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 USB products.
*
* Until we detect a device which is pleasing, we silently punt.
*/
for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
(dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
valid_device = 1;
break;
}
}
if (dev->descriptor.idVendor == vendor && /* User specified */
dev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
}
if (!valid_device)
return -ENODEV; /* We didn't find anything pleasing */
/*
* After this point we can be a little noisy about what we are trying to
* configure.
*/
if (dev->descriptor.bNumConfigurations != 1) {
info("probe_scanner: Only one device configuration is supported.");
return -ENODEV;
}
interface = intf->altsetting;
if (interface[0].desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
interface[0].desc.bInterfaceClass != USB_CLASS_PER_INTERFACE &&
interface[0].desc.bInterfaceClass != USB_CLASS_CDC_DATA &&
interface[0].desc.bInterfaceClass != SCN_CLASS_SCANJET) {
dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].desc.bInterfaceClass);
return -ENODEV;
}
/*
* Start checking for bulk and interrupt endpoints. We are only using the first
* one of each type of endpoint. If we have an interrupt endpoint go ahead and
* setup the handler. FIXME: This is a future enhancement...
*/
dbg("probe_scanner: Number of Endpoints:%d", (int) interface->desc.bNumEndpoints);
ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
while (ep_cnt < interface->desc.bNumEndpoints) {
endpoint = &interface->endpoint[ep_cnt].desc;
if (IS_EP_BULK_IN(endpoint)) {
ep_cnt++;
if (have_bulk_in) {
info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
continue;
}
have_bulk_in = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
continue;
}
if (IS_EP_BULK_OUT(endpoint)) {
ep_cnt++;
if (have_bulk_out) {
info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
continue;
}
have_bulk_out = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
continue;
}
if (IS_EP_INTR(endpoint)) {
ep_cnt++;
if (have_intr) {
info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
continue;
}
have_intr = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: intr_ep:%d", have_intr);
continue;
}
info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
return -EIO; /* Shouldn't ever get here unless we have something weird */
}
/*
* Perform a quick check to make sure that everything worked as it
* should have.
*/
if (!have_bulk_in) {
err("probe_scanner: One bulk-in endpoint required.");
return -EIO;
}
/*
* Determine a minor number and initialize the structure associated
* with it. The problem with this is that we are counting on the fact
* that the user will sequentially add device nodes for the scanner
* devices. */
down(&scn_mutex);
retval = usb_register_dev(intf, &scanner_class);
if (retval) {
err ("Not able to get a minor for this device.");
up(&scn_mutex);
return -ENOMEM;
}
dbg("probe_scanner: Allocated minor:%d", intf->minor);
if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
err("probe_scanner: Out of memory.");
up(&scn_mutex);
return -ENOMEM;
}
memset (scn, 0, sizeof(struct scn_usb_data));
kobject_init(&scn->kobj);
scn->kobj.ktype = &scanner_kobj_type;
scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
if (!scn->scn_irq) {
usb_deregister_dev(intf, &scanner_class);
kfree(scn);
up(&scn_mutex);
return -ENOMEM;
}
init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
dbg ("probe_scanner(%d): Address of scn:%p", intf->minor, scn);
/* Ok, if we detected an interrupt EP, setup a handler for it */
if (have_intr) {
dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", intf->minor, have_intr);
usb_fill_int_urb(scn->scn_irq, dev,
usb_rcvintpipe(dev, have_intr),
&scn->button, 1, irq_scanner, scn,
// endpoint[(int)have_intr].bInterval);
250);
retval = usb_submit_urb(scn->scn_irq, GFP_KERNEL);
if (retval) {
err("probe_scanner(%d): Unable to allocate INT URB.", intf->minor);
usb_deregister_dev(intf, &scanner_class);
kfree(scn);
up(&scn_mutex);
return retval;
}
}
/* Ok, now initialize all the relevant values */
if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
err("probe_scanner(%d): Not enough memory for the output buffer.", intf->minor);
if (have_intr)
usb_unlink_urb(scn->scn_irq);
usb_free_urb(scn->scn_irq);
usb_deregister_dev(intf, &scanner_class);
kfree(scn);
up(&scn_mutex);
return -ENOMEM;
}
dbg("probe_scanner(%d): obuf address:%p", intf->minor, scn->obuf);
if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
err("probe_scanner(%d): Not enough memory for the input buffer.", intf->minor);
if (have_intr)
usb_unlink_urb(scn->scn_irq);
usb_free_urb(scn->scn_irq);
usb_deregister_dev(intf, &scanner_class);
kfree(scn->obuf);
kfree(scn);
up(&scn_mutex);
return -ENOMEM;
}
dbg("probe_scanner(%d): ibuf address:%p", intf->minor, scn->ibuf);
switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
case 0x04b8: /* Seiko/Epson */
scn->rd_nak_timeout = HZ * 60;
break;
case 0x055f: /* Mustek */
case 0x0400: /* Another Mustek */
scn->rd_nak_timeout = HZ * 1;
default:
scn->rd_nak_timeout = RD_NAK_TIMEOUT;
}
if (read_timeout > 0) { /* User specified read timeout overrides everything */
info("probe_scanner: User specified USB read timeout - %d", read_timeout);
scn->rd_nak_timeout = read_timeout;
}
usb_get_dev(dev);
scn->bulk_in_ep = have_bulk_in;
scn->bulk_out_ep = have_bulk_out;
scn->intr_ep = have_intr;
scn->present = 1;
scn->scn_dev = dev;
scn->scn_minor = intf->minor;
scn->isopen = 0;
snprintf(name, sizeof(name), scanner_class.name,
intf->minor - scanner_class.minor_base);
info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
dev->descriptor.idVendor, dev->descriptor.idProduct, name);
usb_set_intfdata(intf, scn);
up(&scn_mutex);
return 0;
}
static void
disconnect_scanner(struct usb_interface *intf)
{
struct scn_usb_data *scn = usb_get_intfdata(intf);
/* disable open() */
dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor);
usb_deregister_dev(intf, &scanner_class);
usb_set_intfdata(intf, NULL);
if(scn->intr_ep) {
dbg("%s(%d): Unlinking IRQ URB", __FUNCTION__, scn->scn_minor);
usb_unlink_urb(scn->scn_irq);
}
if (scn)
kobject_put(&scn->kobj);
}
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id ids[] = {
{.driver_info = 42},
{}
};
static struct
usb_driver scanner_driver = {
.owner = THIS_MODULE,
.name = "usbscanner",
.probe = probe_scanner,
.disconnect = disconnect_scanner,
.id_table = ids,
};
static void __exit
usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
static int __init
usb_scanner_init (void)
{
int retval;
retval = usb_register(&scanner_driver);
if (retval)
goto out;
info(DRIVER_VERSION ":" DRIVER_DESC);
if (vendor != -1 && product != -1)
info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
out:
return retval;
}
module_init(usb_scanner_init);
module_exit(usb_scanner_exit);
/*
* Driver for USB Scanners (linux-2.6)
*
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Previously maintained by Brian Beattie
*
* Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
*
* 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.
*
*/
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
// #define DEBUG
#define DRIVER_VERSION "0.4.16"
#define DRIVER_DESC "USB Scanner Driver"
#include <linux/usb.h>
static __s32 vendor=-1, product=-1, read_timeout=0;
MODULE_AUTHOR("Henning Meier-Geinitz, henning@meier-geinitz.de");
MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
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");
MODULE_PARM(read_timeout, "i");
MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
static struct usb_device_id scanner_device_ids [] = {
/* Acer (now Benq) */
{ USB_DEVICE(0x04a5, 0x1a20) }, /* Prisa 310U */
{ USB_DEVICE(0x04a5, 0x1a2a) }, /* Another 620U */
{ USB_DEVICE(0x04a5, 0x2022) }, /* 340U */
{ USB_DEVICE(0x04a5, 0x2040) }, /* 620U (!) */
{ USB_DEVICE(0x04a5, 0x2060) }, /* 620U & 640U (!)*/
{ USB_DEVICE(0x04a5, 0x207e) }, /* 640BU */
{ USB_DEVICE(0x04a5, 0x20b0) }, /* Benq 4300 */
{ USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
{ USB_DEVICE(0x04a5, 0x20c0) }, /* 1240UT, 1240U */
{ USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
{ USB_DEVICE(0x04a5, 0x20fc) }, /* Benq 5000 */
{ USB_DEVICE(0x04a5, 0x20fe) }, /* Benq 5300 */
/* Agfa */
{ USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
{ USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
{ USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */
{ USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
{ USB_DEVICE(0x06bd, 0x208f) }, /* SnapScan e50*/
{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
{ USB_DEVICE(0x06bd, 0x2093) }, /* SnapScan e10*/
{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
{ USB_DEVICE(0x06bd, 0x20fd) }, /* SnapScan e52*/
{ USB_DEVICE(0x06bd, 0x20ff) }, /* SnapScan e42*/
/* Artec */
{ USB_DEVICE(0x05d8, 0x4001) }, /* Ultima 2000 */
{ USB_DEVICE(0x05d8, 0x4002) }, /* Ultima 2000 (GT6801 based) */
{ USB_DEVICE(0x05d8, 0x4003) }, /* E+ 48U */
{ USB_DEVICE(0x05d8, 0x4004) }, /* E+ Pro */
/* Avision */
{ USB_DEVICE(0x0638, 0x0268) }, /* iVina 1200U */
{ USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */
{ USB_DEVICE(0x0638, 0x0a20) }, /* iVina FB1800 (=Umax Astra 4700) */
/* Benq: see Acer */
/* Brother */
{ USB_DEVICE(0x04f9, 0x010f) }, /* MFC 5100C */
{ USB_DEVICE(0x04f9, 0x0111) }, /* MFC 6800 */
/* Canon */
{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
{ USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */
{ USB_DEVICE(0x04a9, 0x2205) }, /* CanoScan FB1210U */
{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */
{ USB_DEVICE(0x04a9, 0x220a) }, /* CanoScan D2400UF */
{ USB_DEVICE(0x04a9, 0x220b) }, /* CanoScan D646U */
{ USB_DEVICE(0x04a9, 0x220c) }, /* CanoScan D1250U2 */
{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
{ USB_DEVICE(0x04a9, 0x220f) }, /* CanoScan 8000F */
{ USB_DEVICE(0x04a9, 0x2210) }, /* CanoScan 9900F */
{ USB_DEVICE(0x04a9, 0x2212) }, /* CanoScan 5000F */
{ USB_DEVICE(0x04a9, 0x2213) }, /* LIDE 50 */
{ USB_DEVICE(0x04a9, 0x2215) }, /* CanoScan 3000 */
{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
/* Colorado -- See Primax/Colorado below */
/* Compaq */
{ USB_DEVICE(0x049f, 0x001a) }, /* S4 100 */
{ USB_DEVICE(0x049f, 0x0021) }, /* S200 */
/* Epson -- See Seiko/Epson below */
/* Fujitsu */
{ USB_DEVICE(0x04c5, 0x1041) }, /* fi-4220c USB/SCSI info:mza@mu-tec.de */
{ USB_DEVICE(0x04c5, 0x1042) }, /* fi-4120c USB/SCSI info:mza@mu-tec.de */
{ USB_DEVICE(0x04c5, 0x1029) }, /* fi-4010c USB AVision info:mza@mu-tec.de */
/* Genius */
{ USB_DEVICE(0x0458, 0x2001) }, /* ColorPage Vivid Pro */
{ USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */
{ USB_DEVICE(0x0458, 0x2008) }, /* ColorPage HR6 V2 */
{ USB_DEVICE(0x0458, 0x2009) }, /* ColorPage HR6A */
{ USB_DEVICE(0x0458, 0x2011) }, /* ColorPage Vivid3x */
{ USB_DEVICE(0x0458, 0x2013) }, /* ColorPage HR7 */
{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
{ USB_DEVICE(0x0458, 0x2018) }, /* ColorPage HR7X */
{ USB_DEVICE(0x0458, 0x201b) }, /* Colorpage Vivid 4x */
/* Hewlett Packard */
/* IMPORTANT: Hewlett-Packard multi-function peripherals (OfficeJet,
Printer/Scanner/Copier (PSC), LaserJet, or PhotoSmart printer)
should not be added to this table because they are accessed by a
userspace driver (hpoj) */
{ USB_DEVICE(0x03f0, 0x0101) }, /* ScanJet 4100C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0105) }, /* ScanJet 4200C */
{ USB_DEVICE(0x03f0, 0x0201) }, /* ScanJet 6200C */
{ USB_DEVICE(0x03f0, 0x0205) }, /* ScanJet 3300C */
{ USB_DEVICE(0x03f0, 0x0305) }, /* ScanJet 4300C */
{ USB_DEVICE(0x03f0, 0x0401) }, /* ScanJet 5200C */
{ USB_DEVICE(0x03f0, 0x0405) }, /* ScanJet 3400C */
{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */
{ USB_DEVICE(0x03f0, 0x0601) }, /* ScanJet 6300C */
{ USB_DEVICE(0x03f0, 0x0605) }, /* ScanJet 2200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* ScanJet 5300C - NOT SUPPORTED - use hpusbscsi driver */
{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
// { USB_DEVICE(0x03f0, 0x0801) }, /* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
{ USB_DEVICE(0x03f0, 0x0805) }, /* ScanJet 4470c */
{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
{ USB_DEVICE(0x03f0, 0x0a01) }, /* ScanJet 2400c */
{ USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */
{ USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */
{ USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */
{ USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */
// { USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 - NOT SUPPORTED - use hpoj userspace driver */
{ USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */
{ USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */
// { USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 - NOT SUPPORTED - use hpoj userspace driver */
/* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
{ USB_DEVICE(0x043d, 0x003d) }, /* X83 */
/* LG Electronics */
{ USB_DEVICE(0x0461, 0x0364) }, /* Scanworks 600U (repackaged Primax?) */
/* Medion */
{ USB_DEVICE(0x0461, 0x0377) }, /* MD 5345 - repackaged Primax? */
/* Memorex */
{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
/* Microtek */
{ USB_DEVICE(0x05da, 0x20a7) }, /* ScanMaker 5600 */
{ USB_DEVICE(0x05da, 0x20c9) }, /* ScanMaker 6700 */
{ USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */
{ USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */
{ USB_DEVICE(0x05da, 0x30d4) }, /* ScanMaker 3830 + 3840 */
{ USB_DEVICE(0x05da, 0x30d8) }, /* ScanMaker 5900 */
{ USB_DEVICE(0x04a7, 0x0224) }, /* Scanport 3000 (actually Visioneer?)*/
/* The following SCSI-over-USB Microtek devices are supported by the
microtek driver: Enable SCSI and USB Microtek in kernel config */
// { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */
// { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */
// { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */
// { USB_DEVICE(0x05da, 0x009a) }, /* Phantom C6 */
// { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */
// { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
// { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
/* Minolta */
{ USB_DEVICE(0x0686, 0x400d) }, /* Scan Dual III */
/* The following SCSI-over-USB Minolta devices are supported by the
hpusbscsi driver: Enable SCSI and USB hpusbscsi in kernel config */
// { USB_DEVICE(0x0638, 0x026a) }, /* Minolta Dimage Scan Dual II */
// { USB_DEVICE(0x0686, 0x4004) }, /* Scan Elite II (need interrupt ep) */
/* Mustek */
{ USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 (National Semiconductor LM9831) */
{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 (National Semiconductor LM9832) */
{ USB_DEVICE(0x055f, 0x0001) }, /* ScanExpress 1200 CU */
{ USB_DEVICE(0x055f, 0x0002) }, /* ScanExpress 600 CU */
{ USB_DEVICE(0x055f, 0x0003) }, /* ScanExpress 1200 USB */
{ USB_DEVICE(0x055f, 0x0006) }, /* ScanExpress 1200 UB */
{ USB_DEVICE(0x055f, 0x0007) }, /* ScanExpress 1200 USB Plus */
{ USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */
{ USB_DEVICE(0x055f, 0x0210) }, /* ScanExpress A3 USB */
{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
{ USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */
{ USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */
{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
{ USB_DEVICE(0x055f, 0x0401) }, /* P 3600 A3 Pro */
{ USB_DEVICE(0x055f, 0x0409) }, /* BearPaw 2448TA Pro */
{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
// { USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */
/* Nikon */
{ USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */
/* Pacific Image Electronics */
{ USB_DEVICE(0x05e3, 0x0120) }, /* PrimeFilm 1800u */
/* Plustek */
{ USB_DEVICE(0x07b3, 0x0001) }, /* 1212U */
{ USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0010) }, /* OpticPro U12 */
{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0013) }, /* UT12 */
{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
{ USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */
{ USB_DEVICE(0x07b3, 0x0403) }, /* U16B */
{ USB_DEVICE(0x07b3, 0x0413) }, /* OpticSlim 1200 */
/* Primax/Colorado */
{ USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
{ USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
{ USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */
{ USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
{ USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
{ USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
{ USB_DEVICE(0x0461, 0x0347) }, /* Primascan Colorado 2600u */
{ USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */
{ USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
{ USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
{ USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
{ USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
/* Prolink */
{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
/* Reflecta */
{ USB_DEVICE(0x05e3, 0x0120) }, /* iScan 1800 */
/* Relisis */
// { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
{ USB_DEVICE(0x0475, 0x0210) }, /* Scorpio Ultra 3 */
/* Seiko/Epson Corp. */
{ USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */
{ USB_DEVICE(0x04b8, 0x0102) }, /* GT-2200 */
{ USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */
{ USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/
{ USB_DEVICE(0x04b8, 0x0105) }, /* StylusScan 2000 */
{ USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */
{ USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */
{ USB_DEVICE(0x04b8, 0x0109) }, /* Expression 1640XL */
{ USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
{ USB_DEVICE(0x04b8, 0x010f) }, /* Perfection 1250U */
{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
{ USB_DEVICE(0x04b8, 0x011f) }, /* Perfection 1670 */
{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* Siemens */
{ USB_DEVICE(0x0681, 0x0005) }, /* ID Mouse Professional */
{ USB_DEVICE(0x0681, 0x0010) }, /* Cherry FingerTIP ID Board - Sensor */
/* SYSCAN */
{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
/* Trust */
{ USB_DEVICE(0x05cb, 0x1483) }, /* CombiScan 19200 */
{ USB_DEVICE(0x05d8, 0x4006) }, /* Easy Webscan 19200 (repackaged Artec?) */
/* Umax */
{ USB_DEVICE(0x05d8, 0x4009) }, /* Astraslim (actually Artec?) */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
{ USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */
{ USB_DEVICE(0x1606, 0x0070) }, /* Astra 4400 */
{ USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
{ USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */
{ USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
/* Visioneer */
{ USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0224) }, /* OneTouch 4800 USB */
{ USB_DEVICE(0x04a7, 0x0226) }, /* OneTouch 5800 USB */
{ USB_DEVICE(0x04a7, 0x0229) }, /* OneTouch 7100 USB */
{ USB_DEVICE(0x04a7, 0x022c) }, /* OneTouch 9020 USB */
{ USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
{ USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
{ USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */
{ USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
{ USB_DEVICE(0x0461, 0x0345) }, /* 6200 (actually Primax?) */
{ USB_DEVICE(0x0461, 0x0371) }, /* Onetouch 8920 USB (actually Primax?) */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, scanner_device_ids);
#define IS_EP_BULK(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
#define IS_EP_INTR(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
#define USB_SCN_MINOR(X) iminor(X)
#ifdef DEBUG
#define SCN_DEBUG(X) X
#else
#define SCN_DEBUG(X)
#endif
#define IBUF_SIZE 32768
#define OBUF_SIZE 4096
/* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */
#define RD_EXPIRE 12 /* Number of attempts to wait X seconds */
/* read vendor and product IDs from the scanner */
#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
/* send/recv a control message to the scanner */
#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest)
/* USB bInterfaceClass used by Hewlett-Packard ScanJet 3300c and Genius HR6
USB - Vivid III */
#define SCN_CLASS_SCANJET 16
#define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */
static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
struct scn_usb_data {
struct usb_device *scn_dev;
struct urb *scn_irq;
unsigned int ifnum; /* Interface number of the USB device */
int scn_minor; /* Scanner minor - used in disconnect() */
unsigned char button; /* Front panel buffer */
char isopen; /* Not zero if the device is open */
char present; /* Not zero if device is present */
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
wait_queue_head_t rd_wait_q; /* read timeouts */
struct semaphore sem; /* lock to prevent concurrent reads or writes */
unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
struct kobject kobj; /* Handles our reference counting */
};
#define to_scanner(d) container_of(d, struct scn_usb_data, kobj)
static struct usb_driver scanner_driver;
...@@ -602,14 +602,16 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) ...@@ -602,14 +602,16 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
case 2: case 2:
if ((end - start) < 2) if ((end - start) < 2)
return NULL; return NULL;
item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++)); item->data.u16 = le16_to_cpu(get_unaligned((__u16*)start));
start = (__u8 *)((__u16 *)start + 1);
return start; return start;
case 3: case 3:
item->size++; item->size++;
if ((end - start) < 4) if ((end - start) < 4)
return NULL; return NULL;
item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++)); item->data.u32 = le32_to_cpu(get_unaligned((__u32*)start));
start = (__u8 *)((__u32 *)start + 1);
return start; return start;
} }
......
#include <linux/config.h> #include <linux/config.h>
#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
# define DEBUG
#endif
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <asm/scatterlist.h> #include <asm/scatterlist.h>
#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
# define DEBUG
#endif
#include <linux/usb.h> #include <linux/usb.h>
...@@ -20,10 +21,10 @@ ...@@ -20,10 +21,10 @@
struct usbtest_param { struct usbtest_param {
// inputs // inputs
unsigned test_num; /* 0..(TEST_CASES-1) */ unsigned test_num; /* 0..(TEST_CASES-1) */
int iterations; unsigned iterations;
int length; unsigned length;
int vary; unsigned vary;
int sglen; unsigned sglen;
// outputs // outputs
struct timeval duration; struct timeval duration;
...@@ -48,6 +49,8 @@ struct usbtest_info { ...@@ -48,6 +49,8 @@ struct usbtest_info {
u8 ep_in; /* bulk/intr source */ u8 ep_in; /* bulk/intr source */
u8 ep_out; /* bulk/intr sink */ u8 ep_out; /* bulk/intr sink */
unsigned autoconf : 1; unsigned autoconf : 1;
unsigned ctrl_out : 1;
unsigned iso : 1; /* try iso in/out */
int alt; int alt;
}; };
...@@ -60,9 +63,11 @@ struct usbtest_info { ...@@ -60,9 +63,11 @@ struct usbtest_info {
struct usbtest_dev { struct usbtest_dev {
struct usb_interface *intf; struct usb_interface *intf;
struct usbtest_info *info; struct usbtest_info *info;
char id [32];
int in_pipe; int in_pipe;
int out_pipe; int out_pipe;
int in_iso_pipe;
int out_iso_pipe;
struct usb_endpoint_descriptor *iso_in, *iso_out;
struct semaphore sem; struct semaphore sem;
#define TBUF_SIZE 256 #define TBUF_SIZE 256
...@@ -77,6 +82,31 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test) ...@@ -77,6 +82,31 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
/* set up all urbs so they can be used with either bulk or interrupt */ /* set up all urbs so they can be used with either bulk or interrupt */
#define INTERRUPT_RATE 1 /* msec/transfer */ #define INTERRUPT_RATE 1 /* msec/transfer */
#define xprintk(tdev,level,fmt,args...) \
dev_printk(level , &(tdev)->intf->dev , fmt , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG DBG
#else
#define VDBG(dev,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define WARN(dev,fmt,args...) \
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int static int
...@@ -85,12 +115,14 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) ...@@ -85,12 +115,14 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf)
int tmp; int tmp;
struct usb_host_interface *alt; struct usb_host_interface *alt;
struct usb_host_endpoint *in, *out; struct usb_host_endpoint *in, *out;
struct usb_host_endpoint *iso_in, *iso_out;
struct usb_device *udev; struct usb_device *udev;
for (tmp = 0; tmp < intf->num_altsetting; tmp++) { for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
unsigned ep; unsigned ep;
in = out = 0; in = out = 0;
iso_in = iso_out = 0;
alt = intf->altsetting + tmp; alt = intf->altsetting + tmp;
/* take the first altsetting with in-bulk + out-bulk; /* take the first altsetting with in-bulk + out-bulk;
...@@ -100,8 +132,16 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) ...@@ -100,8 +132,16 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf)
struct usb_host_endpoint *e; struct usb_host_endpoint *e;
e = alt->endpoint + ep; e = alt->endpoint + ep;
if (e->desc.bmAttributes != USB_ENDPOINT_XFER_BULK) switch (e->desc.bmAttributes) {
case USB_ENDPOINT_XFER_BULK:
break;
case USB_ENDPOINT_XFER_ISOC:
if (dev->info->iso)
goto try_iso;
// FALLTHROUGH
default:
continue; continue;
}
if (e->desc.bEndpointAddress & USB_DIR_IN) { if (e->desc.bEndpointAddress & USB_DIR_IN) {
if (!in) if (!in)
in = e; in = e;
...@@ -111,6 +151,17 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) ...@@ -111,6 +151,17 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf)
} }
if (in && out) if (in && out)
goto found; goto found;
continue;
try_iso:
if (e->desc.bEndpointAddress & USB_DIR_IN) {
if (!iso_in)
iso_in = e;
} else {
if (!iso_out)
iso_out = e;
}
if (iso_in && iso_out)
goto found;
} }
} }
return -EINVAL; return -EINVAL;
...@@ -125,10 +176,21 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) ...@@ -125,10 +176,21 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf)
return tmp; return tmp;
} }
dev->in_pipe = usb_rcvbulkpipe (udev, if (in) {
dev->in_pipe = usb_rcvbulkpipe (udev,
in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
dev->out_pipe = usb_sndbulkpipe (udev, dev->out_pipe = usb_sndbulkpipe (udev,
out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
} else if (iso_in) {
dev->iso_in = &iso_in->desc;
dev->in_iso_pipe = usb_rcvisocpipe (udev,
iso_in->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
dev->iso_out = &iso_out->desc;
dev->out_iso_pipe = usb_sndisocpipe (udev,
iso_out->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
}
return 0; return 0;
} }
...@@ -176,6 +238,63 @@ static struct urb *simple_alloc_urb ( ...@@ -176,6 +238,63 @@ static struct urb *simple_alloc_urb (
return urb; return urb;
} }
static unsigned pattern = 0;
module_param (pattern, uint, S_IRUGO);
// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
static inline void simple_fill_buf (struct urb *urb)
{
unsigned i;
u8 *buf = urb->transfer_buffer;
unsigned len = urb->transfer_buffer_length;
switch (pattern) {
default:
// FALLTHROUGH
case 0:
memset (buf, 0, len);
break;
case 1: /* mod63 */
for (i = 0; i < len; i++)
*buf++ = (u8) (i % 63);
break;
}
}
static inline int simple_check_buf (struct urb *urb)
{
unsigned i;
u8 expected;
u8 *buf = urb->transfer_buffer;
unsigned len = urb->actual_length;
for (i = 0; i < len; i++, buf++) {
switch (pattern) {
/* all-zeroes has no synchronization issues */
case 0:
expected = 0;
break;
/* mod63 stays in sync with short-terminated transfers,
* or otherwise when host and gadget agree on how large
* each usb transfer request should be. resync is done
* with set_interface or set_config.
*/
case 1: /* mod63 */
expected = i % 63;
break;
/* always fail unsupported patterns */
default:
expected = !*buf;
break;
}
if (*buf == expected)
continue;
dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
return -EINVAL;
}
return 0;
}
static void simple_free_urb (struct urb *urb) static void simple_free_urb (struct urb *urb)
{ {
usb_buffer_free (urb->dev, urb->transfer_buffer_length, usb_buffer_free (urb->dev, urb->transfer_buffer_length,
...@@ -186,7 +305,9 @@ static void simple_free_urb (struct urb *urb) ...@@ -186,7 +305,9 @@ static void simple_free_urb (struct urb *urb)
static int simple_io ( static int simple_io (
struct urb *urb, struct urb *urb,
int iterations, int iterations,
int vary int vary,
int expected,
const char *label
) )
{ {
struct usb_device *udev = urb->dev; struct usb_device *udev = urb->dev;
...@@ -197,6 +318,8 @@ static int simple_io ( ...@@ -197,6 +318,8 @@ static int simple_io (
urb->context = &completion; urb->context = &completion;
while (retval == 0 && iterations-- > 0) { while (retval == 0 && iterations-- > 0) {
init_completion (&completion); init_completion (&completion);
if (usb_pipeout (urb->pipe))
simple_fill_buf (urb);
if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0)
break; break;
...@@ -204,6 +327,8 @@ static int simple_io ( ...@@ -204,6 +327,8 @@ static int simple_io (
wait_for_completion (&completion); wait_for_completion (&completion);
retval = urb->status; retval = urb->status;
urb->dev = udev; urb->dev = udev;
if (retval == 0 && usb_pipein (urb->pipe))
retval = simple_check_buf (urb);
if (vary) { if (vary) {
int len = urb->transfer_buffer_length; int len = urb->transfer_buffer_length;
...@@ -219,14 +344,14 @@ static int simple_io ( ...@@ -219,14 +344,14 @@ static int simple_io (
} }
urb->transfer_buffer_length = max; urb->transfer_buffer_length = max;
// FIXME for unlink or fault handling tests, don't report if (expected != retval)
// failure if retval is as we expected ... dev_dbg (&udev->dev,
if (retval) "%s failed, iterations left %d, status %d (not %d)\n",
dbg ("simple_io failed, iterations left %d, status %d", label, iterations, retval, expected);
iterations, retval);
return retval; return retval;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* We use scatterlist primitives to test queued I/O. /* We use scatterlist primitives to test queued I/O.
...@@ -360,54 +485,18 @@ static int get_altsetting (struct usbtest_dev *dev) ...@@ -360,54 +485,18 @@ static int get_altsetting (struct usbtest_dev *dev)
} }
} }
/* this is usb_set_interface(), with no 'only one altsetting' case */
static int set_altsetting (struct usbtest_dev *dev, int alternate) static int set_altsetting (struct usbtest_dev *dev, int alternate)
{ {
struct usb_interface *iface = dev->intf; struct usb_interface *iface = dev->intf;
struct usb_device *udev; struct usb_device *udev;
struct usb_host_interface *iface_as;
int i, ret;
if (alternate < 0 || alternate >= iface->num_altsetting) if (alternate < 0 || alternate >= iface->num_altsetting)
return -EINVAL; return -EINVAL;
udev = interface_to_usbdev (iface); udev = interface_to_usbdev (iface);
if ((ret = usb_control_msg (udev, usb_sndctrlpipe (udev, 0), return usb_set_interface (udev,
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, iface->altsetting [0].desc.bInterfaceNumber,
alternate, alternate);
iface->altsetting->desc.bInterfaceNumber,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
return ret;
// FIXME usbcore should be more like this:
// - remove that special casing in usbcore.
// - fix usbcore signature to take interface
/* prevent requests using previous endpoint settings */
iface_as = iface->altsetting + iface->act_altsetting;
for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
u8 ep = iface_as->endpoint [i].desc.bEndpointAddress;
int out = !(ep & USB_DIR_IN);
ep &= USB_ENDPOINT_NUMBER_MASK;
(out ? udev->epmaxpacketout : udev->epmaxpacketin ) [ep] = 0;
// FIXME want hcd hook here, "forget this endpoint"
}
iface->act_altsetting = alternate;
/* reset toggles and maxpacket for all endpoints affected */
iface_as = iface->altsetting + iface->act_altsetting;
for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
u8 ep = iface_as->endpoint [i].desc.bEndpointAddress;
int out = !(ep & USB_DIR_IN);
ep &= USB_ENDPOINT_NUMBER_MASK;
usb_settoggle (udev, ep, out, 0);
(out ? udev->epmaxpacketout : udev->epmaxpacketin ) [ep]
= iface_as->endpoint [i].desc.wMaxPacketSize;
}
return 0;
} }
static int is_good_config (char *buf, int len) static int is_good_config (char *buf, int len)
...@@ -421,15 +510,19 @@ static int is_good_config (char *buf, int len) ...@@ -421,15 +510,19 @@ static int is_good_config (char *buf, int len)
switch (config->bDescriptorType) { switch (config->bDescriptorType) {
case USB_DT_CONFIG: case USB_DT_CONFIG:
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_OTHER_SPEED_CONFIG:
if (config->bLength != 9) if (config->bLength != 9) {
dbg ("bogus config descriptor length");
return 0; return 0;
}
/* this bit 'must be 1' but often isn't */ /* this bit 'must be 1' but often isn't */
if (!realworld && !(config->bmAttributes & 0x80)) { if (!realworld && !(config->bmAttributes & 0x80)) {
dbg ("high bit of config attributes not set"); dbg ("high bit of config attributes not set");
return 0; return 0;
} }
if (config->bmAttributes & 0x1f) /* reserved == 0 */ if (config->bmAttributes & 0x1f) { /* reserved == 0 */
dbg ("reserved config bits set");
return 0; return 0;
}
break; break;
default: default:
return 0; return 0;
...@@ -438,7 +531,10 @@ static int is_good_config (char *buf, int len) ...@@ -438,7 +531,10 @@ static int is_good_config (char *buf, int len)
le16_to_cpus (&config->wTotalLength); le16_to_cpus (&config->wTotalLength);
if (config->wTotalLength == len) /* read it all */ if (config->wTotalLength == len) /* read it all */
return 1; return 1;
return config->wTotalLength >= TBUF_SIZE; /* max partial read */ if (config->wTotalLength >= TBUF_SIZE) /* max partial read */
return 1;
dbg ("bogus config descriptor read size");
return 0;
} }
/* sanity test for standard requests working with usb_control_mesg() and some /* sanity test for standard requests working with usb_control_mesg() and some
...@@ -471,8 +567,9 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -471,8 +567,9 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* they're ordered meaningfully in this array * they're ordered meaningfully in this array
*/ */
if (iface->altsetting [i].desc.bAlternateSetting != i) { if (iface->altsetting [i].desc.bAlternateSetting != i) {
dbg ("%s, invalid alt [%d].bAltSetting = %d", dev_dbg (&iface->dev,
dev->id, i, "invalid alt [%d].bAltSetting = %d\n",
i,
iface->altsetting [i].desc iface->altsetting [i].desc
.bAlternateSetting); .bAlternateSetting);
return -EDOM; return -EDOM;
...@@ -485,16 +582,16 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -485,16 +582,16 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.10] set_interface */ /* [9.4.10] set_interface */
retval = set_altsetting (dev, i); retval = set_altsetting (dev, i);
if (retval) { if (retval) {
dbg ("%s can't set_interface = %d, %d", dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
dev->id, i, retval); i, retval);
return retval; return retval;
} }
/* [9.4.4] get_interface always works */ /* [9.4.4] get_interface always works */
retval = get_altsetting (dev); retval = get_altsetting (dev);
if (retval != i) { if (retval != i) {
dbg ("%s get alt should be %d, was %d", dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
dev->id, i, retval); i, retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
...@@ -513,7 +610,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -513,7 +610,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DIR_IN | USB_RECIP_DEVICE, USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT); 0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) { if (retval != 1 || dev->buf [0] != expected) {
dbg ("%s get config --> %d (%d)", dev->id, retval, dev_dbg (&iface->dev,
"get config --> %d (%d)\n", retval,
expected); expected);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
...@@ -523,7 +621,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -523,7 +621,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0, retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
dev->buf, sizeof udev->descriptor); dev->buf, sizeof udev->descriptor);
if (retval != sizeof udev->descriptor) { if (retval != sizeof udev->descriptor) {
dbg ("%s dev descriptor --> %d", dev->id, retval); dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
...@@ -532,8 +630,9 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -532,8 +630,9 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev, USB_DT_CONFIG, i, retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
dev->buf, TBUF_SIZE); dev->buf, TBUF_SIZE);
if (!is_good_config (dev->buf, retval)) { if (!is_good_config (dev->buf, retval)) {
dbg ("%s config [%d] descriptor --> %d", dev_dbg (&iface->dev,
dev->id, i, retval); "config [%d] descriptor --> %d\n",
i, retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
...@@ -551,13 +650,14 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -551,13 +650,14 @@ static int ch9_postconfig (struct usbtest_dev *dev)
sizeof (struct usb_qualifier_descriptor)); sizeof (struct usb_qualifier_descriptor));
if (retval == -EPIPE) { if (retval == -EPIPE) {
if (udev->speed == USB_SPEED_HIGH) { if (udev->speed == USB_SPEED_HIGH) {
dbg ("%s hs dev qualifier --> %d", dev_dbg (&iface->dev,
dev->id, retval); "hs dev qualifier --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
/* usb2.0 but not high-speed capable; fine */ /* usb2.0 but not high-speed capable; fine */
} else if (retval != sizeof (struct usb_qualifier_descriptor)) { } else if (retval != sizeof (struct usb_qualifier_descriptor)) {
dbg ("%s dev qualifier --> %d", dev->id, retval); dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} else } else
d = (struct usb_qualifier_descriptor *) dev->buf; d = (struct usb_qualifier_descriptor *) dev->buf;
...@@ -570,8 +670,9 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -570,8 +670,9 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DT_OTHER_SPEED_CONFIG, i, USB_DT_OTHER_SPEED_CONFIG, i,
dev->buf, TBUF_SIZE); dev->buf, TBUF_SIZE);
if (!is_good_config (dev->buf, retval)) { if (!is_good_config (dev->buf, retval)) {
dbg ("%s other speed config --> %d", dev_dbg (&iface->dev,
dev->id, retval); "other speed config --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
} }
...@@ -582,7 +683,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -582,7 +683,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.5] get_status always works */ /* [9.4.5] get_status always works */
retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf); retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
if (retval != 2) { if (retval != 2) {
dbg ("%s get dev status --> %d", dev->id, retval); dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
...@@ -592,7 +693,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -592,7 +693,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_status (udev, USB_RECIP_INTERFACE, retval = usb_get_status (udev, USB_RECIP_INTERFACE,
iface->altsetting [0].desc.bInterfaceNumber, dev->buf); iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
if (retval != 2) { if (retval != 2) {
dbg ("%s get interface status --> %d", dev->id, retval); dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM; return (retval < 0) ? retval : -EDOM;
} }
// FIXME get status for each endpoint in the interface // FIXME get status for each endpoint in the interface
...@@ -606,7 +707,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -606,7 +707,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* (a) queues work for control, keeping N subtests queued and * (a) queues work for control, keeping N subtests queued and
* active (auto-resubmit) for M loops through the queue. * active (auto-resubmit) for M loops through the queue.
* (b) protocol stalls (control-only) will autorecover. * (b) protocol stalls (control-only) will autorecover.
* it's quite not like bulk/intr; no halt clearing. * it's not like bulk/intr; no halt clearing.
* (c) short control reads are reported and handled. * (c) short control reads are reported and handled.
* (d) queues are always processed in-order * (d) queues are always processed in-order
*/ */
...@@ -654,6 +755,7 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs) ...@@ -654,6 +755,7 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
dbg ("subcase %d completed out of order, last %d", dbg ("subcase %d completed out of order, last %d",
subcase->number, ctx->last); subcase->number, ctx->last);
status = -EDOM; status = -EDOM;
ctx->last = subcase->number;
goto error; goto error;
} }
} }
...@@ -995,6 +1097,368 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) ...@@ -995,6 +1097,368 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int verify_not_halted (int ep, struct urb *urb)
{
int retval;
u16 status;
/* shouldn't look or act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
return retval;
}
if (status != 0) {
dbg ("ep %02x bogus status: %04x != 0", ep, status);
return -EINVAL;
}
retval = simple_io (urb, 1, 0, 0, __FUNCTION__);
if (retval != 0)
return -EINVAL;
return 0;
}
static int verify_halted (int ep, struct urb *urb)
{
int retval;
u16 status;
/* should look and act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
dbg ("ep %02x couldn't get halt status, %d", ep, retval);
return retval;
}
if (status != 1) {
dbg ("ep %02x bogus status: %04x != 1", ep, status);
return -EINVAL;
}
retval = simple_io (urb, 1, 0, -EPIPE, __FUNCTION__);
if (retval != -EPIPE)
return -EINVAL;
retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
if (retval != -EPIPE)
return -EINVAL;
return 0;
}
static int test_halt (int ep, struct urb *urb)
{
int retval;
/* shouldn't look or act halted now */
retval = verify_not_halted (ep, urb);
if (retval < 0)
return retval;
/* set halt (protocol test only), verify it worked */
retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, 0, ep,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
dbg ("ep %02x couldn't set halt, %d", ep, retval);
return retval;
}
retval = verify_halted (ep, urb);
if (retval < 0)
return retval;
/* clear halt (tests API + protocol), verify it worked */
retval = usb_clear_halt (urb->dev, urb->pipe);
if (retval < 0) {
dbg ("ep %02x couldn't clear halt, %d", ep, retval);
return retval;
}
retval = verify_not_halted (ep, urb);
if (retval < 0)
return retval;
/* NOTE: could also verify SET_INTERFACE clear halts ... */
return 0;
}
static int halt_simple (struct usbtest_dev *dev)
{
int ep;
int retval = 0;
struct urb *urb;
urb = simple_alloc_urb (testdev_to_usbdev (dev), 0, 512);
if (urb == 0)
return -ENOMEM;
if (dev->in_pipe) {
ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
urb->pipe = dev->in_pipe;
retval = test_halt (ep, urb);
if (retval < 0)
goto done;
}
if (dev->out_pipe) {
ep = usb_pipeendpoint (dev->out_pipe);
urb->pipe = dev->out_pipe;
retval = test_halt (ep, urb);
}
done:
simple_free_urb (urb);
return retval;
}
/*-------------------------------------------------------------------------*/
/* Control OUT tests use the vendor control requests from Intel's
* USB 2.0 compliance test device: write a buffer, read it back.
*
* Intel's spec only _requires_ that it work for one packet, which
* is pretty weak. Some HCDs place limits here; most devices will
* need to be able to handle more than one OUT data packet. We'll
* try whatever we're told to try.
*/
static int ctrl_out (struct usbtest_dev *dev,
unsigned count, unsigned length, unsigned vary)
{
unsigned i, j, len, retval;
u8 *buf;
char *what = "?";
struct usb_device *udev;
if (length > 0xffff || vary >= length)
return -EINVAL;
buf = kmalloc(length, SLAB_KERNEL);
if (!buf)
return -ENOMEM;
udev = testdev_to_usbdev (dev);
len = length;
retval = 0;
/* NOTE: hardware might well act differently if we pushed it
* with lots back-to-back queued requests.
*/
for (i = 0; i < count; i++) {
/* write patterned data */
for (j = 0; j < len; j++)
buf [j] = i + j;
retval = usb_control_msg (udev, usb_sndctrlpipe (udev,0),
0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
0, 0, buf, len, HZ * USB_CTRL_SET_TIMEOUT);
if (retval != len) {
what = "write";
break;
}
/* read it back -- assuming nothing intervened!! */
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev,0),
0x5c, USB_DIR_IN|USB_TYPE_VENDOR,
0, 0, buf, len, HZ * USB_CTRL_GET_TIMEOUT);
if (retval != len) {
what = "read";
break;
}
/* fail if we can't verify */
for (j = 0; j < len; j++) {
if (buf [j] != (u8) (i + j)) {
INFO (dev, "ctrl_out, byte %d is %d not %d\n",
j, buf [j], (u8) i + j);
retval = -EBADMSG;
break;
}
}
if (retval < 0) {
what = "verify";
break;
}
len += vary;
if (len > length)
len = 0;
}
if (retval < 0)
INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
what, retval, i);
kfree (buf);
return retval;
}
/*-------------------------------------------------------------------------*/
/* ISO tests ... mimics common usage
* - buffer length is split into N packets (mostly maxpacket sized)
* - multi-buffers according to sglen
*/
struct iso_context {
unsigned count;
unsigned pending;
spinlock_t lock;
struct completion done;
unsigned long errors;
struct usbtest_dev *dev;
};
static void iso_callback (struct urb *urb, struct pt_regs *regs)
{
struct iso_context *ctx = urb->context;
spin_lock(&ctx->lock);
ctx->count--;
if (urb->error_count > 0)
ctx->errors += urb->error_count;
if (urb->status == 0 && ctx->count > (ctx->pending - 1)) {
int status = usb_submit_urb (urb, GFP_ATOMIC);
switch (status) {
case 0:
goto done;
default:
dev_dbg (&ctx->dev->intf->dev,
"iso resubmit err %d\n",
status);
/* FALLTHROUGH */
case -ENODEV: /* disconnected */
break;
}
}
simple_free_urb (urb);
ctx->pending--;
if (ctx->pending == 0) {
if (ctx->errors)
dev_dbg (&ctx->dev->intf->dev,
"iso test, %lu errors\n",
ctx->errors);
complete (&ctx->done);
} else
done:
spin_unlock(&ctx->lock);
}
static struct urb *iso_alloc_urb (
struct usb_device *udev,
int pipe,
struct usb_endpoint_descriptor *desc,
long bytes
)
{
struct urb *urb;
unsigned i, maxp, packets;
if (bytes < 0 || !desc)
return 0;
maxp = 0x7ff & desc->wMaxPacketSize;
maxp *= 1 + (0x3 & (desc->wMaxPacketSize >> 11));
packets = (bytes + maxp - 1) / maxp;
urb = usb_alloc_urb (packets, SLAB_KERNEL);
if (!urb)
return urb;
urb->dev = udev;
urb->pipe = pipe;
urb->number_of_packets = packets;
urb->transfer_buffer_length = bytes;
urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL,
&urb->transfer_dma);
if (!urb->transfer_buffer) {
usb_free_urb (urb);
return 0;
}
memset (urb->transfer_buffer, 0, bytes);
for (i = 0; i < packets; i++) {
/* here, only the last packet will be short */
urb->iso_frame_desc[i].length = min ((unsigned) bytes, maxp);
bytes -= urb->iso_frame_desc[i].length;
urb->iso_frame_desc[i].offset = maxp * i;
}
urb->complete = iso_callback;
// urb->context = SET BY CALLER
urb->interval = 1 << (desc->bInterval - 1);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
return urb;
}
static int
test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
int pipe, struct usb_endpoint_descriptor *desc)
{
struct iso_context context;
struct usb_device *udev;
unsigned i;
unsigned long packets = 0;
int status;
struct urb *urbs[10]; /* FIXME no limit */
if (param->sglen > 10)
return -EDOM;
context.count = param->iterations * param->sglen;
context.pending = param->sglen;
context.errors = 0;
context.dev = dev;
init_completion (&context.done);
spin_lock_init (&context.lock);
memset (urbs, 0, sizeof urbs);
udev = testdev_to_usbdev (dev);
dev_dbg (&dev->intf->dev,
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
desc->wMaxPacketSize);
for (i = 0; i < param->sglen; i++) {
urbs [i] = iso_alloc_urb (udev, pipe, desc,
param->length);
if (!urbs [i]) {
status = -ENOMEM;
goto fail;
}
packets += urbs[i]->number_of_packets;
urbs [i]->context = &context;
}
packets *= param->iterations;
dev_dbg (&dev->intf->dev,
"... total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
packets);
spin_lock_irq (&context.lock);
for (i = 0; i < param->sglen; i++) {
status = usb_submit_urb (urbs [i], SLAB_ATOMIC);
if (status < 0) {
ERROR (dev, "submit iso[%d], error %d\n", i, status);
if (i == 0)
goto fail;
simple_free_urb (urbs [i]);
context.pending--;
}
}
spin_unlock_irq (&context.lock);
wait_for_completion (&context.done);
return 0;
fail:
for (i = 0; i < param->sglen; i++) {
if (urbs [i])
simple_free_urb (urbs [i]);
}
return status;
}
/*-------------------------------------------------------------------------*/
/* We only have this one interface to user space, through usbfs. /* We only have this one interface to user space, through usbfs.
* User mode code can scan usbfs to find N different devices (maybe on * User mode code can scan usbfs to find N different devices (maybe on
* different busses) to use when testing, and allocate one thread per * different busses) to use when testing, and allocate one thread per
...@@ -1047,8 +1511,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1047,8 +1511,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
} }
res = set_altsetting (dev, dev->info->alt); res = set_altsetting (dev, dev->info->alt);
if (res) { if (res) {
err ("%s: set altsetting to %d failed, %d", dev_err (&intf->dev,
dev->id, dev->info->alt, res); "set altsetting to %d failed, %d\n",
dev->info->alt, res);
up (&dev->sem); up (&dev->sem);
return res; return res;
} }
...@@ -1067,7 +1532,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1067,7 +1532,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
switch (param->test_num) { switch (param->test_num) {
case 0: case 0:
dbg ("%s TEST 0: NOP", dev->id); dev_dbg (&intf->dev, "TEST 0: NOP\n");
retval = 0; retval = 0;
break; break;
...@@ -1075,7 +1540,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1075,7 +1540,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 1: case 1:
if (dev->out_pipe == 0) if (dev->out_pipe == 0)
break; break;
dbg ("%s TEST 1: write %d bytes %u times", dev->id, dev_dbg (&intf->dev,
"TEST 1: write %d bytes %u times\n",
param->length, param->iterations); param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length); urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
if (!urb) { if (!urb) {
...@@ -1083,13 +1549,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1083,13 +1549,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break; break;
} }
// FIRMWARE: bulk sink (maybe accepts short writes) // FIRMWARE: bulk sink (maybe accepts short writes)
retval = simple_io (urb, param->iterations, 0); retval = simple_io (urb, param->iterations, 0, 0, "test1");
simple_free_urb (urb); simple_free_urb (urb);
break; break;
case 2: case 2:
if (dev->in_pipe == 0) if (dev->in_pipe == 0)
break; break;
dbg ("%s TEST 2: read %d bytes %u times", dev->id, dev_dbg (&intf->dev,
"TEST 2: read %d bytes %u times\n",
param->length, param->iterations); param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length); urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
if (!urb) { if (!urb) {
...@@ -1097,13 +1564,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1097,13 +1564,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break; break;
} }
// FIRMWARE: bulk source (maybe generates short writes) // FIRMWARE: bulk source (maybe generates short writes)
retval = simple_io (urb, param->iterations, 0); retval = simple_io (urb, param->iterations, 0, 0, "test2");
simple_free_urb (urb); simple_free_urb (urb);
break; break;
case 3: case 3:
if (dev->out_pipe == 0 || param->vary == 0) if (dev->out_pipe == 0 || param->vary == 0)
break; break;
dbg ("%s TEST 3: write/%d 0..%d bytes %u times", dev->id, dev_dbg (&intf->dev,
"TEST 3: write/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations); param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length); urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
if (!urb) { if (!urb) {
...@@ -1111,13 +1579,15 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1111,13 +1579,15 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break; break;
} }
// FIRMWARE: bulk sink (maybe accepts short writes) // FIRMWARE: bulk sink (maybe accepts short writes)
retval = simple_io (urb, param->iterations, param->vary); retval = simple_io (urb, param->iterations, param->vary,
0, "test3");
simple_free_urb (urb); simple_free_urb (urb);
break; break;
case 4: case 4:
if (dev->in_pipe == 0 || param->vary == 0) if (dev->in_pipe == 0 || param->vary == 0)
break; break;
dbg ("%s TEST 4: read/%d 0..%d bytes %u times", dev->id, dev_dbg (&intf->dev,
"TEST 4: read/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations); param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length); urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
if (!urb) { if (!urb) {
...@@ -1125,7 +1595,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1125,7 +1595,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break; break;
} }
// FIRMWARE: bulk source (maybe generates short writes) // FIRMWARE: bulk source (maybe generates short writes)
retval = simple_io (urb, param->iterations, param->vary); retval = simple_io (urb, param->iterations, param->vary,
0, "test4");
simple_free_urb (urb); simple_free_urb (urb);
break; break;
...@@ -1133,8 +1604,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1133,8 +1604,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 5: case 5:
if (dev->out_pipe == 0 || param->sglen == 0) if (dev->out_pipe == 0 || param->sglen == 0)
break; break;
dbg ("%s TEST 5: write %d sglists, %d entries of %d bytes", dev_dbg (&intf->dev,
dev->id, param->iterations, "TEST 5: write %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length); param->sglen, param->length);
sg = alloc_sglist (param->sglen, param->length, 0); sg = alloc_sglist (param->sglen, param->length, 0);
if (!sg) { if (!sg) {
...@@ -1150,8 +1622,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1150,8 +1622,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 6: case 6:
if (dev->in_pipe == 0 || param->sglen == 0) if (dev->in_pipe == 0 || param->sglen == 0)
break; break;
dbg ("%s TEST 6: read %d sglists, %d entries of %d bytes", dev_dbg (&intf->dev,
dev->id, param->iterations, "TEST 6: read %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length); param->sglen, param->length);
sg = alloc_sglist (param->sglen, param->length, 0); sg = alloc_sglist (param->sglen, param->length, 0);
if (!sg) { if (!sg) {
...@@ -1166,8 +1639,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1166,8 +1639,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 7: case 7:
if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0) if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
break; break;
dbg ("%s TEST 7: write/%d %d sglists, %d entries 0..%d bytes", dev_dbg (&intf->dev,
dev->id, param->vary, param->iterations, "TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length); param->sglen, param->length);
sg = alloc_sglist (param->sglen, param->length, param->vary); sg = alloc_sglist (param->sglen, param->length, param->vary);
if (!sg) { if (!sg) {
...@@ -1182,8 +1656,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1182,8 +1656,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 8: case 8:
if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0) if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
break; break;
dbg ("%s TEST 8: read/%d %d sglists, %d entries 0..%d bytes", dev_dbg (&intf->dev,
dev->id, param->vary, param->iterations, "TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length); param->sglen, param->length);
sg = alloc_sglist (param->sglen, param->length, param->vary); sg = alloc_sglist (param->sglen, param->length, param->vary);
if (!sg) { if (!sg) {
...@@ -1199,8 +1674,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1199,8 +1674,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
/* non-queued sanity tests for control (chapter 9 subset) */ /* non-queued sanity tests for control (chapter 9 subset) */
case 9: case 9:
retval = 0; retval = 0;
dbg ("%s TEST 9: ch9 (subset) control tests, %d times", dev_dbg (&intf->dev,
dev->id, param->iterations); "TEST 9: ch9 (subset) control tests, %d times\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */) for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = ch9_postconfig (dev); retval = ch9_postconfig (dev);
if (retval) if (retval)
...@@ -1212,8 +1688,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1212,8 +1688,9 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (param->sglen == 0) if (param->sglen == 0)
break; break;
retval = 0; retval = 0;
dbg ("%s TEST 10: queue %d control calls, %d times", dev_dbg (&intf->dev,
dev->id, param->sglen, "TEST 10: queue %d control calls, %d times\n",
param->sglen,
param->iterations); param->iterations);
retval = test_ctrl_queue (dev, param); retval = test_ctrl_queue (dev, param);
break; break;
...@@ -1223,10 +1700,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1223,10 +1700,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->in_pipe == 0 || !param->length) if (dev->in_pipe == 0 || !param->length)
break; break;
retval = 0; retval = 0;
dbg ("%s TEST 11: unlink %d reads of %d", dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n",
dev->id, param->iterations, param->length); param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */) for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe, param->length); retval = unlink_simple (dev, dev->in_pipe,
param->length);
if (retval) if (retval)
dbg ("unlink reads failed, iterations left %d", i); dbg ("unlink reads failed, iterations left %d", i);
break; break;
...@@ -1234,14 +1712,65 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1234,14 +1712,65 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->out_pipe == 0 || !param->length) if (dev->out_pipe == 0 || !param->length)
break; break;
retval = 0; retval = 0;
dbg ("%s TEST 12: unlink %d writes of %d", dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n",
dev->id, param->iterations, param->length); param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */) for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe, param->length); retval = unlink_simple (dev, dev->out_pipe,
param->length);
if (retval) if (retval)
dbg ("unlink writes failed, iterations left %d", i); dbg ("unlink writes failed, iterations left %d", i);
break; break;
/* ep halt tests */
case 13:
if (dev->out_pipe == 0 && dev->in_pipe == 0)
break;
retval = 0;
dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = halt_simple (dev);
if (retval)
DBG (dev, "halts failed, iterations left %d\n", i);
break;
/* control write tests */
case 14:
if (!dev->info->ctrl_out)
break;
dev_dbg (&intf->dev, "TEST 14: %d ep0out, 0..%d vary %d\n",
param->iterations, param->length, param->vary);
retval = ctrl_out (dev, param->iterations,
param->length, param->vary);
break;
/* iso write tests */
case 15:
if (dev->out_iso_pipe == 0 || param->sglen == 0)
break;
dev_dbg (&intf->dev,
"TEST 15: write %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
// FIRMWARE: iso sink
retval = test_iso_queue (dev, param,
dev->out_iso_pipe, dev->iso_out);
break;
/* iso read tests */
case 16:
if (dev->in_iso_pipe == 0 || param->sglen == 0)
break;
dev_dbg (&intf->dev,
"TEST 16: read %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
// FIRMWARE: iso source
retval = test_iso_queue (dev, param,
dev->in_iso_pipe, dev->iso_in);
break;
// FIXME unlink from queue (ring with N urbs) // FIXME unlink from queue (ring with N urbs)
// FIXME scatterlist cancel (needs helper thread) // FIXME scatterlist cancel (needs helper thread)
...@@ -1262,7 +1791,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -1262,7 +1791,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
static int force_interrupt = 0; static int force_interrupt = 0;
MODULE_PARM (force_interrupt, "i"); MODULE_PARM (force_interrupt, "i");
MODULE_PARM_DESC (force_interrupt, "0 = test bulk (default), else interrupt"); MODULE_PARM_DESC (force_interrupt, "0 = test default; else interrupt");
#ifdef GENERIC #ifdef GENERIC
static int vendor; static int vendor;
...@@ -1281,6 +1810,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1281,6 +1810,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
struct usbtest_dev *dev; struct usbtest_dev *dev;
struct usbtest_info *info; struct usbtest_info *info;
char *rtest, *wtest; char *rtest, *wtest;
char *irtest, *iwtest;
udev = interface_to_usbdev (intf); udev = interface_to_usbdev (intf);
...@@ -1306,10 +1836,6 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1306,10 +1836,6 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
dev->info = info; dev->info = info;
init_MUTEX (&dev->sem); init_MUTEX (&dev->sem);
/* use the same kind of id the hid driver shows */
snprintf (dev->id, sizeof dev->id, "%s-%s:%d",
udev->bus->bus_name, udev->devpath,
intf->altsetting [0].desc.bInterfaceNumber);
dev->intf = intf; dev->intf = intf;
/* cacheline-aligned scratch for i/o */ /* cacheline-aligned scratch for i/o */
...@@ -1323,6 +1849,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1323,6 +1849,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
* "high bandwidth" modes (up to 3 packets/uframe). * "high bandwidth" modes (up to 3 packets/uframe).
*/ */
rtest = wtest = ""; rtest = wtest = "";
irtest = iwtest = "";
if (force_interrupt || udev->speed == USB_SPEED_LOW) { if (force_interrupt || udev->speed == USB_SPEED_LOW) {
if (info->ep_in) { if (info->ep_in) {
dev->in_pipe = usb_rcvintpipe (udev, info->ep_in); dev->in_pipe = usb_rcvintpipe (udev, info->ep_in);
...@@ -1341,6 +1868,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1341,6 +1868,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
dbg ("couldn't get endpoints, %d\n", status); dbg ("couldn't get endpoints, %d\n", status);
return status; return status;
} }
/* may find bulk or ISO pipes */
} else { } else {
if (info->ep_in) if (info->ep_in)
dev->in_pipe = usb_rcvbulkpipe (udev, dev->in_pipe = usb_rcvbulkpipe (udev,
...@@ -1353,18 +1881,26 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1353,18 +1881,26 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
rtest = " bulk-in"; rtest = " bulk-in";
if (dev->out_pipe) if (dev->out_pipe)
wtest = " bulk-out"; wtest = " bulk-out";
if (dev->in_iso_pipe)
irtest = " iso-in";
if (dev->out_iso_pipe)
iwtest = " iso-out";
} }
usb_set_intfdata (intf, dev); usb_set_intfdata (intf, dev);
info ("%s at %s ... %s speed {control%s%s} tests", dev_info (&intf->dev, "%s\n", info->name);
info->name, dev->id, dev_info (&intf->dev, "%s speed {control%s%s%s%s%s} tests%s\n",
({ char *tmp; ({ char *tmp;
switch (udev->speed) { switch (udev->speed) {
case USB_SPEED_LOW: tmp = "low"; break; case USB_SPEED_LOW: tmp = "low"; break;
case USB_SPEED_FULL: tmp = "full"; break; case USB_SPEED_FULL: tmp = "full"; break;
case USB_SPEED_HIGH: tmp = "high"; break; case USB_SPEED_HIGH: tmp = "high"; break;
default: tmp = "unknown"; break; default: tmp = "unknown"; break;
}; tmp; }), rtest, wtest); }; tmp; }),
info->ctrl_out ? " in/out" : "",
rtest, wtest,
irtest, iwtest,
info->alt >= 0 ? " (+alt)" : "");
return 0; return 0;
} }
...@@ -1375,7 +1911,7 @@ static void usbtest_disconnect (struct usb_interface *intf) ...@@ -1375,7 +1911,7 @@ static void usbtest_disconnect (struct usb_interface *intf)
down (&dev->sem); down (&dev->sem);
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
info ("unbound %s", dev->id); dev_dbg (&intf->dev, "disconnect\n");
kfree (dev); kfree (dev);
} }
...@@ -1423,6 +1959,7 @@ static struct usbtest_info fw_info = { ...@@ -1423,6 +1959,7 @@ static struct usbtest_info fw_info = {
static struct usbtest_info gz_info = { static struct usbtest_info gz_info = {
.name = "Linux gadget zero", .name = "Linux gadget zero",
.autoconf = 1, .autoconf = 1,
.ctrl_out = 1,
.alt = 0, .alt = 0,
}; };
...@@ -1432,6 +1969,13 @@ static struct usbtest_info um_info = { ...@@ -1432,6 +1969,13 @@ static struct usbtest_info um_info = {
.alt = -1, .alt = -1,
}; };
static struct usbtest_info um2_info = {
.name = "Linux user mode ISO test driver",
.autoconf = 1,
.iso = 1,
.alt = -1,
};
#ifdef IBOT2 #ifdef IBOT2
/* this is a nice source of high speed bulk data; /* this is a nice source of high speed bulk data;
* uses an FX2, with firmware provided in the device * uses an FX2, with firmware provided in the device
...@@ -1502,6 +2046,11 @@ static struct usb_device_id id_table [] = { ...@@ -1502,6 +2046,11 @@ static struct usb_device_id id_table [] = {
.driver_info = (unsigned long) &um_info, .driver_info = (unsigned long) &um_info,
}, },
/* ... and a user-mode variant that talks iso */
{ USB_DEVICE (0x0525, 0xa4a3),
.driver_info = (unsigned long) &um2_info,
},
#ifdef KEYSPAN_19Qi #ifdef KEYSPAN_19Qi
/* Keyspan 19qi uses an21xx (original EZ-USB) */ /* Keyspan 19qi uses an21xx (original EZ-USB) */
// this does not coexist with the real Keyspan 19qi driver! // this does not coexist with the real Keyspan 19qi driver!
......
...@@ -333,7 +333,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t ...@@ -333,7 +333,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t
for (; got < length; got++) { for (; got < length; got++) {
if (get_1284_register(pp, 4, (char *)buf)) if (get_1284_register(pp, 4, (char *)buf))
break; break;
((char*)buf)++; buf++;
if (priv->reg[0] & 0x01) { if (priv->reg[0] & 0x01) {
clear_epp_timeout(pp); clear_epp_timeout(pp);
break; break;
...@@ -392,7 +392,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t ...@@ -392,7 +392,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t
for (; got < length; got++) { for (; got < length; got++) {
if (get_1284_register(pp, 3, (char *)buf)) if (get_1284_register(pp, 3, (char *)buf))
break; break;
((char*)buf)++; buf++;
if (priv->reg[0] & 0x01) { if (priv->reg[0] & 0x01) {
clear_epp_timeout(pp); clear_epp_timeout(pp);
break; break;
...@@ -412,7 +412,7 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, ...@@ -412,7 +412,7 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf,
for (; written < length; written++) { for (; written < length; written++) {
if (set_1284_register(pp, 3, *(char *)buf)) if (set_1284_register(pp, 3, *(char *)buf))
break; break;
((char*)buf)++; buf++;
if (get_1284_register(pp, 1, NULL)) if (get_1284_register(pp, 1, NULL))
break; break;
if (priv->reg[0] & 0x01) { if (priv->reg[0] & 0x01) {
...@@ -469,7 +469,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff ...@@ -469,7 +469,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff
for (; written < len; written++) { for (; written < len; written++) {
if (set_1284_register(pp, 5, *(char *)buffer)) if (set_1284_register(pp, 5, *(char *)buffer))
break; break;
((char*)buffer)++; buffer++;
} }
change_mode(pp, ECR_PS2); change_mode(pp, ECR_PS2);
return written; return written;
......
...@@ -254,13 +254,14 @@ config USB_AX8817X ...@@ -254,13 +254,14 @@ config USB_AX8817X
10/100 Ethernet devices. 10/100 Ethernet devices.
This driver should work with at least the following devices: This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172 * ASIX AX88172
* D-Link DUB-E100 * D-Link DUB-E100
* Hawking UF200 * Hawking UF200
* Linksys USB200M * Linksys USB200M
* Netgear FA120 * Netgear FA120
* Intellinet * Intellinet USB 2.0 Ethernet
* ST Lab USB Ethernet * ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100 * TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on This driver creates an interface named "ethX", where X depends on
......
...@@ -222,6 +222,7 @@ struct driver_info { ...@@ -222,6 +222,7 @@ struct driver_info {
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ #define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ #define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ #define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ #define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ #define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
...@@ -300,7 +301,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); ...@@ -300,7 +301,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct ethtool_ops usbnet_ethtool_ops;
static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
static u32 usbnet_get_link (struct net_device *); static u32 usbnet_get_link (struct net_device *);
static u32 usbnet_get_msglevel (struct net_device *); static u32 usbnet_get_msglevel (struct net_device *);
...@@ -364,6 +364,25 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf) ...@@ -364,6 +364,25 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf)
return 0; return 0;
} }
static void skb_return (struct usbnet *dev, struct sk_buff *skb)
{
int status;
skb->dev = dev->net;
skb->protocol = eth_type_trans (skb, dev->net);
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
#ifdef VERBOSE
devdbg (dev, "< rx, len %d, type 0x%x",
skb->len + sizeof (struct ethhdr), skb->protocol);
#endif
memset (skb->cb, 0, sizeof (struct skb_data));
status = netif_rx (skb);
if (status != NET_RX_SUCCESS)
devdbg (dev, "netif_rx status %d", status);
}
#ifdef CONFIG_USB_AN2720 #ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE #define HAVE_HARDWARE
...@@ -818,23 +837,30 @@ static const struct driver_info belkin_info = { ...@@ -818,23 +837,30 @@ static const struct driver_info belkin_info = {
#if defined (CONFIG_USB_CDCETHER) || defined (CONFIG_USB_ZAURUS)
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* Communications Device Class, Ethernet Control model * Communications Device Class declarations.
* * Used by CDC Ethernet, and some CDC variants
* Takes two interfaces. The DATA interface is inactive till an altsetting
* is selected. Configuration data includes class descriptors.
*
* Zaurus uses nonstandard framing, and doesn't uniquify its Ethernet
* addresses, but is otherwise CDC Ether.
*
* This should interop with whatever the 2.4 "CDCEther.c" driver
* (by Brad Hards) talked with.
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_CDCETHER
#define NEED_GENERIC_CDC
#endif
#ifdef CONFIG_USB_ZAURUS
/* Ethernet variant uses funky framing, broken ethernet addressing */
#define NEED_GENERIC_CDC
#endif
#ifdef CONFIG_USB_RNDIS
/* ACM variant uses even funkier framing, complex control RPC scheme */
#define NEED_GENERIC_CDC
#endif
#ifdef NEED_GENERIC_CDC
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ /* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct header_desc { struct header_desc {
u8 bLength; u8 bLength;
...@@ -876,43 +902,21 @@ struct cdc_state { ...@@ -876,43 +902,21 @@ struct cdc_state {
struct usb_interface *data; struct usb_interface *data;
}; };
#include <linux/ctype.h>
static u8 nibble (unsigned char c)
{
if (likely (isdigit (c)))
return c - '0';
c = toupper (c);
if (likely (isxdigit (c)))
return 10 + c - 'A';
return 0;
}
static inline int get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
{
int tmp, i;
unsigned char buf [13];
tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
if (tmp < 0)
return tmp;
else if (tmp != 12)
return -EINVAL;
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
(nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);
return 0;
}
static struct usb_driver usbnet_driver; static struct usb_driver usbnet_driver;
static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) /*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
* all pure cdc, except for certain firmware workarounds.
*/
static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
{ {
u8 *buf = intf->altsetting->extra; u8 *buf = intf->altsetting->extra;
int len = intf->altsetting->extralen; int len = intf->altsetting->extralen;
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data; struct cdc_state *info = (void *) &dev->data;
int status; int status;
int rndis;
if (sizeof dev->data < sizeof *info) if (sizeof dev->data < sizeof *info)
return -EDOM; return -EDOM;
...@@ -931,14 +935,23 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -931,14 +935,23 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
"CDC descriptors on config\n"); "CDC descriptors on config\n");
} }
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
rndis = (intf->altsetting->desc.bInterfaceProtocol == 0xff);
memset (info, 0, sizeof *info); memset (info, 0, sizeof *info);
info->control = intf; info->control = intf;
while (len > 3) { while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE) if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc; goto next_desc;
/* bDescriptorSubType identifies three "must have" descriptors; /* use bDescriptorSubType to identify the CDC descriptors.
* save them for later. * We expect devices with CDC header and union descriptors.
* For CDC Ethernet we need the ethernet descriptor.
* For RNDIS, ignore two (pointless) CDC modem descriptors
* in favor of a complicated OID-based RPC scheme doing what
* CDC Ethernet achieves with a simple descriptor.
*/ */
switch (buf [2]) { switch (buf [2]) {
case 0x00: /* Header, mostly useless */ case 0x00: /* Header, mostly useless */
...@@ -1001,8 +1014,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1001,8 +1014,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
d->bInterfaceClass); d->bInterfaceClass);
goto bad_desc; goto bad_desc;
} }
if (usb_interface_claimed (info->data))
return -EBUSY;
break; break;
case 0x0F: /* Ethernet Networking */ case 0x0F: /* Ethernet Networking */
if (info->ether) { if (info->ether) {
...@@ -1015,13 +1026,20 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1015,13 +1026,20 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
info->u->bLength); info->u->bLength);
goto bad_desc; goto bad_desc;
} }
dev->net->mtu = cpu_to_le16p (
&info->ether->wMaxSegmentSize)
- ETH_HLEN;
/* because of Zaurus, we may be ignoring the host
* side link address we were given.
*/
break; break;
} }
next_desc: next_desc:
len -= buf [0]; /* bLength */ len -= buf [0]; /* bLength */
buf += buf [0]; buf += buf [0];
} }
if (!info->header || !info ->u || !info->ether) {
if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n", dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ", info->header ? "" : "header ",
info->u ? "" : "union ", info->u ? "" : "union ",
...@@ -1029,18 +1047,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1029,18 +1047,6 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
goto bad_desc; goto bad_desc;
} }
#ifdef CONFIG_USB_ZAURUS
/* Zaurus ethernet addresses aren't unique ... */
if ((dev->driver_info->flags & FLAG_FRAMING_Z) != 0)
/* ignore */ ;
else
#endif
{
status = get_ethernet_addr (dev, info->ether);
if (status < 0)
return status;
}
/* claim data interface and set it up ... with side effects. /* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled. * network traffic can't flow until an altsetting is enabled.
*/ */
...@@ -1049,16 +1055,11 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1049,16 +1055,11 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
return status; return status;
status = get_endpoints (dev, info->data); status = get_endpoints (dev, info->data);
if (status < 0) { if (status < 0) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data); usb_driver_release_interface (&usbnet_driver, info->data);
return status; return status;
} }
/* FIXME cdc-ether has some multicast code too, though it complains
* in routine cases. info->ether describes the multicast support.
*/
dev->net->mtu = cpu_to_le16p (&info->ether->wMaxSegmentSize)
- ETH_HLEN;
return 0; return 0;
bad_desc: bad_desc:
...@@ -1072,24 +1073,89 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) ...@@ -1072,24 +1073,89 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf)
/* disconnect master --> disconnect slave */ /* disconnect master --> disconnect slave */
if (intf == info->control && info->data) { if (intf == info->control && info->data) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data); usb_driver_release_interface (&usbnet_driver, info->data);
info->data = 0; info->data = 0;
} }
/* and vice versa (just in case) */ /* and vice versa (just in case) */
else if (intf == info->data && info->control) { else if (intf == info->data && info->control) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->control, NULL);
usb_driver_release_interface (&usbnet_driver, info->control); usb_driver_release_interface (&usbnet_driver, info->control);
info->control = 0; info->control = 0;
} }
} }
#endif /* CONFIG_USB_ZAURUS || CONFIG_USB_CDCETHER */ #endif /* NEED_GENERIC_CDC */
#ifdef CONFIG_USB_CDCETHER #ifdef CONFIG_USB_CDCETHER
#define HAVE_HARDWARE #define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* Communications Device Class, Ethernet Control model
*
* Takes two interfaces. The DATA interface is inactive till an altsetting
* is selected. Configuration data includes class descriptors.
*
* This should interop with whatever the 2.4 "CDCEther.c" driver
* (by Brad Hards) talked with.
*
*-------------------------------------------------------------------------*/
#include <linux/ctype.h>
static u8 nibble (unsigned char c)
{
if (likely (isdigit (c)))
return c - '0';
c = toupper (c);
if (likely (isxdigit (c)))
return 10 + c - 'A';
return 0;
}
static inline int
get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
{
int tmp, i;
unsigned char buf [13];
tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
if (tmp < 0)
return tmp;
else if (tmp != 12)
return -EINVAL;
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
(nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);
return 0;
}
static int cdc_bind (struct usbnet *dev, struct usb_interface *intf)
{
int status;
struct cdc_state *info = (void *) &dev->data;
status = generic_cdc_bind (dev, intf);
if (status < 0)
return status;
status = get_ethernet_addr (dev, info->ether);
if (status < 0) {
usb_driver_release_interface (&usbnet_driver, info->data);
return status;
}
/* FIXME cdc-ether has some multicast code too, though it complains
* in routine cases. info->ether describes the multicast support.
*/
return 0;
}
static const struct driver_info cdc_info = { static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device", .description = "CDC Ethernet Device",
.flags = FLAG_ETHER, .flags = FLAG_ETHER,
...@@ -1337,7 +1403,6 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1337,7 +1403,6 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
struct gl_header *header; struct gl_header *header;
struct gl_packet *packet; struct gl_packet *packet;
struct sk_buff *gl_skb; struct sk_buff *gl_skb;
int status;
u32 size; u32 size;
header = (struct gl_header *) skb->data; header = (struct gl_header *) skb->data;
...@@ -1373,17 +1438,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1373,17 +1438,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
// copy the packet data to the new skb // copy the packet data to the new skb
memcpy(skb_put(gl_skb, size), packet->packet_data, size); memcpy(skb_put(gl_skb, size), packet->packet_data, size);
gl_skb->dev = dev->net; skb_return (dev, skb);
// determine the packet's protocol ID
gl_skb->protocol = eth_type_trans (gl_skb, dev->net);
// update the status
dev->stats.rx_packets++;
dev->stats.rx_bytes += size;
// notify os of the received packet
status = netif_rx (gl_skb);
} }
// advance to the next packet // advance to the next packet
...@@ -2141,7 +2196,7 @@ static const struct driver_info zaurus_sl5x00_info = { ...@@ -2141,7 +2196,7 @@ static const struct driver_info zaurus_sl5x00_info = {
.description = "Sharp Zaurus SL-5x00", .description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z, .flags = FLAG_FRAMING_Z,
.check_connect = always_connected, .check_connect = always_connected,
.bind = cdc_bind, .bind = generic_cdc_bind,
.unbind = cdc_unbind, .unbind = cdc_unbind,
.tx_fixup = zaurus_tx_fixup, .tx_fixup = zaurus_tx_fixup,
}; };
...@@ -2255,6 +2310,11 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -2255,6 +2310,11 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
if (dev->driver_info->flags & FLAG_FRAMING_Z) if (dev->driver_info->flags & FLAG_FRAMING_Z)
size = 6 + (sizeof (struct ethhdr) + dev->net->mtu); size = 6 + (sizeof (struct ethhdr) + dev->net->mtu);
else else
#endif
#ifdef CONFIG_USB_RNDIS
if (dev->driver_info->flags & FLAG_FRAMING_RN)
size = RNDIS_MAX_TRANSFER;
else
#endif #endif
size = (sizeof (struct ethhdr) + dev->net->mtu); size = (sizeof (struct ethhdr) + dev->net->mtu);
...@@ -2319,23 +2379,9 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) ...@@ -2319,23 +2379,9 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
goto error; goto error;
// else network stack removes extra byte if we forced a short packet // else network stack removes extra byte if we forced a short packet
if (skb->len) { if (skb->len)
int status; skb_return (dev, skb);
else {
skb->dev = dev->net;
skb->protocol = eth_type_trans (skb, dev->net);
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
#ifdef VERBOSE
devdbg (dev, "< rx, len %d, type 0x%x",
skb->len + sizeof (struct ethhdr), skb->protocol);
#endif
memset (skb->cb, 0, sizeof (struct skb_data));
status = netif_rx (skb);
if (status != NET_RX_SUCCESS)
devdbg (dev, "netif_rx status %d", status);
} else {
devdbg (dev, "drop"); devdbg (dev, "drop");
error: error:
dev->stats.rx_errors++; dev->stats.rx_errors++;
...@@ -2544,6 +2590,8 @@ static int usbnet_open (struct net_device *net) ...@@ -2544,6 +2590,8 @@ static int usbnet_open (struct net_device *net)
framing = "GeneSys"; framing = "GeneSys";
else if (dev->driver_info->flags & FLAG_FRAMING_Z) else if (dev->driver_info->flags & FLAG_FRAMING_Z)
framing = "Zaurus"; framing = "Zaurus";
else if (dev->driver_info->flags & FLAG_FRAMING_RN)
framing = "RNDIS";
else else
framing = "simple"; framing = "simple";
...@@ -2941,6 +2989,8 @@ static void usbnet_disconnect (struct usb_interface *intf) ...@@ -2941,6 +2989,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct ethtool_ops usbnet_ethtool_ops;
// precondition: never called in_interrupt // precondition: never called in_interrupt
int int
...@@ -3127,7 +3177,11 @@ static const struct usb_device_id products [] = { ...@@ -3127,7 +3177,11 @@ static const struct usb_device_id products [] = {
// Hawking UF200, TrendNet TU2-ET100 // Hawking UF200, TrendNet TU2-ET100
USB_DEVICE (0x07b8, 0x420a), USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info, .driver_info = (unsigned long) &hawking_uf200_info,
}, }, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
.driver_info = (unsigned long) &ax8817x_info,
},
#endif #endif
#ifdef CONFIG_USB_EPSON2888 #ifdef CONFIG_USB_EPSON2888
...@@ -3167,6 +3221,14 @@ static const struct usb_device_id products [] = { ...@@ -3167,6 +3221,14 @@ static const struct usb_device_id products [] = {
}, },
#endif #endif
#ifdef CONFIG_USB_RNDIS
{
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO (USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
},
#endif
#ifdef CONFIG_USB_ARMLINUX #ifdef CONFIG_USB_ARMLINUX
/* /*
* SA-1100 using standard ARM Linux kernels, or compatible. * SA-1100 using standard ARM Linux kernels, or compatible.
...@@ -3238,7 +3300,16 @@ static const struct usb_device_id products [] = { ...@@ -3238,7 +3300,16 @@ static const struct usb_device_id products [] = {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE, | USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD, .idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 */ .idProduct = 0x9031, /* C-750 C-760 */
.bInterfaceClass = 0x02,
.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 = 0x9032, /* SL-6000 */
.bInterfaceClass = 0x02, .bInterfaceClass = 0x02,
.bInterfaceSubClass = 0x0a, .bInterfaceSubClass = 0x0a,
.bInterfaceProtocol = 0x00, .bInterfaceProtocol = 0x00,
......
...@@ -232,8 +232,10 @@ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp) ...@@ -232,8 +232,10 @@ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) if (retval) {
usb_unlink_urb(port->read_urb);
err(" usb_submit_urb(read int) failed"); err(" usb_submit_urb(read int) failed");
}
exit: exit:
return retval; return retval;
......
...@@ -409,8 +409,6 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs) ...@@ -409,8 +409,6 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
// someone sets the dev to 0 if the close method has been called // someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
// usb_dump_urb(port->interrupt_in_urb);
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
} }
...@@ -496,8 +494,6 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -496,8 +494,6 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
// start reading // start reading
//usb_dump_urb(port->interrupt_in_urb);
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
} }
......
...@@ -241,6 +241,8 @@ static struct usb_device_id id_table [] = { ...@@ -241,6 +241,8 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ }, /* optional parameter entry */ { }, /* optional parameter entry */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -274,6 +276,7 @@ static struct usb_device_id id_table_combined [] = { ...@@ -274,6 +276,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_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_SCH_I330_ID) },
{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
{ }, /* optional parameter entry */ { }, /* optional parameter entry */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -50,6 +50,9 @@ ...@@ -50,6 +50,9 @@
#define GARMIN_VENDOR_ID 0x091E #define GARMIN_VENDOR_ID 0x091E
#define GARMIN_IQUE_3600_ID 0x0004 #define GARMIN_IQUE_3600_ID 0x0004
#define ACEECA_VENDOR_ID 0x4766
#define ACEECA_MEZ1000_ID 0x0001
/**************************************************************************** /****************************************************************************
* Handspring Visor Vendor specific request codes (bRequest values) * Handspring Visor Vendor specific request codes (bRequest values)
* A big thank you to Handspring for providing the following information. * A big thank you to Handspring for providing the following information.
......
...@@ -29,7 +29,7 @@ extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); ...@@ -29,7 +29,7 @@ extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us);
struct datafab_info { struct datafab_info {
unsigned long sectors; // total sector count unsigned long sectors; // total sector count
unsigned long ssize; // sector size in bytes unsigned long ssize; // sector size in bytes
char lun; // used for dual-slot readers signed char lun; // used for dual-slot readers
// the following aren't used yet // the following aren't used yet
unsigned char sense_key; unsigned char sense_key;
......
...@@ -604,7 +604,14 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, ...@@ -604,7 +604,14 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff,
* - They don't like the INQUIRY command. So we must handle this command * - They don't like the INQUIRY command. So we must handle this command
* of the SCSI layer ourselves. * of the SCSI layer ourselves.
*/ */
UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999, UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
"Casio",
"QV DigitalCamera",
US_SC_8070, US_PR_CB, NULL,
US_FL_FIX_INQUIRY ),
/* Later Casio cameras apparently tell the truth */
UNUSUAL_DEV( 0x07cf, 0x1001, 0x9010, 0x9999,
"Casio", "Casio",
"QV DigitalCamera", "QV DigitalCamera",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
......
...@@ -834,7 +834,7 @@ void usb_stor_release_resources(struct us_data *us) ...@@ -834,7 +834,7 @@ void usb_stor_release_resources(struct us_data *us)
/* Finish the SCSI host removal sequence */ /* Finish the SCSI host removal sequence */
if (us->host) { if (us->host) {
(struct us_data *) us->host->hostdata[0] = NULL; us->host->hostdata[0] = 0;
scsi_host_put(us->host); scsi_host_put(us->host);
} }
......
...@@ -1016,16 +1016,6 @@ static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int en ...@@ -1016,16 +1016,6 @@ static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int en
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/*
* Debugging and troubleshooting/diagnostic helpers.
*/
void usb_show_device_descriptor(struct usb_device_descriptor *);
void usb_show_config_descriptor(struct usb_config_descriptor *);
void usb_show_interface_descriptor(struct usb_interface_descriptor *);
void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
void usb_show_device(struct usb_device *);
void usb_show_string(struct usb_device *dev, char *id, int index);
#ifdef DEBUG #ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg) #define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg)
#else #else
......
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