Commit 916da46b authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linuxusb.bkbits.net/linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents f2a7c782 6cbd4aa9
...@@ -368,7 +368,7 @@ static void usb_bulk_read(struct urb *urb) ...@@ -368,7 +368,7 @@ static void usb_bulk_read(struct urb *urb)
{ {
struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context); struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
unsigned char *data = urb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
int i, l, wake; int i, j, wake;
unsigned long int flags; unsigned long int flags;
if ( !ep->urbSubmitted ) { if ( !ep->urbSubmitted ) {
...@@ -379,14 +379,14 @@ static void usb_bulk_read(struct urb *urb) ...@@ -379,14 +379,14 @@ static void usb_bulk_read(struct urb *urb)
wake = 0; wake = 0;
spin_lock_irqsave( &ep->lock, flags ); spin_lock_irqsave( &ep->lock, flags );
for(l = 0; l < urb->actual_length; l += 4) { for(j = 0; j < urb->actual_length; j += 4) {
int cin = (data[l]>>0)&0xf; int cin = (data[j]>>0)&0xf;
int cab = (data[l]>>4)&0xf; int cab = (data[j]>>4)&0xf;
struct usb_mididev *cable = ep->cables[cab]; struct usb_mididev *cable = ep->cables[cab];
if ( cable ) { if ( cable ) {
int len = cin_to_len[cin]; /** length of MIDI data **/ int len = cin_to_len[cin]; /** length of MIDI data **/
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
cable->min.buf[cable->min.bufWrPtr] = data[1+i]; cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ; cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
if (cable->min.bufRemains < MIDI_IN_BUFSIZ) if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
cable->min.bufRemains += 1; cable->min.bufRemains += 1;
......
...@@ -111,6 +111,7 @@ ...@@ -111,6 +111,7 @@
#define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_MULT_TT 1
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_ASYNC_JIFFIES (HZ/3) /* async idle timeout */
/* Initial IRQ latency: lower than default */ /* Initial IRQ latency: lower than default */
static int log2_irq_thresh = 0; // 0 to 6 static int log2_irq_thresh = 0; // 0 to 6
...@@ -190,7 +191,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ...@@ -190,7 +191,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
dbg_cmd (ehci, "reset", command); dbg_cmd (ehci, "reset", command);
writel (command, &ehci->regs->command); writel (command, &ehci->regs->command);
ehci->hcd.state = USB_STATE_HALT; ehci->hcd.state = USB_STATE_HALT;
return handshake (&ehci->regs->command, CMD_RESET, 0, 050); return handshake (&ehci->regs->command, CMD_RESET, 0, 250);
} }
/* idle the controller (from running) */ /* idle the controller (from running) */
...@@ -247,9 +248,14 @@ static void ehci_watchdog (unsigned long param) ...@@ -247,9 +248,14 @@ static void ehci_watchdog (unsigned long param)
struct ehci_hcd *ehci = (struct ehci_hcd *) param; struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags; unsigned long flags;
/* guard against lost IAA, which wedges everything */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
/* guard against lost IAA, which wedges everything */
ehci_irq (&ehci->hcd); ehci_irq (&ehci->hcd);
/* unlink the last qh after it's idled a while */
if (ehci->async_idle) {
start_unlink_async (ehci, ehci->async);
ehci->async_idle = 0;
}
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
} }
...@@ -368,6 +374,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -368,6 +374,7 @@ static int ehci_start (struct usb_hcd *hcd)
* *
* NOTE: layered drivers can't yet tell when we enable that, * NOTE: layered drivers can't yet tell when we enable that,
* so they can't pass this info along (like NETIF_F_HIGHDMA) * so they can't pass this info along (like NETIF_F_HIGHDMA)
* (or like Scsi_Host.highmem_io) ... usb_bus.flags?
*/ */
if (HCC_64BIT_ADDR (hcc_params)) { if (HCC_64BIT_ADDR (hcc_params)) {
writel (0, &ehci->regs->segment); writel (0, &ehci->regs->segment);
...@@ -586,6 +593,10 @@ static void ehci_tasklet (unsigned long param) ...@@ -586,6 +593,10 @@ static void ehci_tasklet (unsigned long param)
struct ehci_hcd *ehci = (struct ehci_hcd *) param; struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags; unsigned long flags;
// FIXME don't pass flags; on sparc they aren't really flags.
// qh_completions can just leave irqs blocked,
// then have scan_async() allow IRQs if it's very busy
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (ehci->reclaim_ready) if (ehci->reclaim_ready)
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
* Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd"
* entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
* buffers needed for the larger number). We use one QH per endpoint, queue * buffers needed for the larger number). We use one QH per endpoint, queue
* multiple (bulk or control) urbs per endpoint. URBs may need several qtds. * multiple urbs (all three types) per endpoint. URBs may need several qtds.
* A scheduled interrupt qh always (for now) has one qtd, one urb.
* *
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be * interrupts) needs careful scheduling. Performance improvements can be
...@@ -281,7 +280,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags) ...@@ -281,7 +280,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
|| (qh->qh_state == QH_STATE_IDLE); || (qh->qh_state == QH_STATE_IDLE);
// FIXME Remove the automagic unlink mode. // FIXME Remove the automagic unlink mode.
// Drivers can now clean up safely; its' their job. // Drivers can now clean up safely; it's their job.
//
// FIXME Removing it should fix the short read scenarios
// with "huge" urb data (more than one 16+KByte td) with
// the short read someplace other than the last data TD.
// Except the control case: 'retrigger' status ACKs.
/* fault: unlink the rest, since this qtd saw an error? */ /* fault: unlink the rest, since this qtd saw an error? */
if (unlikely ((token & QTD_STS_HALT) != 0)) { if (unlikely ((token & QTD_STS_HALT) != 0)) {
...@@ -391,7 +395,7 @@ qh_urb_transaction ( ...@@ -391,7 +395,7 @@ qh_urb_transaction (
struct ehci_qtd *qtd, *qtd_prev; struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf; dma_addr_t buf;
int len, maxpacket; int len, maxpacket;
int is_input; int is_input, status_patch = 0;
u32 token; u32 token;
/* /*
...@@ -422,6 +426,9 @@ qh_urb_transaction ( ...@@ -422,6 +426,9 @@ qh_urb_transaction (
qtd->urb = urb; qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head); list_add_tail (&qtd->qtd_list, head);
if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
status_patch = 1;
} }
/* /*
...@@ -499,6 +506,19 @@ qh_urb_transaction ( ...@@ -499,6 +506,19 @@ qh_urb_transaction (
} }
} }
/* if we're permitting a short control read, we want the hardware to
* just continue after short data and send the status ack. it can do
* that on the last data packet (typically the only one). for other
* packets, software fixup is needed (in qh_completions).
*/
if (status_patch) {
struct ehci_qtd *prev;
prev = list_entry (qtd->qtd_list.prev,
struct ehci_qtd, qtd_list);
prev->hw_alt_next = QTD_NEXT (qtd->qtd_dma);
}
/* by default, enable interrupt on urb completion */ /* by default, enable interrupt on urb completion */
if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
...@@ -653,9 +673,8 @@ ehci_qh_make ( ...@@ -653,9 +673,8 @@ ehci_qh_make (
} }
break; break;
default: default:
#ifdef DEBUG dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
BUG (); return 0;
#endif
} }
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
...@@ -717,6 +736,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -717,6 +736,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
qh->qh_state = QH_STATE_LINKED; qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */ /* qtd completions reported later by interrupt */
ehci->async_idle = 0;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -837,7 +858,7 @@ submit_async ( ...@@ -837,7 +858,7 @@ submit_async (
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
dev = (struct hcd_dev *)urb->dev->hcpriv; dev = (struct hcd_dev *)urb->dev->hcpriv;
epnum = usb_pipeendpoint (urb->pipe); epnum = usb_pipeendpoint (urb->pipe);
if (usb_pipein (urb->pipe)) if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
epnum |= 0x10; epnum |= 0x10;
vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]", vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
...@@ -923,9 +944,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -923,9 +944,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) { if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
/* can't get here without STS_ASS set */ /* can't get here without STS_ASS set */
if (ehci->hcd.state != USB_STATE_HALT) { if (ehci->hcd.state != USB_STATE_HALT) {
if (cmd & CMD_PSE) if (cmd & CMD_PSE) {
writel (cmd & ~CMD_ASE, &ehci->regs->command); writel (cmd & ~CMD_ASE, &ehci->regs->command);
else (void) handshake (&ehci->regs->status,
STS_ASS, 0, 150);
} else
ehci_ready (ehci); ehci_ready (ehci);
} }
qh->qh_next.qh = ehci->async = 0; qh->qh_next.qh = ehci->async = 0;
...@@ -944,10 +967,6 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -944,10 +967,6 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
prev = ehci->async; prev = ehci->async;
while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async) while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
prev = prev->qh_next.qh; prev = prev->qh_next.qh;
#ifdef DEBUG
if (prev->qh_next.qh != qh)
BUG ();
#endif
if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) { if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
ehci->async = prev; ehci->async = prev;
...@@ -987,16 +1006,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags) ...@@ -987,16 +1006,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
} }
/* unlink idle entries, reducing HC PCI usage as /* unlink idle entries, reducing HC PCI usage as
* well as HCD schedule-scanning costs * well as HCD schedule-scanning costs. removing
* the last qh is deferred, since it's costly.
*/ */
if (list_empty (&qh->qtd_list) && !ehci->reclaim) { if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
if (qh->qh_next.qh != qh) { if (qh->qh_next.qh != qh) {
// dbg ("irq/empty"); // dbg ("irq/empty");
start_unlink_async (ehci, qh); start_unlink_async (ehci, qh);
} else { } else if (!timer_pending (&ehci->watchdog)) {
// FIXME: arrange to stop /* can't use IAA for last entry */
// after it's been idle a while. ehci->async_idle = 1;
// stop/restart isn't free... mod_timer (&ehci->watchdog,
jiffies + EHCI_ASYNC_JIFFIES);
} }
} }
qh = qh->qh_next.qh; qh = qh->qh_next.qh;
......
...@@ -971,119 +971,10 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) ...@@ -971,119 +971,10 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
/* /*
* "Split ISO TDs" ... used for USB 1.1 devices going through * "Split ISO TDs" ... used for USB 1.1 devices going through
* the TTs in USB 2.0 hubs. * the TTs in USB 2.0 hubs.
*
* FIXME not yet implemented
*/ */
static void
sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
}
static struct ehci_sitd *
sitd_make (
struct ehci_hcd *ehci,
struct urb *urb,
unsigned index, // urb->iso_frame_desc [index]
unsigned uframe, // scheduled start
dma_addr_t dma, // mapped transfer buffer
int mem_flags
) {
struct ehci_sitd *sitd;
unsigned length;
sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
if (!sitd)
return sitd;
sitd->urb = urb;
length = urb->iso_frame_desc [index].length;
dma += urb->iso_frame_desc [index].offset;
#if 0
// FIXME: do the rest!
#else
sitd_free (ehci, sitd);
return 0;
#endif
}
static void
sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
{
u32 ptr;
ptr = cpu_to_le32 (sitd->sitd_dma | 2); // type 2 == sitd
if (ehci->pshadow [frame].ptr) {
if (!sitd->sitd_next.ptr) {
sitd->sitd_next = ehci->pshadow [frame];
sitd->hw_next = ehci->periodic [frame];
} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
dbg ("frame %d sitd link goof", frame);
BUG ();
}
}
ehci->pshadow [frame].sitd = sitd;
ehci->periodic [frame] = ptr;
}
static unsigned long
sitd_complete (
struct ehci_hcd *ehci,
struct ehci_sitd *sitd,
unsigned long flags
) {
// FIXME -- implement!
dbg ("NYI -- sitd_complete");
return flags;
}
/*-------------------------------------------------------------------------*/
static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
{
// struct ehci_sitd *first_sitd = 0;
unsigned frame_index;
dma_addr_t dma;
dbg ("NYI -- sitd_submit");
// FIXME -- implement!
// FIXME: setup one big dma mapping
dma = 0;
for (frame_index = 0;
frame_index < urb->number_of_packets;
frame_index++) {
struct ehci_sitd *sitd;
unsigned uframe;
// FIXME: use real arguments, schedule this!
uframe = -1;
sitd = sitd_make (ehci, urb, frame_index,
uframe, dma, mem_flags);
if (sitd) {
/*
if (first_sitd)
list_add_tail (&sitd->sitd_list,
&first_sitd->sitd_list);
else
first_sitd = sitd;
*/
} else {
// FIXME: clean everything up
}
}
// if we have a first sitd, then
// store them all into the periodic schedule!
// urb->hcpriv = first sitd in sitd_list
return -ENOSYS;
}
#endif /* have_split_iso */ #endif /* have_split_iso */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -39,7 +39,8 @@ struct ehci_hcd { /* one per controller */ ...@@ -39,7 +39,8 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */ /* async schedule support */
struct ehci_qh *async; struct ehci_qh *async;
struct ehci_qh *reclaim; struct ehci_qh *reclaim;
int reclaim_ready; int reclaim_ready : 1,
async_idle : 1;
/* periodic schedule support */ /* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */
......
...@@ -154,7 +154,13 @@ hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr) ...@@ -154,7 +154,13 @@ hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
static struct usb_device_id hpusbscsi_usb_ids[] = { static struct usb_device_id hpusbscsi_usb_ids[] = {
{USB_DEVICE (0x03f0, 0x0701)}, /* HP 53xx */ {USB_DEVICE (0x03f0, 0x0701)}, /* HP 53xx */
{USB_DEVICE (0x03f0, 0x0801)}, /* HP 7400 */ {USB_DEVICE (0x03f0, 0x0801)}, /* HP 7400 */
{USB_DEVICE (0x0638, 0x026a)}, /*Scan Dual II */ {USB_DEVICE (0x0638, 0x0268)}, /*iVina 1200U */
{USB_DEVICE (0x0638, 0x026a)}, /*Scan Dual II */
{USB_DEVICE (0x0638, 0x0A13)}, /*Avision AV600U */
{USB_DEVICE (0x0638, 0x0A16)}, /*Avision DS610CU Scancopier */
{USB_DEVICE (0x0638, 0x0A18)}, /*Avision AV600U Plus */
{USB_DEVICE (0x0638, 0x0A23)}, /*Avision AV220 */
{USB_DEVICE (0x0638, 0x0A24)}, /*Avision AV210 */
{USB_DEVICE (0x0686, 0x4004)}, /*Minolta Elite II */ {USB_DEVICE (0x0686, 0x4004)}, /*Minolta Elite II */
{} /* Terminating entry */ {} /* Terminating entry */
}; };
......
...@@ -583,13 +583,22 @@ static void mts_command_done( struct urb *transfer ) ...@@ -583,13 +583,22 @@ static void mts_command_done( struct urb *transfer )
return; return;
} }
if ( context->data ) { if (context->srb->cmnd[0] == REQUEST_SENSE) {
mts_int_submit_urb(transfer, mts_int_submit_urb(transfer,
context->data_pipe, context->data_pipe,
context->data, context->srb->sense_buffer,
context->data_length, context->data_length,
context->srb->use_sg ? mts_do_sg : mts_data_done); mts_data_done);
} else mts_get_status(transfer); } else { if ( context->data ) {
mts_int_submit_urb(transfer,
context->data_pipe,
context->data,
context->data_length,
context->srb->use_sg ? mts_do_sg : mts_data_done);
} else {
mts_get_status(transfer);
}
}
return; return;
} }
...@@ -598,7 +607,7 @@ static void mts_do_sg (struct urb* transfer) ...@@ -598,7 +607,7 @@ static void mts_do_sg (struct urb* transfer)
{ {
struct scatterlist * sg; struct scatterlist * sg;
MTS_INT_INIT(); MTS_INT_INIT();
MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
if (unlikely(transfer->status)) { if (unlikely(transfer->status)) {
......
...@@ -8,4 +8,4 @@ dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD ...@@ -8,4 +8,4 @@ dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate ' Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB LCD driver support' CONFIG_USB_LCD $CONFIG_USB dep_tristate ' USB LCD driver support' CONFIG_USB_LCD $CONFIG_USB
dep_tristate ' Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB dep_tristate ' Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB $CONFIG_ATM
...@@ -464,7 +464,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) ...@@ -464,7 +464,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
} }
static void kaweth_usb_receive(struct urb *); static void kaweth_usb_receive(struct urb *);
static void kaweth_resubmit_rx_urb(struct kaweth_device *, int); static int kaweth_resubmit_rx_urb(struct kaweth_device *, int);
/**************************************************************** /****************************************************************
int_callback int_callback
...@@ -493,7 +493,7 @@ static void int_callback(struct urb *u) ...@@ -493,7 +493,7 @@ static void int_callback(struct urb *u)
/**************************************************************** /****************************************************************
* kaweth_resubmit_rx_urb * kaweth_resubmit_rx_urb
****************************************************************/ ****************************************************************/
static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
int mem_flags) int mem_flags)
{ {
int result; int result;
...@@ -513,6 +513,8 @@ static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, ...@@ -513,6 +513,8 @@ static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
} else { } else {
kaweth->suspend_lowmem = 0; kaweth->suspend_lowmem = 0;
} }
return result;
} }
static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
...@@ -592,14 +594,15 @@ static void kaweth_usb_receive(struct urb *urb) ...@@ -592,14 +594,15 @@ static void kaweth_usb_receive(struct urb *urb)
static int kaweth_open(struct net_device *net) static int kaweth_open(struct net_device *net)
{ {
struct kaweth_device *kaweth = (struct kaweth_device *)net->priv; struct kaweth_device *kaweth = (struct kaweth_device *)net->priv;
int res;
kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter); kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter);
kaweth_dbg("Opening network device."); kaweth_dbg("Opening network device.");
MOD_INC_USE_COUNT; res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); return -EIO;
FILL_INT_URB( FILL_INT_URB(
kaweth->irq_urb, kaweth->irq_urb,
...@@ -611,7 +614,11 @@ static int kaweth_open(struct net_device *net) ...@@ -611,7 +614,11 @@ static int kaweth_open(struct net_device *net)
kaweth, kaweth,
HZ/4); HZ/4);
usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
if (res) {
usb_unlink_urb(kaweth->rx_urb);
return -EIO;
}
netif_start_queue(net); netif_start_queue(net);
...@@ -635,7 +642,6 @@ static int kaweth_close(struct net_device *net) ...@@ -635,7 +642,6 @@ static int kaweth_close(struct net_device *net)
kaweth->status &= ~KAWETH_STATUS_CLOSING; kaweth->status &= ~KAWETH_STATUS_CLOSING;
MOD_DEC_USE_COUNT;
printk("Dev usage: %d", kaweth->dev->refcnt.counter); printk("Dev usage: %d", kaweth->dev->refcnt.counter);
...@@ -848,6 +854,7 @@ static void *kaweth_probe( ...@@ -848,6 +854,7 @@ static void *kaweth_probe(
) )
{ {
struct kaweth_device *kaweth; struct kaweth_device *kaweth;
struct net_device *netdev;
const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int result = 0; int result = 0;
...@@ -863,10 +870,8 @@ static void *kaweth_probe( ...@@ -863,10 +870,8 @@ static void *kaweth_probe(
(int)dev->descriptor.bLength, (int)dev->descriptor.bLength,
(int)dev->descriptor.bDescriptorType); (int)dev->descriptor.bDescriptorType);
if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) { if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL)))
kaweth_dbg("out of memory allocating device structure\n");
return NULL; return NULL;
}
memset(kaweth, 0, sizeof(struct kaweth_device)); memset(kaweth, 0, sizeof(struct kaweth_device));
...@@ -992,11 +997,17 @@ static void *kaweth_probe( ...@@ -992,11 +997,17 @@ static void *kaweth_probe(
if(result < 0) { if(result < 0) {
kaweth_err("Error setting receive filter"); kaweth_err("Error setting receive filter");
return kaweth; kfree(kaweth);
return NULL;
} }
kaweth_dbg("Initializing net device."); kaweth_dbg("Initializing net device.");
if(!(netdev = kmalloc(sizeof(struct net_device), GFP_KERNEL))) {
kfree(kaweth);
return NULL;
}
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb) if (!kaweth->tx_urb)
goto err_no_urb; goto err_no_urb;
...@@ -1007,12 +1018,7 @@ static void *kaweth_probe( ...@@ -1007,12 +1018,7 @@ static void *kaweth_probe(
if (!kaweth->irq_urb) if (!kaweth->irq_urb)
goto err_tx_and_rx; goto err_tx_and_rx;
kaweth->net = init_etherdev(0, 0); kaweth->net = netdev;
if (!kaweth->net) {
kaweth_err("Error calling init_etherdev.");
return kaweth;
}
memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr)); memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
memcpy(kaweth->net->dev_addr, memcpy(kaweth->net->dev_addr,
&kaweth->configuration.hw_addr, &kaweth->configuration.hw_addr,
...@@ -1032,6 +1038,13 @@ static void *kaweth_probe( ...@@ -1032,6 +1038,13 @@ static void *kaweth_probe(
kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size); kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size);
memset(&kaweth->stats, 0, sizeof(kaweth->stats)); memset(&kaweth->stats, 0, sizeof(kaweth->stats));
SET_MODULE_OWNER(netdev);
if (!init_etherdev(netdev, 0)) {
kaweth_err("Error calling init_etherdev.");
goto err_tx_and_rx;
}
kaweth_info("kaweth interface created at %s", kaweth->net->name); kaweth_info("kaweth interface created at %s", kaweth->net->name);
...@@ -1045,6 +1058,7 @@ static void *kaweth_probe( ...@@ -1045,6 +1058,7 @@ static void *kaweth_probe(
usb_free_urb(kaweth->tx_urb); usb_free_urb(kaweth->tx_urb);
err_no_urb: err_no_urb:
kfree(kaweth); kfree(kaweth);
kfree(netdev);
return NULL; return NULL;
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
* *
* - AnchorChip 2720 * - AnchorChip 2720
* - Belkin, eTEK (interops with Win32 drivers) * - Belkin, eTEK (interops with Win32 drivers)
* - EPSON USB clients
* - GeneSys GL620USB-A * - GeneSys GL620USB-A
* - "Linux Devices" (like iPaq and similar SA-1100 based PDAs) * - "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
* - NetChip 1080 (interoperates with NetChip Win32 drivers) * - NetChip 1080 (interoperates with NetChip Win32 drivers)
...@@ -23,7 +24,7 @@ ...@@ -23,7 +24,7 @@
* *
* USB devices can implement their side of this protocol at the cost * USB devices can implement their side of this protocol at the cost
* of two bulk endpoints; it's not restricted to "cable" applications. * of two bulk endpoints; it's not restricted to "cable" applications.
* See the LINUXDEV support. * See the LINUXDEV or EPSON device/client support.
* *
* *
* Status: * Status:
...@@ -57,7 +58,7 @@ ...@@ -57,7 +58,7 @@
* *
* Need smarter hotplug policy scripts ... ones that know how to arrange * Need smarter hotplug policy scripts ... ones that know how to arrange
* bridging with "brctl", and can handle static and dynamic ("pump") setups. * bridging with "brctl", and can handle static and dynamic ("pump") setups.
* Use those eventual "peer connected" events. * Use those eventual "peer connected" events, and zeroconf.
* *
* *
* CHANGELOG: * CHANGELOG:
...@@ -128,6 +129,7 @@ ...@@ -128,6 +129,7 @@
/* minidrivers _could_ be individually configured */ /* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720 #define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN #define CONFIG_USB_BELKIN
#define CONFIG_USB_EPSON2888
#define CONFIG_USB_GENESYS #define CONFIG_USB_GENESYS
#define CONFIG_USB_LINUXDEV #define CONFIG_USB_LINUXDEV
#define CONFIG_USB_NET1080 #define CONFIG_USB_NET1080
...@@ -328,6 +330,29 @@ static const struct driver_info belkin_info = { ...@@ -328,6 +330,29 @@ static const struct driver_info belkin_info = {
#endif /* CONFIG_USB_BELKIN */ #endif /* CONFIG_USB_BELKIN */
#ifdef CONFIG_USB_EPSON2888
/*-------------------------------------------------------------------------
*
* EPSON USB clients
*
* This is the same idea as "linuxdev" (below) except the firmware in the
* device might not be Tux-powered. Epson provides reference firmware that
* implements this interface. Product developers can reuse or modify that
* code, such as by using their own product and vendor codes.
*
*-------------------------------------------------------------------------*/
static const struct driver_info epson2888_info = {
.description = "Epson USB Device",
.in = 4, .out = 3,
.epsize = 64,
};
#endif /* CONFIG_USB_EPSON2888 */
#ifdef CONFIG_USB_GENESYS #ifdef CONFIG_USB_GENESYS
...@@ -338,6 +363,15 @@ static const struct driver_info belkin_info = { ...@@ -338,6 +363,15 @@ static const struct driver_info belkin_info = {
* ... should partially interop with the Win32 driver for this hardware * ... should partially interop with the Win32 driver for this hardware
* The GeneSys docs imply there's some NDIS issue motivating this framing. * The GeneSys docs imply there's some NDIS issue motivating this framing.
* *
* Some info from GeneSys:
* - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
* (Some cables, like the BAFO-100c, use the half duplex version.)
* - For the full duplex model, the low bit of the version code says
* which side is which ("left/right").
* - For the half duplex type, a control/interrupt handshake settles
* the transfer direction. (That's disabled here, partially coded.)
* A control URB would block until other side writes an interrupt.
*
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
// control msg write command // control msg write command
...@@ -504,13 +538,6 @@ static int genelink_free (struct usbnet *dev) ...@@ -504,13 +538,6 @@ static int genelink_free (struct usbnet *dev)
#endif #endif
// reset the device status
static int genelink_reset (struct usbnet *dev)
{
// we don't need to reset, just return 0
return 0;
}
static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
{ {
struct gl_header *header; struct gl_header *header;
...@@ -632,7 +659,6 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) ...@@ -632,7 +659,6 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
static const struct driver_info genelink_info = { static const struct driver_info genelink_info = {
.description = "Genesys GeneLink", .description = "Genesys GeneLink",
.flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT,
.reset = genelink_reset,
.rx_fixup = genelink_rx_fixup, .rx_fixup = genelink_rx_fixup,
.tx_fixup = genelink_tx_fixup, .tx_fixup = genelink_tx_fixup,
...@@ -662,25 +688,19 @@ static const struct driver_info genelink_info = { ...@@ -662,25 +688,19 @@ static const struct driver_info genelink_info = {
* *
* One example is Intel's SA-1100 chip, which integrates basic USB * One example is Intel's SA-1100 chip, which integrates basic USB
* support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA. * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
* And others too, like the Yopy.
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
static int linuxdev_check_connect (struct usbnet *dev)
{
return 0; // by definition, always connected
}
static const struct driver_info linuxdev_info = { static const struct driver_info linuxdev_info = {
.description = "Linux Device", .description = "Linux Device",
// no reset defined (yet?)
.check_connect =linuxdev_check_connect,
.in = 2, .out = 1, .in = 2, .out = 1,
.epsize =64, .epsize = 64,
}; };
#endif /* CONFIG_USB_LINUXDEV */ #endif /* CONFIG_USB_LINUXDEV */
#ifdef CONFIG_USB_NET1080 #ifdef CONFIG_USB_NET1080
...@@ -2049,9 +2069,7 @@ static const struct usb_device_id products [] = { ...@@ -2049,9 +2069,7 @@ static const struct usb_device_id products [] = {
{ {
USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults
.driver_info = (unsigned long) &an2720_info, .driver_info = (unsigned long) &an2720_info,
}, }, {
{
USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET
.driver_info = (unsigned long) &an2720_info, .driver_info = (unsigned long) &an2720_info,
}, },
...@@ -2070,11 +2088,21 @@ static const struct usb_device_id products [] = { ...@@ -2070,11 +2088,21 @@ static const struct usb_device_id products [] = {
}, },
#endif #endif
#ifdef CONFIG_USB_EPSON2888
{
USB_DEVICE (0x0525, 0x2888), // EPSON USB client
driver_info: (unsigned long) &epson2888_info,
},
#endif
#ifdef CONFIG_USB_GENESYS #ifdef CONFIG_USB_GENESYS
{ {
USB_DEVICE (0x05e3, 0x0502), // GL620USB-A USB_DEVICE (0x05e3, 0x0502), // GL620USB-A
.driver_info = (unsigned long) &genelink_info, .driver_info = (unsigned long) &genelink_info,
}, },
/* NOT: USB_DEVICE (0x05e3, 0x0501), // GL620USB
* that's half duplex, not currently supported
*/
#endif #endif
#ifdef CONFIG_USB_LINUXDEV #ifdef CONFIG_USB_LINUXDEV
...@@ -2098,8 +2126,7 @@ static const struct usb_device_id products [] = { ...@@ -2098,8 +2126,7 @@ static const struct usb_device_id products [] = {
{ {
USB_DEVICE (0x0525, 0x1080), // NetChip ref design USB_DEVICE (0x0525, 0x1080), // NetChip ref design
.driver_info = (unsigned long) &net1080_info, .driver_info = (unsigned long) &net1080_info,
}, }, {
{
USB_DEVICE (0x06D0, 0x0622), // Laplink Gold USB_DEVICE (0x06D0, 0x0622), // Laplink Gold
.driver_info = (unsigned long) &net1080_info, .driver_info = (unsigned long) &net1080_info,
}, },
......
...@@ -108,6 +108,7 @@ static struct usb_device_id id_table_combined [] = { ...@@ -108,6 +108,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
{ USB_DEVICE(PERACOM_VID, PERACOM_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) },
{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
{ USB_DEVICE(GOHUBS_VID, HANDYLINK_PID) },
{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#define GOHUBS_VID 0x0921 /* GoHubs vendor id */ #define GOHUBS_VID 0x0921 /* GoHubs vendor id */
#define GOHUBS_PID 0x1000 /* GoHubs single port serial converter's id (identical to the Peracom device) */ #define GOHUBS_PID 0x1000 /* GoHubs single port serial converter's id (identical to the Peracom device) */
#define HANDYLINK_PID 0x1200 /* HandyLink USB's id (identical to the Peracom device) */
/* Vendor Request Interface */ /* Vendor Request Interface */
#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ #define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */
......
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