📄 scanner.c
字号:
nb = le16_to_cpup(&cmsg.req.wLength);
if (nb > sizeof(buf))
return -EINVAL;
if ((cmsg.req.bRequestType & 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.bRequest,
cmsg.req.bRequestType,
le16_to_cpup(&cmsg.req.wValue),
le16_to_cpup(&cmsg.req.wIndex),
buf, nb, HZ);
if (ret < 0) {
err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
return -EIO;
}
if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
return -EFAULT;
return 0;
}
default:
return -ENOTTY;
}
return 0;
}
static struct
file_operations usb_scanner_fops = {
read: read_scanner,
write: write_scanner,
ioctl: ioctl_scanner,
open: open_scanner,
release: close_scanner,
};
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;
int scn_minor;
int retval;
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
char name[10];
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 -- consult Documentation/usb/scanner.txt.");
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 -- consult Documentation/usb/scanner.txt");
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. */
down(&scn_mutex);
retval = usb_register_dev(&scanner_driver, 1, &scn_minor);
if (retval) {
if (retval != -ENODEV) {
err ("Not able to get a minor for this device.");
up(&scn_mutex);
return NULL;
}
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.");
up(&scn_mutex);
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.");
up(&scn_mutex);
return NULL;
}
memset (scn, 0, sizeof(struct scn_usb_data));
scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
if (!scn->scn_irq) {
kfree(scn);
up(&scn_mutex);
return NULL;
}
init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
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, GFP_KERNEL)) {
err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
kfree(scn);
up(&scn_mutex);
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);
up(&scn_mutex);
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);
up(&scn_mutex);
return NULL;
}
dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
case 0x04b8: /* Seiko/Epson */
scn->rd_nak_timeout = HZ * 40;
break;
case 0x055f: /* Mustek */
case 0x0400: /* Another Mustek */
case 0x0ff5: /* And yet 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;
}
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;
sprintf(name, "scanner%d", scn->scn_minor);
scn->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR,
SCN_BASE_MNR + scn->scn_minor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
if (scn->devfs == NULL)
dbg("scanner%d: device node registration failed", scn_minor);
p_scn_table[scn_minor] = scn;
up(&scn_mutex);
return scn;
}
static void
disconnect_scanner(struct usb_device *dev, void *ptr)
{
struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
down (&scn_mutex);
down (&(scn->sem));
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);
devfs_unregister(scn->devfs);
usb_deregister_dev(&scanner_driver, 1, scn->scn_minor);
p_scn_table[scn->scn_minor] = NULL;
usb_free_urb(scn->scn_irq);
up (&(scn->sem));
kfree (scn);
up (&scn_mutex);
}
static struct
usb_driver scanner_driver = {
name: "usbscanner",
probe: probe_scanner,
disconnect: disconnect_scanner,
fops: &usb_scanner_fops,
minor: SCN_BASE_MNR,
num_minors: SCN_MAX_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 __exit
usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
int __init
usb_scanner_init (void)
{
if (usb_register(&scanner_driver) < 0)
return -1;
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
module_init(usb_scanner_init);
module_exit(usb_scanner_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -