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

📄 scanner.c

📁 Driver for USB Scanners (linux-2.6)
💻 C
📖 第 1 页 / 共 3 页
字号:
 		nb = cmsg.req.wLength;

 		if (nb > sizeof(buf)) {
 			retval = -EINVAL;
			break;
		}

 		if ((cmsg.req.bRequestType & 0x80) == 0) {
 			pipe = usb_sndctrlpipe(dev, 0);
 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) {
 				retval = -EFAULT;
				break;
			}
 		} else {
 			pipe = usb_rcvctrlpipe(dev, 0);
		}

 		ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
 				      cmsg.req.bRequestType,
 				      cmsg.req.wValue,
 				      cmsg.req.wIndex,
 				      buf, nb, HZ);

 		if (ret < 0) {
 			err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
 			retval = -EIO;
			break;
 		}

 		if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
 			retval = -EFAULT;

 		break;
 	}
	default:
		break;
	}
	up(&(scn->sem));
	return retval;
}

static void destroy_scanner (struct kobject *kobj)
{
	struct scn_usb_data *scn;

	dbg ("%s", __FUNCTION__);

	scn = to_scanner(kobj);

	down (&scn_mutex);
	down (&(scn->sem));

	usb_driver_release_interface(&scanner_driver,
		scn->scn_dev->actconfig->interface[scn->ifnum]);

	kfree(scn->ibuf);
	kfree(scn->obuf);

	usb_free_urb(scn->scn_irq);
	usb_put_dev(scn->scn_dev);
	up (&(scn->sem));
	kfree (scn);
	up (&scn_mutex);
}

static struct kobj_type scanner_kobj_type = {
	.release = destroy_scanner,
};

static struct
file_operations usb_scanner_fops = {
	.owner =	THIS_MODULE,
	.read =		read_scanner,
	.write =	write_scanner,
	.ioctl =	ioctl_scanner,
	.open =		open_scanner,
	.release =	close_scanner,
};

static struct usb_class_driver scanner_class = {
	.name =		"usb/scanner%d",
	.fops =		&usb_scanner_fops,
	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
	.minor_base =	SCN_BASE_MNR,
};

static int
probe_scanner(struct usb_interface *intf,
	      const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev (intf);
	struct scn_usb_data *scn;
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;

	int ep_cnt;
	int ix;
	int retval;

	char valid_device = 0;
	char have_bulk_in, have_bulk_out, have_intr;
	char name[14];

	dbg("probe_scanner: USB dev address:%p", dev);

/*
 * 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 -ENODEV;	/* 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 -ENODEV;
	}

	interface = intf->altsetting;
 
	if (interface[0].desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
	    interface[0].desc.bInterfaceClass != USB_CLASS_PER_INTERFACE &&
	    interface[0].desc.bInterfaceClass != USB_CLASS_CDC_DATA &&
	    interface[0].desc.bInterfaceClass != SCN_CLASS_SCANJET) {
		dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].desc.bInterfaceClass);
		return -ENODEV;
	}

/*
 * Start checking for bulk and interrupt endpoints. We are only using the first
 * one of each type of 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->desc.bNumEndpoints);

	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;

	while (ep_cnt < interface->desc.bNumEndpoints) {
		endpoint = &interface->endpoint[ep_cnt].desc;

		if (IS_EP_BULK_IN(endpoint)) {
			ep_cnt++;
			if (have_bulk_in) {
				info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
				continue;
			}
			have_bulk_in = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
			continue;
		}

		if (IS_EP_BULK_OUT(endpoint)) {
			ep_cnt++;
			if (have_bulk_out) {
				info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
				continue;
			}
			have_bulk_out = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
			continue;
		}

		if (IS_EP_INTR(endpoint)) {
			ep_cnt++;
			if (have_intr) {
				info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
				continue;
			}
			have_intr = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
			dbg("probe_scanner: intr_ep:%d", have_intr);
			continue;
		}
		info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
		return -EIO;	/* Shouldn't ever get here unless we have something weird */
	}


/*
 * Perform a quick check to make sure that everything worked as it
 * should have.
 */

	if (!have_bulk_in) {
		err("probe_scanner: One bulk-in endpoint required.");
		return -EIO;
	}

/*
 * 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.  */
	
	down(&scn_mutex);

	retval = usb_register_dev(intf, &scanner_class);
	if (retval) {
		err ("Not able to get a minor for this device.");
		up(&scn_mutex);
		return -ENOMEM;
	}

	dbg("probe_scanner: Allocated minor:%d", intf->minor);

	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
		err("probe_scanner: Out of memory.");
		up(&scn_mutex);
		return -ENOMEM;
	}
	memset (scn, 0, sizeof(struct scn_usb_data));
	kobject_init(&scn->kobj);
	scn->kobj.ktype = &scanner_kobj_type;

	scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
	if (!scn->scn_irq) {
		usb_deregister_dev(intf, &scanner_class);
		kfree(scn);
		up(&scn_mutex);
		return -ENOMEM;
	}

	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */

	dbg ("probe_scanner(%d): Address of scn:%p", intf->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", intf->minor, have_intr);
		usb_fill_int_urb(scn->scn_irq, dev,
			     usb_rcvintpipe(dev, have_intr),
			     &scn->button, 1, irq_scanner, scn,
			     // endpoint[(int)have_intr].bInterval);
			     250);

		retval = usb_submit_urb(scn->scn_irq, GFP_KERNEL);
		if (retval) {
			err("probe_scanner(%d): Unable to allocate INT URB.", intf->minor);
			usb_deregister_dev(intf, &scanner_class);
                	kfree(scn);
			up(&scn_mutex);
                	return retval;
        	}
	}


/* 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.", intf->minor);
		if (have_intr)
			usb_unlink_urb(scn->scn_irq);
		usb_free_urb(scn->scn_irq);
		usb_deregister_dev(intf, &scanner_class);
		kfree(scn);
		up(&scn_mutex);
		return -ENOMEM;
	}
	dbg("probe_scanner(%d): obuf address:%p", intf->minor, scn->obuf);

	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
		err("probe_scanner(%d): Not enough memory for the input buffer.", intf->minor);
		if (have_intr)
			usb_unlink_urb(scn->scn_irq);
		usb_free_urb(scn->scn_irq);
		usb_deregister_dev(intf, &scanner_class);
		kfree(scn->obuf);
		kfree(scn);
		up(&scn_mutex);
		return -ENOMEM;
	}
	dbg("probe_scanner(%d): ibuf address:%p", intf->minor, scn->ibuf);
	

	switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
	case 0x04b8:		/* Seiko/Epson */
		scn->rd_nak_timeout = HZ * 60;
		break;
	case 0x055f:		/* Mustek */
	case 0x0400:		/* Another Mustek */
		scn->rd_nak_timeout = HZ * 1;
	default:
		scn->rd_nak_timeout = RD_NAK_TIMEOUT;
	}


	if (read_timeout > 0) {	/* User specified read timeout overrides everything */
		info("probe_scanner: User specified USB read timeout - %d", read_timeout);
		scn->rd_nak_timeout = read_timeout;
	}


	usb_get_dev(dev);
	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 = intf->minor;
	scn->isopen = 0;

	snprintf(name, sizeof(name), scanner_class.name,
		 intf->minor - scanner_class.minor_base);

	info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
	      dev->descriptor.idVendor, dev->descriptor.idProduct, name);

	usb_set_intfdata(intf, scn);
	up(&scn_mutex);
	
	return 0;
}

static void
disconnect_scanner(struct usb_interface *intf)
{
	struct scn_usb_data *scn = usb_get_intfdata(intf);

	/* disable open() */
	dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor);
	usb_deregister_dev(intf, &scanner_class);

	usb_set_intfdata(intf, NULL);
	if(scn->intr_ep) {
		dbg("%s(%d): Unlinking IRQ URB", __FUNCTION__, scn->scn_minor);
		usb_unlink_urb(scn->scn_irq);
	}

	if (scn)
		kobject_put(&scn->kobj);
}

/* we want to look at all devices, as the vendor/product id can change
 * depending on the command line argument */
static struct usb_device_id ids[] = {
	{.driver_info = 42},
	{}
};

static struct
usb_driver scanner_driver = {
	.owner =	THIS_MODULE,
	.name =		"usbscanner",
	.probe =	probe_scanner,
	.disconnect =	disconnect_scanner,
	.id_table =	ids,
};

static void __exit
usb_scanner_exit(void)
{
	usb_deregister(&scanner_driver);
}

static int __init
usb_scanner_init (void)
{
	int retval;
	retval = usb_register(&scanner_driver);
	if (retval)
		goto out;

	info(DRIVER_VERSION ":" DRIVER_DESC);
	if (vendor != -1 && product != -1)
		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
 out:
	return retval;
}

module_init(usb_scanner_init);
module_exit(usb_scanner_exit);

⌨️ 快捷键说明

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