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

📄 ib-usb.c

📁 linux下的无线宽带驱动
💻 C
字号:
/* iBurst (TM) compatible driver for 2.6 Linux kernel. * based on the original ArrayComm (TM) iBurst (TM) driver. * Nicholas Jefferson <nicholas@pythontraining.com.au> * 11 May 2005 * * Ported to 2.6 Linux kernel by David Michael Barr. * Fixes to support new hardware by Shane MacPhillamy. * Fixes to support further new hardware by Nik Trevallyn-Jones. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include "ib-net.h"#include <asm/io.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/timer.h>#include <linux/usb.h>#define PROTO_USB_CONF 0x03#define VENDOR_USB_REQUEST (USB_DIR_IN | USB_TYPE_VENDOR)#define CONTROL_USB_GET_MAC_ADDR_UT_02 0x63#define CONTROL_USB_GET_MAC_ADDR_UT_04 0x4d#define UT_DEVICE_UT_02 0x0101#define UT_DEVICE_UT_04 0x0401static int debug = 0;module_param(debug, int, 0);#define DEBUG(n, args...) if (debug < (n)) ; else printk(KERN_INFO args)/** * struct ib_usb_priv_t - USB device private state. * @usbdev: USB device state. * @rx_urb: * @tx_urb: * @ctl_buf: buffer for control messages. * @modem: corresponding modem state. */struct ib_usb_priv_t {	struct usb_device *usbdev;	int rx_endpoint, tx_endpoint;	struct urb rx_urb;	struct urb tx_urb;	unsigned char ctl_buf[32];	struct ib_net_modem_t *modem;	short packet_modulo;};/** * ib_usb_conf - USB configuration frame. */static unsigned char ib_usb_conf[] = {	0x00, 0x08, 0x00, 0xf7, IB_PROTO, PROTO_USB_CONF, 0x00, 0x00,};/** * ib_usb_disconnect - USB device disconnected. * @usbintf: */static void ib_usb_disconnect(struct usb_interface *usbintf){	unsigned long state;	struct ib_usb_priv_t *priv = usb_get_intfdata(usbintf);	spin_lock_irqsave(&ib_lock, state);	priv->usbdev = NULL;	spin_unlock_irqrestore(&ib_lock, state);	if (priv->rx_urb.status == -EINPROGRESS)		usb_kill_urb(&priv->rx_urb);	if (priv->tx_urb.status == -EINPROGRESS)		usb_kill_urb(&priv->tx_urb);	ib_net_flush(priv->modem);	ib_net_deregister(priv->modem);	kfree(priv);}/** * ib_usb_rx_read - receive radio frame. * @urb: * @pt_regs: */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void ib_usb_rx_read(struct urb *urb, struct pt_regs *pt_regs)#elsestatic void ib_usb_rx_read(struct urb *urb)#endif{	unsigned long state;	struct ib_usb_priv_t *priv = urb->context;	struct ib_net_modem_t *modem = priv->modem;	struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf;	int nbuf;	spin_lock_irqsave(&ib_lock, state);	if (urb->status == 0 && urb->actual_length != 0) {		nbuf = IB_NET_NBUF(radio->word[0], radio->word[1]);		if (nbuf < IB_NET_RADIO_HEAD				|| IB_NET_RADIO_HEAD + ETH_DATA_LEN < nbuf)			goto failed;		ib_net_rx_parse(modem, urb->actual_length);		ib_net_schedule(modem);	}	/* fall through */failed:	if (urb->status != -ECONNRESET) {		urb->actual_length = 0;		urb->dev = priv->usbdev;		usb_submit_urb(urb, GFP_ATOMIC);	}	spin_unlock_irqrestore(&ib_lock, state);}/** * ib_usb_open *     called under ib_lock * @_priv: device private state. */static int ib_usb_open(void *_priv){	struct ib_usb_priv_t *priv = _priv;	struct ib_net_modem_t *modem = priv->modem;	struct ib_net_radio_t *radio;	struct sk_buff *skb;	skb = alloc_skb(sizeof(ib_usb_conf), GFP_ATOMIC);	if (skb == NULL)		return -EINVAL;	radio = (struct ib_net_radio_t*) skb_put(skb, sizeof(ib_usb_conf));	memcpy(radio, ib_usb_conf, sizeof(ib_usb_conf));	radio->payload[0] = modem->stats.tx_packets & 0xff;	radio->payload[1] = (modem->pc_status |= STATUS_READY);	skb_queue_tail(&modem->tx_queue, skb);	ib_net_schedule(modem);	return 0;}/** * ib_usb_rx_parse - *     called under ib_lock * @modem: modem private state. */static void ib_usb_rx_parse(void *_priv){	struct ib_usb_priv_t *priv = _priv;	struct ib_net_modem_t *modem = priv->modem;	struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf;	struct sk_buff *skb;	ib_net_ut_status(modem, radio->payload[1]);	if (radio->proto[1] == PROTO_USB_CONF) {		skb = alloc_skb(sizeof(ib_usb_conf), GFP_ATOMIC);		if (skb != NULL) {			radio = (struct ib_net_radio_t*)					skb_put(skb, sizeof(ib_usb_conf));			memcpy(radio, ib_usb_conf, sizeof(ib_usb_conf));			radio->payload[0] = modem->stats.tx_packets & 0xff;			radio->payload[1] = modem->pc_status;			skb_queue_tail(&modem->tx_queue, skb);			ib_net_schedule(modem);		}	}}/** * ib_usb_close *     called under ib_lock * @modem: modem private state. */static int ib_usb_close(void *_priv){	struct ib_usb_priv_t *priv = _priv;	struct ib_net_modem_t *modem = priv->modem;	struct ib_net_radio_t *radio;	struct sk_buff *skb;	if (modem->pc_status & STATUS_READY) {		skb = alloc_skb(sizeof(ib_usb_conf), GFP_ATOMIC);		if (skb == NULL)			return -EINVAL;		radio = (struct ib_net_radio_t*)				skb_put(skb, sizeof(ib_usb_conf));		memcpy(radio, ib_usb_conf, sizeof(ib_usb_conf));		radio->payload[0] = modem->stats.tx_packets & 0xff;		radio->payload[1] = (modem->pc_status &= ~STATUS_READY);		skb_queue_tail(&modem->tx_queue, skb);		ib_net_schedule(modem);	}	return 0;}/** * ib_usb_tx_done - transfer completed. * @urb: * @pt_regs: */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void ib_usb_tx_done(struct urb *urb, struct pt_regs *pt_regs)#elsestatic void ib_usb_tx_done(struct urb *urb)#endif{	unsigned long state;	struct ib_usb_priv_t *priv = urb->context;	spin_lock_irqsave(&ib_lock, state);	if (urb->status)		priv->modem->stats.tx_errors += 1;	if (urb->status != -ECONNRESET)		ib_net_schedule(priv->modem);	spin_unlock_irqrestore(&ib_lock, state);}/** * ib_usb_poll - poll device. *     called under ib_lock * @_priv: device private state. */static void ib_usb_poll(void *_priv){	struct ib_usb_priv_t *priv = _priv;	struct ib_net_modem_t *modem = priv->modem;	int nbuf, pad_bytes;	if (priv->tx_urb.status == -EINPROGRESS)		return;	nbuf = ib_net_tx_prepare(modem);	if (nbuf == 0)		return;	if (priv->usbdev == NULL)		return;	usb_fill_bulk_urb(&priv->tx_urb, priv->usbdev,			usb_sndbulkpipe(priv->usbdev, priv->tx_endpoint),			modem->tx_buf, IB_NET_RADIO_HEAD + ETH_DATA_LEN,			ib_usb_tx_done, priv);	// NTJ: 1.3.4: avoid modulo-aligned transfers by padding tx_length	pad_bytes = (priv->packet_modulo > 0		    && (nbuf % priv->packet_modulo == 0) ? 1 : 0);	priv->tx_urb.transfer_buffer_length = nbuf + pad_bytes;	if (usb_submit_urb(&priv->tx_urb, GFP_KERNEL)) {		modem->stats.tx_errors += 1;		return;	}	modem->stats.tx_bytes += nbuf;	modem->stats.tx_packets += 1;}/** * ib_usb_tx_timeout *     called under ib_lock * @_priv: device private state. */static void ib_usb_tx_timeout(void *_priv){	struct ib_usb_priv_t *priv = _priv;	if (priv == NULL) {		/* can't happen? */		DEBUG(1,"ib-usb: NULL passed to ib_usb_tx_timeout\n");		return;	}	if (priv->tx_urb.status == -EINPROGRESS)		usb_unlink_urb(&priv->tx_urb);}/** * ib_usb_net_driver - USB driver callback functions. */static struct ib_net_driver_t ib_usb_net_driver = {	.poll = ib_usb_poll,	.tx_timeout = ib_usb_tx_timeout,	.open = ib_usb_open,	.rx_parse = ib_usb_rx_parse,	.close = ib_usb_close,};/** * ib_usb_probe - probe USB device. * @usbintf: * @id: */static int ib_usb_probe(struct usb_interface *usbintf,		const struct usb_device_id *id){	struct usb_device *usbdev = interface_to_usbdev(usbintf);	struct usb_host_interface *hostif = usbintf->cur_altsetting;	struct ib_usb_priv_t *priv;	struct net_device *netdev;	struct ib_net_modem_t *modem;	struct usb_endpoint_descriptor *ep;	int nbuf, err, i;	int control;	switch (usbdev->descriptor.bcdDevice) {	case UT_DEVICE_UT_02:		control = CONTROL_USB_GET_MAC_ADDR_UT_02;		DEBUG(9, "ib-usb: UT_02 Detected\n");		break;	case UT_DEVICE_UT_04:		control = CONTROL_USB_GET_MAC_ADDR_UT_04;		DEBUG(9, "ib-usb: UT_04 Detected\n");		break;	default:		DEBUG(1, "ib-usb: UT device %04x\n",				usbdev->descriptor.bcdDevice);		control = 0x0;		//return -ENODEV;	}	err = usb_reset_configuration(usbdev);	if (err) {		DEBUG(1, "ib-usb: usb_reset_configuration failed\n");		return err;	}	priv = kmalloc(sizeof(struct ib_usb_priv_t), GFP_KERNEL);	if (priv == NULL) {		DEBUG(1, "ib-usb: kmalloc failed\n");		return -ENOMEM;	}	memset(priv, 0, sizeof(struct ib_usb_priv_t)); /* hack */	priv->usbdev = usbdev;	usb_init_urb(&priv->rx_urb);	usb_init_urb(&priv->tx_urb);	nbuf = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),			CONTROL_USB_GET_MAC_ADDR_UT_02, VENDOR_USB_REQUEST,			cpu_to_le16(0), cpu_to_le16(0), priv->ctl_buf,			cpu_to_le16(8), 0);	if (nbuf != 8) {		DEBUG(1, "ib-usb: invalid read %02x %02x %02x\n",				priv->ctl_buf[0], nbuf,				CONTROL_USB_GET_MAC_ADDR_UT_02);		err = -ENODEV;		goto failed;	}	// NTJ: 1.3.4: disabled - now determined by endpoint characteristics#if 0	if (priv->ctl_buf[1] != control) {		DEBUG(1, "ib-usb: mismatch command %02x %02x\n",				priv->ctl_buf[1], control); 		err = -ENODEV; 		goto failed; 	}	switch (control) {	case CONTROL_USB_GET_MAC_ADDR_UT_02: 		priv->rx_endpoint = 2; 		priv->tx_endpoint = 1;		break;	case CONTROL_USB_GET_MAC_ADDR_UT_04: 		priv->rx_endpoint = 3; 		priv->tx_endpoint = 2;		break;	default:		/* can't happen */ 		err = -ENODEV; 		goto failed; 	}#endif	/* NTJ: 1.3.4: set the modulo for more recent devices */	if (control == CONTROL_USB_GET_MAC_ADDR_UT_04) {	  priv->packet_modulo = 64;	  DEBUG(9, "ib-usb: packet modulo set to %d\n",		(int) priv->packet_modulo);	}	/*	 * NTJ: 1.3.4: find the endpoints by characteristics, not by descriptor	 */		priv->rx_endpoint = -1;	priv->tx_endpoint = -1;	// iterate the endpoints to find the bulk-io endpoints	for (i = 0; i < hostif->desc.bNumEndpoints; i++) {	  ep = &hostif->endpoint[i].desc;	  if (usb_endpoint_xfer_bulk(ep)) {	    if (usb_endpoint_dir_in(ep)) {	      if (priv->rx_endpoint == -1) priv->rx_endpoint = i+1;	    } else if (usb_endpoint_dir_out(ep)) {	      if (priv->tx_endpoint == -1) priv->tx_endpoint = i+1;	    } else {	      DEBUG(1, "ib-usb: broken Endpoint descr: ep[%d]\n", i);	    }	  }	  if (priv->rx_endpoint != -1 && priv->tx_endpoint != -1) break;	}	if (priv->rx_endpoint == -1 || priv->tx_endpoint == -1) {	  DEBUG(1, "ib-usb: One or more bulk-io endpoints not found\n");	  return -ENODEV;	}	DEBUG(9, "ib-usb: rx_endpoint=%d; tx_endpoint=%d\n",	      priv->rx_endpoint, priv->tx_endpoint);	err = ib_net_register(&netdev);	if (err)		goto failed;	modem = netdev->priv;	modem->driver = &ib_usb_net_driver;	modem->pdriver = priv;	priv->modem = modem;	ib_net_addr(modem, priv->ctl_buf + 2);	usb_fill_bulk_urb(&priv->rx_urb, usbdev,			usb_rcvbulkpipe(usbdev, priv->rx_endpoint),			modem->rx_buf, IB_NET_RADIO_HEAD + ETH_DATA_LEN,			ib_usb_rx_read, priv);	priv->rx_urb.actual_length = 0;	priv->rx_urb.dev = usbdev;	usb_fill_bulk_urb(&priv->tx_urb, usbdev,			usb_sndbulkpipe(usbdev, priv->tx_endpoint),			modem->tx_buf, IB_NET_RADIO_HEAD + ETH_DATA_LEN,			ib_usb_tx_done, priv);	priv->tx_urb.transfer_flags |= URB_ZERO_PACKET;	usb_set_intfdata(usbintf, priv);	usb_submit_urb(&priv->rx_urb, GFP_ATOMIC);	return 0;failed:	kfree(priv);	return err;}/** * ib_usb_table - USB device table. */static struct usb_device_id ib_usb_table[] = {	{ USB_DEVICE(0x0d14, 0x0009) },	{ USB_DEVICE(0x0482, 0x0204) },	{}};MODULE_DEVICE_TABLE(usb, ib_usb_table);/** * ib_usb_driver - USB driver. */static struct usb_driver ib_usb_driver = {#if KERNEL_VERSION(2,4,20) <= LINUX_VERSION_CODE \		&& LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)	.owner = THIS_MODULE,#endif	.name = "iburst",	.probe = ib_usb_probe,	.disconnect = ib_usb_disconnect,	.id_table = ib_usb_table,};/** * ib_usb_init - ib-usb module init. */static int __init ib_usb_init(void){	return usb_register(&ib_usb_driver);}/** * ib_usb_exit - ib-usb module exit. */static void __exit ib_usb_exit(void){	usb_deregister(&ib_usb_driver);}module_init(ib_usb_init);module_exit(ib_usb_exit);MODULE_DESCRIPTION("iBurst compatible USB driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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