From 0d9899f8139b1e4ee84b97fb61615714fd40be5b Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Thu, 28 Jul 2005 20:46:32 -0700 Subject: [PATCH] USB: usbnet and unsigned gfp_flags This just fixes some gfp flags warnings that joined us recently. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/usbnet.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index a2f67245f6d..4682696450d 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -252,7 +252,7 @@ struct driver_info { /* fixup tx packet (add framing) */ struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, int flags); + struct sk_buff *skb, unsigned flags); // FIXME -- also an interrupt mechanism // useful for at least PL2301/2302 and GL620USB-A @@ -1144,7 +1144,7 @@ static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - int flags) + unsigned flags) { int padlen; int headroom = skb_headroom(skb); @@ -1945,7 +1945,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) +genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) { int padlen; int length = skb->len; @@ -2468,7 +2468,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) +net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) { int padlen; struct sk_buff *skb2; @@ -2662,7 +2662,7 @@ static const struct driver_info blob_info = { *-------------------------------------------------------------------------*/ static struct sk_buff * -zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) +zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) { int padlen; struct sk_buff *skb2; @@ -2935,7 +2935,7 @@ static void defer_kevent (struct usbnet *dev, int work) static void rx_complete (struct urb *urb, struct pt_regs *regs); -static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) +static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) { struct sk_buff *skb; struct skb_data *entry; -- cgit v1.2.3-70-g09d2 From b375a0495fd622037560c73c05f23ae6f127bb0c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 29 Jul 2005 16:11:07 -0400 Subject: [PATCH] USB: URB_ASYNC_UNLINK flag removed from the kernel 29 July 2005, Cambridge, MA: This afternoon Alan Stern submitted a patch to remove the URB_ASYNC_UNLINK flag from the Linux kernel. Mr. Stern explained, "This flag is a relic from an earlier, less-well-designed system. For over a year it hasn't been used for anything other than printing warning messages." An anonymous spokesman for the Linux kernel development community commented, "This is exactly the sort of thing we see happening all the time. As the kernel evolves, support for old techniques and old code can be jettisoned and replaced by newer, better approaches. Proprietary operating systems do not have the freedom or flexibility to change so quickly." Mr. Stern, a staff member at Harvard University's Rowland Institute who works on Linux only as a hobby, noted that the patch (labelled as548) did not update two files, keyspan.c and option.c, in the USB drivers' "serial" subdirectory. "Those files need more extensive changes," he remarked. "They examine the status field of several URBs at times when they're not supposed to. That will need to be fixed before the URB_ASYNC_UNLINK flag is removed." Greg Kroah-Hartman, the kernel maintainer responsible for overseeing all of Linux's USB drivers, did not respond to our inquiries or return our calls. His only comment was "Applied, thanks." Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/block/ub.c | 8 ++++---- drivers/net/irda/irda-usb.c | 13 ++----------- drivers/usb/atm/cxacru.c | 2 -- drivers/usb/core/message.c | 4 +--- drivers/usb/core/urb.c | 26 ++++---------------------- drivers/usb/input/hid-core.c | 6 +++--- drivers/usb/misc/auerswald.c | 3 +-- drivers/usb/misc/sisusbvga/sisusb.c | 4 ++-- drivers/usb/misc/usbtest.c | 2 -- drivers/usb/net/catc.c | 2 -- drivers/usb/net/kaweth.c | 1 - drivers/usb/net/pegasus.c | 1 - drivers/usb/net/rtl8150.c | 1 - drivers/usb/net/usbnet.c | 2 -- drivers/usb/net/zd1201.c | 1 - drivers/usb/storage/transport.c | 7 +++---- include/linux/usb.h | 9 +-------- sound/usb/usbaudio.c | 10 ++++------ 18 files changed, 25 insertions(+), 77 deletions(-) (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 57d3279a881..aa0bf7ee008 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1010,7 +1010,7 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->send_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.transfer_flags = 0; /* Fill what we shouldn't be filling, because usb-storage did so. */ sc->work_urb.actual_length = 0; @@ -1395,7 +1395,7 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, page_address(sg->page) + sg->offset, sg->length, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; @@ -1442,7 +1442,7 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->recv_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; @@ -1563,7 +1563,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; + sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 46e0022d325..6c766fdc51a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -267,7 +267,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); urb->transfer_buffer_length = USB_IRDA_HEADER; - urb->transfer_flags = URB_ASYNC_UNLINK; + urb->transfer_flags = 0; /* Irq disabled -> GFP_ATOMIC */ if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { @@ -401,15 +401,12 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) skb->data, IRDA_SKB_MAX_MTU, write_bulk_callback, skb); urb->transfer_buffer_length = skb->len; - /* Note : unlink *must* be Asynchronous because of the code in - * irda_usb_net_timeout() -> call in irq - Jean II */ - urb->transfer_flags = URB_ASYNC_UNLINK; /* This flag (URB_ZERO_PACKET) indicates that what we send is not * a continuous stream of data but separate packets. * In this case, the USB layer will insert an empty USB frame (TD) * after each of our packets that is exact multiple of the frame size. * This is how the dongle will detect the end of packet - Jean II */ - urb->transfer_flags |= URB_ZERO_PACKET; + urb->transfer_flags = URB_ZERO_PACKET; /* Generate min turn time. FIXME: can we do better than this? */ /* Trying to a turnaround time at this level is trying to measure @@ -630,8 +627,6 @@ static void irda_usb_net_timeout(struct net_device *netdev) * in completion handler, because urb->status will * be -ENOENT. We will fix that at the next watchdog, * leaving more time to USB to recover... - * Also, we are in interrupt, so we need to have - * URB_ASYNC_UNLINK to work properly... * Jean II */ done = 1; break; @@ -1008,9 +1003,7 @@ static int irda_usb_net_close(struct net_device *netdev) } } /* Cancel Tx and speed URB - need to be synchronous to avoid races */ - self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->tx_urb); - self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->speed_urb); /* Stop and remove instance of IrLAP */ @@ -1521,9 +1514,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) usb_kill_urb(self->rx_urb[i]); /* Cancel Tx and speed URB. * Toggle flags to make sure it's synchronous. */ - self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->tx_urb); - self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->speed_urb); } diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 8e184e2641c..79861ee12a2 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -715,13 +715,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), instance->rcv_buf, PAGE_SIZE, cxacru_blocking_completion, &instance->rcv_done, 1); - instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_fill_int_urb(instance->snd_urb, usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD), instance->snd_buf, PAGE_SIZE, cxacru_blocking_completion, &instance->snd_done, 4); - instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK; init_MUTEX(&instance->cm_serialize); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 88d1b376f67..74197249c24 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -48,7 +48,6 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) init_completion(&done); urb->context = &done; - urb->transfer_flags |= URB_ASYNC_UNLINK; urb->actual_length = 0; status = usb_submit_urb(urb, GFP_NOIO); @@ -357,8 +356,7 @@ int usb_sg_init ( if (!io->urbs) goto nomem; - urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP - | URB_NO_INTERRUPT; + urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c0feee25ff0..c846fefb738 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -309,9 +309,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags) unsigned int allowed; /* enforce simple/standard policy */ - allowed = URB_ASYNC_UNLINK; // affects later unlinks - allowed |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - allowed |= URB_NO_INTERRUPT; + allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | + URB_NO_INTERRUPT); switch (temp) { case PIPE_BULK: if (is_out) @@ -400,14 +399,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags) * canceled (rather than any other code) and will quickly be removed * from host controller data structures. * - * In the past, clearing the URB_ASYNC_UNLINK transfer flag for the - * URB indicated that the request was synchronous. This usage is now - * deprecated; if the flag is clear the call will be forwarded to - * usb_kill_urb() and the return value will be 0. In the future, drivers - * should call usb_kill_urb() directly for synchronous unlinking. - * - * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this - * request is asynchronous. Success is indicated by returning -EINPROGRESS, + * This request is always asynchronous. + * Success is indicated by returning -EINPROGRESS, * at which time the URB will normally have been unlinked but not yet * given back to the device driver. When it is called, the completion * function will see urb->status == -ECONNRESET. Failure is indicated @@ -453,17 +446,6 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { -#ifdef CONFIG_DEBUG_KERNEL - if (printk_ratelimit()) { - printk(KERN_NOTICE "usb_unlink_urb() is deprecated for " - "synchronous unlinks. Use usb_kill_urb() instead.\n"); - WARN_ON(1); - } -#endif - usb_kill_urb(urb); - return 0; - } if (!(urb->dev && urb->dev->bus && urb->dev->bus->op)) return -ENODEV; return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 719c0316cc3..1ab95d24c5e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1688,7 +1688,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); + hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { if (hid->urbout) continue; @@ -1698,7 +1698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid, interval); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); + hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } @@ -1750,7 +1750,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK); + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); return hid; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 6f7994f5a71..ae4681f9f0e 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -426,7 +426,7 @@ static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb) /* cancel an urb which is submitted to the chain the result is 0 if the urb is cancelled, or -EINPROGRESS if - URB_ASYNC_UNLINK is set and the function is successfully started. + the function is successfully started. */ static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb) { @@ -515,7 +515,6 @@ static void auerchain_unlink_all (pauerchain_t acp) acep = acp->active; if (acep) { urbp = acep->urbp; - urbp->transfer_flags &= ~URB_ASYNC_UNLINK; dbg ("unlink active urb"); usb_kill_urb (urbp); } diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 2fd12264fd5..d63ce6c030f 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -229,7 +229,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len, sisusb_bulk_completeout, &sisusb->urbout_context[index]); - urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK); + urb->transfer_flags |= tflags; urb->actual_length = 0; if ((urb->transfer_dma = transfer_dma)) @@ -295,7 +295,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len, sisusb_bulk_completein, sisusb); - urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK); + urb->transfer_flags |= tflags; urb->actual_length = 0; if ((urb->transfer_dma = transfer_dma)) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index fd7fb98e4b2..54799eb0bc6 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -986,7 +986,6 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) u->context = &context; u->complete = ctrl_complete; - u->transfer_flags |= URB_ASYNC_UNLINK; } /* queue the urbs */ @@ -1052,7 +1051,6 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size); if (!urb) return -ENOMEM; - urb->transfer_flags |= URB_ASYNC_UNLINK; urb->context = &completion; urb->complete = unlink1_callback; diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index c8be912f24e..37ef365a247 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -383,7 +383,6 @@ static void catc_tx_done(struct urb *urb, struct pt_regs *regs) if (urb->status == -ECONNRESET) { dbg("Tx Reset."); - urb->transfer_flags &= ~URB_ASYNC_UNLINK; urb->status = 0; catc->netdev->trans_start = jiffies; catc->stats.tx_errors++; @@ -445,7 +444,6 @@ static void catc_tx_timeout(struct net_device *netdev) struct catc *catc = netdev_priv(netdev); warn("Transmit timed out."); - catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(catc->tx_urb); } diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 7ffa99b9760..e04b0ce3611 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -787,7 +787,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth_usb_transmit_complete, kaweth); kaweth->end = 0; - kaweth->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index fcd6d3ccef4..7484d34780f 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -825,7 +825,6 @@ static void pegasus_tx_timeout(struct net_device *net) pegasus_t *pegasus = netdev_priv(net); if (netif_msg_timer(pegasus)) printk(KERN_WARNING "%s: tx timeout\n", net->name); - pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(pegasus->tx_urb); pegasus->stats.tx_errors++; } diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 59ab40ebb39..c3d4e3589e3 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -653,7 +653,6 @@ static void rtl8150_tx_timeout(struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); warn("%s: Tx timeout.", netdev->name); - dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(dev->tx_urb); dev->stats.tx_errors++; } diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 4682696450d..3c6eef4168e 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -2987,7 +2987,6 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) usb_fill_bulk_urb (urb, dev->udev, dev->in, skb->data, size, rx_complete, skb); - urb->transfer_flags |= URB_ASYNC_UNLINK; spin_lock_irqsave (&dev->rxq.lock, lockflags); @@ -3561,7 +3560,6 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); - urb->transfer_flags |= URB_ASYNC_UNLINK; /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index fc013978837..c4e479ee926 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -847,7 +847,6 @@ static void zd1201_tx_timeout(struct net_device *dev) return; dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", dev->name); - zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(zd->tx_urb); zd->stats.tx_errors++; /* Restart the timeout to quiet the watchdog: */ diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index e42875152c3..c1ba5301ebf 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -96,8 +96,8 @@ * or before the URB_ACTIVE bit was set. If so, it's essential to cancel * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit * is still set). Either way, the function must then wait for the URB to - * finish. Note that because the URB_ASYNC_UNLINK flag is set, the URB can - * still be in progress even after a call to usb_unlink_urb() returns. + * finish. Note that the URB can still be in progress even after a call to + * usb_unlink_urb() returns. * * The idea is that (1) once the ABORTING or DISCONNECTING bit is set, * either the stop_transport() function or the submitting function @@ -158,8 +158,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) * hasn't been mapped for DMA. Yes, this is clunky, but it's * easier than always having the caller tell us whether the * transfer buffer has already been mapped. */ - us->current_urb->transfer_flags = - URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP; + us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP; if (us->current_urb->transfer_buffer == us->iobuf) us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; us->current_urb->transfer_dma = us->iobuf_dma; diff --git a/include/linux/usb.h b/include/linux/usb.h index 434e35120c6..4dbe580f933 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -616,7 +616,6 @@ extern int usb_disabled(void); #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ #define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ #define URB_NO_SETUP_DMA_MAP 0x0008 /* urb->setup_dma valid on submit */ -#define URB_ASYNC_UNLINK 0x0010 /* usb_unlink_urb() returns asap */ #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 */ @@ -724,13 +723,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * Initialization: * * All URBs submitted must initialize the dev, pipe, transfer_flags (may be - * zero), and complete fields. - * The URB_ASYNC_UNLINK transfer flag affects later invocations of - * the usb_unlink_urb() routine. Note: Failure to set URB_ASYNC_UNLINK - * with usb_unlink_urb() is deprecated. For synchronous unlinks use - * usb_kill_urb() instead. - * - * All URBs must also initialize + * zero), and complete fields. All URBs must also initialize * transfer_buffer and transfer_buffer_length. They may provide the * URB_SHORT_NOT_OK transfer flag, indicating that short reads are * to be treated as errors; that flag is invalid for write requests. diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 5aa5fe651a8..bfbec587665 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -735,10 +735,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) if (test_bit(i, &subs->active_mask)) { if (! test_and_set_bit(i, &subs->unlink_mask)) { struct urb *u = subs->dataurb[i].urb; - if (async) { - u->transfer_flags |= URB_ASYNC_UNLINK; + if (async) usb_unlink_urb(u); - } else + else usb_kill_urb(u); } } @@ -748,10 +747,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) if (test_bit(i+16, &subs->active_mask)) { if (! test_and_set_bit(i+16, &subs->unlink_mask)) { struct urb *u = subs->syncurb[i].urb; - if (async) { - u->transfer_flags |= URB_ASYNC_UNLINK; + if (async) usb_unlink_urb(u); - } else + else usb_kill_urb(u); } } -- cgit v1.2.3-70-g09d2 From f29fc259976e9f4dd1fe8ed59ccdd50e4ea61db0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:52:31 -0700 Subject: [PATCH] USB: usbnet (1/9) clean up framing This starts to prepare the core of "usbnet" to know less about various framing protocols that map Ethernet packets onto USB, so "minidrivers" can be modules that just plug into the core. - Remove some framing-specific code that cluttered the core: * net->hard_header_len records how much space to preallocate; now drivers that add their own framing (Net1080, GeneLink, Zaurus, and RNDIS) will have smoother TX paths. Even for the drivers (Zaurus, Net1080) that need trailers. * defines new dev->hard_mtu, using this "hardware" limit to check changes to the link's settable "software" mtu. * now net->hard_header_len and dev->hard_mtu are set up in the driver bind() routines, if needed. - Transaction ID is no longer specific to the Net1080 framing; RNDIS needs one too. - Creates a new "usbnet.h" header with declarations that are shared between the core and what will be separate modules. - Plus a couple other minor tweaks, like recognizing -ESHUTDOWN means the keventd work should just shut itself down asap. The core code is only about 1/3 of this large file. Splitting out the minidrivers into separate modules (e.g. ones for ASIX adapters, Zaurii and similar, CDC Ethernet, etc), in later patches, will improve maintainability and shrink typical runtime footprints. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 1 + drivers/usb/net/usbnet.c | 289 +++++++++++++++-------------------------------- drivers/usb/net/usbnet.h | 150 ++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 200 deletions(-) create mode 100644 drivers/usb/net/usbnet.h (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index b104430e2c6..135d50889d8 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -247,6 +247,7 @@ config USB_CDCETHER CDC Ethernet is an implementation option for DOCSIS cable modems that support USB connectivity, used for non-Microsoft USB hosts. + The Linux-USB CDC Ethernet Gadget driver is an open implementation. This driver should work with at least the following devices: * Ericsson PipeRider (all variants) diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 3c6eef4168e..3f2cad6dc26 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,6 +1,6 @@ /* * USB Networking Links - * Copyright (C) 2000-2005 by David Brownell + * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2002 Pavel Machek * Copyright (C) 2003-2005 David Hollis * Copyright (C) 2005 Phil Chang @@ -126,19 +126,18 @@ #include #include #include -#include #include #include #include -#include -#include #include -#include -#include #include #include -#define DRIVER_VERSION "03-Nov-2004" +#include + +#include "usbnet.h" + +#define DRIVER_VERSION "22-Aug-2005" /*-------------------------------------------------------------------------*/ @@ -149,14 +148,16 @@ * One maximum size Ethernet packet takes twenty four of them. * For high speed, each frame comfortably fits almost 36 max size * Ethernet packets (so queues should be bigger). + * + * REVISIT qlens should be members of 'struct usbnet'; the goal is to + * let the USB host controller be busy for 5msec or more before an irq + * is required, under load. Jumbograms change the equation. */ #define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) #define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) -// packets are always ethernet inside -// ... except they can be bigger (limit of 64K with NetChip framing) +/* packets are always ethernet, sometimes wrapped in other framing */ #define MIN_PACKET sizeof(struct ethhdr) -#define MAX_PACKET 32768 // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) @@ -166,7 +167,7 @@ #define THROTTLE_JIFFIES (HZ/8) // for vendor-specific control operations -#define CONTROL_TIMEOUT_MS 500 +#define CONTROL_TIMEOUT_MS USB_CTRL_GET_TIMEOUT // between wakeups #define UNLINK_TIMEOUT_MS 3 @@ -176,109 +177,6 @@ // randomly generated ethernet address static u8 node_id [ETH_ALEN]; -// state we keep for each device we handle -struct usbnet { - // housekeeping - struct usb_device *udev; - struct driver_info *driver_info; - wait_queue_head_t *wait; - - // i/o info: pipes etc - unsigned in, out; - struct usb_host_endpoint *status; - unsigned maxpacket; - struct timer_list delay; - - // protocol/interface state - struct net_device *net; - struct net_device_stats stats; - int msg_enable; - unsigned long data [5]; - - struct mii_if_info mii; - - // various kinds of pending driver work - struct sk_buff_head rxq; - struct sk_buff_head txq; - struct sk_buff_head done; - struct urb *interrupt; - struct tasklet_struct bh; - - struct work_struct kevent; - unsigned long flags; -# define EVENT_TX_HALT 0 -# define EVENT_RX_HALT 1 -# define EVENT_RX_MEMORY 2 -# define EVENT_STS_SPLIT 3 -# define EVENT_LINK_RESET 4 -}; - -// device-specific info used by the driver -struct driver_info { - char *description; - - int flags; -/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ -#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ -#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ -#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ -#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ - -#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ -#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ - -#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ - - /* init device ... can sleep, or cause probe() failure */ - int (*bind)(struct usbnet *, struct usb_interface *); - - /* cleanup device ... can sleep, but can't fail */ - void (*unbind)(struct usbnet *, struct usb_interface *); - - /* reset device ... can sleep */ - int (*reset)(struct usbnet *); - - /* see if peer is connected ... can sleep */ - int (*check_connect)(struct usbnet *); - - /* for status polling */ - void (*status)(struct usbnet *, struct urb *); - - /* link reset handling, called from defer_kevent */ - int (*link_reset)(struct usbnet *); - - /* fixup rx packet (strip framing) */ - int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); - - /* fixup tx packet (add framing) */ - struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, unsigned flags); - - // FIXME -- also an interrupt mechanism - // useful for at least PL2301/2302 and GL620USB-A - // and CDC use them to report 'is it connected' changes - - /* for new devices, use the descriptor-reading code instead */ - int in; /* rx endpoint */ - int out; /* tx endpoint */ - - unsigned long data; /* Misc driver specific data */ -}; - -// we record the state for each of our queued skbs -enum skb_state { - illegal = 0, - tx_start, tx_done, - rx_start, rx_done, rx_cleanup -}; - -struct skb_data { // skb->cb is one of these - struct urb *urb; - struct usbnet *dev; - enum skb_state state; - size_t length; -}; - static const char driver_name [] = "usbnet"; /* use ethtool to change the level for any given device */ @@ -286,22 +184,6 @@ static int msg_level = -1; module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Override default message level"); - -#ifdef DEBUG -#define devdbg(usbnet, fmt, arg...) \ - printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg) -#else -#define devdbg(usbnet, fmt, arg...) do {} while(0) -#endif - -#define deverr(usbnet, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) -#define devwarn(usbnet, fmt, arg...) \ - printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) - -#define devinfo(usbnet, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ - /*-------------------------------------------------------------------------*/ static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); @@ -921,6 +803,11 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); + if (dev->driver_info->flags & FLAG_FRAMING_AX) { + /* REVISIT: adjust hard_header_len too */ + dev->hard_mtu = 2048; + } + return 0; out2: kfree(buf); @@ -1432,9 +1319,8 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) info->ether->bLength); goto bad_desc; } - dev->net->mtu = le16_to_cpup ( - &info->ether->wMaxSegmentSize) - - ETH_HLEN; + dev->hard_mtu = le16_to_cpu( + info->ether->wMaxSegmentSize); /* because of Zaurus, we may be ignoring the host * side link address we were given. */ @@ -1988,9 +1874,17 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) return skb; } +static int genelink_bind (struct usbnet *dev, struct usb_interface *intf) +{ + dev->hard_mtu = GL_RCV_BUF_SIZE; + dev->net->hard_header_len += 4; + return 0; +} + static const struct driver_info genelink_info = { .description = "Genesys GeneLink", .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, + .bind = genelink_bind, .rx_fixup = genelink_rx_fixup, .tx_fixup = genelink_tx_fixup, @@ -2015,7 +1909,6 @@ static const struct driver_info genelink_info = { * *-------------------------------------------------------------------------*/ -#define dev_packet_id data[0] #define frame_errors data[1] /* @@ -2057,6 +1950,9 @@ struct nc_trailer { #define MIN_FRAMED FRAMED_SIZE(0) +/* packets _could_ be up to 64KB... */ +#define NC_MAX_PACKET 32767 + /* * Zero means no timeout; else, how long a 64 byte bulk packet may be queued @@ -2398,16 +2294,14 @@ static void nc_ensure_sync (struct usbnet *dev) static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) { struct nc_header *header; + struct net_device *net = dev->net; struct nc_trailer *trailer; u16 hdr_len, packet_len; - if (!(skb->len & 0x01) - || MIN_FRAMED > skb->len - || skb->len > FRAMED_SIZE (dev->net->mtu)) { + if (!(skb->len & 0x01)) { dev->stats.rx_frame_errors++; dbg ("rx framesize %d range %d..%d mtu %d", skb->len, - (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net->mtu), - dev->net->mtu); + net->hard_header_len, dev->hard_mtu, net->mtu); nc_ensure_sync (dev); return 0; } @@ -2415,7 +2309,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) header = (struct nc_header *) skb->data; hdr_len = le16_to_cpup (&header->hdr_len); packet_len = le16_to_cpup (&header->packet_len); - if (FRAMED_SIZE (packet_len) > MAX_PACKET) { + if (FRAMED_SIZE (packet_len) > NC_MAX_PACKET) { dev->stats.rx_frame_errors++; dbg ("packet too big, %d", packet_len); nc_ensure_sync (dev); @@ -2505,11 +2399,23 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) return skb2; } +static int net1080_bind (struct usbnet *dev, struct usb_interface *intf) +{ + unsigned extra = sizeof (struct nc_header) + + 1 + + sizeof (struct nc_trailer); + + dev->net->hard_header_len += extra; + dev->hard_mtu = NC_MAX_PACKET; + return 0; +} + static const struct driver_info net1080_info = { .description = "NetChip TurboCONNECT", .flags = FLAG_FRAMING_NC, + .bind = net1080_bind, .reset = net1080_reset, - .check_connect =net1080_check_connect, + .check_connect = net1080_check_connect, .rx_fixup = net1080_rx_fixup, .tx_fixup = net1080_tx_fixup, }; @@ -2690,11 +2596,20 @@ done: return skb; } +static int zaurus_bind (struct usbnet *dev, struct usb_interface *intf) +{ + /* Belcarra's funky framing has other options; mostly + * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. + */ + dev->net->hard_header_len += 6; + return generic_cdc_bind(dev, intf); +} + static const struct driver_info zaurus_sl5x00_info = { .description = "Sharp Zaurus SL-5x00", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, - .bind = generic_cdc_bind, + .bind = zaurus_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, }; @@ -2704,7 +2619,7 @@ static const struct driver_info zaurus_pxa_info = { .description = "Sharp Zaurus, PXA-2xx based", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, - .bind = generic_cdc_bind, + .bind = zaurus_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, }; @@ -2714,7 +2629,7 @@ static const struct driver_info olympus_mxl_info = { .description = "Olympus R1000", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, - .bind = generic_cdc_bind, + .bind = zaurus_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, }; @@ -2868,22 +2783,12 @@ static const struct driver_info bogus_mdlm_info = { static int usbnet_change_mtu (struct net_device *net, int new_mtu) { struct usbnet *dev = netdev_priv(net); + int ll_mtu = new_mtu + net->hard_header_len; - if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET) - return -EINVAL; -#ifdef CONFIG_USB_NET1080 - if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) { - if (FRAMED_SIZE (new_mtu) > MAX_PACKET) - return -EINVAL; - } -#endif -#ifdef CONFIG_USB_GENESYS - if (((dev->driver_info->flags) & FLAG_FRAMING_GL) - && new_mtu > GL_MAX_PACKET_LEN) + if (new_mtu <= 0 || ll_mtu > dev->hard_mtu) return -EINVAL; -#endif // no second zero-length packet read wanted after mtu-sized packets - if (((new_mtu + sizeof (struct ethhdr)) % dev->maxpacket) == 0) + if ((ll_mtu % dev->maxpacket) == 0) return -EDOM; net->mtu = new_mtu; return 0; @@ -2943,33 +2848,8 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) unsigned long lockflags; size_t size; -#ifdef CONFIG_USB_NET1080 - if (dev->driver_info->flags & FLAG_FRAMING_NC) - size = FRAMED_SIZE (dev->net->mtu); - else -#endif -#ifdef CONFIG_USB_GENESYS - if (dev->driver_info->flags & FLAG_FRAMING_GL) - size = GL_RCV_BUF_SIZE; - else -#endif -#ifdef CONFIG_USB_ZAURUS - if (dev->driver_info->flags & FLAG_FRAMING_Z) - size = 6 + (sizeof (struct ethhdr) + dev->net->mtu); - else -#endif -#ifdef CONFIG_USB_RNDIS - if (dev->driver_info->flags & FLAG_FRAMING_RN) - size = RNDIS_MAX_TRANSFER; - else -#endif -#ifdef CONFIG_USB_AX8817X - if (dev->driver_info->flags & FLAG_FRAMING_AX) - size = 2048; - else -#endif - size = (sizeof (struct ethhdr) + dev->net->mtu); - + size = max(dev->net->hard_header_len + dev->net->mtu, + (unsigned)ETH_FRAME_LEN); if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { if (netif_msg_rx_err (dev)) devdbg (dev, "no rx skb"); @@ -3062,7 +2942,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) switch (urb_status) { // success case 0: - if (MIN_PACKET > skb->len || skb->len > MAX_PACKET) { + if (skb->len < dev->net->hard_header_len) { entry->state = rx_cleanup; dev->stats.rx_errors++; dev->stats.rx_length_errors++; @@ -3334,11 +3214,11 @@ static u32 usbnet_get_link (struct net_device *net) { struct usbnet *dev = netdev_priv(net); - /* If a check_connect is defined, return it's results */ + /* If a check_connect is defined, return its result */ if (dev->driver_info->check_connect) return dev->driver_info->check_connect (dev) == 0; - /* Otherwise, we're up to avoid breaking scripts */ + /* Otherwise, say we're up (to avoid breaking scripts) */ return 1; } @@ -3386,19 +3266,24 @@ kevent (void *data) if (test_bit (EVENT_TX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->txq); status = usb_clear_halt (dev->udev, dev->out); - if (status < 0 && status != -EPIPE) { + if (status < 0 + && status != -EPIPE + && status != -ESHUTDOWN) { if (netif_msg_tx_err (dev)) deverr (dev, "can't clear tx halt, status %d", status); } else { clear_bit (EVENT_TX_HALT, &dev->flags); - netif_wake_queue (dev->net); + if (status != -ESHUTDOWN) + netif_wake_queue (dev->net); } } if (test_bit (EVENT_RX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->rxq); status = usb_clear_halt (dev->udev, dev->in); - if (status < 0 && status != -EPIPE) { + if (status < 0 + && status != -EPIPE + && status != -ESHUTDOWN) { if (netif_msg_rx_err (dev)) deverr (dev, "can't clear rx halt, status %d", status); @@ -3574,7 +3459,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) #ifdef CONFIG_USB_NET1080 if (info->flags & FLAG_FRAMING_NC) { - header->packet_id = cpu_to_le16 ((u16)dev->dev_packet_id++); + header->packet_id = cpu_to_le16 ((u16)dev->xid++); put_unaligned (header->packet_id, &trailer->packet_id); #if 0 devdbg (dev, "frame >tx h %d p %d id %d", @@ -3776,6 +3661,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->net = net; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); + dev->hard_mtu = net->mtu + net->hard_header_len; #if 0 // dma_supported() is deeply broken on almost all architectures @@ -3804,6 +3690,10 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if ((dev->driver_info->flags & FLAG_ETHER) != 0 && (net->dev_addr [0] & 0x02) == 0) strcpy (net->name, "eth%d"); + + /* maybe the remote can't receive an Ethernet MTU */ + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) + net->mtu = dev->hard_mtu - net->hard_header_len; } else if (!info->in || info->out) status = get_endpoints (dev, udev); else { @@ -3817,7 +3707,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) status = 0; } - if (status == 0 && dev->status) status = init_status (dev, udev); if (status < 0) @@ -4212,7 +4101,7 @@ static struct ethtool_ops usbnet_ethtool_ops = { /*-------------------------------------------------------------------------*/ -static int __init usbnet_init (void) +static int __init usbnet_init(void) { // compiler should optimize these out BUG_ON (sizeof (((struct sk_buff *)0)->cb) @@ -4226,14 +4115,14 @@ static int __init usbnet_init (void) return usb_register(&usbnet_driver); } -module_init (usbnet_init); +module_init(usbnet_init); -static void __exit usbnet_exit (void) +static void __exit usbnet_exit(void) { - usb_deregister (&usbnet_driver); + usb_deregister(&usbnet_driver); } -module_exit (usbnet_exit); +module_exit(usbnet_exit); -MODULE_AUTHOR ("David Brownell "); -MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)"); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("USB Host-to-Host Link Drivers (numerous vendors)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h new file mode 100644 index 00000000000..44026189a8a --- /dev/null +++ b/drivers/usb/net/usbnet.h @@ -0,0 +1,150 @@ +/* + * USB Networking Link Interface + * + * Copyright (C) 2000-2005 by David Brownell + * Copyright (C) 2003-2005 David Hollis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __USBNET_H +#define __USBNET_H + + +/* interface from usbnet core to each USB networking device we handle */ +struct usbnet { + /* housekeeping */ + struct usb_device *udev; + struct driver_info *driver_info; + wait_queue_head_t *wait; + + /* i/o info: pipes etc */ + unsigned in, out; + struct usb_host_endpoint *status; + unsigned maxpacket; + struct timer_list delay; + + /* protocol/interface state */ + struct net_device *net; + struct net_device_stats stats; + int msg_enable; + unsigned long data [5]; + u32 xid; + u32 hard_mtu; /* count any extra framing */ + struct mii_if_info mii; + + /* various kinds of pending driver work */ + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct urb *interrupt; + struct tasklet_struct bh; + + struct work_struct kevent; + unsigned long flags; +# define EVENT_TX_HALT 0 +# define EVENT_RX_HALT 1 +# define EVENT_RX_MEMORY 2 +# define EVENT_STS_SPLIT 3 +# define EVENT_LINK_RESET 4 +}; + + +/* interface from the device/framing level "minidriver" to core */ +struct driver_info { + char *description; + + int flags; +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ +#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ +#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ +#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ +#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ + +#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ +#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ + +#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ + + /* init device ... can sleep, or cause probe() failure */ + int (*bind)(struct usbnet *, struct usb_interface *); + + /* cleanup device ... can sleep, but can't fail */ + void (*unbind)(struct usbnet *, struct usb_interface *); + + /* reset device ... can sleep */ + int (*reset)(struct usbnet *); + + /* see if peer is connected ... can sleep */ + int (*check_connect)(struct usbnet *); + + /* for status polling */ + void (*status)(struct usbnet *, struct urb *); + + /* link reset handling, called from defer_kevent */ + int (*link_reset)(struct usbnet *); + + /* fixup rx packet (strip framing) */ + int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); + + /* fixup tx packet (add framing) */ + struct sk_buff *(*tx_fixup)(struct usbnet *dev, + struct sk_buff *skb, unsigned flags); + + /* for new devices, use the descriptor-reading code instead */ + int in; /* rx endpoint */ + int out; /* tx endpoint */ + + unsigned long data; /* Misc driver specific data */ +}; + + +/* we record the state for each of our queued skbs */ +enum skb_state { + illegal = 0, + tx_start, tx_done, + rx_start, rx_done, rx_cleanup +}; + +struct skb_data { /* skb->cb is one of these */ + struct urb *urb; + struct usbnet *dev; + enum skb_state state; + size_t length; +}; + + + +/* messaging support includes the interface name, so it must not be + * used before it has one ... notably, in minidriver bind() calls. + */ +#ifdef DEBUG +#define devdbg(usbnet, fmt, arg...) \ + printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg) +#else +#define devdbg(usbnet, fmt, arg...) do {} while(0) +#endif + +#define deverr(usbnet, fmt, arg...) \ + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) +#define devwarn(usbnet, fmt, arg...) \ + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) + +#define devinfo(usbnet, fmt, arg...) \ + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ + + +#endif /* __USBNET_H */ -- cgit v1.2.3-70-g09d2 From 38bde1d4699af45e6a4167a72e2e512e45c35ca8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:52:45 -0700 Subject: [PATCH] USB: usbnet (2/9) module for simple network links This patch creates the first of several separate "minidriver" modules for "usbnet". This one handles only the very simplest hardware, which can be handled almost entirely by the "usbnet" core. - Move device-specific bits into new "cdc_subset.c" driver, shrinking "usbnet" by a bunch; - Export the functions needed to support this minidriver (with EXPORT_SYMBOL_GPL); - Update Kconfig and kbuild accordingly. This one handles about a dozen different device types, with the most notable ones being Gumstix and most Linux-based PDAs (except Zaurus running that ancient code from Sharp). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 123 ++++++++-------- drivers/usb/net/Makefile | 1 + drivers/usb/net/cdc_subset.c | 335 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 240 ++----------------------------- drivers/usb/net/usbnet.h | 15 +- 5 files changed, 429 insertions(+), 285 deletions(-) create mode 100644 drivers/usb/net/cdc_subset.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 135d50889d8..6399b43d41a 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -128,32 +128,6 @@ config USB_USBNET comment "USB Host-to-Host Cables" depends on USB_USBNET -config USB_ALI_M5632 - boolean "ALi M5632 based 'USB 2.0 Data Link' cables" - depends on USB_USBNET - default y - help - Choose this option if you're using a host-to-host cable - based on this design, which supports USB 2.0 high speed. - -config USB_AN2720 - boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" - depends on USB_USBNET - default y - help - Choose this option if you're using a host-to-host cable - based on this design. Note that AnchorChips is now a - Cypress brand. - -config USB_BELKIN - boolean "eTEK based host-to-host cables (Advance, Belkin, ...)" - depends on USB_USBNET - default y - help - Choose this option if you're using a host-to-host cable - based on this design: two NetChip 2890 chips and an Atmel - microcontroller, with LEDs that indicate traffic. - config USB_GENESYS boolean "GeneSys GL620USB-A based cables" default y @@ -182,42 +156,9 @@ config USB_PL2301 Choose this option if you're using a host-to-host cable with one of these chips. -config USB_KC2190 - boolean "KT Technology KC2190 based cables (InstaNet)" - default y - depends on USB_USBNET && EXPERIMENTAL - help - Choose this option if you're using a host-to-host cable - with one of these chips. - comment "Intelligent USB Devices/Gadgets" depends on USB_USBNET -config USB_ARMLINUX - boolean "Embedded ARM Linux links (iPaq, ...)" - depends on USB_USBNET - default y - help - Choose this option to support the "usb-eth" networking driver - used by most of the ARM Linux community with device controllers - such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities - in some PXA versions of the "blob" boot loader. - - Linux-based "Gumstix" PXA-25x based systems use this protocol - to talk with other Linux systems. - - Although the ROMs shipped with Sharp Zaurus products use a - different link level framing protocol, you can have them use - this simpler protocol by installing a different kernel. - -config USB_EPSON2888 - boolean "Epson 2888 based firmware (DEVELOPMENT)" - depends on USB_USBNET - default y - help - Choose this option to support the usb networking links used - by some sample firmware from Epson. - config USB_ZAURUS boolean "Sharp Zaurus (stock ROMs) and compatible" depends on USB_USBNET @@ -292,6 +233,70 @@ config USB_AX8817X This driver creates an interface named "ethX", where X depends on what other networking devices you have in use. + +config USB_NET_CDC_SUBSET + tristate "Simple USB Network Links (CDC Ethernet subset)" + depends on USB_USBNET + help + This driver module supports USB network devices that can work + without any device-specific information. Select it if you have + one of these drivers. + + Note that while many USB host-to-host cables can work in this mode, + that may mean not being able to talk to Win32 systems or more + commonly not being able to handle certain events (like replugging + the host on the other end) very well. Also, these devices will + not generally have permanently assigned Ethernet addresses. + +config USB_ALI_M5632 + boolean "ALi M5632 based 'USB 2.0 Data Link' cables" + depends on USB_NET_CDC_SUBSET + help + Choose this option if you're using a host-to-host cable + based on this design, which supports USB 2.0 high speed. + +config USB_AN2720 + boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" + depends on USB_NET_CDC_SUBSET + help + Choose this option if you're using a host-to-host cable + based on this design. Note that AnchorChips is now a + Cypress brand. + +config USB_BELKIN + boolean "eTEK based host-to-host cables (Advance, Belkin, ...)" + depends on USB_NET_CDC_SUBSET + default y + help + Choose this option if you're using a host-to-host cable + based on this design: two NetChip 2890 chips and an Atmel + microcontroller, with LEDs that indicate traffic. + +config USB_ARMLINUX + boolean "Embedded ARM Linux links (iPaq, ...)" + depends on USB_NET_CDC_SUBSET + default y + help + Choose this option to support the "usb-eth" networking driver + used by most of the ARM Linux community with device controllers + such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities + in some PXA versions of the "blob" boot loader. + + Linux-based "Gumstix" PXA-25x based systems use this protocol + to talk with other Linux systems. + + Although the ROMs shipped with Sharp Zaurus products use a + different link level framing protocol, you can have them use + this simpler protocol by installing a different kernel. + +config USB_EPSON2888 + boolean "Epson 2888 based firmware (DEVELOPMENT)" + depends on USB_NET_CDC_SUBSET + help + Choose this option to support the usb networking links used + by some sample firmware from Epson. + + config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" depends on NET_RADIO diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index fe3fd4115e1..23608ccc638 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o +obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_USBNET) += usbnet.o obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c new file mode 100644 index 00000000000..f1730b685fd --- /dev/null +++ b/drivers/usb/net/cdc_subset.c @@ -0,0 +1,335 @@ +/* + * Simple "CDC Subset" USB Networking Links + * Copyright (C) 2000-2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * This supports simple USB network links that don't require any special + * framing or hardware control operations. The protocol used here is a + * strict subset of CDC Ethernet, with three basic differences reflecting + * the goal that almost any hardware should run it: + * + * - Minimal runtime control: one interface, no altsettings, and + * no vendor or class specific control requests. If a device is + * configured, it is allowed to exchange packets with the host. + * Fancier models would mean not working on some hardware. + * + * - Minimal manufacturing control: no IEEE "Organizationally + * Unique ID" required, or an EEPROMs to store one. Each host uses + * one random "locally assigned" Ethernet address instead, which can + * of course be overridden using standard tools like "ifconfig". + * (With 2^46 such addresses, same-net collisions are quite rare.) + * + * - There is no additional framing data for USB. Packets are written + * exactly as in CDC Ethernet, starting with an Ethernet header and + * terminated by a short packet. However, the host will never send a + * zero length packet; some systems can't handle those robustly. + * + * Anything that can transmit and receive USB bulk packets can implement + * this protocol. That includes both smart peripherals and quite a lot + * of "host-to-host" USB cables (which embed two devices back-to-back). + * + * Note that although Linux may use many of those host-to-host links + * with this "cdc_subset" framing, that doesn't mean there may not be a + * better approach. Handling the "other end unplugs/replugs" scenario + * well tends to require chip-specific vendor requests. Also, Windows + * peers at the other end of host-to-host cables may expect their own + * framing to be used rather than this "cdc_subset" model. + */ + +#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX) +/* PDA style devices are always connected if present */ +static int always_connected (struct usbnet *dev) +{ + return 0; +} +#endif + +#ifdef CONFIG_USB_ALI_M5632 +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * ALi M5632 driver ... does high speed + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info ali_m5632_info = { + .description = "ALi M5632", +}; + + +#endif + + +#ifdef CONFIG_USB_AN2720 +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * AnchorChips 2720 driver ... http://www.cypress.com + * + * This doesn't seem to have a way to detect whether the peer is + * connected, or need any reset handshaking. It's got pretty big + * internal buffers (handles most of a frame's worth of data). + * Chip data sheets don't describe any vendor control messages. + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info an2720_info = { + .description = "AnchorChips/Cypress 2720", + // no reset available! + // no check_connect available! + + .in = 2, .out = 2, // direction distinguishes these +}; + +#endif /* CONFIG_USB_AN2720 */ + + +#ifdef CONFIG_USB_BELKIN +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller + * + * ... also two eTEK designs, including one sold as "Advance USBNET" + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info belkin_info = { + .description = "Belkin, eTEK, or compatible", +}; + +#endif /* CONFIG_USB_BELKIN */ + + + +#ifdef CONFIG_USB_EPSON2888 +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * EPSON USB clients + * + * This is the same idea as Linux PDAs (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. + * + * Support was from Juro Bystricky + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info epson2888_info = { + .description = "Epson USB Device", + .check_connect = always_connected, + + .in = 4, .out = 3, +}; + +#endif /* CONFIG_USB_EPSON2888 */ + + +#ifdef CONFIG_USB_KC2190 +#define HAVE_HARDWARE +static const struct driver_info kc2190_info = { + .description = "KC Technology KC-190", +}; +#endif /* CONFIG_USB_KC2190 */ + + +#ifdef CONFIG_USB_ARMLINUX +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * Intel's SA-1100 chip integrates basic USB support, and is used + * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. + * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to + * network using minimal USB framing data. + * + * This describes the driver currently in standard ARM Linux kernels. + * The Zaurus uses a different driver (see later). + * + * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support + * and different USB endpoint numbering than the SA1100 devices. The + * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 + * so we rely on the endpoint descriptors. + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info linuxdev_info = { + .description = "Linux Device", + .check_connect = always_connected, +}; + +static const struct driver_info yopy_info = { + .description = "Yopy", + .check_connect = always_connected, +}; + +static const struct driver_info blob_info = { + .description = "Boot Loader OBject", + .check_connect = always_connected, +}; + +#endif /* CONFIG_USB_ARMLINUX */ + + +/*-------------------------------------------------------------------------*/ + +#ifndef HAVE_HARDWARE +#error You need to configure some hardware for this driver +#endif + +/* + * chip vendor names won't normally be on the cables, and + * may not be on the device. + */ + +static const struct usb_device_id products [] = { + +#ifdef CONFIG_USB_ALI_M5632 +{ + USB_DEVICE (0x0402, 0x5632), // ALi defaults + .driver_info = (unsigned long) &ali_m5632_info, +}, +#endif + +#ifdef CONFIG_USB_AN2720 +{ + USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults + .driver_info = (unsigned long) &an2720_info, +}, { + USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET + .driver_info = (unsigned long) &an2720_info, +}, +#endif + +#ifdef CONFIG_USB_BELKIN +{ + USB_DEVICE (0x050d, 0x0004), // Belkin + .driver_info = (unsigned long) &belkin_info, +}, { + USB_DEVICE (0x056c, 0x8100), // eTEK + .driver_info = (unsigned long) &belkin_info, +}, { + USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) + .driver_info = (unsigned long) &belkin_info, +}, +#endif + +#ifdef CONFIG_USB_EPSON2888 +{ + USB_DEVICE (0x0525, 0x2888), // EPSON USB client + .driver_info = (unsigned long) &epson2888_info, +}, +#endif + +#ifdef CONFIG_USB_KC2190 +{ + USB_DEVICE (0x050f, 0x0190), // KC-190 + .driver_info = (unsigned long) &kc2190_info, +}, +#endif + +#ifdef CONFIG_USB_ARMLINUX +/* + * SA-1100 using standard ARM Linux kernels, or compatible. + * Often used when talking to Linux PDAs (iPaq, Yopy, etc). + * The sa-1100 "usb-eth" driver handles the basic framing. + * + * PXA25x or PXA210 ... these use a "usb-eth" driver much like + * the sa1100 one, but hardware uses different endpoint numbers. + * + * Or the Linux "Ethernet" gadget on hardware that can't talk + * CDC Ethernet (e.g., no altsettings), in either of two modes: + * - acting just like the old "usb-eth" firmware, though + * the implementation is different + * - supporting RNDIS as the first/default configuration for + * MS-Windows interop; Linux needs to use the other config + */ +{ + // 1183 = 0x049F, both used as hex values? + // Compaq "Itsy" vendor/product id + USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible + .driver_info = (unsigned long) &linuxdev_info, +}, { + USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" + .driver_info = (unsigned long) &yopy_info, +}, { + USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader + .driver_info = (unsigned long) &blob_info, +}, { + // Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config + // e.g. Gumstix, current OpenZaurus, ... + USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), + .driver_info = (unsigned long) &linuxdev_info, +}, +#endif + + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +/*-------------------------------------------------------------------------*/ + +static struct usb_driver cdc_subset_driver = { + .owner = THIS_MODULE, + .name = "cdc_subset", + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, + .id_table = products, +}; + +static int __init cdc_subset_init(void) +{ + return usb_register(&cdc_subset_driver); +} +module_init(cdc_subset_init); + +static void __exit cdc_subset_exit(void) +{ + usb_deregister(&cdc_subset_driver); +} +module_exit(cdc_subset_exit); + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 3f2cad6dc26..57b41fbd3bb 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -321,48 +321,6 @@ static void skb_return (struct usbnet *dev, struct sk_buff *skb) devdbg (dev, "netif_rx status %d", status); } - -#ifdef CONFIG_USB_ALI_M5632 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * ALi M5632 driver ... does high speed - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info ali_m5632_info = { - .description = "ALi M5632", -}; - - -#endif - - -#ifdef CONFIG_USB_AN2720 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * AnchorChips 2720 driver ... http://www.cypress.com - * - * This doesn't seem to have a way to detect whether the peer is - * connected, or need any reset handshaking. It's got pretty big - * internal buffers (handles most of a frame's worth of data). - * Chip data sheets don't describe any vendor control messages. - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info an2720_info = { - .description = "AnchorChips/Cypress 2720", - // no reset available! - // no check_connect available! - - .in = 2, .out = 2, // direction distinguishes these -}; - -#endif /* CONFIG_USB_AN2720 */ - #ifdef CONFIG_USB_AX8817X /* ASIX AX8817X based USB 2.0 Ethernet Devices */ @@ -1141,25 +1099,6 @@ static const struct driver_info ax88772_info = { #endif /* CONFIG_USB_AX8817X */ - -#ifdef CONFIG_USB_BELKIN -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller - * - * ... also two eTEK designs, including one sold as "Advance USBNET" - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info belkin_info = { - .description = "Belkin, eTEK, or compatible", -}; - -#endif /* CONFIG_USB_BELKIN */ - - /*------------------------------------------------------------------------- * @@ -1537,32 +1476,6 @@ static const struct driver_info cdc_info = { #endif /* CONFIG_USB_CDCETHER */ - -#ifdef CONFIG_USB_EPSON2888 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * EPSON USB clients - * - * This is the same idea as Linux PDAs (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. - * - * Support was from Juro Bystricky - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info epson2888_info = { - .description = "Epson USB Device", - .check_connect = always_connected, - - .in = 4, .out = 3, -}; - -#endif /* CONFIG_USB_EPSON2888 */ - #ifdef CONFIG_USB_GENESYS #define HAVE_HARDWARE @@ -2494,52 +2407,6 @@ static const struct driver_info prolific_info = { #endif /* CONFIG_USB_PL2301 */ - -#ifdef CONFIG_USB_KC2190 -#define HAVE_HARDWARE -static const struct driver_info kc2190_info = { - .description = "KC Technology KC-190", -}; -#endif /* CONFIG_USB_KC2190 */ - - -#ifdef CONFIG_USB_ARMLINUX -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Intel's SA-1100 chip integrates basic USB support, and is used - * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. - * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to - * network using minimal USB framing data. - * - * This describes the driver currently in standard ARM Linux kernels. - * The Zaurus uses a different driver (see later). - * - * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support - * and different USB endpoint numbering than the SA1100 devices. The - * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 - * so we rely on the endpoint descriptors. - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info linuxdev_info = { - .description = "Linux Device", - .check_connect = always_connected, -}; - -static const struct driver_info yopy_info = { - .description = "Yopy", - .check_connect = always_connected, -}; - -static const struct driver_info blob_info = { - .description = "Boot Loader OBject", - .check_connect = always_connected, -}; - -#endif /* CONFIG_USB_ARMLINUX */ - #ifdef CONFIG_USB_ZAURUS #define HAVE_HARDWARE @@ -3575,7 +3442,7 @@ static void usbnet_bh (unsigned long param) // precondition: never called in_interrupt -static void usbnet_disconnect (struct usb_interface *intf) +void usbnet_disconnect (struct usb_interface *intf) { struct usbnet *dev; struct usb_device *xdev; @@ -3589,7 +3456,8 @@ static void usbnet_disconnect (struct usb_interface *intf) xdev = interface_to_usbdev (intf); if (netif_msg_probe (dev)) - devinfo (dev, "unregister usbnet usb-%s-%s, %s", + devinfo (dev, "unregister '%s' usb-%s-%s, %s", + intf->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); @@ -3605,6 +3473,7 @@ static void usbnet_disconnect (struct usb_interface *intf) free_netdev(net); usb_put_dev (xdev); } +EXPORT_SYMBOL_GPL(usbnet_disconnect); /*-------------------------------------------------------------------------*/ @@ -3613,7 +3482,7 @@ static struct ethtool_ops usbnet_ethtool_ops; // precondition: never called in_interrupt -static int +int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; @@ -3719,8 +3588,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status) goto out3; if (netif_msg_probe (dev)) - devinfo (dev, "register usbnet at usb-%s-%s, %s, " + devinfo (dev, "register '%s' at usb-%s-%s, %s, " "%02x:%02x:%02x:%02x:%02x:%02x", + udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, net->dev_addr [0], net->dev_addr [1], @@ -3744,12 +3614,15 @@ out: usb_put_dev(xdev); return status; } +EXPORT_SYMBOL_GPL(usbnet_probe); /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_PM +/* FIXME these suspend/resume methods assume non-CDC style + * devices, with only one interface. + */ -static int usbnet_suspend (struct usb_interface *intf, pm_message_t message) +int usbnet_suspend (struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); @@ -3762,8 +3635,9 @@ static int usbnet_suspend (struct usb_interface *intf, pm_message_t message) intf->dev.power.power_state = PMSG_SUSPEND; return 0; } +EXPORT_SYMBOL_GPL(usbnet_suspend); -static int usbnet_resume (struct usb_interface *intf) +int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); @@ -3772,13 +3646,8 @@ static int usbnet_resume (struct usb_interface *intf) tasklet_schedule (&dev->bh); return 0; } +EXPORT_SYMBOL_GPL(usbnet_resume); -#else /* !CONFIG_PM */ - -#define usbnet_suspend NULL -#define usbnet_resume NULL - -#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -3793,36 +3662,6 @@ static int usbnet_resume (struct usb_interface *intf) static const struct usb_device_id products [] = { -#ifdef CONFIG_USB_ALI_M5632 -{ - USB_DEVICE (0x0402, 0x5632), // ALi defaults - .driver_info = (unsigned long) &ali_m5632_info, -}, -#endif - -#ifdef CONFIG_USB_AN2720 -{ - USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults - .driver_info = (unsigned long) &an2720_info, -}, { - USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET - .driver_info = (unsigned long) &an2720_info, -}, -#endif - -#ifdef CONFIG_USB_BELKIN -{ - USB_DEVICE (0x050d, 0x0004), // Belkin - .driver_info = (unsigned long) &belkin_info, -}, { - USB_DEVICE (0x056c, 0x8100), // eTEK - .driver_info = (unsigned long) &belkin_info, -}, { - USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) - .driver_info = (unsigned long) &belkin_info, -}, -#endif - #ifdef CONFIG_USB_AX8817X { // Linksys USB200M @@ -3879,13 +3718,6 @@ static const struct usb_device_id products [] = { }, #endif -#ifdef CONFIG_USB_EPSON2888 -{ - USB_DEVICE (0x0525, 0x2888), // EPSON USB client - .driver_info = (unsigned long) &epson2888_info, -}, -#endif - #ifdef CONFIG_USB_GENESYS { USB_DEVICE (0x05e3, 0x0502), // GL620USB-A @@ -3916,13 +3748,6 @@ static const struct usb_device_id products [] = { }, #endif -#ifdef CONFIG_USB_KC2190 -{ - USB_DEVICE (0x050f, 0x0190), // KC-190 - .driver_info = (unsigned long) &kc2190_info, -}, -#endif - #ifdef CONFIG_USB_RNDIS { /* RNDIS is MSFT's un-official variant of CDC ACM */ @@ -3931,41 +3756,6 @@ static const struct usb_device_id products [] = { }, #endif -#ifdef CONFIG_USB_ARMLINUX -/* - * SA-1100 using standard ARM Linux kernels, or compatible. - * Often used when talking to Linux PDAs (iPaq, Yopy, etc). - * The sa-1100 "usb-eth" driver handles the basic framing. - * - * PXA25x or PXA210 ... these use a "usb-eth" driver much like - * the sa1100 one, but hardware uses different endpoint numbers. - * - * Or the Linux "Ethernet" gadget on hardware that can't talk - * CDC Ethernet (e.g., no altsettings), in either of two modes: - * - acting just like the old "usb-eth" firmware, though - * the implementation is different - * - supporting RNDIS as the first/default configuration for - * MS-Windows interop; Linux needs to use the other config - */ -{ - // 1183 = 0x049F, both used as hex values? - // Compaq "Itsy" vendor/product id - USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible - .driver_info = (unsigned long) &linuxdev_info, -}, { - USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" - .driver_info = (unsigned long) &yopy_info, -}, { - USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader - .driver_info = (unsigned long) &blob_info, -}, { - // Linux Ethernet/RNDIS gadget on pxa210/25x/26x - // e.g. Gumstix, current OpenZaurus, ... - USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), - .driver_info = (unsigned long) &linuxdev_info, -}, -#endif - #if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_CDCETHER) /* * SA-1100 based Sharp Zaurus ("collie"), or compatible. diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 44026189a8a..d903b461756 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -24,7 +24,7 @@ #define __USBNET_H -/* interface from usbnet core to each USB networking device we handle */ +/* interface from usbnet core to each USB networking link we handle */ struct usbnet { /* housekeeping */ struct usb_device *udev; @@ -62,6 +62,10 @@ struct usbnet { # define EVENT_LINK_RESET 4 }; +static inline struct usb_driver *driver_of(struct usb_interface *intf) +{ + return to_usb_driver(intf->dev.driver); +} /* interface from the device/framing level "minidriver" to core */ struct driver_info { @@ -111,6 +115,15 @@ struct driver_info { unsigned long data; /* Misc driver specific data */ }; +/* Minidrivers are just drivers using the "usbnet" core as a powerful + * network-specific subroutine library ... that happens to do pretty + * much everything except custom framing and chip-specific stuff. + */ +extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *); +extern int usbnet_suspend (struct usb_interface *, pm_message_t ); +extern int usbnet_resume (struct usb_interface *); +extern void usbnet_disconnect(struct usb_interface *); + /* we record the state for each of our queued skbs */ enum skb_state { -- cgit v1.2.3-70-g09d2 From 2e55cc7210fef90f88201e860d8767594974574e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:53:10 -0700 Subject: [PATCH] USB: usbnet (3/9) module for ASIX Ethernet adapters This patch moves the ASIX AX8817x driver into its own file, just using the "usbnet" infrastructure as a utility library. - As with "cdc_subset" this involved minor Kconfig/kbuild tweaks, moving code from one file to another, and exporting a few functions. - This includes updates from Jamie Painter to add (and use) a new hook to handle the different maximum transfer sizes for rx and tx sides. - Also from Jamie, some bugfixes: * MDIO byteorder (to address some PPC media negotiation problems); * Force alignment at key spots when using ax88772 framing (on some embedded hardware, the network stack will break otherwise); * Address some link reset problems. It also makes this driver use the standard (5 seconds vs half second) control timeouts used elsewhere in USB; and wraps a few lines before the 80th column (which previously needed it). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 13 +- drivers/usb/net/Makefile | 1 + drivers/usb/net/asix.c | 948 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 936 +++------------------------------------------- drivers/usb/net/usbnet.h | 8 + 5 files changed, 1010 insertions(+), 896 deletions(-) create mode 100644 drivers/usb/net/asix.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 6399b43d41a..4fb51b998cc 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -202,23 +202,22 @@ config USB_CDCETHER IEEE 802 "local assignment" bit is set in the address, a "usbX" name is used instead. -comment "USB Network Adapters" - depends on USB_USBNET +comment "Drivers built using the usbnet core" -config USB_AX8817X - boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices" +config USB_NET_AX8817X + tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" depends on USB_USBNET && NET_ETHERNET select CRC32 select MII default y help This option adds support for ASIX AX88xxx based USB 2.0 - 10/100 Ethernet devices. + 10/100 Ethernet adapters. This driver should work with at least the following devices: * Aten UC210T * ASIX AX88172 - * Billionton Systems, USB2AR + * Billionton Systems, USB2AR * Buffalo LUA-U2-KTX * Corega FEther USB2-TX * D-Link DUB-E100 @@ -231,7 +230,7 @@ config USB_AX8817X * TrendNet TU2-ET100 This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. + what other networking devices you have in use. config USB_NET_CDC_SUBSET diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 23608ccc638..60dc91e5cdb 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o +obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_USBNET) += usbnet.o obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c new file mode 100644 index 00000000000..861f00a4375 --- /dev/null +++ b/drivers/usb/net/asix.c @@ -0,0 +1,948 @@ +/* + * ASIX AX8817X based USB 2.0 Ethernet Devices + * Copyright (C) 2003-2005 David Hollis + * Copyright (C) 2005 Phil Chang + * Copyright (c) 2002-2003 TiVo Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ + +#define AX_CMD_SET_SW_MII 0x06 +#define AX_CMD_READ_MII_REG 0x07 +#define AX_CMD_WRITE_MII_REG 0x08 +#define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_READ_EEPROM 0x0b +#define AX_CMD_WRITE_EEPROM 0x0c +#define AX_CMD_WRITE_ENABLE 0x0d +#define AX_CMD_WRITE_DISABLE 0x0e +#define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_READ_IPG012 0x11 +#define AX_CMD_WRITE_IPG0 0x12 +#define AX_CMD_WRITE_IPG1 0x13 +#define AX_CMD_WRITE_IPG2 0x14 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX_CMD_READ_NODE_ID 0x17 +#define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_READ_MEDIUM_STATUS 0x1a +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_READ_MONITOR_MODE 0x1c +#define AX_CMD_WRITE_MONITOR_MODE 0x1d +#define AX_CMD_WRITE_GPIOS 0x1f +#define AX_CMD_SW_RESET 0x20 +#define AX_CMD_SW_PHY_STATUS 0x21 +#define AX_CMD_SW_PHY_SELECT 0x22 +#define AX88772_CMD_READ_NODE_ID 0x13 + +#define AX_MONITOR_MODE 0x01 +#define AX_MONITOR_LINK 0x02 +#define AX_MONITOR_MAGIC 0x04 +#define AX_MONITOR_HSFS 0x10 + +/* AX88172 Medium Status Register values */ +#define AX_MEDIUM_FULL_DUPLEX 0x02 +#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 +#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 + +#define AX_MCAST_FILTER_SIZE 8 +#define AX_MAX_MCAST 64 + +#define AX_EEPROM_LEN 0x40 + +#define AX_SWRESET_CLEAR 0x00 +#define AX_SWRESET_RR 0x01 +#define AX_SWRESET_RT 0x02 +#define AX_SWRESET_PRTE 0x04 +#define AX_SWRESET_PRL 0x08 +#define AX_SWRESET_BZ 0x10 +#define AX_SWRESET_IPRL 0x20 +#define AX_SWRESET_IPPD 0x40 + +#define AX88772_IPG0_DEFAULT 0x15 +#define AX88772_IPG1_DEFAULT 0x0c +#define AX88772_IPG2_DEFAULT 0x12 + +#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 +#define AX88772_MEDIUM_RESERVED 0x0004 +#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 +#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 +#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 +#define AX88772_MEDIUM_RX_ENABLE 0x0100 +#define AX88772_MEDIUM_100MB 0x0200 +#define AX88772_MEDIUM_DEFAULT \ + (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ + AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ + AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) + +#define AX_EEPROM_MAGIC 0xdeadbeef + +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ +struct ax8817x_data { + u8 multi_filter[AX_MCAST_FILTER_SIZE]; +}; + +struct ax88172_int_data { + u16 res1; + u8 link; + u16 res2; + u8 status; + u16 res3; +} __attribute__ ((packed)); + +static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + return usb_control_msg( + dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + cmd, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + data, + size, + USB_CTRL_GET_TIMEOUT); +} + +static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + return usb_control_msg( + dev->udev, + usb_sndctrlpipe(dev->udev, 0), + cmd, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + data, + size, + USB_CTRL_SET_TIMEOUT); +} + +static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void ax8817x_status(struct usbnet *dev, struct urb *urb) +{ + struct ax88172_int_data *event; + int link; + + if (urb->actual_length < 8) + return; + + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + usbnet_defer_kevent (dev, EVENT_LINK_RESET ); + } else + netif_carrier_off(dev->net); + devdbg(dev, "ax8817x - Link Status is: %d", link); + } +} + +static void +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + struct usb_ctrlrequest *req; + int status; + struct urb *urb; + + if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { + devdbg(dev, "Error allocating URB in write_cmd_async!"); + return; + } + + if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { + deverr(dev, "Failed to allocate memory for control request"); + usb_free_urb(urb); + return; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + req->bRequest = cmd; + req->wValue = cpu_to_le16(value); + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + ax8817x_async_cmd_callback, req); + + if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + deverr(dev, "Error submitting the control message: status=%d", + status); + kfree(req); + usb_free_urb(urb); + } +} + +static void ax8817x_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + u8 rx_ctl = 0x8c; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x01; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > AX_MAX_MCAST) { + rx_ctl |= 0x02; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + struct dev_mc_list *mc_list = net->mc_list; + u32 crc_bits; + int i; + + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + AX_MCAST_FILTER_SIZE, data->multi_filter); + + rx_ctl |= 0x10; + } + + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); +} + +static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 res; + u8 buf[1]; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, + (__u16)loc, 2, (u16 *)&res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + + return res & 0xffff; +} + +/* same as above, but converts resulting value to cpu byte order */ +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) +{ + return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc)); +} + +static void +ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 res = val; + u8 buf[1]; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + (__u16)loc, 2, (u16 *)&res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); +} + +/* same as above, but converts new value to le16 byte order before writing */ +static void +ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) +{ + ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); +} + +static int ax88172_link_reset(struct usbnet *dev) +{ + u16 lpa; + u16 adv; + u16 res; + u8 mode; + + mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + res = mii_nway_result(lpa|adv); + if (res & LPA_DUPLEX) + mode |= AX_MEDIUM_FULL_DUPLEX; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + + return 0; +} + +static void +ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt; + + if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { + wolinfo->supported = 0; + wolinfo->wolopts = 0; + return; + } + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; + wolinfo->wolopts = 0; + if (opt & AX_MONITOR_MODE) { + if (opt & AX_MONITOR_LINK) + wolinfo->wolopts |= WAKE_PHY; + if (opt & AX_MONITOR_MAGIC) + wolinfo->wolopts |= WAKE_MAGIC; + } +} + +static int +ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt = 0; + u8 buf[1]; + + if (wolinfo->wolopts & WAKE_PHY) + opt |= AX_MONITOR_LINK; + if (wolinfo->wolopts & WAKE_MAGIC) + opt |= AX_MONITOR_MAGIC; + if (opt != 0) + opt |= AX_MONITOR_MODE; + + if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, + opt, 0, 0, &buf) < 0) + return -EINVAL; + + return 0; +} + +static int ax8817x_get_eeprom_len(struct net_device *net) +{ + return AX_EEPROM_LEN; +} + +static int ax8817x_get_eeprom(struct net_device *net, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct usbnet *dev = netdev_priv(net); + u16 *ebuf = (u16 *)data; + int i; + + /* Crude hack to ensure that we don't overwrite memory + * if an odd length is supplied + */ + if (eeprom->len % 2) + return -EINVAL; + + eeprom->magic = AX_EEPROM_MAGIC; + + /* ax8817x returns 2 bytes from eeprom on read */ + for (i=0; i < eeprom->len / 2; i++) { + if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, + eeprom->offset + i, 0, 2, &ebuf[i]) < 0) + return -EINVAL; + } + return 0; +} + +static void ax8817x_get_drvinfo (struct net_device *net, + struct ethtool_drvinfo *info) +{ + /* Inherit standard device info */ + usbnet_get_drvinfo(net, info); + info->eedump_len = 0x3e; +} + +static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + + return mii_ethtool_gset(&dev->mii,cmd); +} + +static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + + return mii_ethtool_sset(&dev->mii,cmd); +} + +/* We need to override some ethtool_ops so we require our + own structure so we don't interfere with other usbnet + devices that may be connected at the same time. */ +static struct ethtool_ops ax8817x_ethtool_ops = { + .get_drvinfo = ax8817x_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_wol = ax8817x_get_wol, + .set_wol = ax8817x_set_wol, + .get_eeprom_len = ax8817x_get_eeprom_len, + .get_eeprom = ax8817x_get_eeprom, + .get_settings = ax8817x_get_settings, + .set_settings = ax8817x_set_settings, +}; + +static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret = 0; + void *buf; + int i; + unsigned long gpio_bits = dev->driver_info->data; + + usbnet_get_endpoints(dev,intf); + + buf = kmalloc(ETH_ALEN, GFP_KERNEL); + if(!buf) { + ret = -ENOMEM; + goto out1; + } + + /* Toggle the GPIOs in a manufacturer/model specific way */ + for (i = 2; i >= 0; i--) { + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + (gpio_bits >> (i * 8)) & 0xff, 0, 0, + buf)) < 0) + goto out2; + msleep(5); + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + 0x80, 0, 0, buf)) < 0) { + dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); + goto out2; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, + 0, 0, 6, buf)) < 0) { + dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); + goto out2; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); + goto out2; + } else if (ret < 2) { + /* this should always return 2 bytes */ + dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", + ret); + ret = -EIO; + goto out2; + } + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read; + dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = *((u8 *)buf + 1); + dev->net->do_ioctl = ax8817x_ioctl; + + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->ethtool_ops = &ax8817x_ethtool_ops; + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + mii_nway_restart(&dev->mii); + + return 0; +out2: + kfree(buf); +out1: + return ret; +} + +static struct ethtool_ops ax88772_ethtool_ops = { + .get_drvinfo = ax8817x_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_wol = ax8817x_get_wol, + .set_wol = ax8817x_set_wol, + .get_eeprom_len = ax8817x_get_eeprom_len, + .get_eeprom = ax8817x_get_eeprom, + .get_settings = ax8817x_get_settings, + .set_settings = ax8817x_set_settings, +}; + +static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + void *buf; + + usbnet_get_endpoints(dev,intf); + + buf = kmalloc(6, GFP_KERNEL); + if(!buf) { + dbg ("Cannot allocate memory for buffer"); + ret = -ENOMEM; + goto out1; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + 0x00B0, 0, 0, buf)) < 0) + goto out2; + + msleep(5); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + 0x0001, 0, 0, buf)) < 0) { + dbg("Select PHY #1 failed: %d", ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, + 0, 0, buf)) < 0) { + dbg("Failed to power down internal PHY: %d", ret); + goto out2; + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, + 0, 0, buf)) < 0) { + dbg("Failed to perform software reset: %d", ret); + goto out2; + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | AX_SWRESET_PRL, + 0, 0, buf)) < 0) { + dbg("Failed to set Internal/External PHY reset control: %d", + ret); + goto out2; + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + 0x0000, 0, 0, buf)) < 0) { + dbg("Failed to reset RX_CTL: %d", ret); + goto out2; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, + 0, 0, ETH_ALEN, buf)) < 0) { + dbg("Failed to read MAC address: %d", ret); + goto out2; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, + 0, 0, 0, buf)) < 0) { + dbg("Enabling software MII failed: %d", ret); + goto out2; + } + + if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, + 0x0010, 2, 2, buf)) < 0) + || (*((u16 *)buf) != 0x003b)) { + dbg("Read PHY register 2 must be 0x3b00: %d", ret); + goto out2; + } + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read; + dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.phy_id_mask = 0xff; + dev->mii.reg_num_mask = 0xff; + dev->net->do_ioctl = ax8817x_ioctl; + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + dbg("Error reading PHY ID: %02x", ret); + goto out2; + } else if (ret < 2) { + /* this should always return 2 bytes */ + dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", + ret); + ret = -EIO; + goto out2; + } + dev->mii.phy_id = *((u8 *)buf + 1); + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, + 0, 0, buf)) < 0) { + dbg("Set external PHY reset pin level: %d", ret); + goto out2; + } + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | AX_SWRESET_PRL, + 0, 0, buf)) < 0) { + dbg("Set Internal/External PHY reset control: %d", ret); + goto out2; + } + msleep(150); + + + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->ethtool_ops = &ax88772_ethtool_ops; + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA); + mii_nway_restart(&dev->mii); + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { + dbg("Write medium mode register: %d", ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, + AX88772_IPG2_DEFAULT, 0, buf)) < 0) { + dbg("Write IPG,IPG1,IPG2 failed: %d", ret); + goto out2; + } + if ((ret = + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { + dbg("Failed to set hardware MII: %02x", ret); + goto out2; + } + + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ + if ((ret = + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, + buf)) < 0) { + dbg("Reset RX_CTL failed: %d", ret); + goto out2; + } + + kfree(buf); + + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ + if (dev->driver_info->flags & FLAG_FRAMING_AX) { + /* hard_mtu is still the default - the device does not support + jumbo eth frames */ + dev->rx_urb_size = 2048; + } + + return 0; + +out2: + kfree(buf); +out1: + return ret; +} + +static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 *head; + u32 header; + char *packet; + struct sk_buff *ax_skb; + u16 size; + + head = (u8 *) skb->data; + memcpy(&header, head, sizeof(header)); + le32_to_cpus(&header); + packet = head + sizeof(header); + + skb_pull(skb, 4); + + while (skb->len > 0) { + if ((short)(header & 0x0000ffff) != + ~((short)((header & 0xffff0000) >> 16))) { + devdbg(dev,"header length data is error"); + } + /* get the packet length */ + size = (u16) (header & 0x0000ffff); + + if ((skb->len) - ((size + 1) & 0xfffe) == 0) + return 2; + if (size > ETH_FRAME_LEN) { + devdbg(dev,"invalid rx length %d", size); + return 0; + } + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (ax_skb) { + ax_skb->len = size; + ax_skb->data = packet; + ax_skb->tail = packet + size; + usbnet_skb_return(dev, ax_skb); + } else { + return 0; + } + + skb_pull(skb, (size + 1) & 0xfffe); + + if (skb->len == 0) + break; + + head = (u8 *) skb->data; + memcpy(&header, head, sizeof(header)); + le32_to_cpus(&header); + packet = head + sizeof(header); + skb_pull(skb, 4); + } + + if (skb->len < 0) { + devdbg(dev,"invalid rx length %d", skb->len); + return 0; + } + return 1; +} + +static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + unsigned flags) +{ + int padlen; + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + u32 packet_len; + u32 padbytes = 0xffff0000; + + padlen = ((skb->len + 4) % 512) ? 0 : 4; + + if ((!skb_cloned(skb)) + && ((headroom + tailroom) >= (4 + padlen))) { + if ((headroom < 4) || (tailroom < padlen)) { + skb->data = memmove(skb->head + 4, skb->data, skb->len); + skb->tail = skb->data + skb->len; + } + } else { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, 4, padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + memcpy(skb->data, &packet_len, sizeof(packet_len)); + + if ((skb->len % 512) == 0) { + memcpy( skb->tail, &padbytes, sizeof(padbytes)); + skb_put(skb, sizeof(padbytes)); + } + return skb; +} + +static int ax88772_link_reset(struct usbnet *dev) +{ + u16 lpa; + u16 adv; + u16 res; + u16 mode; + + mode = AX88772_MEDIUM_DEFAULT; + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + res = mii_nway_result(lpa|adv); + + if ((res & LPA_DUPLEX) == 0) + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; + if ((res & LPA_100) == 0) + mode &= ~AX88772_MEDIUM_100MB; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + + return 0; +} + +static const struct driver_info ax8817x_info = { + .description = "ASIX AX8817x USB 2.0 Ethernet", + .bind = ax8817x_bind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, + .flags = FLAG_ETHER, + .data = 0x00130103, +}; + +static const struct driver_info dlink_dub_e100_info = { + .description = "DLink DUB-E100 USB Ethernet", + .bind = ax8817x_bind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, + .flags = FLAG_ETHER, + .data = 0x009f9d9f, +}; + +static const struct driver_info netgear_fa120_info = { + .description = "Netgear FA-120 USB Ethernet", + .bind = ax8817x_bind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, + .flags = FLAG_ETHER, + .data = 0x00130103, +}; + +static const struct driver_info hawking_uf200_info = { + .description = "Hawking UF200 USB Ethernet", + .bind = ax8817x_bind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, + .flags = FLAG_ETHER, + .data = 0x001f1d1f, +}; + +static const struct driver_info ax88772_info = { + .description = "ASIX AX88772 USB 2.0 Ethernet", + .bind = ax88772_bind, + .status = ax8817x_status, + .link_reset = ax88772_link_reset, + .reset = ax88772_link_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, + .data = 0x00130103, +}; + +static const struct usb_device_id products [] = { +{ + // Linksys USB200M + USB_DEVICE (0x077b, 0x2226), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Netgear FA120 + USB_DEVICE (0x0846, 0x1040), + .driver_info = (unsigned long) &netgear_fa120_info, +}, { + // DLink DUB-E100 + USB_DEVICE (0x2001, 0x1a00), + .driver_info = (unsigned long) &dlink_dub_e100_info, +}, { + // Intellinet, ST Lab USB Ethernet + USB_DEVICE (0x0b95, 0x1720), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Hawking UF200, TrendNet TU2-ET100 + USB_DEVICE (0x07b8, 0x420a), + .driver_info = (unsigned long) &hawking_uf200_info, +}, { + // Billionton Systems, USB2AR + USB_DEVICE (0x08dd, 0x90ff), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // ATEN UC210T + USB_DEVICE (0x0557, 0x2009), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Buffalo LUA-U2-KTX + USB_DEVICE (0x0411, 0x003d), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" + USB_DEVICE (0x6189, 0x182d), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // corega FEther USB2-TX + USB_DEVICE (0x07aa, 0x0017), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Surecom EP-1427X-2 + USB_DEVICE (0x1189, 0x0893), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // goodway corp usb gwusb2e + USB_DEVICE (0x1631, 0x6200), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // ASIX AX88772 10/100 + USB_DEVICE (0x0b95, 0x7720), + .driver_info = (unsigned long) &ax88772_info, +}, + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver asix_driver = { + .owner = THIS_MODULE, + .name = "asix", + .id_table = products, + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, +}; + +static int __init asix_init(void) +{ + return usb_register(&asix_driver); +} +module_init(asix_init); + +static void __exit asix_exit(void) +{ + usb_deregister(&asix_driver); +} +module_exit(asix_exit); + +MODULE_AUTHOR("David Hollis"); +MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 57b41fbd3bb..99a48814014 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -3,8 +3,6 @@ * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2002 Pavel Machek * Copyright (C) 2003-2005 David Hollis - * Copyright (C) 2005 Phil Chang - * Copyright (c) 2002-2003 TiVo Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -156,9 +154,6 @@ #define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) #define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) -/* packets are always ethernet, sometimes wrapped in other framing */ -#define MIN_PACKET sizeof(struct ethhdr) - // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) @@ -186,11 +181,7 @@ MODULE_PARM_DESC (msg_level, "Override default message level"); /*-------------------------------------------------------------------------*/ -static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); static u32 usbnet_get_link (struct net_device *); -static u32 usbnet_get_msglevel (struct net_device *); -static void usbnet_set_msglevel (struct net_device *, u32); -static void defer_kevent (struct usbnet *, int); /* mostly for PDA style devices, which are always connected if present */ static int always_connected (struct usbnet *dev) @@ -199,8 +190,7 @@ static int always_connected (struct usbnet *dev) } /* handles CDC Ethernet and many other network "bulk data" interfaces */ -static int -get_endpoints (struct usbnet *dev, struct usb_interface *intf) +int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt = NULL; @@ -264,6 +254,7 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf) dev->status = status; return 0; } +EXPORT_SYMBOL_GPL(usbnet_get_endpoints); static void intr_complete (struct urb *urb, struct pt_regs *regs); @@ -303,7 +294,11 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) return 0; } -static void skb_return (struct usbnet *dev, struct sk_buff *skb) +/* Passes this packet up the stack, updating its accounting. + * Some link protocols batch packets, so their rx_fixup paths + * can return clones as well as just modify the original skb. + */ +void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { int status; @@ -320,784 +315,7 @@ static void skb_return (struct usbnet *dev, struct sk_buff *skb) if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) devdbg (dev, "netif_rx status %d", status); } - - -#ifdef CONFIG_USB_AX8817X -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - -#define HAVE_HARDWARE -#define NEED_MII - -#include - -#define AX_CMD_SET_SW_MII 0x06 -#define AX_CMD_READ_MII_REG 0x07 -#define AX_CMD_WRITE_MII_REG 0x08 -#define AX_CMD_SET_HW_MII 0x0a -#define AX_CMD_READ_EEPROM 0x0b -#define AX_CMD_WRITE_EEPROM 0x0c -#define AX_CMD_WRITE_ENABLE 0x0d -#define AX_CMD_WRITE_DISABLE 0x0e -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_READ_IPG012 0x11 -#define AX_CMD_WRITE_IPG0 0x12 -#define AX_CMD_WRITE_IPG1 0x13 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_READ_MEDIUM_STATUS 0x1a -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_READ_MONITOR_MODE 0x1c -#define AX_CMD_WRITE_MONITOR_MODE 0x1d -#define AX_CMD_WRITE_GPIOS 0x1f -#define AX_CMD_SW_RESET 0x20 -#define AX_CMD_SW_PHY_STATUS 0x21 -#define AX_CMD_SW_PHY_SELECT 0x22 -#define AX88772_CMD_READ_NODE_ID 0x13 - -#define AX_MONITOR_MODE 0x01 -#define AX_MONITOR_LINK 0x02 -#define AX_MONITOR_MAGIC 0x04 -#define AX_MONITOR_HSFS 0x10 - -/* AX88172 Medium Status Register values */ -#define AX_MEDIUM_FULL_DUPLEX 0x02 -#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 -#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_EEPROM_LEN 0x40 - -#define AX_SWRESET_CLEAR 0x00 -#define AX_SWRESET_RR 0x01 -#define AX_SWRESET_RT 0x02 -#define AX_SWRESET_PRTE 0x04 -#define AX_SWRESET_PRL 0x08 -#define AX_SWRESET_BZ 0x10 -#define AX_SWRESET_IPRL 0x20 -#define AX_SWRESET_IPPD 0x40 - -#define AX88772_IPG0_DEFAULT 0x15 -#define AX88772_IPG1_DEFAULT 0x0c -#define AX88772_IPG2_DEFAULT 0x12 - -#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 -#define AX88772_MEDIUM_RESERVED 0x0004 -#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 -#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 -#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 -#define AX88772_MEDIUM_RX_ENABLE 0x0100 -#define AX88772_MEDIUM_100MB 0x0200 -#define AX88772_MEDIUM_DEFAULT \ - (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ - AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ - AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) - -#define AX_EEPROM_MAGIC 0xdeadbeef - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct ax8817x_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; -}; - -struct ax88172_int_data { - u16 res1; - u8 link; - u16 res2; - u8 status; - u16 res3; -} __attribute__ ((packed)); - -static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - return usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - data, - size, - CONTROL_TIMEOUT_MS); -} - -static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - return usb_control_msg( - dev->udev, - usb_sndctrlpipe(dev->udev, 0), - cmd, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - data, - size, - CONTROL_TIMEOUT_MS); -} - -static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - - if (urb->status < 0) - printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", - urb->status); - - kfree(req); - usb_free_urb(urb); -} - -static void ax8817x_status(struct usbnet *dev, struct urb *urb) -{ - struct ax88172_int_data *event; - int link; - - if (urb->actual_length < 8) - return; - - event = urb->transfer_buffer; - link = event->link & 0x01; - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); - devdbg(dev, "ax8817x - Link Status is: %d", link); - } -} - -static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - struct usb_ctrlrequest *req; - int status; - struct urb *urb; - - if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { - devdbg(dev, "Error allocating URB in write_cmd_async!"); - return; - } - - if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { - deverr(dev, "Failed to allocate memory for control request"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = cmd; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(index); - req->wLength = cpu_to_le16(size); - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, size, - ax8817x_async_cmd_callback, req); - - if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - deverr(dev, "Error submitting the control message: status=%d", status); - kfree(req); - usb_free_urb(urb); - } -} - -static void ax8817x_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; - u8 rx_ctl = 0x8c; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (net->mc_count == 0) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct dev_mc_list *mc_list = net->mc_list; - u32 crc_bits; - int i; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { - crc_bits = - ether_crc(ETH_ALEN, - mc_list->dmi_addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - mc_list = mc_list->next; - } - - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= 0x10; - } - - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res; - u8 buf[1]; - - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); - - return res & 0xffff; -} - -static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - u16 res = val; - u8 buf[1]; - - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); -} - -static int ax88172_link_reset(struct usbnet *dev) -{ - u16 lpa; - u8 mode; - - mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; - lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); - if (lpa & LPA_DUPLEX) - mode |= AX_MEDIUM_FULL_DUPLEX; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - - return 0; -} - -static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt; - - if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { - wolinfo->supported = 0; - wolinfo->wolopts = 0; - return; - } - wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = 0; - if (opt & AX_MONITOR_MODE) { - if (opt & AX_MONITOR_LINK) - wolinfo->wolopts |= WAKE_PHY; - if (opt & AX_MONITOR_MAGIC) - wolinfo->wolopts |= WAKE_MAGIC; - } -} - -static int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt = 0; - u8 buf[1]; - - if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; - if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - if (opt != 0) - opt |= AX_MONITOR_MODE; - - if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, &buf) < 0) - return -EINVAL; - - return 0; -} - -static int ax8817x_get_eeprom_len(struct net_device *net) -{ - return AX_EEPROM_LEN; -} - -static int ax8817x_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct usbnet *dev = netdev_priv(net); - u16 *ebuf = (u16 *)data; - int i; - - /* Crude hack to ensure that we don't overwrite memory - * if an odd length is supplied - */ - if (eeprom->len % 2) - return -EINVAL; - - eeprom->magic = AX_EEPROM_MAGIC; - - /* ax8817x returns 2 bytes from eeprom on read */ - for (i=0; i < eeprom->len / 2; i++) { - if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static void ax8817x_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) -{ - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - info->eedump_len = 0x3e; -} - -static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_gset(&dev->mii,cmd); -} - -static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_sset(&dev->mii,cmd); -} - -/* We need to override some ethtool_ops so we require our - own structure so we don't interfere with other usbnet - devices that may be connected at the same time. */ -static struct ethtool_ops ax8817x_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, -}; - -static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - void *buf; - int i; - unsigned long gpio_bits = dev->driver_info->data; - - get_endpoints(dev,intf); - - buf = kmalloc(ETH_ALEN, GFP_KERNEL); - if(!buf) { - ret = -ENOMEM; - goto out1; - } - - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, - buf)) < 0) - goto out2; - msleep(5); - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { - dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); - goto out2; - } - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out2; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { - dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); - ret = -EIO; - goto out2; - } - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = *((u8 *)buf + 1); - - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax8817x_ethtool_ops; - - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - mii_nway_restart(&dev->mii); - - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* REVISIT: adjust hard_header_len too */ - dev->hard_mtu = 2048; - } - - return 0; -out2: - kfree(buf); -out1: - return ret; -} - -static struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, -}; - -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - void *buf; - - get_endpoints(dev,intf); - - buf = kmalloc(6, GFP_KERNEL); - if(!buf) { - dbg ("Cannot allocate memory for buffer"); - ret = -ENOMEM; - goto out1; - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, - 0x00B0, 0, 0, buf)) < 0) - goto out2; - - msleep(5); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out2; - } - - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { - dbg("Failed to power down internal PHY: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { - dbg("Failed to perform software reset: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Failed to set Internal/External PHY reset control: %d", ret); - goto out2; - } - - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, - buf)) < 0) { - dbg("Failed to reset RX_CTL: %d", ret); - goto out2; - } - - /* Get the MAC address */ - memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { - dbg("Failed to read MAC address: %d", ret); - goto out2; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { - dbg("Enabling software MII failed: %d", ret); - goto out2; - } - - if (((ret = - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) - || (*((u16 *)buf) != 0x003b)) { - dbg("Read PHY register 2 must be 0x3b00: %d", ret); - goto out2; - } - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; - dev->mii.phy_id_mask = 0xff; - dev->mii.reg_num_mask = 0xff; - - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { - dbg("Error reading PHY ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - dev->mii.phy_id = *((u8 *)buf + 1); - - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Set external PHY reset pin level: %d", ret); - goto out2; - } - msleep(150); - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { - dbg("Set Internal/External PHY reset control: %d", ret); - goto out2; - } - msleep(150); - - - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); - mii_nway_restart(&dev->mii); - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { - dbg("Write medium mode register: %d", ret); - goto out2; - } - - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out2; - } - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to set hardware MII: %02x", ret); - goto out2; - } - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, - buf)) < 0) { - dbg("Reset RX_CTL failed: %d", ret); - goto out2; - } - - kfree(buf); - - return 0; - -out2: - kfree(buf); -out1: - return ret; -} - -static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - u32 *header; - char *packet; - struct sk_buff *ax_skb; - u16 size; - - header = (u32 *) skb->data; - le32_to_cpus(header); - packet = (char *)(header + 1); - - skb_pull(skb, 4); - - while (skb->len > 0) { - if ((short)(*header & 0x0000ffff) != - ~((short)((*header & 0xffff0000) >> 16))) { - devdbg(dev,"header length data is error"); - } - /* get the packet length */ - size = (u16) (*header & 0x0000ffff); - - if ((skb->len) - ((size + 1) & 0xfffe) == 0) - return 2; - if (size > ETH_FRAME_LEN) { - devdbg(dev,"invalid rx length %d", size); - return 0; - } - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (ax_skb) { - ax_skb->len = size; - ax_skb->data = packet; - ax_skb->tail = packet + size; - skb_return(dev, ax_skb); - } else { - return 0; - } - - skb_pull(skb, (size + 1) & 0xfffe); - - if (skb->len == 0) - break; - - header = (u32 *) skb->data; - le32_to_cpus(header); - packet = (char *)(header + 1); - skb_pull(skb, 4); - } - - if (skb->len < 0) { - devdbg(dev,"invalid rx length %d", skb->len); - return 0; - } - return 1; -} - -static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - unsigned flags) -{ - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 *packet_len; - u32 *padbytes_ptr; - - padlen = ((skb->len + 4) % 512) ? 0 : 4; - - if ((!skb_cloned(skb)) - && ((headroom + tailroom) >= (4 + padlen))) { - if ((headroom < 4) || (tailroom < padlen)) { - skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb->tail = skb->data + skb->len; - } - } else { - struct sk_buff *skb2; - skb2 = skb_copy_expand(skb, 4, padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - packet_len = (u32 *) skb_push(skb, 4); - - packet_len = (u32 *) skb->data; - *packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); - - if ((skb->len % 512) == 0) { - padbytes_ptr = (u32 *) skb->tail; - *padbytes_ptr = 0xffff0000; - skb_put(skb, padlen); - } - return skb; -} - -static int ax88772_link_reset(struct usbnet *dev) -{ - u16 lpa; - u16 mode; - - mode = AX88772_MEDIUM_DEFAULT; - lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); - - if ((lpa & LPA_DUPLEX) == 0) - mode &= ~AX88772_MEDIUM_FULL_DUPLEX; - if ((lpa & LPA_100) == 0) - mode &= ~AX88772_MEDIUM_100MB; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - - return 0; -} - -static const struct driver_info ax8817x_info = { - .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x00130103, -}; - -static const struct driver_info dlink_dub_e100_info = { - .description = "DLink DUB-E100 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x009f9d9f, -}; - -static const struct driver_info netgear_fa120_info = { - .description = "Netgear FA-120 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x00130103, -}; - -static const struct driver_info hawking_uf200_info = { - .description = "Hawking UF200 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER, - .data = 0x001f1d1f, -}; - -static const struct driver_info ax88772_info = { - .description = "ASIX AX88772 USB 2.0 Ethernet", - .bind = ax88772_bind, - .status = ax8817x_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_link_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX, - .rx_fixup = ax88772_rx_fixup, - .tx_fixup = ax88772_tx_fixup, - .data = 0x00130103, -}; - -#endif /* CONFIG_USB_AX8817X */ - +EXPORT_SYMBOL_GPL(usbnet_skb_return); /*------------------------------------------------------------------------- @@ -1284,7 +502,7 @@ next_desc: status = usb_driver_claim_interface (&usbnet_driver, info->data, dev); if (status < 0) return status; - status = get_endpoints (dev, info->data); + status = usbnet_get_endpoints (dev, info->data); if (status < 0) { /* ensure immediate exit from usbnet_disconnect */ usb_set_intfdata(info->data, NULL); @@ -1721,7 +939,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) // copy the packet data to the new skb memcpy(skb_put(gl_skb, size), packet->packet_data, size); - skb_return (dev, gl_skb); + usbnet_skb_return (dev, gl_skb); } // advance to the next packet @@ -2616,7 +1834,7 @@ next_desc: * bother to make it unique. Likewise there's no point in tracking * of the CDC event notifications. */ - return get_endpoints (dev, intf); + return usbnet_get_endpoints (dev, intf); bad_desc: dev_info (&dev->udev->dev, "unsupported MDLM descriptors\n"); @@ -2694,7 +1912,7 @@ static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_hea * NOTE: annoying asymmetry: if it's active, schedule_work() fails, * but tasklet_schedule() doesn't. hope the failure is rare. */ -static void defer_kevent (struct usbnet *dev, int work) +void usbnet_defer_kevent (struct usbnet *dev, int work) { set_bit (work, &dev->flags); if (!schedule_work (&dev->kevent)) @@ -2702,6 +1920,7 @@ static void defer_kevent (struct usbnet *dev, int work) else devdbg (dev, "kevent %d scheduled", work); } +EXPORT_SYMBOL_GPL(usbnet_defer_kevent); /*-------------------------------------------------------------------------*/ @@ -2713,14 +1932,12 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) struct skb_data *entry; int retval = 0; unsigned long lockflags; - size_t size; + size_t size = dev->rx_urb_size; - size = max(dev->net->hard_header_len + dev->net->mtu, - (unsigned)ETH_FRAME_LEN); if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { if (netif_msg_rx_err (dev)) devdbg (dev, "no rx skb"); - defer_kevent (dev, EVENT_RX_MEMORY); + usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return; } @@ -2742,10 +1959,10 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) && !test_bit (EVENT_RX_HALT, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: - defer_kevent (dev, EVENT_RX_HALT); + usbnet_defer_kevent (dev, EVENT_RX_HALT); break; case -ENOMEM: - defer_kevent (dev, EVENT_RX_MEMORY); + usbnet_defer_kevent (dev, EVENT_RX_MEMORY); break; case -ENODEV: if (netif_msg_ifdown (dev)) @@ -2783,7 +2000,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) // else network stack removes extra byte if we forced a short packet if (skb->len) - skb_return (dev, skb); + usbnet_skb_return (dev, skb); else { if (netif_msg_rx_err (dev)) devdbg (dev, "drop"); @@ -2824,7 +2041,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) // storm, recovering as needed. case -EPIPE: dev->stats.rx_errors++; - defer_kevent (dev, EVENT_RX_HALT); + usbnet_defer_kevent (dev, EVENT_RX_HALT); // FALLTHROUGH // software-driven interface shutdown @@ -3066,16 +2283,22 @@ done: /*-------------------------------------------------------------------------*/ -static void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +/* ethtool methods; minidrivers may need to add some more, but + * they'll probably want to use this base set. + */ + +void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { struct usbnet *dev = netdev_priv(net); + /* REVISIT don't always return "usbnet" */ strncpy (info->driver, driver_name, sizeof info->driver); strncpy (info->version, DRIVER_VERSION, sizeof info->version); strncpy (info->fw_version, dev->driver_info->description, sizeof info->fw_version); usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); } +EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); static u32 usbnet_get_link (struct net_device *net) { @@ -3089,32 +2312,29 @@ static u32 usbnet_get_link (struct net_device *net) return 1; } -static u32 usbnet_get_msglevel (struct net_device *net) +u32 usbnet_get_msglevel (struct net_device *net) { struct usbnet *dev = netdev_priv(net); return dev->msg_enable; } +EXPORT_SYMBOL_GPL(usbnet_get_msglevel); -static void usbnet_set_msglevel (struct net_device *net, u32 level) +void usbnet_set_msglevel (struct net_device *net, u32 level) { struct usbnet *dev = netdev_priv(net); dev->msg_enable = level; } +EXPORT_SYMBOL_GPL(usbnet_set_msglevel); -static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) -{ -#ifdef NEED_MII - { - struct usbnet *dev = netdev_priv(net); - - if (dev->mii.mdio_read != NULL && dev->mii.mdio_write != NULL) - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); - } -#endif - return -EOPNOTSUPP; -} +/* drivers may override default ethtool_ops in their bind() routine */ +static struct ethtool_ops usbnet_ethtool_ops = { + .get_drvinfo = usbnet_get_drvinfo, + .get_link = usbnet_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, +}; /*-------------------------------------------------------------------------*/ @@ -3209,7 +2429,7 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs) switch (urb->status) { case -EPIPE: - defer_kevent (dev, EVENT_TX_HALT); + usbnet_defer_kevent (dev, EVENT_TX_HALT); break; /* software-driven interface shutdown */ @@ -3339,7 +2559,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue (net); - defer_kevent (dev, EVENT_TX_HALT); + usbnet_defer_kevent (dev, EVENT_TX_HALT); break; default: if (netif_msg_tx_err (dev)) @@ -3478,8 +2698,6 @@ EXPORT_SYMBOL_GPL(usbnet_disconnect); /*-------------------------------------------------------------------------*/ -static struct ethtool_ops usbnet_ethtool_ops; - // precondition: never called in_interrupt int @@ -3530,8 +2748,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->net = net; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); - dev->hard_mtu = net->mtu + net->hard_header_len; + /* rx and tx sides can use different message sizes; + * bind() should set rx_urb_size in that case. + */ + dev->hard_mtu = net->mtu + net->hard_header_len; #if 0 // dma_supported() is deeply broken on almost all architectures // possible with some EHCI controllers @@ -3546,7 +2767,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) net->stop = usbnet_stop; net->watchdog_timeo = TX_TIMEOUT_JIFFIES; net->tx_timeout = usbnet_tx_timeout; - net->do_ioctl = usbnet_ioctl; net->ethtool_ops = &usbnet_ethtool_ops; // allow device-specific bind/init procedures @@ -3563,8 +2783,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) /* maybe the remote can't receive an Ethernet MTU */ if (net->mtu > (dev->hard_mtu - net->hard_header_len)) net->mtu = dev->hard_mtu - net->hard_header_len; - } else if (!info->in || info->out) - status = get_endpoints (dev, udev); + } else if (!info->in || !info->out) + status = usbnet_get_endpoints (dev, udev); else { dev->in = usb_rcvbulkpipe (xdev, info->in); dev->out = usb_sndbulkpipe (xdev, info->out); @@ -3581,6 +2801,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status < 0) goto out1; + if (!dev->rx_urb_size) + dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); SET_NETDEV_DEV(net, &udev->dev); @@ -3662,62 +2884,6 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static const struct usb_device_id products [] = { -#ifdef CONFIG_USB_AX8817X -{ - // Linksys USB200M - USB_DEVICE (0x077b, 0x2226), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Netgear FA120 - USB_DEVICE (0x0846, 0x1040), - .driver_info = (unsigned long) &netgear_fa120_info, -}, { - // DLink DUB-E100 - USB_DEVICE (0x2001, 0x1a00), - .driver_info = (unsigned long) &dlink_dub_e100_info, -}, { - // Intellinet, ST Lab USB Ethernet - USB_DEVICE (0x0b95, 0x1720), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Hawking UF200, TrendNet TU2-ET100 - USB_DEVICE (0x07b8, 0x420a), - .driver_info = (unsigned long) &hawking_uf200_info, -}, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ATEN UC210T - USB_DEVICE (0x0557, 0x2009), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-KTX - USB_DEVICE (0x0411, 0x003d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" - USB_DEVICE (0x6189, 0x182d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // corega FEther USB2-TX - USB_DEVICE (0x07aa, 0x0017), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Surecom EP-1427X-2 - USB_DEVICE (0x1189, 0x0893), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // goodway corp usb gwusb2e - USB_DEVICE (0x1631, 0x6200), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, -#endif - #ifdef CONFIG_USB_GENESYS { USB_DEVICE (0x05e3, 0x0502), // GL620USB-A @@ -3881,14 +3047,6 @@ static struct usb_driver usbnet_driver = { .resume = usbnet_resume, }; -/* Default ethtool_ops assigned. Devices can override in their bind() routine */ -static struct ethtool_ops usbnet_ethtool_ops = { - .get_drvinfo = usbnet_get_drvinfo, - .get_link = usbnet_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, -}; - /*-------------------------------------------------------------------------*/ static int __init usbnet_init(void) diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index d903b461756..21b5feb54fc 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -44,6 +44,7 @@ struct usbnet { unsigned long data [5]; u32 xid; u32 hard_mtu; /* count any extra framing */ + size_t rx_urb_size; /* size for rx urbs */ struct mii_if_info mii; /* various kinds of pending driver work */ @@ -140,6 +141,13 @@ struct skb_data { /* skb->cb is one of these */ }; +extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); +extern void usbnet_defer_kevent (struct usbnet *, int); +extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); + +extern u32 usbnet_get_msglevel (struct net_device *); +extern void usbnet_set_msglevel (struct net_device *, u32); +extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); /* messaging support includes the interface name, so it must not be * used before it has one ... notably, in minidriver bind() calls. -- cgit v1.2.3-70-g09d2 From 904813cd8a0b334189da285bb05af0b18b062502 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:53:26 -0700 Subject: [PATCH] USB: usbnet (4/9) module for net1080 cables As with the "cdc_subset" and "asix" drivers, this just moves the net1080 support into its one driver module. In this case there's a small bit of extra cleanup involved, moving some funky framing logic into the tx_fixup() routine (resolving a long overdue FIXME). Minor historical note: "usbnet" started out as "net1080", then got generalized to make it easier for other network drivers to reuse the urb queueing and fault management code here. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 18 +- drivers/usb/net/Makefile | 1 + drivers/usb/net/net1080.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 571 ------------------------------------------ 4 files changed, 632 insertions(+), 580 deletions(-) create mode 100644 drivers/usb/net/net1080.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 4fb51b998cc..0aa8637e5ff 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -138,15 +138,6 @@ config USB_GENESYS Note that the half-duplex "GL620USB" is not supported. -config USB_NET1080 - boolean "NetChip 1080 based cables (Laplink, ...)" - default y - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable based - on this design: one NetChip 1080 chips and supporting logic, - supporting LEDs that indicate traffic - config USB_PL2301 boolean "Prolific PL-2301/2302 based cables" default y @@ -233,6 +224,15 @@ config USB_NET_AX8817X what other networking devices you have in use. +config USB_NET_NET1080 + tristate "NetChip 1080 based cables (Laplink, ...)" + default y + depends on USB_USBNET + help + Choose this option if you're using a host-to-host cable based + on this design: one NetChip 1080 chip and supporting logic, + optionally with LEDs that indicate traffic + config USB_NET_CDC_SUBSET tristate "Simple USB Network Links (CDC Ethernet subset)" depends on USB_USBNET diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 60dc91e5cdb..14d554080aa 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o +obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_USBNET) += usbnet.o obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c new file mode 100644 index 00000000000..a4309c4a491 --- /dev/null +++ b/drivers/usb/net/net1080.c @@ -0,0 +1,622 @@ +/* + * Net1080 based USB host-to-host cables + * Copyright (C) 2000-2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usbnet.h" + + +/* + * Netchip 1080 driver ... http://www.netchip.com + * (Sept 2004: End-of-life announcement has been sent.) + * Used in (some) LapLink cables + */ + +#define frame_errors data[1] + +/* + * NetChip framing of ethernet packets, supporting additional error + * checks for links that may drop bulk packets from inside messages. + * Odd USB length == always short read for last usb packet. + * - nc_header + * - Ethernet header (14 bytes) + * - payload + * - (optional padding byte, if needed so length becomes odd) + * - nc_trailer + * + * This framing is to be avoided for non-NetChip devices. + */ + +struct nc_header { // packed: + __le16 hdr_len; // sizeof nc_header (LE, all) + __le16 packet_len; // payload size (including ethhdr) + __le16 packet_id; // detects dropped packets +#define MIN_HEADER 6 + + // all else is optional, and must start with: + // __le16 vendorId; // from usb-if + // __le16 productId; +} __attribute__((__packed__)); + +#define PAD_BYTE ((unsigned char)0xAC) + +struct nc_trailer { + __le16 packet_id; +} __attribute__((__packed__)); + +// packets may use FLAG_FRAMING_NC and optional pad +#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ + + sizeof (struct ethhdr) \ + + (mtu) \ + + 1 \ + + sizeof (struct nc_trailer)) + +#define MIN_FRAMED FRAMED_SIZE(0) + +/* packets _could_ be up to 64KB... */ +#define NC_MAX_PACKET 32767 + + +/* + * Zero means no timeout; else, how long a 64 byte bulk packet may be queued + * before the hardware drops it. If that's done, the driver will need to + * frame network packets to guard against the dropped USB packets. The win32 + * driver sets this for both sides of the link. + */ +#define NC_READ_TTL_MS ((u8)255) // ms + +/* + * We ignore most registers and EEPROM contents. + */ +#define REG_USBCTL ((u8)0x04) +#define REG_TTL ((u8)0x10) +#define REG_STATUS ((u8)0x11) + +/* + * Vendor specific requests to read/write data + */ +#define REQUEST_REGISTER ((u8)0x10) +#define REQUEST_EEPROM ((u8)0x11) + +static int +nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) +{ + int status = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, regnum, + retval_ptr, sizeof *retval_ptr, + USB_CTRL_GET_TIMEOUT); + if (status > 0) + status = 0; + if (!status) + le16_to_cpus(retval_ptr); + return status; +} + +static inline int +nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr) +{ + return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr); +} + +// no retval ... can become async, usable in_interrupt() +static void +nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value) +{ + usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, regnum, + NULL, 0, // data is in setup packet + USB_CTRL_SET_TIMEOUT); +} + +static inline void +nc_register_write(struct usbnet *dev, u8 regnum, u16 value) +{ + nc_vendor_write(dev, REQUEST_REGISTER, regnum, value); +} + + +#if 0 +static void nc_dump_registers(struct usbnet *dev) +{ + u8 reg; + u16 *vp = kmalloc(sizeof (u16)); + + if (!vp) { + dbg("no memory?"); + return; + } + + dbg("%s registers:", dev->net->name); + for (reg = 0; reg < 0x20; reg++) { + int retval; + + // reading some registers is trouble + if (reg >= 0x08 && reg <= 0xf) + continue; + if (reg >= 0x12 && reg <= 0x1e) + continue; + + retval = nc_register_read(dev, reg, vp); + if (retval < 0) + dbg("%s reg [0x%x] ==> error %d", + dev->net->name, reg, retval); + else + dbg("%s reg [0x%x] = 0x%x", + dev->net->name, reg, *vp); + } + kfree(vp); +} +#endif + + +/*-------------------------------------------------------------------------*/ + +/* + * Control register + */ + +#define USBCTL_WRITABLE_MASK 0x1f0f +// bits 15-13 reserved, r/o +#define USBCTL_ENABLE_LANG (1 << 12) +#define USBCTL_ENABLE_MFGR (1 << 11) +#define USBCTL_ENABLE_PROD (1 << 10) +#define USBCTL_ENABLE_SERIAL (1 << 9) +#define USBCTL_ENABLE_DEFAULTS (1 << 8) +// bits 7-4 reserved, r/o +#define USBCTL_FLUSH_OTHER (1 << 3) +#define USBCTL_FLUSH_THIS (1 << 2) +#define USBCTL_DISCONN_OTHER (1 << 1) +#define USBCTL_DISCONN_THIS (1 << 0) + +static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) +{ + if (!netif_msg_link(dev)) + return; + devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" + " this%s%s;" + " other%s%s; r/o 0x%x", + dev->udev->bus->bus_name, dev->udev->devpath, + usbctl, + (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", + (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", + (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", + (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", + (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", + + (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", + (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", + usbctl & ~USBCTL_WRITABLE_MASK + ); +} + +/*-------------------------------------------------------------------------*/ + +/* + * Status register + */ + +#define STATUS_PORT_A (1 << 15) + +#define STATUS_CONN_OTHER (1 << 14) +#define STATUS_SUSPEND_OTHER (1 << 13) +#define STATUS_MAILBOX_OTHER (1 << 12) +#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) + +#define STATUS_CONN_THIS (1 << 6) +#define STATUS_SUSPEND_THIS (1 << 5) +#define STATUS_MAILBOX_THIS (1 << 4) +#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) + +#define STATUS_UNSPEC_MASK 0x0c8c +#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) + + +static inline void nc_dump_status(struct usbnet *dev, u16 status) +{ + if (!netif_msg_link(dev)) + return; + devdbg(dev, "net1080 %s-%s status 0x%x:" + " this (%c) PKT=%d%s%s%s;" + " other PKT=%d%s%s%s; unspec 0x%x", + dev->udev->bus->bus_name, dev->udev->devpath, + status, + + // XXX the packet counts don't seem right + // (1 at reset, not 0); maybe UNSPEC too + + (status & STATUS_PORT_A) ? 'A' : 'B', + STATUS_PACKETS_THIS(status), + (status & STATUS_CONN_THIS) ? " CON" : "", + (status & STATUS_SUSPEND_THIS) ? " SUS" : "", + (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", + + STATUS_PACKETS_OTHER(status), + (status & STATUS_CONN_OTHER) ? " CON" : "", + (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", + (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", + + status & STATUS_UNSPEC_MASK + ); +} + +/*-------------------------------------------------------------------------*/ + +/* + * TTL register + */ + +#define TTL_THIS(ttl) (0x00ff & ttl) +#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) +#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) + +static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) +{ + if (netif_msg_link(dev)) + devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", + dev->udev->bus->bus_name, dev->udev->devpath, + ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); +} + +/*-------------------------------------------------------------------------*/ + +static int net1080_reset(struct usbnet *dev) +{ + u16 usbctl, status, ttl; + u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); + int retval; + + if (!vp) + return -ENOMEM; + + // nc_dump_registers(dev); + + if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) { + dbg("can't read %s-%s status: %d", + dev->udev->bus->bus_name, dev->udev->devpath, retval); + goto done; + } + status = *vp; + nc_dump_status(dev, status); + + if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) { + dbg("can't read USBCTL, %d", retval); + goto done; + } + usbctl = *vp; + nc_dump_usbctl(dev, usbctl); + + nc_register_write(dev, REG_USBCTL, + USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); + + if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) { + dbg("can't read TTL, %d", retval); + goto done; + } + ttl = *vp; + // nc_dump_ttl(dev, ttl); + + nc_register_write(dev, REG_TTL, + MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); + dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); + + if (netif_msg_link(dev)) + devinfo(dev, "port %c, peer %sconnected", + (status & STATUS_PORT_A) ? 'A' : 'B', + (status & STATUS_CONN_OTHER) ? "" : "dis" + ); + retval = 0; + +done: + kfree(vp); + return retval; +} + +static int net1080_check_connect(struct usbnet *dev) +{ + int retval; + u16 status; + u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); + + if (!vp) + return -ENOMEM; + retval = nc_register_read(dev, REG_STATUS, vp); + status = *vp; + kfree(vp); + if (retval != 0) { + dbg("%s net1080_check_conn read - %d", dev->net->name, retval); + return retval; + } + if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) + return -ENOLINK; + return 0; +} + +static void nc_flush_complete(struct urb *urb, struct pt_regs *regs) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void nc_ensure_sync(struct usbnet *dev) +{ + dev->frame_errors++; + if (dev->frame_errors > 5) { + struct urb *urb; + struct usb_ctrlrequest *req; + int status; + + /* Send a flush */ + urb = usb_alloc_urb(0, SLAB_ATOMIC); + if (!urb) + return; + + req = kmalloc(sizeof *req, GFP_ATOMIC); + if (!req) { + usb_free_urb(urb); + return; + } + + req->bRequestType = USB_DIR_OUT + | USB_TYPE_VENDOR + | USB_RECIP_DEVICE; + req->bRequest = REQUEST_REGISTER; + req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS + | USBCTL_FLUSH_OTHER); + req->wIndex = cpu_to_le16(REG_USBCTL); + req->wLength = cpu_to_le16(0); + + /* queue an async control request, we don't need + * to do anything when it finishes except clean up. + */ + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (unsigned char *) req, + NULL, 0, + nc_flush_complete, req); + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) { + kfree(req); + usb_free_urb(urb); + return; + } + + if (netif_msg_rx_err(dev)) + devdbg(dev, "flush net1080; too many framing errors"); + dev->frame_errors = 0; + } +} + +static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct nc_header *header; + struct nc_trailer *trailer; + u16 hdr_len, packet_len; + + if (!(skb->len & 0x01)) { +#ifdef DEBUG + struct net_device *net = dev->net; + dbg("rx framesize %d range %d..%d mtu %d", skb->len, + net->hard_header_len, dev->hard_mtu, net->mtu); +#endif + dev->stats.rx_frame_errors++; + nc_ensure_sync(dev); + return 0; + } + + header = (struct nc_header *) skb->data; + hdr_len = le16_to_cpup(&header->hdr_len); + packet_len = le16_to_cpup(&header->packet_len); + if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) { + dev->stats.rx_frame_errors++; + dbg("packet too big, %d", packet_len); + nc_ensure_sync(dev); + return 0; + } else if (hdr_len < MIN_HEADER) { + dev->stats.rx_frame_errors++; + dbg("header too short, %d", hdr_len); + nc_ensure_sync(dev); + return 0; + } else if (hdr_len > MIN_HEADER) { + // out of band data for us? + dbg("header OOB, %d bytes", hdr_len - MIN_HEADER); + nc_ensure_sync(dev); + // switch (vendor/product ids) { ... } + } + skb_pull(skb, hdr_len); + + trailer = (struct nc_trailer *) + (skb->data + skb->len - sizeof *trailer); + skb_trim(skb, skb->len - sizeof *trailer); + + if ((packet_len & 0x01) == 0) { + if (skb->data [packet_len] != PAD_BYTE) { + dev->stats.rx_frame_errors++; + dbg("bad pad"); + return 0; + } + skb_trim(skb, skb->len - 1); + } + if (skb->len != packet_len) { + dev->stats.rx_frame_errors++; + dbg("bad packet len %d (expected %d)", + skb->len, packet_len); + nc_ensure_sync(dev); + return 0; + } + if (header->packet_id != get_unaligned(&trailer->packet_id)) { + dev->stats.rx_fifo_errors++; + dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", + le16_to_cpu(header->packet_id), + le16_to_cpu(trailer->packet_id)); + return 0; + } +#if 0 + devdbg(dev, "frame hdr_len, + header->packet_len, header->packet_id); +#endif + dev->frame_errors = 0; + return 1; +} + +static struct sk_buff * +net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +{ + int padlen; + struct sk_buff *skb2; + struct nc_header *header = NULL; + struct nc_trailer *trailer = NULL; + int len = skb->len; + + padlen = ((len + sizeof (struct nc_header) + + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; + if (!skb_cloned(skb)) { + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + + if ((padlen + sizeof (struct nc_trailer)) <= tailroom + && sizeof (struct nc_header) <= headroom) + /* There's enough head and tail room */ + goto encapsulate; + + if ((sizeof (struct nc_header) + padlen + + sizeof (struct nc_trailer)) < + (headroom + tailroom)) { + /* There's enough total room, so just readjust */ + skb->data = memmove(skb->head + + sizeof (struct nc_header), + skb->data, skb->len); + skb->tail = skb->data + len; + goto encapsulate; + } + } + + /* Create a new skb to use with the correct size */ + skb2 = skb_copy_expand(skb, + sizeof (struct nc_header), + sizeof (struct nc_trailer) + padlen, + flags); + dev_kfree_skb_any(skb); + if (!skb2) + return skb2; + skb = skb2; + +encapsulate: + /* header first */ + header = (struct nc_header *) skb_push(skb, sizeof *header); + header->hdr_len = cpu_to_le16(sizeof (*header)); + header->packet_len = cpu_to_le16(len); + header->packet_id = cpu_to_le16((u16)dev->xid++); + + /* maybe pad; then trailer */ + if (!((skb->len + sizeof *trailer) & 0x01)) + *skb_put(skb, 1) = PAD_BYTE; + trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer); + put_unaligned(header->packet_id, &trailer->packet_id); +#if 0 + devdbg(dev, "frame >tx h %d p %d id %d", + header->hdr_len, header->packet_len, + header->packet_id); +#endif + return skb; +} + +static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) +{ + unsigned extra = sizeof (struct nc_header) + + 1 + + sizeof (struct nc_trailer); + + dev->net->hard_header_len += extra; + dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; + dev->hard_mtu = NC_MAX_PACKET; + return usbnet_get_endpoints (dev, intf); +} + +static const struct driver_info net1080_info = { + .description = "NetChip TurboCONNECT", + .flags = FLAG_FRAMING_NC, + .bind = net1080_bind, + .reset = net1080_reset, + .check_connect = net1080_check_connect, + .rx_fixup = net1080_rx_fixup, + .tx_fixup = net1080_tx_fixup, +}; + +static const struct usb_device_id products [] = { +{ + USB_DEVICE(0x0525, 0x1080), // NetChip ref design + .driver_info = (unsigned long) &net1080_info, +}, { + USB_DEVICE(0x06D0, 0x0622), // Laplink Gold + .driver_info = (unsigned long) &net1080_info, +}, + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver net1080_driver = { + .owner = THIS_MODULE, + .name = "net1080", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init net1080_init(void) +{ + return usb_register(&net1080_driver); +} +module_init(net1080_init); + +static void __exit net1080_exit(void) +{ + usb_deregister(&net1080_driver); +} +module_exit(net1080_exit); + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 99a48814014..590bf31ae1f 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -119,7 +119,6 @@ # define DEBUG #endif #include -#include #include #include #include @@ -128,10 +127,6 @@ #include #include #include -#include -#include - -#include #include "usbnet.h" @@ -1029,531 +1024,6 @@ static const struct driver_info genelink_info = { #endif /* CONFIG_USB_GENESYS */ - -#ifdef CONFIG_USB_NET1080 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Netchip 1080 driver ... http://www.netchip.com - * Used in LapLink cables - * - *-------------------------------------------------------------------------*/ - -#define frame_errors data[1] - -/* - * NetChip framing of ethernet packets, supporting additional error - * checks for links that may drop bulk packets from inside messages. - * Odd USB length == always short read for last usb packet. - * - nc_header - * - Ethernet header (14 bytes) - * - payload - * - (optional padding byte, if needed so length becomes odd) - * - nc_trailer - * - * This framing is to be avoided for non-NetChip devices. - */ - -struct nc_header { // packed: - __le16 hdr_len; // sizeof nc_header (LE, all) - __le16 packet_len; // payload size (including ethhdr) - __le16 packet_id; // detects dropped packets -#define MIN_HEADER 6 - - // all else is optional, and must start with: - // u16 vendorId; // from usb-if - // u16 productId; -} __attribute__((__packed__)); - -#define PAD_BYTE ((unsigned char)0xAC) - -struct nc_trailer { - __le16 packet_id; -} __attribute__((__packed__)); - -// packets may use FLAG_FRAMING_NC and optional pad -#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ - + sizeof (struct ethhdr) \ - + (mtu) \ - + 1 \ - + sizeof (struct nc_trailer)) - -#define MIN_FRAMED FRAMED_SIZE(0) - -/* packets _could_ be up to 64KB... */ -#define NC_MAX_PACKET 32767 - - -/* - * Zero means no timeout; else, how long a 64 byte bulk packet may be queued - * before the hardware drops it. If that's done, the driver will need to - * frame network packets to guard against the dropped USB packets. The win32 - * driver sets this for both sides of the link. - */ -#define NC_READ_TTL_MS ((u8)255) // ms - -/* - * We ignore most registers and EEPROM contents. - */ -#define REG_USBCTL ((u8)0x04) -#define REG_TTL ((u8)0x10) -#define REG_STATUS ((u8)0x11) - -/* - * Vendor specific requests to read/write data - */ -#define REQUEST_REGISTER ((u8)0x10) -#define REQUEST_EEPROM ((u8)0x11) - -static int -nc_vendor_read (struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) -{ - int status = usb_control_msg (dev->udev, - usb_rcvctrlpipe (dev->udev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, regnum, - retval_ptr, sizeof *retval_ptr, - CONTROL_TIMEOUT_MS); - if (status > 0) - status = 0; - if (!status) - le16_to_cpus (retval_ptr); - return status; -} - -static inline int -nc_register_read (struct usbnet *dev, u8 regnum, u16 *retval_ptr) -{ - return nc_vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr); -} - -// no retval ... can become async, usable in_interrupt() -static void -nc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value) -{ - usb_control_msg (dev->udev, - usb_sndctrlpipe (dev->udev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, regnum, - NULL, 0, // data is in setup packet - CONTROL_TIMEOUT_MS); -} - -static inline void -nc_register_write (struct usbnet *dev, u8 regnum, u16 value) -{ - nc_vendor_write (dev, REQUEST_REGISTER, regnum, value); -} - - -#if 0 -static void nc_dump_registers (struct usbnet *dev) -{ - u8 reg; - u16 *vp = kmalloc (sizeof (u16)); - - if (!vp) { - dbg ("no memory?"); - return; - } - - dbg ("%s registers:", dev->net->name); - for (reg = 0; reg < 0x20; reg++) { - int retval; - - // reading some registers is trouble - if (reg >= 0x08 && reg <= 0xf) - continue; - if (reg >= 0x12 && reg <= 0x1e) - continue; - - retval = nc_register_read (dev, reg, vp); - if (retval < 0) - dbg ("%s reg [0x%x] ==> error %d", - dev->net->name, reg, retval); - else - dbg ("%s reg [0x%x] = 0x%x", - dev->net->name, reg, *vp); - } - kfree (vp); -} -#endif - - -/*-------------------------------------------------------------------------*/ - -/* - * Control register - */ - -#define USBCTL_WRITABLE_MASK 0x1f0f -// bits 15-13 reserved, r/o -#define USBCTL_ENABLE_LANG (1 << 12) -#define USBCTL_ENABLE_MFGR (1 << 11) -#define USBCTL_ENABLE_PROD (1 << 10) -#define USBCTL_ENABLE_SERIAL (1 << 9) -#define USBCTL_ENABLE_DEFAULTS (1 << 8) -// bits 7-4 reserved, r/o -#define USBCTL_FLUSH_OTHER (1 << 3) -#define USBCTL_FLUSH_THIS (1 << 2) -#define USBCTL_DISCONN_OTHER (1 << 1) -#define USBCTL_DISCONN_THIS (1 << 0) - -static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl) -{ - if (!netif_msg_link (dev)) - return; - devdbg (dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" - " this%s%s;" - " other%s%s; r/o 0x%x", - dev->udev->bus->bus_name, dev->udev->devpath, - usbctl, - (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", - (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", - (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", - (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", - (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", - - (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", - (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", - (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", - usbctl & ~USBCTL_WRITABLE_MASK - ); -} - -/*-------------------------------------------------------------------------*/ - -/* - * Status register - */ - -#define STATUS_PORT_A (1 << 15) - -#define STATUS_CONN_OTHER (1 << 14) -#define STATUS_SUSPEND_OTHER (1 << 13) -#define STATUS_MAILBOX_OTHER (1 << 12) -#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) - -#define STATUS_CONN_THIS (1 << 6) -#define STATUS_SUSPEND_THIS (1 << 5) -#define STATUS_MAILBOX_THIS (1 << 4) -#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) - -#define STATUS_UNSPEC_MASK 0x0c8c -#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) - - -static inline void nc_dump_status (struct usbnet *dev, u16 status) -{ - if (!netif_msg_link (dev)) - return; - devdbg (dev, "net1080 %s-%s status 0x%x:" - " this (%c) PKT=%d%s%s%s;" - " other PKT=%d%s%s%s; unspec 0x%x", - dev->udev->bus->bus_name, dev->udev->devpath, - status, - - // XXX the packet counts don't seem right - // (1 at reset, not 0); maybe UNSPEC too - - (status & STATUS_PORT_A) ? 'A' : 'B', - STATUS_PACKETS_THIS (status), - (status & STATUS_CONN_THIS) ? " CON" : "", - (status & STATUS_SUSPEND_THIS) ? " SUS" : "", - (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", - - STATUS_PACKETS_OTHER (status), - (status & STATUS_CONN_OTHER) ? " CON" : "", - (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", - (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", - - status & STATUS_UNSPEC_MASK - ); -} - -/*-------------------------------------------------------------------------*/ - -/* - * TTL register - */ - -#define TTL_THIS(ttl) (0x00ff & ttl) -#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) -#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) - -static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl) -{ - if (netif_msg_link (dev)) - devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", - dev->udev->bus->bus_name, dev->udev->devpath, - ttl, TTL_THIS (ttl), TTL_OTHER (ttl)); -} - -/*-------------------------------------------------------------------------*/ - -static int net1080_reset (struct usbnet *dev) -{ - u16 usbctl, status, ttl; - u16 *vp = kmalloc (sizeof (u16), GFP_KERNEL); - int retval; - - if (!vp) - return -ENOMEM; - - // nc_dump_registers (dev); - - if ((retval = nc_register_read (dev, REG_STATUS, vp)) < 0) { - dbg ("can't read %s-%s status: %d", - dev->udev->bus->bus_name, dev->udev->devpath, retval); - goto done; - } - status = *vp; - nc_dump_status (dev, status); - - if ((retval = nc_register_read (dev, REG_USBCTL, vp)) < 0) { - dbg ("can't read USBCTL, %d", retval); - goto done; - } - usbctl = *vp; - nc_dump_usbctl (dev, usbctl); - - nc_register_write (dev, REG_USBCTL, - USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); - - if ((retval = nc_register_read (dev, REG_TTL, vp)) < 0) { - dbg ("can't read TTL, %d", retval); - goto done; - } - ttl = *vp; - // nc_dump_ttl (dev, ttl); - - nc_register_write (dev, REG_TTL, - MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) ); - dbg ("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); - - if (netif_msg_link (dev)) - devinfo (dev, "port %c, peer %sconnected", - (status & STATUS_PORT_A) ? 'A' : 'B', - (status & STATUS_CONN_OTHER) ? "" : "dis" - ); - retval = 0; - -done: - kfree (vp); - return retval; -} - -static int net1080_check_connect (struct usbnet *dev) -{ - int retval; - u16 status; - u16 *vp = kmalloc (sizeof (u16), GFP_KERNEL); - - if (!vp) - return -ENOMEM; - retval = nc_register_read (dev, REG_STATUS, vp); - status = *vp; - kfree (vp); - if (retval != 0) { - dbg ("%s net1080_check_conn read - %d", dev->net->name, retval); - return retval; - } - if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) - return -ENOLINK; - return 0; -} - -static void nc_flush_complete (struct urb *urb, struct pt_regs *regs) -{ - kfree (urb->context); - usb_free_urb(urb); -} - -static void nc_ensure_sync (struct usbnet *dev) -{ - dev->frame_errors++; - if (dev->frame_errors > 5) { - struct urb *urb; - struct usb_ctrlrequest *req; - int status; - - /* Send a flush */ - urb = usb_alloc_urb (0, SLAB_ATOMIC); - if (!urb) - return; - - req = kmalloc (sizeof *req, GFP_ATOMIC); - if (!req) { - usb_free_urb (urb); - return; - } - - req->bRequestType = USB_DIR_OUT - | USB_TYPE_VENDOR - | USB_RECIP_DEVICE; - req->bRequest = REQUEST_REGISTER; - req->wValue = cpu_to_le16 (USBCTL_FLUSH_THIS - | USBCTL_FLUSH_OTHER); - req->wIndex = cpu_to_le16 (REG_USBCTL); - req->wLength = cpu_to_le16 (0); - - /* queue an async control request, we don't need - * to do anything when it finishes except clean up. - */ - usb_fill_control_urb (urb, dev->udev, - usb_sndctrlpipe (dev->udev, 0), - (unsigned char *) req, - NULL, 0, - nc_flush_complete, req); - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) { - kfree (req); - usb_free_urb (urb); - return; - } - - if (netif_msg_rx_err (dev)) - devdbg (dev, "flush net1080; too many framing errors"); - dev->frame_errors = 0; - } -} - -static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) -{ - struct nc_header *header; - struct net_device *net = dev->net; - struct nc_trailer *trailer; - u16 hdr_len, packet_len; - - if (!(skb->len & 0x01)) { - dev->stats.rx_frame_errors++; - dbg ("rx framesize %d range %d..%d mtu %d", skb->len, - net->hard_header_len, dev->hard_mtu, net->mtu); - nc_ensure_sync (dev); - return 0; - } - - header = (struct nc_header *) skb->data; - hdr_len = le16_to_cpup (&header->hdr_len); - packet_len = le16_to_cpup (&header->packet_len); - if (FRAMED_SIZE (packet_len) > NC_MAX_PACKET) { - dev->stats.rx_frame_errors++; - dbg ("packet too big, %d", packet_len); - nc_ensure_sync (dev); - return 0; - } else if (hdr_len < MIN_HEADER) { - dev->stats.rx_frame_errors++; - dbg ("header too short, %d", hdr_len); - nc_ensure_sync (dev); - return 0; - } else if (hdr_len > MIN_HEADER) { - // out of band data for us? - dbg ("header OOB, %d bytes", hdr_len - MIN_HEADER); - nc_ensure_sync (dev); - // switch (vendor/product ids) { ... } - } - skb_pull (skb, hdr_len); - - trailer = (struct nc_trailer *) - (skb->data + skb->len - sizeof *trailer); - skb_trim (skb, skb->len - sizeof *trailer); - - if ((packet_len & 0x01) == 0) { - if (skb->data [packet_len] != PAD_BYTE) { - dev->stats.rx_frame_errors++; - dbg ("bad pad"); - return 0; - } - skb_trim (skb, skb->len - 1); - } - if (skb->len != packet_len) { - dev->stats.rx_frame_errors++; - dbg ("bad packet len %d (expected %d)", - skb->len, packet_len); - nc_ensure_sync (dev); - return 0; - } - if (header->packet_id != get_unaligned (&trailer->packet_id)) { - dev->stats.rx_fifo_errors++; - dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", - le16_to_cpu (header->packet_id), - le16_to_cpu (trailer->packet_id)); - return 0; - } -#if 0 - devdbg (dev, "frame hdr_len, - header->packet_len, header->packet_id); -#endif - dev->frame_errors = 0; - return 1; -} - -static struct sk_buff * -net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) -{ - int padlen; - struct sk_buff *skb2; - - padlen = ((skb->len + sizeof (struct nc_header) - + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; - if (!skb_cloned (skb)) { - int headroom = skb_headroom (skb); - int tailroom = skb_tailroom (skb); - - if ((padlen + sizeof (struct nc_trailer)) <= tailroom - && sizeof (struct nc_header) <= headroom) - /* There's enough head and tail room */ - return skb; - - if ((sizeof (struct nc_header) + padlen - + sizeof (struct nc_trailer)) < - (headroom + tailroom)) { - /* There's enough total room, so just readjust */ - skb->data = memmove (skb->head - + sizeof (struct nc_header), - skb->data, skb->len); - skb->tail = skb->data + skb->len; - return skb; - } - } - - /* Create a new skb to use with the correct size */ - skb2 = skb_copy_expand (skb, - sizeof (struct nc_header), - sizeof (struct nc_trailer) + padlen, - flags); - dev_kfree_skb_any (skb); - return skb2; -} - -static int net1080_bind (struct usbnet *dev, struct usb_interface *intf) -{ - unsigned extra = sizeof (struct nc_header) - + 1 - + sizeof (struct nc_trailer); - - dev->net->hard_header_len += extra; - dev->hard_mtu = NC_MAX_PACKET; - return 0; -} - -static const struct driver_info net1080_info = { - .description = "NetChip TurboCONNECT", - .flags = FLAG_FRAMING_NC, - .bind = net1080_bind, - .reset = net1080_reset, - .check_connect = net1080_check_connect, - .rx_fixup = net1080_rx_fixup, - .tx_fixup = net1080_tx_fixup, -}; - -#endif /* CONFIG_USB_NET1080 */ - - #ifdef CONFIG_USB_PL2301 #define HAVE_HARDWARE @@ -2486,10 +1956,6 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; -#ifdef CONFIG_USB_NET1080 - struct nc_header *header = NULL; - struct nc_trailer *trailer = NULL; -#endif /* CONFIG_USB_NET1080 */ // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks @@ -2515,21 +1981,6 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) entry->state = tx_start; entry->length = length; - // FIXME: reorganize a bit, so that fixup() fills out NetChip - // framing too. (Packet ID update needs the spinlock...) - // [ BETTER: we already own net->xmit_lock, that's enough ] - -#ifdef CONFIG_USB_NET1080 - if (info->flags & FLAG_FRAMING_NC) { - header = (struct nc_header *) skb_push (skb, sizeof *header); - header->hdr_len = cpu_to_le16 (sizeof (*header)); - header->packet_len = cpu_to_le16 (length); - if (!((skb->len + sizeof *trailer) & 0x01)) - *skb_put (skb, 1) = PAD_BYTE; - trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); - } -#endif /* CONFIG_USB_NET1080 */ - usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); @@ -2544,18 +1995,6 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) spin_lock_irqsave (&dev->txq.lock, flags); -#ifdef CONFIG_USB_NET1080 - if (info->flags & FLAG_FRAMING_NC) { - header->packet_id = cpu_to_le16 ((u16)dev->xid++); - put_unaligned (header->packet_id, &trailer->packet_id); -#if 0 - devdbg (dev, "frame >tx h %d p %d id %d", - header->hdr_len, header->packet_len, - header->packet_id); -#endif - } -#endif /* CONFIG_USB_NET1080 */ - switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue (net); @@ -2894,16 +2333,6 @@ static const struct usb_device_id products [] = { */ #endif -#ifdef CONFIG_USB_NET1080 -{ - USB_DEVICE (0x0525, 0x1080), // NetChip ref design - .driver_info = (unsigned long) &net1080_info, -}, { - USB_DEVICE (0x06D0, 0x0622), // Laplink Gold - .driver_info = (unsigned long) &net1080_info, -}, -#endif - #ifdef CONFIG_USB_PL2301 { USB_DEVICE (0x067b, 0x0000), // PL-2301 -- cgit v1.2.3-70-g09d2 From 47ee3051c856cc2aa95d35d577a8cb37279d540f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:53:42 -0700 Subject: [PATCH] USB: usbnet (5/9) module for genesys gl620a cables This moves the GeneSys GL620USB-A support into its own driver file. It also fixes a "return wrong skb" glitch in the rx unbatching, as recently reported, and adds some missing byteswaps in the special "genelink" headers (so it might now work on big-endian Linux). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 19 ++- drivers/usb/net/Makefile | 1 + drivers/usb/net/gl620a.c | 407 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 350 +--------------------------------------- 4 files changed, 418 insertions(+), 359 deletions(-) create mode 100644 drivers/usb/net/gl620a.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 0aa8637e5ff..0aafd599d7d 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -128,16 +128,6 @@ config USB_USBNET comment "USB Host-to-Host Cables" depends on USB_USBNET -config USB_GENESYS - boolean "GeneSys GL620USB-A based cables" - default y - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable, - or PC2PC motherboard, with this chip. - - Note that the half-duplex "GL620USB" is not supported. - config USB_PL2301 boolean "Prolific PL-2301/2302 based cables" default y @@ -224,6 +214,15 @@ config USB_NET_AX8817X what other networking devices you have in use. +config USB_NET_GL620A + tristate "GeneSys GL620USB-A based cables" + depends on USB_USBNET + help + Choose this option if you're using a host-to-host cable, + or PC2PC motherboard, with this chip. + + Note that the half-duplex "GL620USB" is not supported. + config USB_NET_NET1080 tristate "NetChip 1080 based cables (Laplink, ...)" default y diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 14d554080aa..f9b181e91c1 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o +obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_USBNET) += usbnet.o diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c new file mode 100644 index 00000000000..c8763ae33c7 --- /dev/null +++ b/drivers/usb/net/gl620a.c @@ -0,0 +1,407 @@ +/* + * GeneSys GL620USB-A based links + * Copyright (C) 2001 by Jiun-Jie Huang + * Copyright (C) 2001 by Stanislav Brabec + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * GeneSys GL620USB-A (www.genesyslogic.com.tw) + * + * ... should partially interop with the Win32 driver for this hardware. + * 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. + * + * Original code from Jiun-Jie Huang + * and merged into "usbnet" by Stanislav Brabec . + */ + +// control msg write command +#define GENELINK_CONNECT_WRITE 0xF0 +// interrupt pipe index +#define GENELINK_INTERRUPT_PIPE 0x03 +// interrupt read buffer size +#define INTERRUPT_BUFSIZE 0x08 +// interrupt pipe interval value +#define GENELINK_INTERRUPT_INTERVAL 0x10 +// max transmit packet number per transmit +#define GL_MAX_TRANSMIT_PACKETS 32 +// max packet length +#define GL_MAX_PACKET_LEN 1514 +// max receive buffer size +#define GL_RCV_BUF_SIZE \ + (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) + +struct gl_packet { + u32 packet_length; + char packet_data [1]; +}; + +struct gl_header { + u32 packet_count; + struct gl_packet packets; +}; + +#ifdef GENELINK_ACK + +// FIXME: this code is incomplete, not debugged; it doesn't +// handle interrupts correctly; it should use the generic +// status IRQ code (which didn't exist back in 2001). + +struct gl_priv { + struct urb *irq_urb; + char irq_buf [INTERRUPT_BUFSIZE]; +}; + +static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value) +{ + int retval; + + retval = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + request, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + value, + 0, // index + 0, // data buffer + 0, // size + USB_CTRL_SET_TIMEOUT); + return retval; +} + +static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs) +{ + int status = urb->status; + + switch (status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + } + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) + err("%s - usb_submit_urb failed with result %d", + __FUNCTION__, status); +} + +static int gl_interrupt_read(struct usbnet *dev) +{ + struct gl_priv *priv = dev->priv_data; + int retval; + + // issue usb interrupt read + if (priv && priv->irq_urb) { + // submit urb + if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0) + dbg("gl_interrupt_read: submit fail - %X...", retval); + else + dbg("gl_interrupt_read: submit success..."); + } + + return 0; +} + +// check whether another side is connected +static int genelink_check_connect(struct usbnet *dev) +{ + int retval; + + dbg("genelink_check_connect..."); + + // detect whether another side is connected + if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) { + dbg("%s: genelink_check_connect write fail - %X", + dev->net->name, retval); + return retval; + } + + // usb interrupt read to ack another side + if ((retval = gl_interrupt_read(dev)) != 0) { + dbg("%s: genelink_check_connect read fail - %X", + dev->net->name, retval); + return retval; + } + + dbg("%s: genelink_check_connect read success", dev->net->name); + return 0; +} + +// allocate and initialize the private data for genelink +static int genelink_init(struct usbnet *dev) +{ + struct gl_priv *priv; + + // allocate the private data structure + if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) { + dbg("%s: cannot allocate private data per device", + dev->net->name); + return -ENOMEM; + } + + // allocate irq urb + if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) { + dbg("%s: cannot allocate private irq urb per device", + dev->net->name); + kfree(priv); + return -ENOMEM; + } + + // fill irq urb + usb_fill_int_urb(priv->irq_urb, dev->udev, + usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE), + priv->irq_buf, INTERRUPT_BUFSIZE, + gl_interrupt_complete, 0, + GENELINK_INTERRUPT_INTERVAL); + + // set private data pointer + dev->priv_data = priv; + + return 0; +} + +// release the private data +static int genelink_free(struct usbnet *dev) +{ + struct gl_priv *priv = dev->priv_data; + + if (!priv) + return 0; + +// FIXME: can't cancel here; it's synchronous, and +// should have happened earlier in any case (interrupt +// handling needs to be generic) + + // cancel irq urb first + usb_kill_urb(priv->irq_urb); + + // free irq urb + usb_free_urb(priv->irq_urb); + + // free the private data structure + kfree(priv); + + return 0; +} + +#endif + +static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct gl_header *header; + struct gl_packet *packet; + struct sk_buff *gl_skb; + u32 size; + + header = (struct gl_header *) skb->data; + + // get the packet count of the received skb + le32_to_cpus(&header->packet_count); + if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) + || (header->packet_count < 0)) { + dbg("genelink: invalid received packet count %d", + header->packet_count); + return 0; + } + + // set the current packet pointer to the first packet + packet = &header->packets; + + // decrement the length for the packet count size 4 bytes + skb_pull(skb, 4); + + while (header->packet_count > 1) { + // get the packet length + size = le32_to_cpu(packet->packet_length); + + // this may be a broken packet + if (size > GL_MAX_PACKET_LEN) { + dbg("genelink: invalid rx length %d", size); + return 0; + } + + // allocate the skb for the individual packet + gl_skb = alloc_skb(size, GFP_ATOMIC); + if (gl_skb) { + + // copy the packet data to the new skb + memcpy(skb_put(gl_skb, size), + packet->packet_data, size); + usbnet_skb_return(dev, gl_skb); + } + + // advance to the next packet + packet = (struct gl_packet *) + &packet->packet_data [size]; + header->packet_count--; + + // shift the data pointer to the next gl_packet + skb_pull(skb, size + 4); + } + + // skip the packet length field 4 bytes + skb_pull(skb, 4); + + if (skb->len > GL_MAX_PACKET_LEN) { + dbg("genelink: invalid rx length %d", skb->len); + return 0; + } + return 1; +} + +static struct sk_buff * +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +{ + int padlen; + int length = skb->len; + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + u32 *packet_count; + u32 *packet_len; + + // FIXME: magic numbers, bleech + padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; + + if ((!skb_cloned(skb)) + && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { + if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { + skb->data = memmove(skb->head + (4 + 4*1), + skb->data, skb->len); + skb->tail = skb->data + skb->len; + } + } else { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + // attach the packet count to the header + packet_count = (u32 *) skb_push(skb, (4 + 4*1)); + packet_len = packet_count + 1; + + *packet_count = cpu_to_le32(1); + *packet_len = cpu_to_le32(length); + + // add padding byte + if ((skb->len % dev->maxpacket) == 0) + skb_put(skb, 1); + + return skb; +} + +static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) +{ + dev->hard_mtu = GL_RCV_BUF_SIZE; + dev->net->hard_header_len += 4; + dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in); + dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out); + return 0; +} + +static const struct driver_info genelink_info = { + .description = "Genesys GeneLink", + .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, + .bind = genelink_bind, + .rx_fixup = genelink_rx_fixup, + .tx_fixup = genelink_tx_fixup, + + .in = 1, .out = 2, + +#ifdef GENELINK_ACK + .check_connect =genelink_check_connect, +#endif +}; + +static const struct usb_device_id products [] = { + +{ + USB_DEVICE(0x05e3, 0x0502), // GL620USB-A + .driver_info = (unsigned long) &genelink_info, +}, + /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB + * that's half duplex, not currently supported + */ + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver gl620a_driver = { + .owner = THIS_MODULE, + .name = "gl620a", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init usbnet_init(void) +{ + return usb_register(&gl620a_driver); +} +module_init(usbnet_init); + +static void __exit usbnet_exit(void) +{ + usb_deregister(&gl620a_driver); +} +module_exit(usbnet_exit); + +MODULE_AUTHOR("Jiun-Jie Huang"); +MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 590bf31ae1f..d52480aced8 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -156,9 +156,6 @@ // us (it polls at HZ/4 usually) before we report too many false errors. #define THROTTLE_JIFFIES (HZ/8) -// for vendor-specific control operations -#define CONTROL_TIMEOUT_MS USB_CTRL_GET_TIMEOUT - // between wakeups #define UNLINK_TIMEOUT_MS 3 @@ -689,341 +686,6 @@ static const struct driver_info cdc_info = { #endif /* CONFIG_USB_CDCETHER */ - -#ifdef CONFIG_USB_GENESYS -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * GeneSys GL620USB-A (www.genesyslogic.com.tw) - * - * ... should partially interop with the Win32 driver for this hardware - * 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. - * - * Original code from Jiun-Jie Huang - * and merged into "usbnet" by Stanislav Brabec . - * - *-------------------------------------------------------------------------*/ - -// control msg write command -#define GENELINK_CONNECT_WRITE 0xF0 -// interrupt pipe index -#define GENELINK_INTERRUPT_PIPE 0x03 -// interrupt read buffer size -#define INTERRUPT_BUFSIZE 0x08 -// interrupt pipe interval value -#define GENELINK_INTERRUPT_INTERVAL 0x10 -// max transmit packet number per transmit -#define GL_MAX_TRANSMIT_PACKETS 32 -// max packet length -#define GL_MAX_PACKET_LEN 1514 -// max receive buffer size -#define GL_RCV_BUF_SIZE \ - (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) - -struct gl_packet { - u32 packet_length; - char packet_data [1]; -}; - -struct gl_header { - u32 packet_count; - struct gl_packet packets; -}; - -#ifdef GENELINK_ACK - -// FIXME: this code is incomplete, not debugged; it doesn't -// handle interrupts correctly. interrupts should be generic -// code like all other device I/O, anyway. - -struct gl_priv { - struct urb *irq_urb; - char irq_buf [INTERRUPT_BUFSIZE]; -}; - -static inline int gl_control_write (struct usbnet *dev, u8 request, u16 value) -{ - int retval; - - retval = usb_control_msg (dev->udev, - usb_sndctrlpipe (dev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - value, - 0, // index - 0, // data buffer - 0, // size - CONTROL_TIMEOUT_MS); - return retval; -} - -static void gl_interrupt_complete (struct urb *urb, struct pt_regs *regs) -{ - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __FUNCTION__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); - } - - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -static int gl_interrupt_read (struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - int retval; - - // issue usb interrupt read - if (priv && priv->irq_urb) { - // submit urb - if ((retval = usb_submit_urb (priv->irq_urb, GFP_KERNEL)) != 0) - dbg ("gl_interrupt_read: submit fail - %X...", retval); - else - dbg ("gl_interrupt_read: submit success..."); - } - - return 0; -} - -// check whether another side is connected -static int genelink_check_connect (struct usbnet *dev) -{ - int retval; - - dbg ("genelink_check_connect..."); - - // detect whether another side is connected - if ((retval = gl_control_write (dev, GENELINK_CONNECT_WRITE, 0)) != 0) { - dbg ("%s: genelink_check_connect write fail - %X", - dev->net->name, retval); - return retval; - } - - // usb interrupt read to ack another side - if ((retval = gl_interrupt_read (dev)) != 0) { - dbg ("%s: genelink_check_connect read fail - %X", - dev->net->name, retval); - return retval; - } - - dbg ("%s: genelink_check_connect read success", dev->net->name); - return 0; -} - -// allocate and initialize the private data for genelink -static int genelink_init (struct usbnet *dev) -{ - struct gl_priv *priv; - - // allocate the private data structure - if ((priv = kmalloc (sizeof *priv, GFP_KERNEL)) == 0) { - dbg ("%s: cannot allocate private data per device", - dev->net->name); - return -ENOMEM; - } - - // allocate irq urb - if ((priv->irq_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { - dbg ("%s: cannot allocate private irq urb per device", - dev->net->name); - kfree (priv); - return -ENOMEM; - } - - // fill irq urb - usb_fill_int_urb (priv->irq_urb, dev->udev, - usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE), - priv->irq_buf, INTERRUPT_BUFSIZE, - gl_interrupt_complete, 0, - GENELINK_INTERRUPT_INTERVAL); - - // set private data pointer - dev->priv_data = priv; - - return 0; -} - -// release the private data -static int genelink_free (struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - - if (!priv) - return 0; - -// FIXME: can't cancel here; it's synchronous, and -// should have happened earlier in any case (interrupt -// handling needs to be generic) - - // cancel irq urb first - usb_kill_urb (priv->irq_urb); - - // free irq urb - usb_free_urb (priv->irq_urb); - - // free the private data structure - kfree (priv); - - return 0; -} - -#endif - -static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) -{ - struct gl_header *header; - struct gl_packet *packet; - struct sk_buff *gl_skb; - u32 size; - - header = (struct gl_header *) skb->data; - - // get the packet count of the received skb - le32_to_cpus (&header->packet_count); - if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) - || (header->packet_count < 0)) { - dbg ("genelink: invalid received packet count %d", - header->packet_count); - return 0; - } - - // set the current packet pointer to the first packet - packet = &header->packets; - - // decrement the length for the packet count size 4 bytes - skb_pull (skb, 4); - - while (header->packet_count > 1) { - // get the packet length - size = packet->packet_length; - - // this may be a broken packet - if (size > GL_MAX_PACKET_LEN) { - dbg ("genelink: invalid rx length %d", size); - return 0; - } - - // allocate the skb for the individual packet - gl_skb = alloc_skb (size, GFP_ATOMIC); - if (gl_skb) { - - // copy the packet data to the new skb - memcpy(skb_put(gl_skb, size), packet->packet_data, size); - usbnet_skb_return (dev, gl_skb); - } - - // advance to the next packet - packet = (struct gl_packet *) - &packet->packet_data [size]; - header->packet_count--; - - // shift the data pointer to the next gl_packet - skb_pull (skb, size + 4); - } - - // skip the packet length field 4 bytes - skb_pull (skb, 4); - - if (skb->len > GL_MAX_PACKET_LEN) { - dbg ("genelink: invalid rx length %d", skb->len); - return 0; - } - return 1; -} - -static struct sk_buff * -genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) -{ - int padlen; - int length = skb->len; - int headroom = skb_headroom (skb); - int tailroom = skb_tailroom (skb); - u32 *packet_count; - u32 *packet_len; - - // FIXME: magic numbers, bleech - padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; - - if ((!skb_cloned (skb)) - && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { - if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { - skb->data = memmove (skb->head + (4 + 4*1), - skb->data, skb->len); - skb->tail = skb->data + skb->len; - } - } else { - struct sk_buff *skb2; - skb2 = skb_copy_expand (skb, (4 + 4*1) , padlen, flags); - dev_kfree_skb_any (skb); - skb = skb2; - if (!skb) - return NULL; - } - - // attach the packet count to the header - packet_count = (u32 *) skb_push (skb, (4 + 4*1)); - packet_len = packet_count + 1; - - // FIXME little endian? - *packet_count = 1; - *packet_len = length; - - // add padding byte - if ((skb->len % dev->maxpacket) == 0) - skb_put (skb, 1); - - return skb; -} - -static int genelink_bind (struct usbnet *dev, struct usb_interface *intf) -{ - dev->hard_mtu = GL_RCV_BUF_SIZE; - dev->net->hard_header_len += 4; - return 0; -} - -static const struct driver_info genelink_info = { - .description = "Genesys GeneLink", - .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, - .bind = genelink_bind, - .rx_fixup = genelink_rx_fixup, - .tx_fixup = genelink_tx_fixup, - - .in = 1, .out = 2, - -#ifdef GENELINK_ACK - .check_connect =genelink_check_connect, -#endif -}; - -#endif /* CONFIG_USB_GENESYS */ - - #ifdef CONFIG_USB_PL2301 #define HAVE_HARDWARE @@ -1059,7 +721,7 @@ pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, val, index, NULL, 0, - CONTROL_TIMEOUT_MS); + USB_CTRL_GET_TIMEOUT); } static inline int @@ -2323,16 +1985,6 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static const struct usb_device_id products [] = { -#ifdef CONFIG_USB_GENESYS -{ - USB_DEVICE (0x05e3, 0x0502), // GL620USB-A - .driver_info = (unsigned long) &genelink_info, -}, - /* NOT: USB_DEVICE (0x05e3, 0x0501), // GL620USB - * that's half duplex, not currently supported - */ -#endif - #ifdef CONFIG_USB_PL2301 { USB_DEVICE (0x067b, 0x0000), // PL-2301 -- cgit v1.2.3-70-g09d2 From 0aa599c5644fddd3052433c5335260108a8a39a2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:53:58 -0700 Subject: [PATCH] USB: usbnet (6/9) module for Zaurii and compatibles This moves usbnet support for Zaurus and compatibles into its own module. Other than exporting a couple of helper functions, this just involved shuffling some code and updating the comments. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 34 ++--- drivers/usb/net/Makefile | 1 + drivers/usb/net/usbnet.c | 357 +------------------------------------------ drivers/usb/net/usbnet.h | 22 +++ drivers/usb/net/zaurus.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 433 insertions(+), 367 deletions(-) create mode 100644 drivers/usb/net/zaurus.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 0aafd599d7d..20de10916a4 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -140,23 +140,6 @@ config USB_PL2301 comment "Intelligent USB Devices/Gadgets" depends on USB_USBNET -config USB_ZAURUS - boolean "Sharp Zaurus (stock ROMs) and compatible" - depends on USB_USBNET - select CRC32 - default y - help - Choose this option to support the usb networking links used by - Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. - This also supports some related device firmware, as used in some - PDAs from Olympus and some cell phones from Motorola. - - If you install an alternate ROM image, such as the Linux 2.6 based - versions of OpenZaurus, you should no longer need to support this - protocol. Only the "eth-fd" or "net_fd" drivers in these devices - really need this non-conformant variant of CDC Ethernet (or in - some cases CDC MDLM) protocol, not "g_ether". - config USB_CDCETHER boolean "CDC Ethernet support (smart devices such as cable modems)" depends on USB_USBNET @@ -294,6 +277,23 @@ config USB_EPSON2888 Choose this option to support the usb networking links used by some sample firmware from Epson. +config USB_NET_ZAURUS + tristate "Sharp Zaurus (stock ROMs) and compatible" + depends on USB_USBNET + select CRC32 + default y + help + Choose this option to support the usb networking links used by + Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. + This also supports some related device firmware, as used in some + PDAs from Olympus and some cell phones from Motorola. + + If you install an alternate ROM image, such as the Linux 2.6 based + versions of OpenZaurus, you should no longer need to support this + protocol. Only the "eth-fd" or "net_fd" drivers in these devices + really need this non-conformant variant of CDC Ethernet (or in + some cases CDC MDLM) protocol, not "g_ether". + config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index f9b181e91c1..e13d7af3114 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o +obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o obj-$(CONFIG_USB_USBNET) += usbnet.o obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index d52480aced8..75a05ab0a64 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,7 +1,6 @@ /* * USB Networking Links * Copyright (C) 2000-2005 by David Brownell - * Copyright (C) 2002 Pavel Machek * Copyright (C) 2003-2005 David Hollis * * This program is free software; you can redistribute it and/or modify @@ -173,14 +172,6 @@ MODULE_PARM_DESC (msg_level, "Override default message level"); /*-------------------------------------------------------------------------*/ -static u32 usbnet_get_link (struct net_device *); - -/* mostly for PDA style devices, which are always connected if present */ -static int always_connected (struct usbnet *dev) -{ - return 0; -} - /* handles CDC Ethernet and many other network "bulk data" interfaces */ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { @@ -321,7 +312,7 @@ EXPORT_SYMBOL_GPL(usbnet_skb_return); #define NEED_GENERIC_CDC #endif -#ifdef CONFIG_USB_ZAURUS +#if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_ZAURUS_MODULE) /* Ethernet variant uses funky framing, broken ethernet addressing */ #define NEED_GENERIC_CDC #endif @@ -336,14 +327,6 @@ EXPORT_SYMBOL_GPL(usbnet_skb_return); #include -struct cdc_state { - struct usb_cdc_header_desc *header; - struct usb_cdc_union_desc *u; - struct usb_cdc_ether_desc *ether; - struct usb_interface *control; - struct usb_interface *data; -}; - static struct usb_driver usbnet_driver; /* @@ -351,7 +334,7 @@ static struct usb_driver usbnet_driver; * endpoints, activates data interface (if needed), maybe sets MTU. * all pure cdc, except for certain firmware workarounds. */ -static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) +int usbnet_generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) { u8 *buf = intf->cur_altsetting->extra; int len = intf->cur_altsetting->extralen; @@ -530,8 +513,9 @@ bad_desc: dev_info (&dev->udev->dev, "bad CDC descriptors\n"); return -ENODEV; } +EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); -static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) +void usbnet_cdc_unbind (struct usbnet *dev, struct usb_interface *intf) { struct cdc_state *info = (void *) &dev->data; @@ -551,6 +535,7 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) info->control = NULL; } } +EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); #endif /* NEED_GENERIC_CDC */ @@ -657,7 +642,7 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) int status; struct cdc_state *info = (void *) &dev->data; - status = generic_cdc_bind (dev, intf); + status = usbnet_generic_cdc_bind (dev, intf); if (status < 0) return status; @@ -679,7 +664,7 @@ static const struct driver_info cdc_info = { .flags = FLAG_ETHER, // .check_connect = cdc_check_connect, .bind = cdc_bind, - .unbind = cdc_unbind, + .unbind = usbnet_cdc_unbind, .status = cdc_status, }; @@ -757,239 +742,6 @@ static const struct driver_info prolific_info = { #endif /* CONFIG_USB_PL2301 */ - -#ifdef CONFIG_USB_ZAURUS -#define HAVE_HARDWARE - -#include - -/*------------------------------------------------------------------------- - * - * Zaurus is also a SA-1110 based PDA, but one using a different driver - * (and framing) for its USB slave/gadget controller than the case above. - * - * For the current version of that driver, the main way that framing is - * nonstandard (also from perspective of the CDC ethernet model!) is a - * crc32, added to help detect when some sa1100 usb-to-memory DMA errata - * haven't been fully worked around. Also, all Zaurii use the same - * default Ethernet address. - * - * PXA based models use the same framing, and also can't implement - * set_interface properly. - * - * All known Zaurii lie about their standards conformance. Most lie by - * saying they support CDC Ethernet. Some lie and say they support CDC - * MDLM (as if for access to cell phone modems). Someone, please beat - * on Sharp (and other such vendors) for a while with a cluestick. - * - *-------------------------------------------------------------------------*/ - -static struct sk_buff * -zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, unsigned flags) -{ - int padlen; - struct sk_buff *skb2; - - padlen = 2; - if (!skb_cloned (skb)) { - int tailroom = skb_tailroom (skb); - if ((padlen + 4) <= tailroom) - goto done; - } - skb2 = skb_copy_expand (skb, 0, 4 + padlen, flags); - dev_kfree_skb_any (skb); - skb = skb2; - if (skb) { - u32 fcs; -done: - fcs = crc32_le (~0, skb->data, skb->len); - fcs = ~fcs; - - *skb_put (skb, 1) = fcs & 0xff; - *skb_put (skb, 1) = (fcs>> 8) & 0xff; - *skb_put (skb, 1) = (fcs>>16) & 0xff; - *skb_put (skb, 1) = (fcs>>24) & 0xff; - } - return skb; -} - -static int zaurus_bind (struct usbnet *dev, struct usb_interface *intf) -{ - /* Belcarra's funky framing has other options; mostly - * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. - */ - dev->net->hard_header_len += 6; - return generic_cdc_bind(dev, intf); -} - -static const struct driver_info zaurus_sl5x00_info = { - .description = "Sharp Zaurus SL-5x00", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) - -static const struct driver_info zaurus_pxa_info = { - .description = "Sharp Zaurus, PXA-2xx based", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) - -static const struct driver_info olympus_mxl_info = { - .description = "Olympus R1000", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .bind = zaurus_bind, - .unbind = cdc_unbind, - .tx_fixup = zaurus_tx_fixup, -}; -#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) - - -/* Some more recent products using Lineo/Belcarra code will wrongly claim - * CDC MDLM conformance. They aren't conformant: data endpoints live - * in the control interface, there's no data interface, and it's not used - * to talk to a cell phone radio. But at least we can detect these two - * pseudo-classes, rather than growing this product list with entries for - * each new nonconformant product (sigh). - */ -static const u8 safe_guid[16] = { - 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, - 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, -}; -static const u8 blan_guid[16] = { - 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, - 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, -}; - -static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf) -{ - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_cdc_mdlm_desc *desc = NULL; - struct usb_cdc_mdlm_detail_desc *detail = NULL; - - while (len > 3) { - if (buf [1] != USB_DT_CS_INTERFACE) - goto next_desc; - - /* use bDescriptorSubType, and just verify that we get a - * "BLAN" (or "SAFE") descriptor. - */ - switch (buf [2]) { - case USB_CDC_MDLM_TYPE: - if (desc) { - dev_dbg (&intf->dev, "extra MDLM\n"); - goto bad_desc; - } - desc = (void *) buf; - if (desc->bLength != sizeof *desc) { - dev_dbg (&intf->dev, "MDLM len %u\n", - desc->bLength); - goto bad_desc; - } - /* expect bcdVersion 1.0, ignore */ - if (memcmp(&desc->bGUID, blan_guid, 16) - && memcmp(&desc->bGUID, safe_guid, 16) ) { - /* hey, this one might _really_ be MDLM! */ - dev_dbg (&intf->dev, "MDLM guid\n"); - goto bad_desc; - } - break; - case USB_CDC_MDLM_DETAIL_TYPE: - if (detail) { - dev_dbg (&intf->dev, "extra MDLM detail\n"); - goto bad_desc; - } - detail = (void *) buf; - switch (detail->bGuidDescriptorType) { - case 0: /* "SAFE" */ - if (detail->bLength != (sizeof *detail + 2)) - goto bad_detail; - break; - case 1: /* "BLAN" */ - if (detail->bLength != (sizeof *detail + 3)) - goto bad_detail; - break; - default: - goto bad_detail; - } - - /* assuming we either noticed BLAN already, or will - * find it soon, there are some data bytes here: - * - bmNetworkCapabilities (unused) - * - bmDataCapabilities (bits, see below) - * - bPad (ignored, for PADAFTER -- BLAN-only) - * bits are: - * - 0x01 -- Zaurus framing (add CRC) - * - 0x02 -- PADBEFORE (CRC includes some padding) - * - 0x04 -- PADAFTER (some padding after CRC) - * - 0x08 -- "fermat" packet mangling (for hw bugs) - * the PADBEFORE appears not to matter; we interop - * with devices that use it and those that don't. - */ - if ((detail->bDetailData[1] & ~02) != 0x01) { - /* bmDataCapabilites == 0 would be fine too, - * but framing is minidriver-coupled for now. - */ -bad_detail: - dev_dbg (&intf->dev, - "bad MDLM detail, %d %d %d\n", - detail->bLength, - detail->bDetailData[0], - detail->bDetailData[2]); - goto bad_desc; - } - break; - } -next_desc: - len -= buf [0]; /* bLength */ - buf += buf [0]; - } - - if (!desc || !detail) { - dev_dbg (&intf->dev, "missing cdc mdlm %s%sdescriptor\n", - desc ? "" : "func ", - detail ? "" : "detail "); - goto bad_desc; - } - - /* There's probably a CDC Ethernet descriptor there, but we can't - * rely on the Ethernet address it provides since not all vendors - * bother to make it unique. Likewise there's no point in tracking - * of the CDC event notifications. - */ - return usbnet_get_endpoints (dev, intf); - -bad_desc: - dev_info (&dev->udev->dev, "unsupported MDLM descriptors\n"); - return -ENODEV; -} - -static const struct driver_info bogus_mdlm_info = { - .description = "pseudo-MDLM (BLAN) device", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .tx_fixup = zaurus_tx_fixup, - .bind = blan_mdlm_bind, -}; - -#else - -/* blacklist all those devices */ -#define ZAURUS_STRONGARM_INFO 0 -#define ZAURUS_PXA_INFO 0 -#define OLYMPUS_MXL_INFO 0 - -#endif - /*------------------------------------------------------------------------- * @@ -2003,101 +1755,6 @@ static const struct usb_device_id products [] = { }, #endif -#if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_CDCETHER) -/* - * SA-1100 based Sharp Zaurus ("collie"), or compatible. - * Same idea as above, but different framing. - * - * PXA-2xx based models are also lying-about-cdc. - * Some models don't even tell the same lies ... - * - * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries, - * unlike the older ones with 2.4 "embedix" kernels. - * - * NOTE: These entries do double-duty, serving as blacklist entries - * whenever Zaurus support isn't enabled, but CDC Ethernet is. - */ -#define ZAURUS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ - .bInterfaceProtocol = USB_CDC_PROTO_NONE -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8004, - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_STRONGARM_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8005, /* A-300 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8006, /* B-500/SL-5600 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8007, /* C-700 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9031, /* C-750 C-760 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x9032, /* SL-6000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - /* reported with some C860 units */ - .idProduct = 0x9050, /* C-860 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = ZAURUS_PXA_INFO, -}, - -#ifdef CONFIG_USB_ZAURUS - /* At least some (reports vary) PXA units have very different lies - * about their standards support: they claim to be cell phones with - * direct access to their radios. (They don't conform to CDC MDLM.) - */ -{ - USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &bogus_mdlm_info, -}, -#endif - -/* Olympus has some models with a Zaurus-compatible option. - * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x07B4, - .idProduct = 0x0F02, /* R-1000 */ - ZAURUS_MASTER_INTERFACE, - .driver_info = OLYMPUS_MXL_INFO, -}, -#endif - #ifdef CONFIG_USB_CDCETHER { /* CDC Ether uses two interfaces, not necessarily consecutive. diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 21b5feb54fc..7aa0abd1a9b 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -126,6 +126,28 @@ extern int usbnet_resume (struct usb_interface *); extern void usbnet_disconnect(struct usb_interface *); +/* Drivers that reuse some of the standard USB CDC infrastructure + * (notably, using multiple interfaces according to the the CDC + * union descriptor) get some helper code. + */ +struct cdc_state { + struct usb_cdc_header_desc *header; + struct usb_cdc_union_desc *u; + struct usb_cdc_ether_desc *ether; + struct usb_interface *control; + struct usb_interface *data; +}; + +extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *); +extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *); + +/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ + |USB_CDC_PACKET_TYPE_DIRECTED) + + /* we record the state for each of our queued skbs */ enum skb_state { illegal = 0, diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c new file mode 100644 index 00000000000..ee3b892aeab --- /dev/null +++ b/drivers/usb/net/zaurus.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2002 Pavel Machek + * Copyright (C) 2002-2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * All known Zaurii lie about their standards conformance. At least + * the earliest SA-1100 models lie by saying they support CDC Ethernet. + * Some later models (especially PXA-25x and PXA-27x based ones) lie + * and say they support CDC MDLM (for access to cell phone modems). + * + * There are non-Zaurus products that use these same protocols too. + * + * The annoying thing is that at the same time Sharp was developing + * that annoying standards-breaking software, the Linux community had + * a simple "CDC Subset" working reliably on the same SA-1100 hardware. + * That is, the same functionality but not violating standards. + * + * The CDC Ethernet nonconformance points are troublesome to hosts + * with a true CDC Ethernet implementation: + * - Framing appends a CRC, which the spec says drivers "must not" do; + * - Transfers data in altsetting zero, instead of altsetting 1; + * - All these peripherals use the same ethernet address. + * + * The CDC MDLM nonconformance is less immediately troublesome, since all + * MDLM implementations are quasi-proprietary anyway. + */ + +static struct sk_buff * +zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +{ + int padlen; + struct sk_buff *skb2; + + padlen = 2; + if (!skb_cloned(skb)) { + int tailroom = skb_tailroom(skb); + if ((padlen + 4) <= tailroom) + goto done; + } + skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (skb) { + u32 fcs; +done: + fcs = crc32_le(~0, skb->data, skb->len); + fcs = ~fcs; + + *skb_put (skb, 1) = fcs & 0xff; + *skb_put (skb, 1) = (fcs>> 8) & 0xff; + *skb_put (skb, 1) = (fcs>>16) & 0xff; + *skb_put (skb, 1) = (fcs>>24) & 0xff; + } + return skb; +} + +static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf) +{ + /* Belcarra's funky framing has other options; mostly + * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. + */ + dev->net->hard_header_len += 6; + dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; + return usbnet_generic_cdc_bind(dev, intf); +} + +/* PDA style devices are always connected if present */ +static int always_connected (struct usbnet *dev) +{ + return 0; +} + +static const struct driver_info zaurus_sl5x00_info = { + .description = "Sharp Zaurus SL-5x00", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .bind = zaurus_bind, + .unbind = usbnet_cdc_unbind, + .tx_fixup = zaurus_tx_fixup, +}; +#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) + +static const struct driver_info zaurus_pxa_info = { + .description = "Sharp Zaurus, PXA-2xx based", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .bind = zaurus_bind, + .unbind = usbnet_cdc_unbind, + .tx_fixup = zaurus_tx_fixup, +}; +#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) + +static const struct driver_info olympus_mxl_info = { + .description = "Olympus R1000", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .bind = zaurus_bind, + .unbind = usbnet_cdc_unbind, + .tx_fixup = zaurus_tx_fixup, +}; +#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) + + +/* Some more recent products using Lineo/Belcarra code will wrongly claim + * CDC MDLM conformance. They aren't conformant: data endpoints live + * in the control interface, there's no data interface, and it's not used + * to talk to a cell phone radio. But at least we can detect these two + * pseudo-classes, rather than growing this product list with entries for + * each new nonconformant product (sigh). + */ +static const u8 safe_guid[16] = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, +}; +static const u8 blan_guid[16] = { + 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, + 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, +}; + +static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) +{ + u8 *buf = intf->cur_altsetting->extra; + int len = intf->cur_altsetting->extralen; + struct usb_cdc_mdlm_desc *desc = NULL; + struct usb_cdc_mdlm_detail_desc *detail = NULL; + + while (len > 3) { + if (buf [1] != USB_DT_CS_INTERFACE) + goto next_desc; + + /* use bDescriptorSubType, and just verify that we get a + * "BLAN" (or "SAFE") descriptor. + */ + switch (buf [2]) { + case USB_CDC_MDLM_TYPE: + if (desc) { + dev_dbg(&intf->dev, "extra MDLM\n"); + goto bad_desc; + } + desc = (void *) buf; + if (desc->bLength != sizeof *desc) { + dev_dbg(&intf->dev, "MDLM len %u\n", + desc->bLength); + goto bad_desc; + } + /* expect bcdVersion 1.0, ignore */ + if (memcmp(&desc->bGUID, blan_guid, 16) + && memcmp(&desc->bGUID, safe_guid, 16) ) { + /* hey, this one might _really_ be MDLM! */ + dev_dbg(&intf->dev, "MDLM guid\n"); + goto bad_desc; + } + break; + case USB_CDC_MDLM_DETAIL_TYPE: + if (detail) { + dev_dbg(&intf->dev, "extra MDLM detail\n"); + goto bad_desc; + } + detail = (void *) buf; + switch (detail->bGuidDescriptorType) { + case 0: /* "SAFE" */ + if (detail->bLength != (sizeof *detail + 2)) + goto bad_detail; + break; + case 1: /* "BLAN" */ + if (detail->bLength != (sizeof *detail + 3)) + goto bad_detail; + break; + default: + goto bad_detail; + } + + /* assuming we either noticed BLAN already, or will + * find it soon, there are some data bytes here: + * - bmNetworkCapabilities (unused) + * - bmDataCapabilities (bits, see below) + * - bPad (ignored, for PADAFTER -- BLAN-only) + * bits are: + * - 0x01 -- Zaurus framing (add CRC) + * - 0x02 -- PADBEFORE (CRC includes some padding) + * - 0x04 -- PADAFTER (some padding after CRC) + * - 0x08 -- "fermat" packet mangling (for hw bugs) + * the PADBEFORE appears not to matter; we interop + * with devices that use it and those that don't. + */ + if ((detail->bDetailData[1] & ~0x02) != 0x01) { + /* bmDataCapabilites == 0 would be fine too, + * but framing is minidriver-coupled for now. + */ +bad_detail: + dev_dbg(&intf->dev, + "bad MDLM detail, %d %d %d\n", + detail->bLength, + detail->bDetailData[0], + detail->bDetailData[2]); + goto bad_desc; + } + break; + } +next_desc: + len -= buf [0]; /* bLength */ + buf += buf [0]; + } + + if (!desc || !detail) { + dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n", + desc ? "" : "func ", + detail ? "" : "detail "); + goto bad_desc; + } + + /* There's probably a CDC Ethernet descriptor there, but we can't + * rely on the Ethernet address it provides since not all vendors + * bother to make it unique. Likewise there's no point in tracking + * of the CDC event notifications. + */ + return usbnet_get_endpoints(dev, intf); + +bad_desc: + dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); + return -ENODEV; +} + +static const struct driver_info bogus_mdlm_info = { + .description = "pseudo-MDLM (BLAN) device", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .tx_fixup = zaurus_tx_fixup, + .bind = blan_mdlm_bind, +}; + +static const struct usb_device_id products [] = { +#define ZAURUS_MASTER_INTERFACE \ + .bInterfaceClass = USB_CLASS_COMM, \ + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ + .bInterfaceProtocol = USB_CDC_PROTO_NONE + +/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */ +{ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8004, + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_STRONGARM_INFO, +}, + +/* PXA-2xx based models are also lying-about-cdc. If you add any + * more devices that claim to be CDC Ethernet, make sure they get + * added to the blacklist in cdc_ether too. + * + * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries, + * unlike the older ones with 2.4 "embedix" kernels. + */ +{ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8005, /* A-300 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8006, /* B-500/SL-5600 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8007, /* C-700 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9031, /* C-750 C-760 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9032, /* SL-6000 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + /* reported with some C860 units */ + .idProduct = 0x9050, /* C-860 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = ZAURUS_PXA_INFO, +}, + + +/* At least some of the newest PXA units have very different lies about + * their standards support: they claim to be cell phones offering + * direct access to their radios! (No, they don't conform to CDC MDLM.) + */ +{ + USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &bogus_mdlm_info, +}, + +/* Olympus has some models with a Zaurus-compatible option. + * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) + */ +{ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x07B4, + .idProduct = 0x0F02, /* R-1000 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = OLYMPUS_MXL_INFO, +}, + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver zaurus_driver = { + .owner = THIS_MODULE, + .name = "zaurus", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init zaurus_init(void) +{ + return usb_register(&zaurus_driver); +} +module_init(zaurus_init); + +static void __exit zaurus_exit(void) +{ + usb_deregister(&zaurus_driver); +} +module_exit(zaurus_exit); + +MODULE_AUTHOR("Pavel Machek, David Brownell"); +MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 4324fd493430c0ab99dd7e89d50540b5e70f8098 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:54:20 -0700 Subject: [PATCH] USB: usbnet (7/9) module for CDC Ethernet Makes the CDC Ethernet support live in a separate driver module. This module is a bit special since it exports utility functions that are reused by the the Zaurus and RNDIS drivers, but it's not "core" like usbnet itself. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 56 +++-- drivers/usb/net/Makefile | 1 + drivers/usb/net/cdc_ether.c | 509 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 392 ---------------------------------- 4 files changed, 537 insertions(+), 421 deletions(-) create mode 100644 drivers/usb/net/cdc_ether.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 20de10916a4..4921101d93d 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -137,35 +137,6 @@ config USB_PL2301 Choose this option if you're using a host-to-host cable with one of these chips. -comment "Intelligent USB Devices/Gadgets" - depends on USB_USBNET - -config USB_CDCETHER - boolean "CDC Ethernet support (smart devices such as cable modems)" - depends on USB_USBNET - default y - help - This option supports devices conforming to the Communication Device - Class (CDC) Ethernet Control Model, a specification that's easy to - implement in device firmware. The CDC specifications are available - from . - - CDC Ethernet is an implementation option for DOCSIS cable modems - that support USB connectivity, used for non-Microsoft USB hosts. - The Linux-USB CDC Ethernet Gadget driver is an open implementation. - This driver should work with at least the following devices: - - * Ericsson PipeRider (all variants) - * Motorola (DM100 and SB4100) - * Broadcom Cable Modem (reference design) - * Toshiba PCX1100U - * ... - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. However, if the - IEEE 802 "local assignment" bit is set in the address, a "usbX" - name is used instead. - comment "Drivers built using the usbnet core" config USB_NET_AX8817X @@ -197,6 +168,32 @@ config USB_NET_AX8817X what other networking devices you have in use. +config USB_NET_CDCETHER + tristate "CDC Ethernet support (smart devices such as cable modems)" + depends on USB_USBNET + default y + help + This option supports devices conforming to the Communication Device + Class (CDC) Ethernet Control Model, a specification that's easy to + implement in device firmware. The CDC specifications are available + from . + + CDC Ethernet is an implementation option for DOCSIS cable modems + that support USB connectivity, used for non-Microsoft USB hosts. + The Linux-USB CDC Ethernet Gadget driver is an open implementation. + This driver should work with at least the following devices: + + * Ericsson PipeRider (all variants) + * Motorola (DM100 and SB4100) + * Broadcom Cable Modem (reference design) + * Toshiba PCX1100U + * ... + + This driver creates an interface named "ethX", where X depends on + what other networking devices you have in use. However, if the + IEEE 802 "local assignment" bit is set in the address, a "usbX" + name is used instead. + config USB_NET_GL620A tristate "GeneSys GL620USB-A based cables" depends on USB_USBNET @@ -280,6 +277,7 @@ config USB_EPSON2888 config USB_NET_ZAURUS tristate "Sharp Zaurus (stock ROMs) and compatible" depends on USB_USBNET + select USB_NET_CDCETHER select CRC32 default y help diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index e13d7af3114..697eb191320 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o +obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c new file mode 100644 index 00000000000..652b04bbf6a --- /dev/null +++ b/drivers/usb/net/cdc_ether.c @@ -0,0 +1,509 @@ +/* + * CDC Ethernet based networking peripherals + * Copyright (C) 2003-2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * probes control interface, claims data interface, collects the bulk + * endpoints, activates data interface (if needed), maybe sets MTU. + * all pure cdc, except for certain firmware workarounds, and knowing + * that rndis uses one different rule. + */ +int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) +{ + u8 *buf = intf->cur_altsetting->extra; + int len = intf->cur_altsetting->extralen; + struct usb_interface_descriptor *d; + struct cdc_state *info = (void *) &dev->data; + int status; + int rndis; + struct usb_driver *driver = driver_of(intf); + + if (sizeof dev->data < sizeof *info) + return -EDOM; + + /* expect strict spec conformance for the descriptors, but + * cope with firmware which stores them in the wrong place + */ + if (len == 0 && dev->udev->actconfig->extralen) { + /* Motorola SB4100 (and others: Brad Hards says it's + * from a Broadcom design) put CDC descriptors here + */ + buf = dev->udev->actconfig->extra; + len = dev->udev->actconfig->extralen; + if (len) + dev_dbg(&intf->dev, + "CDC descriptors on config\n"); + } + + /* this assumes that if there's a non-RNDIS vendor variant + * of cdc-acm, it'll fail RNDIS requests cleanly. + */ + rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); + + memset(info, 0, sizeof *info); + info->control = intf; + while (len > 3) { + if (buf [1] != USB_DT_CS_INTERFACE) + goto next_desc; + + /* use bDescriptorSubType to identify the CDC descriptors. + * We expect devices with CDC header and union descriptors. + * For CDC Ethernet we need the ethernet descriptor. + * For RNDIS, ignore two (pointless) CDC modem descriptors + * in favor of a complicated OID-based RPC scheme doing what + * CDC Ethernet achieves with a simple descriptor. + */ + switch (buf [2]) { + case USB_CDC_HEADER_TYPE: + if (info->header) { + dev_dbg(&intf->dev, "extra CDC header\n"); + goto bad_desc; + } + info->header = (void *) buf; + if (info->header->bLength != sizeof *info->header) { + dev_dbg(&intf->dev, "CDC header len %u\n", + info->header->bLength); + goto bad_desc; + } + break; + case USB_CDC_UNION_TYPE: + if (info->u) { + dev_dbg(&intf->dev, "extra CDC union\n"); + goto bad_desc; + } + info->u = (void *) buf; + if (info->u->bLength != sizeof *info->u) { + dev_dbg(&intf->dev, "CDC union len %u\n", + info->u->bLength); + goto bad_desc; + } + + /* we need a master/control interface (what we're + * probed with) and a slave/data interface; union + * descriptors sort this all out. + */ + info->control = usb_ifnum_to_if(dev->udev, + info->u->bMasterInterface0); + info->data = usb_ifnum_to_if(dev->udev, + info->u->bSlaveInterface0); + if (!info->control || !info->data) { + dev_dbg(&intf->dev, + "master #%u/%p slave #%u/%p\n", + info->u->bMasterInterface0, + info->control, + info->u->bSlaveInterface0, + info->data); + goto bad_desc; + } + if (info->control != intf) { + dev_dbg(&intf->dev, "bogus CDC Union\n"); + /* Ambit USB Cable Modem (and maybe others) + * interchanges master and slave interface. + */ + if (info->data == intf) { + info->data = info->control; + info->control = intf; + } else + goto bad_desc; + } + + /* a data interface altsetting does the real i/o */ + d = &info->data->cur_altsetting->desc; + if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { + dev_dbg(&intf->dev, "slave class %u\n", + d->bInterfaceClass); + goto bad_desc; + } + break; + case USB_CDC_ETHERNET_TYPE: + if (info->ether) { + dev_dbg(&intf->dev, "extra CDC ether\n"); + goto bad_desc; + } + info->ether = (void *) buf; + if (info->ether->bLength != sizeof *info->ether) { + dev_dbg(&intf->dev, "CDC ether len %u\n", + info->ether->bLength); + goto bad_desc; + } + dev->hard_mtu = le16_to_cpu( + info->ether->wMaxSegmentSize); + /* because of Zaurus, we may be ignoring the host + * side link address we were given. + */ + break; + } +next_desc: + len -= buf [0]; /* bLength */ + buf += buf [0]; + } + + if (!info->header || !info->u || (!rndis && !info->ether)) { + dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", + info->header ? "" : "header ", + info->u ? "" : "union ", + info->ether ? "" : "ether "); + goto bad_desc; + } + + /* claim data interface and set it up ... with side effects. + * network traffic can't flow until an altsetting is enabled. + */ + status = usb_driver_claim_interface(driver, info->data, dev); + if (status < 0) + return status; + status = usbnet_get_endpoints(dev, info->data); + if (status < 0) { + /* ensure immediate exit from usbnet_disconnect */ + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver, info->data); + return status; + } + + /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ + dev->status = NULL; + if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { + struct usb_endpoint_descriptor *desc; + + dev->status = &info->control->cur_altsetting->endpoint [0]; + desc = &dev->status->desc; + if (desc->bmAttributes != USB_ENDPOINT_XFER_INT + || !(desc->bEndpointAddress & USB_DIR_IN) + || (le16_to_cpu(desc->wMaxPacketSize) + < sizeof(struct usb_cdc_notification)) + || !desc->bInterval) { + dev_dbg(&intf->dev, "bad notification endpoint\n"); + dev->status = NULL; + } + } + if (rndis && !dev->status) { + dev_dbg(&intf->dev, "missing RNDIS status endpoint\n"); + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver, info->data); + return -ENODEV; + } + return 0; + +bad_desc: + dev_info(&dev->udev->dev, "bad CDC descriptors\n"); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); + +void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct cdc_state *info = (void *) &dev->data; + struct usb_driver *driver = driver_of(intf); + + /* disconnect master --> disconnect slave */ + if (intf == info->control && info->data) { + /* ensure immediate exit from usbnet_disconnect */ + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver, info->data); + info->data = NULL; + } + + /* and vice versa (just in case) */ + else if (intf == info->data && info->control) { + /* ensure immediate exit from usbnet_disconnect */ + usb_set_intfdata(info->control, NULL); + usb_driver_release_interface(driver, info->control); + info->control = NULL; + } +} +EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); + + +/*------------------------------------------------------------------------- + * + * Communications Device Class, Ethernet Control model + * + * Takes two interfaces. The DATA interface is inactive till an altsetting + * is selected. Configuration data includes class descriptors. There's + * an optional status endpoint on the control interface. + * + * This should interop with whatever the 2.4 "CDCEther.c" driver + * (by Brad Hards) talked with, with more functionality. + * + *-------------------------------------------------------------------------*/ + +static void dumpspeed(struct usbnet *dev, __le32 *speeds) +{ + if (netif_msg_timer(dev)) + devinfo(dev, "link speeds: %u kbps up, %u kbps down", + __le32_to_cpu(speeds[0]) / 1000, + __le32_to_cpu(speeds[1]) / 1000); +} + +static void cdc_status(struct usbnet *dev, struct urb *urb) +{ + struct usb_cdc_notification *event; + + if (urb->actual_length < sizeof *event) + return; + + /* SPEED_CHANGE can get split into two 8-byte packets */ + if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { + dumpspeed(dev, (__le32 *) urb->transfer_buffer); + return; + } + + event = urb->transfer_buffer; + switch (event->bNotificationType) { + case USB_CDC_NOTIFY_NETWORK_CONNECTION: + if (netif_msg_timer(dev)) + devdbg(dev, "CDC: carrier %s", + event->wValue ? "on" : "off"); + if (event->wValue) + netif_carrier_on(dev->net); + else + netif_carrier_off(dev->net); + break; + case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ + if (netif_msg_timer(dev)) + devdbg(dev, "CDC: speed change (len %d)", + urb->actual_length); + if (urb->actual_length != (sizeof *event + 8)) + set_bit(EVENT_STS_SPLIT, &dev->flags); + else + dumpspeed(dev, (__le32 *) &event[1]); + break; + /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), + * but there are no standard formats for the response data. + */ + default: + deverr(dev, "CDC: unexpected notification %02x!", + event->bNotificationType); + break; + } +} + +static u8 nibble(unsigned char c) +{ + if (likely(isdigit(c))) + return c - '0'; + c = toupper(c); + if (likely(isxdigit(c))) + return 10 + c - 'A'; + return 0; +} + +static inline int +get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) +{ + int tmp, i; + unsigned char buf [13]; + + tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); + if (tmp != 12) { + dev_dbg(&dev->udev->dev, + "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); + if (tmp >= 0) + tmp = -EINVAL; + return tmp; + } + for (i = tmp = 0; i < 6; i++, tmp += 2) + dev->net->dev_addr [i] = + (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); + return 0; +} + +static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int status; + struct cdc_state *info = (void *) &dev->data; + + status = usbnet_generic_cdc_bind(dev, intf); + if (status < 0) + return status; + + status = get_ethernet_addr(dev, info->ether); + if (status < 0) { + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver_of(intf), info->data); + return status; + } + + /* FIXME cdc-ether has some multicast code too, though it complains + * in routine cases. info->ether describes the multicast support. + * Implement that here, manipulating the cdc filter as needed. + */ + return 0; +} + +static const struct driver_info cdc_info = { + .description = "CDC Ethernet Device", + .flags = FLAG_ETHER, + // .check_connect = cdc_check_connect, + .bind = cdc_bind, + .unbind = usbnet_cdc_unbind, + .status = cdc_status, +}; + +/*-------------------------------------------------------------------------*/ + + +static const struct usb_device_id products [] = { +/* + * BLACKLIST !! + * + * First blacklist any products that are egregiously nonconformant + * with the CDC Ethernet specs. Minor braindamage we cope with; when + * they're not even trying, needing a separate driver is only the first + * of the differences to show up. + */ + +#define ZAURUS_MASTER_INTERFACE \ + .bInterfaceClass = USB_CLASS_COMM, \ + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ + .bInterfaceProtocol = USB_CDC_PROTO_NONE + +/* SA-1100 based Sharp Zaurus ("collie"), or compatible; + * wire-incompatible with true CDC Ethernet implementations. + * (And, it seems, needlessly so...) + */ +{ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8004, + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, + +/* PXA-25x based Sharp Zaurii. Note that it seems some of these + * (later models especially) may have shipped only with firmware + * advertising false "CDC MDLM" compatibility ... but we're not + * clear which models did that, so for now let's assume the worst. + */ +{ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8005, /* A-300 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8006, /* B-500/SL-5600 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8007, /* C-700 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9031, /* C-750 C-760 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9032, /* SL-6000 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + /* reported with some C860 units */ + .idProduct = 0x9050, /* C-860 */ + ZAURUS_MASTER_INTERFACE, + .driver_info = 0, +}, + +/* + * WHITELIST!!! + * + * CDC Ether uses two interfaces, not necessarily consecutive. + * We match the main interface, ignoring the optional device + * class so we could handle devices that aren't exclusively + * CDC ether. + * + * NOTE: this match must come AFTER entries blacklisting devices + * because of bugs/quirks in a given product (like Zaurus, above). + */ +{ + USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver cdc_driver = { + .owner = THIS_MODULE, + .name = "cdc_ether", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + + +static int __init cdc_init(void) +{ + BUG_ON((sizeof(((struct usbnet *)0)->data) + < sizeof(struct cdc_state))); + + return usb_register(&cdc_driver); +} +module_init(cdc_init); + +static void __exit cdc_exit(void) +{ + usb_deregister(&cdc_driver); +} +module_exit(cdc_exit); + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("USB CDC Ethernet devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 75a05ab0a64..7703725327d 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -300,377 +300,6 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(usbnet_skb_return); - -/*------------------------------------------------------------------------- - * - * Communications Device Class declarations. - * Used by CDC Ethernet, and some CDC variants - * - *-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_CDCETHER -#define NEED_GENERIC_CDC -#endif - -#if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_ZAURUS_MODULE) -/* Ethernet variant uses funky framing, broken ethernet addressing */ -#define NEED_GENERIC_CDC -#endif - -#ifdef CONFIG_USB_RNDIS -/* ACM variant uses even funkier framing, complex control RPC scheme */ -#define NEED_GENERIC_CDC -#endif - - -#ifdef NEED_GENERIC_CDC - -#include - -static struct usb_driver usbnet_driver; - -/* - * probes control interface, claims data interface, collects the bulk - * endpoints, activates data interface (if needed), maybe sets MTU. - * all pure cdc, except for certain firmware workarounds. - */ -int usbnet_generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) -{ - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_interface_descriptor *d; - struct cdc_state *info = (void *) &dev->data; - int status; - int rndis; - - if (sizeof dev->data < sizeof *info) - return -EDOM; - - /* expect strict spec conformance for the descriptors, but - * cope with firmware which stores them in the wrong place - */ - if (len == 0 && dev->udev->actconfig->extralen) { - /* Motorola SB4100 (and others: Brad Hards says it's - * from a Broadcom design) put CDC descriptors here - */ - buf = dev->udev->actconfig->extra; - len = dev->udev->actconfig->extralen; - if (len) - dev_dbg (&intf->dev, - "CDC descriptors on config\n"); - } - - /* this assumes that if there's a non-RNDIS vendor variant - * of cdc-acm, it'll fail RNDIS requests cleanly. - */ - rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); - - memset (info, 0, sizeof *info); - info->control = intf; - while (len > 3) { - if (buf [1] != USB_DT_CS_INTERFACE) - goto next_desc; - - /* use bDescriptorSubType to identify the CDC descriptors. - * We expect devices with CDC header and union descriptors. - * For CDC Ethernet we need the ethernet descriptor. - * For RNDIS, ignore two (pointless) CDC modem descriptors - * in favor of a complicated OID-based RPC scheme doing what - * CDC Ethernet achieves with a simple descriptor. - */ - switch (buf [2]) { - case USB_CDC_HEADER_TYPE: - if (info->header) { - dev_dbg (&intf->dev, "extra CDC header\n"); - goto bad_desc; - } - info->header = (void *) buf; - if (info->header->bLength != sizeof *info->header) { - dev_dbg (&intf->dev, "CDC header len %u\n", - info->header->bLength); - goto bad_desc; - } - break; - case USB_CDC_UNION_TYPE: - if (info->u) { - dev_dbg (&intf->dev, "extra CDC union\n"); - goto bad_desc; - } - info->u = (void *) buf; - if (info->u->bLength != sizeof *info->u) { - dev_dbg (&intf->dev, "CDC union len %u\n", - info->u->bLength); - goto bad_desc; - } - - /* we need a master/control interface (what we're - * probed with) and a slave/data interface; union - * descriptors sort this all out. - */ - info->control = usb_ifnum_to_if(dev->udev, - info->u->bMasterInterface0); - info->data = usb_ifnum_to_if(dev->udev, - info->u->bSlaveInterface0); - if (!info->control || !info->data) { - dev_dbg (&intf->dev, - "master #%u/%p slave #%u/%p\n", - info->u->bMasterInterface0, - info->control, - info->u->bSlaveInterface0, - info->data); - goto bad_desc; - } - if (info->control != intf) { - dev_dbg (&intf->dev, "bogus CDC Union\n"); - /* Ambit USB Cable Modem (and maybe others) - * interchanges master and slave interface. - */ - if (info->data == intf) { - info->data = info->control; - info->control = intf; - } else - goto bad_desc; - } - - /* a data interface altsetting does the real i/o */ - d = &info->data->cur_altsetting->desc; - if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { - dev_dbg (&intf->dev, "slave class %u\n", - d->bInterfaceClass); - goto bad_desc; - } - break; - case USB_CDC_ETHERNET_TYPE: - if (info->ether) { - dev_dbg (&intf->dev, "extra CDC ether\n"); - goto bad_desc; - } - info->ether = (void *) buf; - if (info->ether->bLength != sizeof *info->ether) { - dev_dbg (&intf->dev, "CDC ether len %u\n", - info->ether->bLength); - goto bad_desc; - } - dev->hard_mtu = le16_to_cpu( - info->ether->wMaxSegmentSize); - /* because of Zaurus, we may be ignoring the host - * side link address we were given. - */ - break; - } -next_desc: - len -= buf [0]; /* bLength */ - buf += buf [0]; - } - - if (!info->header || !info->u || (!rndis && !info->ether)) { - dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n", - info->header ? "" : "header ", - info->u ? "" : "union ", - info->ether ? "" : "ether "); - goto bad_desc; - } - - /* claim data interface and set it up ... with side effects. - * network traffic can't flow until an altsetting is enabled. - */ - status = usb_driver_claim_interface (&usbnet_driver, info->data, dev); - if (status < 0) - return status; - status = usbnet_get_endpoints (dev, info->data); - if (status < 0) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface (&usbnet_driver, info->data); - return status; - } - - /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ - dev->status = NULL; - if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { - struct usb_endpoint_descriptor *desc; - - dev->status = &info->control->cur_altsetting->endpoint [0]; - desc = &dev->status->desc; - if (desc->bmAttributes != USB_ENDPOINT_XFER_INT - || !(desc->bEndpointAddress & USB_DIR_IN) - || (le16_to_cpu(desc->wMaxPacketSize) - < sizeof (struct usb_cdc_notification)) - || !desc->bInterval) { - dev_dbg (&intf->dev, "bad notification endpoint\n"); - dev->status = NULL; - } - } - if (rndis && !dev->status) { - dev_dbg (&intf->dev, "missing RNDIS status endpoint\n"); - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface (&usbnet_driver, info->data); - return -ENODEV; - } - return 0; - -bad_desc: - dev_info (&dev->udev->dev, "bad CDC descriptors\n"); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); - -void usbnet_cdc_unbind (struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_state *info = (void *) &dev->data; - - /* disconnect master --> disconnect slave */ - if (intf == info->control && info->data) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface (&usbnet_driver, info->data); - info->data = NULL; - } - - /* and vice versa (just in case) */ - else if (intf == info->data && info->control) { - /* ensure immediate exit from usbnet_disconnect */ - usb_set_intfdata(info->control, NULL); - usb_driver_release_interface (&usbnet_driver, info->control); - info->control = NULL; - } -} -EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); - -#endif /* NEED_GENERIC_CDC */ - - -#ifdef CONFIG_USB_CDCETHER -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Communications Device Class, Ethernet Control model - * - * Takes two interfaces. The DATA interface is inactive till an altsetting - * is selected. Configuration data includes class descriptors. - * - * This should interop with whatever the 2.4 "CDCEther.c" driver - * (by Brad Hards) talked with. - * - *-------------------------------------------------------------------------*/ - -#include - - -static void dumpspeed (struct usbnet *dev, __le32 *speeds) -{ - if (netif_msg_timer (dev)) - devinfo (dev, "link speeds: %u kbps up, %u kbps down", - __le32_to_cpu(speeds[0]) / 1000, - __le32_to_cpu(speeds[1]) / 1000); -} - -static void cdc_status (struct usbnet *dev, struct urb *urb) -{ - struct usb_cdc_notification *event; - - if (urb->actual_length < sizeof *event) - return; - - /* SPEED_CHANGE can get split into two 8-byte packets */ - if (test_and_clear_bit (EVENT_STS_SPLIT, &dev->flags)) { - dumpspeed (dev, (__le32 *) urb->transfer_buffer); - return; - } - - event = urb->transfer_buffer; - switch (event->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - if (netif_msg_timer (dev)) - devdbg (dev, "CDC: carrier %s", - event->wValue ? "on" : "off"); - if (event->wValue) - netif_carrier_on(dev->net); - else - netif_carrier_off(dev->net); - break; - case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ - if (netif_msg_timer (dev)) - devdbg (dev, "CDC: speed change (len %d)", - urb->actual_length); - if (urb->actual_length != (sizeof *event + 8)) - set_bit (EVENT_STS_SPLIT, &dev->flags); - else - dumpspeed (dev, (__le32 *) &event[1]); - break; - // case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: /* RNDIS; or unsolicited */ - default: - deverr (dev, "CDC: unexpected notification %02x!", - event->bNotificationType); - break; - } -} - -static u8 nibble (unsigned char c) -{ - if (likely (isdigit (c))) - return c - '0'; - c = toupper (c); - if (likely (isxdigit (c))) - return 10 + c - 'A'; - return 0; -} - -static inline int -get_ethernet_addr (struct usbnet *dev, struct usb_cdc_ether_desc *e) -{ - int tmp, i; - unsigned char buf [13]; - - tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf); - if (tmp != 12) { - dev_dbg (&dev->udev->dev, - "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; - } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]); - return 0; -} - -static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) -{ - int status; - struct cdc_state *info = (void *) &dev->data; - - status = usbnet_generic_cdc_bind (dev, intf); - if (status < 0) - return status; - - status = get_ethernet_addr (dev, info->ether); - if (status < 0) { - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface (&usbnet_driver, info->data); - return status; - } - - /* FIXME cdc-ether has some multicast code too, though it complains - * in routine cases. info->ether describes the multicast support. - */ - return 0; -} - -static const struct driver_info cdc_info = { - .description = "CDC Ethernet Device", - .flags = FLAG_ETHER, - // .check_connect = cdc_check_connect, - .bind = cdc_bind, - .unbind = usbnet_cdc_unbind, - .status = cdc_status, -}; - -#endif /* CONFIG_USB_CDCETHER */ - - #ifdef CONFIG_USB_PL2301 #define HAVE_HARDWARE @@ -1754,23 +1383,6 @@ static const struct usb_device_id products [] = { .driver_info = (unsigned long) &rndis_info, }, #endif - -#ifdef CONFIG_USB_CDCETHER -{ - /* CDC Ether uses two interfaces, not necessarily consecutive. - * We match the main interface, ignoring the optional device - * class so we could handle devices that aren't exclusively - * CDC ether. - * - * NOTE: this match must come AFTER entries working around - * bugs/quirks in a given product (like Zaurus, above). - */ - USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long) &cdc_info, -}, -#endif - { }, // END }; MODULE_DEVICE_TABLE (usb, products); @@ -1792,10 +1404,6 @@ static int __init usbnet_init(void) // compiler should optimize these out BUG_ON (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)); -#ifdef CONFIG_USB_CDCETHER - BUG_ON ((sizeof (((struct usbnet *)0)->data) - < sizeof (struct cdc_state))); -#endif random_ether_addr(node_id); -- cgit v1.2.3-70-g09d2 From 64e049102d3de3e61409cb6019403a9e689dfda6 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:54:36 -0700 Subject: [PATCH] USB: usbnet (8/9) module for RNDIS devices This adds host-side RNDIS support to the "usbnet" driver, so Linux can talk to various devices (often based on WinCE) that otherwise only Windows could talk to. Tested with little-endian Linux talking to a Linux-USB Ethernet/RNDIS based peripheral. This also includes updates from Eddie C. Dost for big-endian SPARC Linux talking to a Nokia 9500 Communicator. It's still marked as EXPERIMENTAL because this code is so young. This ought to let Linux to work with various cable modems that previously would have been "Windows Only". Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 13 + drivers/usb/net/Makefile | 1 + drivers/usb/net/rndis_host.c | 615 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 9 +- 4 files changed, 630 insertions(+), 8 deletions(-) create mode 100644 drivers/usb/net/rndis_host.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 4921101d93d..5f3ae1e06b1 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -212,6 +212,19 @@ config USB_NET_NET1080 on this design: one NetChip 1080 chip and supporting logic, optionally with LEDs that indicate traffic +config USB_NET_RNDIS_HOST + tristate "Host for RNDIS devices (EXPERIMENTAL)" + depends on USB_USBNET && EXPERIMENTAL + select USB_NET_CDCETHER + help + This option enables hosting "Remote NDIS" USB networking links, + as encouraged by Microsoft (instead of CDC Ethernet!) for use in + various devices that may only support this protocol. + + Avoid using this protocol unless you have no better options. + The protocol specification is incomplete, and is controlled by + (and for) Microsoft; it isn't an "Open" ecosystem or market. + config USB_NET_CDC_SUBSET tristate "Simple USB Network Links (CDC Ethernet subset)" depends on USB_USBNET diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 697eb191320..cb789c3ded5 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o +obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o obj-$(CONFIG_USB_USBNET) += usbnet.o diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c new file mode 100644 index 00000000000..2ed2e5fb777 --- /dev/null +++ b/drivers/usb/net/rndis_host.c @@ -0,0 +1,615 @@ +/* + * Host Side support for RNDIS Networking Links + * Copyright (C) 2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of + * course ACM was intended for modems, not Ethernet links! USB's standard + * for Ethernet links is "CDC Ethernet", which is significantly simpler. + */ + +/* + * CONTROL uses CDC "encapsulated commands" with funky notifications. + * - control-out: SEND_ENCAPSULATED + * - interrupt-in: RESPONSE_AVAILABLE + * - control-in: GET_ENCAPSULATED + * + * We'll try to ignore the RESPONSE_AVAILABLE notifications. + */ +struct rndis_msg_hdr { + __le32 msg_type; /* RNDIS_MSG_* */ + __le32 msg_len; + // followed by data that varies between messages + __le32 request_id; + __le32 status; + // ... and more +} __attribute__ ((packed)); + +/* RNDIS defines this (absurdly huge) control timeout */ +#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000) + + +#define ccpu2 __constant_cpu_to_le32 + +#define RNDIS_MSG_COMPLETION ccpu2(0x80000000) + +/* codes for "msg_type" field of rndis messages; + * only the data channel uses packet messages (maybe batched); + * everything else goes on the control channel. + */ +#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */ +#define RNDIS_MSG_INIT ccpu2(0x00000002) +#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_HALT ccpu2(0x00000003) +#define RNDIS_MSG_QUERY ccpu2(0x00000004) +#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_SET ccpu2(0x00000005) +#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_RESET ccpu2(0x00000006) +#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_INDICATE ccpu2(0x00000007) +#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008) +#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) + +/* codes for "status" field of completion messages */ +#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000) +#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001) +#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015) +#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb) +#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b) +#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c) + + +struct rndis_data_hdr { + __le32 msg_type; /* RNDIS_MSG_PACKET */ + __le32 msg_len; // rndis_data_hdr + data_len + pad + __le32 data_offset; // 36 -- right after header + __le32 data_len; // ... real packet size + + __le32 oob_data_offset; // zero + __le32 oob_data_len; // zero + __le32 num_oob; // zero + __le32 packet_data_offset; // zero + + __le32 packet_data_len; // zero + __le32 vc_handle; // zero + __le32 reserved; // zero +} __attribute__ ((packed)); + +struct rndis_init { /* OUT */ + // header and: + __le32 msg_type; /* RNDIS_MSG_INIT */ + __le32 msg_len; // 24 + __le32 request_id; + __le32 major_version; // of rndis (1.0) + __le32 minor_version; + __le32 max_transfer_size; +} __attribute__ ((packed)); + +struct rndis_init_c { /* IN */ + // header and: + __le32 msg_type; /* RNDIS_MSG_INIT_C */ + __le32 msg_len; + __le32 request_id; + __le32 status; + __le32 major_version; // of rndis (1.0) + __le32 minor_version; + __le32 device_flags; + __le32 medium; // zero == 802.3 + __le32 max_packets_per_message; + __le32 max_transfer_size; + __le32 packet_alignment; // max 7; (1<actual_length, urb->status); + // FIXME for keepalives, respond immediately (asynchronously) + // if not an RNDIS status, do like cdc_status(dev,urb) does +} + +/* + * RPC done RNDIS-style. Caller guarantees: + * - message is properly byteswapped + * - there's no other request pending + * - buf can hold up to 1KB response (required by RNDIS spec) + * On return, the first few entries are already byteswapped. + * + * Call context is likely probe(), before interface name is known, + * which is why we won't try to use it in the diagnostics. + */ +static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) +{ + struct cdc_state *info = (void *) &dev->data; + int retval; + unsigned count; + __le32 rsp; + u32 xid = 0, msg_len, request_id; + + /* REVISIT when this gets called from contexts other than probe() or + * disconnect(): either serialize, or dispatch responses on xid + */ + + /* Issue the request; don't bother byteswapping our xid */ + if (likely(buf->msg_type != RNDIS_MSG_HALT + && buf->msg_type != RNDIS_MSG_RESET)) { + xid = dev->xid++; + if (!xid) + xid = dev->xid++; + buf->request_id = (__force __le32) xid; + } + retval = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + USB_CDC_SEND_ENCAPSULATED_COMMAND, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, info->u->bMasterInterface0, + buf, le32_to_cpu(buf->msg_len), + RNDIS_CONTROL_TIMEOUT_MS); + if (unlikely(retval < 0 || xid == 0)) + return retval; + + // FIXME Seems like some devices discard responses when + // we time out and cancel our "get response" requests... + // so, this is fragile. Probably need to poll for status. + + /* ignore status endpoint, just poll the control channel; + * the request probably completed immediately + */ + rsp = buf->msg_type | RNDIS_MSG_COMPLETION; + for (count = 0; count < 10; count++) { + memset(buf, 0, 1024); + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USB_CDC_GET_ENCAPSULATED_RESPONSE, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, info->u->bMasterInterface0, + buf, 1024, + RNDIS_CONTROL_TIMEOUT_MS); + if (likely(retval >= 8)) { + msg_len = le32_to_cpu(buf->msg_len); + request_id = (__force u32) buf->request_id; + if (likely(buf->msg_type == rsp)) { + if (likely(request_id == xid)) { + if (unlikely(rsp == RNDIS_MSG_RESET_C)) + return 0; + if (likely(RNDIS_STATUS_SUCCESS + == buf->status)) + return 0; + dev_dbg(&info->control->dev, + "rndis reply status %08x\n", + le32_to_cpu(buf->status)); + return -EL3RST; + } + dev_dbg(&info->control->dev, + "rndis reply id %d expected %d\n", + request_id, xid); + /* then likely retry */ + } else switch (buf->msg_type) { + case RNDIS_MSG_INDICATE: { /* fault */ + // struct rndis_indicate *msg = (void *)buf; + dev_info(&info->control->dev, + "rndis fault indication\n"); + } + break; + case RNDIS_MSG_KEEPALIVE: { /* ping */ + struct rndis_keepalive_c *msg = (void *)buf; + + msg->msg_type = RNDIS_MSG_KEEPALIVE_C; + msg->msg_len = ccpu2(sizeof *msg); + msg->status = RNDIS_STATUS_SUCCESS; + retval = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + USB_CDC_SEND_ENCAPSULATED_COMMAND, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, info->u->bMasterInterface0, + msg, sizeof *msg, + RNDIS_CONTROL_TIMEOUT_MS); + if (unlikely(retval < 0)) + dev_dbg(&info->control->dev, + "rndis keepalive err %d\n", + retval); + } + break; + default: + dev_dbg(&info->control->dev, + "unexpected rndis msg %08x len %d\n", + le32_to_cpu(buf->msg_type), msg_len); + } + } else { + /* device probably issued a protocol stall; ignore */ + dev_dbg(&info->control->dev, + "rndis response error, code %d\n", retval); + } + msleep(2); + } + dev_dbg(&info->control->dev, "rndis response timeout\n"); + return -ETIMEDOUT; +} + +static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int retval; + struct net_device *net = dev->net; + union { + void *buf; + struct rndis_msg_hdr *header; + struct rndis_init *init; + struct rndis_init_c *init_c; + struct rndis_query *get; + struct rndis_query_c *get_c; + struct rndis_set *set; + struct rndis_set_c *set_c; + } u; + u32 tmp; + + /* we can't rely on i/o from stack working, or stack allocation */ + u.buf = kmalloc(1024, GFP_KERNEL); + if (!u.buf) + return -ENOMEM; + retval = usbnet_generic_cdc_bind(dev, intf); + if (retval < 0) + goto done; + + net->hard_header_len += sizeof (struct rndis_data_hdr); + + /* initialize; max transfer is 16KB at full speed */ + u.init->msg_type = RNDIS_MSG_INIT; + u.init->msg_len = ccpu2(sizeof *u.init); + u.init->major_version = ccpu2(1); + u.init->minor_version = ccpu2(0); + u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len); + + retval = rndis_command(dev, u.header); + if (unlikely(retval < 0)) { + /* it might not even be an RNDIS device!! */ + dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); +fail: + usb_driver_release_interface(driver_of(intf), + ((struct cdc_state *)&(dev->data))->data); + goto done; + } + dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); + /* REVISIT: peripheral "alignment" request is ignored ... */ + dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu, + 1 << le32_to_cpu(u.init_c->packet_alignment)); + + /* get designated host ethernet address */ + memset(u.get, 0, sizeof *u.get); + u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_len = ccpu2(sizeof *u.get); + u.get->oid = OID_802_3_PERMANENT_ADDRESS; + + retval = rndis_command(dev, u.header); + if (unlikely(retval < 0)) { + dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); + goto fail; + } + tmp = le32_to_cpu(u.get_c->offset); + if (unlikely((tmp + 8) > (1024 - ETH_ALEN) + || u.get_c->len != ccpu2(ETH_ALEN))) { + dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", + tmp, le32_to_cpu(u.get_c->len)); + retval = -EDOM; + goto fail; + } + memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); + + /* set a nonzero filter to enable data transfers */ + memset(u.set, 0, sizeof *u.set); + u.set->msg_type = RNDIS_MSG_SET; + u.set->msg_len = ccpu2(4 + sizeof *u.set); + u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; + u.set->len = ccpu2(4); + u.set->offset = ccpu2((sizeof *u.set) - 8); + *(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER); + + retval = rndis_command(dev, u.header); + if (unlikely(retval < 0)) { + dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); + goto fail; + } + + retval = 0; +done: + kfree(u.buf); + return retval; +} + +static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct rndis_halt *halt; + + /* try to clear any rndis state/activity (no i/o from stack!) */ + halt = kcalloc(1, sizeof *halt, SLAB_KERNEL); + if (halt) { + halt->msg_type = RNDIS_MSG_HALT; + halt->msg_len = ccpu2(sizeof *halt); + (void) rndis_command(dev, (void *)halt); + kfree(halt); + } + + return usbnet_cdc_unbind(dev, intf); +} + +/* + * DATA -- host must not write zlps + */ +static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + /* peripheral may have batched packets to us... */ + while (likely(skb->len)) { + struct rndis_data_hdr *hdr = (void *)skb->data; + struct sk_buff *skb2; + u32 msg_len, data_offset, data_len; + + msg_len = le32_to_cpu(hdr->msg_len); + data_offset = le32_to_cpu(hdr->data_offset); + data_len = le32_to_cpu(hdr->data_len); + + /* don't choke if we see oob, per-packet data, etc */ + if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET + || skb->len < msg_len + || (data_offset + data_len + 8) > msg_len)) { + dev->stats.rx_frame_errors++; + devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", + le32_to_cpu(hdr->msg_type), + msg_len, data_offset, data_len, skb->len); + return 0; + } + skb_pull(skb, 8 + data_offset); + + /* at most one packet left? */ + if (likely((data_len - skb->len) <= sizeof *hdr)) { + skb_trim(skb, data_len); + break; + } + + /* try to return all the packets in the batch */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!skb2)) + break; + skb_pull(skb, msg_len - sizeof *hdr); + skb_trim(skb2, data_len); + usbnet_skb_return(dev, skb2); + } + + /* caller will usbnet_skb_return the remaining packet */ + return 1; +} + +static struct sk_buff * +rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +{ + struct rndis_data_hdr *hdr; + struct sk_buff *skb2; + unsigned len = skb->len; + + if (likely(!skb_cloned(skb))) { + int room = skb_headroom(skb); + + /* enough head room as-is? */ + if (unlikely((sizeof *hdr) <= room)) + goto fill; + + /* enough room, but needs to be readjusted? */ + room += skb_tailroom(skb); + if (likely((sizeof *hdr) <= room)) { + skb->data = memmove(skb->head + sizeof *hdr, + skb->data, len); + skb->tail = skb->data + len; + goto fill; + } + } + + /* create a new skb, with the correct size (and tailpad) */ + skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); + dev_kfree_skb_any(skb); + if (unlikely(!skb2)) + return skb2; + skb = skb2; + + /* fill out the RNDIS header. we won't bother trying to batch + * packets; Linux minimizes wasted bandwidth through tx queues. + */ +fill: + hdr = (void *) __skb_push(skb, sizeof *hdr); + memset(hdr, 0, sizeof *hdr); + hdr->msg_type = RNDIS_MSG_PACKET; + hdr->msg_len = cpu_to_le32(skb->len); + hdr->data_offset = ccpu2(sizeof(*hdr) - 8); + hdr->data_len = cpu_to_le32(len); + + /* FIXME make the last packet always be short ... */ + return skb; +} + + +static const struct driver_info rndis_info = { + .description = "RNDIS device", + .flags = FLAG_ETHER | FLAG_FRAMING_RN, + .bind = rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, + .tx_fixup = rndis_tx_fixup, +}; + +#undef ccpu2 + + +/*-------------------------------------------------------------------------*/ + +static const struct usb_device_id products [] = { +{ + /* RNDIS is MSFT's un-official variant of CDC ACM */ + USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long) &rndis_info, +}, + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver rndis_driver = { + .owner = THIS_MODULE, + .name = "rndis_host", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init rndis_init(void) +{ + return usb_register(&rndis_driver); +} +module_init(rndis_init); + +static void __exit rndis_exit(void) +{ + usb_deregister(&rndis_driver); +} +module_exit(rndis_exit); + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("USB Host side RNDIS driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 7703725327d..6c78a42affa 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -103,6 +103,7 @@ * disconnect; other cleanups. (db) Flush net1080 fifos * after several sequential framing errors. (Johannes Erdfelt) * 22-aug-2003 AX8817X support (Dave Hollis). + * * 14-jun-2004 Trivial patch for AX8817X based Buffalo LUA-U2-KTX in Japan * (Neil Bortnak) * 03-nov-2004 Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell) @@ -1374,14 +1375,6 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x067b, 0x0001), // PL-2302 .driver_info = (unsigned long) &prolific_info, }, -#endif - -#ifdef CONFIG_USB_RNDIS -{ - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO (USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_info, -}, #endif { }, // END }; -- cgit v1.2.3-70-g09d2 From 090ffa9d0e904e1ed0f86c84dcf20684a8ac1a5a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 31 Aug 2005 09:54:50 -0700 Subject: [PATCH] USB: usbnet (9/9) module for pl2301/2302 cables This wraps up the conversion of the "usbnet" driver structure, by moving the Prolific PL-2201/2302 minidriver to a module of its own. It also includes some minor cleanups to the remaining "usbnet" file, notably removing that long changelog at the top. Minor historical note: Linux 2.2 first called the driver for this hardware "plusb". Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 25 +++--- drivers/usb/net/Makefile | 1 + drivers/usb/net/plusb.c | 156 ++++++++++++++++++++++++++++++++++ drivers/usb/net/usbnet.c | 214 +++-------------------------------------------- 4 files changed, 179 insertions(+), 217 deletions(-) create mode 100644 drivers/usb/net/plusb.c (limited to 'drivers/usb/net/usbnet.c') diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 5f3ae1e06b1..8c010bb44eb 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -99,7 +99,7 @@ config USB_USBNET with "minidrivers" built around a common network driver core that supports deep queues for efficient transfers. (This gives better performance with small packets and at high speeds). - + The USB host runs "usbnet", and the other end of the link might be: - Another USB host, when using USB "network" or "data transfer" @@ -125,20 +125,6 @@ config USB_USBNET To compile this driver as a module, choose M here: the module will be called usbnet. -comment "USB Host-to-Host Cables" - depends on USB_USBNET - -config USB_PL2301 - boolean "Prolific PL-2301/2302 based cables" - default y - # handshake/init/reset problems, from original 'plusb' driver - depends on USB_USBNET && EXPERIMENTAL - help - Choose this option if you're using a host-to-host cable - with one of these chips. - -comment "Drivers built using the usbnet core" - config USB_NET_AX8817X tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" depends on USB_USBNET && NET_ETHERNET @@ -212,6 +198,15 @@ config USB_NET_NET1080 on this design: one NetChip 1080 chip and supporting logic, optionally with LEDs that indicate traffic +config USB_NET_PLUSB + tristate "Prolific PL-2301/2302 based cables" + # if the handshake/init/reset problems, from original 'plusb', + # are ever resolved ... then remove "experimental" + depends on USB_USBNET && EXPERIMENTAL + help + Choose this option if you're using a host-to-host cable + with one of these chips. + config USB_NET_RNDIS_HOST tristate "Host for RNDIS devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index cb789c3ded5..222c0495f79 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o +obj-$(CONFIG_USB_NET_PLUSB) += plusb.o obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o diff --git a/drivers/usb/net/plusb.c b/drivers/usb/net/plusb.c new file mode 100644 index 00000000000..74c2b3581c7 --- /dev/null +++ b/drivers/usb/net/plusb.c @@ -0,0 +1,156 @@ +/* + * PL-2301/2302 USB host-to-host link cables + * Copyright (C) 2000-2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbnet.h" + + +/* + * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com + * + * The protocol and handshaking used here should be bug-compatible + * with the Linux 2.2 "plusb" driver, by Deti Fliegl. + * + * HEADS UP: this handshaking isn't all that robust. This driver + * gets confused easily if you unplug one end of the cable then + * try to connect it again; you'll need to restart both ends. The + * "naplink" software (used by some PlayStation/2 deveopers) does + * the handshaking much better! Also, sometimes this hardware + * seems to get wedged under load. Prolific docs are weak, and + * don't identify differences between PL2301 and PL2302, much less + * anything to explain the different PL2302 versions observed. + */ + +/* + * Bits 0-4 can be used for software handshaking; they're set from + * one end, cleared from the other, "read" with the interrupt byte. + */ +#define PL_S_EN (1<<7) /* (feature only) suspend enable */ +/* reserved bit -- rx ready (6) ? */ +#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ +#define PL_RESET_OUT (1<<4) /* reset output pipe */ +#define PL_RESET_IN (1<<3) /* reset input pipe */ +#define PL_TX_C (1<<2) /* transmission complete */ +#define PL_TX_REQ (1<<1) /* transmission received */ +#define PL_PEER_E (1<<0) /* peer exists */ + +static inline int +pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) +{ + return usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, index, + NULL, 0, + USB_CTRL_GET_TIMEOUT); +} + +static inline int +pl_clear_QuickLink_features(struct usbnet *dev, int val) +{ + return pl_vendor_req(dev, 1, (u8) val, 0); +} + +static inline int +pl_set_QuickLink_features(struct usbnet *dev, int val) +{ + return pl_vendor_req(dev, 3, (u8) val, 0); +} + +static int pl_reset(struct usbnet *dev) +{ + /* some units seem to need this reset, others reject it utterly. + * FIXME be more like "naplink" or windows drivers. + */ + (void) pl_set_QuickLink_features(dev, + PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); + return 0; +} + +static const struct driver_info prolific_info = { + .description = "Prolific PL-2301/PL-2302", + .flags = FLAG_NO_SETINT, + /* some PL-2302 versions seem to fail usb_set_interface() */ + .reset = pl_reset, +}; + + +/*-------------------------------------------------------------------------*/ + +/* + * Proilific's name won't normally be on the cables, and + * may not be on the device. + */ + +static const struct usb_device_id products [] = { + +{ + USB_DEVICE(0x067b, 0x0000), // PL-2301 + .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x067b, 0x0001), // PL-2302 + .driver_info = (unsigned long) &prolific_info, +}, + + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver plusb_driver = { + .owner = THIS_MODULE, + .name = "plusb", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init plusb_init(void) +{ + return usb_register(&plusb_driver); +} +module_init(plusb_init); + +static void __exit plusb_exit(void) +{ + usb_deregister(&plusb_driver); +} +module_exit(plusb_exit); + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6c78a42affa..6c460918d54 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,5 +1,5 @@ /* - * USB Networking Links + * USB Network driver infrastructure * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2003-2005 David Hollis * @@ -20,96 +20,15 @@ /* * This is a generic "USB networking" framework that works with several - * kinds of full and high speed networking devices: + * kinds of full and high speed networking devices: host-to-host cables, + * smart usb peripherals, and actual Ethernet adapters. * - * + USB host-to-host "network cables", used for IP-over-USB links. - * These are often used for Laplink style connectivity products. - * - AnchorChip 2720 - * - Belkin, eTEK (interops with Win32 drivers) - * - GeneSys GL620USB-A - * - NetChip 1080 (interoperates with NetChip Win32 drivers) - * - Prolific PL-2301/2302 (replaces "plusb" driver) - * - KC Technology KC2190 - * - * + Smart USB devices can support such links directly, using Internet - * standard protocols instead of proprietary host-to-device links. - * - Linux PDAs like iPaq, Yopy, and Zaurus - * - The BLOB boot loader (for diskless booting) - * - Linux "gadgets", perhaps using PXA-2xx or Net2280 controllers - * - Devices using EPSON's sample USB firmware - * - CDC-Ethernet class devices, such as many cable modems - * - * + Adapters to networks such as Ethernet. - * - AX8817X based USB 2.0 products - * - * Links to these devices can be bridged using Linux Ethernet bridging. - * With minor exceptions, these all use similar USB framing for network - * traffic, but need different protocols for control traffic. - * - * USB devices can implement their side of this protocol at the cost - * of two bulk endpoints; it's not restricted to "cable" applications. - * See the SA1110, Zaurus, or EPSON device/client support in this driver; - * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) or - * "g_ether" (in the Linux "gadget" framework) implement that behavior - * within devices. - * - * - * CHANGELOG: - * - * 13-sep-2000 experimental, new - * 10-oct-2000 usb_device_id table created. - * 28-oct-2000 misc fixes; mostly, discard more TTL-mangled rx packets. - * 01-nov-2000 usb_device_id table and probing api update by - * Adam J. Richter . - * 18-dec-2000 (db) tx watchdog, "net1080" renaming to "usbnet", device_info - * and prolific support, isolate net1080-specific bits, cleanup. - * fix unlink_urbs oops in D3 PM resume code path. - * - * 02-feb-2001 (db) fix tx skb sharing, packet length, match_flags, ... - * 08-feb-2001 stubbed in "linuxdev", maybe the SA-1100 folk can use it; - * AnchorChips 2720 support (from spec) for testing; - * fix bit-ordering problem with ethernet multicast addr - * 19-feb-2001 Support for clearing halt conditions. SA1100 UDC support - * updates. Oleg Drokin (green@iXcelerator.com) - * 25-mar-2001 More SA-1100 updates, including workaround for ip problem - * expecting cleared skb->cb and framing change to match latest - * handhelds.org version (Oleg). Enable device IDs from the - * Win32 Belkin driver; other cleanups (db). - * 16-jul-2001 Bugfixes for uhci oops-on-unplug, Belkin support, various - * cleanups for problems not yet seen in the field. (db) - * 17-oct-2001 Handle "Advance USBNET" product, like Belkin/eTEK devices, - * from Ioannis Mavroukakis ; - * rx unlinks somehow weren't async; minor cleanup. - * 03-nov-2001 Merged GeneSys driver; original code from Jiun-Jie Huang - * , updated by Stanislav Brabec - * . Made framing options (NetChip/GeneSys) - * tie mostly to (sub)driver info. Workaround some PL-2302 - * chips that seem to reject SET_INTERFACE requests. - * - * 06-apr-2002 Added ethtool support, based on a patch from Brad Hards. - * Level of diagnostics is more configurable; they use device - * location (usb_device->devpath) instead of address (2.5). - * For tx_fixup, memflags can't be NOIO. - * 07-may-2002 Generalize/cleanup keventd support, handling rx stalls (mostly - * for USB 2.0 TTs) and memory shortages (potential) too. (db) - * Use "locally assigned" IEEE802 address space. (Brad Hards) - * 18-oct-2002 Support for Zaurus (Pavel Machek), related cleanup (db). - * 14-dec-2002 Remove Zaurus-private crc32 code (Pavel); 2.5 oops fix, - * cleanups and stubbed PXA-250 support (db), fix for framing - * issues on Z, net1080, and gl620a (Toby Milne) - * - * 31-mar-2003 Use endpoint descriptors: high speed support, simpler sa1100 - * vs pxa25x, and CDC Ethernet. Throttle down log floods on - * disconnect; other cleanups. (db) Flush net1080 fifos - * after several sequential framing errors. (Johannes Erdfelt) - * 22-aug-2003 AX8817X support (Dave Hollis). - * - * 14-jun-2004 Trivial patch for AX8817X based Buffalo LUA-U2-KTX in Japan - * (Neil Bortnak) - * 03-nov-2004 Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell) - * - * 01-feb-2005 AX88772 support (Phil Chang & Dave Hollis) - *-------------------------------------------------------------------------*/ + * These devices usually differ in terms of control protocols (if they + * even have one!) and sometimes they define new framing to wrap or batch + * Ethernet packets. Otherwise, they talk to USB pretty much the same, + * so interface (un)binding, endpoint I/O queues, fault handling, and other + * issues can usefully be addressed by this framework. + */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages @@ -301,77 +220,6 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(usbnet_skb_return); - -#ifdef CONFIG_USB_PL2301 -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com - * - * The protocol and handshaking used here should be bug-compatible - * with the Linux 2.2 "plusb" driver, by Deti Fliegl. - * - *-------------------------------------------------------------------------*/ - -/* - * Bits 0-4 can be used for software handshaking; they're set from - * one end, cleared from the other, "read" with the interrupt byte. - */ -#define PL_S_EN (1<<7) /* (feature only) suspend enable */ -/* reserved bit -- rx ready (6) ? */ -#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ -#define PL_RESET_OUT (1<<4) /* reset output pipe */ -#define PL_RESET_IN (1<<3) /* reset input pipe */ -#define PL_TX_C (1<<2) /* transmission complete */ -#define PL_TX_REQ (1<<1) /* transmission received */ -#define PL_PEER_E (1<<0) /* peer exists */ - -static inline int -pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index) -{ - return usb_control_msg (dev->udev, - usb_rcvctrlpipe (dev->udev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, index, - NULL, 0, - USB_CTRL_GET_TIMEOUT); -} - -static inline int -pl_clear_QuickLink_features (struct usbnet *dev, int val) -{ - return pl_vendor_req (dev, 1, (u8) val, 0); -} - -static inline int -pl_set_QuickLink_features (struct usbnet *dev, int val) -{ - return pl_vendor_req (dev, 3, (u8) val, 0); -} - -/*-------------------------------------------------------------------------*/ - -static int pl_reset (struct usbnet *dev) -{ - /* some units seem to need this reset, others reject it utterly. - * FIXME be more like "naplink" or windows drivers. - */ - (void) pl_set_QuickLink_features (dev, - PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); - return 0; -} - -static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302", - .flags = FLAG_NO_SETINT, - /* some PL-2302 versions seem to fail usb_set_interface() */ - .reset = pl_reset, -}; - -#endif /* CONFIG_USB_PL2301 */ - /*------------------------------------------------------------------------- * @@ -1354,62 +1202,24 @@ int usbnet_resume (struct usb_interface *intf) EXPORT_SYMBOL_GPL(usbnet_resume); -/*-------------------------------------------------------------------------*/ - -#ifndef HAVE_HARDWARE -#error You need to configure some hardware for this driver -#endif - -/* - * chip vendor names won't normally be on the cables, and - * may not be on the device. - */ - -static const struct usb_device_id products [] = { - -#ifdef CONFIG_USB_PL2301 -{ - USB_DEVICE (0x067b, 0x0000), // PL-2301 - .driver_info = (unsigned long) &prolific_info, -}, { - USB_DEVICE (0x067b, 0x0001), // PL-2302 - .driver_info = (unsigned long) &prolific_info, -}, -#endif - { }, // END -}; -MODULE_DEVICE_TABLE (usb, products); - -static struct usb_driver usbnet_driver = { - .owner = THIS_MODULE, - .name = driver_name, - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, -}; - /*-------------------------------------------------------------------------*/ static int __init usbnet_init(void) { - // compiler should optimize these out + /* compiler should optimize this out */ BUG_ON (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)); random_ether_addr(node_id); - - return usb_register(&usbnet_driver); + return 0; } module_init(usbnet_init); static void __exit usbnet_exit(void) { - usb_deregister(&usbnet_driver); } module_exit(usbnet_exit); MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("USB Host-to-Host Link Drivers (numerous vendors)"); +MODULE_DESCRIPTION("USB network driver framework"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2