Commit 20b397bb authored by Linus Torvalds's avatar Linus Torvalds

Merge

parents 46b11ba9 fb6d52e5
...@@ -212,6 +212,14 @@ config NET_ETHERNET ...@@ -212,6 +212,14 @@ config NET_ETHERNET
kernel: saying N will just cause the configurator to skip all kernel: saying N will just cause the configurator to skip all
the questions about Ethernet network cards. If unsure, say N. the questions about Ethernet network cards. If unsure, say N.
config MII
tristate "generic Media Independent Interface device support"
depends on NET_ETHERNET
help
Most ethernet controllers have MII transceiver either as an external
or internal device. It is safe to say Y or M here even if your
ethernet card lack MII.
config ARM_AM79C961A config ARM_AM79C961A
bool "ARM EBSA110 AM79C961A support" bool "ARM EBSA110 AM79C961A support"
depends on NET_ETHERNET && ARM && ARCH_EBSA110 depends on NET_ETHERNET && ARM && ARCH_EBSA110
......
...@@ -57,6 +57,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o ...@@ -57,6 +57,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
# end link order section # end link order section
# #
obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_AIRONET4500) += aironet4500_core.o obj-$(CONFIG_AIRONET4500) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o
...@@ -193,3 +194,6 @@ obj-$(CONFIG_NET_WIRELESS) += wireless/ ...@@ -193,3 +194,6 @@ obj-$(CONFIG_NET_WIRELESS) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_IRDA) += irda/
include $(TOPDIR)/drivers/usb/net/Makefile.mii
...@@ -257,7 +257,7 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) ...@@ -257,7 +257,7 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
if (urb->status) if (urb->status)
dbg("nonzero read bulk status received: %d", urb->status); dbg("nonzero read bulk status received: %d", urb->status);
if (!urb->status & !acm->throttle) { if (!urb->status && !acm->throttle) {
for (i = 0; i < urb->actual_length && !acm->throttle; i++) { for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, /* if we insert more than TTY_FLIPBUF_SIZE characters,
* we drop them. */ * we drop them. */
...@@ -697,6 +697,7 @@ static void acm_disconnect(struct usb_interface *intf) ...@@ -697,6 +697,7 @@ static void acm_disconnect(struct usb_interface *intf)
static struct usb_device_id acm_ids[] = { static struct usb_device_id acm_ids[] = {
{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) }, { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
{ USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
{ } { }
}; };
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
static char *format_topo = static char *format_topo =
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */ /* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
"T: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n"; "\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
static char *format_string_manufacturer = static char *format_string_manufacturer =
/* S: Manufacturer=xxxx */ /* S: Manufacturer=xxxx */
......
...@@ -310,9 +310,9 @@ static int rh_string ( ...@@ -310,9 +310,9 @@ static int rh_string (
} else } else
return 0; return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2); data [0] = 2 * (strlen (buf) + 1);
data [1] = 3; /* type == string */ data [1] = 3; /* type == string */
return data [0]; return 2 + ascii2utf (buf, data + 2, len - 2);
} }
...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
return status; return status;
} }
/* lower level hcd code should use *_dma exclusively */ /* lower level hcd code should use *_dma exclusively,
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { * unless it uses pio or talks to another transport.
*/
if (!(urb->transfer_flags & URB_NO_DMA_MAP)
&& hcd->controller->dma_mask) {
if (usb_pipecontrol (urb->pipe)) if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single ( urb->setup_dma = dma_map_single (
hcd->controller, hcd->controller,
......
...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
*/ */
}; };
/* 2.4 does this a bit differently ... */
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{
return &hcd->self;
}
struct hcd_dev { /* usb_device.hcpriv points to this */ struct hcd_dev { /* usb_device.hcpriv points to this */
struct list_head dev_list; /* on this hcd */ struct list_head dev_list; /* on this hcd */
struct list_head urb_list; /* pending on this dev */ struct list_head urb_list; /* pending on this dev */
...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *); ...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_dev, extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev); struct device *parent_dev);
/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->controller);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* exported only within usbcore */ /* exported only within usbcore */
......
...@@ -206,6 +206,7 @@ static void sg_clean (struct usb_sg_request *io) ...@@ -206,6 +206,7 @@ static void sg_clean (struct usb_sg_request *io)
kfree (io->urbs); kfree (io->urbs);
io->urbs = 0; io->urbs = 0;
} }
if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0; io->dev = 0;
} }
...@@ -301,6 +302,7 @@ int usb_sg_init ( ...@@ -301,6 +302,7 @@ int usb_sg_init (
{ {
int i; int i;
int urb_flags; int urb_flags;
int dma;
if (!io || !dev || !sg if (!io || !dev || !sg
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
...@@ -314,8 +316,16 @@ int usb_sg_init ( ...@@ -314,8 +316,16 @@ int usb_sg_init (
io->sg = sg; io->sg = sg;
io->nents = nents; io->nents = nents;
/* initialize all the urbs we'll use */ /* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
dma = (dev->dev.dma_mask != 0);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
io->entries = nents;
/* initialize all the urbs we'll use */
if (io->entries <= 0) if (io->entries <= 0)
return io->entries; return io->entries;
...@@ -347,8 +357,17 @@ int usb_sg_init ( ...@@ -347,8 +357,17 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS; io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0; io->urbs [i]->actual_length = 0;
if (dma) {
/* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (sg + i); io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i); len = sg_dma_len (sg + i);
} else {
/* hc may use _only_ transfer_buffer */
io->urbs [i]->transfer_buffer =
page_address (sg [i].page) + sg [i].offset;
len = sg [i].length;
}
if (length) { if (length) {
len = min_t (unsigned, len, length); len = min_t (unsigned, len, length);
length -= len; length -= len;
...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
retval = 0; retval = 0;
i--; i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT? // FIXME: should it usb_sg_cancel() on INTERRUPT?
// how about imposing a backoff? yield ();
set_current_state (TASK_UNINTERRUPTIBLE);
schedule ();
break; break;
/* no error? continue immediately. /* no error? continue immediately.
......
...@@ -1224,7 +1224,8 @@ void usb_buffer_free ( ...@@ -1224,7 +1224,8 @@ void usb_buffer_free (
* *
* Return value is either null (indicating no buffer could be mapped), or * Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the
* operation succeeds. * operation succeeds. If the device is connected to this system through
* a non-DMA controller, this operation always succeeds.
* *
* This call would normally be used for an urb which is reused, perhaps * This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync() * as the target of a large periodic transfer, with usb_buffer_dmasync()
...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb) ...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return 0; return 0;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller, urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP; urb->transfer_flags |= URB_NO_DMA_MAP;
return urb; return urb;
} }
...@@ -1271,6 +1275,7 @@ void usb_buffer_dmasync (struct urb *urb) ...@@ -1271,6 +1275,7 @@ void usb_buffer_dmasync (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
if (controller->dma_mask)
dma_sync_single (controller, dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb) ...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
if (controller->dma_mask)
dma_unmap_single (controller, dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
urb->transfer_flags &= ~URB_NO_DMA_MAP;
} }
/** /**
...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, ...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return -1; return -1;
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, ...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_sync_sg (controller, sg, n_hw_ents, dma_sync_sg (controller, sg, n_hw_ents,
...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_unmap_sg (controller, sg, n_hw_ents, dma_unmap_sg (controller, sg, n_hw_ents,
......
...@@ -277,7 +277,26 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } ...@@ -277,7 +277,26 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \ default: tmp = '?'; break; \
}; tmp; }) }; tmp; })
static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) static inline char token_mark (u32 token)
{
token = le32_to_cpu (token);
if (token & QTD_STS_ACTIVE)
return '*';
if (token & QTD_STS_HALT)
return '-';
if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */
|| QTD_LENGTH (token) == 0)
return ' ';
/* tries to advance through hw_alt_next */
return '/';
}
static void qh_lines (
struct ehci_hcd *ehci,
struct ehci_qh *qh,
char **nextp,
unsigned *sizep
)
{ {
u32 scratch; u32 scratch;
u32 hw_curr; u32 hw_curr;
...@@ -286,26 +305,49 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) ...@@ -286,26 +305,49 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
unsigned temp; unsigned temp;
unsigned size = *sizep; unsigned size = *sizep;
char *next = *nextp; char *next = *nextp;
char mark;
mark = token_mark (qh->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
mark = '#'; /* blocked */
else if (qh->hw_alt_next & cpu_to_le32 (0x01))
mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */
}
scratch = cpu_to_le32p (&qh->hw_info1); scratch = cpu_to_le32p (&qh->hw_info1);
hw_curr = cpu_to_le32p (&qh->hw_current); hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0;
temp = snprintf (next, size, temp = snprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)", "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f, qh, scratch & 0x007f,
speed_char (scratch), speed_char (scratch),
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
scratch, cpu_to_le32p (&qh->hw_info2), scratch, cpu_to_le32p (&qh->hw_info2),
hw_curr, cpu_to_le32p (&qh->hw_token)); cpu_to_le32p (&qh->hw_token), mark,
(cpu_to_le32 (0x8000000) & qh->hw_token)
? "data0" : "data1",
(cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f);
size -= temp; size -= temp;
next += temp; next += temp;
/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) { list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list); td = list_entry (entry, struct ehci_qtd, qtd_list);
scratch = cpu_to_le32p (&td->hw_token); scratch = cpu_to_le32p (&td->hw_token);
mark = ' ';
if (hw_curr == td->qtd_dma)
mark = '*';
else if (qh->hw_qtd_next == td->qtd_dma)
mark = '+';
else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next)
mark = '#';
else if (td->hw_alt_next != EHCI_LIST_END)
mark = '/';
}
temp = snprintf (next, size, temp = snprintf (next, size,
"\n\t%std/%p %s len=%d %08x urb %p", "\n\t%p%c%s len=%d %08x urb %p",
(hw_curr == td->qtd_dma) ? "*" : "", td, mark, ({ char *tmp;
td, ({ char *tmp;
switch ((scratch>>8)&0x03) { switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break; case 0: tmp = "out"; break;
case 1: tmp = "in"; break; case 1: tmp = "in"; break;
...@@ -315,13 +357,27 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) ...@@ -315,13 +357,27 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
(scratch >> 16) & 0x7fff, (scratch >> 16) & 0x7fff,
scratch, scratch,
td->urb); td->urb);
if (temp < 0)
temp = 0;
else if (size < temp)
temp = size;
size -= temp; size -= temp;
next += temp; next += temp;
if (temp == size)
goto done;
} }
temp = snprintf (next, size, "\n"); temp = snprintf (next, size, "\n");
*sizep = size - temp; if (temp < 0)
*nextp = next + temp; temp = 0;
else if (size < temp)
temp = size;
size -= temp;
next += temp;
done:
*sizep = size;
*nextp = next;
} }
static ssize_t static ssize_t
...@@ -344,14 +400,15 @@ show_async (struct device *dev, char *buf) ...@@ -344,14 +400,15 @@ show_async (struct device *dev, char *buf)
* one QH per line, and TDs we know about * one QH per line, and TDs we know about
*/ */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh) for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (qh, &next, &size); qh_lines (ehci, qh, &next, &size);
if (ehci->reclaim) { if (ehci->reclaim && size > 0) {
temp = snprintf (next, size, "\nreclaim =\n"); temp = snprintf (next, size, "\nreclaim =\n");
size -= temp; size -= temp;
next += temp; next += temp;
qh_lines (ehci->reclaim, &next, &size); for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
qh_lines (ehci, qh, &next, &size);
} }
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
...@@ -421,7 +478,7 @@ show_periodic (struct device *dev, char *buf) ...@@ -421,7 +478,7 @@ show_periodic (struct device *dev, char *buf)
scratch & 0x007f, scratch & 0x007f,
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
p.qh->usecs, p.qh->c_usecs, p.qh->usecs, p.qh->c_usecs,
scratch >> 16); 0x7ff & (scratch >> 16));
/* FIXME TD info too */ /* FIXME TD info too */
...@@ -490,7 +547,8 @@ show_registers (struct device *dev, char *buf) ...@@ -490,7 +547,8 @@ show_registers (struct device *dev, char *buf)
/* Capability Registers */ /* Capability Registers */
i = readw (&ehci->caps->hci_version); i = readw (&ehci->caps->hci_version);
temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n", temp = snprintf (next, size,
"EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n",
i >> 8, i & 0x0ff, ehci->hcd.state); i >> 8, i & 0x0ff, ehci->hcd.state);
size -= temp; size -= temp;
next += temp; next += temp;
......
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4 * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "2002-Nov-29" #define DRIVER_VERSION "2003-Jan-22"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...@@ -110,10 +110,11 @@ static const char hcd_name [] = "ehci-hcd"; ...@@ -110,10 +110,11 @@ static const char hcd_name [] = "ehci-hcd";
/* magic numbers that can affect system performance */ /* magic numbers that can affect system performance */
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
#define EHCI_TUNE_RL_HS 0 /* nak throttle; see 4.9 */ #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
#define EHCI_TUNE_RL_TT 0 #define EHCI_TUNE_RL_TT 0
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
...@@ -416,13 +417,26 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -416,13 +417,26 @@ static int ehci_start (struct usb_hcd *hcd)
ehci_info (ehci, "enabled 64bit PCI DMA\n"); ehci_info (ehci, "enabled 64bit PCI DMA\n");
} }
/* help hc dma work well with cachelines */
pci_set_mwi (ehci->hcd.pdev);
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
temp = readl (&ehci->regs->command) & 0xff; temp = readl (&ehci->regs->command) & 0xff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6) if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0; log2_irq_thresh = 0;
temp |= 1 << (16 + log2_irq_thresh); temp |= 1 << (16 + log2_irq_thresh);
// if hc can park (ehci >= 0.96), default is 3 packets per async QH // if hc can park (ehci >= 0.96), default is 3 packets per async QH
// keeping default periodic framelist size if (HCC_PGM_FRAMELISTLEN (hcc_params)) {
/* periodic schedule size can be smaller than default */
temp &= ~(3 << 2);
temp |= (EHCI_TUNE_FLS << 2);
switch (EHCI_TUNE_FLS) {
case 0: ehci->periodic_size = 1024; break;
case 1: ehci->periodic_size = 512; break;
case 2: ehci->periodic_size = 256; break;
default: BUG ();
}
}
temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE), temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
// Philips, Intel, and maybe others need CMD_RUN before the // Philips, Intel, and maybe others need CMD_RUN before the
// root hub will detect new devices (why?); NEC doesn't // root hub will detect new devices (why?); NEC doesn't
...@@ -759,7 +773,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -759,7 +773,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh; struct ehci_qh *qh;
unsigned long flags; unsigned long flags;
int maybe_irq = 1;
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
...@@ -769,23 +782,23 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -769,23 +782,23 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv; qh = (struct ehci_qh *) urb->hcpriv;
if (!qh) if (!qh)
break; break;
while (qh->qh_state == QH_STATE_LINKED
/* if we need to use IAA and it's busy, defer */
if (qh->qh_state == QH_STATE_LINKED
&& ehci->reclaim && ehci->reclaim
&& HCD_IS_RUNNING (ehci->hcd.state) && HCD_IS_RUNNING (ehci->hcd.state)
) { ) {
spin_unlock_irqrestore (&ehci->lock, flags); struct ehci_qh *last;
if (maybe_irq) { for (last = ehci->reclaim;
if (in_interrupt ()) last->reclaim;
return -EAGAIN; last = last->reclaim)
maybe_irq = 0; continue;
} qh->qh_state = QH_STATE_UNLINK_WAIT;
/* let pending unlinks complete, so this can start */ last->reclaim = qh;
wait_ms (1);
spin_lock_irqsave (&ehci->lock, flags); /* bypass IAA if the hc can't care */
} } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
end_unlink_async (ehci, NULL); end_unlink_async (ehci, NULL);
/* something else might have unlinked the qh by now */ /* something else might have unlinked the qh by now */
......
...@@ -75,8 +75,6 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) ...@@ -75,8 +75,6 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) { if (qtd != 0) {
ehci_qtd_init (qtd, dma); ehci_qtd_init (qtd, dma);
if (ehci->async)
qtd->hw_alt_next = ehci->async->hw_alt_next;
} }
return qtd; return qtd;
} }
......
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
/* fill a qtd, returning how much of the buffer we were able to queue up */ /* fill a qtd, returning how much of the buffer we were able to queue up */
static int static int
qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token) qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
int token, int maxpacket)
{ {
int i, count; int i, count;
u64 addr = buf; u64 addr = buf;
...@@ -69,6 +70,10 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token) ...@@ -69,6 +70,10 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
else else
count = len; count = len;
} }
/* short packets may only terminate transfers */
if (count != len)
count -= (count % maxpacket);
} }
qtd->hw_token = cpu_to_le32 ((count << 16) | token); qtd->hw_token = cpu_to_le32 ((count << 16) | token);
qtd->length = count; qtd->length = count;
...@@ -85,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) ...@@ -85,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{ {
qh->hw_current = 0; qh->hw_current = 0;
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
qh->hw_alt_next = ehci->async->hw_alt_next; qh->hw_alt_next = EHCI_LIST_END;
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb (); wmb ();
...@@ -96,7 +101,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) ...@@ -96,7 +101,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) #define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
static inline void qtd_copy_status ( static void qtd_copy_status (
struct ehci_hcd *ehci, struct ehci_hcd *ehci,
struct urb *urb, struct urb *urb,
size_t length, size_t length,
...@@ -224,12 +229,24 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -224,12 +229,24 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
{ {
struct ehci_qtd *last = 0, *end = qh->dummy; struct ehci_qtd *last = 0, *end = qh->dummy;
struct list_head *entry, *tmp; struct list_head *entry, *tmp;
int stopped = 0; int stopped;
unsigned count = 0; unsigned count = 0;
int do_status = 0;
u8 state;
if (unlikely (list_empty (&qh->qtd_list))) if (unlikely (list_empty (&qh->qtd_list)))
return count; return count;
/* completions (or tasks on other cpus) must never clobber HALT
* till we've gone through and cleaned everything up, even when
* they add urbs to this qh's queue or mark them for unlinking.
*
* NOTE: unlinking expects to be done in queue order.
*/
state = qh->qh_state;
qh->qh_state = QH_STATE_COMPLETING;
stopped = (state == QH_STATE_IDLE);
/* remove de-activated QTDs from front of queue. /* remove de-activated QTDs from front of queue.
* after faults (including short reads), cleanup this urb * after faults (including short reads), cleanup this urb
* then let the queue advance. * then let the queue advance.
...@@ -261,7 +278,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -261,7 +278,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
rmb (); rmb ();
token = le32_to_cpu (qtd->hw_token); token = le32_to_cpu (qtd->hw_token);
stopped = stopped stopped = stopped
|| (qh->qh_state == QH_STATE_IDLE)
|| (HALT_BIT & qh->hw_token) != 0 || (HALT_BIT & qh->hw_token) != 0
|| (ehci->hcd.state == USB_STATE_HALT); || (ehci->hcd.state == USB_STATE_HALT);
...@@ -271,36 +287,53 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -271,36 +287,53 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
/* magic dummy for short reads; won't advance */ /* magic dummy for short reads; won't advance */
if (IS_SHORT_READ (token) if (IS_SHORT_READ (token)
&& !(token & QTD_STS_HALT) && !(token & QTD_STS_HALT)
&& ehci->async->hw_alt_next && (qh->hw_alt_next & QTD_MASK)
== qh->hw_alt_next) == ehci->async->hw_alt_next) {
stopped = 1;
goto halt; goto halt;
}
/* stop scanning when we reach qtds the hc is using */ /* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped)) { } else if (likely (!stopped)) {
last = 0;
break; break;
} else { } else {
/* ignore active qtds unless some previous qtd /* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or * for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds. * its urb was canceled. we may patch qh or qtds.
*/ */
if ((token & QTD_STS_ACTIVE) if (likely (urb->status == -EINPROGRESS))
&& urb->status == -EINPROGRESS) { continue;
last = 0;
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
do_status = 0;
continue; continue;
} }
/* token in overlay may be most current */
if (state == QH_STATE_IDLE
&& cpu_to_le32 (qtd->qtd_dma)
== qh->hw_current)
token = le32_to_cpu (qh->hw_token);
/* force halt for unlinked or blocked qh, so we'll
* patch the qh later and so that completions can't
* activate it while we "know" it's stopped.
*/
if ((HALT_BIT & qh->hw_token) == 0) { if ((HALT_BIT & qh->hw_token) == 0) {
halt: halt:
qh->hw_token |= HALT_BIT; qh->hw_token |= HALT_BIT;
wmb (); wmb ();
stopped = 1;
} }
} }
/* remove it from the queue */ /* remove it from the queue */
spin_lock (&urb->lock); spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token); qtd_copy_status (ehci, urb, qtd->length, token);
do_status = (urb->status == -EREMOTEIO)
&& usb_pipecontrol (urb->pipe);
spin_unlock (&urb->lock); spin_unlock (&urb->lock);
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
...@@ -319,6 +352,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -319,6 +352,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
ehci_qtd_free (ehci, last); ehci_qtd_free (ehci, last);
} }
/* restore original state; caller must unlink or relink */
qh->qh_state = state;
/* update qh after fault cleanup */ /* update qh after fault cleanup */
if (unlikely ((HALT_BIT & qh->hw_token) != 0)) { if (unlikely ((HALT_BIT & qh->hw_token) != 0)) {
qh_update (ehci, qh, qh_update (ehci, qh,
...@@ -367,7 +403,7 @@ qh_urb_transaction ( ...@@ -367,7 +403,7 @@ qh_urb_transaction (
struct ehci_qtd *qtd, *qtd_prev; struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf; dma_addr_t buf;
int len, maxpacket; int len, maxpacket;
int is_input, status_patch = 0; int is_input;
u32 token; u32 token;
/* /*
...@@ -388,7 +424,7 @@ qh_urb_transaction ( ...@@ -388,7 +424,7 @@ qh_urb_transaction (
if (usb_pipecontrol (urb->pipe)) { if (usb_pipecontrol (urb->pipe)) {
/* SETUP pid */ /* SETUP pid */
qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest), qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
token | (2 /* "setup" */ << 8)); token | (2 /* "setup" */ << 8), 8);
/* ... and always at least one more pid */ /* ... and always at least one more pid */
token ^= QTD_TOGGLE; token ^= QTD_TOGGLE;
...@@ -399,10 +435,6 @@ qh_urb_transaction ( ...@@ -399,10 +435,6 @@ qh_urb_transaction (
qtd->urb = urb; qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head); list_add_tail (&qtd->qtd_list, head);
if (len > 0 && is_input
&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
status_patch = 1;
} }
/* /*
...@@ -413,6 +445,7 @@ qh_urb_transaction ( ...@@ -413,6 +445,7 @@ qh_urb_transaction (
else else
buf = 0; buf = 0;
// FIXME this 'buf' check break some zlps...
if (!buf || is_input) if (!buf || is_input)
token |= (1 /* "in" */ << 8); token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */ /* else it's already initted to "out" pid (0 << 8) */
...@@ -427,9 +460,11 @@ qh_urb_transaction ( ...@@ -427,9 +460,11 @@ qh_urb_transaction (
for (;;) { for (;;) {
int this_qtd_len; int this_qtd_len;
this_qtd_len = qtd_fill (qtd, buf, len, token); this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
len -= this_qtd_len; len -= this_qtd_len;
buf += this_qtd_len; buf += this_qtd_len;
if (is_input)
qtd->hw_alt_next = ehci->async->hw_alt_next;
/* qh makes control packets use qtd toggle; maybe switch it */ /* qh makes control packets use qtd toggle; maybe switch it */
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
...@@ -447,6 +482,13 @@ qh_urb_transaction ( ...@@ -447,6 +482,13 @@ qh_urb_transaction (
list_add_tail (&qtd->qtd_list, head); list_add_tail (&qtd->qtd_list, head);
} }
/* unless the bulk/interrupt caller wants a chance to clean
* up after short reads, hc should advance qh past this urb
*/
if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
|| usb_pipecontrol (urb->pipe)))
qtd->hw_alt_next = EHCI_LIST_END;
/* /*
* control requests may need a terminating data "status" ack; * control requests may need a terminating data "status" ack;
* bulk ones may need a terminating short packet (zero length). * bulk ones may need a terminating short packet (zero length).
...@@ -473,21 +515,8 @@ qh_urb_transaction ( ...@@ -473,21 +515,8 @@ qh_urb_transaction (
list_add_tail (&qtd->qtd_list, head); list_add_tail (&qtd->qtd_list, head);
/* never any data in such packets */ /* never any data in such packets */
qtd_fill (qtd, 0, 0, token); qtd_fill (qtd, 0, 0, token, 0);
}
} }
/* if we're permitting a short control read, we want the hardware to
* just continue after short data and send the status ack. it can do
* that on the last data packet (typically the only one). for other
* packets, software fixup is needed (in qh_completions).
*/
if (status_patch) {
struct ehci_qtd *prev;
prev = list_entry (qtd->qtd_list.prev,
struct ehci_qtd, qtd_list);
prev->hw_alt_next = QTD_NEXT (qtd->qtd_dma);
} }
/* by default, enable interrupt on urb completion */ /* by default, enable interrupt on urb completion */
...@@ -611,6 +640,7 @@ qh_make ( ...@@ -611,6 +640,7 @@ qh_make (
case USB_SPEED_FULL: case USB_SPEED_FULL:
/* EPS 0 means "full" */ /* EPS 0 means "full" */
if (type != PIPE_INTERRUPT)
info1 |= (EHCI_TUNE_RL_TT << 28); info1 |= (EHCI_TUNE_RL_TT << 28);
if (type == PIPE_CONTROL) { if (type == PIPE_CONTROL) {
info1 |= (1 << 27); /* for TT */ info1 |= (1 << 27); /* for TT */
...@@ -628,12 +658,13 @@ qh_make ( ...@@ -628,12 +658,13 @@ qh_make (
case USB_SPEED_HIGH: /* no TT involved */ case USB_SPEED_HIGH: /* no TT involved */
info1 |= (2 << 12); /* EPS "high" */ info1 |= (2 << 12); /* EPS "high" */
info1 |= (EHCI_TUNE_RL_HS << 28);
if (type == PIPE_CONTROL) { if (type == PIPE_CONTROL) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 64 << 16; /* usb2 fixed maxpacket */ info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */ info1 |= 1 << 14; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30); info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (type == PIPE_BULK) { } else if (type == PIPE_BULK) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 512 << 16; /* usb2 fixed maxpacket */ info1 |= 512 << 16; /* usb2 fixed maxpacket */
info2 |= (EHCI_TUNE_MULT_HS << 30); info2 |= (EHCI_TUNE_MULT_HS << 30);
} else { /* PIPE_INTERRUPT */ } else { /* PIPE_INTERRUPT */
...@@ -769,8 +800,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -769,8 +800,7 @@ static struct ehci_qh *qh_append_tds (
&& !usb_pipecontrol (urb->pipe)) { && !usb_pipecontrol (urb->pipe)) {
/* "never happens": drivers do stall cleanup right */ /* "never happens": drivers do stall cleanup right */
if (qh->qh_state != QH_STATE_IDLE if (qh->qh_state != QH_STATE_IDLE
&& (cpu_to_le32 (QTD_STS_HALT) && qh->qh_state != QH_STATE_COMPLETING)
& qh->hw_token) == 0)
ehci_warn (ehci, "clear toggle dev%d " ehci_warn (ehci, "clear toggle dev%d "
"ep%d%s: not idle\n", "ep%d%s: not idle\n",
usb_pipedevice (urb->pipe), usb_pipedevice (urb->pipe),
...@@ -809,7 +839,6 @@ static struct ehci_qh *qh_append_tds ( ...@@ -809,7 +839,6 @@ static struct ehci_qh *qh_append_tds (
__list_splice (qtd_list, qh->qtd_list.prev); __list_splice (qtd_list, qh->qtd_list.prev);
ehci_qtd_init (qtd, qtd->qtd_dma); ehci_qtd_init (qtd, qtd->qtd_dma);
qtd->hw_alt_next = ehci->async->hw_alt_next;
qh->dummy = qtd; qh->dummy = qtd;
/* hc must see the new dummy at list end */ /* hc must see the new dummy at list end */
...@@ -877,9 +906,12 @@ submit_async ( ...@@ -877,9 +906,12 @@ submit_async (
/* the async qh for the qtds being reclaimed are now unlinked from the HC */ /* the async qh for the qtds being reclaimed are now unlinked from the HC */
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
{ {
struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
del_timer (&ehci->watchdog); del_timer (&ehci->watchdog);
...@@ -890,6 +922,10 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -890,6 +922,10 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
ehci->reclaim = 0; ehci->reclaim = 0;
ehci->reclaim_ready = 0; ehci->reclaim_ready = 0;
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
qh->reclaim = 0;
qh_completions (ehci, qh, regs); qh_completions (ehci, qh, regs);
if (!list_empty (&qh->qtd_list) if (!list_empty (&qh->qtd_list)
...@@ -909,6 +945,9 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -909,6 +945,9 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
jiffies + EHCI_ASYNC_JIFFIES); jiffies + EHCI_ASYNC_JIFFIES);
} }
} }
if (next)
start_unlink_async (ehci, next);
} }
/* makes sure the async qh will become idle */ /* makes sure the async qh will become idle */
...@@ -921,7 +960,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -921,7 +960,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
#ifdef DEBUG #ifdef DEBUG
if (ehci->reclaim if (ehci->reclaim
|| qh->qh_state != QH_STATE_LINKED || (qh->qh_state != QH_STATE_LINKED
&& qh->qh_state != QH_STATE_UNLINK_WAIT)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
// this macro lies except on SMP compiles // this macro lies except on SMP compiles
|| !spin_is_locked (&ehci->lock) || !spin_is_locked (&ehci->lock)
...@@ -953,6 +993,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -953,6 +993,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
wmb (); wmb ();
if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
* this will recurse, probably not much
*/
end_unlink_async (ehci, NULL); end_unlink_async (ehci, NULL);
return; return;
} }
......
...@@ -236,12 +236,12 @@ struct ehci_qtd { ...@@ -236,12 +236,12 @@ struct ehci_qtd {
/* the rest is HCD-private */ /* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */ dma_addr_t qtd_dma; /* qtd address */
struct list_head qtd_list; /* sw qtd list */ struct list_head qtd_list; /* sw qtd list */
/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
struct urb *urb; /* qtd's urb */ struct urb *urb; /* qtd's urb */
size_t length; /* length of buffer */ size_t length; /* length of buffer */
} __attribute__ ((aligned (32))); } __attribute__ ((aligned (32)));
#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */ /* type tag from {qh,itd,sitd,fstn}->hw_next */
...@@ -305,6 +305,7 @@ struct ehci_qh { ...@@ -305,6 +305,7 @@ struct ehci_qh {
union ehci_shadow qh_next; /* ptr to qh; or periodic */ union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */ struct list_head qtd_list; /* sw qtd list */
struct ehci_qtd *dummy; struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */
atomic_t refcount; atomic_t refcount;
unsigned stamp; unsigned stamp;
...@@ -313,6 +314,8 @@ struct ehci_qh { ...@@ -313,6 +314,8 @@ struct ehci_qh {
#define QH_STATE_LINKED 1 /* HC sees this */ #define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */ #define QH_STATE_UNLINK 2 /* HC may still see this */
#define QH_STATE_IDLE 3 /* HC doesn't see this */ #define QH_STATE_IDLE 3 /* HC doesn't see this */
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
/* periodic schedule info */ /* periodic schedule info */
u8 usecs; /* intr bandwidth */ u8 usecs; /* intr bandwidth */
...@@ -426,16 +429,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd) ...@@ -426,16 +429,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd)
#else /* LINUX_VERSION_CODE */ #else /* LINUX_VERSION_CODE */
// hcd_to_bus() eventually moves to hcd.h on 2.5 too
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
// ... as does hcd_register_root()
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) #define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG #ifndef DEBUG
......
...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb) ...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb)
if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) { if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
/* URB active? */ /* URB active? */
if (urb->transfer_flags & (URB_ASYNC_UNLINK | URB_TIMEOUT_KILLED)) { if (urb->transfer_flags & URB_ASYNC_UNLINK) {
/* asynchronous with callback */ /* asynchronous with callback */
/* relink the urb to the del list */ /* relink the urb to the del list */
list_move (&urb->urb_list, &hci->del_list); list_move (&urb->urb_list, &hci->del_list);
...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb) ...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb)
struct urb *urb = (struct urb *) lurb; struct urb *urb = (struct urb *) lurb;
DBGFUNC ("enter qu_urb_timeout\n"); DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= URB_TIMEOUT_KILLED;
hci_unlink_urb (urb); hci_unlink_urb (urb);
} }
#endif #endif
......
...@@ -203,26 +203,26 @@ static int ohci_urb_enqueue ( ...@@ -203,26 +203,26 @@ static int ohci_urb_enqueue (
return -ENOMEM; return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
if (ohci->disabled || ohci->sleeping) {
retval = -ENODEV;
goto fail;
}
/* fill the private part of the URB */ /* fill the private part of the URB */
urb_priv->length = size; urb_priv->length = size;
urb_priv->ed = ed; urb_priv->ed = ed;
/* allocate the TDs (updating hash chains) */ /* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC); urb_priv->td [i] = td_alloc (ohci, mem_flags);
if (!urb_priv->td [i]) { if (!urb_priv->td [i]) {
urb_priv->length = i; urb_priv->length = i;
retval = -ENOMEM; urb_free_priv (ohci, urb_priv);
goto fail; return -ENOMEM;
}
} }
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
if (ohci->disabled || ohci->sleeping) {
retval = -ENODEV;
goto fail;
} }
/* schedule the ed if needed */ /* schedule the ed if needed */
......
...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) { if (td) {
int hash;
/* in case hc fetches it, make it look dead */ /* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td); memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma); td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma; td->td_dma = dma;
/* hashed in td_fill */
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (dma);
td->td_hash = hc->td_hash [hash];
hc->td_hash [hash] = td;
} }
return td; return td;
} }
......
...@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
static void static void
td_fill (unsigned int info, td_fill (struct ohci_hcd *ohci, u32 info,
dma_addr_t data, int len, dma_addr_t data, int len,
struct urb *urb, int index) struct urb *urb, int index)
{ {
struct td *td, *td_pt; struct td *td, *td_pt;
struct urb_priv *urb_priv = urb->hcpriv; struct urb_priv *urb_priv = urb->hcpriv;
int is_iso = info & TD_ISO; int is_iso = info & TD_ISO;
int hash;
// ASSERT (index < urb_priv->length); // ASSERT (index < urb_priv->length);
...@@ -516,11 +517,16 @@ td_fill (unsigned int info, ...@@ -516,11 +517,16 @@ td_fill (unsigned int info,
td->hwBE = 0; td->hwBE = 0;
td->hwNextTD = cpu_to_le32 (td_pt->td_dma); td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
/* HC might read the TD right after we link it ... */
wmb ();
/* append to queue */ /* append to queue */
list_add_tail (&td->td_list, &td->ed->td_list); list_add_tail (&td->td_list, &td->ed->td_list);
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (td->td_dma);
td->td_hash = ohci->td_hash [hash];
ohci->td_hash [hash] = td;
/* HC might read the TD (or cachelines) right away ... */
wmb ();
td->ed->hwTailP = td->hwNextTD; td->ed->hwTailP = td->hwNextTD;
} }
...@@ -578,7 +584,7 @@ static void td_submit_urb ( ...@@ -578,7 +584,7 @@ static void td_submit_urb (
: TD_T_TOGGLE | TD_CC | TD_DP_IN; : TD_T_TOGGLE | TD_CC | TD_DP_IN;
/* TDs _could_ transfer up to 8K each */ /* TDs _could_ transfer up to 8K each */
while (data_len > 4096) { while (data_len > 4096) {
td_fill (info, data, 4096, urb, cnt); td_fill (ohci, info, data, 4096, urb, cnt);
data += 4096; data += 4096;
data_len -= 4096; data_len -= 4096;
cnt++; cnt++;
...@@ -586,11 +592,11 @@ static void td_submit_urb ( ...@@ -586,11 +592,11 @@ static void td_submit_urb (
/* maybe avoid ED halt on final TD short read */ /* maybe avoid ED halt on final TD short read */
if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
info |= TD_R; info |= TD_R;
td_fill (info, data, data_len, urb, cnt); td_fill (ohci, info, data, data_len, urb, cnt);
cnt++; cnt++;
if ((urb->transfer_flags & URB_ZERO_PACKET) if ((urb->transfer_flags & URB_ZERO_PACKET)
&& cnt < urb_priv->length) { && cnt < urb_priv->length) {
td_fill (info, 0, 0, urb, cnt); td_fill (ohci, info, 0, 0, urb, cnt);
cnt++; cnt++;
} }
/* maybe kickstart bulk list */ /* maybe kickstart bulk list */
...@@ -605,17 +611,17 @@ static void td_submit_urb ( ...@@ -605,17 +611,17 @@ static void td_submit_urb (
*/ */
case PIPE_CONTROL: case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0; info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
td_fill (info, urb->setup_dma, 8, urb, cnt++); td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);
if (data_len > 0) { if (data_len > 0) {
info = TD_CC | TD_R | TD_T_DATA1; info = TD_CC | TD_R | TD_T_DATA1;
info |= is_out ? TD_DP_OUT : TD_DP_IN; info |= is_out ? TD_DP_OUT : TD_DP_IN;
/* NOTE: mishandles transfers >8K, some >4K */ /* NOTE: mishandles transfers >8K, some >4K */
td_fill (info, data, data_len, urb, cnt++); td_fill (ohci, info, data, data_len, urb, cnt++);
} }
info = is_out info = is_out
? TD_CC | TD_DP_IN | TD_T_DATA1 ? TD_CC | TD_DP_IN | TD_T_DATA1
: TD_CC | TD_DP_OUT | TD_T_DATA1; : TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (info, data, 0, urb, cnt++); td_fill (ohci, info, data, 0, urb, cnt++);
/* maybe kickstart control list */ /* maybe kickstart control list */
wmb (); wmb ();
writel (OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_CLF, &ohci->regs->cmdstatus);
...@@ -634,7 +640,7 @@ static void td_submit_urb ( ...@@ -634,7 +640,7 @@ static void td_submit_urb (
// a 2^16 iso range, vs other HCs max of 2^10) // a 2^16 iso range, vs other HCs max of 2^10)
frame += cnt * urb->interval; frame += cnt * urb->interval;
frame &= 0xffff; frame &= 0xffff;
td_fill (TD_CC | TD_ISO | frame, td_fill (ohci, TD_CC | TD_ISO | frame,
data + urb->iso_frame_desc [cnt].offset, data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt); urb->iso_frame_desc [cnt].length, urb, cnt);
} }
......
...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr) ...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next; tmp = tmp->next;
u->transfer_flags |= URB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u); uhci_urb_dequeue(hcd, u);
} }
......
/* -*- linux-c -*- */ /* -*- linux-c -*- */
/* /*
* Driver for USB Scanners (linux-2.5.54) * Driver for USB Scanners (linux-2.5.60)
* *
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * 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. * Portions may be copyright Brad Keryan and Michael Gee.
* *
* Brian Beattie <beattie@beattie-home.net> * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -300,8 +303,6 @@ ...@@ -300,8 +303,6 @@
* Frank Zago <fzago@greshamstorage.com> and * Frank Zago <fzago@greshamstorage.com> and
* Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing. * Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
* *
* 05/21/02 Currently maintained by Brian Beattie <beattie@beattie-home.net>
*
* 0.4.8 5/30/2002 * 0.4.8 5/30/2002
* - Added Mustek BearPaw 2400 TA. Thanks to Sergey * - Added Mustek BearPaw 2400 TA. Thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>. * Vlasov <vsu@mivlgu.murom.ru>.
...@@ -332,12 +333,18 @@ ...@@ -332,12 +333,18 @@
* <oliver@neukum.name>. * <oliver@neukum.name>.
* *
* 0.4.10 01/07/2003 * 0.4.10 01/07/2003
* - Added vendor/product ids for Visioneer scanners. * - 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 * - Print information about user-supplied ids only once at startup instead
* of everytime any USB device is plugged in. * of everytime any USB device is plugged in.
* - Removed PV8630 ioctls. Use the standard ioctls instead. * - Removed PV8630 ioctls. Use the standard ioctls instead.
* - Made endpoint detection more generic. Basically, only one bulk-in * - Made endpoint detection more generic. Basically, only one bulk-in
* endpoint is required, everything else is optional. * 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.
* *
* TODO * TODO
* - Performance * - Performance
...@@ -360,7 +367,7 @@ ...@@ -360,7 +367,7 @@
* - All the developers that are working on USB SANE backends or other * - All the developers that are working on USB SANE backends or other
* applications to use USB scanners. * applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie * - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* to be the new USB Scanner maintainer. * and Henning Meier-Geinitz to be the new USB Scanner maintainer.
* *
* Performance: * Performance:
* *
...@@ -369,6 +376,14 @@ ...@@ -369,6 +376,14 @@
* 24 Bit Color ~ 70 secs - 3.6 Mbit/sec * 24 Bit Color ~ 70 secs - 3.6 Mbit/sec
* 8 Bit Gray ~ 17 secs - 4.2 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> #include <asm/byteorder.h>
/* /*
...@@ -461,7 +476,7 @@ open_scanner(struct inode * inode, struct file * file) ...@@ -461,7 +476,7 @@ open_scanner(struct inode * inode, struct file * file)
} }
if (scn->isopen) { if (scn->isopen) {
err("open_scanner(%d): Scanner device is already open", scn_minor); dbg("open_scanner(%d): Scanner device is already open", scn_minor);
err = -EBUSY; err = -EBUSY;
goto out_error; goto out_error;
} }
...@@ -1047,6 +1062,9 @@ probe_scanner(struct usb_interface *intf, ...@@ -1047,6 +1062,9 @@ probe_scanner(struct usb_interface *intf,
if (scn->devfs == NULL) if (scn->devfs == NULL)
dbg("scanner%d: device node registration failed", scn_minor); dbg("scanner%d: device node registration failed", scn_minor);
info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
dev->descriptor.idVendor, dev->descriptor.idProduct, name);
up(&scn_mutex); up(&scn_mutex);
usb_set_intfdata(intf, scn); usb_set_intfdata(intf, scn);
......
/* /*
* Driver for USB Scanners (linux-2.5.54) * Driver for USB Scanners (linux-2.5.60)
* *
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Previously maintained by Brian Beattie
* *
* Brian Beattie <beattie@beattie-home.net> * Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -19,11 +20,16 @@ ...@@ -19,11 +20,16 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* 05/21/02 Currently maintained by Brian Beattie <beattie@beattie-home.net>
*
*
*/ */
/*
* 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/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -45,7 +51,7 @@ ...@@ -45,7 +51,7 @@
static __s32 vendor=-1, product=-1, read_timeout=0; static __s32 vendor=-1, product=-1, read_timeout=0;
MODULE_AUTHOR("Brian Beattie, beattie@beattie-home.net"); MODULE_AUTHOR("Henning Meier-Geinitz, henning@meier-geinitz.de");
MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION); MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -65,79 +71,90 @@ MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds"); ...@@ -65,79 +71,90 @@ MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
static struct usb_device_id scanner_device_ids [] = { static struct usb_device_id scanner_device_ids [] = {
/* Acer (now Benq) */ /* Acer (now Benq) */
{ USB_DEVICE(0x04a5, 0x2060) }, /* 620U & 640U (!)*/
{ USB_DEVICE(0x04a5, 0x2040) }, /* 620U (!) */
{ USB_DEVICE(0x04a5, 0x20c0) }, /* 1240UT, 1240U */
{ USB_DEVICE(0x04a5, 0x2022) }, /* 340U */
{ USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */ { USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */
{ USB_DEVICE(0x04a5, 0x1a2a) }, /* Another 620U */ { 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, 0x207e) }, /* 640BU */
{ USB_DEVICE(0x04a5, 0x20b0) }, /* Benq 4300 */
{ USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */ { USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
{ USB_DEVICE(0x04a5, 0x20c0) }, /* 1240UT, 1240U */
{ USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */ { USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
{ USB_DEVICE(0x04a5, 0x20b0) }, /* Benq 4300 */
{ USB_DEVICE(0x04a5, 0x20fe) }, /* Benq 5300 */
{ USB_DEVICE(0x04a5, 0x20fc) }, /* Benq 5000 */ { USB_DEVICE(0x04a5, 0x20fc) }, /* Benq 5000 */
{ USB_DEVICE(0x04a5, 0x20fe) }, /* Benq 5300 */
/* Agfa */ /* Agfa */
{ USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */ { USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
{ USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */ { USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
{ USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
{ USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */ { 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, 0x2091) }, /* SnapScan e20 */
{ USB_DEVICE(0x06bd, 0x2093) }, /* SnapScan e10*/
{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */ { USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */ { USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
{ USB_DEVICE(0x06bd, 0x2093) }, /* SnapScan e10*/
{ USB_DEVICE(0x06bd, 0x20ff) }, /* SnapScan e42*/
{ USB_DEVICE(0x06bd, 0x208f) }, /* SnapScan e50*/
{ USB_DEVICE(0x06bd, 0x20fd) }, /* SnapScan e52*/ { 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) */
/* Benq: see Acer */ /* Benq: see Acer */
/* Canon */ /* Canon */
{ USB_DEVICE(0x04a9, 0x2201) }, /* FB320U */ { USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
{ USB_DEVICE(0x04a9, 0x2205) }, /* FB1210U */
{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */ { USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
{ USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */ { USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */
{ USB_DEVICE(0x04a9, 0x2205) }, /* CanoScan FB1210U */
{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */ { USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */ { USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ { USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */
{ USB_DEVICE(0x04a9, 0x220b) }, /* D646U */ { USB_DEVICE(0x04a9, 0x220b) }, /* CanoScan D646U */
{ USB_DEVICE(0x04a9, 0x220c) }, /* CanoScan D1250U2 */
{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */ { USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */ { USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */ { USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
/* Colorado -- See Primax/Colorado below */ /* Colorado -- See Primax/Colorado below */
/* Compaq */
{ USB_DEVICE(0x049f, 0x0021) }, /* S200 */
/* Epson -- See Seiko/Epson below */ /* Epson -- See Seiko/Epson below */
/* Genius */ /* Genius */
{ USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */ { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage Vivid Pro */
{ USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */ { USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */
{ USB_DEVICE(0x0458, 0x2008) }, /* ColorPage-HR6 V2 */ { USB_DEVICE(0x0458, 0x2008) }, /* ColorPage HR6 V2 */
{ USB_DEVICE(0x0458, 0x2009) }, /* ColorPage-HR6A */ { USB_DEVICE(0x0458, 0x2009) }, /* ColorPage HR6A */
{ USB_DEVICE(0x0458, 0x2011) }, /* ColorPage-Vivid3x */ { USB_DEVICE(0x0458, 0x2011) }, /* ColorPage Vivid3x */
{ USB_DEVICE(0x0458, 0x2013) }, /* ColorPage-HR7 */ { USB_DEVICE(0x0458, 0x2013) }, /* ColorPage HR7 */
{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage-HR7LE */ { USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage-HR6X */ { USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
/* Hewlett Packard */ /* Hewlett Packard */
{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */ { USB_DEVICE(0x03f0, 0x0101) }, /* ScanJet 4100C */
{ USB_DEVICE(0x03f0, 0x0605) }, /* 2200C */
{ USB_DEVICE(0x03f0, 0x0901) }, /* 2300C */
{ USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */
{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
{ USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */
{ USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */
{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */ { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */ { USB_DEVICE(0x03f0, 0x0105) }, /* ScanJet 4200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */ { USB_DEVICE(0x03f0, 0x0201) }, /* ScanJet 6200C */
{ USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */ { USB_DEVICE(0x03f0, 0x0205) }, /* ScanJet 3300C */
{ USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */ { 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, 0x0901) }, /* ScanJet 2300C */
{ USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */
{ USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */
{ USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */
/* iVina */ /* iVina */
{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
/* Lexmark */ /* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */ { USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
/* Lifetec */
{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
/* Memorex */ /* Memorex */
{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */ { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */ /* Microtek */
{ USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */
/* 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, 0x0099) }, /* ScanMaker X6 - X6U */
// { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */ // { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */
// { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */ // { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */
...@@ -146,58 +163,59 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -146,58 +163,59 @@ static struct usb_device_id scanner_device_ids [] = {
// { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */ // { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
// { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */ // { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
/* Minolta */ /* Minolta */
// { USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
// { USB_DEVICE(0x0686, 0x4004) }, /* Scan Elite II (need interrupt ep) */
{ USB_DEVICE(0x0686, 0x400d) }, /* Scan Dual III */ { 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 */ /* 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, 0x0001) }, /* ScanExpress 1200 CU */
{ USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */
{ USB_DEVICE(0x055f, 0x0002) }, /* ScanExpress 600 CU */ { USB_DEVICE(0x055f, 0x0002) }, /* ScanExpress 600 CU */
{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
{ USB_DEVICE(0x055f, 0x0003) }, /* ScanExpress 1200 USB */ { USB_DEVICE(0x055f, 0x0003) }, /* ScanExpress 1200 USB */
{ USB_DEVICE(0x055f, 0x0006) }, /* ScanExpress 1200 UB */ { USB_DEVICE(0x055f, 0x0006) }, /* ScanExpress 1200 UB */
{ USB_DEVICE(0x055f, 0x0007) }, /* ScanExpress 1200 USB Plus */ { USB_DEVICE(0x055f, 0x0007) }, /* ScanExpress 1200 USB Plus */
{ USB_DEVICE(0x055f, 0x0210) }, /* ScanExpress A3 USB */
{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
{ USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */ { USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */ { USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */
{ USB_DEVICE(0x055f, 0x0210) }, /* ScanExpress A3 USB */
{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */ { USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
{ USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus */
{ USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */ { USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */
{ USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */ { USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */ { USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */
{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */ { USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */ { USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */ { USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
// { USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */
/* Nikon */ /* Nikon */
{ USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */ { USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */
/* Plustek */ /* Plustek */
{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0010) }, /* OpticPro U12 */
{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x000F) }, /* 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, 0x0012) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U */ { USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U */
/* Primax/Colorado */ /* Primax/Colorado */
{ USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */ { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
{ USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
{ USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */ { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
{ USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
{ USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */ { USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */
{ USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
{ USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */ { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
{ USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */ { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
// { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 - undetected endpoint */
{ USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */ { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
{ USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */
{ USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */ { 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 */
/* Relisis */ /* Relisis */
// { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */ // { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
/* Seiko/Epson Corp. */ /* Seiko/Epson Corp. */
...@@ -221,6 +239,7 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -221,6 +239,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */ { USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */ { USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */ { USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */ { USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* Umax */ /* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
...@@ -230,8 +249,8 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -230,8 +249,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */ { USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */
{ USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */ { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
/* Visioneer */ /* Visioneer */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */ { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */ { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
{ USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */ { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
{ USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */ { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */
......
...@@ -1324,6 +1324,9 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1324,6 +1324,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS 0xffff
#define USB_DEVICE_ID_MGE_UPS1 0x0001 #define USB_DEVICE_ID_MGE_UPS1 0x0001
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
struct hid_blacklist { struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
...@@ -1359,6 +1362,12 @@ struct hid_blacklist { ...@@ -1359,6 +1362,12 @@ struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -381,6 +381,83 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) ...@@ -381,6 +381,83 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
** **
***********************/ ***********************/
/* encapsulate in an AAL5 frame, which is then split into ATM cells */
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length)
{
unsigned int num_cells = (pdu_length + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
unsigned int num_pdu_cells = pdu_length / ATM_CELL_PAYLOAD + 1;
unsigned int aal5_length = num_cells * ATM_CELL_PAYLOAD;
unsigned int zero_padding = aal5_length - pdu_length - ATM_AAL5_TRAILER;
unsigned int final_length = num_cells * ATM_CELL_SIZE;
unsigned char aal5_trailer [ATM_AAL5_TRAILER];
unsigned char cell_header [ATM_CELL_HEADER];
u32 crc;
int i;
PDEBUG ("atmsar_encode entered\n");
PDEBUG ("pdu_length %d, num_cells %d, num_pdu_cells %d, aal5_length %d, zero_padding %d, final_length %d\n", pdu_length, num_cells, num_pdu_cells, aal5_length, zero_padding, final_length);
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
aal5_trailer [0] = 0; /* UU = 0 */
aal5_trailer [1] = 0; /* CPI = 0 */
aal5_trailer [2] = pdu_length >> 8;
aal5_trailer [3] = pdu_length;
crc = crc32 (~0, source, pdu_length);
for (i = 0; i < zero_padding; i++)
crc = CRC32 (0, crc);
crc = crc32 (crc, aal5_trailer, 4);
crc = ~crc;
aal5_trailer [4] = crc >> 24;
aal5_trailer [5] = crc >> 16;
aal5_trailer [6] = crc >> 8;
aal5_trailer [7] = crc;
cell_header [0] = ctx->atmHeader >> 24;
cell_header [1] = ctx->atmHeader >> 16;
cell_header [2] = ctx->atmHeader >> 8;
cell_header [3] = ctx->atmHeader;
cell_header [4] = 0xec;
for (i = 1; i < num_pdu_cells; i++) {
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, ATM_CELL_PAYLOAD);
target += ATM_CELL_PAYLOAD;
source += ATM_CELL_PAYLOAD;
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
}
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, pdu_length % ATM_CELL_PAYLOAD);
target += pdu_length % ATM_CELL_PAYLOAD;
if (num_pdu_cells < num_cells) {
memset (target, 0, zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD);
target += zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD;
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
zero_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
}
memset (target, 0, zero_padding);
target += zero_padding;
memcpy (target, aal5_trailer, ATM_AAL5_TRAILER);
/* set pti bit in last cell */
*(target + ATM_AAL5_TRAILER + 3 - ATM_CELL_SIZE) |= 0x2;
/* update stats */
if (ctx->stats)
atomic_inc (&ctx->stats->tx);
if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
atomic_add (num_cells, &(ctx->stats->tx));
return final_length;
}
struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb) struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
{ {
int number_of_cells = (skb->len) / 48; int number_of_cells = (skb->len) / 48;
...@@ -624,9 +701,8 @@ struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_b ...@@ -624,9 +701,8 @@ struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_b
} else { } else {
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) == if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
NULL) { NULL)
skb_trim (skb, 0); return NULL;
}
} }
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define ATMSAR_USE_53BYTE_CELL 0x1L #define ATMSAR_USE_53BYTE_CELL 0x1L
#define ATMSAR_SET_PTI 0x2L #define ATMSAR_SET_PTI 0x2L
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
/* types */ /* types */
#define ATMSAR_TYPE_AAL0 ATM_AAL0 #define ATMSAR_TYPE_AAL0 ATM_AAL0
...@@ -89,4 +90,6 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff ...@@ -89,4 +90,6 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff
struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size); struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size);
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length);
#endif /* _ATMSAR_H_ */ #endif /* _ATMSAR_H_ */
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
* *
*/ */
#include <asm/semaphore.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -58,7 +59,6 @@ ...@@ -58,7 +59,6 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/atm.h> #include <linux/atm.h>
#include <linux/atmdev.h> #include <linux/atmdev.h>
#include "atmsar.h" #include "atmsar.h"
...@@ -106,20 +106,21 @@ ...@@ -106,20 +106,21 @@
#define UDSL_ENDPOINT_DATA_OUT 0x07 #define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87 #define UDSL_ENDPOINT_DATA_IN 0x87
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
/* usb_device_id struct */ /* usb_device_id struct */
static struct usb_device_id udsl_usb_ids[] = { static struct usb_device_id udsl_usb_ids [] = {
{USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)}, { USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID) },
{} /* list terminator */ { } /* Terminating entry */
}; };
/* not exporting this prevents the depmod from generating the map that causes the modules to be isnserted as driver. MODULE_DEVICE_TABLE (usb, udsl_usb_ids);
* we do not want this, we want the script run.
MODULE_DEVICE_TABLE ( usb, udsl_usb_ids);
*/
/* context declarations */ /* context declarations */
struct udsl_data_ctx { struct udsl_receiver {
struct list_head list;
struct sk_buff *skb; struct sk_buff *skb;
struct urb *urb; struct urb *urb;
struct udsl_instance_data *instance; struct udsl_instance_data *instance;
...@@ -137,25 +138,32 @@ struct udsl_usb_send_data_context { ...@@ -137,25 +138,32 @@ struct udsl_usb_send_data_context {
*/ */
struct udsl_instance_data { struct udsl_instance_data {
struct tasklet_struct recvqueue_tasklet; struct semaphore serialize;
/* usb device part */ /* usb device part */
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct udsl_data_ctx *rcvbufs;
struct sk_buff_head sndqueue; struct sk_buff_head sndqueue;
struct udsl_usb_send_data_context send_ctx[UDSL_NUMBER_SND_URBS]; struct udsl_usb_send_data_context send_ctx [UDSL_NUMBER_SND_URBS];
int data_started; int firmware_loaded;
/* atm device part */ /* atm device part */
struct atm_dev *atm_dev; struct atm_dev *atm_dev;
struct sk_buff_head recvqueue;
struct atmsar_vcc_data *atmsar_vcc_list; struct atmsar_vcc_data *atmsar_vcc_list;
};
static const char udsl_driver_name[] = "Alcatel SpeedTouch USB"; /* receiving */
struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
spinlock_t spare_receivers_lock;
struct list_head spare_receivers;
static DECLARE_MUTEX(udsl_usb_ioctl_lock); spinlock_t completed_receivers_lock;
struct list_head completed_receivers;
struct tasklet_struct receive_tasklet;
};
static const char udsl_driver_name [] = "Alcatel SpeedTouch USB";
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
static int udsl_print_packet (const unsigned char *data, int len); static int udsl_print_packet (const unsigned char *data, int len);
...@@ -169,8 +177,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci); ...@@ -169,8 +177,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
static void udsl_atm_close (struct atm_vcc *vcc); static void udsl_atm_close (struct atm_vcc *vcc);
static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg); static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb); static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page); static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
static void udsl_atm_processqueue (unsigned long data);
static struct atmdev_ops udsl_atm_devops = { static struct atmdev_ops udsl_atm_devops = {
.open = udsl_atm_open, .open = udsl_atm_open,
...@@ -203,6 +210,170 @@ static struct usb_driver udsl_usb_driver = { ...@@ -203,6 +210,170 @@ static struct usb_driver udsl_usb_driver = {
.id_table = udsl_usb_ids, .id_table = udsl_usb_ids,
}; };
/**************
** receive **
**************/
static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs)
{
struct udsl_instance_data *instance;
struct udsl_receiver *rcv;
unsigned long flags;
PDEBUG ("udsl_complete_receive entered\n");
if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
PDEBUG ("udsl_complete_receive: bad urb!\n");
return;
}
/* may not be in_interrupt() */
spin_lock_irqsave (&instance->completed_receivers_lock, flags);
list_add_tail (&rcv->list, &instance->completed_receivers);
spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
PDEBUG ("udsl_complete_receive: scheduling tasklet\n");
tasklet_schedule (&instance->receive_tasklet);
}
static void udsl_process_receive (unsigned long data)
{
struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
struct udsl_receiver *rcv;
unsigned long flags;
unsigned char *data_start;
struct sk_buff *skb;
struct urb *urb;
struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *tmp = NULL;
PDEBUG ("udsl_process_receive entered\n");
spin_lock_irqsave (&instance->completed_receivers_lock, flags);
while (!list_empty (&instance->completed_receivers)) {
rcv = list_entry (instance->completed_receivers.next, struct udsl_receiver, list);
list_del (&rcv->list);
spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
urb = rcv->urb;
PDEBUG ("udsl_process_receive: got packet %p with length %d and status %d\n", urb, urb->actual_length, urb->status);
switch (urb->status) {
case 0:
PDEBUG ("udsl_process_receive: processing urb with rcv %p, urb %p, skb %p\n", rcv, urb, rcv->skb);
/* update the skb structure */
skb = rcv->skb;
skb_trim (skb, 0);
skb_put (skb, urb->actual_length);
data_start = skb->data;
PDEBUG ("skb->len = %d\n", skb->len);
PACKETDEBUG (skb->data, skb->len);
while ((new =
atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
&atmsar_vcc)) != NULL) {
PDEBUG ("(after cell processing)skb->len = %d\n", new->len);
switch (atmsar_vcc->type) {
case ATMSAR_TYPE_AAL5:
tmp = new;
new = atmsar_decode_aal5 (atmsar_vcc, new);
/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
if (new) {
PDEBUG ("(after aal5 decap) skb->len = %d\n", new->len);
if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
PACKETDEBUG (new->data, new->len);
atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
} else {
PDEBUG
("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
atomic_read (&atmsar_vcc->vcc->rx_inuse),
atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
dev_kfree_skb (new);
}
} else {
PDEBUG ("atmsar_decode_aal5 returned NULL!\n");
dev_kfree_skb (tmp);
}
break;
default:
/* not supported. we delete the skb. */
printk (KERN_INFO
"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
dev_kfree_skb (new);
break;
}
}
/* restore skb */
skb_push (skb, skb->data - data_start);
usb_fill_bulk_urb (urb,
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
udsl_complete_receive,
rcv);
if (!usb_submit_urb (urb, GFP_ATOMIC))
break;
PDEBUG ("udsl_process_receive: submission failed\n");
/* fall through */
default: /* error or urb unlinked */
PDEBUG ("udsl_process_receive: adding to spare_receivers\n");
spin_lock_irqsave (&instance->spare_receivers_lock, flags);
list_add (&rcv->list, &instance->spare_receivers);
spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
break;
} /* switch */
spin_lock_irqsave (&instance->completed_receivers_lock, flags);
} /* while */
spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
PDEBUG ("udsl_process_receive successful\n");
}
static void udsl_fire_receivers (struct udsl_instance_data *instance)
{
struct list_head receivers, *pos, *n;
unsigned long flags;
INIT_LIST_HEAD (&receivers);
down (&instance->serialize);
spin_lock_irqsave (&instance->spare_receivers_lock, flags);
list_splice_init (&instance->spare_receivers, &receivers);
spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
list_for_each_safe (pos, n, &receivers) {
struct udsl_receiver *rcv = list_entry (pos, struct udsl_receiver, list);
PDEBUG ("udsl_fire_receivers: firing urb %p\n", rcv->urb);
usb_fill_bulk_urb (rcv->urb,
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
udsl_complete_receive,
rcv);
if (usb_submit_urb (rcv->urb, GFP_KERNEL) < 0) {
PDEBUG ("udsl_fire_receivers: submit failed!\n");
spin_lock_irqsave (&instance->spare_receivers_lock, flags);
list_move (pos, &instance->spare_receivers);
spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
}
}
up (&instance->serialize);
}
/************ /************
** ATM ** ** ATM **
************/ ************/
...@@ -213,27 +384,9 @@ static struct usb_driver udsl_usb_driver = { ...@@ -213,27 +384,9 @@ static struct usb_driver udsl_usb_driver = {
* *
****************************************************************************/ ****************************************************************************/
static struct atm_dev *udsl_atm_startdevice (struct udsl_instance_data *instance, struct atmdev_ops *devops)
{
MOD_INC_USE_COUNT;
instance->atm_dev = atm_dev_register (udsl_driver_name, devops, -1, 0);
instance->atm_dev->dev_data = instance;
instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
skb_queue_head_init (&instance->recvqueue);
/* tmp init atm device, set to 128kbit */
instance->atm_dev->link_rate = 128 * 1000 / 424;
return instance->atm_dev;
}
static void udsl_atm_stopdevice (struct udsl_instance_data *instance) static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
{ {
struct atm_vcc *walk; struct atm_vcc *walk;
struct sk_buff *skb;
struct atm_dev *atm_dev; struct atm_dev *atm_dev;
if (!instance->atm_dev) if (!instance->atm_dev)
...@@ -241,10 +394,6 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance) ...@@ -241,10 +394,6 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
atm_dev = instance->atm_dev; atm_dev = instance->atm_dev;
/* clean queue */
while ((skb = skb_dequeue (&instance->recvqueue)))
dev_kfree_skb (skb);
atm_dev->signal = ATM_PHY_SIG_LOST; atm_dev->signal = ATM_PHY_SIG_LOST;
walk = atm_dev->vccs; walk = atm_dev->vccs;
shutdown_atm_dev (atm_dev); shutdown_atm_dev (atm_dev);
...@@ -253,16 +402,8 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance) ...@@ -253,16 +402,8 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
wake_up (&walk->sleep); wake_up (&walk->sleep);
instance->atm_dev = NULL; instance->atm_dev = NULL;
MOD_DEC_USE_COUNT;
} }
static void udsl_atm_set_mac (struct udsl_instance_data *instance, const char mac[6])
{
if (!instance->atm_dev)
return;
memcpy (instance->atm_dev->esi, mac, 6);
}
/*************************************************************************** /***************************************************************************
* *
...@@ -281,11 +422,16 @@ static struct sk_buff *udsl_atm_alloc_tx (struct atm_vcc *vcc, unsigned int size ...@@ -281,11 +422,16 @@ static struct sk_buff *udsl_atm_alloc_tx (struct atm_vcc *vcc, unsigned int size
return NULL; return NULL;
} }
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page) static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
{ {
struct udsl_instance_data *instance = atm_dev->dev_data; struct udsl_instance_data *instance = atm_dev->dev_data;
int left = *pos; int left = *pos;
if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
if (!left--) if (!left--)
return sprintf (page, "SpeedTouch USB %s-%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", return sprintf (page, "SpeedTouch USB %s-%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
instance->usb_dev->bus->bus_name, instance->usb_dev->devpath, instance->usb_dev->bus->bus_name, instance->usb_dev->devpath,
...@@ -311,6 +457,7 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page ...@@ -311,6 +457,7 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page
return 0; return 0;
} }
/*************************************************************************** /***************************************************************************
* *
* ATM DATA functions * ATM DATA functions
...@@ -325,8 +472,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -325,8 +472,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
PDEBUG ("udsl_atm_send called\n"); PDEBUG ("udsl_atm_send called\n");
if (!dev_data) if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
return -EINVAL; return -EINVAL;
}
if (!instance->firmware_loaded)
return -EAGAIN;
switch (vcc->qos.aal) { switch (vcc->qos.aal) {
case ATM_AAL5: case ATM_AAL5:
...@@ -350,67 +502,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -350,67 +502,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
break; break;
default: default:
return -EINVAL; return -EINVAL;
}; }
PDEBUG ("udsl_atm_send unsuccessfull\n"); PDEBUG ("udsl_atm_send unsuccessfull\n");
return 0; return 0;
nomem: nomem:
vcc->pop (vcc, skb); vcc->pop (vcc, skb);
return -ENOMEM; return -ENOMEM;
};
static void udsl_atm_processqueue (unsigned long data)
{
struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *skb = NULL, *tmp = NULL;
PDEBUG ("udsl_atm_processqueue entered\n");
while ((skb = skb_dequeue (&instance->recvqueue))) {
PDEBUG ("skb = %p, skb->len = %d\n", skb, skb->len);
PACKETDEBUG (skb->data, skb->len);
while ((new =
atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
&atmsar_vcc)) != NULL) {
PDEBUG ("(after cell processing)skb->len = %d\n", new->len);
switch (atmsar_vcc->type) {
case ATMSAR_TYPE_AAL5:
tmp = new;
new = atmsar_decode_aal5 (atmsar_vcc, new);
/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
if (new) {
PDEBUG ("(after aal5 decap) skb->len = %d\n", new->len);
if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
PACKETDEBUG (new->data, new->len);
atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
} else {
PDEBUG
("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
atomic_read (&atmsar_vcc->vcc->rx_inuse),
atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
dev_kfree_skb (new);
}
} else {
PDEBUG ("atmsar_decode_aal5 returned NULL!\n");
dev_kfree_skb (tmp);
}
break;
default:
/* not supported. we delete the skb. */
printk (KERN_INFO
"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
dev_kfree_skb (new);
break;
}
};
dev_kfree_skb (skb);
};
PDEBUG ("udsl_atm_processqueue successfull\n");
} }
...@@ -419,6 +517,7 @@ static void udsl_atm_processqueue (unsigned long data) ...@@ -419,6 +517,7 @@ static void udsl_atm_processqueue (unsigned long data)
* SAR driver entries * SAR driver entries
* *
****************************************************************************/ ****************************************************************************/
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
{ {
struct udsl_atm_dev_data *dev_data; struct udsl_atm_dev_data *dev_data;
...@@ -426,6 +525,11 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -426,6 +525,11 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
PDEBUG ("udsl_atm_open called\n"); PDEBUG ("udsl_atm_open called\n");
if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
/* at the moment only AAL5 support */ /* at the moment only AAL5 support */
if (vcc->qos.aal != ATM_AAL5) if (vcc->qos.aal != ATM_AAL5)
return -EINVAL; return -EINVAL;
...@@ -453,6 +557,9 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -453,6 +557,9 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
dev_data->atmsar_vcc->mtu = UDSL_MAX_AAL5_MRU; dev_data->atmsar_vcc->mtu = UDSL_MAX_AAL5_MRU;
if (instance->firmware_loaded)
udsl_fire_receivers (instance);
PDEBUG ("udsl_atm_open successfull\n"); PDEBUG ("udsl_atm_open successfull\n");
return 0; return 0;
} }
...@@ -464,6 +571,11 @@ static void udsl_atm_close (struct atm_vcc *vcc) ...@@ -464,6 +571,11 @@ static void udsl_atm_close (struct atm_vcc *vcc)
PDEBUG ("udsl_atm_close called\n"); PDEBUG ("udsl_atm_close called\n");
if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
return;
}
/* freeing resources */ /* freeing resources */
/* cancel all sends on this vcc */ /* cancel all sends on this vcc */
udsl_usb_cancelsends (instance, vcc); udsl_usb_cancelsends (instance, vcc);
...@@ -482,7 +594,7 @@ static void udsl_atm_close (struct atm_vcc *vcc) ...@@ -482,7 +594,7 @@ static void udsl_atm_close (struct atm_vcc *vcc)
PDEBUG ("udsl_atm_close successfull\n"); PDEBUG ("udsl_atm_close successfull\n");
return; return;
}; }
static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
{ {
...@@ -492,7 +604,7 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) ...@@ -492,7 +604,7 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
}; }
/************ /************
...@@ -566,9 +678,6 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v ...@@ -566,9 +678,6 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v
PDEBUG ("udsl_usb_send_data entered, sending packet %p with length %d\n", skb, skb->len); PDEBUG ("udsl_usb_send_data entered, sending packet %p with length %d\n", skb, skb->len);
if (!instance->data_started)
return -EAGAIN;
PACKETDEBUG (skb->data, skb->len); PACKETDEBUG (skb->data, skb->len);
spin_lock_irqsave (&instance->sndqueue.lock, flags); spin_lock_irqsave (&instance->sndqueue.lock, flags);
...@@ -592,7 +701,7 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v ...@@ -592,7 +701,7 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v
spin_unlock_irqrestore (&instance->sndqueue.lock, flags); spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
PDEBUG ("udsl_usb_send_data: skb (0x%p) queued\n", skb); PDEBUG ("udsl_usb_send_data: skb (0x%p) queued\n", skb);
return 0; return 0;
}; }
/* init context */ /* init context */
urb = instance->send_ctx[i].urb; urb = instance->send_ctx[i].urb;
...@@ -620,285 +729,264 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v ...@@ -620,285 +729,264 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v
return err; return err;
} }
/********* receive *******/
static void udsl_usb_data_receive (struct urb *urb, struct pt_regs *regs)
{
struct udsl_data_ctx *ctx;
struct udsl_instance_data *instance;
if (!urb) /***************************************************************************
return; *
* usb driver entries
*
****************************************************************************/
PDEBUG ("udsl_usb_receive_data entered, got packet %p with length %d an status %d\n", urb, static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
urb->actual_length, urb->status); {
struct udsl_instance_data *instance = usb_get_intfdata (intf);
ctx = urb->context; PDEBUG ("udsl_usb_ioctl entered\n");
if (!ctx || !ctx->skb)
return;
instance = ctx->instance; if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
switch (urb->status) { switch (code) {
case 0: case UDSL_IOCTL_START:
PDEBUG ("udsl_usb_data_receive: processing urb with ctx %p, urb %p (%p), skb %p\n", instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
ctx, ctx ? ctx->urb : NULL, urb, ctx ? ctx->skb : NULL); down (&instance->serialize); /* vs self */
/* update the skb structure */ if (!instance->firmware_loaded) {
skb_put (ctx->skb, urb->actual_length); usb_set_interface (instance->usb_dev, 1, 2);
instance->firmware_loaded = 1;
/* queue the skb for processing and wake the SAR */
skb_queue_tail (&instance->recvqueue, ctx->skb);
tasklet_schedule (&instance->recvqueue_tasklet);
/* get a new skb */
ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
if (!ctx->skb) {
PDEBUG ("No skb, loosing urb.\n");
usb_free_urb (ctx->urb);
ctx->urb = NULL;
return;
} }
break; up (&instance->serialize);
case -ENOENT: /* buffer was unlinked */ udsl_fire_receivers (instance);
case -EILSEQ: /* unplug or timeout */ return 0;
case -ETIMEDOUT: /* unplug or timeout */ case UDSL_IOCTL_STOP:
/* instance->atm_dev->signal = ATM_PHY_SIG_LOST;
* we don't do anything here and we don't resubmit return 0;
*/ default:
return; return -ENOTTY;
} }
}
usb_fill_bulk_urb (urb, static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) ctx->skb->data,
UDSL_RECEIVE_BUFFER_SIZE, udsl_usb_data_receive, ctx);
usb_submit_urb (urb, GFP_ATOMIC);
return;
};
static int udsl_usb_data_init (struct udsl_instance_data *instance)
{ {
int i, succes; struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->altsetting->desc.bInterfaceNumber;
struct udsl_instance_data *instance;
unsigned char mac_str [13];
unsigned char mac [6];
int i, err;
if (instance->data_started) PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
return 1; dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
/* set alternate setting 1 on interface 1 */ if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
usb_set_interface (instance->usb_dev, 1, 2); (dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
(dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
return -ENODEV;
PDEBUG ("max packet size on endpoint %d is %d\n", UDSL_ENDPOINT_DATA_OUT, PDEBUG ("Device Accepted\n");
usb_maxpacket (instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), 0));
instance->rcvbufs = kmalloc (sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS, GFP_KERNEL); /* instance init */
if (!instance->rcvbufs) if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
return -ENOMEM; PDEBUG ("No memory for Instance data!\n");
err = -ENOMEM;
goto fail_instance;
}
memset (instance->rcvbufs, 0, sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS); memset (instance, 0, sizeof (struct udsl_instance_data));
skb_queue_head_init (&instance->sndqueue); init_MUTEX (&instance->serialize);
for (i = 0, succes = 0; i < UDSL_NUMBER_RCV_URBS; i++) { instance->usb_dev = dev;
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
ctx->urb = NULL; spin_lock_init (&instance->spare_receivers_lock);
ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE); INIT_LIST_HEAD (&instance->spare_receivers);
if (!ctx->skb)
continue;
ctx->urb = usb_alloc_urb (0, GFP_KERNEL); spin_lock_init (&instance->completed_receivers_lock);
if (!ctx->urb) { INIT_LIST_HEAD (&instance->completed_receivers);
kfree_skb (ctx->skb);
ctx->skb = NULL;
break;
};
usb_fill_bulk_urb (ctx->urb, tasklet_init (&instance->receive_tasklet, udsl_process_receive, (unsigned long) instance);
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) ctx->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
udsl_usb_data_receive, ctx);
skb_queue_head_init (&instance->sndqueue);
ctx->instance = instance; /* receive urb init */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
PDEBUG ("udsl_usb_data_init: usb with skb->truesize = %d (Asked for %d)\n", if (!(rcv->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE))) {
ctx->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE); PDEBUG ("No memory for skb %d!\n", i);
err = -ENOMEM;
goto fail_urbs;
}
if (usb_submit_urb (ctx->urb, GFP_KERNEL) < 0) if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("udsl_usb_data_init: Submit failed, loosing urb.\n"); PDEBUG ("No memory for receive urb %d!\n", i);
else err = -ENOMEM;
succes++; goto fail_urbs;
} }
PDEBUG ("udsl_usb_data_init %d urb%s queued for receive\n", succes, rcv->instance = instance;
(succes != 1) ? "s" : "");
list_add (&rcv->list, &instance->spare_receivers);
for (i = 0, succes = 0; i < UDSL_NUMBER_SND_URBS; i++) { PDEBUG ("skb->truesize = %d (asked for %d)\n", rcv->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE);
instance->send_ctx[i].urb = usb_alloc_urb (0, GFP_KERNEL);
PDEBUG ("udsl_usb_data_init: send urb allocted address %p\n",
instance->send_ctx[i].urb);
if (instance->send_ctx[i].urb)
succes++;
} }
PDEBUG ("udsl_usb_data_init %d urb%s queued for send\n", succes, (succes != 1) ? "s" : ""); for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
instance->data_started = 1; if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
instance->atm_dev->signal = ATM_PHY_SIG_FOUND; PDEBUG ("No memory for send urb %d!\n", i);
err = -ENOMEM;
goto fail_urbs;
}
return 0; snd->instance = instance;
} }
static int udsl_usb_data_exit (struct udsl_instance_data *instance) /* atm init */
{ if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
int i; PDEBUG ("failed to register ATM device!\n");
err = -ENOMEM;
goto fail_atm;
}
if (!instance->data_started) instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
return 0; instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
if (!instance->rcvbufs) /* tmp init atm device, set to 128kbit */
return 0; instance->atm_dev->link_rate = 128 * 1000 / 424;
/* destroy urbs */ /* set MAC address, it is stored in the serial number */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) { usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13);
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]); for (i = 0; i < 6; i++)
mac[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
if ((!ctx->urb) || (!ctx->skb)) PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
continue;
usb_unlink_urb (ctx->urb); memcpy (instance->atm_dev->esi, mac, 6);
usb_free_urb (ctx->urb); wmb ();
kfree_skb (ctx->skb);
ctx->skb = NULL; instance->atm_dev->dev_data = instance;
}
tasklet_kill (&instance->recvqueue_tasklet); usb_set_intfdata (intf, instance);
return 0;
fail_atm:
fail_urbs:
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) { for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]); struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
usb_unlink_urb (ctx->urb); if (snd->urb)
usb_free_urb (snd->urb);
}
if (ctx->skb) for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
ctx->vcc->pop (ctx->vcc, ctx->skb); struct udsl_receiver *rcv = &(instance->all_receivers[i]);
ctx->skb = NULL;
usb_free_urb (ctx->urb); if (rcv->skb)
kfree_skb (rcv->skb);
if (rcv->urb)
usb_free_urb (rcv->urb);
} }
kfree (instance);
fail_instance:
return err;
}
/* free receive contexts */ static void udsl_usb_disconnect (struct usb_interface *intf)
kfree (instance->rcvbufs); {
instance->rcvbufs = NULL; struct udsl_instance_data *instance = usb_get_intfdata (intf);
struct list_head *pos;
unsigned long flags;
unsigned int count = 0;
int i;
instance->data_started = 0; PDEBUG ("disconnecting\n");
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
return 0; usb_set_intfdata (intf, NULL);
};
if (!instance) {
PDEBUG ("NULL instance!\n");
return;
}
/*************************************************************************** tasklet_disable (&instance->receive_tasklet);
*
* usb driver entries
*
****************************************************************************/
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
down (&instance->serialize); /* vs udsl_fire_receivers */
/* no need to take the spinlock - receive_tasklet is not running */
list_for_each (pos, &instance->spare_receivers)
if (++count > UDSL_NUMBER_RCV_URBS)
panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
INIT_LIST_HEAD (&instance->spare_receivers);
up (&instance->serialize);
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data) PDEBUG ("udsl_usb_disconnect: flushed %u spare receivers\n", count);
{
struct udsl_instance_data *instance = usb_get_intfdata (intf);
int retval;
down(&udsl_usb_ioctl_lock); count = UDSL_NUMBER_RCV_URBS - count;
switch (code) {
case UDSL_IOCTL_START:
retval = udsl_usb_data_init (instance);
break;
case UDSL_IOCTL_STOP:
retval = udsl_usb_data_exit (instance);
break;
default:
retval = -ENOTTY;
break;
}
up(&udsl_usb_ioctl_lock);
return retval;
}
static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id) for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
{ usb_unlink_urb (instance->all_receivers[i].urb);
struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->altsetting->desc.bInterfaceNumber;
int i;
unsigned char mac[6];
unsigned char mac_str[13];
struct udsl_instance_data *instance = NULL;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n", /* wait for completion handlers to finish */
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); do {
unsigned int completed = 0;
if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || spin_lock_irqsave (&instance->completed_receivers_lock, flags);
(dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) || list_for_each (pos, &instance->completed_receivers)
(dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1)) if (++completed > count)
return -ENODEV; panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
MOD_INC_USE_COUNT; PDEBUG ("udsl_usb_disconnect: found %u completed receivers\n", completed);
PDEBUG ("Device Accepted\n"); if (completed == count)
break;
/* device init */ /* not all urbs completed */
instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL); yield ();
if (!instance) { } while (1);
PDEBUG ("No memory for Instance data!\n");
return -ENOMEM;
}
/* initialize structure */ PDEBUG ("udsl_usb_disconnect: flushing %u completed receivers\n", count);
memset (instance, 0, sizeof (struct udsl_instance_data)); /* no need to take the spinlock - no completion handlers running */
instance->usb_dev = dev; INIT_LIST_HEAD (&instance->completed_receivers);
instance->rcvbufs = NULL;
tasklet_init (&instance->recvqueue_tasklet, udsl_atm_processqueue, (unsigned long) instance);
udsl_atm_startdevice (instance, &udsl_atm_devops); tasklet_enable (&instance->receive_tasklet);
tasklet_kill (&instance->receive_tasklet);
/* set MAC address, it is stored in the serial number */ PDEBUG ("udsl_usb_disconnect: freeing receivers\n");
usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13); for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
for (i = 0; i < 6; i++) struct udsl_receiver *rcv = &(instance->all_receivers[i]);
mac[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], usb_free_urb (rcv->urb);
mac[5]); kfree_skb (rcv->skb);
udsl_atm_set_mac (instance, mac); }
usb_set_intfdata (intf, instance); for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
return 0; struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
}
static void udsl_usb_disconnect (struct usb_interface *intf) usb_unlink_urb (ctx->urb);
{
struct udsl_instance_data *instance = usb_get_intfdata (intf);
PDEBUG ("disconnecting\n"); if (ctx->skb)
ctx->vcc->pop (ctx->vcc, ctx->skb);
ctx->skb = NULL;
usb_free_urb (ctx->urb);
}
usb_set_intfdata (intf, NULL);
if (instance) {
/* unlinking receive buffers */
udsl_usb_data_exit (instance);
/* removing atm device */ /* removing atm device */
if (instance->atm_dev) if (instance->atm_dev)
udsl_atm_stopdevice (instance); udsl_atm_stopdevice (instance);
kfree (instance); kfree (instance);
MOD_DEC_USE_COUNT;
}
} }
/*************************************************************************** /***************************************************************************
* *
* Driver Init * Driver Init
...@@ -907,18 +995,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -907,18 +995,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
static int __init udsl_usb_init (void) static int __init udsl_usb_init (void)
{ {
PDEBUG ("Initializing SpeedTouch Driver Version " DRIVER_VERSION "\n"); PDEBUG ("udsl_usb_init: driver version " DRIVER_VERSION "\n");
return usb_register (&udsl_usb_driver); return usb_register (&udsl_usb_driver);
} }
static void __exit udsl_usb_cleanup (void) static void __exit udsl_usb_cleanup (void)
{ {
PDEBUG ("udsl_usb_cleanup\n");
usb_deregister (&udsl_usb_driver); usb_deregister (&udsl_usb_driver);
} }
module_init(udsl_usb_init); module_init (udsl_usb_init);
module_exit(udsl_usb_cleanup); module_exit (udsl_usb_cleanup);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
/******************************************************************************* /*******************************************************************************
...@@ -929,7 +1024,7 @@ module_exit(udsl_usb_cleanup); ...@@ -929,7 +1024,7 @@ module_exit(udsl_usb_cleanup);
static int udsl_print_packet (const unsigned char *data, int len) static int udsl_print_packet (const unsigned char *data, int len)
{ {
unsigned char buffer[256]; unsigned char buffer [256];
int i = 0, j = 0; int i = 0, j = 0;
for (i = 0; i < len;) { for (i = 0; i < len;) {
...@@ -941,10 +1036,6 @@ static int udsl_print_packet (const unsigned char *data, int len) ...@@ -941,10 +1036,6 @@ static int udsl_print_packet (const unsigned char *data, int len)
PDEBUG ("%s\n", buffer); PDEBUG ("%s\n", buffer);
} }
return i; return i;
}; }
#endif /* PACKETDEBUG */ #endif /* PACKETDEBUG */
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
#
# Makefile for USB Network drivers which require generic MII code.
#
obj-$(CONFIG_USB_PEGASUS) += mii.o
...@@ -135,6 +135,7 @@ static struct usb_device_id id_table_sio [] = { ...@@ -135,6 +135,7 @@ static struct usb_device_id id_table_sio [] = {
static struct usb_device_id id_table_8U232AM [] = { static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -143,6 +144,7 @@ static struct usb_device_id id_table_8U232AM [] = { ...@@ -143,6 +144,7 @@ static struct usb_device_id id_table_8U232AM [] = {
static struct usb_device_id id_table_combined [] = { static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -17,11 +17,14 @@ ...@@ -17,11 +17,14 @@
* Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
* FTDI_SIO implementation. * FTDI_SIO implementation.
* *
* Philipp Ghring - pg@futureware.at - added the Device ID of the USB relais
* from Rudolf Gugler
*/ */
#define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */
......
...@@ -106,6 +106,7 @@ static struct usb_device_id ipaq_id_table [] = { ...@@ -106,6 +106,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) }, { USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
...@@ -126,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = { ...@@ -126,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) }, { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) },
{ USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) }, { USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) },
{ USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) },
{ USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#define COMPAQ_IPAQ_ID 0x0003 #define COMPAQ_IPAQ_ID 0x0003
#define COMPAQ_0032_ID 0x0032 #define COMPAQ_0032_ID 0x0032
#define DELL_VENDOR_ID 0x413c
#define DELL_AXIM_ID 0x4001
#define HP_VENDOR_ID 0x03f0 #define HP_VENDOR_ID 0x03f0
#define HP_JORNADA_548_ID 0x1016 #define HP_JORNADA_548_ID 0x1016
#define HP_JORNADA_568_ID 0x1116 #define HP_JORNADA_568_ID 0x1116
...@@ -63,6 +66,7 @@ ...@@ -63,6 +66,7 @@
#define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_VENDOR_ID 0x0930
#define TOSHIBA_PRODUCT_ID 0x0700 #define TOSHIBA_PRODUCT_ID 0x0700
#define TOSHIBA_E740_ID 0x0706
#define HTC_VENDOR_ID 0x0bb4 #define HTC_VENDOR_ID 0x0bb4
#define HTC_PRODUCT_ID 0x00ce #define HTC_PRODUCT_ID 0x00ce
......
...@@ -74,6 +74,7 @@ static struct usb_device_id id_table [] = { ...@@ -74,6 +74,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -28,3 +28,6 @@ ...@@ -28,3 +28,6 @@
#define RATOC_VENDOR_ID 0x0584 #define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000 #define RATOC_PRODUCT_ID 0xb000
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
...@@ -50,23 +50,25 @@ ...@@ -50,23 +50,25 @@
#include "transport.h" #include "transport.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h>
/*********************************************************************** /***********************************************************************
* Host functions * Host functions
***********************************************************************/ ***********************************************************************/
static const char* host_info(struct Scsi_Host *host) static const char* usb_storage_info(struct Scsi_Host *host)
{ {
return "SCSI emulation for USB Mass Storage devices"; return "SCSI emulation for USB Mass Storage devices";
} }
#if 0
/* detect a virtual adapter (always works) /* detect a virtual adapter (always works)
* Synchronization: 2.4: with the io_request_lock * Synchronization: 2.4: with the io_request_lock
* 2.5: no locks. * 2.5: no locks.
* fortunately we don't care. * fortunately we don't care.
* */ * */
static int detect(struct SHT *sht) static int usb_storage_detect(struct SHT *sht)
{ {
struct us_data *us; struct us_data *us;
char local_name[32]; char local_name[32];
...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht) ...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht)
* the driver and we're doing each virtual host in turn, not in parallel * the driver and we're doing each virtual host in turn, not in parallel
* Synchronization: BKL, no spinlock. * Synchronization: BKL, no spinlock.
*/ */
static int release(struct Scsi_Host *psh) static int usb_storage_release(struct Scsi_Host *psh)
{ {
struct us_data *us = (struct us_data *)psh->hostdata[0]; struct us_data *us = (struct us_data *)psh->hostdata[0];
...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh) ...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh)
/* we always have a successful release */ /* we always have a successful release */
return 0; return 0;
} }
#endif
/* run command */
static int command( Scsi_Cmnd *srb )
{
US_DEBUGP("Bad use of us_command\n");
return DID_BAD_TARGET << 16;
}
/* queue a command */ /* queue a command */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) ...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
/* Command abort */ /* Command abort */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int command_abort( Scsi_Cmnd *srb ) static int usb_storage_command_abort( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb ) ...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb )
/* This invokes the transport reset mechanism to reset the state of the /* This invokes the transport reset mechanism to reset the state of the
* device */ * device */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int device_reset( Scsi_Cmnd *srb ) static int usb_storage_device_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
int result; int result;
...@@ -202,11 +197,10 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -202,11 +197,10 @@ static int device_reset( Scsi_Cmnd *srb )
/* lock the device pointers */ /* lock the device pointers */
down(&(us->dev_semaphore)); down(&(us->dev_semaphore));
/* if the device was removed, then we're already reset */ /* do the reset */
if (!(us->flags & US_FL_DEV_ATTACHED))
result = SUCCESS;
else
result = us->transport_reset(us); result = us->transport_reset(us);
/* unlock */
up(&(us->dev_semaphore)); up(&(us->dev_semaphore));
/* lock access to the state and clear it */ /* lock access to the state and clear it */
...@@ -219,31 +213,26 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -219,31 +213,26 @@ static int device_reset( Scsi_Cmnd *srb )
* disconnect/reconnect for all drivers which have claimed * disconnect/reconnect for all drivers which have claimed
* interfaces, including ourself. */ * interfaces, including ourself. */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int bus_reset( Scsi_Cmnd *srb )
/* FIXME: This needs to be re-examined in the face of the new
* hotplug system -- this will implicitly cause a detach/reattach of
* usb-storage, which is not what we want now.
*
* Can we just skip over usb-storage in the while loop?
*/
static int usb_storage_bus_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us;
int i; int i;
int result; int result;
struct usb_device *pusb_dev_save;
/* we use the usb_reset_device() function to handle this for us */ /* we use the usb_reset_device() function to handle this for us */
US_DEBUGP("bus_reset() called\n"); US_DEBUGP("bus_reset() called\n");
scsi_unlock(srb->device->host); us = (struct us_data *)srb->device->host->hostdata[0];
/* if the device has been removed, this worked */
down(&us->dev_semaphore);
if (!(us->flags & US_FL_DEV_ATTACHED)) {
US_DEBUGP("-- device removed already\n");
up(&us->dev_semaphore);
scsi_lock(srb->device->host);
return SUCCESS;
}
pusb_dev_save = us->pusb_dev;
up(&us->dev_semaphore);
/* attempt to reset the port */ /* attempt to reset the port */
result = usb_reset_device(pusb_dev_save); result = usb_reset_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result); US_DEBUGP("usb_reset_device returns %d\n", result);
if (result < 0) { if (result < 0) {
scsi_lock(srb->device->host); scsi_lock(srb->device->host);
...@@ -253,9 +242,9 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -253,9 +242,9 @@ static int bus_reset( Scsi_Cmnd *srb )
/* FIXME: This needs to lock out driver probing while it's working /* FIXME: This needs to lock out driver probing while it's working
* or we can have race conditions */ * or we can have race conditions */
/* This functionality really should be provided by the khubd thread */ /* This functionality really should be provided by the khubd thread */
for (i = 0; i < pusb_dev_save->actconfig->desc.bNumInterfaces; i++) { for (i = 0; i < us->pusb_dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf = struct usb_interface *intf =
&pusb_dev_save->actconfig->interface[i]; &us->pusb_dev->actconfig->interface[i];
/* if this is an unclaimed interface, skip it */ /* if this is an unclaimed interface, skip it */
if (!intf->driver) { if (!intf->driver) {
...@@ -274,14 +263,6 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -274,14 +263,6 @@ static int bus_reset( Scsi_Cmnd *srb )
return SUCCESS; return SUCCESS;
} }
/* FIXME: This doesn't do anything right now */
static int host_reset( Scsi_Cmnd *srb )
{
printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
bus_reset(srb);
return FAILED;
}
/*********************************************************************** /***********************************************************************
* /proc/scsi/ functions * /proc/scsi/ functions
***********************************************************************/ ***********************************************************************/
...@@ -291,29 +272,23 @@ static int host_reset( Scsi_Cmnd *srb ) ...@@ -291,29 +272,23 @@ static int host_reset( Scsi_Cmnd *srb )
#define SPRINTF(args...) \ #define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
static int proc_info (char *buffer, char **start, off_t offset, int length, static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
int hostno, int inout) int length, int hostno, int inout)
{ {
struct us_data *us; struct us_data *us;
char *pos = buffer; char *pos = buffer;
struct Scsi_Host *hostptr;
/* if someone is sending us data, just throw it away */ /* if someone is sending us data, just throw it away */
if (inout) if (inout)
return length; return length;
/* lock the data structures */ /* find our data from the given hostno */
down(&us_list_semaphore); hostptr = scsi_host_hn_get(hostno);
if (!hostptr) { /* if we couldn't find it, we return an error */
/* find our data from hostno */ return -ESRCH;
us = us_list;
while (us) {
if (us->host_no == hostno)
break;
us = us->next;
} }
us = (struct us_data*)hostptr->hostdata[0];
/* release our lock on the data structures */
up(&us_list_semaphore);
/* if we couldn't find it, we return an error */ /* if we couldn't find it, we return an error */
if (!us) { if (!us) {
...@@ -332,10 +307,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -332,10 +307,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
SPRINTF(" Protocol: %s\n", us->protocol_name); SPRINTF(" Protocol: %s\n", us->protocol_name);
SPRINTF(" Transport: %s\n", us->transport_name); SPRINTF(" Transport: %s\n", us->transport_name);
/* show the GUID of the device */ /* release the reference count on this host */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); scsi_host_put(hostptr);
SPRINTF(" Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ?
"Yes" : "No"));
/* /*
* Calculate start of next buffer, and return value. * Calculate start of next buffer, and return value.
...@@ -351,33 +324,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -351,33 +324,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
} }
/* /*
* this defines our 'host' * this defines our host template, with which we'll allocate hosts
*/ */
Scsi_Host_Template usb_stor_host_template = { struct SHT usb_stor_host_template = {
/* basic userland interface stuff */
.name = "usb-storage", .name = "usb-storage",
.proc_info = proc_info, .proc_name = "usb-storage",
.info = host_info, .proc_info = usb_storage_proc_info,
.proc_dir = NULL,
.info = usb_storage_info,
.ioctl = NULL,
/* old-style detect and release */
.detect = NULL,
.release = NULL,
/* command interface -- queued only */
.command = NULL,
.queuecommand = usb_storage_queuecommand,
/* error and abort handlers */
.eh_abort_handler = usb_storage_command_abort,
.eh_device_reset_handler = usb_storage_device_reset,
.eh_bus_reset_handler = usb_storage_bus_reset,
.eh_host_reset_handler = NULL,
.eh_strategy_handler = NULL,
/* queue commands only, only one command per LUN */
.can_queue = 1,
.cmd_per_lun = 1,
.detect = detect, /* unknown initiator id */
.release = release, .this_id = -1,
.command = command,
.queuecommand = queuecommand,
.eh_abort_handler = command_abort, /* no limit on commands */
.eh_device_reset_handler =device_reset, .max_sectors = 0,
.eh_bus_reset_handler = bus_reset,
.eh_host_reset_handler =host_reset,
.can_queue = 1, /* pre- and post- device scan functions */
.this_id = -1, .slave_alloc = NULL,
.slave_configure = NULL,
.slave_destroy = NULL,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL, .sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.present = 0, /* use 32-bit address space for DMA */
.unchecked_isa_dma = FALSE, .unchecked_isa_dma = FALSE,
.highmem_io = FALSE,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal.
*/
.use_clustering = TRUE, .use_clustering = TRUE,
.emulated = TRUE
/* emulated HBA */
.emulated = TRUE,
/* sorry, no BIOS to help us */
.bios_param = NULL,
/* module management */
.module = THIS_MODULE
}; };
/* For a device that is "Not Ready" */ /* For a device that is "Not Ready" */
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_notready[18];
extern unsigned char usb_stor_sense_invalidCDB[18]; extern unsigned char usb_stor_sense_invalidCDB[18];
extern Scsi_Host_Template usb_stor_host_template; extern struct SHT usb_stor_host_template;
extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
......
...@@ -55,8 +55,7 @@ ...@@ -55,8 +55,7 @@
#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */ #define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */
#endif #endif
#ifdef CONFIG_USB_STORAGE_SDDR09 #ifdef CONFIG_USB_STORAGE_SDDR09
#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */
SDDR-09 */
#endif #endif
#ifdef CONFIG_USB_STORAGE_SDDR55 #ifdef CONFIG_USB_STORAGE_SDDR55
#define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */ #define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */
......
...@@ -93,16 +93,6 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); ...@@ -93,16 +93,6 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* Per device data
*/
static int my_host_number;
/* The list of structures and the protective lock for them */
struct us_data *us_list;
struct semaphore us_list_semaphore;
static int storage_probe(struct usb_interface *iface, static int storage_probe(struct usb_interface *iface,
const struct usb_device_id *id); const struct usb_device_id *id);
...@@ -319,7 +309,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -319,7 +309,7 @@ static int usb_stor_control_thread(void * __us)
spin_unlock_irq(&current->sig->siglock); spin_unlock_irq(&current->sig->siglock);
/* set our name for identification purposes */ /* set our name for identification purposes */
sprintf(current->comm, "usb-storage-%d", us->host_number); sprintf(current->comm, "usb-storage");
unlock_kernel(); unlock_kernel();
...@@ -395,35 +385,6 @@ static int usb_stor_control_thread(void * __us) ...@@ -395,35 +385,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = CHECK_CONDITION << 1; us->srb->result = CHECK_CONDITION << 1;
} }
/* our device has gone - pretend not ready */
else if (!(us->flags & US_FL_DEV_ATTACHED)) {
US_DEBUGP("Request is for removed device\n");
/* For REQUEST_SENSE, it's the data. But
* for anything else, it should look like
* we auto-sensed for it.
*/
if (us->srb->cmnd[0] == REQUEST_SENSE) {
memcpy(us->srb->request_buffer,
usb_stor_sense_notready,
sizeof(usb_stor_sense_notready));
us->srb->result = GOOD << 1;
} else if(us->srb->cmnd[0] == INQUIRY) {
/* INQUIRY should always work, per spec... */
unsigned char data_ptr[36] = {
0x20, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
US_DEBUGP("Faking INQUIRY command for disconnected device\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = GOOD << 1;
} else {
/* not ready */
memcpy(us->srb->sense_buffer,
usb_stor_sense_notready,
sizeof(usb_stor_sense_notready));
us->srb->result = CHECK_CONDITION << 1;
}
} /* !(us->flags & US_FL_DEV_ATTACHED) */
/* Handle those devices which need us to fake /* Handle those devices which need us to fake
* their inquiry data */ * their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) && else if ((us->srb->cmnd[0] == INQUIRY) &&
...@@ -547,7 +508,6 @@ static void usb_stor_deallocate_urbs(struct us_data *ss) ...@@ -547,7 +508,6 @@ static void usb_stor_deallocate_urbs(struct us_data *ss)
} }
/* mark the device as gone */ /* mark the device as gone */
ss->flags &= ~ US_FL_DEV_ATTACHED;
usb_put_dev(ss->pusb_dev); usb_put_dev(ss->pusb_dev);
ss->pusb_dev = NULL; ss->pusb_dev = NULL;
} }
...@@ -563,12 +523,10 @@ static int storage_probe(struct usb_interface *intf, ...@@ -563,12 +523,10 @@ static int storage_probe(struct usb_interface *intf,
char mf[USB_STOR_STRING_LEN]; /* manufacturer */ char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */ char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */ char serial[USB_STOR_STRING_LEN]; /* serial number */
GUID(guid); /* Global Unique Identifier */
unsigned int flags; unsigned int flags;
struct us_unusual_dev *unusual_dev; struct us_unusual_dev *unusual_dev;
struct us_data *ss = NULL; struct us_data *ss = NULL;
int result; int result;
int new_device = 0;
/* these are temporary copies -- we test on these, then put them /* these are temporary copies -- we test on these, then put them
* in the us-data structure * in the us-data structure
...@@ -676,8 +634,7 @@ static int storage_probe(struct usb_interface *intf, ...@@ -676,8 +634,7 @@ static int storage_probe(struct usb_interface *intf,
/* At this point, we've decided to try to use the device */ /* At this point, we've decided to try to use the device */
usb_get_dev(dev); usb_get_dev(dev);
/* clear the GUID and fetch the strings */ /* fetch the strings */
GUID_CLEAR(guid);
if (dev->descriptor.iManufacturer) if (dev->descriptor.iManufacturer)
usb_string(dev, dev->descriptor.iManufacturer, usb_string(dev, dev->descriptor.iManufacturer,
mf, sizeof(mf)); mf, sizeof(mf));
...@@ -688,69 +645,7 @@ static int storage_probe(struct usb_interface *intf, ...@@ -688,69 +645,7 @@ static int storage_probe(struct usb_interface *intf,
usb_string(dev, dev->descriptor.iSerialNumber, usb_string(dev, dev->descriptor.iSerialNumber,
serial, sizeof(serial)); serial, sizeof(serial));
/* Create a GUID for this device */
if (dev->descriptor.iSerialNumber && serial[0]) {
/* If we have a serial number, and it's a non-NULL string */
make_guid(guid, dev->descriptor.idVendor,
dev->descriptor.idProduct, serial);
} else {
/* We don't have a serial number, so we use 0 */
make_guid(guid, dev->descriptor.idVendor,
dev->descriptor.idProduct, "0");
}
/*
* Now check if we have seen this GUID before
* We're looking for a device with a matching GUID that isn't
* already on the system
*/
ss = us_list;
while ((ss != NULL) &&
((ss->flags & US_FL_DEV_ATTACHED) ||
!GUID_EQUAL(guid, ss->guid)))
ss = ss->next;
if (ss != NULL) {
/* Existing device -- re-connect */
US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
GUID_ARGS(guid));
/* lock the device pointers */
down(&(ss->dev_semaphore));
/* establish the connection to the new device upon reconnect */
ss->ifnum = ifnum;
ss->pusb_dev = dev;
ss->flags |= US_FL_DEV_ATTACHED;
/* copy over the endpoint data */
ss->ep_in = ep_in->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->ep_out = ep_out->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
if (ep_int) {
ss->ep_int = ep_int->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->ep_bInterval = ep_int->bInterval;
}
else
ss->ep_int = ss->ep_bInterval = 0;
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
if (usb_stor_allocate_urbs(ss))
goto BadDevice;
/* Re-Initialize the device if it needs it */
if (unusual_dev && unusual_dev->initFunction)
(unusual_dev->initFunction)(ss);
/* unlock the device pointers */
up(&(ss->dev_semaphore));
} else {
/* New device -- allocate memory and initialize */ /* New device -- allocate memory and initialize */
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) { GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n"); printk(KERN_WARNING USB_STORAGE "Out of memory\n");
...@@ -758,7 +653,6 @@ static int storage_probe(struct usb_interface *intf, ...@@ -758,7 +653,6 @@ static int storage_probe(struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
} }
memset(ss, 0, sizeof(struct us_data)); memset(ss, 0, sizeof(struct us_data));
new_device = 1;
/* Initialize the mutexes only when the struct is new */ /* Initialize the mutexes only when the struct is new */
init_completion(&(ss->notify)); init_completion(&(ss->notify));
...@@ -767,7 +661,7 @@ static int storage_probe(struct usb_interface *intf, ...@@ -767,7 +661,7 @@ static int storage_probe(struct usb_interface *intf,
/* copy over the subclass and protocol data */ /* copy over the subclass and protocol data */
ss->subclass = subclass; ss->subclass = subclass;
ss->protocol = protocol; ss->protocol = protocol;
ss->flags = flags | US_FL_DEV_ATTACHED; ss->flags = flags;
ss->unusual_dev = unusual_dev; ss->unusual_dev = unusual_dev;
/* copy over the endpoint data */ /* copy over the endpoint data */
...@@ -810,9 +704,6 @@ static int storage_probe(struct usb_interface *intf, ...@@ -810,9 +704,6 @@ static int storage_probe(struct usb_interface *intf,
if (strlen(ss->serial) == 0) if (strlen(ss->serial) == 0)
strncpy(ss->serial, "None", USB_STOR_STRING_LEN); strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
/* copy the GUID we created before */
memcpy(ss->guid, guid, sizeof(guid));
/* /*
* Set the handler pointers based on the protocol * Set the handler pointers based on the protocol
* Again, this data is persistant across reattachments * Again, this data is persistant across reattachments
...@@ -968,19 +859,6 @@ static int storage_probe(struct usb_interface *intf, ...@@ -968,19 +859,6 @@ static int storage_probe(struct usb_interface *intf,
* host definition, and register with the higher SCSI layers * host definition, and register with the higher SCSI layers
*/ */
/* Initialize the host template based on the default one */
memcpy(&(ss->htmplt), &usb_stor_host_template,
sizeof(usb_stor_host_template));
/* Grab the next host number */
ss->host_number = my_host_number++;
/* We abuse this pointer so we can pass the ss pointer to
* the host controller thread in us_detect. But how else are
* we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
/* Just before we start our control thread, initialize /* Just before we start our control thread, initialize
* the device if it needs initialization */ * the device if it needs initialization */
if (unusual_dev && unusual_dev->initFunction) if (unusual_dev && unusual_dev->initFunction)
...@@ -1002,10 +880,9 @@ static int storage_probe(struct usb_interface *intf, ...@@ -1002,10 +880,9 @@ static int storage_probe(struct usb_interface *intf,
/* unlock the device pointers */ /* unlock the device pointers */
up(&(ss->dev_semaphore)); up(&(ss->dev_semaphore));
/* now register - our detect function will be called */ /* now register */
ss->htmplt.module = THIS_MODULE; ss->host = scsi_register(&usb_stor_host_template, sizeof(ss));
result = scsi_register_host(&(ss->htmplt)); if (!ss->host) {
if (result) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to register the scsi host\n"); "Unable to register the scsi host\n");
...@@ -1019,15 +896,26 @@ static int storage_probe(struct usb_interface *intf, ...@@ -1019,15 +896,26 @@ static int storage_probe(struct usb_interface *intf,
goto BadDevice; goto BadDevice;
} }
/* lock access to the data structures */ /* set the hostdata to prepare for scanning */
down(&us_list_semaphore); ss->host->hostdata[0] = (unsigned long)ss;
/* put us in the list */ /* associate this host with our interface */
ss->next = us_list; scsi_set_device(ss->host, &intf->dev);
us_list = ss;
/* now add the host */
result = scsi_add_host(ss->host, NULL);
if (result) {
printk(KERN_WARNING USB_STORAGE
"Unable to add the scsi host\n");
/* tell the control thread to exit */
ss->srb = NULL;
up(&ss->sema);
wait_for_completion(&ss->notify);
/* release the data structure lock */ /* re-lock the device pointers */
up(&us_list_semaphore); down(&ss->dev_semaphore);
goto BadDevice;
} }
printk(KERN_DEBUG printk(KERN_DEBUG
...@@ -1041,11 +929,10 @@ static int storage_probe(struct usb_interface *intf, ...@@ -1041,11 +929,10 @@ static int storage_probe(struct usb_interface *intf,
/* we come here if there are any problems */ /* we come here if there are any problems */
/* ss->dev_semaphore must be locked */ /* ss->dev_semaphore must be locked */
BadDevice: BadDevice:
US_DEBUGP("storage_probe() failed\n"); US_DEBUGP("storage_probe() failed\n");
usb_stor_deallocate_urbs(ss); usb_stor_deallocate_urbs(ss);
up(&ss->dev_semaphore); up(&ss->dev_semaphore);
if (new_device)
kfree(ss); kfree(ss);
return -EIO; return -EIO;
} }
...@@ -1053,21 +940,85 @@ static int storage_probe(struct usb_interface *intf, ...@@ -1053,21 +940,85 @@ static int storage_probe(struct usb_interface *intf,
/* Handle a disconnect event from the USB core */ /* Handle a disconnect event from the USB core */
static void storage_disconnect(struct usb_interface *intf) static void storage_disconnect(struct usb_interface *intf)
{ {
struct us_data *ss = usb_get_intfdata(intf); struct us_data *ss;
struct scsi_device *sdev;
US_DEBUGP("storage_disconnect() called\n"); US_DEBUGP("storage_disconnect() called\n");
ss = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
/* this is the odd case -- we disconnected but weren't using it */ /* serious error -- we're attempting to disconnect an interface but
if (!ss) { * cannot locate the local data structure
US_DEBUGP("-- device was not in use\n"); */
return; BUG_ON(ss == NULL);
}
/* set devices offline -- need host lock for this */
scsi_lock(ss->host);
list_for_each_entry(sdev, &ss->host->my_devices, siblings)
sdev->online = 0;
scsi_unlock(ss->host);
/* lock device access -- no need to unlock, as we're going away */
down(&(ss->dev_semaphore)); down(&(ss->dev_semaphore));
/* Complete all pending commands with * cmd->result = DID_ERROR << 16.
* Since we only queue one command at a time, this is pretty easy. */
if (ss->srb) {
ss->srb->result = DID_ERROR << 16;
ss->srb->scsi_done(ss->srb);
}
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
/* remove the pointer to the data structure we were using */
(struct us_data*)ss->host->hostdata[0] = NULL;
/* begin SCSI host removal sequence */
if(scsi_remove_host(ss->host)) {
US_DEBUGP("-- SCSI refused to unregister\n");
BUG();
return;
};
/* finish SCSI host removal sequence */
scsi_unregister(ss->host);
/* Kill the control threads
*
* Enqueue the command, wake up the thread, and wait for
* notification that it has exited.
*/
US_DEBUGP("-- sending exit command to thread\n");
BUG_ON(atomic_read(&ss->sm_state) != US_STATE_IDLE);
ss->srb = NULL;
up(&(ss->sema));
wait_for_completion(&(ss->notify));
/* free allocated urbs */
usb_stor_deallocate_urbs(ss); usb_stor_deallocate_urbs(ss);
/* If there's extra data in the us_data structure then
* free that first */
if (ss->extra) {
/* call the destructor routine, if it exists */
if (ss->extra_destructor) {
US_DEBUGP("-- calling extra_destructor()\n");
ss->extra_destructor(ss->extra);
}
/* destroy the extra data */
US_DEBUGP("-- freeing the data structure\n");
kfree(ss->extra);
}
/* up the semaphore so auto-code-checkers won't complain about
* the down/up imbalance */
up(&(ss->dev_semaphore)); up(&(ss->dev_semaphore));
/* free the structure itself */
kfree (ss);
} }
/*********************************************************************** /***********************************************************************
...@@ -1078,11 +1029,6 @@ int __init usb_stor_init(void) ...@@ -1078,11 +1029,6 @@ int __init usb_stor_init(void)
{ {
printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
/* initialize internal global data elements */
us_list = NULL;
init_MUTEX(&us_list_semaphore);
my_host_number = 0;
/* register the driver, return -1 if error */ /* register the driver, return -1 if error */
if (usb_register(&usb_storage_driver) < 0) if (usb_register(&usb_storage_driver) < 0)
return -1; return -1;
...@@ -1094,16 +1040,16 @@ int __init usb_stor_init(void) ...@@ -1094,16 +1040,16 @@ int __init usb_stor_init(void)
void __exit usb_stor_exit(void) void __exit usb_stor_exit(void)
{ {
struct us_data *next;
US_DEBUGP("usb_stor_exit() called\n"); US_DEBUGP("usb_stor_exit() called\n");
/* Deregister the driver /* Deregister the driver
* This eliminates races with probes and disconnects * This will cause disconnect() to be called for each
* attached unit
*/ */
US_DEBUGP("-- calling usb_deregister()\n"); US_DEBUGP("-- calling usb_deregister()\n");
usb_deregister(&usb_storage_driver) ; usb_deregister(&usb_storage_driver) ;
#if 0
/* While there are still virtual hosts, unregister them /* While there are still virtual hosts, unregister them
* Note that it's important to do this completely before removing * Note that it's important to do this completely before removing
* the structures because of possible races with the /proc * the structures because of possible races with the /proc
...@@ -1111,7 +1057,7 @@ void __exit usb_stor_exit(void) ...@@ -1111,7 +1057,7 @@ void __exit usb_stor_exit(void)
*/ */
for (next = us_list; next; next = next->next) { for (next = us_list; next; next = next->next) {
US_DEBUGP("-- calling scsi_unregister_host()\n"); US_DEBUGP("-- calling scsi_unregister_host()\n");
scsi_unregister_host(&(next->htmplt)); scsi_unregister_host(&usb_stor_host_template);
} }
/* While there are still structures, free them. Note that we are /* While there are still structures, free them. Note that we are
...@@ -1142,6 +1088,7 @@ void __exit usb_stor_exit(void) ...@@ -1142,6 +1088,7 @@ void __exit usb_stor_exit(void)
/* advance the list pointer */ /* advance the list pointer */
us_list = next; us_list = next;
} }
#endif
} }
module_init(usb_stor_init); module_init(usb_stor_init);
......
...@@ -52,33 +52,6 @@ ...@@ -52,33 +52,6 @@
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
/*
* GUID definitions
*/
#define GUID(x) __u32 x[3]
#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
#define GUID_FORMAT "%08x%08x%08x"
#define GUID_ARGS(x) x[0], x[1], x[2]
static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
{
pg[0] = (vendor << 16) | product;
pg[1] = pg[2] = 0;
while (*serial) {
pg[1] <<= 4;
pg[1] |= pg[2] >> 28;
pg[2] <<= 4;
if (*serial >= 'a')
*serial -= 'a' - 'A';
pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
: *serial - 'A' + 10;
serial++;
}
}
struct us_data; struct us_data;
/* /*
...@@ -104,7 +77,6 @@ struct us_unusual_dev { ...@@ -104,7 +77,6 @@ struct us_unusual_dev {
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */
#define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */
#define US_FL_DEV_ATTACHED 0x00010000 /* is the device attached? */
#define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */ #define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */
#define US_FLIDX_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */ #define US_FLIDX_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */
...@@ -124,12 +96,9 @@ typedef void (*extra_data_destructor)(void *); /* extra data destructor */ ...@@ -124,12 +96,9 @@ typedef void (*extra_data_destructor)(void *); /* extra data destructor */
/* we allocate one of these for every device that we remember */ /* we allocate one of these for every device that we remember */
struct us_data { struct us_data {
struct us_data *next; /* next device */
/* The device we're working with /* The device we're working with
* It's important to note: * It's important to note:
* (o) you must hold dev_semaphore to change pusb_dev * (o) you must hold dev_semaphore to change pusb_dev
* (o) DEV_ATTACHED in flags should change whenever pusb_dev does
*/ */
struct semaphore dev_semaphore; /* protect pusb_dev */ struct semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */ struct usb_device *pusb_dev; /* this usb_device */
...@@ -163,11 +132,7 @@ struct us_data { ...@@ -163,11 +132,7 @@ struct us_data {
proto_cmnd proto_handler; /* protocol handler */ proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */ /* SCSI interfaces */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */ struct Scsi_Host *host; /* our dummy host data */
Scsi_Host_Template htmplt; /* own host template */
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */ Scsi_Cmnd *srb; /* current srb */
/* thread information */ /* thread information */
...@@ -192,10 +157,6 @@ struct us_data { ...@@ -192,10 +157,6 @@ struct us_data {
extra_data_destructor extra_destructor;/* extra data destructor */ extra_data_destructor extra_destructor;/* extra data destructor */
}; };
/* The list of structures and the protective lock for them */
extern struct us_data *us_list;
extern struct semaphore us_list_semaphore;
/* The structure which defines our driver */ /* The structure which defines our driver */
extern struct usb_driver usb_storage_driver; extern struct usb_driver usb_storage_driver;
......
...@@ -554,7 +554,6 @@ extern int usb_disabled(void); ...@@ -554,7 +554,6 @@ extern int usb_disabled(void);
#define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
#define URB_TIMEOUT_KILLED 0x1000 /* only set by HCD! */
struct usb_iso_packet_descriptor { struct usb_iso_packet_descriptor {
unsigned int offset; unsigned int offset;
......
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