ChangeSet 1.1932, 2004/04/22 13:43:39-07:00, [EMAIL PROTECTED]
[PATCH] USB: rndis gadget driver updates
Various build fixes: 64bit (Andrew Morton), static linking,
broken on big-endian, etc.
Tighten up the integration with the main "ether" driver, so
state transitions and host ethernet addresses are shared too.
Add missing spinlock calls around RNDIS command outcall,
fix GET_INTERFACE issue, host mustn't clobber netdev flags.
Minor code cleanups.
drivers/usb/gadget/ether.c | 49 +++++++++-------
drivers/usb/gadget/rndis.c | 135 +++++++++++++++++++++++++++++----------------
drivers/usb/gadget/rndis.h | 7 +-
3 files changed, 120 insertions(+), 71 deletions(-)
diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
--- a/drivers/usb/gadget/ether.c Thu Apr 22 14:41:20 2004
+++ b/drivers/usb/gadget/ether.c Thu Apr 22 14:41:20 2004
@@ -120,6 +120,7 @@
unsigned long todo;
#define WORK_RX_MEMORY 0
int rndis_config;
+ u8 host_mac [ETH_ALEN];
};
/* This version autoconfigures as much as possible at run-time.
@@ -159,9 +160,8 @@
/* For hardware that can talk RNDIS and either of the above protocols,
* use this ID ... the windows INF files will know it. Unless it's
- * used with CDC Ethernet, Linux hosts will need updates to choose the
- * non-MSFT configuration, either in the kernel (2.4) or else from a
- * hotplug script (2.6).
+ * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose
+ * the non-RNDIS configuration.
*/
#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
@@ -1334,8 +1334,10 @@
struct eth_dev *dev = ep->driver_data;
/* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */
+ spin_lock(&dev->lock);
if (rndis_msg_parser (dev->rndis_config, (u8 *) req->buf))
ERROR(dev, "%s: rndis parse error\n", __FUNCTION__ );
+ spin_unlock(&dev->lock);
}
#endif /* RNDIS */
@@ -1486,14 +1488,14 @@
|| !dev->config
|| ctrl->wIndex > 1)
break;
- if (!dev->cdc && ctrl->wIndex != 0)
+ if (!(dev->cdc || dev->rndis) && ctrl->wIndex != 0)
break;
- /* if carrier is on, data interface is active. */
- *(u8 *)req->buf =
- ((ctrl->wIndex == 1) && netif_carrier_ok (dev->net))
- ? 1
- : 0,
+ /* for CDC, iff carrier is on, data interface is active. */
+ if (dev->rndis || ctrl->wIndex != 1)
+ *(u8 *)req->buf = 0;
+ else
+ *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
value = min (ctrl->wLength, (u16) 1);
break;
@@ -1552,6 +1554,7 @@
memcpy (req->buf, buf, value);
req->complete = rndis_response_complete;
}
+ /* else stalls ... spec says to avoid that */
}
break;
#endif /* RNDIS */
@@ -1590,6 +1593,8 @@
eth_reset_config (dev);
spin_unlock_irqrestore (&dev->lock, flags);
+ /* FIXME RNDIS should enter RNDIS_UNINITIALIZED */
+
/* next we may get setup() calls to enumerate new connections;
* or an unbind() during shutdown (including removing module).
*/
@@ -2376,19 +2381,19 @@
*/
random_ether_addr(net->dev_addr);
-#ifdef DEV_CONFIG_CDC
/* ... another address for the host, on the other end of the
* link, gets exported through CDC (see CDC spec table 41)
+ * and RNDIS.
*/
- if (cdc) {
- u8 node_id [ETH_ALEN];
-
- random_ether_addr(node_id);
+ if (cdc || rndis) {
+ random_ether_addr(dev->host_mac);
+#ifdef DEV_CONFIG_CDC
snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
- node_id [0], node_id [1], node_id [2],
- node_id [3], node_id [4], node_id [5]);
- }
+ dev->host_mac [0], dev->host_mac [1],
+ dev->host_mac [2], dev->host_mac [3],
+ dev->host_mac [4], dev->host_mac [5]);
#endif
+ }
if (rndis) {
status = rndis_init();
@@ -2448,10 +2453,11 @@
net->dev_addr [2], net->dev_addr [3],
net->dev_addr [4], net->dev_addr [5]);
-#ifdef DEV_CONFIG_CDC
- if (cdc)
- INFO (dev, "CDC host enet %s\n", ethaddr);
-#endif
+ if (cdc || rndis)
+ INFO (dev, "HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->host_mac [0], dev->host_mac [1],
+ dev->host_mac [2], dev->host_mac [3],
+ dev->host_mac [4], dev->host_mac [5]);
#ifdef CONFIG_USB_ETH_RNDIS
if (rndis) {
@@ -2468,6 +2474,7 @@
}
/* these set up a lot of the OIDs that RNDIS needs */
+ rndis_set_host_mac (dev->rndis_config, dev->host_mac);
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats))
goto fail0;
diff -Nru a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
--- a/drivers/usb/gadget/rndis.c Thu Apr 22 14:41:20 2004
+++ b/drivers/usb/gadget/rndis.c Thu Apr 22 14:41:20 2004
@@ -37,6 +37,16 @@
#include "rndis.h"
+/* The driver for your USB chip needs to support ep0 OUT to work with
+ * RNDIS, plus the same three descriptors as CDC Ethernet.
+ *
+ * Windows hosts need an INF file like Documentation/usb/linux.inf
+ */
+
+#ifndef __LITTLE_ENDIAN
+#warning this code is missing all cpu_to_leXX() calls ...
+#endif
+
#if 0
#define DEBUG if (rndis_debug) printk
static int rndis_debug = 0;
@@ -89,8 +99,12 @@
static void currentFilter2devFlags (u32 currentFilter, struct net_device *dev)
{
+ /* FIXME the filter is supposed to control what gets
+ * forwarded from gadget to host; but dev->flags controls
+ * reporting from host to gadget ...
+ */
+#if 0
if (!dev) return;
-
if (currentFilter & NDIS_PACKET_TYPE_MULTICAST)
dev->flags |= IFF_MULTICAST;
if (currentFilter & NDIS_PACKET_TYPE_BROADCAST)
@@ -99,8 +113,13 @@
dev->flags |= IFF_ALLMULTI;
if (currentFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
dev->flags |= IFF_PROMISC;
+#endif
}
+/* FIXME OMITTED OIDs, that RNDIS-on-USB "must" support, include
+ * - power management (OID_PNP_CAPABILITIES, ...)
+ * - network wakeup (OID_PNP_ENABLE_WAKE_UP, ...)
+ */
/* NDIS Functions */
static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
@@ -114,8 +133,6 @@
if (!resp) return -ENOMEM;
- if (!resp) return -ENOMEM;
-
switch (OID) {
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
@@ -178,7 +195,8 @@
case OID_GEN_LINK_SPEED:
DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
length = 4;
- if (rndis_per_dev_params [configNr].media_state)
+ if (rndis_per_dev_params [configNr].media_state
+ == NDIS_MEDIA_STATE_DISCONNECTED)
*((u32 *) resp + 6) = 0;
else
*((u32 *) resp + 6) = rndis_per_dev_params [configNr].speed;
@@ -611,15 +629,10 @@
case OID_802_3_PERMANENT_ADDRESS:
DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
- length = 6;
+ length = ETH_ALEN;
memcpy ((u8 *) resp + 24,
- rndis_per_dev_params [configNr].dev->dev_addr,
+ rndis_per_dev_params [configNr].host_mac,
length);
- /*
- * we need a MAC address and hope that
- * (our MAC + 1) is not in use
- */
- *((u8 *) resp + 29) += 1;
retval = 0;
} else {
*((u32 *) resp + 6) = 0;
@@ -631,15 +644,10 @@
case OID_802_3_CURRENT_ADDRESS:
DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
- length = 6;
+ length = ETH_ALEN;
memcpy ((u8 *) resp + 24,
- rndis_per_dev_params [configNr].dev->dev_addr,
+ rndis_per_dev_params [configNr].host_mac,
length);
- /*
- * we need a MAC address and hope that
- * (our MAC + 1) is not in use
- */
- *((u8 *) resp + 29) += 1;
retval = 0;
}
break;
@@ -746,22 +754,38 @@
rndis_set_cmplt_type *resp;
int i, retval = -ENOTSUPP;
struct rndis_config_parameter *param;
-
- if (!r) return -ENOMEM;
+ struct rndis_params *params;
+ u8 *cp;
+
+ if (!r)
+ return -ENOMEM;
resp = (rndis_set_cmplt_type *) r->buf;
-
- if (!resp) return -ENOMEM;
-
+ if (!resp)
+ return -ENOMEM;
+
+ cp = (u8 *)resp;
+
switch (OID) {
case OID_GEN_CURRENT_PACKET_FILTER:
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
- currentFilter2devFlags ((u32) ((u8 *) resp + 28),
- rndis_per_dev_params [configNr].dev);
+ params = &rndis_per_dev_params [configNr];
+ currentFilter2devFlags(cp[28], params->dev);
retval = 0;
- if ((u32) ((u8 *) resp + 28))
- rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED;
- else
- rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+
+ /* this call has a significant side effect: it's
+ * what makes the packet flow start and stop, like
+ * activating the CDC Ethernet altsetting.
+ */
+ if (cp[28]) {
+ params->state = RNDIS_DATA_INITIALIZED;
+ netif_carrier_on(params->dev);
+ if (netif_running(params->dev))
+ netif_wake_queue (params->dev);
+ } else {
+ params->state = RNDIS_INITIALIZED;
+ netif_carrier_off (params->dev);
+ netif_stop_queue (params->dev);
+ }
break;
case OID_802_3_MULTICAST_LIST:
@@ -937,10 +961,9 @@
{
rndis_keepalive_cmplt_type *resp;
rndis_resp_t *r;
-
- /* respond only in RNDIS_INITIALIZED state */
- if (rndis_per_dev_params [configNr].state != RNDIS_INITIALIZED)
- return 0;
+
+ /* host "should" check only in RNDIS_DATA_INITIALIZED state */
+
r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
resp = (rndis_keepalive_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
@@ -1004,35 +1027,48 @@
RNDIS_STATUS_MEDIA_DISCONNECT);
}
+void rndis_set_host_mac (int configNr, const u8 *addr)
+{
+ rndis_per_dev_params [configNr].host_mac = addr;
+}
+
/*
* Message Parser
*/
int rndis_msg_parser (u8 configNr, u8 *buf)
{
u32 MsgType, MsgLength, *tmp;
+ struct rndis_params *params;
- if (!buf) return -ENOMEM;
+ if (!buf)
+ return -ENOMEM;
tmp = (u32 *) buf;
MsgType = *tmp;
MsgLength = *(tmp + 1);
- if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP;
+ if (configNr >= RNDIS_MAX_CONFIGS)
+ return -ENOTSUPP;
+ params = &rndis_per_dev_params [configNr];
+ /* For USB: responses may take up to 10 seconds */
switch (MsgType)
{
- case REMOTE_NDIS_INIZIALIZE_MSG:
- DEBUG(KERN_INFO "%s: REMOTE_NDIS_INIZIALIZE_MSG\n",
+ case REMOTE_NDIS_INITIALIZE_MSG:
+ DEBUG(KERN_INFO "%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
- rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED;
+ params->state = RNDIS_INITIALIZED;
return rndis_init_response (configNr,
(rndis_init_msg_type *) buf);
- break;
case REMOTE_NDIS_HALT_MSG:
DEBUG(KERN_INFO "%s: REMOTE_NDIS_HALT_MSG\n",
__FUNCTION__ );
- rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+ params->state = RNDIS_UNINITIALIZED;
+ if (params->dev) {
+ netif_carrier_off (params->dev);
+ netif_stop_queue (params->dev);
+ }
return 0;
case REMOTE_NDIS_QUERY_MSG:
@@ -1040,29 +1076,26 @@
__FUNCTION__ );
return rndis_query_response (configNr,
(rndis_query_msg_type *) buf);
- break;
case REMOTE_NDIS_SET_MSG:
DEBUG(KERN_INFO "%s: REMOTE_NDIS_SET_MSG\n",
__FUNCTION__ );
return rndis_set_response (configNr,
(rndis_set_msg_type *) buf);
- break;
case REMOTE_NDIS_RESET_MSG:
DEBUG(KERN_INFO "%s: REMOTE_NDIS_RESET_MSG\n",
__FUNCTION__ );
return rndis_reset_response (configNr,
(rndis_reset_msg_type *) buf);
- break;
case REMOTE_NDIS_KEEPALIVE_MSG:
+ /* For USB: host does this every 5 seconds */
DEBUG(KERN_INFO "%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
buf);
- break;
default:
printk (KERN_ERR "%s: unknown RNDIS Message Type 0x%08X\n",
@@ -1240,9 +1273,15 @@
"vendor ID : 0x%08X\n"
"vendor : %s\n",
param->confignr, (param->used) ? "y" : "n",
- (param->state)
- ? "RNDIS_INITIALIZED"
- : "RNDIS_UNINITIALIZED",
+ ({ char *s = "?";
+ switch (param->state) {
+ case RNDIS_UNINITIALIZED:
+ s = "RNDIS_UNINITIALIZED"; break;
+ case RNDIS_INITIALIZED:
+ s = "RNDIS_INITIALIZED"; break;
+ case RNDIS_DATA_INITIALIZED:
+ s = "RNDIS_DATA_INITIALIZED"; break;
+ }; s; }),
param->medium,
(param->media_state) ? 0 : param->speed*100,
(param->media_state) ? "disconnected" : "connected",
@@ -1353,7 +1392,7 @@
return 0;
}
-void __exit rndis_exit (void)
+void rndis_exit (void)
{
u8 i;
char name [4];
diff -Nru a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
--- a/drivers/usb/gadget/rndis.h Thu Apr 22 14:41:20 2004
+++ b/drivers/usb/gadget/rndis.h Thu Apr 22 14:41:20 2004
@@ -38,7 +38,7 @@
*/
/* Message Set for Connectionless (802.3) Devices */
-#define REMOTE_NDIS_INIZIALIZE_MSG 0x00000002U /* Initialize device */
+#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */
#define REMOTE_NDIS_HALT_MSG 0x00000003U
#define REMOTE_NDIS_QUERY_MSG 0x00000004U
#define REMOTE_NDIS_SET_MSG 0x00000005U
@@ -280,6 +280,7 @@
u32 medium;
u32 speed;
u32 media_state;
+ const u8 *host_mac;
struct net_device *dev;
struct net_device_stats *stats;
u32 vendorID;
@@ -301,11 +302,13 @@
int rndis_rm_hdr (u8 *buf, u32 *length);
u8 *rndis_get_next_response (int configNr, u32 *length);
void rndis_free_response (int configNr, u8 *buf);
+
int rndis_signal_connect (int configNr);
int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
+extern void rndis_set_host_mac (int configNr, const u8 *addr);
int __init rndis_init (void);
-void __exit rndis_exit (void);
+void rndis_exit (void);
#endif /* _LINUX_RNDIS_H */
-------------------------------------------------------
This SF.net email is sponsored by: The Robotic Monkeys at ThinkGeek
For a limited time only, get FREE Ground shipping on all orders of $35
or more. Hurry up and shop folks, this offer expires April 30th!
http://www.thinkgeek.com/freeshipping/?cpg297
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel