diff options
Diffstat (limited to 'drivers/usb/class/usblp.c')
| -rw-r--r-- | drivers/usb/class/usblp.c | 274 |
1 files changed, 164 insertions, 110 deletions
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d4c47d5d7625..a7a1d38b6bef 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * usblp.c * @@ -31,33 +32,18 @@ * none - Maintained in Linux kernel after v0.13 */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/minmax.h> +#include <linux/sched/signal.h> #include <linux/signal.h> #include <linux/poll.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/lp.h> #include <linux/mutex.h> #undef DEBUG #include <linux/usb.h> +#include <linux/usb/ch9.h> #include <linux/ratelimit.h> /* @@ -80,12 +66,20 @@ #define IOCNR_SOFT_RESET 7 /* Get device_id string: */ #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) -/* The following ioctls were added for http://hpoj.sourceforge.net: */ -/* Get two-int array: - * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), - * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ +/* The following ioctls were added for http://hpoj.sourceforge.net: + * Get two-int array: + * [0]=current protocol + * (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3), + * [1]=supported protocol mask (mask&(1<<n)!=0 means + * USB_CLASS_PRINTER/1/n supported): + */ #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) -/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ +/* + * Set protocol + * (arg: 1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3): + */ #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) /* Set channel number (HP Vendor-specific command): */ #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) @@ -94,7 +88,7 @@ /* Get two-int array: [0]=vendor ID, [1]=product ID: */ #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) /* Perform class specific soft reset */ -#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0); +#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0) /* * A DEVICE_ID string may include the printer's serial number. @@ -147,8 +141,10 @@ struct usblp { int readcount; /* Counter for reads */ int ifnum; /* Interface number */ struct usb_interface *intf; /* The interface */ - /* Alternate-setting numbers and endpoints for each protocol - * (7/1/{index=1,2,3}) that the device supports: */ + /* + * Alternate-setting numbers and endpoints for each protocol + * (USB_CLASS_PRINTER/1/{index=1,2,3}) that the device supports: + */ struct { int alt_setting; struct usb_endpoint_descriptor *epwrite; @@ -279,12 +275,29 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i #define usblp_reset(usblp)\ usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) -#define usblp_hp_channel_change_request(usblp, channel, buffer) \ - usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) +static int usblp_hp_channel_change_request(struct usblp *usblp, int channel, u8 *new_channel) +{ + u8 *buf; + int ret; + + buf = kzalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, + USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, + channel, buf, 1); + if (ret == 0) + *new_channel = buf[0]; + + kfree(buf); + + return ret; +} /* * See the description for usblp_select_alts() below for the usage - * explanation. Look into your /proc/bus/usb/devices and dmesg in + * explanation. Look into your /sys/kernel/debug/usb/devices and dmesg in * case of any trouble. */ static int proto_bias = -1; @@ -297,6 +310,7 @@ static void usblp_bulk_read(struct urb *urb) { struct usblp *usblp = urb->context; int status = urb->status; + unsigned long flags; if (usblp->present && usblp->used) { if (status) @@ -304,14 +318,14 @@ static void usblp_bulk_read(struct urb *urb) "nonzero read bulk status received: %d\n", usblp->minor, status); } - spin_lock(&usblp->lock); + spin_lock_irqsave(&usblp->lock, flags); if (status < 0) usblp->rstatus = status; else usblp->rstatus = urb->actual_length; usblp->rcomplete = 1; wake_up(&usblp->rwait); - spin_unlock(&usblp->lock); + spin_unlock_irqrestore(&usblp->lock, flags); usb_free_urb(urb); } @@ -320,6 +334,7 @@ static void usblp_bulk_write(struct urb *urb) { struct usblp *usblp = urb->context; int status = urb->status; + unsigned long flags; if (usblp->present && usblp->used) { if (status) @@ -327,7 +342,7 @@ static void usblp_bulk_write(struct urb *urb) "nonzero write bulk status received: %d\n", usblp->minor, status); } - spin_lock(&usblp->lock); + spin_lock_irqsave(&usblp->lock, flags); if (status < 0) usblp->wstatus = status; else @@ -335,7 +350,7 @@ static void usblp_bulk_write(struct urb *urb) usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); - spin_unlock(&usblp->lock); + spin_unlock_irqrestore(&usblp->lock, flags); usb_free_urb(urb); } @@ -352,7 +367,8 @@ static int usblp_check_status(struct usblp *usblp, int err) int error; mutex_lock(&usblp->mut); - if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + error = usblp_read_status(usblp, usblp->statusbuf); + if (error < 0) { mutex_unlock(&usblp->mut); printk_ratelimited(KERN_ERR "usblp%d: error %d reading printer status\n", @@ -448,6 +464,7 @@ static void usblp_cleanup(struct usblp *usblp) kfree(usblp->readbuf); kfree(usblp->device_id_string); kfree(usblp->statusbuf); + usb_put_intf(usblp->intf); kfree(usblp); } @@ -464,28 +481,39 @@ static int usblp_release(struct inode *inode, struct file *file) mutex_lock(&usblp_mutex); usblp->used = 0; - if (usblp->present) { + if (usblp->present) usblp_unlink_urbs(usblp); - usb_autopm_put_interface(usblp->intf); - } else /* finish cleanup from disconnect */ - usblp_cleanup(usblp); + + usb_autopm_put_interface(usblp->intf); + + if (!usblp->present) /* finish cleanup from disconnect */ + usblp_cleanup(usblp); /* any URBs must be dead */ + mutex_unlock(&usblp_mutex); return 0; } /* No kernel lock - fine */ -static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) +static __poll_t usblp_poll(struct file *file, struct poll_table_struct *wait) { - int ret; + struct usblp *usblp = file->private_data; + __poll_t ret = 0; unsigned long flags; - struct usblp *usblp = file->private_data; /* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */ poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); + + mutex_lock(&usblp->mut); + if (!usblp->present) + ret |= EPOLLHUP; + mutex_unlock(&usblp->mut); + spin_lock_irqsave(&usblp->lock, flags); - ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | - ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); + if (usblp->bidir && usblp->rcomplete) + ret |= EPOLLIN | EPOLLRDNORM; + if (usblp->no_paper || usblp->wcomplete) + ret |= EPOLLOUT | EPOLLWRNORM; spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -661,7 +689,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case LPGETSTATUS: - if ((retval = usblp_read_status(usblp, usblp->statusbuf))) { + retval = usblp_read_status(usblp, usblp->statusbuf); + if (retval) { printk_ratelimited(KERN_ERR "usblp%d:" "failed reading printer status (%d)\n", usblp->minor, retval); @@ -694,9 +723,11 @@ static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) struct urb *urb; char *writebuf; - if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + writebuf = kmalloc(transfer_length, GFP_KERNEL); + if (writebuf == NULL) return NULL; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { kfree(writebuf); return NULL; } @@ -722,18 +753,21 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t rv = -EINTR; goto raise_biglock; } - if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0) + rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK)); + if (rv < 0) goto raise_wait; while (writecount < count) { /* * Step 1: Submit next block. */ - if ((transfer_length = count - writecount) > USBLP_BUF_SIZE) + transfer_length = count - writecount; + if (transfer_length > USBLP_BUF_SIZE) transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) + writeurb = usblp_new_writeurb(usblp, transfer_length); + if (writeurb == NULL) goto raise_urb; usb_anchor_urb(writeurb, &usblp->urbs); @@ -746,7 +780,9 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t spin_lock_irq(&usblp->lock); usblp->wcomplete = 0; spin_unlock_irq(&usblp->lock); - if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { + + rv = usb_submit_urb(writeurb, GFP_KERNEL); + if (rv < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); usblp->no_paper = 0; @@ -822,22 +858,29 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo if (rv < 0) return rv; - if ((avail = usblp->rstatus) < 0) { + if (!usblp->present) { + count = -ENODEV; + goto done; + } + + avail = usblp->rstatus; + if (avail < 0) { printk(KERN_ERR "usblp%d: error %d reading from printer\n", - usblp->minor, (int)avail); + usblp->minor, (int)avail); usblp_submit_read(usblp); count = -EIO; goto done; } - count = len < avail - usblp->readcount ? len : avail - usblp->readcount; + count = min_t(ssize_t, len, avail - usblp->readcount); if (count != 0 && copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) { count = -EFAULT; goto done; } - if ((usblp->readcount += count) == avail) { + usblp->readcount += count; + if (usblp->readcount == avail) { if (usblp_submit_read(usblp) < 0) { /* We don't want to leak USB return codes into errno. */ if (count == 0) @@ -870,11 +913,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock) add_wait_queue(&usblp->wwait, &waita); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } + set_current_state(TASK_INTERRUPTIBLE); rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); if (rc <= 0) @@ -938,7 +981,8 @@ static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock) break; } set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_rtest(usblp, nonblock)) < 0) { + rc = usblp_rtest(usblp, nonblock); + if (rc < 0) { mutex_unlock(&usblp->mut); break; } @@ -981,7 +1025,8 @@ static int usblp_submit_read(struct usblp *usblp) int rc; rc = -ENOMEM; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) goto raise_urb; usb_fill_bulk_urb(urb, usblp->dev, @@ -995,7 +1040,8 @@ static int usblp_submit_read(struct usblp *usblp) usblp->readcount = 0; /* XXX Why here? */ usblp->rcomplete = 0; spin_unlock_irqrestore(&usblp->lock, flags); - if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { + rc = usb_submit_urb(urb, GFP_KERNEL); + if (rc < 0) { dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc); spin_lock_irqsave(&usblp->lock, flags); usblp->rstatus = rc; @@ -1054,7 +1100,7 @@ static const struct file_operations usblp_fops = { .llseek = noop_llseek, }; -static char *usblp_devnode(struct device *dev, umode_t *mode) +static char *usblp_devnode(const struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); } @@ -1066,7 +1112,7 @@ static struct usb_class_driver usblp_class = { .minor_base = USBLP_MINOR_BASE, }; -static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t ieee1284_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); struct usblp *usblp = usb_get_intfdata(intf); @@ -1078,7 +1124,13 @@ static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribut return sprintf(buf, "%s", usblp->device_id_string+2); } -static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL); +static DEVICE_ATTR_RO(ieee1284_id); + +static struct attribute *usblp_attrs[] = { + &dev_attr_ieee1284_id.attr, + NULL, +}; +ATTRIBUTE_GROUPS(usblp); static int usblp_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1103,12 +1155,13 @@ static int usblp_probe(struct usb_interface *intf, init_waitqueue_head(&usblp->wwait); init_usb_anchor(&usblp->urbs); usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usblp->intf = intf; + usblp->intf = usb_get_intf(intf); /* Malloc device ID string buffer to the largest expected length, * since we can re-query it on an ioctl and a dynamic string * could change in length. */ - if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { + usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL); + if (!usblp->device_id_string) { retval = -ENOMEM; goto abort; } @@ -1118,7 +1171,8 @@ static int usblp_probe(struct usb_interface *intf, * malloc both regardless of bidirectionality, because the * alternate setting can be changed later via an ioctl. */ - if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) { + usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL); + if (!usblp->readbuf) { retval = -ENOMEM; goto abort; } @@ -1154,9 +1208,6 @@ static int usblp_probe(struct usb_interface *intf, /* Retrieve and store the device ID string. */ usblp_cache_device_id_string(usblp); - retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id); - if (retval) - goto abort_intfdata; #ifdef DEBUG usblp_check_status(usblp, 0); @@ -1187,11 +1238,11 @@ static int usblp_probe(struct usb_interface *intf, abort_intfdata: usb_set_intfdata(intf, NULL); - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); abort: kfree(usblp->readbuf); kfree(usblp->statusbuf); kfree(usblp->device_id_string); + usb_put_intf(usblp->intf); kfree(usblp); abort_ret: return retval; @@ -1202,26 +1253,31 @@ abort_ret: * but our requirements are too intricate for simple match to handle. * * The "proto_bias" option may be used to specify the preferred protocol - * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device - * supports the preferred protocol, then we bind to it. + * for all USB printers (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3). If the device supports the preferred protocol, + * then we bind to it. * - * The best interface for us is 7/1/2, because it is compatible - * with a stream of characters. If we find it, we bind to it. + * The best interface for us is USB_CLASS_PRINTER/1/2, because it + * is compatible with a stream of characters. If we find it, we bind to it. * * Note that the people from hpoj.sourceforge.net need to be able to - * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. + * bind to USB_CLASS_PRINTER/1/3 (MLC/1284.4), so we provide them ioctls + * for this purpose. * - * Failing 7/1/2, we look for 7/1/3, even though it's probably not - * stream-compatible, because this matches the behaviour of the old code. + * Failing USB_CLASS_PRINTER/1/2, we look for USB_CLASS_PRINTER/1/3, + * even though it's probably not stream-compatible, because this matches + * the behaviour of the old code. * - * If nothing else, we bind to 7/1/1 - the unidirectional interface. + * If nothing else, we bind to USB_CLASS_PRINTER/1/1 + * - the unidirectional interface. */ static int usblp_select_alts(struct usblp *usblp) { struct usb_interface *if_alt; struct usb_host_interface *ifd; - struct usb_endpoint_descriptor *epd, *epwrite, *epread; - int p, i, e; + struct usb_endpoint_descriptor *epwrite, *epread; + int p, i; + int res; if_alt = usblp->intf; @@ -1232,7 +1288,8 @@ static int usblp_select_alts(struct usblp *usblp) for (i = 0; i < if_alt->num_altsetting; i++) { ifd = &if_alt->altsetting[i]; - if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) + if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER || + ifd->desc.bInterfaceSubClass != 1) if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) continue; @@ -1240,29 +1297,21 @@ static int usblp_select_alts(struct usblp *usblp) ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) continue; - /* Look for bulk OUT and IN endpoints. */ - epwrite = epread = NULL; - for (e = 0; e < ifd->desc.bNumEndpoints; e++) { - epd = &ifd->endpoint[e].desc; - - if (usb_endpoint_is_bulk_out(epd)) - if (!epwrite) - epwrite = epd; - - if (usb_endpoint_is_bulk_in(epd)) - if (!epread) - epread = epd; + /* Look for the expected bulk endpoints. */ + if (ifd->desc.bInterfaceProtocol > 1) { + res = usb_find_common_endpoints(ifd, + &epread, &epwrite, NULL, NULL); + } else { + epread = NULL; + res = usb_find_bulk_out_endpoint(ifd, &epwrite); } /* Ignore buggy hardware without the right endpoints. */ - if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) + if (res) continue; - /* Turn off reads for 7/1/1 (unidirectional) interfaces - * and buggy bidirectional printers. */ - if (ifd->desc.bInterfaceProtocol == 1) { - epread = NULL; - } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { + /* Turn off reads for buggy bidirectional printers. */ + if (usblp->quirks & USBLP_QUIRK_BIDIR) { printk(KERN_INFO "usblp%d: Disabling reads from " "problematic bidirectional printer\n", usblp->minor); @@ -1303,11 +1352,15 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) alts = usblp->protocol[protocol].alt_setting; if (alts < 0) return -EINVAL; - r = usb_set_interface(usblp->dev, usblp->ifnum, alts); - if (r < 0) { - printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", - alts, usblp->ifnum); - return r; + + /* Don't unnecessarily set the interface if there's a single alt. */ + if (usblp->intf->num_altsetting > 1) { + r = usb_set_interface(usblp->dev, usblp->ifnum, alts); + if (r < 0) { + printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", + alts, usblp->ifnum); + return r; + } } usblp->bidir = (usblp->protocol[protocol].epread != NULL); @@ -1360,8 +1413,6 @@ static void usblp_disconnect(struct usb_interface *intf) BUG(); } - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); - mutex_lock(&usblp_mutex); mutex_lock(&usblp->mut); usblp->present = 0; @@ -1371,9 +1422,11 @@ static void usblp_disconnect(struct usb_interface *intf) usblp_unlink_urbs(usblp); mutex_unlock(&usblp->mut); + usb_poison_anchored_urbs(&usblp->urbs); if (!usblp->used) usblp_cleanup(usblp); + mutex_unlock(&usblp_mutex); } @@ -1402,12 +1455,12 @@ static int usblp_resume(struct usb_interface *intf) } static const struct usb_device_id usblp_ids[] = { - { USB_DEVICE_INFO(7, 1, 1) }, - { USB_DEVICE_INFO(7, 1, 2) }, - { USB_DEVICE_INFO(7, 1, 3) }, - { USB_INTERFACE_INFO(7, 1, 1) }, - { USB_INTERFACE_INFO(7, 1, 2) }, - { USB_INTERFACE_INFO(7, 1, 3) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) }, { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ { } /* Terminating entry */ }; @@ -1421,6 +1474,7 @@ static struct usb_driver usblp_driver = { .suspend = usblp_suspend, .resume = usblp_resume, .id_table = usblp_ids, + .dev_groups = usblp_groups, .supports_autosuspend = 1, }; |
