📄 scanner.c
字号:
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 + -