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

📄 dactron.c

📁 Linux环境下usb数据采集设备的驱动程序
💻 C
字号:
#include "dactron.h"#include "firmware.h"static  void*dactron_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static	voiddactron_disconnect( struct usb_device *dev, void *ptr );static	intdactron_open( struct inode *inode, struct file *file );static	intdactron_release( struct inode *inode, struct file *file );static	ssize_tdactron_write( struct file *file, const char *buffer, size_t count, loff_t *ppos );static	ssize_tdactron_read( struct file *file, char *buffer, size_t count, loff_t *ppos );static intdactron_ioctl( struct inode *inode, struct file *file,	      unsigned int cmd, unsigned long arg );static struct	file_operations	usb_dactron_fops = {	open:		dactron_open,	release:	dactron_release,	read:		dactron_read,	write:		dactron_write,	ioctl:		dactron_ioctl,};static	structusb_driver usb_dactron_driver = {	name:		"dactron",	probe:		dactron_probe,	disconnect:	dactron_disconnect,	fops:		&usb_dactron_fops,	minor:		DACT_BASE_MNR,	id_table:	dactron_device_ids,};static	int dactron_open( struct inode *inode, struct file *file ){	struct	usb_dactron_data 	*dactron;	struct	usb_device		*dev;	kdev_t dact_minor;	int err=0;	MOD_INC_USE_COUNT;	down( &dactron_mutex );	dact_minor = USB_DACT_MINOR( inode );	pr_debug( "dactron_open: dact_minor:%d\n", dact_minor );	if( !p_table[ dact_minor ] ){		up( &dactron_mutex );		MOD_DEC_USE_COUNT;		pr_debug( "dactron_open(%d): Unable to access minor data\n", dact_minor );		return -ENODEV;	}	dactron = p_table[ dact_minor ];	dev = dactron->dact_dev;	down( &( dactron->sem ));	/* Now protect the dactron_usb_data structure */ 	up( &dactron_mutex ); /* Now handled by the above */	if( !dev ){		pr_debug( "dactron_open(%d): Dactron device not present\n", dact_minor );		err = -ENODEV;		goto out_error;	}	if( !dactron->present ){		pr_debug( "dactron_open(%d): Dactron is not present\n", dact_minor );		err = -ENODEV;		goto out_error;	}	if( dactron->isopen ){		pr_debug( "dactron_open(%d): Dactron device is already open\n", dact_minor );		err = -EBUSY;		goto out_error;	}	init_waitqueue_head( &dactron->rd_wait_q );	dactron->isopen = 1;	file->private_data = dactron; /* Used by the read and write methods */out_error:	up( &( dactron->sem )); /* Wake up any possible contending processes */	if( err )		MOD_DEC_USE_COUNT;	return err;};static intdactron_release( struct inode * inode, struct file * file ){	struct usb_dactron_data	*dactron;	kdev_t dact_minor;	dact_minor = USB_DACT_MINOR( inode );	pr_debug( "dactron_release: dact_minor:%d\n", dact_minor );	if( !p_table[ dact_minor ] ){		pr_debug( "dactron_release(%d): invalid dact_minor\n", dact_minor );		return -ENODEV;	}	down( &dactron_mutex );	dactron = p_table[ dact_minor ];	down( &( dactron->sem ));	dactron->isopen = 0;	file->private_data = NULL;	up( &dactron_mutex );	up( &( dactron->sem ));	MOD_DEC_USE_COUNT;	return 0;};static ssize_tdactron_read(struct file * file, char * buffer, size_t count, loff_t *ppos){	struct usb_dactron_data *dactron;	struct usb_device *dev;	ssize_t bytes_read;	/* Overall count of bytes_read */	ssize_t ret;	kdev_t dact_minor;	int partial;		/* Number of bytes successfully read */	int this_read;		/* Max number of bytes to read */	int result;	int rd_expire = RD_EXPIRE;	char *ibuf;	dactron = file->private_data;	down( &( dactron->sem ));	dact_minor = dactron->dact_minor;	ibuf = dactron->ibuf;	dev = dactron->dact_dev;	bytes_read = 0;	ret = 0;	file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the atime of the device node */	while( count > 0 ){		if( signal_pending( current )){			ret = -ERESTARTSYS;			break;		}		this_read = ( count >= IBUF_SIZE ) ? IBUF_SIZE : count;		result = usb_bulk_msg( dev, usb_rcvbulkpipe( dev, 2 ), ibuf, this_read, &partial, dactron->rd_nak_timeout );		pr_debug( "read stats( %d ): result:%d this_read:%d partial:%d count:%d", dact_minor, result, this_read, partial, count );		if( result == -ETIMEDOUT ){ /* NAK */			if( !partial ){ /* No data */				if( --rd_expire <= 0 ){	/* Give it up */					pr_debug( "dactron_read( %d ): excessive NAK's received\n", dact_minor );					ret = result;					break;				} else { /* Keep trying to read data */					interruptible_sleep_on_timeout( &dactron->rd_wait_q, dactron->rd_nak_timeout );					continue;				}			} else { /* Timeout w/ some data */				goto data_recvd;			}		}				if( result == -EPIPE ){ /* No hope */			if( usb_clear_halt( dev, 2 )){				pr_debug( "dactron_read( %d ): Failure to clear endpoint halt condition ( %Zd ).\n", dact_minor, ret );			}			ret = result;			break;		} else if(( result < 0 ) && ( result != USB_ST_DATAUNDERRUN )){			pr_debug( "dactron_read( %d ): funky result:%d\n", dact_minor, ( int )result );			ret = -EIO;			break;		}	data_recvd:		if( partial ){ /* Data returned */			if( copy_to_user( buffer, ibuf, partial )){				ret = -EFAULT;				break;			}			count -= this_read; /* Compensate for short reads */			bytes_read += partial; /* Keep tally of what actually was read */			buffer += partial;		} else {			ret = 0;			break;		}	}	up( &( dactron->sem ));	return ret ? ret : bytes_read;};static	ssize_t dactron_write( struct file *file, const char *buffer, 					       size_t count, loff_t *ppos ){	struct	usb_dactron_data	*dactron;	struct	usb_device		*dev;	kdev_t	dact_minor;	ssize_t bytes_written = 0; /* Overall count of bytes written */	ssize_t	ret = 0;		int this_write;		/* Number of bytes to write */	int partial;		/* Number of bytes successfully written */	int result = 0;	char *obuf;	dactron = file->private_data;	down( &( dactron->sem ));	dact_minor = dactron->dact_minor;	dev = dactron->dact_dev;	obuf = dactron->obuf;	file->f_dentry->d_inode->i_atime = CURRENT_TIME;	while( count > 0 ){		if (signal_pending(current)) {			ret = -ERESTARTSYS;		}		this_write = ( count >= OBUF_SIZE ) ? OBUF_SIZE : count;		if( copy_from_user( dactron->obuf, buffer, this_write )){			ret = -EFAULT;		}		result = usb_bulk_msg( dev, usb_sndbulkpipe( dev, 2 ), obuf, this_write, &partial, 60*HZ );		pr_debug("write stats(%d): result:%d this_write:%d partial:%d\n", dact_minor, result, this_write, partial);		if( result == -ETIMEDOUT ){	/* NAK -- shouldn't happen */			pr_debug( "write_dactron: NAK received.\n" );			ret = result;			break;		}else if( result < 0 ){ /* We should not get any I/O errors */			ret = -EIO;			break;		}		if( partial != this_write ){ /* Unable to write all contents of obuf */			ret = -EIO;			break;		}		if( partial ){ /* Data written */			buffer += partial;			count -= partial;			bytes_written += partial;		}else{ /* No data written */			ret = 0;			break;		}	}	up( &( dactron->sem ));	mdelay( 5 );		/* This seems to help with SANE queries */	return ret ? ret : bytes_written;};static intdactron_ioctl( struct inode *inode, struct file *file,	      unsigned int cmd, unsigned long arg ){	struct usb_device *dev;	kdev_t dact_minor;	dact_minor = USB_DACT_MINOR(inode);	if (!p_table[dact_minor]) {		err("dactron_ioctl(%d): invalid dact_minor", dact_minor);		return -ENODEV;	}	dev = p_table[dact_minor]->dact_dev;	switch (cmd)	{	case DACTRON_IOCTL_VENDOR :		return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));	case DACTRON_IOCTL_PRODUCT :		return (put_user(dev->descriptor.idProduct, (unsigned int *) arg)); 	case DACTRON_IOCTL_CTRLMSG: 	{ 		struct ctrlmsg_ioctl { 			devrequest	req; 			void		*data; 		} cmsg; 		int pipe, nb, ret; 		unsigned char buf[64];  		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) 			return -EFAULT; 		nb = le16_to_cpup(&cmsg.req.length); 		if (nb > sizeof(buf)) 			return -EINVAL; 		if ((cmsg.req.requesttype & 0x80) == 0) { 			pipe = usb_sndctrlpipe(dev, 0); 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) 				return -EFAULT; 		} else { 			pipe = usb_rcvctrlpipe(dev, 0);		} 		ret = usb_control_msg(dev, pipe, cmsg.req.request, 				      cmsg.req.requesttype, 				      le16_to_cpup(&cmsg.req.value), 				      le16_to_cpup(&cmsg.req.index), 				      buf, nb, HZ); 		if (ret < 0) { 			err("dactron_ioctl(%d): control_msg returned %d\n", dact_minor, ret); 			return -EIO; 		} 		if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb)) 			return -EFAULT; 		return 0; 	}	default:		return -ENOTTY;	}	return 0;}static intwritemem( struct usb_device *usbdev, int pos, unsigned char *data, int len){	int ret;	unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);	if (!transfer_buffer) {		pr_debug("writemem: kmalloc(%d) failed.\n", len);		return -ENOMEM;	}	memcpy (transfer_buffer, data, len);	ret = usb_control_msg( usbdev, usb_sndctrlpipe( usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);	kfree (transfer_buffer);	return ret;}static	intload_8051_code( struct usb_device *dev, char *filename ){	int	ret;	PINTEL_HEX_RECORD ptr = firmware;	ret = usb_set_configuration( dev, dev->config[0].bConfigurationValue );	while( ptr->Type == 0 ){		pr_debug("writemem:(%04X %p %d)\n", ptr->Address, ptr->Data, ptr->Length);		ret = writemem( dev, ptr->Address, ptr->Data, ptr->Length );		if (ret < 0) {			pr_debug("writemem failed (%d %04X %p %d)\n", ret, ptr->Address, ptr->Data, ptr->Length);			break;		}		ptr++;	}	return ret;};static  void *dactron_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){	struct	usb_interface_descriptor *interface;	struct	usb_endpoint_descriptor  *endpoint;	struct	usb_dactron_data 	 *dactron;	int	ep_cnt;	int	i, j;	int	ret;	int	act_set;	kdev_t	dact_minor;	char	valid_device = 0;	char	have_bulk_in[3], have_bulk_out[3];	char	name[10];	pr_debug( "usb_dactron: USB dev address:%p\n", dev );	pr_debug( "usb_dactron: interface No: %u\n", ifnum );	/* Check the vendor and product id */	for( i = 0; i < sizeof( dactron_device_ids ) / sizeof( struct usb_device_id ); i ++ ){		if(( dev->descriptor.idVendor == dactron_device_ids[i].idVendor ) && ( dev->descriptor.idProduct == dactron_device_ids[i].idProduct )){			valid_device = 1;			break;		}	}	pr_debug( "valid_device:%d\n", valid_device );	if( !valid_device ){		pr_debug( "Wrong vendor & product id\n" );		return	NULL;	}	pr_debug( "bNumConfigurations:%d\n", ( int ) dev->descriptor.bNumConfigurations );	if( dev->descriptor.bNumConfigurations == 0 ){		pr_debug("probe_dactron: no configuration\n" );		return NULL;	}	pr_debug( "dev->actconfig->bNumInterfaces:%d\n", dev->actconfig->bNumInterfaces );	if( dev->actconfig->bNumInterfaces == 0 ){		pr_debug("probe_dactron: no interface\n" );		return NULL;	}	/* Check the device endpoints' No. & type */	act_set = dev->actconfig->interface[ ifnum ].act_altsetting;	interface = &dev->actconfig->interface[ ifnum ].altsetting[ act_set ];	endpoint = &interface->endpoint[ 0 ];	pr_debug( "probe_dactron: Number of Endpoints:%d\n", ( int )interface->bNumEndpoints );	if( interface->bNumEndpoints != 13 ){		pr_debug( "probe_dactron: not enough endpoint\n" );		return NULL;	}	if( !( dactron = kmalloc( sizeof( struct usb_dactron_data ), GFP_KERNEL ))){		pr_debug( "probe_dactron: Out of memory.\n" );		up( &dactron_mutex );		return NULL;	}	memset( dactron, 0, sizeof( struct usb_dactron_data ));	ep_cnt = 0;	for( i = 0; i < 3; i++ ){		have_bulk_in[i] = 0;		have_bulk_out[i] = 0;	}	i = j = 0;	while( ep_cnt < interface->bNumEndpoints ){		if( IS_EP_BULK_IN( endpoint[ ep_cnt ] )) {			ep_cnt++;			if( i > 2 ){				pr_debug( "Wrong Bulk In Endpoints Type\n" );				return NULL;			}			have_bulk_in[ i ] = ep_cnt;			dactron->bulk_in_ep[ i ] = ep_cnt;			pr_debug( "bulk_in[%d]:%d\n", i, ep_cnt );			i++;			continue;		}		if( IS_EP_BULK_OUT( endpoint[ ep_cnt ] )) {			ep_cnt++;			if( j > 2 ){				pr_debug( "Wrong Bulk Out Endpoints Type\n" );				return NULL;			}			have_bulk_out[ j ] = ep_cnt;			dactron->bulk_out_ep[ j ] = ep_cnt;			pr_debug( "bulk_out[%d]:%d\n", j, ep_cnt );			j++;			continue;		}		ep_cnt++;	}	down( &dactron_mutex );	for( dact_minor = 0; dact_minor < DACT_MAX_MNR; dact_minor++ )		if( !p_table[ dact_minor ] )			break;	if( p_table[ dact_minor ] ){		pr_debug( "probe_dactron: No more minor devices remaining.\n" );		kfree( dactron );		up( &dactron_mutex );		return NULL;	}	pr_debug( "probe_dactron: Allocated minor:%d\n", dact_minor );	init_MUTEX( &( dactron->sem )); /* Initializes to unlocked */	pr_debug( "probe_dactron(%d): Address of dactron:%p\n", dact_minor, dactron );	if( !( dactron->obuf = ( char * ) kmalloc( OBUF_SIZE, GFP_KERNEL ))){		pr_debug( "probe_dactron(%d): Not enough memory for the output buffer.\n", dact_minor );		kfree( dactron );		up( &dactron_mutex );		return NULL;	}	if( !( dactron->ibuf = ( char * ) kmalloc( IBUF_SIZE, GFP_KERNEL ))){		pr_debug("probe_dactron(%d): Not enough memory for the input buffer.\n", dact_minor );		kfree( dactron->obuf );		kfree( dactron );		up( &dactron_mutex );		return NULL;	}		dactron->present = 1;	dactron->dact_dev = dev;	dactron->dact_minor = dact_minor;	dactron->isopen = 0;	dactron->ifnum = ifnum;	pr_debug( "dactron->ifnum:%d\n", dactron->ifnum );	pr_debug( "dactron->dact_minor:%d\n", dactron->dact_minor );	sprintf( name, "dactron%d", dactron->dact_minor );		/*	dactron->devfs = devfs_register( usb_devfs_handle_dactron, name,				    DEVFS_FL_DEFAULT, USB_MAJOR,				    DACT_BASE_MNR + dactron->dact_minor,				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |				    S_IWGRP | S_IROTH | S_IWOTH, &usb_dactron_fops, NULL );	if( dactron->devfs == NULL )		pr_debug( "dactron%d: device node registration failed\n", dact_minor );	*/	p_table[ dact_minor ] = dactron;	ret = load_8051_code( dactron->dact_dev, NULL );	if( ret < 0 )		return NULL;	up( &dactron_mutex );	MOD_INC_USE_COUNT;	if( dactron != NULL ){		pr_debug( "Succeed to probe\n" );		return dactron;	}else{		pr_debug( "Fail to probe\n" );		return	NULL;	}};static	voiddactron_disconnect( struct usb_device *dev, void *ptr ){	struct usb_dactron_data *dactron = ( struct usb_dactron_data * )ptr;	down( &dactron_mutex );	down( &( dactron->sem ));        usb_driver_release_interface( &usb_dactron_driver, &( dactron->dact_dev->actconfig->interface[ dactron->ifnum ] ));	kfree(dactron->ibuf);	kfree(dactron->obuf);	pr_debug( "disconnect_dactron: De-allocating minor:%d\n", dactron->dact_minor );	devfs_unregister(dactron->devfs);	p_table[ dactron->dact_minor ] = NULL;	up( &( dactron->sem ));	kfree( dactron );	up( &dactron_mutex );	MOD_DEC_USE_COUNT;};int __initusb_dactron_init( void ){	pr_debug( "loading the module...\n" );	if( usb_register( &usb_dactron_driver ) < 0 ){		pr_debug( "Unable to register the dactron driver\n" );		return -1;	};	return 0;};void __exitusb_dactron_exit( void ){	pr_debug( "unloading the moudle...\n" );	usb_deregister( &usb_dactron_driver );};module_init( usb_dactron_init );module_exit( usb_dactron_exit );MODULE_LICENSE( "GPL" );

⌨️ 快捷键说明

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