]> err.no Git - linux-2.6/commitdiff
[PATCH] usb gadget: ethernet/rndis updates
authorDavid Brownell <david-b@pacbell.net>
Tue, 19 Apr 2005 00:39:34 +0000 (17:39 -0700)
committerGreg K-H <gregkh@suse.de>
Tue, 19 Apr 2005 00:39:34 +0000 (17:39 -0700)
Updates to the Ethernet/RNDIS gadget driver (mostly for RNDIS):

  - Fix brown-paper bag goof with RNDIS packet TX ... the wrong length
    field got set, so Windows would ignore data packets it received.

  - More consistent handling of CDC output filters (but not yet hooking
    things up so RNDIS uses the mechanism).

  - Zerocopy RX for RNDIS packets too (saving CPU cycles).

  - Use the pre-allocated interrupt/status request and buffer, rather
    than allocating and freeing one of each every few seconds (which
    could fail).

  - Some more "sparse" tweaks, making both dual-speed and single-speed
    configurations happier.

  - RNDIS speeds are reported in units of 100bps, not bps.

Plus two minor cleanups (whitespace, messaging).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/gadget/ether.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/rndis.h

index cff9fb0b73cc09724c59483759906f08202b261c..3993156c2e826ce8d95a8717338d151e805a8104 100644 (file)
@@ -100,6 +100,8 @@ static const char driver_desc [] = DRIVER_DESC;
 
 /* CDC and RNDIS support the same host-chosen outgoing packet filters. */
 #define        DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
+                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
                        |USB_CDC_PACKET_TYPE_DIRECTED)
 
 
@@ -322,12 +324,18 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
 /* also defer IRQs on highspeed TX */
 #define TX_DELAY       qmult
 
-#define        BITRATE(g)      (((g)->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS)
+static inline int BITRATE(struct usb_gadget *g)
+{
+       return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
+}
 
 #else  /* full speed (low speed doesn't do bulk) */
 #define qlen(gadget) DEFAULT_QLEN
 
-#define        BITRATE(g)      FS_BPS
+static inline int BITRATE(struct usb_gadget *g)
+{
+       return FS_BPS;
+}
 #endif
 
 
@@ -1167,7 +1175,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
        eth_reset_config (dev);
 
        /* default:  pass all packets, no multicast filtering */
-       dev->cdc_filter = 0x000f;
+       dev->cdc_filter = DEFAULT_FILTER;
 
        switch (number) {
        case DEV_CONFIG_VALUE:
@@ -1343,9 +1351,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct eth_dev          *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
-       u16                     wIndex = ctrl->wIndex;
-       u16                     wValue = ctrl->wValue;
-       u16                     wLength = ctrl->wLength;
+       u16                     wIndex = (__force u16) ctrl->wIndex;
+       u16                     wValue = (__force u16) ctrl->wValue;
+       u16                     wLength = (__force u16) ctrl->wLength;
 
        /* descriptors just go into the pre-allocated ep0 buffer,
         * while config change events may enable network traffic.
@@ -1693,7 +1701,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
        
        /* Some platforms perform better when IP packets are aligned,
         * but on at least one, checksumming fails otherwise.  Note:
-        * this doesn't account for variable-sized RNDIS headers.
+        * RNDIS headers involve variable numbers of LE32 values.
         */
        skb_reserve(skb, NET_IP_ALIGN);
 
@@ -1730,9 +1738,11 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
 #ifdef CONFIG_USB_ETH_RNDIS
                /* we know MaxPacketsPerTransfer == 1 here */
                if (dev->rndis)
-                       rndis_rm_hdr (req->buf, &(skb->len));
+                       status = rndis_rm_hdr (skb);
 #endif
-               if (ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) {
+               if (status < 0
+                               || ETH_HLEN > skb->len
+                               || skb->len > ETH_FRAME_LEN) {
                        dev->stats.rx_errors++;
                        dev->stats.rx_length_errors++;
                        DEBUG (dev, "rx length %d\n", skb->len);
@@ -2047,38 +2057,20 @@ rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
                DEBUG ((struct eth_dev *) ep->driver_data,
                        "rndis control ack complete --> %d, %d/%d\n",
                        req->status, req->actual, req->length);
-
-       usb_ep_free_buffer(ep, req->buf, req->dma, 8);
-       usb_ep_free_request(ep, req);
 }
 
 static int rndis_control_ack (struct net_device *net)
 {
        struct eth_dev          *dev = netdev_priv(net);
        u32                     length;
-       struct usb_request      *resp;
+       struct usb_request      *resp = dev->stat_req;
        
        /* in case RNDIS calls this after disconnect */
-       if (!dev->status_ep) {
+       if (!dev->status) {
                DEBUG (dev, "status ENODEV\n");
                return -ENODEV;
        }
 
-       /* Allocate memory for notification ie. ACK */
-       resp = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
-       if (!resp) {
-               DEBUG (dev, "status ENOMEM\n");
-               return -ENOMEM;
-       }
-       
-       resp->buf = usb_ep_alloc_buffer (dev->status_ep, 8,
-                                        &resp->dma, GFP_ATOMIC);
-       if (!resp->buf) {
-               DEBUG (dev, "status buf ENOMEM\n");
-               usb_ep_free_request (dev->status_ep, resp);
-               return -ENOMEM;
-       }
-       
        /* Send RNDIS RESPONSE_AVAILABLE notification;
         * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
         */
@@ -2113,7 +2105,7 @@ static void eth_start (struct eth_dev *dev, int gfp_flags)
        if (dev->rndis) {
                rndis_set_param_medium (dev->rndis_config,
                                        NDIS_MEDIUM_802_3,
-                                       BITRATE(dev->gadget));
+                                       BITRATE(dev->gadget)/100);
                rndis_send_media_state (dev, 1);
        }
 #endif 
@@ -2307,8 +2299,8 @@ eth_bind (struct usb_gadget *gadget)
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
        } else if (gadget_is_pxa27x(gadget)) {
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
-       } else if (gadget_is_s3c2410(gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
+       } else if (gadget_is_s3c2410(gadget)) {
+               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
        } else if (gadget_is_at91(gadget)) {
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
        } else {
index 6c5197850edc1f7b14942e211fefb14a91f1242f..7457268d5f282b9e9d1d6217857db70e0ecaefc9 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 
 #undef RNDIS_PM
@@ -165,7 +166,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
                
        /* mandatory */
        case OID_GEN_LINK_SPEED:
-               DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+//             DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
                length = 4;
                if (rndis_per_dev_params [configNr].media_state
                        == NDIS_MEDIA_STATE_DISCONNECTED)
@@ -729,7 +730,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
                retval = 0;
 
                /* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-                * filter packets in hard_start_xmit()
+                * set the cdc_filter; it's not RNDIS-specific
                 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
                 *      PROMISCUOUS, DIRECTED,
                 *      MULTICAST, ALL_MULTICAST, BROADCAST
@@ -1194,10 +1195,10 @@ void rndis_add_hdr (struct sk_buff *skb)
                return;
        header = (void *) skb_push (skb, sizeof *header);
        memset (header, 0, sizeof *header);
-       header->MessageType = __constant_cpu_to_le32 (1);
+       header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
        header->MessageLength = cpu_to_le32(skb->len);
        header->DataOffset = __constant_cpu_to_le32 (36);
-       header->OOBDataOffset = cpu_to_le32(skb->len - 44);
+       header->DataLength = cpu_to_le32(skb->len - sizeof *header);
 }
 
 void rndis_free_response (int configNr, u8 *buf)
@@ -1253,26 +1254,23 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
        return r;
 }
 
-int rndis_rm_hdr (u8 *buf, u32 *length)
+int rndis_rm_hdr(struct sk_buff *skb)
 {
-       u32 i, messageLen, dataOffset;
-       __le32 *tmp;
-       
-       tmp = (__le32 *) buf; 
+       /* tmp points to a struct rndis_packet_msg_type */
+       __le32          *tmp = (void *) skb->data;
 
-       if (!buf || !length) return -1;
-       if (le32_to_cpup(tmp++) != 1) return -1;
-       
-       messageLen = le32_to_cpup(tmp++);
-       dataOffset = le32_to_cpup(tmp++) + 8;
+       /* MessageType, MessageLength */
+       if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
+                       != get_unaligned(tmp++))
+               return -EINVAL;
+       tmp++;
+
+       /* DataOffset, DataLength */
+       if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
+                       + 8 /* offset of DataOffset */))
+               return -EOVERFLOW;
+       skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
 
-       if (messageLen < dataOffset || messageLen > *length) return -1;
-       
-       for (i = dataOffset; i < messageLen; i++)
-               buf [i - dataOffset] = buf [i];
-               
-       *length = messageLen - dataOffset;
-       
        return 0;
 }
 
index 822501852c50ba9776d8f4bfca1f8c4774ff3ce1..2b5b55df3cfd3042bfc189c12e6cbbc8fea54a4b 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 /* Message Set for Connectionless (802.3) Devices */
+#define REMOTE_NDIS_PACKET_MSG         0x00000001U
 #define REMOTE_NDIS_INITIALIZE_MSG     0x00000002U     /* Initialize device */
 #define REMOTE_NDIS_HALT_MSG           0x00000003U
 #define REMOTE_NDIS_QUERY_MSG          0x00000004U
@@ -333,7 +334,7 @@ int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
                            const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
 void rndis_add_hdr (struct sk_buff *skb);
-int  rndis_rm_hdr (u8 *buf, u32 *length);
+int rndis_rm_hdr (struct sk_buff *skb);
 u8   *rndis_get_next_response (int configNr, u32 *length);
 void rndis_free_response (int configNr, u8 *buf);