ether.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,360 行 · 第 1/5 页

C
2,360
字号
	}}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 void /* __init_or_exit */eth_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 __devinit 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 int __devinit 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 0;	}	random_ether_addr(dev_addr);	return 1;}static int __deviniteth_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 */	/* 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_musbhdrc(gadget)) {		/* reduce tx dma overhead by avoiding special cases */		zlp = 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",		init_utsname()->sysname, init_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.  (That may be improved by	 * supporting one submode of the "SAFE" variant of MDLM.)	 */	} else if (!cdc) {		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);	if (iSerialNumber) {		device_desc.iSerialNumber = STRING_SERIALNUMBER,		strlcpy(serial_number, iSerialNumber, sizeof serial_number);	}	/* 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 */	/* 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;		/* pxa25x only does CDC subset; often used with RNDIS */		} else if (cdc) {			control_intf.bNumEndpoints = 0;			/* FIXME remove endpoint from descriptor list */		}	}	/* one config:  cdc, else minimal subset */	if (!cdc) {		eth_config.bNumInterfaces = 1;		eth_config.iConfiguration = STRING_SUBSET;		/* use functions to set these up, in case we're built to work		 * with multiple controllers and must override CDC Ethernet.		 */		fs_subset_descriptors();		hs_subset_descriptors();	}	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;	usb_gadget_set_selfpowered (gadget);	/* For now RNDIS is always a second config */	if (rndis)		device_desc.bNumConfigurations = 2;	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 (status_ep)		hs_status_desc.bEndpointAddress =				fs_status_desc.bEndpointAddress;	if (gadget->is_otg) {		otg_descriptor.bmAttributes |= USB_OTG_HNP,		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		eth_config.bMaxPower = 4;		rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		rndis_config.bMaxPower = 4;	}	net = alloc_etherdev (sizeof *dev);	if (!net)		return status;	dev = netdev_priv(net);	spin_lock_init (&dev->lock);	spin_lock_init (&dev->req_lock);	INIT_WORK (&dev->work, eth_work);	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.  It's not clear if	 * host side code for the SAFE thing cares -- its original BLAN	 * thing didn't, Sharp never assigned those addresses on Zaurii.	 */	if (get_ether_addr(dev_addr, net->dev_addr))		dev_warn(&gadget->dev,			"using random %s ethernet address\n", "self");	if (get_ether_addr(host_addr, dev->host_mac))		dev_warn(&gadget->dev,			"using random %s ethernet address\n", "host");	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]);	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, GFP_KERNEL);	if (!dev->req)		goto fail;	dev->req->complete = eth_setup_complete;	/* ... and maybe likewise for status transfer */	if (dev->status_ep) {		dev->stat_req = eth_req_alloc (dev->status_ep,					STATUS_BYTECOUNT, GFP_KERNEL);		if (!dev->stat_req) {			eth_req_free (gadget->ep0, dev->req);			goto fail;		}		dev->stat_req->context = NULL;	}	/* finish hookup to lower layer ... */	dev->gadget = gadget;	set_gadget_data (gadget, dev);	gadget->ep0->driver_data = dev;	/* two kinds of host-initiated state changes:	 *  - iff DATA transfer is active, carrier is "on"	 *  - tx queueing enabled if open *and* carrier is "on"	 */	netif_stop_queue (dev->net);	netif_carrier_off (dev->net);	SET_NETDEV_DEV (dev->net, &gadget->dev);	status = register_netdev (dev->net);	if (status < 0)		goto fail1;	INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);	INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,		out_ep->name, in_ep->name,		status_ep ? " STATUS " : "",		status_ep ? status_ep->name : ""		);	INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",		net->dev_addr [0], net->dev_addr [1],		net->dev_addr [2], net->dev_addr [3],		net->dev_addr [4], net->dev_addr [5]);	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]);	if (rndis) {		u32	vendorID = 0;		/* FIXME RNDIS vendor id == "vendor NIC code" == ? */		dev->rndis_config = rndis_register (rndis_control_ack);		if (dev->rndis_config < 0) {fail0:			unregister_netdev (dev->net);			status = -ENODEV;			goto fail;		}		/* 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, &dev->cdc_filter))			goto fail0;		if (rndis_set_param_vendor (dev->rndis_config, vendorID,					    manufacturer))			goto fail0;		if (rndis_set_param_medium (dev->rndis_config,					    NDIS_MEDIUM_802_3,					    0))			goto fail0;		INFO (dev, "RNDIS ready\n");	}	return status;fail1:	dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status);fail:	eth_unbind (gadget);	return status;}/*-------------------------------------------------------------------------*/static voideth_suspend (struct usb_gadget *gadget){	struct eth_dev		*dev = get_gadget_data (gadget);	DEBUG (dev, "suspend\n");	dev->suspended = 1;}static voideth_resume (struct usb_gadget *gadget){	struct eth_dev		*dev = get_gadget_data (gadget);	DEBUG (dev, "resume\n");	dev-

⌨️ 快捷键说明

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