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

📄 catc.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (urb->status)		dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length);	spin_lock_irqsave(&catc->ctrl_lock, flags);	q = catc->ctrl_queue + catc->ctrl_tail;	if (q->dir) {		if (q->buf && q->len)			memcpy(q->buf, catc->ctrl_buf, q->len);		else			q->buf = catc->ctrl_buf;	}	if (q->callback)		q->callback(catc, q);	catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);	if (catc->ctrl_head != catc->ctrl_tail)		catc_ctrl_run(catc);	else		clear_bit(CTRL_RUNNING, &catc->flags);	spin_unlock_irqrestore(&catc->ctrl_lock, flags);}static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,	u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q)){	struct ctrl_queue *q;	int retval = 0;	unsigned long flags;	spin_lock_irqsave(&catc->ctrl_lock, flags);		q = catc->ctrl_queue + catc->ctrl_head;	q->dir = dir;	q->request = request;	q->value = value;	q->index = index;	q->buf = buf;	q->len = len;	q->callback = callback;	catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);	if (catc->ctrl_head == catc->ctrl_tail) {		err("ctrl queue full");		catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);		retval = -1;	}	if (!test_and_set_bit(CTRL_RUNNING, &catc->flags))		catc_ctrl_run(catc);	spin_unlock_irqrestore(&catc->ctrl_lock, flags);	return retval;}/* * Statistics. */static void catc_stats_done(struct catc *catc, struct ctrl_queue *q){	int index = q->index - EthStats;	u16 data, last;	catc->stats_buf[index] = *((char *)q->buf);	if (index & 1)		return;	data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1];	last = catc->stats_vals[index >> 1];	switch (index) {		case TxSingleColl:		case TxMultiColl:			catc->stats.collisions += data - last;			break;		case TxExcessColl:			catc->stats.tx_aborted_errors += data - last;			catc->stats.tx_errors += data - last;			break;		case RxFramErr:			catc->stats.rx_frame_errors += data - last;			catc->stats.rx_errors += data - last;			break;	}	catc->stats_vals[index >> 1] = data;}static void catc_stats_timer(unsigned long data){	struct catc *catc = (void *) data;	int i;	for (i = 0; i < 8; i++)		catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done);	mod_timer(&catc->timer, jiffies + STATS_UPDATE);}static struct net_device_stats *catc_get_stats(struct net_device *netdev){	struct catc *catc = netdev->priv;	return &catc->stats;}/* * Receive modes. Broadcast, Multicast, Promisc. */static inline u32 ether_crc_le(int cnt, unsigned char *addr){	unsigned int crc = 0xffffffff;	u8 byte, idx, bit;	        for (idx = 0; idx < cnt; idx++)                for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)                        crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);	return crc;}static void catc_multicast(unsigned char *addr, u8 *multicast){	unsigned int crc = ether_crc_le(6, addr);	multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);}static void catc_set_multicast_list(struct net_device *netdev){	struct catc *catc = netdev->priv;	struct dev_mc_list *mc;	u8 broadcast[6];	u8 rx = RxEnable | RxPolarity | RxMultiCast;	int i;	memset(broadcast, 0xff, 6);	memset(catc->multicast, 0, 64);	catc_multicast(broadcast, catc->multicast);	catc_multicast(netdev->dev_addr, catc->multicast);	if (netdev->flags & IFF_PROMISC) {		memset(catc->multicast, 0xff, 64);		rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc;	} 	if (netdev->flags & IFF_ALLMULTI) {		memset(catc->multicast, 0xff, 64);	} else {		for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) {			u32 crc = ether_crc_le(6, mc->dmi_addr);			if (!catc->is_f5u011) {				catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);			} else {				catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7);			}		}	}	if (!catc->is_f5u011) {		catc_set_reg_async(catc, RxUnit, rx);		catc_write_mem_async(catc, 0xfa80, catc->multicast, 64);	} else {		f5u011_mchash_async(catc, catc->multicast);		if (catc->rxmode[0] != rx) {			catc->rxmode[0] = rx;			dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0],			    catc->rxmode[1]);			f5u011_rxmode_async(catc, catc->rxmode);		}	}}/* * ioctl's */static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){        struct catc *catc = dev->priv;        u32 cmd;	char tmp[40];                if (get_user(cmd, (u32 *)useraddr))                return -EFAULT;        switch (cmd) {        /* get driver info */        case ETHTOOL_GDRVINFO: {                struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};                strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN);                strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);		sprintf(tmp, "usb%d:%d", catc->usbdev->bus->busnum, catc->usbdev->devnum);                strncpy(info.bus_info, tmp,ETHTOOL_BUSINFO_LEN);                if (copy_to_user(useraddr, &info, sizeof(info)))                        return -EFAULT;                return 0;        }	/* get settings */	case ETHTOOL_GSET:		if (catc->is_f5u011) {			struct ethtool_cmd ecmd = { 				ETHTOOL_GSET, 				SUPPORTED_10baseT_Half | SUPPORTED_TP, 				ADVERTISED_10baseT_Half | ADVERTISED_TP, 				SPEED_10, 				DUPLEX_HALF, 				PORT_TP, 				0, 				XCVR_INTERNAL, 				AUTONEG_DISABLE, 				1, 				1 			};			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))				return -EFAULT;			return 0;		} else {			return -EOPNOTSUPP;		}        /* get link status */        case ETHTOOL_GLINK: {                struct ethtool_value edata = {ETHTOOL_GLINK};                edata.data = netif_carrier_ok(dev);                if (copy_to_user(useraddr, &edata, sizeof(edata)))                        return -EFAULT;                return 0;        }	}        /* Note that the ethtool user space code requires EOPNOTSUPP */        return -EOPNOTSUPP;}static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){        switch(cmd) {        case SIOCETHTOOL:	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);        default:	       return -ENOTTY; /* Apparently this is the standard ioctl errno */        }}/* * Open, close. */static int catc_open(struct net_device *netdev){	struct catc *catc = netdev->priv;	int status;	catc->irq_urb.dev = catc->usbdev;	if ((status = usb_submit_urb(&catc->irq_urb)) < 0) {		err("submit(irq_urb) status %d", status);		return -1;	}	netif_start_queue(netdev);	if (!catc->is_f5u011)		mod_timer(&catc->timer, jiffies + STATS_UPDATE);	return 0;}static int catc_stop(struct net_device *netdev){	struct catc *catc = netdev->priv;	netif_stop_queue(netdev);	if (!catc->is_f5u011)		del_timer_sync(&catc->timer);	usb_unlink_urb(&catc->rx_urb);	usb_unlink_urb(&catc->tx_urb);	usb_unlink_urb(&catc->irq_urb);	usb_unlink_urb(&catc->ctrl_urb);	return 0;}/* * USB probe, disconnect. */static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const struct usb_device_id *id){	struct net_device *netdev;	struct catc *catc;	u8 broadcast[6];	int i, pktsz;	if (usb_set_interface(usbdev, ifnum, 1)) {                err("Can't set altsetting 1.");		return NULL;	}	catc = kmalloc(sizeof(struct catc), GFP_KERNEL);	if (!catc)		return NULL;	memset(catc, 0, sizeof(struct catc));	netdev = init_etherdev(0, 0);	if (!netdev) {		kfree(catc);		return NULL;	}	netdev->open = catc_open;	netdev->hard_start_xmit = catc_hard_start_xmit;	netdev->stop = catc_stop;	netdev->get_stats = catc_get_stats;	netdev->tx_timeout = catc_tx_timeout;	netdev->watchdog_timeo = TX_TIMEOUT;	netdev->set_multicast_list = catc_set_multicast_list;	netdev->do_ioctl = catc_ioctl;	netdev->priv = catc;	catc->usbdev = usbdev;	catc->netdev = netdev;	catc->tx_lock = SPIN_LOCK_UNLOCKED;	catc->ctrl_lock = SPIN_LOCK_UNLOCKED;	init_timer(&catc->timer);	catc->timer.data = (long) catc;	catc->timer.function = catc_stats_timer;	/* The F5U011 has the same vendor/product as the netmate 	 *  but a device version of 0x130	 */	if (usbdev->descriptor.idVendor == 0x0423 && 	    usbdev->descriptor.idProduct == 0xa &&	    catc->usbdev->descriptor.bcdDevice == 0x0130) {		dbg("Testing for f5u011");		catc->is_f5u011 = 1;		atomic_set(&catc->recq_sz, 0);		pktsz = RX_PKT_SZ;	} else {		pktsz = RX_MAX_BURST * (PKT_SZ + 2);	}	FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),		NULL, NULL, 0, catc_ctrl_done, catc);	FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),		NULL, 0, catc_tx_done, catc);	FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),		catc->rx_buf, pktsz, catc_rx_done, catc);	FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),                catc->irq_buf, 2, catc_irq_done, catc, 1);	if (!catc->is_f5u011) {		dbg("Checking memory size\n");		i = 0x12345678;		catc_write_mem(catc, 0x7a80, &i, 4);		i = 0x87654321;			catc_write_mem(catc, 0xfa80, &i, 4);		catc_read_mem(catc, 0x7a80, &i, 4);	  		switch (i) {		case 0x12345678:			catc_set_reg(catc, TxBufCount, 8);			catc_set_reg(catc, RxBufCount, 32);			dbg("64k Memory\n");			break;		default:			warn("Couldn't detect memory size, assuming 32k");		case 0x87654321:			catc_set_reg(catc, TxBufCount, 4);			catc_set_reg(catc, RxBufCount, 16);			dbg("32k Memory\n");			break;		}	  		dbg("Getting MAC from SEEROM.");	  		catc_get_mac(catc, netdev->dev_addr);				dbg("Setting MAC into registers.");	  		for (i = 0; i < 6; i++)			catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]);				dbg("Filling the multicast list.");	  		memset(broadcast, 0xff, 6);		catc_multicast(broadcast, catc->multicast);		catc_multicast(netdev->dev_addr, catc->multicast);		catc_write_mem(catc, 0xfa80, catc->multicast, 64);				dbg("Clearing error counters.");				for (i = 0; i < 8; i++)			catc_set_reg(catc, EthStats + i, 0);		catc->last_stats = jiffies;				dbg("Enabling.");				catc_set_reg(catc, MaxBurst, RX_MAX_BURST);		catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits);		catc_set_reg(catc, LEDCtrl, LEDLink);		catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast);	} else {		dbg("Performing reset\n");		catc_reset(catc);		catc_get_mac(catc, netdev->dev_addr);				dbg("Setting RX Mode");		catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast;		catc->rxmode[1] = 0;		f5u011_rxmode(catc, catc->rxmode);	}	dbg("Init done.");	printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ",	       netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",	       usbdev->bus->busnum, usbdev->devnum, ifnum);	for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);	printk("%2.2x.\n", netdev->dev_addr[i]);	return catc;}static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr){	struct catc *catc = dev_ptr;	unregister_netdev(catc->netdev);	kfree(catc->netdev);	kfree(catc);}/* * Module functions and tables. */static struct usb_device_id catc_id_table [] = {	{ USB_DEVICE(0x0423, 0xa) },	/* CATC Netmate, Belkin F5U011 */	{ USB_DEVICE(0x0423, 0xc) },	/* CATC Netmate II, Belkin F5U111 */	{ USB_DEVICE(0x08d1, 0x1) },	/* smartBridges smartNIC */	{ }};MODULE_DEVICE_TABLE(usb, catc_id_table);static struct usb_driver catc_driver = {	name:		"catc",	probe:		catc_probe,	disconnect:	catc_disconnect,	id_table:	catc_id_table,};static int __init catc_init(void){	info(DRIVER_VERSION " " DRIVER_DESC);	usb_register(&catc_driver);	return 0;}static void __exit catc_exit(void){	usb_deregister(&catc_driver);}module_init(catc_init);module_exit(catc_exit);

⌨️ 快捷键说明

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