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

📄 ether.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
		spin_unlock_irqrestore (&dev->lock, flags);		if (rx_submit (dev, req, gfp_flags) < 0) {			defer_kevent (dev, WORK_RX_MEMORY);			return;		}		spin_lock_irqsave (&dev->lock, flags);	}	spin_unlock_irqrestore (&dev->lock, flags);}static void eth_work (void *_dev){	struct eth_dev		*dev = _dev;	if (test_bit (WORK_RX_MEMORY, &dev->todo)) {		if (netif_running (dev->net))			rx_fill (dev, GFP_KERNEL);		else			clear_bit (WORK_RX_MEMORY, &dev->todo);	}	if (dev->todo)		DEBUG (dev, "work done, flags = 0x%lx\n", dev->todo);}static void tx_complete (struct usb_ep *ep, struct usb_request *req){	struct sk_buff	*skb = req->context;	struct eth_dev	*dev = ep->driver_data;	switch (req->status) {	default:		dev->stats.tx_errors++;		VDEBUG (dev, "tx err %d\n", req->status);		/* FALLTHROUGH */	case -ECONNRESET:		// unlink	case -ESHUTDOWN:		// disconnect etc		break;	case 0:		dev->stats.tx_bytes += skb->len;	}	dev->stats.tx_packets++;	spin_lock (&dev->lock);	list_add (&req->list, &dev->tx_reqs);	spin_unlock (&dev->lock);	dev_kfree_skb_any (skb);	atomic_dec (&dev->tx_qlen);	if (netif_carrier_ok (dev->net))		netif_wake_queue (dev->net);}static int eth_start_xmit (struct sk_buff *skb, struct net_device *net){	struct eth_dev		*dev = netdev_priv(net);	int			length = skb->len;	int			retval;	struct usb_request	*req = NULL;	unsigned long		flags;	/* FIXME check dev->cdc_filter to decide whether to send this,	 * instead of acting as if CDC_PACKET_TYPE_PROMISCUOUS were	 * always set.  RNDIS has the same kind of outgoing filter.	 */	spin_lock_irqsave (&dev->lock, flags);	req = container_of (dev->tx_reqs.next, struct usb_request, list);	list_del (&req->list);	if (list_empty (&dev->tx_reqs))		netif_stop_queue (net);	spin_unlock_irqrestore (&dev->lock, flags);	/* no buffer copies needed, unless the network stack did it	 * or the hardware can't use skb buffers.	 * or there's not enough space for any RNDIS headers we need	 */#ifdef CONFIG_USB_ETH_RNDIS	if (dev->rndis) {		struct sk_buff	*skb_rndis;		skb_rndis = skb_realloc_headroom (skb,				sizeof (struct rndis_packet_msg_type));		if (!skb_rndis)			goto drop;			dev_kfree_skb_any (skb);		skb = skb_rndis;		rndis_add_hdr (skb);		length = skb->len;	}#endif	req->buf = skb->data;	req->context = skb;	req->complete = tx_complete;	/* use zlp framing on tx for strict CDC-Ether conformance,	 * though any robust network rx path ignores extra padding.	 * and some hardware doesn't like to write zlps.	 */	req->zero = 1;	if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)		length++;	req->length = length;#ifdef	CONFIG_USB_GADGET_DUALSPEED	/* throttle highspeed IRQ rate back slightly */	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)		: 0;#endif	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) {#ifdef CONFIG_USB_ETH_RNDISdrop:#endif		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_RNDISstatic void rndis_send_media_state (struct eth_dev *dev, int connect){	if (!dev)		return;		if (connect) {		if (rndis_signal_connect (dev->rndis_config))			return;	} else {		if (rndis_signal_disconnect (dev->rndis_config))			return;	}}static voidrndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req){	if (req->status || req->actual != req->length)		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;		/* in case RNDIS calls this after disconnect */	if (!dev->status_ep) {		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;	 * CDC_NOTIFY_RESPONSE_AVAILABLE should work too	 */	resp->length = 8;	resp->complete = rndis_control_ack_complete;		*((u32 *) resp->buf) = __constant_cpu_to_le32 (1);	*((u32 *) 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;}#endif	/* RNDIS */static void eth_start (struct eth_dev *dev, int 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);#ifdef CONFIG_USB_ETH_RNDIS	if (dev->rndis) {		rndis_set_param_medium (dev->rndis_config,					NDIS_MEDIUM_802_3,					BITRATE(dev->gadget));		rndis_send_media_state (dev, 1);	}#endif	}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);		}	}	#ifdef	CONFIG_USB_ETH_RNDIS	if (dev->rndis) {		rndis_set_param_medium (dev->rndis_config,					NDIS_MEDIUM_802_3, 0);		rndis_send_media_state (dev, 0);	}#endif	return 0;}/*-------------------------------------------------------------------------*/static voideth_unbind (struct usb_gadget *gadget){	struct eth_dev		*dev = get_gadget_data (gadget);	DEBUG (dev, "unbind\n");#ifdef CONFIG_USB_ETH_RNDIS	rndis_deregister (dev->rndis_config);	rndis_exit ();#endif	/* we've already been disconnected ... no i/o is active */	if (dev->req) {		usb_ep_free_buffer (gadget->ep0,				dev->req->buf, dev->req->dma,				USB_BUFSIZ);		usb_ep_free_request (gadget->ep0, dev->req);		dev->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		*ep;	int			status = -ENOMEM;	/* 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_net2280 (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);	} else if (gadget_is_dummy (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0202);	} else if (gadget_is_pxa (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);		/* pxa doesn't support altsettings */		cdc = 0;	} else if (gadget_is_sh(gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);		/* sh doesn't support multiple interfaces or configs */		cdc = 0;		rndis = 0;	} else if (gadget_is_sa1100 (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);		/* 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;	} else if (gadget_is_goku (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);	} else if (gadget_is_mq11xx (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);	} else if (gadget_is_omap (gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);	} else if (gadget_is_lh7a40x(gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);	} else if (gadget_is_n9604(gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);	} else if (gadget_is_pxa27x(gadget)) {		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);	} 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);	ep = usb_ep_autoconfig (gadget, &fs_source_desc);	if (!ep) {autoconf_fail:		dev_err (&gadget->dev,			"can't autoconfigure on %s\n",			gadget->name);		return -ENODEV;	}	EP_IN_NAME = ep->name;	ep->driver_data = ep;	/* claim */		ep = usb_ep_autoconfig (gadget, &fs_sink_desc);	if (!ep)		goto autoconf_fail;	EP_OUT_NAME = ep->name;	ep->driver_data = 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) {		ep = usb_ep_autoconfig (gadget, 

⌨️ 快捷键说明

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