⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ether.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);	switch (retval) {	default:		DEBUG (dev, "tx queue err %d\n", retval);		break;	case 0:		net->trans_start = jiffies;		atomic_inc (&dev->tx_qlen);	}	if (retval) {drop:		dev->stats.tx_dropped++;		dev_kfree_skb_any (skb);		spin_lock_irqsave (&dev->lock, flags);		if (list_empty (&dev->tx_reqs))			netif_start_queue (net);		list_add (&req->list, &dev->tx_reqs);		spin_unlock_irqrestore (&dev->lock, flags);	}	return 0;}/*-------------------------------------------------------------------------*/#ifdef CONFIG_USB_ETH_RNDIS/* The interrupt endpoint is used in RNDIS to notify the host when messages * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even * REMOTE_NDIS_KEEPALIVE_MSG. * * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and * normally just one notification will be queued. */static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, gfp_t);static void eth_req_free (struct usb_ep *ep, struct usb_request *req);static voidrndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req){	struct eth_dev          *dev = ep->driver_data;	if (req->status || req->actual != req->length)		DEBUG (dev,			"rndis control ack complete --> %d, %d/%d\n",			req->status, req->actual, req->length);	req->context = NULL;	if (req != dev->stat_req)		eth_req_free(ep, req);}static int rndis_control_ack (struct net_device *net){	struct eth_dev          *dev = netdev_priv(net);	u32                     length;	struct usb_request      *resp = dev->stat_req;		/* in case RNDIS calls this after disconnect */	if (!dev->status) {		DEBUG (dev, "status ENODEV\n");		return -ENODEV;	}	/* in case queue length > 1 */	if (resp->context) {		resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);		if (!resp)			return -ENOMEM;	}	/* Send RNDIS RESPONSE_AVAILABLE notification;	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too	 */	resp->length = 8;	resp->complete = rndis_control_ack_complete;	resp->context = dev;		*((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);	*((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);		length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);	if (length < 0) {		resp->status = 0;		rndis_control_ack_complete (dev->status_ep, resp);	}		return 0;}#else#define	rndis_control_ack	NULL#endif	/* RNDIS */static void eth_start (struct eth_dev *dev, gfp_t gfp_flags){	DEBUG (dev, "%s\n", __FUNCTION__);	/* fill the rx queue */	rx_fill (dev, gfp_flags);	/* and open the tx floodgates */ 	atomic_set (&dev->tx_qlen, 0);	netif_wake_queue (dev->net);	if (rndis_active(dev)) {		rndis_set_param_medium (dev->rndis_config,					NDIS_MEDIUM_802_3,					BITRATE(dev->gadget)/100);		(void) rndis_signal_connect (dev->rndis_config);	}}static int eth_open (struct net_device *net){	struct eth_dev		*dev = netdev_priv(net);	DEBUG (dev, "%s\n", __FUNCTION__);	if (netif_carrier_ok (dev->net))		eth_start (dev, GFP_KERNEL);	return 0;}static int eth_stop (struct net_device *net){	struct eth_dev		*dev = netdev_priv(net);	VDEBUG (dev, "%s\n", __FUNCTION__);	netif_stop_queue (net);	DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",		dev->stats.rx_packets, dev->stats.tx_packets, 		dev->stats.rx_errors, dev->stats.tx_errors		);	/* ensure there are no more active requests */	if (dev->config) {		usb_ep_disable (dev->in_ep);		usb_ep_disable (dev->out_ep);		if (netif_carrier_ok (dev->net)) {			DEBUG (dev, "host still using in/out endpoints\n");			// FIXME idiom may leave toggle wrong here			usb_ep_enable (dev->in_ep, dev->in);			usb_ep_enable (dev->out_ep, dev->out);		}		if (dev->status_ep) {			usb_ep_disable (dev->status_ep);			usb_ep_enable (dev->status_ep, dev->status);		}	}		if (rndis_active(dev)) {		rndis_set_param_medium (dev->rndis_config,					NDIS_MEDIUM_802_3, 0);		(void) rndis_signal_disconnect (dev->rndis_config);	}	return 0;}/*-------------------------------------------------------------------------*/static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags){	struct usb_request	*req;	req = usb_ep_alloc_request (ep, gfp_flags);	if (!req)		return NULL;	req->buf = kmalloc (size, gfp_flags);	if (!req->buf) {		usb_ep_free_request (ep, req);		req = NULL;	}	return req;}static voideth_req_free (struct usb_ep *ep, struct usb_request *req){	kfree (req->buf);	usb_ep_free_request (ep, req);}static voideth_unbind (struct usb_gadget *gadget){	struct eth_dev		*dev = get_gadget_data (gadget);	DEBUG (dev, "unbind\n");	rndis_deregister (dev->rndis_config);	rndis_exit ();	/* we've already been disconnected ... no i/o is active */	if (dev->req) {		eth_req_free (gadget->ep0, dev->req);		dev->req = NULL;	}	if (dev->stat_req) {		eth_req_free (dev->status_ep, dev->stat_req);		dev->stat_req = NULL;	}	unregister_netdev (dev->net);	free_netdev(dev->net);	/* assuming we used keventd, it must quiesce too */	flush_scheduled_work ();	set_gadget_data (gadget, NULL);}static u8 __init 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 void __init get_ether_addr (const char *str, u8 *dev_addr){	if (str) {		unsigned	i;		for (i = 0; i < 6; i++) {			unsigned char num;			if((*str == '.') || (*str == ':'))				str++;			num = nibble(*str++) << 4;			num |= (nibble(*str++));			dev_addr [i] = num;		}		if (is_valid_ether_addr (dev_addr))			return;	}	random_ether_addr(dev_addr);}static int __initeth_bind (struct usb_gadget *gadget){	struct eth_dev		*dev;	struct net_device	*net;	u8			cdc = 1, zlp = 1, rndis = 1;	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;	int			status = -ENOMEM;	int			gcnum;	/* these flags are only ever cleared; compiler take note */#ifndef	DEV_CONFIG_CDC	cdc = 0;#endif#ifndef	CONFIG_USB_ETH_RNDIS	rndis = 0;#endif	/* Because most host side USB stacks handle CDC Ethernet, that	 * standard protocol is _strongly_ preferred for interop purposes.	 * (By everyone except Microsoft.)	 */	if (gadget_is_pxa (gadget)) {		/* pxa doesn't support altsettings */		cdc = 0;	} else if (gadget_is_sh(gadget)) {		/* sh doesn't support multiple interfaces or configs */		cdc = 0;		rndis = 0;	} else if (gadget_is_sa1100 (gadget)) {		/* hardware can't write zlps */		zlp = 0;		/* sa1100 CAN do CDC, without status endpoint ... we use		 * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".		 */		cdc = 0;	}	gcnum = usb_gadget_controller_number (gadget);	if (gcnum >= 0)		device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);	else {		/* can't assume CDC works.  don't want to default to		 * anything less functional on CDC-capable hardware,		 * so we fail in this case.		 */		dev_err (&gadget->dev,			"controller '%s' not recognized\n",			gadget->name);		return -ENODEV;	}	snprintf (manufacturer, sizeof manufacturer, "%s %s/%s",		system_utsname.sysname, system_utsname.release,		gadget->name);	/* If there's an RNDIS configuration, that's what Windows wants to	 * be using ... so use these product IDs here and in the "linux.inf"	 * needed to install MSFT drivers.  Current Linux kernels will use	 * the second configuration if it's CDC Ethernet, and need some help	 * to choose the right configuration otherwise.	 */	if (rndis) {		device_desc.idVendor =			__constant_cpu_to_le16(RNDIS_VENDOR_NUM);		device_desc.idProduct =			__constant_cpu_to_le16(RNDIS_PRODUCT_NUM);		snprintf (product_desc, sizeof product_desc,			"RNDIS/%s", driver_desc);	/* CDC subset ... recognized by Linux since 2.4.10, but Windows	 * drivers aren't widely available.	 */	} else if (!cdc) {		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;		device_desc.idVendor =			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);		device_desc.idProduct =			__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);	}	/* support optional vendor/distro customization */	if (idVendor) {		if (!idProduct) {			dev_err (&gadget->dev, "idVendor needs idProduct!\n");			return -ENODEV;		}		device_desc.idVendor = cpu_to_le16(idVendor);		device_desc.idProduct = cpu_to_le16(idProduct);		if (bcdDevice)			device_desc.bcdDevice = cpu_to_le16(bcdDevice);	}	if (iManufacturer)		strlcpy (manufacturer, iManufacturer, sizeof manufacturer);	if (iProduct)		strlcpy (product_desc, iProduct, sizeof product_desc);	/* all we really need is bulk IN/OUT */	usb_ep_autoconfig_reset (gadget);	in_ep = usb_ep_autoconfig (gadget, &fs_source_desc);	if (!in_ep) {autoconf_fail:		dev_err (&gadget->dev,			"can't autoconfigure on %s\n",			gadget->name);		return -ENODEV;	}	in_ep->driver_data = in_ep;	/* claim */		out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);	if (!out_ep)		goto autoconf_fail;	out_ep->driver_data = out_ep;	/* claim */#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)	/* CDC Ethernet control interface doesn't require a status endpoint.	 * Since some hosts expect one, try to allocate one anyway.	 */	if (cdc || rndis) {		status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);		if (status_ep) {			status_ep->driver_data = status_ep;	/* claim */		} else if (rndis) {			dev_err (&gadget->dev,				"can't run RNDIS on %s\n",				gadget->name);			return -ENODEV;#ifdef DEV_CONFIG_CDC		/* pxa25x only does CDC subset; often used with RNDIS */		} else if (cdc) {			control_intf.bNumEndpoints = 0;			/* FIXME remove endpoint from descriptor list */#endif		}	}#endif	/* one config:  cdc, else minimal subset */	if (!cdc) {		eth_config.bNumInterfaces = 1;		eth_config.iConfiguration = STRING_SUBSET;		fs_subset_descriptors();		hs_subset_descriptors();	}	/* For now RNDIS is always a second config */	if (rndis)		device_desc.bNumConfigurations = 2;#ifdef	CONFIG_USB_GADGET_DUALSPEED	if (rndis)		dev_qualifier.bNumConfigurations = 2;	else if (!cdc)		dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;	/* assumes ep0 uses the same value for both speeds ... */	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;	/* and that all endpoints are dual-speed */	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)	if (status_ep)		hs_status_desc.bEndpointAddress =				fs_status_desc.bEndpointAddress;#endif#endif	/* DUALSPEED */	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;	usb_gadget_set_selfpowered (gadget);	if (gadget->is_otg) {		otg_descriptor.bmAttributes |= USB_OTG_HNP,		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		eth_config.bMaxPower = 4;#ifdef	CONFIG_USB_ETH_RNDIS		rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		rndis_config.bMaxPower = 4;#endif	} 	net = alloc_etherdev (sizeof *dev); 	if (!net)		return status;	dev = netdev_priv(net);	spin_lock_init (&dev->lock);	INIT_WORK (&dev->work, eth_work, dev);	INIT_LIST_HEAD (&dev->tx_reqs);	INIT_LIST_HEAD (&dev->rx_reqs);	/* network device setup */	dev->net = net;	SET_MODULE_OWNER (net);	strcpy (net->name, "usb%d");	dev->cdc = cdc;	dev->zlp = zlp;	dev->in_ep = in_ep;	dev->out_ep = out_ep;	dev->status_ep = status_ep;	/* Module params for these addresses should come from ID proms.	 * The host side address is used with CDC and RNDIS, and commonly	 * ends up in a persistent config database.	 */	get_ether_addr(dev_addr, net->dev_addr);	if (cdc || rndis) {		get_ether_addr(host_addr, dev->host_mac);#ifdef	DEV_CONFIG_CDC		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",			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();		if (status < 0) {			dev_err (&gadget->dev, "can't init RNDIS, %d\n",				status);			goto fail;		}	}	net->change_mtu = eth_change_mtu;	net->get_stats = eth_get_stats;	net->hard_start_xmit = eth_start_xmit;	net->open = eth_open;	net->stop = eth_stop;	// watchdog_timeo, tx_timeout ...	// set_multicast_list	SET_ETHTOOL_OPS(net, &ops);	/* preallocate control message data and buffer */	dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -