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

Merge

parents 46b11ba9 fb6d52e5
......@@ -212,6 +212,14 @@ config NET_ETHERNET
kernel: saying N will just cause the configurator to skip all
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
bool "ARM EBSA110 AM79C961A support"
depends on NET_ETHERNET && ARM && ARCH_EBSA110
......
......@@ -57,6 +57,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
# end link order section
#
obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_AIRONET4500) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o
......@@ -193,3 +194,6 @@ obj-$(CONFIG_NET_WIRELESS) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/
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)
if (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++) {
/* if we insert more than TTY_FLIPBUF_SIZE characters,
* we drop them. */
......@@ -697,6 +697,7 @@ static void acm_disconnect(struct usb_interface *intf)
static struct usb_device_id acm_ids[] = {
{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
{ USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
{ }
};
......
......@@ -68,7 +68,7 @@
static char *format_topo =
/* 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 =
/* S: Manufacturer=xxxx */
......
......@@ -310,9 +310,9 @@ static int rh_string (
} else
return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
data [0] = 2 * (strlen (buf) + 1);
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)
return status;
}
/* lower level hcd code should use *_dma exclusively */
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
/* lower level hcd code should use *_dma exclusively,
* 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))
urb->setup_dma = dma_map_single (
hcd->controller,
......
......@@ -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 list_head dev_list; /* on this hcd */
struct list_head urb_list; /* pending on this dev */
......@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_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 */
......
......@@ -206,6 +206,7 @@ static void sg_clean (struct usb_sg_request *io)
kfree (io->urbs);
io->urbs = 0;
}
if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0;
}
......@@ -301,6 +302,7 @@ int usb_sg_init (
{
int i;
int urb_flags;
int dma;
if (!io || !dev || !sg
|| usb_pipecontrol (pipe)
......@@ -314,8 +316,16 @@ int usb_sg_init (
io->sg = sg;
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);
else
io->entries = nents;
/* initialize all the urbs we'll use */
if (io->entries <= 0)
return io->entries;
......@@ -347,8 +357,17 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0;
if (dma) {
/* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (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) {
len = min_t (unsigned, len, length);
length -= len;
......@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
retval = 0;
i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT?
// how about imposing a backoff?
set_current_state (TASK_UNINTERRUPTIBLE);
schedule ();
yield ();
break;
/* no error? continue immediately.
......
......@@ -1224,7 +1224,8 @@ void usb_buffer_free (
*
* 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
* 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
* as the target of a large periodic transfer, with usb_buffer_dmasync()
......@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb)
|| !(controller = bus->controller))
return 0;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP;
return urb;
}
......@@ -1271,6 +1275,7 @@ void usb_buffer_dmasync (struct urb *urb)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
......@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? 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,
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// 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,
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_sync_sg (controller, sg, n_hw_ents,
......@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_unmap_sg (controller, sg, n_hw_ents,
......
......@@ -277,7 +277,26 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \
}; 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 hw_curr;
......@@ -286,26 +305,49 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
unsigned temp;
unsigned size = *sizep;
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);
hw_curr = cpu_to_le32p (&qh->hw_current);
hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0;
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,
speed_char (scratch),
(scratch >> 8) & 0x000f,
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;
next += temp;
/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list);
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,
"\n\t%std/%p %s len=%d %08x urb %p",
(hw_curr == td->qtd_dma) ? "*" : "",
td, ({ char *tmp;
"\n\t%p%c%s len=%d %08x urb %p",
td, mark, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
case 1: tmp = "in"; break;
......@@ -315,13 +357,27 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
(scratch >> 16) & 0x7fff,
scratch,
td->urb);
if (temp < 0)
temp = 0;
else if (size < temp)
temp = size;
size -= temp;
next += temp;
if (temp == size)
goto done;
}
temp = snprintf (next, size, "\n");
*sizep = size - temp;
*nextp = next + temp;
if (temp < 0)
temp = 0;
else if (size < temp)
temp = size;
size -= temp;
next += temp;
done:
*sizep = size;
*nextp = next;
}
static ssize_t
......@@ -344,14 +400,15 @@ show_async (struct device *dev, char *buf)
* one QH per line, and TDs we know about
*/
spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh)
qh_lines (qh, &next, &size);
if (ehci->reclaim) {
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (ehci, qh, &next, &size);
if (ehci->reclaim && size > 0) {
temp = snprintf (next, size, "\nreclaim =\n");
size -= 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);
......@@ -421,7 +478,7 @@ show_periodic (struct device *dev, char *buf)
scratch & 0x007f,
(scratch >> 8) & 0x000f,
p.qh->usecs, p.qh->c_usecs,
scratch >> 16);
0x7ff & (scratch >> 16));
/* FIXME TD info too */
......@@ -490,7 +547,8 @@ show_registers (struct device *dev, char *buf)
/* Capability Registers */
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);
size -= temp;
next += temp;
......
......@@ -94,7 +94,7 @@
* 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_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
......@@ -110,10 +110,11 @@ static const char hcd_name [] = "ehci-hcd";
/* magic numbers that can affect system performance */
#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_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#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_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
......@@ -416,13 +417,26 @@ static int ehci_start (struct usb_hcd *hcd)
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 */
temp = readl (&ehci->regs->command) & 0xff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0;
temp |= 1 << (16 + log2_irq_thresh);
// 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),
// Philips, Intel, and maybe others need CMD_RUN before the
// 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)
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
int maybe_irq = 1;
spin_lock_irqsave (&ehci->lock, flags);
switch (usb_pipetype (urb->pipe)) {
......@@ -769,23 +782,23 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
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
&& HCD_IS_RUNNING (ehci->hcd.state)
) {
spin_unlock_irqrestore (&ehci->lock, flags);
struct ehci_qh *last;
if (maybe_irq) {
if (in_interrupt ())
return -EAGAIN;
maybe_irq = 0;
}
/* let pending unlinks complete, so this can start */
wait_ms (1);
for (last = ehci->reclaim;
last->reclaim;
last = last->reclaim)
continue;
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;
spin_lock_irqsave (&ehci->lock, flags);
}
if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
/* bypass IAA if the hc can't care */
} else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
end_unlink_async (ehci, NULL);
/* 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)
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) {
ehci_qtd_init (qtd, dma);
if (ehci->async)
qtd->hw_alt_next = ehci->async->hw_alt_next;
}
return qtd;
}
......
......@@ -43,7 +43,8 @@
/* fill a qtd, returning how much of the buffer we were able to queue up */
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;
u64 addr = buf;
......@@ -69,6 +70,10 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
else
count = len;
}
/* short packets may only terminate transfers */
if (count != len)
count -= (count % maxpacket);
}
qtd->hw_token = cpu_to_le32 ((count << 16) | token);
qtd->length = count;
......@@ -85,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{
qh->hw_current = 0;
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 */
wmb ();
......@@ -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)
static inline void qtd_copy_status (
static void qtd_copy_status (
struct ehci_hcd *ehci,
struct urb *urb,
size_t length,
......@@ -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 list_head *entry, *tmp;
int stopped = 0;
int stopped;
unsigned count = 0;
int do_status = 0;
u8 state;
if (unlikely (list_empty (&qh->qtd_list)))
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.
* after faults (including short reads), cleanup this urb
* then let the queue advance.
......@@ -261,7 +278,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
rmb ();
token = le32_to_cpu (qtd->hw_token);
stopped = stopped
|| (qh->qh_state == QH_STATE_IDLE)
|| (HALT_BIT & qh->hw_token) != 0
|| (ehci->hcd.state == USB_STATE_HALT);
......@@ -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 */
if (IS_SHORT_READ (token)
&& !(token & QTD_STS_HALT)
&& ehci->async->hw_alt_next
== qh->hw_alt_next)
&& (qh->hw_alt_next & QTD_MASK)
== ehci->async->hw_alt_next) {
stopped = 1;
goto halt;
}
/* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped)) {
last = 0;
break;
} else {
/* ignore active qtds unless some previous qtd
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
if ((token & QTD_STS_ACTIVE)
&& urb->status == -EINPROGRESS) {
last = 0;
if (likely (urb->status == -EINPROGRESS))
continue;
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
do_status = 0;
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) {
halt:
qh->hw_token |= HALT_BIT;
wmb ();
stopped = 1;
}
}
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
do_status = (urb->status == -EREMOTEIO)
&& usb_pipecontrol (urb->pipe);
spin_unlock (&urb->lock);
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)
ehci_qtd_free (ehci, last);
}
/* restore original state; caller must unlink or relink */
qh->qh_state = state;
/* update qh after fault cleanup */
if (unlikely ((HALT_BIT & qh->hw_token) != 0)) {
qh_update (ehci, qh,
......@@ -367,7 +403,7 @@ qh_urb_transaction (
struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf;
int len, maxpacket;
int is_input, status_patch = 0;
int is_input;
u32 token;
/*
......@@ -388,7 +424,7 @@ qh_urb_transaction (
if (usb_pipecontrol (urb->pipe)) {
/* SETUP pid */
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 */
token ^= QTD_TOGGLE;
......@@ -399,10 +435,6 @@ qh_urb_transaction (
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
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 (
else
buf = 0;
// FIXME this 'buf' check break some zlps...
if (!buf || is_input)
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
......@@ -427,9 +460,11 @@ qh_urb_transaction (
for (;;) {
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;
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 */
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
......@@ -447,6 +482,13 @@ qh_urb_transaction (
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;
* bulk ones may need a terminating short packet (zero length).
......@@ -473,21 +515,8 @@ qh_urb_transaction (
list_add_tail (&qtd->qtd_list, head);
/* 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 */
......@@ -611,6 +640,7 @@ qh_make (
case USB_SPEED_FULL:
/* EPS 0 means "full" */
if (type != PIPE_INTERRUPT)
info1 |= (EHCI_TUNE_RL_TT << 28);
if (type == PIPE_CONTROL) {
info1 |= (1 << 27); /* for TT */
......@@ -628,12 +658,13 @@ qh_make (
case USB_SPEED_HIGH: /* no TT involved */
info1 |= (2 << 12); /* EPS "high" */
info1 |= (EHCI_TUNE_RL_HS << 28);
if (type == PIPE_CONTROL) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (type == PIPE_BULK) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 512 << 16; /* usb2 fixed maxpacket */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else { /* PIPE_INTERRUPT */
......@@ -769,8 +800,7 @@ static struct ehci_qh *qh_append_tds (
&& !usb_pipecontrol (urb->pipe)) {
/* "never happens": drivers do stall cleanup right */
if (qh->qh_state != QH_STATE_IDLE
&& (cpu_to_le32 (QTD_STS_HALT)
& qh->hw_token) == 0)
&& qh->qh_state != QH_STATE_COMPLETING)
ehci_warn (ehci, "clear toggle dev%d "
"ep%d%s: not idle\n",
usb_pipedevice (urb->pipe),
......@@ -809,7 +839,6 @@ static struct ehci_qh *qh_append_tds (
__list_splice (qtd_list, qh->qtd_list.prev);
ehci_qtd_init (qtd, qtd->qtd_dma);
qtd->hw_alt_next = ehci->async->hw_alt_next;
qh->dummy = qtd;
/* hc must see the new dummy at list end */
......@@ -877,9 +906,12 @@ submit_async (
/* 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)
{
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
del_timer (&ehci->watchdog);
......@@ -890,6 +922,10 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
ehci->reclaim = 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);
if (!list_empty (&qh->qtd_list)
......@@ -909,6 +945,9 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
jiffies + EHCI_ASYNC_JIFFIES);
}
}
if (next)
start_unlink_async (ehci, next);
}
/* 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)
#ifdef DEBUG
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
// this macro lies except on SMP compiles
|| !spin_is_locked (&ehci->lock)
......@@ -953,6 +993,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
wmb ();
if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
* this will recurse, probably not much
*/
end_unlink_async (ehci, NULL);
return;
}
......
......@@ -236,12 +236,12 @@ struct ehci_qtd {
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
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 */
size_t length; /* length of buffer */
} __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 */
......@@ -305,6 +305,7 @@ struct ehci_qh {
union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */
struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */
atomic_t refcount;
unsigned stamp;
......@@ -313,6 +314,8 @@ struct ehci_qh {
#define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still 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 */
u8 usecs; /* intr bandwidth */
......@@ -426,16 +429,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd)
#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)
#ifndef DEBUG
......
......@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb)
if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
/* URB active? */
if (urb->transfer_flags & (URB_ASYNC_UNLINK | URB_TIMEOUT_KILLED)) {
if (urb->transfer_flags & URB_ASYNC_UNLINK) {
/* asynchronous with callback */
/* relink the urb to the del list */
list_move (&urb->urb_list, &hci->del_list);
......@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb)
struct urb *urb = (struct urb *) lurb;
DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= URB_TIMEOUT_KILLED;
hci_unlink_urb (urb);
}
#endif
......
......@@ -203,26 +203,26 @@ static int ohci_urb_enqueue (
return -ENOMEM;
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 */
urb_priv->length = size;
urb_priv->ed = ed;
/* allocate the TDs (updating hash chains) */
/* allocate the TDs (deferring hash chain updates) */
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]) {
urb_priv->length = i;
retval = -ENOMEM;
goto fail;
urb_free_priv (ohci, urb_priv);
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 */
......
......@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) {
int hash;
/* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma;
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (dma);
td->td_hash = hc->td_hash [hash];
hc->td_hash [hash] = td;
/* hashed in td_fill */
}
return td;
}
......
......@@ -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) */
static void
td_fill (unsigned int info,
td_fill (struct ohci_hcd *ohci, u32 info,
dma_addr_t data, int len,
struct urb *urb, int index)
{
struct td *td, *td_pt;
struct urb_priv *urb_priv = urb->hcpriv;
int is_iso = info & TD_ISO;
int hash;
// ASSERT (index < urb_priv->length);
......@@ -516,11 +517,16 @@ td_fill (unsigned int info,
td->hwBE = 0;
td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
/* HC might read the TD right after we link it ... */
wmb ();
/* append to queue */
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;
}
......@@ -578,7 +584,7 @@ static void td_submit_urb (
: TD_T_TOGGLE | TD_CC | TD_DP_IN;
/* TDs _could_ transfer up to 8K each */
while (data_len > 4096) {
td_fill (info, data, 4096, urb, cnt);
td_fill (ohci, info, data, 4096, urb, cnt);
data += 4096;
data_len -= 4096;
cnt++;
......@@ -586,11 +592,11 @@ static void td_submit_urb (
/* maybe avoid ED halt on final TD short read */
if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
info |= TD_R;
td_fill (info, data, data_len, urb, cnt);
td_fill (ohci, info, data, data_len, urb, cnt);
cnt++;
if ((urb->transfer_flags & URB_ZERO_PACKET)
&& cnt < urb_priv->length) {
td_fill (info, 0, 0, urb, cnt);
td_fill (ohci, info, 0, 0, urb, cnt);
cnt++;
}
/* maybe kickstart bulk list */
......@@ -605,17 +611,17 @@ static void td_submit_urb (
*/
case PIPE_CONTROL:
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) {
info = TD_CC | TD_R | TD_T_DATA1;
info |= is_out ? TD_DP_OUT : TD_DP_IN;
/* 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
? TD_CC | TD_DP_IN | 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 */
wmb ();
writel (OHCI_CLF, &ohci->regs->cmdstatus);
......@@ -634,7 +640,7 @@ static void td_submit_urb (
// a 2^16 iso range, vs other HCs max of 2^10)
frame += cnt * urb->interval;
frame &= 0xffff;
td_fill (TD_CC | TD_ISO | frame,
td_fill (ohci, TD_CC | TD_ISO | frame,
data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt);
}
......
......@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next;
u->transfer_flags |= URB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u);
}
......
/* -*- 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) 2002, 2003 Henning Meier-Geinitz
*
* 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
* modify it under the terms of the GNU General Public License as
......@@ -300,8 +303,6 @@
* Frank Zago <fzago@greshamstorage.com> and
* 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
* - Added Mustek BearPaw 2400 TA. Thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>.
......@@ -332,12 +333,18 @@
* <oliver@neukum.name>.
*
* 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
* of everytime any USB device is plugged in.
* - Removed PV8630 ioctls. Use the standard ioctls instead.
* - Made endpoint detection more generic. Basically, only one bulk-in
* endpoint is required, everything else is optional.
* - New maintainer: Henning Meier-Geinitz.
* - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy.
*
* TODO
* - Performance
......@@ -360,7 +367,7 @@
* - All the developers that are working on USB SANE backends or other
* applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* to be the new USB Scanner maintainer.
* and Henning Meier-Geinitz to be the new USB Scanner maintainer.
*
* Performance:
*
......@@ -369,6 +376,14 @@
* 24 Bit Color ~ 70 secs - 3.6 Mbit/sec
* 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
#include <asm/byteorder.h>
/*
......@@ -461,7 +476,7 @@ open_scanner(struct inode * inode, struct file * file)
}
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;
goto out_error;
}
......@@ -1047,6 +1062,9 @@ probe_scanner(struct usb_interface *intf,
if (scn->devfs == NULL)
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);
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
* 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
* modify it under the terms of the GNU General Public License as
......@@ -19,11 +20,16 @@
* along with this program; if not, write to the Free Software
* 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/kernel.h>
#include <linux/errno.h>
......@@ -45,7 +51,7 @@
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_LICENSE("GPL");
......@@ -65,79 +71,90 @@ MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
static struct usb_device_id scanner_device_ids [] = {
/* 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, 0x1a2a) }, /* Another 620U */
{ USB_DEVICE(0x04a5, 0x2022) }, /* 340U */
{ USB_DEVICE(0x04a5, 0x2040) }, /* 620U (!) */
{ USB_DEVICE(0x04a5, 0x2060) }, /* 620U & 640U (!)*/
{ USB_DEVICE(0x04a5, 0x207e) }, /* 640BU */
{ USB_DEVICE(0x04a5, 0x20b0) }, /* Benq 4300 */
{ USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
{ USB_DEVICE(0x04a5, 0x20c0) }, /* 1240UT, 1240U */
{ USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
{ USB_DEVICE(0x04a5, 0x20b0) }, /* Benq 4300 */
{ USB_DEVICE(0x04a5, 0x20fe) }, /* Benq 5300 */
{ USB_DEVICE(0x04a5, 0x20fc) }, /* Benq 5000 */
{ USB_DEVICE(0x04a5, 0x20fe) }, /* Benq 5300 */
/* Agfa */
{ USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
{ USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
{ USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
{ USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */
{ USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
{ USB_DEVICE(0x06bd, 0x208f) }, /* SnapScan e50*/
{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
{ USB_DEVICE(0x06bd, 0x2093) }, /* SnapScan e10*/
{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
{ USB_DEVICE(0x06bd, 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, 0x20ff) }, /* SnapScan e42*/
/* Artec */
{ USB_DEVICE(0x05d8, 0x4001) }, /* Ultima 2000 */
{ USB_DEVICE(0x05d8, 0x4002) }, /* Ultima 2000 (GT6801 based) */
/* Benq: see Acer */
/* Canon */
{ USB_DEVICE(0x04a9, 0x2201) }, /* FB320U */
{ USB_DEVICE(0x04a9, 0x2205) }, /* FB1210U */
{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
{ USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */
{ USB_DEVICE(0x04a9, 0x2205) }, /* CanoScan FB1210U */
{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */
{ USB_DEVICE(0x04a9, 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, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
/* Colorado -- See Primax/Colorado below */
/* Compaq */
{ USB_DEVICE(0x049f, 0x0021) }, /* S200 */
/* Epson -- See Seiko/Epson below */
/* 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, 0x2008) }, /* ColorPage-HR6 V2 */
{ USB_DEVICE(0x0458, 0x2009) }, /* ColorPage-HR6A */
{ USB_DEVICE(0x0458, 0x2011) }, /* ColorPage-Vivid3x */
{ USB_DEVICE(0x0458, 0x2013) }, /* ColorPage-HR7 */
{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage-HR7LE */
{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage-HR6X */
{ USB_DEVICE(0x0458, 0x2008) }, /* ColorPage HR6 V2 */
{ USB_DEVICE(0x0458, 0x2009) }, /* ColorPage HR6A */
{ USB_DEVICE(0x0458, 0x2011) }, /* ColorPage Vivid3x */
{ USB_DEVICE(0x0458, 0x2013) }, /* ColorPage HR7 */
{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
/* Hewlett Packard */
{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */
{ 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, 0x0101) }, /* ScanJet 4100C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
{ USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */
{ USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */
{ USB_DEVICE(0x03f0, 0x0105) }, /* ScanJet 4200C */
{ USB_DEVICE(0x03f0, 0x0201) }, /* ScanJet 6200C */
{ USB_DEVICE(0x03f0, 0x0205) }, /* ScanJet 3300C */
{ USB_DEVICE(0x03f0, 0x0305) }, /* ScanJet 4300C */
{ USB_DEVICE(0x03f0, 0x0401) }, /* ScanJet 5200C */
{ USB_DEVICE(0x03f0, 0x0405) }, /* ScanJet 3400C */
{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */
{ USB_DEVICE(0x03f0, 0x0601) }, /* ScanJet 6300C */
{ USB_DEVICE(0x03f0, 0x0605) }, /* ScanJet 2200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* ScanJet 5300C - NOT SUPPORTED - use hpusbscsi driver */
{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
// { USB_DEVICE(0x03f0, 0x0801) }, /* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
{ USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */
{ USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */
{ USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */
/* iVina */
{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
/* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
/* Lifetec */
{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
/* Memorex */
{ 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, 0x0094) }, /* Phantom 336CX - C3 */
// { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */
......@@ -146,58 +163,59 @@ static struct usb_device_id scanner_device_ids [] = {
// { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
// { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
/* 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 */
/* The following SCSI-over-USB Minolta devices are supported by the
hpusbscsi driver: Enable SCSI and USB hpusbscsi in kernel config */
// { USB_DEVICE(0x0638, 0x026a) }, /* Minolta Dimage Scan Dual II */
// { USB_DEVICE(0x0686, 0x4004) }, /* Scan Elite II (need interrupt ep) */
/* Mustek */
{ USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 (National Semiconductor LM9831) */
{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 (National Semiconductor LM9832) */
{ USB_DEVICE(0x055f, 0x0001) }, /* ScanExpress 1200 CU */
{ USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */
{ USB_DEVICE(0x055f, 0x0002) }, /* ScanExpress 600 CU */
{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
{ USB_DEVICE(0x055f, 0x0003) }, /* ScanExpress 1200 USB */
{ USB_DEVICE(0x055f, 0x0006) }, /* ScanExpress 1200 UB */
{ USB_DEVICE(0x055f, 0x0007) }, /* ScanExpress 1200 USB Plus */
{ USB_DEVICE(0x055f, 0x0210) }, /* ScanExpress A3 USB */
{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
{ USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */
{ USB_DEVICE(0x055f, 0x0210) }, /* ScanExpress A3 USB */
{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
{ USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus */
{ USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */
{ USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */
{ USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */
{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
// { USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */
/* Nikon */
{ USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */
/* 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, 0x0007) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0010) }, /* OpticPro U12 */
{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U */
/* Primax/Colorado */
{ USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
{ USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
{ USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
{ USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
{ USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */
{ USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
{ USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
{ 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, 0x0360) }, /* Colorado USB 19200 */
{ USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
{ USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
{ USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
{ USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
/* Relisis */
// { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
/* Seiko/Epson Corp. */
......@@ -221,6 +239,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
......@@ -230,8 +249,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */
{ USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
/* Visioneer */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
{ USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
{ USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */
......
......@@ -1324,6 +1324,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_MGE_UPS 0xffff
#define USB_DEVICE_ID_MGE_UPS1 0x0001
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
......@@ -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_UPS1, HID_QUIRK_HIDDEV },
{ 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 }
};
......
......@@ -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)
{
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
} else {
/* 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)) ==
NULL) {
skb_trim (skb, 0);
}
NULL)
return NULL;
}
}
......
......@@ -33,6 +33,7 @@
#define ATMSAR_USE_53BYTE_CELL 0x1L
#define ATMSAR_SET_PTI 0x2L
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
/* types */
#define ATMSAR_TYPE_AAL0 ATM_AAL0
......@@ -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);
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length);
#endif /* _ATMSAR_H_ */
......@@ -46,6 +46,7 @@
*
*/
#include <asm/semaphore.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......@@ -58,7 +59,6 @@
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include "atmsar.h"
......@@ -106,20 +106,21 @@
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
/* usb_device_id struct */
static struct usb_device_id udsl_usb_ids[] = {
{USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
{} /* list terminator */
static struct usb_device_id udsl_usb_ids [] = {
{ USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID) },
{ } /* Terminating entry */
};
/* not exporting this prevents the depmod from generating the map that causes the modules to be isnserted as driver.
* we do not want this, we want the script run.
MODULE_DEVICE_TABLE ( usb, udsl_usb_ids);
*/
MODULE_DEVICE_TABLE (usb, udsl_usb_ids);
/* context declarations */
struct udsl_data_ctx {
struct udsl_receiver {
struct list_head list;
struct sk_buff *skb;
struct urb *urb;
struct udsl_instance_data *instance;
......@@ -137,25 +138,32 @@ struct udsl_usb_send_data_context {
*/
struct udsl_instance_data {
struct tasklet_struct recvqueue_tasklet;
struct semaphore serialize;
/* usb device part */
struct usb_device *usb_dev;
struct udsl_data_ctx *rcvbufs;
struct sk_buff_head sndqueue;
struct udsl_usb_send_data_context send_ctx[UDSL_NUMBER_SND_URBS];
int data_started;
struct udsl_usb_send_data_context send_ctx [UDSL_NUMBER_SND_URBS];
int firmware_loaded;
/* atm device part */
struct atm_dev *atm_dev;
struct sk_buff_head recvqueue;
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
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);
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_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 void udsl_atm_processqueue (unsigned long data);
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
static struct atmdev_ops udsl_atm_devops = {
.open = udsl_atm_open,
......@@ -203,6 +210,170 @@ static struct usb_driver udsl_usb_driver = {
.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 **
************/
......@@ -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)
{
struct atm_vcc *walk;
struct sk_buff *skb;
struct atm_dev *atm_dev;
if (!instance->atm_dev)
......@@ -241,10 +394,6 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
atm_dev = instance->atm_dev;
/* clean queue */
while ((skb = skb_dequeue (&instance->recvqueue)))
dev_kfree_skb (skb);
atm_dev->signal = ATM_PHY_SIG_LOST;
walk = atm_dev->vccs;
shutdown_atm_dev (atm_dev);
......@@ -253,16 +402,8 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
wake_up (&walk->sleep);
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
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;
int left = *pos;
if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
if (!left--)
return sprintf (page, "SpeedTouch USB %s-%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
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
return 0;
}
/***************************************************************************
*
* ATM DATA functions
......@@ -325,8 +472,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
PDEBUG ("udsl_atm_send called\n");
if (!dev_data)
if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
return -EINVAL;
}
if (!instance->firmware_loaded)
return -EAGAIN;
switch (vcc->qos.aal) {
case ATM_AAL5:
......@@ -350,67 +502,13 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
break;
default:
return -EINVAL;
};
}
PDEBUG ("udsl_atm_send unsuccessfull\n");
return 0;
nomem:
vcc->pop (vcc, skb);
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)
* SAR driver entries
*
****************************************************************************/
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
{
struct udsl_atm_dev_data *dev_data;
......@@ -426,6 +525,11 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
PDEBUG ("udsl_atm_open called\n");
if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
/* at the moment only AAL5 support */
if (vcc->qos.aal != ATM_AAL5)
return -EINVAL;
......@@ -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;
if (instance->firmware_loaded)
udsl_fire_receivers (instance);
PDEBUG ("udsl_atm_open successfull\n");
return 0;
}
......@@ -464,6 +571,11 @@ static void udsl_atm_close (struct atm_vcc *vcc)
PDEBUG ("udsl_atm_close called\n");
if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
return;
}
/* freeing resources */
/* cancel all sends on this vcc */
udsl_usb_cancelsends (instance, vcc);
......@@ -482,7 +594,7 @@ static void udsl_atm_close (struct atm_vcc *vcc)
PDEBUG ("udsl_atm_close successfull\n");
return;
};
}
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:
return -ENOIOCTLCMD;
}
};
}
/************
......@@ -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);
if (!instance->data_started)
return -EAGAIN;
PACKETDEBUG (skb->data, skb->len);
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
spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
PDEBUG ("udsl_usb_send_data: skb (0x%p) queued\n", skb);
return 0;
};
}
/* init context */
urb = instance->send_ctx[i].urb;
......@@ -620,285 +729,264 @@ static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_v
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,
urb->actual_length, urb->status);
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
{
struct udsl_instance_data *instance = usb_get_intfdata (intf);
ctx = urb->context;
if (!ctx || !ctx->skb)
return;
PDEBUG ("udsl_usb_ioctl entered\n");
instance = ctx->instance;
if (!instance) {
PDEBUG ("NULL instance!\n");
return -ENODEV;
}
switch (urb->status) {
case 0:
PDEBUG ("udsl_usb_data_receive: processing urb with ctx %p, urb %p (%p), skb %p\n",
ctx, ctx ? ctx->urb : NULL, urb, ctx ? ctx->skb : NULL);
/* update the skb structure */
skb_put (ctx->skb, urb->actual_length);
/* 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;
switch (code) {
case UDSL_IOCTL_START:
instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
down (&instance->serialize); /* vs self */
if (!instance->firmware_loaded) {
usb_set_interface (instance->usb_dev, 1, 2);
instance->firmware_loaded = 1;
}
break;
case -ENOENT: /* buffer was unlinked */
case -EILSEQ: /* unplug or timeout */
case -ETIMEDOUT: /* unplug or timeout */
/*
* we don't do anything here and we don't resubmit
*/
return;
up (&instance->serialize);
udsl_fire_receivers (instance);
return 0;
case UDSL_IOCTL_STOP:
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
return 0;
default:
return -ENOTTY;
}
}
usb_fill_bulk_urb (urb,
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)
static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
{
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)
return 1;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
/* set alternate setting 1 on interface 1 */
usb_set_interface (instance->usb_dev, 1, 2);
if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
(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,
usb_maxpacket (instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), 0));
PDEBUG ("Device Accepted\n");
instance->rcvbufs = kmalloc (sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS, GFP_KERNEL);
if (!instance->rcvbufs)
return -ENOMEM;
/* instance init */
if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
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++) {
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
instance->usb_dev = dev;
ctx->urb = NULL;
ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
if (!ctx->skb)
continue;
spin_lock_init (&instance->spare_receivers_lock);
INIT_LIST_HEAD (&instance->spare_receivers);
ctx->urb = usb_alloc_urb (0, GFP_KERNEL);
if (!ctx->urb) {
kfree_skb (ctx->skb);
ctx->skb = NULL;
break;
};
spin_lock_init (&instance->completed_receivers_lock);
INIT_LIST_HEAD (&instance->completed_receivers);
usb_fill_bulk_urb (ctx->urb,
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);
tasklet_init (&instance->receive_tasklet, udsl_process_receive, (unsigned long) instance);
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",
ctx->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE);
if (!(rcv->skb = dev_alloc_skb (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)
PDEBUG ("udsl_usb_data_init: Submit failed, loosing urb.\n");
else
succes++;
if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for receive urb %d!\n", i);
err = -ENOMEM;
goto fail_urbs;
}
PDEBUG ("udsl_usb_data_init %d urb%s queued for receive\n", succes,
(succes != 1) ? "s" : "");
rcv->instance = instance;
list_add (&rcv->list, &instance->spare_receivers);
for (i = 0, succes = 0; i < UDSL_NUMBER_SND_URBS; i++) {
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 ("skb->truesize = %d (asked for %d)\n", rcv->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE);
}
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;
instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
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)
{
int i;
/* atm init */
if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
PDEBUG ("failed to register ATM device!\n");
err = -ENOMEM;
goto fail_atm;
}
if (!instance->data_started)
return 0;
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;
if (!instance->rcvbufs)
return 0;
/* tmp init atm device, set to 128kbit */
instance->atm_dev->link_rate = 128 * 1000 / 424;
/* destroy urbs */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
/* set MAC address, it is stored in the serial number */
usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13);
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))
continue;
PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
usb_unlink_urb (ctx->urb);
memcpy (instance->atm_dev->esi, mac, 6);
usb_free_urb (ctx->urb);
kfree_skb (ctx->skb);
ctx->skb = NULL;
}
wmb ();
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++) {
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)
ctx->vcc->pop (ctx->vcc, ctx->skb);
ctx->skb = NULL;
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
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 */
kfree (instance->rcvbufs);
instance->rcvbufs = NULL;
static void udsl_usb_disconnect (struct usb_interface *intf)
{
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;
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
PDEBUG ("disconnecting\n");
return 0;
};
usb_set_intfdata (intf, NULL);
if (!instance) {
PDEBUG ("NULL instance!\n");
return;
}
/***************************************************************************
*
* usb driver entries
*
****************************************************************************/
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
tasklet_disable (&instance->receive_tasklet);
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)
{
struct udsl_instance_data *instance = usb_get_intfdata (intf);
int retval;
PDEBUG ("udsl_usb_disconnect: flushed %u spare receivers\n", count);
down(&udsl_usb_ioctl_lock);
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;
}
count = UDSL_NUMBER_RCV_URBS - count;
static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
{
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;
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
usb_unlink_urb (instance->all_receivers[i].urb);
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
/* wait for completion handlers to finish */
do {
unsigned int completed = 0;
if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
(dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
(dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
return -ENODEV;
spin_lock_irqsave (&instance->completed_receivers_lock, flags);
list_for_each (pos, &instance->completed_receivers)
if (++completed > count)
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 */
instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL);
if (!instance) {
PDEBUG ("No memory for Instance data!\n");
return -ENOMEM;
}
/* not all urbs completed */
yield ();
} while (1);
/* initialize structure */
memset (instance, 0, sizeof (struct udsl_instance_data));
instance->usb_dev = dev;
instance->rcvbufs = NULL;
tasklet_init (&instance->recvqueue_tasklet, udsl_atm_processqueue, (unsigned long) instance);
PDEBUG ("udsl_usb_disconnect: flushing %u completed receivers\n", count);
/* no need to take the spinlock - no completion handlers running */
INIT_LIST_HEAD (&instance->completed_receivers);
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 */
usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13);
for (i = 0; i < 6; i++)
mac[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
PDEBUG ("udsl_usb_disconnect: freeing receivers\n");
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4],
mac[5]);
udsl_atm_set_mac (instance, mac);
usb_free_urb (rcv->urb);
kfree_skb (rcv->skb);
}
usb_set_intfdata (intf, instance);
return 0;
}
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
static void udsl_usb_disconnect (struct usb_interface *intf)
{
struct udsl_instance_data *instance = usb_get_intfdata (intf);
usb_unlink_urb (ctx->urb);
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 */
if (instance->atm_dev)
udsl_atm_stopdevice (instance);
kfree (instance);
MOD_DEC_USE_COUNT;
}
}
/***************************************************************************
*
* Driver Init
......@@ -907,18 +995,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
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);
}
static void __exit udsl_usb_cleanup (void)
{
PDEBUG ("udsl_usb_cleanup\n");
usb_deregister (&udsl_usb_driver);
}
module_init(udsl_usb_init);
module_exit(udsl_usb_cleanup);
module_init (udsl_usb_init);
module_exit (udsl_usb_cleanup);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
#ifdef DEBUG_PACKET
/*******************************************************************************
......@@ -929,7 +1024,7 @@ module_exit(udsl_usb_cleanup);
static int udsl_print_packet (const unsigned char *data, int len)
{
unsigned char buffer[256];
unsigned char buffer [256];
int i = 0, j = 0;
for (i = 0; i < len;) {
......@@ -941,10 +1036,6 @@ static int udsl_print_packet (const unsigned char *data, int len)
PDEBUG ("%s\n", buffer);
}
return i;
};
}
#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 [] = {
static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */
};
......@@ -143,6 +144,7 @@ static struct usb_device_id id_table_8U232AM [] = {
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_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) },
{ } /* Terminating entry */
};
......
......@@ -17,11 +17,14 @@
* Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
* 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_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#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_PID 0x0001 /* Product Id */
......
......@@ -106,6 +106,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_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_568_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
......@@ -126,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) },
{ USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_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(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
{ } /* Terminating entry */
......
......@@ -30,6 +30,9 @@
#define COMPAQ_IPAQ_ID 0x0003
#define COMPAQ_0032_ID 0x0032
#define DELL_VENDOR_ID 0x413c
#define DELL_AXIM_ID 0x4001
#define HP_VENDOR_ID 0x03f0
#define HP_JORNADA_548_ID 0x1016
#define HP_JORNADA_568_ID 0x1116
......@@ -63,6 +66,7 @@
#define TOSHIBA_VENDOR_ID 0x0930
#define TOSHIBA_PRODUCT_ID 0x0700
#define TOSHIBA_E740_ID 0x0706
#define HTC_VENDOR_ID 0x0bb4
#define HTC_PRODUCT_ID 0x00ce
......
......@@ -74,6 +74,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ } /* Terminating entry */
};
......
......@@ -28,3 +28,6 @@
#define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
......@@ -50,23 +50,25 @@
#include "transport.h"
#include <linux/slab.h>
#include <linux/module.h>
/***********************************************************************
* 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";
}
#if 0
/* detect a virtual adapter (always works)
* Synchronization: 2.4: with the io_request_lock
* 2.5: no locks.
* fortunately we don't care.
* */
static int detect(struct SHT *sht)
static int usb_storage_detect(struct SHT *sht)
{
struct us_data *us;
char local_name[32];
......@@ -109,7 +111,7 @@ static int detect(struct SHT *sht)
* the driver and we're doing each virtual host in turn, not in parallel
* 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];
......@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh)
/* we always have a successful release */
return 0;
}
/* run command */
static int command( Scsi_Cmnd *srb )
{
US_DEBUGP("Bad use of us_command\n");
return DID_BAD_TARGET << 16;
}
#endif
/* queue a command */
/* 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];
......@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
/* Command abort */
/* 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];
......@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb )
/* This invokes the transport reset mechanism to reset the state of the
* device */
/* 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];
int result;
......@@ -202,11 +197,10 @@ static int device_reset( Scsi_Cmnd *srb )
/* lock the device pointers */
down(&(us->dev_semaphore));
/* if the device was removed, then we're already reset */
if (!(us->flags & US_FL_DEV_ATTACHED))
result = SUCCESS;
else
/* do the reset */
result = us->transport_reset(us);
/* unlock */
up(&(us->dev_semaphore));
/* lock access to the state and clear it */
......@@ -219,31 +213,26 @@ static int device_reset( Scsi_Cmnd *srb )
* disconnect/reconnect for all drivers which have claimed
* interfaces, including ourself. */
/* 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 result;
struct usb_device *pusb_dev_save;
/* we use the usb_reset_device() function to handle this for us */
US_DEBUGP("bus_reset() called\n");
scsi_unlock(srb->device->host);
/* 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);
us = (struct us_data *)srb->device->host->hostdata[0];
/* 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);
if (result < 0) {
scsi_lock(srb->device->host);
......@@ -253,9 +242,9 @@ static int bus_reset( Scsi_Cmnd *srb )
/* FIXME: This needs to lock out driver probing while it's working
* or we can have race conditions */
/* 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 =
&pusb_dev_save->actconfig->interface[i];
&us->pusb_dev->actconfig->interface[i];
/* if this is an unclaimed interface, skip it */
if (!intf->driver) {
......@@ -274,14 +263,6 @@ static int bus_reset( Scsi_Cmnd *srb )
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
***********************************************************************/
......@@ -291,29 +272,23 @@ static int host_reset( Scsi_Cmnd *srb )
#define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
static int proc_info (char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout)
{
struct us_data *us;
char *pos = buffer;
struct Scsi_Host *hostptr;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* lock the data structures */
down(&us_list_semaphore);
/* find our data from hostno */
us = us_list;
while (us) {
if (us->host_no == hostno)
break;
us = us->next;
/* find our data from the given hostno */
hostptr = scsi_host_hn_get(hostno);
if (!hostptr) { /* if we couldn't find it, we return an error */
return -ESRCH;
}
/* release our lock on the data structures */
up(&us_list_semaphore);
us = (struct us_data*)hostptr->hostdata[0];
/* if we couldn't find it, we return an error */
if (!us) {
......@@ -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(" Transport: %s\n", us->transport_name);
/* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
SPRINTF(" Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ?
"Yes" : "No"));
/* release the reference count on this host */
scsi_host_put(hostptr);
/*
* 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,
}
/*
* 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",
.proc_info = proc_info,
.info = host_info,
.proc_name = "usb-storage",
.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,
.release = release,
.command = command,
.queuecommand = queuecommand,
/* unknown initiator id */
.this_id = -1,
.eh_abort_handler = command_abort,
.eh_device_reset_handler =device_reset,
.eh_bus_reset_handler = bus_reset,
.eh_host_reset_handler =host_reset,
/* no limit on commands */
.max_sectors = 0,
.can_queue = 1,
.this_id = -1,
/* pre- and post- device scan functions */
.slave_alloc = NULL,
.slave_configure = NULL,
.slave_destroy = NULL,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.present = 0,
/* use 32-bit address space for DMA */
.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,
.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" */
......
......@@ -47,7 +47,7 @@
extern unsigned char usb_stor_sense_notready[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_scsiSense6to10(Scsi_Cmnd*);
......
......@@ -55,8 +55,7 @@
#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for
SDDR-09 */
#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */
#endif
#ifdef CONFIG_USB_STORAGE_SDDR55
#define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */
......
......@@ -93,16 +93,6 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
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,
const struct usb_device_id *id);
......@@ -319,7 +309,7 @@ static int usb_stor_control_thread(void * __us)
spin_unlock_irq(&current->sig->siglock);
/* set our name for identification purposes */
sprintf(current->comm, "usb-storage-%d", us->host_number);
sprintf(current->comm, "usb-storage");
unlock_kernel();
......@@ -395,35 +385,6 @@ static int usb_stor_control_thread(void * __us)
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
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
......@@ -547,7 +508,6 @@ static void usb_stor_deallocate_urbs(struct us_data *ss)
}
/* mark the device as gone */
ss->flags &= ~ US_FL_DEV_ATTACHED;
usb_put_dev(ss->pusb_dev);
ss->pusb_dev = NULL;
}
......@@ -563,12 +523,10 @@ static int storage_probe(struct usb_interface *intf,
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */
GUID(guid); /* Global Unique Identifier */
unsigned int flags;
struct us_unusual_dev *unusual_dev;
struct us_data *ss = NULL;
int result;
int new_device = 0;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
......@@ -676,8 +634,7 @@ static int storage_probe(struct usb_interface *intf,
/* At this point, we've decided to try to use the device */
usb_get_dev(dev);
/* clear the GUID and fetch the strings */
GUID_CLEAR(guid);
/* fetch the strings */
if (dev->descriptor.iManufacturer)
usb_string(dev, dev->descriptor.iManufacturer,
mf, sizeof(mf));
......@@ -688,69 +645,7 @@ static int storage_probe(struct usb_interface *intf,
usb_string(dev, dev->descriptor.iSerialNumber,
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 */
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
......@@ -758,7 +653,6 @@ static int storage_probe(struct usb_interface *intf,
return -ENOMEM;
}
memset(ss, 0, sizeof(struct us_data));
new_device = 1;
/* Initialize the mutexes only when the struct is new */
init_completion(&(ss->notify));
......@@ -767,7 +661,7 @@ static int storage_probe(struct usb_interface *intf,
/* copy over the subclass and protocol data */
ss->subclass = subclass;
ss->protocol = protocol;
ss->flags = flags | US_FL_DEV_ATTACHED;
ss->flags = flags;
ss->unusual_dev = unusual_dev;
/* copy over the endpoint data */
......@@ -810,9 +704,6 @@ static int storage_probe(struct usb_interface *intf,
if (strlen(ss->serial) == 0)
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
* Again, this data is persistant across reattachments
......@@ -968,19 +859,6 @@ static int storage_probe(struct usb_interface *intf,
* 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
* the device if it needs initialization */
if (unusual_dev && unusual_dev->initFunction)
......@@ -1002,10 +880,9 @@ static int storage_probe(struct usb_interface *intf,
/* unlock the device pointers */
up(&(ss->dev_semaphore));
/* now register - our detect function will be called */
ss->htmplt.module = THIS_MODULE;
result = scsi_register_host(&(ss->htmplt));
if (result) {
/* now register */
ss->host = scsi_register(&usb_stor_host_template, sizeof(ss));
if (!ss->host) {
printk(KERN_WARNING USB_STORAGE
"Unable to register the scsi host\n");
......@@ -1019,15 +896,26 @@ static int storage_probe(struct usb_interface *intf,
goto BadDevice;
}
/* lock access to the data structures */
down(&us_list_semaphore);
/* set the hostdata to prepare for scanning */
ss->host->hostdata[0] = (unsigned long)ss;
/* put us in the list */
ss->next = us_list;
us_list = ss;
/* associate this host with our interface */
scsi_set_device(ss->host, &intf->dev);
/* 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 */
up(&us_list_semaphore);
/* re-lock the device pointers */
down(&ss->dev_semaphore);
goto BadDevice;
}
printk(KERN_DEBUG
......@@ -1041,11 +929,10 @@ static int storage_probe(struct usb_interface *intf,
/* we come here if there are any problems */
/* ss->dev_semaphore must be locked */
BadDevice:
BadDevice:
US_DEBUGP("storage_probe() failed\n");
usb_stor_deallocate_urbs(ss);
up(&ss->dev_semaphore);
if (new_device)
kfree(ss);
return -EIO;
}
......@@ -1053,21 +940,85 @@ static int storage_probe(struct usb_interface *intf,
/* Handle a disconnect event from the USB core */
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");
ss = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
/* this is the odd case -- we disconnected but weren't using it */
if (!ss) {
US_DEBUGP("-- device was not in use\n");
return;
}
/* serious error -- we're attempting to disconnect an interface but
* cannot locate the local data structure
*/
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));
/* 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);
/* 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));
/* free the structure itself */
kfree (ss);
}
/***********************************************************************
......@@ -1078,11 +1029,6 @@ int __init usb_stor_init(void)
{
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 */
if (usb_register(&usb_storage_driver) < 0)
return -1;
......@@ -1094,16 +1040,16 @@ int __init usb_stor_init(void)
void __exit usb_stor_exit(void)
{
struct us_data *next;
US_DEBUGP("usb_stor_exit() called\n");
/* 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");
usb_deregister(&usb_storage_driver) ;
#if 0
/* While there are still virtual hosts, unregister them
* Note that it's important to do this completely before removing
* the structures because of possible races with the /proc
......@@ -1111,7 +1057,7 @@ void __exit usb_stor_exit(void)
*/
for (next = us_list; next; next = next->next) {
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
......@@ -1142,6 +1088,7 @@ void __exit usb_stor_exit(void)
/* advance the list pointer */
us_list = next;
}
#endif
}
module_init(usb_stor_init);
......
......@@ -52,33 +52,6 @@
#include "scsi.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;
/*
......@@ -104,7 +77,6 @@ struct us_unusual_dev {
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */
#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_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */
......@@ -124,12 +96,9 @@ typedef void (*extra_data_destructor)(void *); /* extra data destructor */
/* we allocate one of these for every device that we remember */
struct us_data {
struct us_data *next; /* next device */
/* The device we're working with
* It's important to note:
* (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 usb_device *pusb_dev; /* this usb_device */
......@@ -163,11 +132,7 @@ struct us_data {
proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */
GUID(guid); /* unique dev id */
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 */
/* thread information */
......@@ -192,10 +157,6 @@ struct us_data {
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 */
extern struct usb_driver usb_storage_driver;
......
......@@ -554,7 +554,6 @@ extern int usb_disabled(void);
#define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */
#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 {
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