📄 dactron.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 + -