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

📄 plusb.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * */static void plusb_int_complete(urb_t *purb){	plusb_t *s=purb->context;	s->status=((unsigned char*)purb->transfer_buffer)[0]&255;	#if 0	/* This isn't right because 0x20 is TX_RDY and	   sometimes will not be set	*/	if((s->status&0x3f)!=0x20) {		warn("invalid device status %02X", s->status);		return;	}#endif		if(!s->connected)		return;	/* Don't turn this on unless you want to see the log flooded. */#if 0	printk("plusb_int_complete: PEER_E:%d TX_REQ:%d TX_C:%d RESET_IN:%d RESET_O: %d TX_RDY:%d RES1:%d RES2:%d\n",	    s->status & _PL_INT_PEER_E  ? 1 : 0,	    s->status & _PL_INT_TX_REQ  ? 1 : 0,	    s->status & _PL_INT_TX_C    ? 1 : 0,	    s->status & _PL_INT_RESET_I ? 1 : 0,	    s->status & _PL_INT_RESET_O ? 1 : 0,	    s->status & _PL_INT_TX_RDY  ? 1 : 0,	    s->status & _PL_INT_RES1    ? 1 : 0,	    s->status & _PL_INT_RES2    ? 1 : 0);#endif#if 1	/* At first glance, this logic appears to not really be needed, but	   it can help recover from intermittent problems where the	   usb_submit_urb() fails in the read callback. -EZA	*/		/* Try to submit the read URB again. Make sure	   we aren't in contention with the bulk read callback	*/	submit_read_urb ("plusb_int_complete", s);		/* While we are at it, why not check to see if the	   write urb should be re-submitted?	*/	dequeue_next_skb("plusb_int_complete", s);		#endif}/* --------------------------------------------------------------------- *//* * plusb_free_all - deallocate all memory kept for an instance of the device. */static void plusb_free_all(plusb_t *s){	struct list_head *skb;	skb_list_t *skb_list;		dbg("plusb_free_all");		/* set a flag to tell all callbacks to cease and desist */	s->connected = 0;	/* If the interrupt handler is about to fire, let it finish up */	run_task_queue(&tq_immediate);		if(s->inturb) {		dbg("unlink inturb");		usb_unlink_urb(s->inturb);		dbg("free_urb inturb");		usb_free_urb(s->inturb);		s->inturb=NULL;	}		if(s->interrupt_in_buffer) {		dbg("kfree s->interrupt_in_buffer");		kfree(s->interrupt_in_buffer);		s->interrupt_in_buffer=NULL;	}	if(s->readurb) {		dbg("unlink readurb");		usb_unlink_urb(s->readurb);		dbg("free_urb readurb:");		usb_free_urb(s->readurb);		s->readurb=NULL;	}	if(s->bulk_in_buffer) {		dbg("kfree s->bulk_in_buffer");		kfree(s->bulk_in_buffer);		s->bulk_in_buffer=NULL;	}		s->readurb_submitted = 0;		if(s->writeurb) {		dbg("unlink writeurb");		usb_unlink_urb(s->writeurb);		dbg("free_urb writeurb:");		usb_free_urb(s->writeurb);		s->writeurb=NULL;	}	s->writeurb_submitted = 0;		while(!list_empty(&s->free_skb_list)) {		skb=s->free_skb_list.next;		list_del(skb);		skb_list = list_entry (skb, skb_list_t, skb_list);		kfree(skb_list);	}	while(!list_empty(&s->tx_skb_list)) {		skb=s->tx_skb_list.next;		list_del(skb);		skb_list = list_entry (skb, skb_list_t, skb_list);		if (skb_list->skb) {			dbg ("Freeing SKB in queue");			dev_kfree_skb_any(skb_list->skb);			skb_list->skb = NULL;		}		kfree(skb_list);	}		s->in_bh=0;		dbg("plusb_free_all: finished");	}/*-------------------------------------------------------------------*//* * plusb_alloc - allocate memory associated with one instance of the device */static int plusb_alloc(plusb_t *s){	int i;	skb_list_t *skb;	dbg("plusb_alloc");	for(i=0 ; i < _SKB_NUM ; i++) {		skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);		if(!skb) {			err("kmalloc for skb_list failed");			goto reject;		}		memset(skb, 0, sizeof(skb_list_t));		list_add(&skb->skb_list, &s->free_skb_list);	}	dbg("inturb allocation:");	s->inturb=usb_alloc_urb(0);	if(!s->inturb) {		err("alloc_urb failed");		goto reject;	}	dbg("bulk read urb allocation:");	s->readurb=usb_alloc_urb(0);	if(!s->readurb) {		err("alloc_urb failed");		goto reject;	}		dbg("bulk write urb allocation:");	s->writeurb=usb_alloc_urb(0);	if(!s->writeurb) {		err("alloc_urb for writeurb failed");		goto reject;	}		dbg("readurb/inturb init:");	s->interrupt_in_buffer=kmalloc(64, GFP_KERNEL);	if(!s->interrupt_in_buffer) {		err("kmalloc failed");		goto reject;	}	/* The original value of '10' makes this interrupt fire off a LOT.	   It was set so low because the callback determined when to	   sumbit the buld read URB. I've lowered it to 100 - the driver	   doesn't depend on that logic anymore. -EZA	*/	FILL_INT_URB(s->inturb, s->usbdev,		     usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE),		     s->interrupt_in_buffer, 1,		     plusb_int_complete, s, HZ);	dbg("inturb submission:");	if(usb_submit_urb(s->inturb)<0) {		err("usb_submit_urb failed");		goto reject;	}		dbg("readurb init:");	s->bulk_in_buffer = kmalloc(_BULK_DATA_LEN, GFP_KERNEL);	if (!s->bulk_in_buffer) {		err("kmalloc %d bytes for bulk in buffer failed", _BULK_DATA_LEN);	}	FILL_BULK_URB(s->readurb, s->usbdev,		      usb_rcvbulkpipe(s->usbdev, _PLUSB_BULKINPIPE),		      s->bulk_in_buffer, _BULK_DATA_LEN,		      plusb_read_bulk_complete, s);	/* The write urb will be initialized inside the network	   interrupt.	*/	/* get the bulk read going */	submit_read_urb("plusb_alloc", s);	dbg ("plusb_alloc: finished. readurb=%p writeurb=%p inturb=%p",		s->readurb, s->writeurb, s->inturb);		return 0;  reject:  	dbg("plusb_alloc: failed");		plusb_free_all(s);	return -ENOMEM;}/*-------------------------------------------------------------------*/static int plusb_net_open(struct net_device *dev){	plusb_t *s=dev->priv;		dbg("plusb_net_open");		if(plusb_alloc(s))		return -ENOMEM;	s->opened=1;		MOD_INC_USE_COUNT;	netif_start_queue(dev);	dbg("plusb_net_open: success");		return 0;	}/* --------------------------------------------------------------------- */static int plusb_net_stop(struct net_device *dev){	plusb_t *s=dev->priv;	netif_stop_queue(dev);		dbg("plusb_net_stop");			s->opened=0;	plusb_free_all(s);	MOD_DEC_USE_COUNT;	dbg("plusb_net_stop:finished");	return 0;}/* --------------------------------------------------------------------- */static struct net_device_stats *plusb_net_get_stats(struct net_device *dev){	plusb_t *s=dev->priv;		dbg("net_device_stats");		return &s->net_stats;}/* --------------------------------------------------------------------- */static plusb_t *plusb_find_struct (void){	int u;	for (u = 0; u < NRPLUSB; u++) {		plusb_t *s = &plusb[u];		if (!s->connected)			return s;	}	return NULL;}/* --------------------------------------------------------------------- */static void plusb_disconnect (struct usb_device *usbdev, void *ptr){	plusb_t *s = ptr;	dbg("plusb_disconnect");		plusb_free_all(s);	if(!s->opened && s->net_dev.name) {		dbg("unregistering netdev: %s",s->net_dev.name);		unregister_netdev(&s->net_dev);		s->net_dev.name[0] = '\0';#if (LINUX_VERSION_CODE < 0x020300)		dbg("plusb_disconnect: About to free name"); 		kfree (s->net_dev.name); 		s->net_dev.name = NULL;#endif		}		dbg("plusb_disconnect: finished");	MOD_DEC_USE_COUNT;}/* --------------------------------------------------------------------- */static int plusb_change_mtu(struct net_device *dev, int new_mtu){	if ((new_mtu < 68) || (new_mtu > _BULK_DATA_LEN))		return -EINVAL;	printk("plusb: changing mtu to %d\n", new_mtu);	dev->mtu = new_mtu;		/* NOTE: Could we change the size of the READ URB here dynamically	   to save kernel memory?	*/	return 0;}/* --------------------------------------------------------------------- */int plusb_net_init(struct net_device *dev){	dbg("plusb_net_init");		dev->open=plusb_net_open;	dev->stop=plusb_net_stop;	dev->hard_start_xmit=plusb_net_xmit;	dev->get_stats	= plusb_net_get_stats;	ether_setup(dev);	dev->change_mtu = plusb_change_mtu;	/* Setting the default MTU to 16K gives good performance for	   me, and keeps the ping latency low too.  Setting it up	   to 32K made performance go down. -EZA	   Pavel says it would be best not to do this...	*/	/*dev->mtu=16384; */	dev->tx_queue_len = 0;		dev->flags = IFF_POINTOPOINT|IFF_NOARP;		dbg("plusb_net_init: finished");	return 0;}/* --------------------------------------------------------------------- */static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum){	plusb_t *s;	dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",	  usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);	if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1)		return NULL;	/* We don't handle multiple configurations */	if (usbdev->descriptor.bNumConfigurations != 1)		return NULL;	s = plusb_find_struct ();	if (!s)		return NULL;	s->usbdev = usbdev;	if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) {		err("set_configuration failed");		return NULL;	}	if (usb_set_interface (s->usbdev, 0, 0) < 0) {		err("set_interface failed");		return NULL;	}#if (LINUX_VERSION_CODE < 0x020300) 	{ 		int i;		 		/* For Kernel version 2.2, the driver is responsible for 		   allocating this memory. For version 2.4, the rules 		   have apparently changed, but there is a nifty function 		   'init_netdev' that might make this easier...  It's in  		   ../net/net_init.c - but can we get there from here?  (no)		   -EZA 		*/ 		 		/* Find the device number... we seem to have lost it... -EZA */ 		for (i=0; i<NRPLUSB; i++) { 			if (&plusb[i] == s) 				break; 		} 	 		if(!s->net_dev.name) { 			s->net_dev.name = kmalloc(strlen("plusbXXXX"), GFP_KERNEL); 			sprintf (s->net_dev.name, "plusb%d", i); 			s->net_dev.init=plusb_net_init; 			s->net_dev.priv=s; 			 			printk ("plusb_probe: Registering Device\n");	 			if(!register_netdev(&s->net_dev)) 				info("registered: %s", s->net_dev.name); 			else { 				err("register_netdev failed"); 				s->net_dev.name[0] = '\0'; 			} 			dbg ("plusb_probe: Connected!"); 		} 	}#else 	/* Kernel version 2.3+ works a little bit differently than 2.2 */	if(!s->net_dev.name[0]) {		strcpy(s->net_dev.name, "plusb%d");		s->net_dev.init=plusb_net_init;		s->net_dev.priv=s;		if(!register_netdev(&s->net_dev))			info("registered: %s", s->net_dev.name);		else {			err("register_netdev failed");			s->net_dev.name[0] = '\0';		}	}#endif		s->connected = 1;	if(s->opened) {		dbg("net device already allocated, restarting USB transfers");		plusb_alloc(s);	}	info("bound to interface: %d dev: %p", ifnum, usbdev);	MOD_INC_USE_COUNT;	return s;}/* --------------------------------------------------------------------- */static struct usb_driver plusb_driver ={	name: "plusb",	probe: plusb_probe,	disconnect: plusb_disconnect,};/* --------------------------------------------------------------------- */static int __init plusb_init (void){	unsigned u;	dbg("plusb_init");		/* initialize struct */	for (u = 0; u < NRPLUSB; u++) {		plusb_t *s = &plusb[u];		memset (s, 0, sizeof (plusb_t));		INIT_LIST_HEAD (&s->tx_skb_list);		INIT_LIST_HEAD (&s->free_skb_list);		spin_lock_init (&s->lock);	}	/* register misc device */	usb_register (&plusb_driver);	dbg("plusb_init: driver registered");	return 0;}/* --------------------------------------------------------------------- */static void __exit plusb_cleanup (void){	unsigned u;	dbg("plusb_cleanup");	for (u = 0; u < NRPLUSB; u++) {		plusb_t *s = &plusb[u];#if (LINUX_VERSION_CODE < 0x020300)		if(s->net_dev.name) {			dbg("unregistering netdev: %s",s->net_dev.name);			unregister_netdev(&s->net_dev);			s->net_dev.name[0] = '\0';			kfree (s->net_dev.name);			s->net_dev.name = NULL;				}		#else		if(s->net_dev.name[0]) {			dbg("unregistering netdev: %s",s->net_dev.name);			unregister_netdev(&s->net_dev);			s->net_dev.name[0] = '\0';		}#endif	}	usb_deregister (&plusb_driver);	dbg("plusb_cleanup: finished");}/* --------------------------------------------------------------------- */MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000");module_init (plusb_init);module_exit (plusb_cleanup);/* --------------------------------------------------------------------- */

⌨️ 快捷键说明

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