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

📄 scanner.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			for (cnt=0; cnt < cnt_max; cnt++) {				printk("%X ", obuf[cnt]);			}			printk("\n");		}#endif		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(&(scn->gen_lock));	mdelay(5);		/* This seems to help with SANE queries */	return ret ? ret : bytes_written;}static ssize_tread_scanner(struct file * file, char * buffer,             size_t count, loff_t *ppos){	struct scn_usb_data *scn;	struct usb_device *dev;	ssize_t bytes_read;	/* Overall count of bytes_read */	ssize_t ret;	kdev_t scn_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;	scn = file->private_data;	scn_minor = scn->scn_minor;	ibuf = scn->ibuf;	dev = scn->scn_dev;	bytes_read = 0;	ret = 0;	file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the                                                            atime of                                                            the device                                                            node */	down(&(scn->gen_lock));	while (count > 0) {		if (signal_pending(current)) {			ret = -EINTR;			break;		}		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT);		dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);/* * Scanners are sometimes inheriently slow since they are mechanical * in nature.  USB bulk reads tend to timeout while the scanner is * positioning, resetting, warming up the lamp, etc if the timeout is * set too low.  A very long timeout parameter for bulk reads was used * to overcome this limitation, but this sometimes resulted in folks * having to wait for the timeout to expire after pressing Ctrl-C from * an application. The user was sometimes left with the impression * that something had hung or crashed when in fact the USB read was * just waiting on data.  So, the below code retains the same long * timeout period, but splits it up into smaller parts so that * Ctrl-C's are acted upon in a reasonable amount of time. */		if (result == USB_ST_TIMEOUT && !partial) { /* Timeout                                                               and no                                                               data */			if (--rd_expire <= 0) {				warn("read_scanner(%d): excessive NAK's received", scn_minor);				ret = -ETIME;				break;			} else {				interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT);				continue;			}		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);			ret = -EIO;			break;		}#ifdef RD_DATA_DUMP		if (partial) {			unsigned char cnt, cnt_max;			cnt_max = (partial > 24) ? 24 : partial;			printk(KERN_DEBUG "dump(%d): ", scn_minor);			for (cnt=0; cnt < cnt_max; cnt++) {				printk("%X ", ibuf[cnt]);			}			printk("\n");		}#endif		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(&(scn->gen_lock));	return ret ? ret : bytes_read;}static void *probe_scanner(struct usb_device *dev, unsigned int ifnum,	      const struct usb_device_id *id){	struct scn_usb_data *scn;	struct usb_interface_descriptor *interface;	struct usb_endpoint_descriptor *endpoint;	int ep_cnt;	int ix;	kdev_t scn_minor;	char valid_device = 0;	char have_bulk_in, have_bulk_out, have_intr;	if (vendor != -1 && product != -1) {		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);	}	dbg("probe_scanner: USB dev address:%p", dev);	dbg("probe_scanner: ifnum:%u", ifnum);/* * 1. Check Vendor/Product * 2. Determine/Assign Bulk Endpoints * 3. Determine/Assign Intr Endpoint *//* * There doesn't seem to be an imaging class defined in the USB * Spec. (yet).  If there is, HP isn't following it and it doesn't * look like anybody else is either.  Therefore, we have to test the * Vendor and Product ID's to see what we have.  Also, other scanners * may be able to use this driver by specifying both vendor and * product ID's as options to the scanner module in conf.modules. * * NOTE: Just because a product is supported here does not mean that * applications exist that support the product.  It's in the hopes * that this will allow developers a means to produce applications * that will support USB products. * * Until we detect a device which is pleasing, we silently punt. */	for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {		if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&		    (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {			valid_device = 1;			break;                }	}	if (dev->descriptor.idVendor == vendor &&   /* User specified */	    dev->descriptor.idProduct == product) { /* User specified */		valid_device = 1;	}        if (!valid_device)                return NULL;    /* We didn't find anything pleasing *//* * After this point we can be a little noisy about what we are trying to *  configure. */	if (dev->descriptor.bNumConfigurations != 1) {		info("probe_scanner: Only one device configuration is supported.");		return NULL;	}	if (dev->config[0].bNumInterfaces != 1) {		info("probe_scanner: Only one device interface is supported.");		return NULL;	}	interface = dev->config[0].interface[ifnum].altsetting;	endpoint = interface[ifnum].endpoint;/* * Start checking for two bulk endpoints OR two bulk endpoints *and* one * interrupt endpoint. If we have an interrupt endpoint go ahead and * setup the handler. FIXME: This is a future enhancement... */	dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);	if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) {		info("probe_scanner: Only two or three endpoints supported.");		return NULL;	}	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;	while (ep_cnt < interface->bNumEndpoints) {		if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {			ep_cnt++;			have_bulk_in = ep_cnt;			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);			continue;		}		if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {			ep_cnt++;			have_bulk_out = ep_cnt;			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);			continue;		}		if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {			ep_cnt++;			have_intr = ep_cnt;			dbg("probe_scanner: intr_ep:%d", have_intr);			continue;		}		info("probe_scanner: Undetected endpoint. Notify the maintainer.");		return NULL;	/* Shouldn't ever get here unless we have something weird */	}/* * Perform a quick check to make sure that everything worked as it * should have. */	switch(interface->bNumEndpoints) {	case 2:		if (!have_bulk_in || !have_bulk_out) {			info("probe_scanner: Two bulk endpoints required.");			return NULL;		}		break;	case 3:		if (!have_bulk_in || !have_bulk_out || !have_intr) {			info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");			return NULL;		}		break;	default:		info("probe_scanner: Endpoint determination failed.  Notify the maintainer.");		return NULL;	}/* * Determine a minor number and initialize the structure associated * with it.  The problem with this is that we are counting on the fact * that the user will sequentially add device nodes for the scanner * devices.  */	for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {		if (!p_scn_table[scn_minor])			break;	}/* Check to make sure that the last slot isn't already taken */	if (p_scn_table[scn_minor]) {		err("probe_scanner: No more minor devices remaining.");		return NULL;	}	dbg("probe_scanner: Allocated minor:%d", scn_minor);	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {		err("probe_scanner: Out of memory.");		return NULL;	}	memset (scn, 0, sizeof(struct scn_usb_data));	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);/* Ok, if we detected an interrupt EP, setup a handler for it */	if (have_intr) {		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);		FILL_INT_URB(&scn->scn_irq, dev,			     usb_rcvintpipe(dev, have_intr),			     &scn->button, 1, irq_scanner, scn,			     // endpoint[(int)have_intr].bInterval);			     250);	        if (usb_submit_urb(&scn->scn_irq)) {			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);                	kfree(scn);                	return NULL;        	}	}/* Ok, now initialize all the relevant values */	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);		kfree(scn);		return NULL;	}	dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);		kfree(scn->obuf);		kfree(scn);		return NULL;	}	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);	scn->bulk_in_ep = have_bulk_in;	scn->bulk_out_ep = have_bulk_out;	scn->intr_ep = have_intr;	scn->present = 1;	scn->scn_dev = dev;	scn->scn_minor = scn_minor;	scn->isopen = 0;	init_MUTEX(&(scn->gen_lock));	return p_scn_table[scn_minor] = scn;}static voiddisconnect_scanner(struct usb_device *dev, void *ptr){	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;	if(scn->intr_ep) {		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);		usb_unlink_urb(&scn->scn_irq);	}        usb_driver_release_interface(&scanner_driver,                &scn->scn_dev->actconfig->interface[scn->ifnum]);	kfree(scn->ibuf);	kfree(scn->obuf);	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);	p_scn_table[scn->scn_minor] = NULL;	kfree (scn);}#ifdef SCN_IOCTLstatic intioctl_scanner(struct inode *inode, struct file *file,	      unsigned int cmd, unsigned long arg){	struct usb_device *dev;	int result;	kdev_t scn_minor;	scn_minor = USB_SCN_MINOR(inode);	if (!p_scn_table[scn_minor]) {		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);		return -ENODEV;	}	dev = p_scn_table[scn_minor]->scn_dev;	switch (cmd)	{	case PV8630_IOCTL_INREQUEST :	{		struct {			__u8  data;			__u8  request;			__u16 value;			__u16 index;		} args;		if (copy_from_user(&args, (void *)arg, sizeof(args)))			return -EFAULT;		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),					 args.request, USB_TYPE_VENDOR|					 USB_RECIP_DEVICE|USB_DIR_IN,					 args.value, args.index, &args.data,					 1, HZ*5);		dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);		if (copy_to_user((void *)arg, &args, sizeof(args)))			return -EFAULT;		dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);		return result;	}	case PV8630_IOCTL_OUTREQUEST :	{		struct {			__u8  request;			__u16 value;			__u16 index;		} args;		if (copy_from_user(&args, (void *)arg, sizeof(args)))			return -EFAULT;		dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);		result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),					 args.request, USB_TYPE_VENDOR|					 USB_RECIP_DEVICE|USB_DIR_OUT,					 args.value, args.index, NULL,					 0, HZ*5);		dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);		return result;	}	default:		return -ENOIOCTLCMD;	}	return 0;}#endif /* SCN_IOCTL */static structfile_operations usb_scanner_fops = {	read:		read_scanner,	write:		write_scanner,#ifdef SCN_IOCTL	ioctl:		ioctl_scanner,#endif /* SCN_IOCTL */	open:		open_scanner,	release:	close_scanner,};static structusb_driver scanner_driver = {	name:		"usbscanner",	probe:		probe_scanner,	disconnect:	disconnect_scanner,	fops:		&usb_scanner_fops,	minor:		SCN_BASE_MNR,	id_table:	NULL, /* This would be scanner_device_ids, but we				 need to check every USB device, in case				 we match a user defined vendor/product ID. */};void __exitusb_scanner_exit(void){	usb_deregister(&scanner_driver);}int __initusb_scanner_init (void){        if (usb_register(&scanner_driver) < 0)                return -1;	info("USB Scanner support registered.");	return 0;}module_init(usb_scanner_init);module_exit(usb_scanner_exit);

⌨️ 快捷键说明

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