aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-04-18 20:39:34 -0400
committerGreg K-H <gregkh@suse.de>2005-04-18 20:39:34 -0400
commit6cdee106e7571751ecc0e9f96606322f88b64a8d (patch)
treeedc75e42c3f3e9bbfecabc12a51b0f6d1bb37930
parent1bc3c9e1e44c2059fe2ffa6ff70ad0a925d7b05f (diff)
[PATCH] usb gadget: ethernet/rndis updates
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>
-rw-r--r--drivers/usb/gadget/ether.c56
-rw-r--r--drivers/usb/gadget/rndis.c40
-rw-r--r--drivers/usb/gadget/rndis.h3
3 files changed, 45 insertions, 54 deletions
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index cff9fb0b73cc..3993156c2e82 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -100,6 +100,8 @@ static const char driver_desc [] = DRIVER_DESC;
100 100
101/* CDC and RNDIS support the same host-chosen outgoing packet filters. */ 101/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
102#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ 102#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
103 |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
104 |USB_CDC_PACKET_TYPE_PROMISCUOUS \
103 |USB_CDC_PACKET_TYPE_DIRECTED) 105 |USB_CDC_PACKET_TYPE_DIRECTED)
104 106
105 107
@@ -322,12 +324,18 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
322/* also defer IRQs on highspeed TX */ 324/* also defer IRQs on highspeed TX */
323#define TX_DELAY qmult 325#define TX_DELAY qmult
324 326
325#define BITRATE(g) (((g)->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS) 327static inline int BITRATE(struct usb_gadget *g)
328{
329 return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
330}
326 331
327#else /* full speed (low speed doesn't do bulk) */ 332#else /* full speed (low speed doesn't do bulk) */
328#define qlen(gadget) DEFAULT_QLEN 333#define qlen(gadget) DEFAULT_QLEN
329 334
330#define BITRATE(g) FS_BPS 335static inline int BITRATE(struct usb_gadget *g)
336{
337 return FS_BPS;
338}
331#endif 339#endif
332 340
333 341
@@ -1167,7 +1175,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
1167 eth_reset_config (dev); 1175 eth_reset_config (dev);
1168 1176
1169 /* default: pass all packets, no multicast filtering */ 1177 /* default: pass all packets, no multicast filtering */
1170 dev->cdc_filter = 0x000f; 1178 dev->cdc_filter = DEFAULT_FILTER;
1171 1179
1172 switch (number) { 1180 switch (number) {
1173 case DEV_CONFIG_VALUE: 1181 case DEV_CONFIG_VALUE:
@@ -1343,9 +1351,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
1343 struct eth_dev *dev = get_gadget_data (gadget); 1351 struct eth_dev *dev = get_gadget_data (gadget);
1344 struct usb_request *req = dev->req; 1352 struct usb_request *req = dev->req;
1345 int value = -EOPNOTSUPP; 1353 int value = -EOPNOTSUPP;
1346 u16 wIndex = ctrl->wIndex; 1354 u16 wIndex = (__force u16) ctrl->wIndex;
1347 u16 wValue = ctrl->wValue; 1355 u16 wValue = (__force u16) ctrl->wValue;
1348 u16 wLength = ctrl->wLength; 1356 u16 wLength = (__force u16) ctrl->wLength;
1349 1357
1350 /* descriptors just go into the pre-allocated ep0 buffer, 1358 /* descriptors just go into the pre-allocated ep0 buffer,
1351 * while config change events may enable network traffic. 1359 * 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)
1693 1701
1694 /* Some platforms perform better when IP packets are aligned, 1702 /* Some platforms perform better when IP packets are aligned,
1695 * but on at least one, checksumming fails otherwise. Note: 1703 * but on at least one, checksumming fails otherwise. Note:
1696 * this doesn't account for variable-sized RNDIS headers. 1704 * RNDIS headers involve variable numbers of LE32 values.
1697 */ 1705 */
1698 skb_reserve(skb, NET_IP_ALIGN); 1706 skb_reserve(skb, NET_IP_ALIGN);
1699 1707
@@ -1730,9 +1738,11 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
1730#ifdef CONFIG_USB_ETH_RNDIS 1738#ifdef CONFIG_USB_ETH_RNDIS
1731 /* we know MaxPacketsPerTransfer == 1 here */ 1739 /* we know MaxPacketsPerTransfer == 1 here */
1732 if (dev->rndis) 1740 if (dev->rndis)
1733 rndis_rm_hdr (req->buf, &(skb->len)); 1741 status = rndis_rm_hdr (skb);
1734#endif 1742#endif
1735 if (ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { 1743 if (status < 0
1744 || ETH_HLEN > skb->len
1745 || skb->len > ETH_FRAME_LEN) {
1736 dev->stats.rx_errors++; 1746 dev->stats.rx_errors++;
1737 dev->stats.rx_length_errors++; 1747 dev->stats.rx_length_errors++;
1738 DEBUG (dev, "rx length %d\n", skb->len); 1748 DEBUG (dev, "rx length %d\n", skb->len);
@@ -2047,38 +2057,20 @@ rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
2047 DEBUG ((struct eth_dev *) ep->driver_data, 2057 DEBUG ((struct eth_dev *) ep->driver_data,
2048 "rndis control ack complete --> %d, %d/%d\n", 2058 "rndis control ack complete --> %d, %d/%d\n",
2049 req->status, req->actual, req->length); 2059 req->status, req->actual, req->length);
2050
2051 usb_ep_free_buffer(ep, req->buf, req->dma, 8);
2052 usb_ep_free_request(ep, req);
2053} 2060}
2054 2061
2055static int rndis_control_ack (struct net_device *net) 2062static int rndis_control_ack (struct net_device *net)
2056{ 2063{
2057 struct eth_dev *dev = netdev_priv(net); 2064 struct eth_dev *dev = netdev_priv(net);
2058 u32 length; 2065 u32 length;
2059 struct usb_request *resp; 2066 struct usb_request *resp = dev->stat_req;
2060 2067
2061 /* in case RNDIS calls this after disconnect */ 2068 /* in case RNDIS calls this after disconnect */
2062 if (!dev->status_ep) { 2069 if (!dev->status) {
2063 DEBUG (dev, "status ENODEV\n"); 2070 DEBUG (dev, "status ENODEV\n");
2064 return -ENODEV; 2071 return -ENODEV;
2065 } 2072 }
2066 2073
2067 /* Allocate memory for notification ie. ACK */
2068 resp = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
2069 if (!resp) {
2070 DEBUG (dev, "status ENOMEM\n");
2071 return -ENOMEM;
2072 }
2073
2074 resp->buf = usb_ep_alloc_buffer (dev->status_ep, 8,
2075 &resp->dma, GFP_ATOMIC);
2076 if (!resp->buf) {
2077 DEBUG (dev, "status buf ENOMEM\n");
2078 usb_ep_free_request (dev->status_ep, resp);
2079 return -ENOMEM;
2080 }
2081
2082 /* Send RNDIS RESPONSE_AVAILABLE notification; 2074 /* Send RNDIS RESPONSE_AVAILABLE notification;
2083 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too 2075 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
2084 */ 2076 */
@@ -2113,7 +2105,7 @@ static void eth_start (struct eth_dev *dev, int gfp_flags)
2113 if (dev->rndis) { 2105 if (dev->rndis) {
2114 rndis_set_param_medium (dev->rndis_config, 2106 rndis_set_param_medium (dev->rndis_config,
2115 NDIS_MEDIUM_802_3, 2107 NDIS_MEDIUM_802_3,
2116 BITRATE(dev->gadget)); 2108 BITRATE(dev->gadget)/100);
2117 rndis_send_media_state (dev, 1); 2109 rndis_send_media_state (dev, 1);
2118 } 2110 }
2119#endif 2111#endif
@@ -2307,8 +2299,8 @@ eth_bind (struct usb_gadget *gadget)
2307 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210); 2299 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
2308 } else if (gadget_is_pxa27x(gadget)) { 2300 } else if (gadget_is_pxa27x(gadget)) {
2309 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211); 2301 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
2310 } else if (gadget_is_s3c2410(gadget)) { 2302 } else if (gadget_is_s3c2410(gadget)) {
2311 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212); 2303 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
2312 } else if (gadget_is_at91(gadget)) { 2304 } else if (gadget_is_at91(gadget)) {
2313 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213); 2305 device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
2314 } else { 2306 } else {
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 6c5197850edc..7457268d5f28 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -37,6 +37,7 @@
37#include <asm/io.h> 37#include <asm/io.h>
38#include <asm/byteorder.h> 38#include <asm/byteorder.h>
39#include <asm/system.h> 39#include <asm/system.h>
40#include <asm/unaligned.h>
40 41
41 42
42#undef RNDIS_PM 43#undef RNDIS_PM
@@ -165,7 +166,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
165 166
166 /* mandatory */ 167 /* mandatory */
167 case OID_GEN_LINK_SPEED: 168 case OID_GEN_LINK_SPEED:
168 DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); 169// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
169 length = 4; 170 length = 4;
170 if (rndis_per_dev_params [configNr].media_state 171 if (rndis_per_dev_params [configNr].media_state
171 == NDIS_MEDIA_STATE_DISCONNECTED) 172 == NDIS_MEDIA_STATE_DISCONNECTED)
@@ -729,7 +730,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
729 retval = 0; 730 retval = 0;
730 731
731 /* FIXME use these NDIS_PACKET_TYPE_* bitflags to 732 /* FIXME use these NDIS_PACKET_TYPE_* bitflags to
732 * filter packets in hard_start_xmit() 733 * set the cdc_filter; it's not RNDIS-specific
733 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: 734 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
734 * PROMISCUOUS, DIRECTED, 735 * PROMISCUOUS, DIRECTED,
735 * MULTICAST, ALL_MULTICAST, BROADCAST 736 * MULTICAST, ALL_MULTICAST, BROADCAST
@@ -1194,10 +1195,10 @@ void rndis_add_hdr (struct sk_buff *skb)
1194 return; 1195 return;
1195 header = (void *) skb_push (skb, sizeof *header); 1196 header = (void *) skb_push (skb, sizeof *header);
1196 memset (header, 0, sizeof *header); 1197 memset (header, 0, sizeof *header);
1197 header->MessageType = __constant_cpu_to_le32 (1); 1198 header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
1198 header->MessageLength = cpu_to_le32(skb->len); 1199 header->MessageLength = cpu_to_le32(skb->len);
1199 header->DataOffset = __constant_cpu_to_le32 (36); 1200 header->DataOffset = __constant_cpu_to_le32 (36);
1200 header->OOBDataOffset = cpu_to_le32(skb->len - 44); 1201 header->DataLength = cpu_to_le32(skb->len - sizeof *header);
1201} 1202}
1202 1203
1203void rndis_free_response (int configNr, u8 *buf) 1204void rndis_free_response (int configNr, u8 *buf)
@@ -1253,26 +1254,23 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
1253 return r; 1254 return r;
1254} 1255}
1255 1256
1256int rndis_rm_hdr (u8 *buf, u32 *length) 1257int rndis_rm_hdr(struct sk_buff *skb)
1257{ 1258{
1258 u32 i, messageLen, dataOffset; 1259 /* tmp points to a struct rndis_packet_msg_type */
1259 __le32 *tmp; 1260 __le32 *tmp = (void *) skb->data;
1260
1261 tmp = (__le32 *) buf;
1262 1261
1263 if (!buf || !length) return -1; 1262 /* MessageType, MessageLength */
1264 if (le32_to_cpup(tmp++) != 1) return -1; 1263 if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
1265 1264 != get_unaligned(tmp++))
1266 messageLen = le32_to_cpup(tmp++); 1265 return -EINVAL;
1267 dataOffset = le32_to_cpup(tmp++) + 8; 1266 tmp++;
1267
1268 /* DataOffset, DataLength */
1269 if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
1270 + 8 /* offset of DataOffset */))
1271 return -EOVERFLOW;
1272 skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
1268 1273
1269 if (messageLen < dataOffset || messageLen > *length) return -1;
1270
1271 for (i = dataOffset; i < messageLen; i++)
1272 buf [i - dataOffset] = buf [i];
1273
1274 *length = messageLen - dataOffset;
1275
1276 return 0; 1274 return 0;
1277} 1275}
1278 1276
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 822501852c50..2b5b55df3cfd 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -38,6 +38,7 @@
38 */ 38 */
39 39
40/* Message Set for Connectionless (802.3) Devices */ 40/* Message Set for Connectionless (802.3) Devices */
41#define REMOTE_NDIS_PACKET_MSG 0x00000001U
41#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */ 42#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */
42#define REMOTE_NDIS_HALT_MSG 0x00000003U 43#define REMOTE_NDIS_HALT_MSG 0x00000003U
43#define REMOTE_NDIS_QUERY_MSG 0x00000004U 44#define REMOTE_NDIS_QUERY_MSG 0x00000004U
@@ -333,7 +334,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID,
333 const char *vendorDescr); 334 const char *vendorDescr);
334int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); 335int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
335void rndis_add_hdr (struct sk_buff *skb); 336void rndis_add_hdr (struct sk_buff *skb);
336int rndis_rm_hdr (u8 *buf, u32 *length); 337int rndis_rm_hdr (struct sk_buff *skb);
337u8 *rndis_get_next_response (int configNr, u32 *length); 338u8 *rndis_get_next_response (int configNr, u32 *length);
338void rndis_free_response (int configNr, u8 *buf); 339void rndis_free_response (int configNr, u8 *buf);
339 340