diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 06:33:03 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 09:44:55 -0300 |
commit | 64131a87f2aae2ed9e05d8227c5b009ca6c50d98 (patch) | |
tree | fdea23fd59216120bf54a48c60ca24489a733f14 /drivers/usb/gadget | |
parent | 676ee36be04985062522804c2de04f0764212be6 (diff) | |
parent | 2c33ce009ca2389dbf0535d0672214d09738e35e (diff) | |
download | blackbird-op-linux-64131a87f2aae2ed9e05d8227c5b009ca6c50d98.tar.gz blackbird-op-linux-64131a87f2aae2ed9e05d8227c5b009ca6c50d98.zip |
Merge branch 'drm-next-merged' of git://people.freedesktop.org/~airlied/linux into v4l_for_linus
* 'drm-next-merged' of git://people.freedesktop.org/~airlied/linux: (9717 commits)
media-bus: Fixup RGB444_1X12, RGB565_1X16, and YUV8_1X24 media bus format
hexdump: avoid warning in test function
fs: take i_mutex during prepare_binprm for set[ug]id executables
smp: Fix error case handling in smp_call_function_*()
iommu-common: Fix PARISC compile-time warnings
sparc: Make LDC use common iommu poll management functions
sparc: Make sparc64 use scalable lib/iommu-common.c functions
Break up monolithic iommu table/lock into finer graularity pools and lock
sparc: Revert generic IOMMU allocator.
tools/power turbostat: correct dumped pkg-cstate-limit value
tools/power turbostat: calculate TSC frequency from CPUID(0x15) on SKL
tools/power turbostat: correct DRAM RAPL units on recent Xeon processors
tools/power turbostat: Initial Skylake support
tools/power turbostat: Use $(CURDIR) instead of $(PWD) and add support for O= option in Makefile
tools/power turbostat: modprobe msr, if needed
tools/power turbostat: dump MSR_TURBO_RATIO_LIMIT2
tools/power turbostat: use new MSR_TURBO_RATIO_LIMIT names
Bluetooth: hidp: Fix regression with older userspace and flags validation
config: Enable NEED_DMA_MAP_STATE by default when SWIOTLB is selected
perf/x86/intel/pt: Fix and clean up error handling in pt_event_add()
...
That solves several merge conflicts:
Documentation/DocBook/media/v4l/subdev-formats.xml
Documentation/devicetree/bindings/vendor-prefixes.txt
drivers/staging/media/mn88473/mn88473.c
include/linux/kconfig.h
include/uapi/linux/media-bus-format.h
The ones at subdev-formats.xml and media-bus-format.h are not trivial.
That's why we opted to merge from DRM.
Diffstat (limited to 'drivers/usb/gadget')
32 files changed, 2490 insertions, 2566 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b454d05be583..bcf83c0a6e62 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -196,6 +196,9 @@ config USB_F_MIDI config USB_F_HID tristate +config USB_F_PRINTER + tristate + choice tristate "USB Gadget Drivers" default USB_ETH @@ -434,6 +437,20 @@ config USB_CONFIGFS_F_UVC device. It provides a userspace API to process UVC control requests and stream video data to the host. +config USB_CONFIGFS_F_PRINTER + bool "Printer function" + select USB_F_PRINTER + depends on USB_CONFIGFS + help + The Printer function channels data between the USB host and a + userspace program driving the print engine. The user space + program reads and writes the device file /dev/g_printer<X> to + receive or send printer data. It can use ioctl calls to + the device file to get or set printer status. + + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 13adfd1a3f54..4e3447bbd097 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1161,11 +1161,11 @@ static struct usb_gadget_string_container *copy_gadget_strings( * This function will create a deep copy of usb_gadget_strings and usb_string * and attach it to the cdev. The actual string (usb_string.s) will not be * copied but only a referenced will be made. The struct usb_gadget_strings - * array may contain multiple languges and should be NULL terminated. + * array may contain multiple languages and should be NULL terminated. * The ->language pointer of each struct usb_gadget_strings has to contain the * same amount of entries. * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first - * usb_string entry of es-ES containts the translation of the first usb_string + * usb_string entry of es-ES contains the translation of the first usb_string * entry of en-US. Therefore both entries become the same id assign. */ struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, @@ -1472,6 +1472,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) req->length = 0; gadget->ep0->driver_data = cdev; + /* + * Don't let non-standard requests match any of the cases below + * by accident. + */ + if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) + goto unknown; + switch (ctrl->bRequest) { /* we handle all standard USB descriptors */ @@ -1751,6 +1758,10 @@ unknown: * take such requests too, if that's ever needed: to work * in config 0, etc. */ + list_for_each_entry(f, &cdev->config->functions, list) + if (f->req_match && f->req_match(f, ctrl)) + goto try_fun_setup; + f = NULL; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) @@ -1768,7 +1779,7 @@ unknown: f = NULL; break; } - +try_fun_setup: if (f && f->setup) value = f->setup(f, ctrl); else { diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 75648145dc1b..c42765b3a060 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1161,7 +1161,6 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, if (desc->opts_mutex) mutex_lock(desc->opts_mutex); memcpy(desc->ext_compat_id, page, l); - desc->ext_compat_id[l] = '\0'; if (desc->opts_mutex) mutex_unlock(desc->opts_mutex); @@ -1192,7 +1191,6 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, if (desc->opts_mutex) mutex_lock(desc->opts_mutex); memcpy(desc->ext_compat_id + 8, page, l); - desc->ext_compat_id[l + 8] = '\0'; if (desc->opts_mutex) mutex_unlock(desc->opts_mutex); diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index f71b1aaa0edf..bd7def576955 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -42,3 +42,5 @@ usb_f_midi-y := f_midi.o obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o usb_f_hid-y := f_hid.o obj-$(CONFIG_USB_F_HID) += usb_f_hid.o +usb_f_printer-y := f_printer.o +obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index af98b096af2f..6bdb57069044 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -23,6 +23,7 @@ #include <linux/export.h> #include <linux/hid.h> #include <linux/module.h> +#include <linux/uio.h> #include <asm/unaligned.h> #include <linux/usb/composite.h> @@ -144,10 +145,9 @@ struct ffs_io_data { bool read; struct kiocb *kiocb; - const struct iovec *iovec; - unsigned long nr_segs; - char __user *buf; - size_t len; + struct iov_iter data; + const void *to_free; + char *buf; struct mm_struct *mm; struct work_struct work; @@ -649,42 +649,24 @@ static void ffs_user_copy_worker(struct work_struct *work) io_data->req->actual; if (io_data->read && ret > 0) { - int i; - size_t pos = 0; - - /* - * Since req->length may be bigger than io_data->len (after - * being rounded up to maxpacketsize), we may end up with more - * data then user space has space for. - */ - ret = min_t(int, ret, io_data->len); - use_mm(io_data->mm); - for (i = 0; i < io_data->nr_segs; i++) { - size_t len = min_t(size_t, ret - pos, - io_data->iovec[i].iov_len); - if (!len) - break; - if (unlikely(copy_to_user(io_data->iovec[i].iov_base, - &io_data->buf[pos], len))) { - ret = -EFAULT; - break; - } - pos += len; - } + ret = copy_to_iter(io_data->buf, ret, &io_data->data); + if (iov_iter_count(&io_data->data)) + ret = -EFAULT; unuse_mm(io_data->mm); } - aio_complete(io_data->kiocb, ret, ret); + io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); - if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd) + if (io_data->ffs->ffs_eventfd && + !(io_data->kiocb->ki_flags & IOCB_EVENTFD)) eventfd_signal(io_data->ffs->ffs_eventfd, 1); usb_ep_free_request(io_data->ep, io_data->req); io_data->kiocb->private = NULL; if (io_data->read) - kfree(io_data->iovec); + kfree(io_data->to_free); kfree(io_data->buf); kfree(io_data); } @@ -743,6 +725,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * before the waiting completes, so do not assign to 'gadget' earlier */ struct usb_gadget *gadget = epfile->ffs->gadget; + size_t copied; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -750,34 +733,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); return -ESHUTDOWN; } + data_len = iov_iter_count(&io_data->data); /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. */ - data_len = io_data->read ? - usb_ep_align_maybe(gadget, ep->ep, io_data->len) : - io_data->len; + if (io_data->read) + data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) return -ENOMEM; - if (io_data->aio && !io_data->read) { - int i; - size_t pos = 0; - for (i = 0; i < io_data->nr_segs; i++) { - if (unlikely(copy_from_user(&data[pos], - io_data->iovec[i].iov_base, - io_data->iovec[i].iov_len))) { - ret = -EFAULT; - goto error; - } - pos += io_data->iovec[i].iov_len; - } - } else { - if (!io_data->read && - unlikely(__copy_from_user(data, io_data->buf, - io_data->len))) { + if (!io_data->read) { + copied = copy_from_iter(data, data_len, &io_data->data); + if (copied != data_len) { ret = -EFAULT; goto error; } @@ -876,10 +846,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ ret = ep->status; if (io_data->read && ret > 0) { - ret = min_t(size_t, ret, io_data->len); - - if (unlikely(copy_to_user(io_data->buf, - data, ret))) + ret = copy_to_iter(data, ret, &io_data->data); + if (unlikely(iov_iter_count(&io_data->data))) ret = -EFAULT; } } @@ -898,37 +866,6 @@ error: return ret; } -static ssize_t -ffs_epfile_write(struct file *file, const char __user *buf, size_t len, - loff_t *ptr) -{ - struct ffs_io_data io_data; - - ENTER(); - - io_data.aio = false; - io_data.read = false; - io_data.buf = (char * __user)buf; - io_data.len = len; - - return ffs_epfile_io(file, &io_data); -} - -static ssize_t -ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) -{ - struct ffs_io_data io_data; - - ENTER(); - - io_data.aio = false; - io_data.read = true; - io_data.buf = buf; - io_data.len = len; - - return ffs_epfile_io(file, &io_data); -} - static int ffs_epfile_open(struct inode *inode, struct file *file) { @@ -965,67 +902,86 @@ static int ffs_aio_cancel(struct kiocb *kiocb) return value; } -static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, - const struct iovec *iovec, - unsigned long nr_segs, loff_t loff) +static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) { - struct ffs_io_data *io_data; + struct ffs_io_data io_data, *p = &io_data; + ssize_t res; ENTER(); - io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); - if (unlikely(!io_data)) - return -ENOMEM; + if (!is_sync_kiocb(kiocb)) { + p = kmalloc(sizeof(io_data), GFP_KERNEL); + if (unlikely(!p)) + return -ENOMEM; + p->aio = true; + } else { + p->aio = false; + } - io_data->aio = true; - io_data->read = false; - io_data->kiocb = kiocb; - io_data->iovec = iovec; - io_data->nr_segs = nr_segs; - io_data->len = kiocb->ki_nbytes; - io_data->mm = current->mm; + p->read = false; + p->kiocb = kiocb; + p->data = *from; + p->mm = current->mm; - kiocb->private = io_data; + kiocb->private = p; kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - return ffs_epfile_io(kiocb->ki_filp, io_data); + res = ffs_epfile_io(kiocb->ki_filp, p); + if (res == -EIOCBQUEUED) + return res; + if (p->aio) + kfree(p); + else + *from = p->data; + return res; } -static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, - const struct iovec *iovec, - unsigned long nr_segs, loff_t loff) +static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) { - struct ffs_io_data *io_data; - struct iovec *iovec_copy; + struct ffs_io_data io_data, *p = &io_data; + ssize_t res; ENTER(); - iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); - if (unlikely(!iovec_copy)) - return -ENOMEM; - - memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); - - io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); - if (unlikely(!io_data)) { - kfree(iovec_copy); - return -ENOMEM; + if (!is_sync_kiocb(kiocb)) { + p = kmalloc(sizeof(io_data), GFP_KERNEL); + if (unlikely(!p)) + return -ENOMEM; + p->aio = true; + } else { + p->aio = false; } - io_data->aio = true; - io_data->read = true; - io_data->kiocb = kiocb; - io_data->iovec = iovec_copy; - io_data->nr_segs = nr_segs; - io_data->len = kiocb->ki_nbytes; - io_data->mm = current->mm; + p->read = true; + p->kiocb = kiocb; + if (p->aio) { + p->to_free = dup_iter(&p->data, to, GFP_KERNEL); + if (!p->to_free) { + kfree(p); + return -ENOMEM; + } + } else { + p->data = *to; + p->to_free = NULL; + } + p->mm = current->mm; - kiocb->private = io_data; + kiocb->private = p; kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - return ffs_epfile_io(kiocb->ki_filp, io_data); + res = ffs_epfile_io(kiocb->ki_filp, p); + if (res == -EIOCBQUEUED) + return res; + + if (p->aio) { + kfree(p->to_free); + kfree(p); + } else { + *to = p->data; + } + return res; } static int @@ -1105,10 +1061,8 @@ static const struct file_operations ffs_epfile_operations = { .llseek = no_llseek, .open = ffs_epfile_open, - .write = ffs_epfile_write, - .read = ffs_epfile_read, - .aio_write = ffs_epfile_aio_write, - .aio_read = ffs_epfile_aio_read, + .write_iter = ffs_epfile_write_iter, + .read_iter = ffs_epfile_read_iter, .release = ffs_epfile_release, .unlocked_ioctl = ffs_epfile_ioctl, }; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 426d69a9c018..13dfc9915b1d 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -569,7 +569,7 @@ fail: return status; } -const struct file_operations f_hidg_fops = { +static const struct file_operations f_hidg_fops = { .owner = THIS_MODULE, .open = f_hidg_open, .release = f_hidg_release, @@ -908,7 +908,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) /* disable/free request and end point */ usb_ep_disable(hidg->in_ep); - usb_ep_dequeue(hidg->in_ep, hidg->req); kfree(hidg->req->buf); usb_ep_free_request(hidg->in_ep, hidg->req); diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 298b46112b1a..39f49f1ad22f 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -289,8 +289,7 @@ static void disable_loopback(struct f_loopback *loop) struct usb_composite_dev *cdev; cdev = loop->function.config->cdev; - disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL, NULL, - NULL); + disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL); VDBG(cdev, "%s disabled\n", loop->function.name); } diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 811929cd4c9e..3cc109f3c9c8 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -1085,7 +1085,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) if (!curlun) { /* Unsupported LUNs are okay */ common->bad_lun_okay = 1; memset(buf, 0, 36); - buf[0] = 0x7f; /* Unsupported, no device-type */ + buf[0] = TYPE_NO_LUN; /* Unsupported, no device-type */ buf[4] = 31; /* Additional length */ return 36; } @@ -2624,13 +2624,10 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr, return fsg_store_file(curlun, filesem, buf, count); } -static DEVICE_ATTR_RW(ro); static DEVICE_ATTR_RW(nofua); -static DEVICE_ATTR_RW(file); - -static struct device_attribute dev_attr_ro_cdrom = __ATTR_RO(ro); -static struct device_attribute dev_attr_file_nonremovable = __ATTR_RO(file); - +/* mode wil be set in fsg_lun_attr_is_visible() */ +static DEVICE_ATTR(ro, 0, ro_show, ro_store); +static DEVICE_ATTR(file, 0, file_show, file_store); /****************************** FSG COMMON ******************************/ @@ -2745,40 +2742,10 @@ error_release: } EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); -static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) -{ - device_remove_file(&lun->dev, &dev_attr_nofua); - /* - * device_remove_file() => - * - * here the attr (e.g. dev_attr_ro) is only used to be passed to: - * - * sysfs_remove_file() => - * - * here e.g. both dev_attr_ro_cdrom and dev_attr_ro are in - * the same namespace and - * from here only attr->name is passed to: - * - * sysfs_hash_and_remove() - * - * attr->name is the same for dev_attr_ro_cdrom and - * dev_attr_ro - * attr->name is the same for dev_attr_file and - * dev_attr_file_nonremovable - * - * so we don't differentiate between removing e.g. dev_attr_ro_cdrom - * and dev_attr_ro - */ - device_remove_file(&lun->dev, &dev_attr_ro); - device_remove_file(&lun->dev, &dev_attr_file); -} - void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) { - if (sysfs) { - fsg_common_remove_sysfs(lun); + if (sysfs) device_unregister(&lun->dev); - } fsg_lun_close(lun); kfree(lun); } @@ -2877,41 +2844,35 @@ int fsg_common_set_cdev(struct fsg_common *common, } EXPORT_SYMBOL_GPL(fsg_common_set_cdev); -static inline int fsg_common_add_sysfs(struct fsg_common *common, - struct fsg_lun *lun) -{ - int rc; +static struct attribute *fsg_lun_dev_attrs[] = { + &dev_attr_ro.attr, + &dev_attr_file.attr, + &dev_attr_nofua.attr, + NULL +}; - rc = device_register(&lun->dev); - if (rc) { - put_device(&lun->dev); - return rc; - } +static umode_t fsg_lun_dev_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct fsg_lun *lun = fsg_lun_from_dev(dev); - rc = device_create_file(&lun->dev, - lun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); - if (rc) - goto error; - rc = device_create_file(&lun->dev, - lun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); - if (rc) - goto error; - rc = device_create_file(&lun->dev, &dev_attr_nofua); - if (rc) - goto error; + if (attr == &dev_attr_ro.attr) + return lun->cdrom ? S_IRUGO : (S_IWUSR | S_IRUGO); + if (attr == &dev_attr_file.attr) + return lun->removable ? (S_IWUSR | S_IRUGO) : S_IRUGO; + return attr->mode; +} - return 0; +static const struct attribute_group fsg_lun_dev_group = { + .attrs = fsg_lun_dev_attrs, + .is_visible = fsg_lun_dev_is_visible, +}; -error: - /* removing nonexistent files is a no-op */ - fsg_common_remove_sysfs(lun); - device_unregister(&lun->dev); - return rc; -} +static const struct attribute_group *fsg_lun_dev_groups[] = { + &fsg_lun_dev_group, + NULL +}; int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, unsigned int id, const char *name, @@ -2949,13 +2910,15 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, } else { lun->dev.release = fsg_lun_release; lun->dev.parent = &common->gadget->dev; + lun->dev.groups = fsg_lun_dev_groups; dev_set_drvdata(&lun->dev, &common->filesem); dev_set_name(&lun->dev, "%s", name); lun->name = dev_name(&lun->dev); - rc = fsg_common_add_sysfs(common, lun); + rc = device_register(&lun->dev); if (rc) { pr_info("failed to register LUN%d: %d\n", id, rc); + put_device(&lun->dev); goto error_sysfs; } } @@ -2988,10 +2951,8 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, return 0; error_lun: - if (common->sysfs) { - fsg_common_remove_sysfs(lun); + if (common->sysfs) device_unregister(&lun->dev); - } fsg_lun_close(lun); common->luns[id] = NULL; error_sysfs: @@ -3077,8 +3038,6 @@ static void fsg_common_release(struct kref *ref) struct fsg_lun *lun = *lun_it; if (!lun) continue; - if (common->sysfs) - fsg_common_remove_sysfs(lun); fsg_lun_close(lun); if (common->sysfs) device_unregister(&lun->dev); diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index c89e96cfa3e4..c0c3ef272714 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -417,7 +417,10 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) return -EINVAL; spin_lock(&port->lock); - __pn_reset(f); + + if (fp->in_ep->driver_data) + __pn_reset(f); + if (alt == 1) { int i; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c new file mode 100644 index 000000000000..44173df27273 --- /dev/null +++ b/drivers/usb/gadget/function/f_printer.c @@ -0,0 +1,1471 @@ +/* + * f_printer.c - USB printer function driver + * + * Copied from drivers/usb/gadget/legacy/printer.c, + * which was: + * + * printer.c -- Printer gadget driver + * + * Copyright (C) 2003-2005 David Brownell + * Copyright (C) 2006 Craig W. Nadler + * + * 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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/idr.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <linux/cdev.h> + +#include <asm/byteorder.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/uaccess.h> +#include <asm/unaligned.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/composite.h> +#include <linux/usb/gadget.h> +#include <linux/usb/g_printer.h> + +#include "u_printer.h" + +#define PNP_STRING_LEN 1024 +#define PRINTER_MINORS 4 +#define GET_DEVICE_ID 0 +#define GET_PORT_STATUS 1 +#define SOFT_RESET 2 + +static int major, minors; +static struct class *usb_gadget_class; +static DEFINE_IDA(printer_ida); +static DEFINE_MUTEX(printer_ida_lock); /* protects access do printer_ida */ + +/*-------------------------------------------------------------------------*/ + +struct printer_dev { + spinlock_t lock; /* lock this structure */ + /* lock buffer lists during read/write calls */ + struct mutex lock_printer_io; + struct usb_gadget *gadget; + s8 interface; + struct usb_ep *in_ep, *out_ep; + + struct list_head rx_reqs; /* List of free RX structs */ + struct list_head rx_reqs_active; /* List of Active RX xfers */ + struct list_head rx_buffers; /* List of completed xfers */ + /* wait until there is data to be read. */ + wait_queue_head_t rx_wait; + struct list_head tx_reqs; /* List of free TX structs */ + struct list_head tx_reqs_active; /* List of Active TX xfers */ + /* Wait until there are write buffers available to use. */ + wait_queue_head_t tx_wait; + /* Wait until all write buffers have been sent. */ + wait_queue_head_t tx_flush_wait; + struct usb_request *current_rx_req; + size_t current_rx_bytes; + u8 *current_rx_buf; + u8 printer_status; + u8 reset_printer; + int minor; + struct cdev printer_cdev; + u8 printer_cdev_open; + wait_queue_head_t wait; + unsigned q_len; + char *pnp_string; /* We don't own memory! */ + struct usb_function function; +}; + +static inline struct printer_dev *func_to_printer(struct usb_function *f) +{ + return container_of(f, struct printer_dev, function); +} + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. + */ + +/* holds our biggest descriptor */ +#define USB_DESC_BUFSIZE 256 +#define USB_BUFSIZE 8192 + +static struct usb_interface_descriptor intf_desc = { + .bLength = sizeof(intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_PRINTER, + .bInterfaceSubClass = 1, /* Printer Sub-Class */ + .bInterfaceProtocol = 2, /* Bi-Directional */ + .iInterface = 0 +}; + +static struct usb_endpoint_descriptor fs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static struct usb_endpoint_descriptor fs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static struct usb_descriptor_header *fs_printer_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_ep_in_desc, + (struct usb_descriptor_header *) &fs_ep_out_desc, + NULL +}; + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + */ + +static struct usb_endpoint_descriptor hs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512) +}; + +static struct usb_endpoint_descriptor hs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512) +}; + +static struct usb_qualifier_descriptor dev_qualifier = { + .bLength = sizeof(dev_qualifier), + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PRINTER, + .bNumConfigurations = 1 +}; + +static struct usb_descriptor_header *hs_printer_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_ep_in_desc, + (struct usb_descriptor_header *) &hs_ep_out_desc, + NULL +}; + +/* + * Added endpoint descriptors for 3.0 devices + */ + +static struct usb_endpoint_descriptor ss_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = { + .bLength = sizeof(ss_ep_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_endpoint_descriptor ss_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { + .bLength = sizeof(ss_ep_out_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *ss_printer_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &ss_ep_in_desc, + (struct usb_descriptor_header *) &ss_ep_in_comp_desc, + (struct usb_descriptor_header *) &ss_ep_out_desc, + (struct usb_descriptor_header *) &ss_ep_out_comp_desc, + NULL +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *ss) +{ + switch (gadget->speed) { + case USB_SPEED_SUPER: + return ss; + case USB_SPEED_HIGH: + return hs; + default: + return fs; + } +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, gfp_flags); + + if (req != NULL) { + req->length = len; + req->buf = kmalloc(len, gfp_flags); + if (req->buf == NULL) { + usb_ep_free_request(ep, req); + return NULL; + } + } + + return req; +} + +static void +printer_req_free(struct usb_ep *ep, struct usb_request *req) +{ + if (ep != NULL && req != NULL) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + int status = req->status; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + list_del_init(&req->list); /* Remode from Active List */ + + switch (status) { + + /* normal completion */ + case 0: + if (req->actual > 0) { + list_add_tail(&req->list, &dev->rx_buffers); + DBG(dev, "G_Printer : rx length %d\n", req->actual); + } else { + list_add(&req->list, &dev->rx_reqs); + } + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + VDBG(dev, "rx shutdown, code %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + + /* for hardware automagic (such as pxa) */ + case -ECONNABORTED: /* endpoint reset */ + DBG(dev, "rx %s reset\n", ep->name); + list_add(&req->list, &dev->rx_reqs); + break; + + /* data overrun */ + case -EOVERFLOW: + /* FALLTHROUGH */ + + default: + DBG(dev, "rx status %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + } + + wake_up_interruptible(&dev->rx_wait); + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + + switch (req->status) { + default: + VDBG(dev, "tx err %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + break; + case 0: + break; + } + + spin_lock(&dev->lock); + /* Take the request struct off the active list and put it on the + * free list. + */ + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + wake_up_interruptible(&dev->tx_wait); + if (likely(list_empty(&dev->tx_reqs_active))) + wake_up_interruptible(&dev->tx_flush_wait); + + spin_unlock(&dev->lock); +} + +/*-------------------------------------------------------------------------*/ + +static int +printer_open(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev; + unsigned long flags; + int ret = -EBUSY; + + dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); + + spin_lock_irqsave(&dev->lock, flags); + + if (!dev->printer_cdev_open) { + dev->printer_cdev_open = 1; + fd->private_data = dev; + ret = 0; + /* Change the printer status to show that it's on-line. */ + dev->printer_status |= PRINTER_SELECTED; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_open returned %x\n", ret); + return ret; +} + +static int +printer_close(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + dev->printer_cdev_open = 0; + fd->private_data = NULL; + /* Change printer status to show that the printer is off-line. */ + dev->printer_status &= ~PRINTER_SELECTED; + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_close\n"); + + return 0; +} + +/* This function must be called with interrupts turned off. */ +static void +setup_rx_reqs(struct printer_dev *dev) +{ + struct usb_request *req; + + while (likely(!list_empty(&dev->rx_reqs))) { + int error; + + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del_init(&req->list); + + /* The USB Host sends us whatever amount of data it wants to + * so we always set the length field to the full USB_BUFSIZE. + * If the amount of data is more than the read() caller asked + * for it will be stored in the request buffer until it is + * asked for by read(). + */ + req->length = USB_BUFSIZE; + req->complete = rx_complete; + + /* here, we unlock, and only unlock, to avoid deadlock. */ + spin_unlock(&dev->lock); + error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); + spin_lock(&dev->lock); + if (error) { + DBG(dev, "rx submit --> %d\n", error); + list_add(&req->list, &dev->rx_reqs); + break; + } + /* if the req is empty, then add it into dev->rx_reqs_active. */ + else if (list_empty(&req->list)) + list_add(&req->list, &dev->rx_reqs_active); + } +} + +static ssize_t +printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; + size_t bytes_copied; + struct usb_request *req; + /* This is a pointer to the current USB rx request. */ + struct usb_request *current_rx_req; + /* This is the number of bytes in the current rx buffer. */ + size_t current_rx_bytes; + /* This is a pointer to the current rx buffer. */ + u8 *current_rx_buf; + + if (len == 0) + return -EINVAL; + + DBG(dev, "printer_read trying to read %d bytes\n", (int)len); + + mutex_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* We will use this flag later to check if a printer reset happened + * after we turn interrupts back on. + */ + dev->reset_printer = 0; + + setup_rx_reqs(dev); + + bytes_copied = 0; + current_rx_req = dev->current_rx_req; + current_rx_bytes = dev->current_rx_bytes; + current_rx_buf = dev->current_rx_buf; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + /* Check if there is any data in the read buffers. Please note that + * current_rx_bytes is the number of bytes in the current rx buffer. + * If it is zero then check if there are any other rx_buffers that + * are on the completed list. We are only out of data if all rx + * buffers are empty. + */ + if ((current_rx_bytes == 0) && + (likely(list_empty(&dev->rx_buffers)))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If no data is available check if this is a NON-Blocking + * call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until data is available */ + wait_event_interruptible(dev->rx_wait, + (likely(!list_empty(&dev->rx_buffers)))); + spin_lock_irqsave(&dev->lock, flags); + } + + /* We have data to return then copy it to the caller's buffer.*/ + while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) + && len) { + if (current_rx_bytes == 0) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del_init(&req->list); + + if (req->actual && req->buf) { + current_rx_req = req; + current_rx_bytes = req->actual; + current_rx_buf = req->buf; + } else { + list_add(&req->list, &dev->rx_reqs); + continue; + } + } + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (len > current_rx_bytes) + size = current_rx_bytes; + else + size = len; + + size -= copy_to_user(buf, current_rx_buf, size); + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset so return. */ + if (dev->reset_printer) { + list_add(¤t_rx_req->list, &dev->rx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* If we not returning all the data left in this RX request + * buffer then adjust the amount of data left in the buffer. + * Othewise if we are done with this RX request buffer then + * requeue it to get any incoming data from the USB host. + */ + if (size < current_rx_bytes) { + current_rx_bytes -= size; + current_rx_buf += size; + } else { + list_add(¤t_rx_req->list, &dev->rx_reqs); + current_rx_bytes = 0; + current_rx_buf = NULL; + current_rx_req = NULL; + } + } + + dev->current_rx_req = current_rx_req; + dev->current_rx_bytes = current_rx_bytes; + dev->current_rx_buf = current_rx_buf; + + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); + + if (bytes_copied) + return bytes_copied; + else + return -EAGAIN; +} + +static ssize_t +printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; /* Amount of data in a TX request. */ + size_t bytes_copied = 0; + struct usb_request *req; + + DBG(dev, "printer_write trying to send %d bytes\n", (int)len); + + if (len == 0) + return -EINVAL; + + mutex_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* Check if a printer reset happens while we have interrupts on */ + dev->reset_printer = 0; + + /* Check if there is any available write buffers */ + if (likely(list_empty(&dev->tx_reqs))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If write buffers are available check if this is + * a NON-Blocking call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until a write buffer is available */ + wait_event_interruptible(dev->tx_wait, + (likely(!list_empty(&dev->tx_reqs)))); + spin_lock_irqsave(&dev->lock, flags); + } + + while (likely(!list_empty(&dev->tx_reqs)) && len) { + + if (len > USB_BUFSIZE) + size = USB_BUFSIZE; + else + size = len; + + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del_init(&req->list); + + req->complete = tx_complete; + req->length = size; + + /* Check if we need to send a zero length packet. */ + if (len > size) + /* They will be more TX requests so no yet. */ + req->zero = 0; + else + /* If the data amount is not a multiple of the + * maxpacket size then send a zero length packet. + */ + req->zero = ((len % dev->in_ep->maxpacket) == 0); + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (copy_from_user(req->buf, buf, size)) { + list_add(&req->list, &dev->tx_reqs); + mutex_unlock(&dev->lock_printer_io); + return bytes_copied; + } + + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset so free the req and buffer */ + if (dev->reset_printer) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + list_add(&req->list, &dev->tx_reqs_active); + + } + + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); + + if (bytes_copied) + return bytes_copied; + else + return -EAGAIN; +} + +static int +printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) +{ + struct printer_dev *dev = fd->private_data; + struct inode *inode = file_inode(fd); + unsigned long flags; + int tx_list_empty; + + mutex_lock(&inode->i_mutex); + spin_lock_irqsave(&dev->lock, flags); + tx_list_empty = (likely(list_empty(&dev->tx_reqs))); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!tx_list_empty) { + /* Sleep until all data has been sent */ + wait_event_interruptible(dev->tx_flush_wait, + (likely(list_empty(&dev->tx_reqs_active)))); + } + mutex_unlock(&inode->i_mutex); + + return 0; +} + +static unsigned int +printer_poll(struct file *fd, poll_table *wait) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + mutex_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + setup_rx_reqs(dev); + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + + poll_wait(fd, &dev->rx_wait, wait); + poll_wait(fd, &dev->tx_wait, wait); + + spin_lock_irqsave(&dev->lock, flags); + if (likely(!list_empty(&dev->tx_reqs))) + status |= POLLOUT | POLLWRNORM; + + if (likely(dev->current_rx_bytes) || + likely(!list_empty(&dev->rx_buffers))) + status |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +static long +printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); + + /* handle ioctls */ + + spin_lock_irqsave(&dev->lock, flags); + + switch (code) { + case GADGET_GET_PRINTER_STATUS: + status = (int)dev->printer_status; + break; + case GADGET_SET_PRINTER_STATUS: + dev->printer_status = (u8)arg; + break; + default: + /* could not handle ioctl */ + DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n", + code); + status = -ENOTTY; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +/* used after endpoint configuration */ +static const struct file_operations printer_io_operations = { + .owner = THIS_MODULE, + .open = printer_open, + .read = printer_read, + .write = printer_write, + .fsync = printer_fsync, + .poll = printer_poll, + .unlocked_ioctl = printer_ioctl, + .release = printer_close, + .llseek = noop_llseek, +}; + +/*-------------------------------------------------------------------------*/ + +static int +set_printer_interface(struct printer_dev *dev) +{ + int result = 0; + + dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc, + &ss_ep_in_desc); + dev->in_ep->driver_data = dev; + + dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc, + &hs_ep_out_desc, &ss_ep_out_desc); + dev->out_ep->driver_data = dev; + + result = usb_ep_enable(dev->in_ep); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + + result = usb_ep_enable(dev->out_ep); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + +done: + /* on error, disable any endpoints */ + if (result != 0) { + (void) usb_ep_disable(dev->in_ep); + (void) usb_ep_disable(dev->out_ep); + dev->in_ep->desc = NULL; + dev->out_ep->desc = NULL; + } + + /* caller is responsible for cleanup on error */ + return result; +} + +static void printer_reset_interface(struct printer_dev *dev) +{ + if (dev->interface < 0) + return; + + DBG(dev, "%s\n", __func__); + + if (dev->in_ep->desc) + usb_ep_disable(dev->in_ep); + + if (dev->out_ep->desc) + usb_ep_disable(dev->out_ep); + + dev->in_ep->desc = NULL; + dev->out_ep->desc = NULL; + dev->interface = -1; +} + +/* Change our operational Interface. */ +static int set_interface(struct printer_dev *dev, unsigned number) +{ + int result = 0; + + /* Free the current interface */ + printer_reset_interface(dev); + + result = set_printer_interface(dev); + if (result) + printer_reset_interface(dev); + else + dev->interface = number; + + if (!result) + INFO(dev, "Using interface %x\n", number); + + return result; +} + +static void printer_soft_reset(struct printer_dev *dev) +{ + struct usb_request *req; + + INFO(dev, "Received Printer Reset Request\n"); + + if (usb_ep_disable(dev->in_ep)) + DBG(dev, "Failed to disable USB in_ep\n"); + if (usb_ep_disable(dev->out_ep)) + DBG(dev, "Failed to disable USB out_ep\n"); + + if (dev->current_rx_req != NULL) { + list_add(&dev->current_rx_req->list, &dev->rx_reqs); + dev->current_rx_req = NULL; + } + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + dev->reset_printer = 1; + + while (likely(!(list_empty(&dev->rx_buffers)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->rx_reqs_active)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->tx_reqs_active)))) { + req = container_of(dev->tx_reqs_active.next, + struct usb_request, list); + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + } + + if (usb_ep_enable(dev->in_ep)) + DBG(dev, "Failed to enable USB in_ep\n"); + if (usb_ep_enable(dev->out_ep)) + DBG(dev, "Failed to enable USB out_ep\n"); + + wake_up_interruptible(&dev->rx_wait); + wake_up_interruptible(&dev->tx_wait); + wake_up_interruptible(&dev->tx_flush_wait); +} + +/*-------------------------------------------------------------------------*/ + +static bool gprinter_req_match(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct printer_dev *dev = func_to_printer(f); + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE || + (ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) + return false; + + switch (ctrl->bRequest) { + case GET_DEVICE_ID: + w_index >>= 8; + if (w_length <= PNP_STRING_LEN && + (USB_DIR_IN & ctrl->bRequestType)) + break; + return false; + case GET_PORT_STATUS: + if (!w_value && w_length == 1 && + (USB_DIR_IN & ctrl->bRequestType)) + break; + return false; + case SOFT_RESET: + if (!w_value && !w_length && + !(USB_DIR_IN & ctrl->bRequestType)) + break; + /* fall through */ + default: + return false; + } + return w_index == dev->interface; +} + +/* + * The setup() callback implements all the ep0 functionality that's not + * handled lower down. + */ +static int printer_func_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct printer_dev *dev = func_to_printer(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); + + DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); + + switch (ctrl->bRequestType&USB_TYPE_MASK) { + case USB_TYPE_CLASS: + switch (ctrl->bRequest) { + case GET_DEVICE_ID: /* Get the IEEE-1284 PNP String */ + /* Only one printer interface is supported. */ + if ((wIndex>>8) != dev->interface) + break; + + value = (dev->pnp_string[0] << 8) | dev->pnp_string[1]; + memcpy(req->buf, dev->pnp_string, value); + DBG(dev, "1284 PNP String: %x %s\n", value, + &dev->pnp_string[2]); + break; + + case GET_PORT_STATUS: /* Get Port Status */ + /* Only one printer interface is supported. */ + if (wIndex != dev->interface) + break; + + *(u8 *)req->buf = dev->printer_status; + value = min_t(u16, wLength, 1); + break; + + case SOFT_RESET: /* Soft Reset */ + /* Only one printer interface is supported. */ + if (wIndex != dev->interface) + break; + + printer_soft_reset(dev); + + value = 0; + break; + + default: + goto unknown; + } + break; + + default: +unknown: + VDBG(dev, + "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); + break; + } + /* host either stalls (value < 0) or reports success */ + if (value >= 0) { + req->length = value; + req->zero = value < wLength; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + ERROR(dev, "%s:%d Error!\n", __func__, __LINE__); + req->status = 0; + } + } + return value; +} + +static int printer_func_bind(struct usb_configuration *c, + struct usb_function *f) +{ + struct usb_gadget *gadget = c->cdev->gadget; + struct printer_dev *dev = func_to_printer(f); + struct device *pdev; + struct usb_composite_dev *cdev = c->cdev; + struct usb_ep *in_ep; + struct usb_ep *out_ep = NULL; + struct usb_request *req; + dev_t devt; + int id; + int ret; + u32 i; + + id = usb_interface_id(c, f); + if (id < 0) + return id; + intf_desc.bInterfaceNumber = id; + + /* finish hookup to lower layer ... */ + dev->gadget = gadget; + + /* all we really need is bulk IN/OUT */ + in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc); + if (!in_ep) { +autoconf_fail: + dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n", + cdev->gadget->name); + return -ENODEV; + } + in_ep->driver_data = in_ep; /* claim */ + + out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc); + if (!out_ep) + goto autoconf_fail; + out_ep->driver_data = out_ep; /* claim */ + + /* assumes that all endpoints are dual-speed */ + hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, fs_printer_function, + hs_printer_function, ss_printer_function); + if (ret) + return ret; + + dev->in_ep = in_ep; + dev->out_ep = out_ep; + + ret = -ENOMEM; + for (i = 0; i < dev->q_len; i++) { + req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) + goto fail_tx_reqs; + list_add(&req->list, &dev->tx_reqs); + } + + for (i = 0; i < dev->q_len; i++) { + req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) + goto fail_rx_reqs; + list_add(&req->list, &dev->rx_reqs); + } + + /* Setup the sysfs files for the printer gadget. */ + devt = MKDEV(major, dev->minor); + pdev = device_create(usb_gadget_class, NULL, devt, + NULL, "g_printer%d", dev->minor); + if (IS_ERR(pdev)) { + ERROR(dev, "Failed to create device: g_printer\n"); + ret = PTR_ERR(pdev); + goto fail_rx_reqs; + } + + /* + * Register a character device as an interface to a user mode + * program that handles the printer specific functionality. + */ + cdev_init(&dev->printer_cdev, &printer_io_operations); + dev->printer_cdev.owner = THIS_MODULE; + ret = cdev_add(&dev->printer_cdev, devt, 1); + if (ret) { + ERROR(dev, "Failed to open char device\n"); + goto fail_cdev_add; + } + + return 0; + +fail_cdev_add: + device_destroy(usb_gadget_class, devt); + +fail_rx_reqs: + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + +fail_tx_reqs: + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + + return ret; + +} + +static int printer_func_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct printer_dev *dev = func_to_printer(f); + int ret = -ENOTSUPP; + + if (!alt) + ret = set_interface(dev, intf); + + return ret; +} + +static void printer_func_disable(struct usb_function *f) +{ + struct printer_dev *dev = func_to_printer(f); + unsigned long flags; + + DBG(dev, "%s\n", __func__); + + spin_lock_irqsave(&dev->lock, flags); + printer_reset_interface(dev); + spin_unlock_irqrestore(&dev->lock, flags); +} + +static inline struct f_printer_opts +*to_f_printer_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_printer_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_printer_opts); +CONFIGFS_ATTR_OPS(f_printer_opts); + +static void printer_attr_release(struct config_item *item) +{ + struct f_printer_opts *opts = to_f_printer_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations printer_item_ops = { + .release = printer_attr_release, + .show_attribute = f_printer_opts_attr_show, + .store_attribute = f_printer_opts_attr_store, +}; + +static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts, + char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts, + const char *page, size_t len) +{ + int result, l; + + mutex_lock(&opts->lock); + result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2); + l = strlen(opts->pnp_string + 2) + 2; + opts->pnp_string[0] = (l >> 8) & 0xFF; + opts->pnp_string[1] = l & 0xFF; + mutex_unlock(&opts->lock); + + return result; +} + +static struct f_printer_opts_attribute f_printer_opts_pnp_string = + __CONFIGFS_ATTR(pnp_string, S_IRUGO | S_IWUSR, + f_printer_opts_pnp_string_show, + f_printer_opts_pnp_string_store); + +static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts, + char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d\n", opts->q_len); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_printer_opts_q_len_store(struct f_printer_opts *opts, + const char *page, size_t len) +{ + int ret; + u16 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou16(page, 0, &num); + if (ret) + goto end; + + opts->q_len = (unsigned)num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_printer_opts_attribute f_printer_opts_q_len = + __CONFIGFS_ATTR(q_len, S_IRUGO | S_IWUSR, f_printer_opts_q_len_show, + f_printer_opts_q_len_store); + +static struct configfs_attribute *printer_attrs[] = { + &f_printer_opts_pnp_string.attr, + &f_printer_opts_q_len.attr, + NULL, +}; + +static struct config_item_type printer_func_type = { + .ct_item_ops = &printer_item_ops, + .ct_attrs = printer_attrs, + .ct_owner = THIS_MODULE, +}; + +static inline int gprinter_get_minor(void) +{ + return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); +} + +static inline void gprinter_put_minor(int minor) +{ + ida_simple_remove(&printer_ida, minor); +} + +static int gprinter_setup(int); +static void gprinter_cleanup(void); + +static void gprinter_free_inst(struct usb_function_instance *f) +{ + struct f_printer_opts *opts; + + opts = container_of(f, struct f_printer_opts, func_inst); + + mutex_lock(&printer_ida_lock); + + gprinter_put_minor(opts->minor); + if (idr_is_empty(&printer_ida.idr)) + gprinter_cleanup(); + + mutex_unlock(&printer_ida_lock); + + kfree(opts); +} + +static struct usb_function_instance *gprinter_alloc_inst(void) +{ + struct f_printer_opts *opts; + struct usb_function_instance *ret; + int status = 0; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + mutex_init(&opts->lock); + opts->func_inst.free_func_inst = gprinter_free_inst; + ret = &opts->func_inst; + + mutex_lock(&printer_ida_lock); + + if (idr_is_empty(&printer_ida.idr)) { + status = gprinter_setup(PRINTER_MINORS); + if (status) { + ret = ERR_PTR(status); + kfree(opts); + goto unlock; + } + } + + opts->minor = gprinter_get_minor(); + if (opts->minor < 0) { + ret = ERR_PTR(opts->minor); + kfree(opts); + if (idr_is_empty(&printer_ida.idr)) + gprinter_cleanup(); + goto unlock; + } + config_group_init_type_name(&opts->func_inst.group, "", + &printer_func_type); + +unlock: + mutex_unlock(&printer_ida_lock); + return ret; +} + +static void gprinter_free(struct usb_function *f) +{ + struct printer_dev *dev = func_to_printer(f); + struct f_printer_opts *opts; + + opts = container_of(f->fi, struct f_printer_opts, func_inst); + kfree(dev); + mutex_lock(&opts->lock); + --opts->refcnt; + mutex_unlock(&opts->lock); +} + +static void printer_func_unbind(struct usb_configuration *c, + struct usb_function *f) +{ + struct printer_dev *dev; + struct usb_request *req; + + dev = func_to_printer(f); + + device_destroy(usb_gadget_class, MKDEV(major, dev->minor)); + + /* Remove Character Device */ + cdev_del(&dev->printer_cdev); + + /* we must already have been disconnected ... no i/o may be active */ + WARN_ON(!list_empty(&dev->tx_reqs_active)); + WARN_ON(!list_empty(&dev->rx_reqs_active)); + + /* Free all memory for this driver. */ + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + + if (dev->current_rx_req != NULL) + printer_req_free(dev->out_ep, dev->current_rx_req); + + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + + while (!list_empty(&dev->rx_buffers)) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + usb_free_all_descriptors(f); +} + +static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) +{ + struct printer_dev *dev; + struct f_printer_opts *opts; + + opts = container_of(fi, struct f_printer_opts, func_inst); + + mutex_lock(&opts->lock); + if (opts->minor >= minors) { + mutex_unlock(&opts->lock); + return ERR_PTR(-ENOENT); + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + mutex_unlock(&opts->lock); + return ERR_PTR(-ENOMEM); + } + + ++opts->refcnt; + dev->minor = opts->minor; + dev->pnp_string = opts->pnp_string; + dev->q_len = opts->q_len; + mutex_unlock(&opts->lock); + + dev->function.name = "printer"; + dev->function.bind = printer_func_bind; + dev->function.setup = printer_func_setup; + dev->function.unbind = printer_func_unbind; + dev->function.set_alt = printer_func_set_alt; + dev->function.disable = printer_func_disable; + dev->function.req_match = gprinter_req_match; + dev->function.free_func = gprinter_free; + + INIT_LIST_HEAD(&dev->tx_reqs); + INIT_LIST_HEAD(&dev->rx_reqs); + INIT_LIST_HEAD(&dev->rx_buffers); + INIT_LIST_HEAD(&dev->tx_reqs_active); + INIT_LIST_HEAD(&dev->rx_reqs_active); + + spin_lock_init(&dev->lock); + mutex_init(&dev->lock_printer_io); + init_waitqueue_head(&dev->rx_wait); + init_waitqueue_head(&dev->tx_wait); + init_waitqueue_head(&dev->tx_flush_wait); + + dev->interface = -1; + dev->printer_cdev_open = 0; + dev->printer_status = PRINTER_NOT_ERROR; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + return &dev->function; +} + +DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Craig Nadler"); + +static int gprinter_setup(int count) +{ + int status; + dev_t devt; + + usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); + if (IS_ERR(usb_gadget_class)) { + status = PTR_ERR(usb_gadget_class); + usb_gadget_class = NULL; + pr_err("unable to create usb_gadget class %d\n", status); + return status; + } + + status = alloc_chrdev_region(&devt, 0, count, "USB printer gadget"); + if (status) { + pr_err("alloc_chrdev_region %d\n", status); + class_destroy(usb_gadget_class); + usb_gadget_class = NULL; + return status; + } + + major = MAJOR(devt); + minors = count; + + return status; +} + +static void gprinter_cleanup(void) +{ + if (major) { + unregister_chrdev_region(MKDEV(major, 0), minors); + major = minors = 0; + } + class_destroy(usb_gadget_class); + usb_gadget_class = NULL; +} diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index e07c50ced64d..3a5ae9900b1e 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -23,15 +23,6 @@ #include "gadget_chips.h" #include "u_f.h" -#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x) - -enum eptype { - EP_CONTROL = 0, - EP_BULK, - EP_ISOC, - EP_INTERRUPT, -}; - /* * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral * controller drivers. @@ -64,8 +55,6 @@ struct f_sourcesink { struct usb_ep *out_ep; struct usb_ep *iso_in_ep; struct usb_ep *iso_out_ep; - struct usb_ep *int_in_ep; - struct usb_ep *int_out_ep; int cur_alt; }; @@ -79,10 +68,6 @@ static unsigned isoc_interval; static unsigned isoc_maxpacket; static unsigned isoc_mult; static unsigned isoc_maxburst; -static unsigned int_interval; /* In ms */ -static unsigned int_maxpacket; -static unsigned int_mult; -static unsigned int_maxburst; static unsigned buflen; /*-------------------------------------------------------------------------*/ @@ -107,16 +92,6 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = { /* .iInterface = DYNAMIC */ }; -static struct usb_interface_descriptor source_sink_intf_alt2 = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 2, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - /* .iInterface = DYNAMIC */ -}; - /* full speed support: */ static struct usb_endpoint_descriptor fs_source_desc = { @@ -155,26 +130,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = { .bInterval = 4, }; -static struct usb_endpoint_descriptor fs_int_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(64), - .bInterval = GZERO_INT_INTERVAL, -}; - -static struct usb_endpoint_descriptor fs_int_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(64), - .bInterval = GZERO_INT_INTERVAL, -}; - static struct usb_descriptor_header *fs_source_sink_descs[] = { (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &fs_sink_desc, @@ -185,10 +140,6 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = { (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_iso_sink_desc, (struct usb_descriptor_header *) &fs_iso_source_desc, - (struct usb_descriptor_header *) &source_sink_intf_alt2, -#define FS_ALT_IFC_2_OFFSET 8 - (struct usb_descriptor_header *) &fs_int_sink_desc, - (struct usb_descriptor_header *) &fs_int_source_desc, NULL, }; @@ -228,24 +179,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = { .bInterval = 4, }; -static struct usb_endpoint_descriptor hs_int_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL), -}; - -static struct usb_endpoint_descriptor hs_int_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL), -}; - static struct usb_descriptor_header *hs_source_sink_descs[] = { (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &hs_source_desc, @@ -256,10 +189,6 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = { (struct usb_descriptor_header *) &hs_sink_desc, (struct usb_descriptor_header *) &hs_iso_source_desc, (struct usb_descriptor_header *) &hs_iso_sink_desc, - (struct usb_descriptor_header *) &source_sink_intf_alt2, -#define HS_ALT_IFC_2_OFFSET 8 - (struct usb_descriptor_header *) &hs_int_source_desc, - (struct usb_descriptor_header *) &hs_int_sink_desc, NULL, }; @@ -335,42 +264,6 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { .wBytesPerInterval = cpu_to_le16(1024), }; -static struct usb_endpoint_descriptor ss_int_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL), -}; - -struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor ss_int_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL), -}; - -struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = cpu_to_le16(1024), -}; - static struct usb_descriptor_header *ss_source_sink_descs[] = { (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &ss_source_desc, @@ -387,12 +280,6 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = { (struct usb_descriptor_header *) &ss_iso_source_comp_desc, (struct usb_descriptor_header *) &ss_iso_sink_desc, (struct usb_descriptor_header *) &ss_iso_sink_comp_desc, - (struct usb_descriptor_header *) &source_sink_intf_alt2, -#define SS_ALT_IFC_2_OFFSET 14 - (struct usb_descriptor_header *) &ss_int_source_desc, - (struct usb_descriptor_header *) &ss_int_source_comp_desc, - (struct usb_descriptor_header *) &ss_int_sink_desc, - (struct usb_descriptor_header *) &ss_int_sink_comp_desc, NULL, }; @@ -414,21 +301,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = { }; /*-------------------------------------------------------------------------*/ -static const char *get_ep_string(enum eptype ep_type) -{ - switch (ep_type) { - case EP_ISOC: - return "ISOC-"; - case EP_INTERRUPT: - return "INTERRUPT-"; - case EP_CONTROL: - return "CTRL-"; - case EP_BULK: - return "BULK-"; - default: - return "UNKNOWN-"; - } -} static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len) { @@ -456,8 +328,7 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) void disable_endpoints(struct usb_composite_dev *cdev, struct usb_ep *in, struct usb_ep *out, - struct usb_ep *iso_in, struct usb_ep *iso_out, - struct usb_ep *int_in, struct usb_ep *int_out) + struct usb_ep *iso_in, struct usb_ep *iso_out) { disable_ep(cdev, in); disable_ep(cdev, out); @@ -465,10 +336,6 @@ void disable_endpoints(struct usb_composite_dev *cdev, disable_ep(cdev, iso_in); if (iso_out) disable_ep(cdev, iso_out); - if (int_in) - disable_ep(cdev, int_in); - if (int_out) - disable_ep(cdev, int_out); } static int @@ -485,7 +352,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) return id; source_sink_intf_alt0.bInterfaceNumber = id; source_sink_intf_alt1.bInterfaceNumber = id; - source_sink_intf_alt2.bInterfaceNumber = id; /* allocate bulk endpoints */ ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); @@ -546,55 +412,14 @@ no_iso: if (isoc_maxpacket > 1024) isoc_maxpacket = 1024; - /* sanity check the interrupt module parameters */ - if (int_interval < 1) - int_interval = 1; - if (int_interval > 4096) - int_interval = 4096; - if (int_mult > 2) - int_mult = 2; - if (int_maxburst > 15) - int_maxburst = 15; - - /* fill in the FS interrupt descriptors from the module parameters */ - fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ? - 64 : int_maxpacket; - fs_int_source_desc.bInterval = int_interval > 255 ? - 255 : int_interval; - fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ? - 64 : int_maxpacket; - fs_int_sink_desc.bInterval = int_interval > 255 ? - 255 : int_interval; - - /* allocate int endpoints */ - ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc); - if (!ss->int_in_ep) - goto no_int; - ss->int_in_ep->driver_data = cdev; /* claim */ - - ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc); - if (ss->int_out_ep) { - ss->int_out_ep->driver_data = cdev; /* claim */ - } else { - ss->int_in_ep->driver_data = NULL; - ss->int_in_ep = NULL; -no_int: - fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL; - hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL; - ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL; - } - - if (int_maxpacket > 1024) - int_maxpacket = 1024; - /* support high speed hardware */ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; /* - * Fill in the HS isoc and interrupt descriptors from the module - * parameters. We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. + * Fill in the HS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. */ hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; @@ -607,17 +432,6 @@ no_int: hs_iso_sink_desc.bInterval = isoc_interval; hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; - hs_int_source_desc.wMaxPacketSize = int_maxpacket; - hs_int_source_desc.wMaxPacketSize |= int_mult << 11; - hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval); - hs_int_source_desc.bEndpointAddress = - fs_int_source_desc.bEndpointAddress; - - hs_int_sink_desc.wMaxPacketSize = int_maxpacket; - hs_int_sink_desc.wMaxPacketSize |= int_mult << 11; - hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval); - hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress; - /* support super speed hardware */ ss_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; @@ -625,9 +439,9 @@ no_int: fs_sink_desc.bEndpointAddress; /* - * Fill in the SS isoc and interrupt descriptors from the module - * parameters. We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. + * Fill in the SS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. */ ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; ss_iso_source_desc.bInterval = isoc_interval; @@ -646,37 +460,17 @@ no_int: isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; - ss_int_source_desc.wMaxPacketSize = int_maxpacket; - ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval); - ss_int_source_comp_desc.bmAttributes = int_mult; - ss_int_source_comp_desc.bMaxBurst = int_maxburst; - ss_int_source_comp_desc.wBytesPerInterval = - int_maxpacket * (int_mult + 1) * (int_maxburst + 1); - ss_int_source_desc.bEndpointAddress = - fs_int_source_desc.bEndpointAddress; - - ss_int_sink_desc.wMaxPacketSize = int_maxpacket; - ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval); - ss_int_sink_comp_desc.bmAttributes = int_mult; - ss_int_sink_comp_desc.bMaxBurst = int_maxburst; - ss_int_sink_comp_desc.wBytesPerInterval = - int_maxpacket * (int_mult + 1) * (int_maxburst + 1); - ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress; - ret = usb_assign_descriptors(f, fs_source_sink_descs, hs_source_sink_descs, ss_source_sink_descs); if (ret) return ret; - DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, " - "INT-IN/%s, INT-OUT/%s\n", + DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), f->name, ss->in_ep->name, ss->out_ep->name, ss->iso_in_ep ? ss->iso_in_ep->name : "<none>", - ss->iso_out_ep ? ss->iso_out_ep->name : "<none>", - ss->int_in_ep ? ss->int_in_ep->name : "<none>", - ss->int_out_ep ? ss->int_out_ep->name : "<none>"); + ss->iso_out_ep ? ss->iso_out_ep->name : "<none>"); return 0; } @@ -807,15 +601,14 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) } static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, - enum eptype ep_type, int speed) + bool is_iso, int speed) { struct usb_ep *ep; struct usb_request *req; int i, size, status; for (i = 0; i < 8; i++) { - switch (ep_type) { - case EP_ISOC: + if (is_iso) { switch (speed) { case USB_SPEED_SUPER: size = isoc_maxpacket * (isoc_mult + 1) * @@ -831,28 +624,9 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, } ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; req = ss_alloc_ep_req(ep, size); - break; - case EP_INTERRUPT: - switch (speed) { - case USB_SPEED_SUPER: - size = int_maxpacket * (int_mult + 1) * - (int_maxburst + 1); - break; - case USB_SPEED_HIGH: - size = int_maxpacket * (int_mult + 1); - break; - default: - size = int_maxpacket > 1023 ? - 1023 : int_maxpacket; - break; - } - ep = is_in ? ss->int_in_ep : ss->int_out_ep; - req = ss_alloc_ep_req(ep, size); - break; - default: + } else { ep = is_in ? ss->in_ep : ss->out_ep; req = ss_alloc_ep_req(ep, 0); - break; } if (!req) @@ -870,12 +644,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, cdev = ss->function.config->cdev; ERROR(cdev, "start %s%s %s --> %d\n", - get_ep_string(ep_type), is_in ? "IN" : "OUT", - ep->name, status); + is_iso ? "ISO-" : "", is_in ? "IN" : "OUT", + ep->name, status); free_ep_req(ep, req); } - if (!(ep_type == EP_ISOC)) + if (!is_iso) break; } @@ -888,7 +662,7 @@ static void disable_source_sink(struct f_sourcesink *ss) cdev = ss->function.config->cdev; disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep, - ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep); + ss->iso_out_ep); VDBG(cdev, "%s disabled\n", ss->function.name); } @@ -900,62 +674,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss, int speed = cdev->gadget->speed; struct usb_ep *ep; - if (alt == 2) { - /* Configure for periodic interrupt endpoint */ - ep = ss->int_in_ep; - if (ep) { - result = config_ep_by_speed(cdev->gadget, - &(ss->function), ep); - if (result) - return result; - - result = usb_ep_enable(ep); - if (result < 0) - return result; - - ep->driver_data = ss; - result = source_sink_start_ep(ss, true, EP_INTERRUPT, - speed); - if (result < 0) { -fail1: - ep = ss->int_in_ep; - if (ep) { - usb_ep_disable(ep); - ep->driver_data = NULL; - } - return result; - } - } - - /* - * one interrupt endpoint reads (sinks) anything OUT (from the - * host) - */ - ep = ss->int_out_ep; - if (ep) { - result = config_ep_by_speed(cdev->gadget, - &(ss->function), ep); - if (result) - goto fail1; - - result = usb_ep_enable(ep); - if (result < 0) - goto fail1; - - ep->driver_data = ss; - result = source_sink_start_ep(ss, false, EP_INTERRUPT, - speed); - if (result < 0) { - ep = ss->int_out_ep; - usb_ep_disable(ep); - ep->driver_data = NULL; - goto fail1; - } - } - - goto out; - } - /* one bulk endpoint writes (sources) zeroes IN (to the host) */ ep = ss->in_ep; result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); @@ -966,7 +684,7 @@ fail1: return result; ep->driver_data = ss; - result = source_sink_start_ep(ss, true, EP_BULK, speed); + result = source_sink_start_ep(ss, true, false, speed); if (result < 0) { fail: ep = ss->in_ep; @@ -985,7 +703,7 @@ fail: goto fail; ep->driver_data = ss; - result = source_sink_start_ep(ss, false, EP_BULK, speed); + result = source_sink_start_ep(ss, false, false, speed); if (result < 0) { fail2: ep = ss->out_ep; @@ -1008,7 +726,7 @@ fail2: goto fail2; ep->driver_data = ss; - result = source_sink_start_ep(ss, true, EP_ISOC, speed); + result = source_sink_start_ep(ss, true, true, speed); if (result < 0) { fail3: ep = ss->iso_in_ep; @@ -1031,14 +749,13 @@ fail3: goto fail3; ep->driver_data = ss; - result = source_sink_start_ep(ss, false, EP_ISOC, speed); + result = source_sink_start_ep(ss, false, true, speed); if (result < 0) { usb_ep_disable(ep); ep->driver_data = NULL; goto fail3; } } - out: ss->cur_alt = alt; @@ -1054,8 +771,6 @@ static int sourcesink_set_alt(struct usb_function *f, if (ss->in_ep->driver_data) disable_source_sink(ss); - else if (alt == 2 && ss->int_in_ep->driver_data) - disable_source_sink(ss); return enable_source_sink(cdev, ss, alt); } @@ -1168,10 +883,6 @@ static struct usb_function *source_sink_alloc_func( isoc_maxpacket = ss_opts->isoc_maxpacket; isoc_mult = ss_opts->isoc_mult; isoc_maxburst = ss_opts->isoc_maxburst; - int_interval = ss_opts->int_interval; - int_maxpacket = ss_opts->int_maxpacket; - int_mult = ss_opts->int_mult; - int_maxburst = ss_opts->int_maxburst; buflen = ss_opts->bulk_buflen; ss->function.name = "source/sink"; @@ -1468,182 +1179,6 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen = f_ss_opts_bulk_buflen_show, f_ss_opts_bulk_buflen_store); -static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page) -{ - int result; - - mutex_lock(&opts->lock); - result = sprintf(page, "%u", opts->int_interval); - mutex_unlock(&opts->lock); - - return result; -} - -static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts, - const char *page, size_t len) -{ - int ret; - u32 num; - - mutex_lock(&opts->lock); - if (opts->refcnt) { - ret = -EBUSY; - goto end; - } - - ret = kstrtou32(page, 0, &num); - if (ret) - goto end; - - if (num > 4096) { - ret = -EINVAL; - goto end; - } - - opts->int_interval = num; - ret = len; -end: - mutex_unlock(&opts->lock); - return ret; -} - -static struct f_ss_opts_attribute f_ss_opts_int_interval = - __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR, - f_ss_opts_int_interval_show, - f_ss_opts_int_interval_store); - -static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page) -{ - int result; - - mutex_lock(&opts->lock); - result = sprintf(page, "%u", opts->int_maxpacket); - mutex_unlock(&opts->lock); - - return result; -} - -static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts, - const char *page, size_t len) -{ - int ret; - u16 num; - - mutex_lock(&opts->lock); - if (opts->refcnt) { - ret = -EBUSY; - goto end; - } - - ret = kstrtou16(page, 0, &num); - if (ret) - goto end; - - if (num > 1024) { - ret = -EINVAL; - goto end; - } - - opts->int_maxpacket = num; - ret = len; -end: - mutex_unlock(&opts->lock); - return ret; -} - -static struct f_ss_opts_attribute f_ss_opts_int_maxpacket = - __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR, - f_ss_opts_int_maxpacket_show, - f_ss_opts_int_maxpacket_store); - -static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page) -{ - int result; - - mutex_lock(&opts->lock); - result = sprintf(page, "%u", opts->int_mult); - mutex_unlock(&opts->lock); - - return result; -} - -static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts, - const char *page, size_t len) -{ - int ret; - u8 num; - - mutex_lock(&opts->lock); - if (opts->refcnt) { - ret = -EBUSY; - goto end; - } - - ret = kstrtou8(page, 0, &num); - if (ret) - goto end; - - if (num > 2) { - ret = -EINVAL; - goto end; - } - - opts->int_mult = num; - ret = len; -end: - mutex_unlock(&opts->lock); - return ret; -} - -static struct f_ss_opts_attribute f_ss_opts_int_mult = - __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR, - f_ss_opts_int_mult_show, - f_ss_opts_int_mult_store); - -static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page) -{ - int result; - - mutex_lock(&opts->lock); - result = sprintf(page, "%u", opts->int_maxburst); - mutex_unlock(&opts->lock); - - return result; -} - -static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts, - const char *page, size_t len) -{ - int ret; - u8 num; - - mutex_lock(&opts->lock); - if (opts->refcnt) { - ret = -EBUSY; - goto end; - } - - ret = kstrtou8(page, 0, &num); - if (ret) - goto end; - - if (num > 15) { - ret = -EINVAL; - goto end; - } - - opts->int_maxburst = num; - ret = len; -end: - mutex_unlock(&opts->lock); - return ret; -} - -static struct f_ss_opts_attribute f_ss_opts_int_maxburst = - __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR, - f_ss_opts_int_maxburst_show, - f_ss_opts_int_maxburst_store); - static struct configfs_attribute *ss_attrs[] = { &f_ss_opts_pattern.attr, &f_ss_opts_isoc_interval.attr, @@ -1651,10 +1186,6 @@ static struct configfs_attribute *ss_attrs[] = { &f_ss_opts_isoc_mult.attr, &f_ss_opts_isoc_maxburst.attr, &f_ss_opts_bulk_buflen.attr, - &f_ss_opts_int_interval.attr, - &f_ss_opts_int_maxpacket.attr, - &f_ss_opts_int_mult.attr, - &f_ss_opts_int_maxburst.attr, NULL, }; @@ -1684,8 +1215,6 @@ static struct usb_function_instance *source_sink_alloc_inst(void) ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; - ss_opts->int_interval = GZERO_INT_INTERVAL; - ss_opts->int_maxpacket = GZERO_INT_MAXPACKET; config_group_init_type_name(&ss_opts->func_inst.group, "", &ss_func_type); diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 33e16658e5cf..6d3eb8b00a48 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -54,7 +54,7 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -const char *uac2_name = "snd_uac2"; +static const char *uac2_name = "snd_uac2"; struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ @@ -634,7 +634,7 @@ static struct usb_interface_descriptor std_ac_if_desc = { }; /* Clock source for IN traffic */ -struct uac_clock_source_descriptor in_clk_src_desc = { +static struct uac_clock_source_descriptor in_clk_src_desc = { .bLength = sizeof in_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -646,7 +646,7 @@ struct uac_clock_source_descriptor in_clk_src_desc = { }; /* Clock source for OUT traffic */ -struct uac_clock_source_descriptor out_clk_src_desc = { +static struct uac_clock_source_descriptor out_clk_src_desc = { .bLength = sizeof out_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -658,7 +658,7 @@ struct uac_clock_source_descriptor out_clk_src_desc = { }; /* Input Terminal for USB_OUT */ -struct uac2_input_terminal_descriptor usb_out_it_desc = { +static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bLength = sizeof usb_out_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -672,7 +672,7 @@ struct uac2_input_terminal_descriptor usb_out_it_desc = { }; /* Input Terminal for I/O-In */ -struct uac2_input_terminal_descriptor io_in_it_desc = { +static struct uac2_input_terminal_descriptor io_in_it_desc = { .bLength = sizeof io_in_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -686,7 +686,7 @@ struct uac2_input_terminal_descriptor io_in_it_desc = { }; /* Ouput Terminal for USB_IN */ -struct uac2_output_terminal_descriptor usb_in_ot_desc = { +static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bLength = sizeof usb_in_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -700,7 +700,7 @@ struct uac2_output_terminal_descriptor usb_in_ot_desc = { }; /* Ouput Terminal for I/O-Out */ -struct uac2_output_terminal_descriptor io_out_ot_desc = { +static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bLength = sizeof io_out_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -713,7 +713,7 @@ struct uac2_output_terminal_descriptor io_out_ot_desc = { .bmControls = (CONTROL_RDWR << COPY_CTRL), }; -struct uac2_ac_header_descriptor ac_hdr_desc = { +static struct uac2_ac_header_descriptor ac_hdr_desc = { .bLength = sizeof ac_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -751,7 +751,7 @@ static struct usb_interface_descriptor std_as_out_if1_desc = { }; /* Audio Stream OUT Intface Desc */ -struct uac2_as_header_descriptor as_out_hdr_desc = { +static struct uac2_as_header_descriptor as_out_hdr_desc = { .bLength = sizeof as_out_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -764,7 +764,7 @@ struct uac2_as_header_descriptor as_out_hdr_desc = { }; /* Audio USB_OUT Format */ -struct uac2_format_type_i_descriptor as_out_fmt1_desc = { +static struct uac2_format_type_i_descriptor as_out_fmt1_desc = { .bLength = sizeof as_out_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, @@ -772,7 +772,7 @@ struct uac2_format_type_i_descriptor as_out_fmt1_desc = { }; /* STD AS ISO OUT Endpoint */ -struct usb_endpoint_descriptor fs_epout_desc = { +static struct usb_endpoint_descriptor fs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -782,7 +782,7 @@ struct usb_endpoint_descriptor fs_epout_desc = { .bInterval = 1, }; -struct usb_endpoint_descriptor hs_epout_desc = { +static struct usb_endpoint_descriptor hs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -828,7 +828,7 @@ static struct usb_interface_descriptor std_as_in_if1_desc = { }; /* Audio Stream IN Intface Desc */ -struct uac2_as_header_descriptor as_in_hdr_desc = { +static struct uac2_as_header_descriptor as_in_hdr_desc = { .bLength = sizeof as_in_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -841,7 +841,7 @@ struct uac2_as_header_descriptor as_in_hdr_desc = { }; /* Audio USB_IN Format */ -struct uac2_format_type_i_descriptor as_in_fmt1_desc = { +static struct uac2_format_type_i_descriptor as_in_fmt1_desc = { .bLength = sizeof as_in_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, @@ -849,7 +849,7 @@ struct uac2_format_type_i_descriptor as_in_fmt1_desc = { }; /* STD AS ISO IN Endpoint */ -struct usb_endpoint_descriptor fs_epin_desc = { +static struct usb_endpoint_descriptor fs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -859,7 +859,7 @@ struct usb_endpoint_descriptor fs_epin_desc = { .bInterval = 1, }; -struct usb_endpoint_descriptor hs_epin_desc = { +static struct usb_endpoint_descriptor hs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -1563,7 +1563,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) agdev->out_ep->driver_data = NULL; } -struct usb_function *afunc_alloc(struct usb_function_instance *fi) +static struct usb_function *afunc_alloc(struct usb_function_instance *fi) { struct audio_dev *agdev; struct f_uac2_opts *opts; diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h index 2ce28b9d97cc..15f180904f8a 100644 --- a/drivers/usb/gadget/function/g_zero.h +++ b/drivers/usb/gadget/function/g_zero.h @@ -10,8 +10,6 @@ #define GZERO_QLEN 32 #define GZERO_ISOC_INTERVAL 4 #define GZERO_ISOC_MAXPACKET 1024 -#define GZERO_INT_INTERVAL 1 /* Default interrupt interval = 1 ms */ -#define GZERO_INT_MAXPACKET 1024 struct usb_zero_options { unsigned pattern; @@ -19,10 +17,6 @@ struct usb_zero_options { unsigned isoc_maxpacket; unsigned isoc_mult; unsigned isoc_maxburst; - unsigned int_interval; /* In ms */ - unsigned int_maxpacket; - unsigned int_mult; - unsigned int_maxburst; unsigned bulk_buflen; unsigned qlen; }; @@ -34,10 +28,6 @@ struct f_ss_opts { unsigned isoc_maxpacket; unsigned isoc_mult; unsigned isoc_maxburst; - unsigned int_interval; /* In ms */ - unsigned int_maxpacket; - unsigned int_mult; - unsigned int_maxburst; unsigned bulk_buflen; /* @@ -72,7 +62,6 @@ int lb_modinit(void); void free_ep_req(struct usb_ep *ep, struct usb_request *req); void disable_endpoints(struct usb_composite_dev *cdev, struct usb_ep *in, struct usb_ep *out, - struct usb_ep *iso_in, struct usb_ep *iso_out, - struct usb_ep *int_in, struct usb_ep *int_out); + struct usb_ep *iso_in, struct usb_ep *iso_out); #endif /* __G_ZERO_H */ diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h new file mode 100644 index 000000000000..0e2c49d4274e --- /dev/null +++ b/drivers/usb/gadget/function/u_printer.h @@ -0,0 +1,37 @@ +/* + * u_printer.h + * + * Utility definitions for the printer function + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_PRINTER_H +#define U_PRINTER_H + +#include <linux/usb/composite.h> + +#define PNP_STRING_LEN 1024 + +struct f_printer_opts { + struct usb_function_instance func_inst; + int minor; + char pnp_string[PNP_STRING_LEN]; + unsigned q_len; + + /* + * Protect the data from concurrent access by read/write + * and create symlink/remove symlink + */ + struct mutex lock; + int refcnt; +}; + +#endif /* U_PRINTER_H */ diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 491082aaf103..89179ab20c10 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -912,7 +912,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch) unsigned long flags; int status; - pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n", + pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %ps\n", port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index cbd9bf020fb3..f4ccbd56f4d2 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -26,6 +26,7 @@ #include "uvc.h" #include "uvc_queue.h" #include "uvc_video.h" +#include "uvc_v4l2.h" /* -------------------------------------------------------------------------- * Requests handling diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 8927358caf24..3d0d5d94a62f 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -21,6 +21,7 @@ #include "uvc.h" #include "uvc_queue.h" +#include "uvc_video.h" /* -------------------------------------------------------------------------- * Video codecs diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 113c87e22117..d5a7102de696 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -301,6 +301,7 @@ config USB_MIDI_GADGET config USB_G_PRINTER tristate "Printer Gadget" select USB_LIBCOMPOSITE + select USB_F_PRINTER help The Printer Gadget channels data between the USB host and a userspace program driving the print engine. The user space diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index 06acfa55864a..b01b88e1b716 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -133,7 +133,9 @@ struct gfs_configuration { struct usb_configuration c; int (*eth)(struct usb_configuration *c); int num; -} gfs_configurations[] = { +}; + +static struct gfs_configuration gfs_configurations[] = { #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { .eth = bind_rndis_config, @@ -278,7 +280,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev) if (!try_module_get(THIS_MODULE)) return ERR_PTR(-ENOENT); - return 0; + return NULL; } static void functionfs_release_dev(struct ffs_dev *dev) diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index db49ec4c748e..6af58c6dba5e 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -26,6 +26,7 @@ #include <linux/poll.h> #include <linux/mmu_context.h> #include <linux/aio.h> +#include <linux/uio.h> #include <linux/device.h> #include <linux/moduleparam.h> @@ -74,6 +75,8 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_AUTHOR ("David Brownell"); MODULE_LICENSE ("GPL"); +static int ep_open(struct inode *, struct file *); + /*----------------------------------------------------------------------*/ @@ -283,14 +286,15 @@ static void epio_complete (struct usb_ep *ep, struct usb_request *req) * still need dev->lock to use epdata->ep. */ static int -get_ready_ep (unsigned f_flags, struct ep_data *epdata) +get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write) { int val; if (f_flags & O_NONBLOCK) { if (!mutex_trylock(&epdata->lock)) goto nonblock; - if (epdata->state != STATE_EP_ENABLED) { + if (epdata->state != STATE_EP_ENABLED && + (!is_write || epdata->state != STATE_EP_READY)) { mutex_unlock(&epdata->lock); nonblock: val = -EAGAIN; @@ -305,18 +309,20 @@ nonblock: switch (epdata->state) { case STATE_EP_ENABLED: + return 0; + case STATE_EP_READY: /* not configured yet */ + if (is_write) + return 0; + // FALLTHRU + case STATE_EP_UNBOUND: /* clean disconnect */ break; // case STATE_EP_DISABLED: /* "can't happen" */ - // case STATE_EP_READY: /* "can't happen" */ default: /* error! */ pr_debug ("%s: ep %p not available, state %d\n", shortname, epdata, epdata->state); - // FALLTHROUGH - case STATE_EP_UNBOUND: /* clean disconnect */ - val = -ENODEV; - mutex_unlock(&epdata->lock); } - return val; + mutex_unlock(&epdata->lock); + return -ENODEV; } static ssize_t @@ -363,97 +369,6 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) return value; } - -/* handle a synchronous OUT bulk/intr/iso transfer */ -static ssize_t -ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ - - value = -ENOMEM; - kbuf = kmalloc (len, GFP_KERNEL); - if (unlikely (!kbuf)) - goto free1; - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %zu OUT, status %d\n", - data->name, len, (int) value); - if (value >= 0 && copy_to_user (buf, kbuf, value)) - value = -EFAULT; - -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - -/* handle a synchronous IN bulk/intr/iso transfer */ -static ssize_t -ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (!usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ - - value = -ENOMEM; - kbuf = memdup_user(buf, len); - if (IS_ERR(kbuf)) { - value = PTR_ERR(kbuf); - kbuf = NULL; - goto free1; - } - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %zu IN, status %d\n", - data->name, len, (int) value); -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - static int ep_release (struct inode *inode, struct file *fd) { @@ -481,7 +396,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value) struct ep_data *data = fd->private_data; int status; - if ((status = get_ready_ep (fd->f_flags, data)) < 0) + if ((status = get_ready_ep (fd->f_flags, data, false)) < 0) return status; spin_lock_irq (&data->dev->lock); @@ -517,8 +432,8 @@ struct kiocb_priv { struct mm_struct *mm; struct work_struct work; void *buf; - const struct iovec *iv; - unsigned long nr_segs; + struct iov_iter to; + const void *to_free; unsigned actual; }; @@ -541,35 +456,6 @@ static int ep_aio_cancel(struct kiocb *iocb) return value; } -static ssize_t ep_copy_to_user(struct kiocb_priv *priv) -{ - ssize_t len, total; - void *to_copy; - int i; - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - to_copy = priv->buf; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - to_copy += this; - if (total == 0) - break; - } - - return len; -} - static void ep_user_copy_worker(struct work_struct *work) { struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work); @@ -578,13 +464,16 @@ static void ep_user_copy_worker(struct work_struct *work) size_t ret; use_mm(mm); - ret = ep_copy_to_user(priv); + ret = copy_to_iter(priv->buf, priv->actual, &priv->to); unuse_mm(mm); + if (!ret) + ret = -EFAULT; /* completing the iocb can drop the ctx and mm, don't touch mm after */ - aio_complete(iocb, ret, ret); + iocb->ki_complete(iocb, ret, ret); kfree(priv->buf); + kfree(priv->to_free); kfree(priv); } @@ -603,12 +492,14 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) * don't need to copy anything to userspace, so we can * complete the aio request immediately. */ - if (priv->iv == NULL || unlikely(req->actual == 0)) { + if (priv->to_free == NULL || unlikely(req->actual == 0)) { kfree(req->buf); + kfree(priv->to_free); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - aio_complete(iocb, req->actual ? req->actual : req->status, + + iocb->ki_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { /* ep_copy_to_user() won't report both; we hide some faults */ @@ -618,6 +509,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) priv->buf = req->buf; priv->actual = req->actual; + INIT_WORK(&priv->work, ep_user_copy_worker); schedule_work(&priv->work); } spin_unlock(&epdata->dev->lock); @@ -626,38 +518,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) put_ep(epdata); } -static ssize_t -ep_aio_rwtail( - struct kiocb *iocb, - char *buf, - size_t len, - struct ep_data *epdata, - const struct iovec *iv, - unsigned long nr_segs -) +static ssize_t ep_aio(struct kiocb *iocb, + struct kiocb_priv *priv, + struct ep_data *epdata, + char *buf, + size_t len) { - struct kiocb_priv *priv; - struct usb_request *req; - ssize_t value; + struct usb_request *req; + ssize_t value; - priv = kmalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - value = -ENOMEM; -fail: - kfree(buf); - return value; - } iocb->private = priv; priv->iocb = iocb; - priv->iv = iv; - priv->nr_segs = nr_segs; - INIT_WORK(&priv->work, ep_user_copy_worker); - - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { - kfree(priv); - goto fail; - } kiocb_set_cancel_fn(iocb, ep_aio_cancel); get_ep(epdata); @@ -669,75 +540,154 @@ fail: * allocate or submit those if the host disconnected. */ spin_lock_irq(&epdata->dev->lock); - if (likely(epdata->ep)) { - req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); - if (likely(req)) { - priv->req = req; - req->buf = buf; - req->length = len; - req->complete = ep_aio_complete; - req->context = iocb; - value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); - if (unlikely(0 != value)) - usb_ep_free_request(epdata->ep, req); - } else - value = -EAGAIN; - } else - value = -ENODEV; - spin_unlock_irq(&epdata->dev->lock); + value = -ENODEV; + if (unlikely(epdata->ep)) + goto fail; - mutex_unlock(&epdata->lock); + req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); + value = -ENOMEM; + if (unlikely(!req)) + goto fail; - if (unlikely(value)) { - kfree(priv); - put_ep(epdata); - } else - value = -EIOCBQUEUED; + priv->req = req; + req->buf = buf; + req->length = len; + req->complete = ep_aio_complete; + req->context = iocb; + value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); + if (unlikely(0 != value)) { + usb_ep_free_request(epdata->ep, req); + goto fail; + } + spin_unlock_irq(&epdata->dev->lock); + return -EIOCBQUEUED; + +fail: + spin_unlock_irq(&epdata->dev->lock); + kfree(priv->to_free); + kfree(priv); + put_ep(epdata); return value; } static ssize_t -ep_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) +ep_read_iter(struct kiocb *iocb, struct iov_iter *to) { - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; + struct file *file = iocb->ki_filp; + struct ep_data *epdata = file->private_data; + size_t len = iov_iter_count(to); + ssize_t value; + char *buf; - if (unlikely(usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; + if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0) + return value; - buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; + /* halt any endpoint by doing a "wrong direction" i/o call */ + if (usb_endpoint_dir_in(&epdata->desc)) { + if (usb_endpoint_xfer_isoc(&epdata->desc) || + !is_sync_kiocb(iocb)) { + mutex_unlock(&epdata->lock); + return -EINVAL; + } + DBG (epdata->dev, "%s halt\n", epdata->name); + spin_lock_irq(&epdata->dev->lock); + if (likely(epdata->ep != NULL)) + usb_ep_set_halt(epdata->ep); + spin_unlock_irq(&epdata->dev->lock); + mutex_unlock(&epdata->lock); + return -EBADMSG; + } - return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs); + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) { + mutex_unlock(&epdata->lock); + return -ENOMEM; + } + if (is_sync_kiocb(iocb)) { + value = ep_io(epdata, buf, len); + if (value >= 0 && copy_to_iter(buf, value, to)) + value = -EFAULT; + } else { + struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); + value = -ENOMEM; + if (!priv) + goto fail; + priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL); + if (!priv->to_free) { + kfree(priv); + goto fail; + } + value = ep_aio(iocb, priv, epdata, buf, len); + if (value == -EIOCBQUEUED) + buf = NULL; + } +fail: + kfree(buf); + mutex_unlock(&epdata->lock); + return value; } +static ssize_t ep_config(struct ep_data *, const char *, size_t); + static ssize_t -ep_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) +ep_write_iter(struct kiocb *iocb, struct iov_iter *from) { - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; - size_t len = 0; - int i = 0; + struct file *file = iocb->ki_filp; + struct ep_data *epdata = file->private_data; + size_t len = iov_iter_count(from); + bool configured; + ssize_t value; + char *buf; + + if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0) + return value; - if (unlikely(!usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; + configured = epdata->state == STATE_EP_ENABLED; - buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); - if (unlikely(!buf)) + /* halt any endpoint by doing a "wrong direction" i/o call */ + if (configured && !usb_endpoint_dir_in(&epdata->desc)) { + if (usb_endpoint_xfer_isoc(&epdata->desc) || + !is_sync_kiocb(iocb)) { + mutex_unlock(&epdata->lock); + return -EINVAL; + } + DBG (epdata->dev, "%s halt\n", epdata->name); + spin_lock_irq(&epdata->dev->lock); + if (likely(epdata->ep != NULL)) + usb_ep_set_halt(epdata->ep); + spin_unlock_irq(&epdata->dev->lock); + mutex_unlock(&epdata->lock); + return -EBADMSG; + } + + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) { + mutex_unlock(&epdata->lock); return -ENOMEM; + } + + if (unlikely(copy_from_iter(buf, len, from) != len)) { + value = -EFAULT; + goto out; + } - for (i=0; i < nr_segs; i++) { - if (unlikely(copy_from_user(&buf[len], iov[i].iov_base, - iov[i].iov_len) != 0)) { - kfree(buf); - return -EFAULT; + if (unlikely(!configured)) { + value = ep_config(epdata, buf, len); + } else if (is_sync_kiocb(iocb)) { + value = ep_io(epdata, buf, len); + } else { + struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); + value = -ENOMEM; + if (priv) { + value = ep_aio(iocb, priv, epdata, buf, len); + if (value == -EIOCBQUEUED) + buf = NULL; } - len += iov[i].iov_len; } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0); +out: + kfree(buf); + mutex_unlock(&epdata->lock); + return value; } /*----------------------------------------------------------------------*/ @@ -745,15 +695,13 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov, /* used after endpoint configuration */ static const struct file_operations ep_io_operations = { .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ep_read, - .write = ep_write, - .unlocked_ioctl = ep_ioctl, + .open = ep_open, .release = ep_release, - - .aio_read = ep_aio_read, - .aio_write = ep_aio_write, + .llseek = no_llseek, + .unlocked_ioctl = ep_ioctl, + .read_iter = ep_read_iter, + .write_iter = ep_write_iter, }; /* ENDPOINT INITIALIZATION @@ -770,17 +718,12 @@ static const struct file_operations ep_io_operations = { * speed descriptor, then optional high speed descriptor. */ static ssize_t -ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) +ep_config (struct ep_data *data, const char *buf, size_t len) { - struct ep_data *data = fd->private_data; struct usb_ep *ep; u32 tag; int value, length = len; - value = mutex_lock_interruptible(&data->lock); - if (value < 0) - return value; - if (data->state != STATE_EP_READY) { value = -EL2HLT; goto fail; @@ -791,9 +734,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) goto fail0; /* we might need to change message format someday */ - if (copy_from_user (&tag, buf, 4)) { - goto fail1; - } + memcpy(&tag, buf, 4); if (tag != 1) { DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); goto fail0; @@ -806,19 +747,15 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) */ /* full/low speed descriptor, then high speed */ - if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) { - goto fail1; - } + memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE); if (data->desc.bLength != USB_DT_ENDPOINT_SIZE || data->desc.bDescriptorType != USB_DT_ENDPOINT) goto fail0; if (len != USB_DT_ENDPOINT_SIZE) { if (len != 2 * USB_DT_ENDPOINT_SIZE) goto fail0; - if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, - USB_DT_ENDPOINT_SIZE)) { - goto fail1; - } + memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, + USB_DT_ENDPOINT_SIZE); if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE || data->hs_desc.bDescriptorType != USB_DT_ENDPOINT) { @@ -840,24 +777,20 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) case USB_SPEED_LOW: case USB_SPEED_FULL: ep->desc = &data->desc; - value = usb_ep_enable(ep); - if (value == 0) - data->state = STATE_EP_ENABLED; break; case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ ep->desc = &data->hs_desc; - value = usb_ep_enable(ep); - if (value == 0) - data->state = STATE_EP_ENABLED; break; default: DBG(data->dev, "unconnected, %s init abandoned\n", data->name); value = -EINVAL; + goto gone; } + value = usb_ep_enable(ep); if (value == 0) { - fd->f_op = &ep_io_operations; + data->state = STATE_EP_ENABLED; value = length; } gone: @@ -867,14 +800,10 @@ fail: data->desc.bDescriptorType = 0; data->hs_desc.bDescriptorType = 0; } - mutex_unlock(&data->lock); return value; fail0: value = -EINVAL; goto fail; -fail1: - value = -EFAULT; - goto fail; } static int @@ -902,15 +831,6 @@ ep_open (struct inode *inode, struct file *fd) return value; } -/* used before endpoint configuration */ -static const struct file_operations ep_config_operations = { - .llseek = no_llseek, - - .open = ep_open, - .write = ep_config, - .release = ep_release, -}; - /*----------------------------------------------------------------------*/ /* EP0 IMPLEMENTATION can be partly in userspace. @@ -989,6 +909,10 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) enum ep0_state state; spin_lock_irq (&dev->lock); + if (dev->state <= STATE_DEV_OPENED) { + retval = -EINVAL; + goto done; + } /* report fd mode change before acting on it */ if (dev->setup_abort) { @@ -1187,8 +1111,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) struct dev_data *dev = fd->private_data; ssize_t retval = -ESRCH; - spin_lock_irq (&dev->lock); - /* report fd mode change before acting on it */ if (dev->setup_abort) { dev->setup_abort = 0; @@ -1234,7 +1156,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } else DBG (dev, "fail %s, state %d\n", __func__, dev->state); - spin_unlock_irq (&dev->lock); return retval; } @@ -1281,6 +1202,9 @@ ep0_poll (struct file *fd, poll_table *wait) struct dev_data *dev = fd->private_data; int mask = 0; + if (dev->state <= STATE_DEV_OPENED) + return DEFAULT_POLLMASK; + poll_wait(fd, &dev->wait, wait); spin_lock_irq (&dev->lock); @@ -1316,19 +1240,6 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) return ret; } -/* used after device configuration */ -static const struct file_operations ep0_io_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .read = ep0_read, - .write = ep0_write, - .fasync = ep0_fasync, - .poll = ep0_poll, - .unlocked_ioctl = dev_ioctl, - .release = dev_release, -}; - /*----------------------------------------------------------------------*/ /* The in-kernel gadget driver handles most ep0 issues, in particular @@ -1650,7 +1561,7 @@ static int activate_ep_files (struct dev_data *dev) goto enomem1; data->dentry = gadgetfs_create_file (dev->sb, data->name, - data, &ep_config_operations); + data, &ep_io_operations); if (!data->dentry) goto enomem2; list_add_tail (&data->epfiles, &dev->epfiles); @@ -1852,6 +1763,14 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) u32 tag; char *kbuf; + spin_lock_irq(&dev->lock); + if (dev->state > STATE_DEV_OPENED) { + value = ep0_write(fd, buf, len, ptr); + spin_unlock_irq(&dev->lock); + return value; + } + spin_unlock_irq(&dev->lock); + if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; @@ -1925,7 +1844,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) * on, they can work ... except in cleanup paths that * kick in after the ep0 descriptor is closed. */ - fd->f_op = &ep0_io_operations; value = len; } return value; @@ -1956,12 +1874,14 @@ dev_open (struct inode *inode, struct file *fd) return value; } -static const struct file_operations dev_init_operations = { +static const struct file_operations ep0_operations = { .llseek = no_llseek, .open = dev_open, + .read = ep0_read, .write = dev_config, .fasync = ep0_fasync, + .poll = ep0_poll, .unlocked_ioctl = dev_ioctl, .release = dev_release, }; @@ -2077,7 +1997,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) goto Enomem; dev->sb = sb; - dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &dev_init_operations); + dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations); if (!dev->dentry) { put_dev(dev); goto Enomem; diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 90545980542f..d5b6ee725a2a 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -12,29 +12,7 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/moduleparam.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/types.h> -#include <linux/ctype.h> -#include <linux/cdev.h> - #include <asm/byteorder.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/uaccess.h> -#include <asm/unaligned.h> #include <linux/usb/ch9.h> #include <linux/usb/composite.h> @@ -46,50 +24,12 @@ USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_DESC "Printer Gadget" -#define DRIVER_VERSION "2007 OCT 06" +#define DRIVER_VERSION "2015 FEB 17" -static DEFINE_MUTEX(printer_mutex); static const char shortname [] = "printer"; static const char driver_desc [] = DRIVER_DESC; -static dev_t g_printer_devno; - -static struct class *usb_gadget_class; - -/*-------------------------------------------------------------------------*/ - -struct printer_dev { - spinlock_t lock; /* lock this structure */ - /* lock buffer lists during read/write calls */ - struct mutex lock_printer_io; - struct usb_gadget *gadget; - s8 interface; - struct usb_ep *in_ep, *out_ep; - - struct list_head rx_reqs; /* List of free RX structs */ - struct list_head rx_reqs_active; /* List of Active RX xfers */ - struct list_head rx_buffers; /* List of completed xfers */ - /* wait until there is data to be read. */ - wait_queue_head_t rx_wait; - struct list_head tx_reqs; /* List of free TX structs */ - struct list_head tx_reqs_active; /* List of Active TX xfers */ - /* Wait until there are write buffers available to use. */ - wait_queue_head_t tx_wait; - /* Wait until all write buffers have been sent. */ - wait_queue_head_t tx_flush_wait; - struct usb_request *current_rx_req; - size_t current_rx_bytes; - u8 *current_rx_buf; - u8 printer_status; - u8 reset_printer; - struct cdev printer_cdev; - struct device *pdev; - u8 printer_cdev_open; - wait_queue_head_t wait; - struct usb_function function; -}; - -static struct printer_dev usb_printer_gadget; +#include "u_printer.h" /*-------------------------------------------------------------------------*/ @@ -120,6 +60,9 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR); #define QLEN qlen +static struct usb_function_instance *fi_printer; +static struct usb_function *f_printer; + /*-------------------------------------------------------------------------*/ /* @@ -127,10 +70,6 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR); * descriptors are built on demand. */ -/* holds our biggest descriptor */ -#define USB_DESC_BUFSIZE 256 -#define USB_BUFSIZE 8192 - static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, @@ -143,108 +82,6 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1 }; -static struct usb_interface_descriptor intf_desc = { - .bLength = sizeof intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_PRINTER, - .bInterfaceSubClass = 1, /* Printer Sub-Class */ - .bInterfaceProtocol = 2, /* Bi-Directional */ - .iInterface = 0 -}; - -static struct usb_endpoint_descriptor fs_ep_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK -}; - -static struct usb_endpoint_descriptor fs_ep_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK -}; - -static struct usb_descriptor_header *fs_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &fs_ep_in_desc, - (struct usb_descriptor_header *) &fs_ep_out_desc, - NULL -}; - -/* - * usb 2.0 devices need to expose both high speed and full speed - * descriptors, unless they only run at full speed. - */ - -static struct usb_endpoint_descriptor hs_ep_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512) -}; - -static struct usb_endpoint_descriptor hs_ep_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512) -}; - -static struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PRINTER, - .bNumConfigurations = 1 -}; - -static struct usb_descriptor_header *hs_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &hs_ep_in_desc, - (struct usb_descriptor_header *) &hs_ep_out_desc, - NULL -}; - -/* - * Added endpoint descriptors for 3.0 devices - */ - -static struct usb_endpoint_descriptor ss_ep_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = { - .bLength = sizeof(ss_ep_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, -}; - -static struct usb_endpoint_descriptor ss_ep_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { - .bLength = sizeof(ss_ep_out_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, -}; - -static struct usb_descriptor_header *ss_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &ss_ep_in_desc, - (struct usb_descriptor_header *) &ss_ep_in_comp_desc, - (struct usb_descriptor_header *) &ss_ep_out_desc, - (struct usb_descriptor_header *) &ss_ep_out_comp_desc, - NULL -}; - static struct usb_otg_descriptor otg_descriptor = { .bLength = sizeof otg_descriptor, .bDescriptorType = USB_DT_OTG, @@ -256,29 +93,13 @@ static const struct usb_descriptor_header *otg_desc[] = { NULL, }; -/* maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget, - struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *ss) -{ - switch (gadget->speed) { - case USB_SPEED_SUPER: - return ss; - case USB_SPEED_HIGH: - return hs; - default: - return fs; - } -} - /*-------------------------------------------------------------------------*/ /* descriptors that are built on-demand */ static char product_desc [40] = DRIVER_DESC; static char serial_num [40] = "1"; -static char pnp_string [1024] = +static char pnp_string[PNP_STRING_LEN] = "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; /* static strings, in UTF-8 */ @@ -299,921 +120,19 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; -/*-------------------------------------------------------------------------*/ - -static struct usb_request * -printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, gfp_flags); - - if (req != NULL) { - req->length = len; - req->buf = kmalloc(len, gfp_flags); - if (req->buf == NULL) { - usb_ep_free_request(ep, req); - return NULL; - } - } - - return req; -} - -static void -printer_req_free(struct usb_ep *ep, struct usb_request *req) -{ - if (ep != NULL && req != NULL) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -/*-------------------------------------------------------------------------*/ - -static void rx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct printer_dev *dev = ep->driver_data; - int status = req->status; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - - list_del_init(&req->list); /* Remode from Active List */ - - switch (status) { - - /* normal completion */ - case 0: - if (req->actual > 0) { - list_add_tail(&req->list, &dev->rx_buffers); - DBG(dev, "G_Printer : rx length %d\n", req->actual); - } else { - list_add(&req->list, &dev->rx_reqs); - } - break; - - /* software-driven interface shutdown */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - VDBG(dev, "rx shutdown, code %d\n", status); - list_add(&req->list, &dev->rx_reqs); - break; - - /* for hardware automagic (such as pxa) */ - case -ECONNABORTED: /* endpoint reset */ - DBG(dev, "rx %s reset\n", ep->name); - list_add(&req->list, &dev->rx_reqs); - break; - - /* data overrun */ - case -EOVERFLOW: - /* FALLTHROUGH */ - - default: - DBG(dev, "rx status %d\n", status); - list_add(&req->list, &dev->rx_reqs); - break; - } - - wake_up_interruptible(&dev->rx_wait); - spin_unlock_irqrestore(&dev->lock, flags); -} - -static void tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct printer_dev *dev = ep->driver_data; - - switch (req->status) { - default: - VDBG(dev, "tx err %d\n", req->status); - /* FALLTHROUGH */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - break; - case 0: - break; - } - - spin_lock(&dev->lock); - /* Take the request struct off the active list and put it on the - * free list. - */ - list_del_init(&req->list); - list_add(&req->list, &dev->tx_reqs); - wake_up_interruptible(&dev->tx_wait); - if (likely(list_empty(&dev->tx_reqs_active))) - wake_up_interruptible(&dev->tx_flush_wait); - - spin_unlock(&dev->lock); -} - -/*-------------------------------------------------------------------------*/ - -static int -printer_open(struct inode *inode, struct file *fd) -{ - struct printer_dev *dev; - unsigned long flags; - int ret = -EBUSY; - - mutex_lock(&printer_mutex); - dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); - - spin_lock_irqsave(&dev->lock, flags); - - if (!dev->printer_cdev_open) { - dev->printer_cdev_open = 1; - fd->private_data = dev; - ret = 0; - /* Change the printer status to show that it's on-line. */ - dev->printer_status |= PRINTER_SELECTED; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - DBG(dev, "printer_open returned %x\n", ret); - mutex_unlock(&printer_mutex); - return ret; -} - -static int -printer_close(struct inode *inode, struct file *fd) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - dev->printer_cdev_open = 0; - fd->private_data = NULL; - /* Change printer status to show that the printer is off-line. */ - dev->printer_status &= ~PRINTER_SELECTED; - spin_unlock_irqrestore(&dev->lock, flags); - - DBG(dev, "printer_close\n"); - - return 0; -} - -/* This function must be called with interrupts turned off. */ -static void -setup_rx_reqs(struct printer_dev *dev) -{ - struct usb_request *req; - - while (likely(!list_empty(&dev->rx_reqs))) { - int error; - - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del_init(&req->list); - - /* The USB Host sends us whatever amount of data it wants to - * so we always set the length field to the full USB_BUFSIZE. - * If the amount of data is more than the read() caller asked - * for it will be stored in the request buffer until it is - * asked for by read(). - */ - req->length = USB_BUFSIZE; - req->complete = rx_complete; - - /* here, we unlock, and only unlock, to avoid deadlock. */ - spin_unlock(&dev->lock); - error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); - spin_lock(&dev->lock); - if (error) { - DBG(dev, "rx submit --> %d\n", error); - list_add(&req->list, &dev->rx_reqs); - break; - } - /* if the req is empty, then add it into dev->rx_reqs_active. */ - else if (list_empty(&req->list)) { - list_add(&req->list, &dev->rx_reqs_active); - } - } -} - -static ssize_t -printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - size_t size; - size_t bytes_copied; - struct usb_request *req; - /* This is a pointer to the current USB rx request. */ - struct usb_request *current_rx_req; - /* This is the number of bytes in the current rx buffer. */ - size_t current_rx_bytes; - /* This is a pointer to the current rx buffer. */ - u8 *current_rx_buf; - - if (len == 0) - return -EINVAL; - - DBG(dev, "printer_read trying to read %d bytes\n", (int)len); - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - - /* We will use this flag later to check if a printer reset happened - * after we turn interrupts back on. - */ - dev->reset_printer = 0; - - setup_rx_reqs(dev); - - bytes_copied = 0; - current_rx_req = dev->current_rx_req; - current_rx_bytes = dev->current_rx_bytes; - current_rx_buf = dev->current_rx_buf; - dev->current_rx_req = NULL; - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - - /* Check if there is any data in the read buffers. Please note that - * current_rx_bytes is the number of bytes in the current rx buffer. - * If it is zero then check if there are any other rx_buffers that - * are on the completed list. We are only out of data if all rx - * buffers are empty. - */ - if ((current_rx_bytes == 0) && - (likely(list_empty(&dev->rx_buffers)))) { - /* Turn interrupts back on before sleeping. */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* - * If no data is available check if this is a NON-Blocking - * call or not. - */ - if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* Sleep until data is available */ - wait_event_interruptible(dev->rx_wait, - (likely(!list_empty(&dev->rx_buffers)))); - spin_lock_irqsave(&dev->lock, flags); - } - - /* We have data to return then copy it to the caller's buffer.*/ - while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) - && len) { - if (current_rx_bytes == 0) { - req = container_of(dev->rx_buffers.next, - struct usb_request, list); - list_del_init(&req->list); - - if (req->actual && req->buf) { - current_rx_req = req; - current_rx_bytes = req->actual; - current_rx_buf = req->buf; - } else { - list_add(&req->list, &dev->rx_reqs); - continue; - } - } - - /* Don't leave irqs off while doing memory copies */ - spin_unlock_irqrestore(&dev->lock, flags); - - if (len > current_rx_bytes) - size = current_rx_bytes; - else - size = len; - - size -= copy_to_user(buf, current_rx_buf, size); - bytes_copied += size; - len -= size; - buf += size; - - spin_lock_irqsave(&dev->lock, flags); - - /* We've disconnected or reset so return. */ - if (dev->reset_printer) { - list_add(¤t_rx_req->list, &dev->rx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* If we not returning all the data left in this RX request - * buffer then adjust the amount of data left in the buffer. - * Othewise if we are done with this RX request buffer then - * requeue it to get any incoming data from the USB host. - */ - if (size < current_rx_bytes) { - current_rx_bytes -= size; - current_rx_buf += size; - } else { - list_add(¤t_rx_req->list, &dev->rx_reqs); - current_rx_bytes = 0; - current_rx_buf = NULL; - current_rx_req = NULL; - } - } - - dev->current_rx_req = current_rx_req; - dev->current_rx_bytes = current_rx_bytes; - dev->current_rx_buf = current_rx_buf; - - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); - - if (bytes_copied) - return bytes_copied; - else - return -EAGAIN; -} - -static ssize_t -printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - size_t size; /* Amount of data in a TX request. */ - size_t bytes_copied = 0; - struct usb_request *req; - - DBG(dev, "printer_write trying to send %d bytes\n", (int)len); - - if (len == 0) - return -EINVAL; - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - - /* Check if a printer reset happens while we have interrupts on */ - dev->reset_printer = 0; - - /* Check if there is any available write buffers */ - if (likely(list_empty(&dev->tx_reqs))) { - /* Turn interrupts back on before sleeping. */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* - * If write buffers are available check if this is - * a NON-Blocking call or not. - */ - if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* Sleep until a write buffer is available */ - wait_event_interruptible(dev->tx_wait, - (likely(!list_empty(&dev->tx_reqs)))); - spin_lock_irqsave(&dev->lock, flags); - } - - while (likely(!list_empty(&dev->tx_reqs)) && len) { - - if (len > USB_BUFSIZE) - size = USB_BUFSIZE; - else - size = len; - - req = container_of(dev->tx_reqs.next, struct usb_request, - list); - list_del_init(&req->list); - - req->complete = tx_complete; - req->length = size; - - /* Check if we need to send a zero length packet. */ - if (len > size) - /* They will be more TX requests so no yet. */ - req->zero = 0; - else - /* If the data amount is not a multple of the - * maxpacket size then send a zero length packet. - */ - req->zero = ((len % dev->in_ep->maxpacket) == 0); - - /* Don't leave irqs off while doing memory copies */ - spin_unlock_irqrestore(&dev->lock, flags); - - if (copy_from_user(req->buf, buf, size)) { - list_add(&req->list, &dev->tx_reqs); - mutex_unlock(&dev->lock_printer_io); - return bytes_copied; - } - - bytes_copied += size; - len -= size; - buf += size; - - spin_lock_irqsave(&dev->lock, flags); - - /* We've disconnected or reset so free the req and buffer */ - if (dev->reset_printer) { - list_add(&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { - list_add(&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - list_add(&req->list, &dev->tx_reqs_active); - - } - - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); - - if (bytes_copied) { - return bytes_copied; - } else { - return -EAGAIN; - } -} - -static int -printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) -{ - struct printer_dev *dev = fd->private_data; - struct inode *inode = file_inode(fd); - unsigned long flags; - int tx_list_empty; - - mutex_lock(&inode->i_mutex); - spin_lock_irqsave(&dev->lock, flags); - tx_list_empty = (likely(list_empty(&dev->tx_reqs))); - spin_unlock_irqrestore(&dev->lock, flags); - - if (!tx_list_empty) { - /* Sleep until all data has been sent */ - wait_event_interruptible(dev->tx_flush_wait, - (likely(list_empty(&dev->tx_reqs_active)))); - } - mutex_unlock(&inode->i_mutex); - - return 0; -} - -static unsigned int -printer_poll(struct file *fd, poll_table *wait) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - int status = 0; - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - setup_rx_reqs(dev); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - poll_wait(fd, &dev->rx_wait, wait); - poll_wait(fd, &dev->tx_wait, wait); - - spin_lock_irqsave(&dev->lock, flags); - if (likely(!list_empty(&dev->tx_reqs))) - status |= POLLOUT | POLLWRNORM; - - if (likely(dev->current_rx_bytes) || - likely(!list_empty(&dev->rx_buffers))) - status |= POLLIN | POLLRDNORM; - - spin_unlock_irqrestore(&dev->lock, flags); - - return status; -} - -static long -printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - int status = 0; - - DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); - - /* handle ioctls */ - - spin_lock_irqsave(&dev->lock, flags); - - switch (code) { - case GADGET_GET_PRINTER_STATUS: - status = (int)dev->printer_status; - break; - case GADGET_SET_PRINTER_STATUS: - dev->printer_status = (u8)arg; - break; - default: - /* could not handle ioctl */ - DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n", - code); - status = -ENOTTY; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return status; -} - -/* used after endpoint configuration */ -static const struct file_operations printer_io_operations = { - .owner = THIS_MODULE, - .open = printer_open, - .read = printer_read, - .write = printer_write, - .fsync = printer_fsync, - .poll = printer_poll, - .unlocked_ioctl = printer_ioctl, - .release = printer_close, - .llseek = noop_llseek, -}; - -/*-------------------------------------------------------------------------*/ - -static int -set_printer_interface(struct printer_dev *dev) -{ - int result = 0; - - dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc, - &ss_ep_in_desc); - dev->in_ep->driver_data = dev; - - dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc, - &hs_ep_out_desc, &ss_ep_out_desc); - dev->out_ep->driver_data = dev; - - result = usb_ep_enable(dev->in_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - - result = usb_ep_enable(dev->out_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - -done: - /* on error, disable any endpoints */ - if (result != 0) { - (void) usb_ep_disable(dev->in_ep); - (void) usb_ep_disable(dev->out_ep); - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - } - - /* caller is responsible for cleanup on error */ - return result; -} - -static void printer_reset_interface(struct printer_dev *dev) -{ - if (dev->interface < 0) - return; - - DBG(dev, "%s\n", __func__); - - if (dev->in_ep->desc) - usb_ep_disable(dev->in_ep); - - if (dev->out_ep->desc) - usb_ep_disable(dev->out_ep); - - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - dev->interface = -1; -} - -/* Change our operational Interface. */ -static int set_interface(struct printer_dev *dev, unsigned number) -{ - int result = 0; - - /* Free the current interface */ - printer_reset_interface(dev); - - result = set_printer_interface(dev); - if (result) - printer_reset_interface(dev); - else - dev->interface = number; - - if (!result) - INFO(dev, "Using interface %x\n", number); - - return result; -} - -static void printer_soft_reset(struct printer_dev *dev) -{ - struct usb_request *req; - - INFO(dev, "Received Printer Reset Request\n"); - - if (usb_ep_disable(dev->in_ep)) - DBG(dev, "Failed to disable USB in_ep\n"); - if (usb_ep_disable(dev->out_ep)) - DBG(dev, "Failed to disable USB out_ep\n"); - - if (dev->current_rx_req != NULL) { - list_add(&dev->current_rx_req->list, &dev->rx_reqs); - dev->current_rx_req = NULL; - } - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - dev->reset_printer = 1; - - while (likely(!(list_empty(&dev->rx_buffers)))) { - req = container_of(dev->rx_buffers.next, struct usb_request, - list); - list_del_init(&req->list); - list_add(&req->list, &dev->rx_reqs); - } - - while (likely(!(list_empty(&dev->rx_reqs_active)))) { - req = container_of(dev->rx_buffers.next, struct usb_request, - list); - list_del_init(&req->list); - list_add(&req->list, &dev->rx_reqs); - } - - while (likely(!(list_empty(&dev->tx_reqs_active)))) { - req = container_of(dev->tx_reqs_active.next, - struct usb_request, list); - list_del_init(&req->list); - list_add(&req->list, &dev->tx_reqs); - } - - if (usb_ep_enable(dev->in_ep)) - DBG(dev, "Failed to enable USB in_ep\n"); - if (usb_ep_enable(dev->out_ep)) - DBG(dev, "Failed to enable USB out_ep\n"); - - wake_up_interruptible(&dev->rx_wait); - wake_up_interruptible(&dev->tx_wait); - wake_up_interruptible(&dev->tx_flush_wait); -} - -/*-------------------------------------------------------------------------*/ - -/* - * The setup() callback implements all the ep0 functionality that's not - * handled lower down. - */ -static int printer_func_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct printer_dev *dev = container_of(f, struct printer_dev, function); - struct usb_composite_dev *cdev = f->config->cdev; - struct usb_request *req = cdev->req; - int value = -EOPNOTSUPP; - u16 wIndex = le16_to_cpu(ctrl->wIndex); - u16 wValue = le16_to_cpu(ctrl->wValue); - u16 wLength = le16_to_cpu(ctrl->wLength); - - DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); - - switch (ctrl->bRequestType&USB_TYPE_MASK) { - case USB_TYPE_CLASS: - switch (ctrl->bRequest) { - case 0: /* Get the IEEE-1284 PNP String */ - /* Only one printer interface is supported. */ - if ((wIndex>>8) != dev->interface) - break; - - value = (pnp_string[0]<<8)|pnp_string[1]; - memcpy(req->buf, pnp_string, value); - DBG(dev, "1284 PNP String: %x %s\n", value, - &pnp_string[2]); - break; - - case 1: /* Get Port Status */ - /* Only one printer interface is supported. */ - if (wIndex != dev->interface) - break; - - *(u8 *)req->buf = dev->printer_status; - value = min(wLength, (u16) 1); - break; - - case 2: /* Soft Reset */ - /* Only one printer interface is supported. */ - if (wIndex != dev->interface) - break; - - printer_soft_reset(dev); - - value = 0; - break; - - default: - goto unknown; - } - break; - - default: -unknown: - VDBG(dev, - "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - wValue, wIndex, wLength); - break; - } - /* host either stalls (value < 0) or reports success */ - return value; -} - -static int __init printer_func_bind(struct usb_configuration *c, - struct usb_function *f) -{ - struct printer_dev *dev = container_of(f, struct printer_dev, function); - struct usb_composite_dev *cdev = c->cdev; - struct usb_ep *in_ep; - struct usb_ep *out_ep = NULL; - int id; - int ret; - - id = usb_interface_id(c, f); - if (id < 0) - return id; - intf_desc.bInterfaceNumber = id; - - /* all we really need is bulk IN/OUT */ - in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc); - if (!in_ep) { -autoconf_fail: - dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n", - cdev->gadget->name); - return -ENODEV; - } - in_ep->driver_data = in_ep; /* claim */ - - out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc); - if (!out_ep) - goto autoconf_fail; - out_ep->driver_data = out_ep; /* claim */ - - /* assumes that all endpoints are dual-speed */ - hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; - ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; - - ret = usb_assign_descriptors(f, fs_printer_function, - hs_printer_function, ss_printer_function); - if (ret) - return ret; - - dev->in_ep = in_ep; - dev->out_ep = out_ep; - return 0; -} - -static void printer_func_unbind(struct usb_configuration *c, - struct usb_function *f) -{ - usb_free_all_descriptors(f); -} - -static int printer_func_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct printer_dev *dev = container_of(f, struct printer_dev, function); - int ret = -ENOTSUPP; - - if (!alt) - ret = set_interface(dev, intf); - - return ret; -} - -static void printer_func_disable(struct usb_function *f) -{ - struct printer_dev *dev = container_of(f, struct printer_dev, function); - unsigned long flags; - - DBG(dev, "%s\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - printer_reset_interface(dev); - spin_unlock_irqrestore(&dev->lock, flags); -} - -static void printer_cfg_unbind(struct usb_configuration *c) -{ - struct printer_dev *dev; - struct usb_request *req; - - dev = &usb_printer_gadget; - - DBG(dev, "%s\n", __func__); - - /* Remove sysfs files */ - device_destroy(usb_gadget_class, g_printer_devno); - - /* Remove Character Device */ - cdev_del(&dev->printer_cdev); - - /* we must already have been disconnected ... no i/o may be active */ - WARN_ON(!list_empty(&dev->tx_reqs_active)); - WARN_ON(!list_empty(&dev->rx_reqs_active)); - - /* Free all memory for this driver. */ - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, struct usb_request, - list); - list_del(&req->list); - printer_req_free(dev->in_ep, req); - } - - if (dev->current_rx_req != NULL) - printer_req_free(dev->out_ep, dev->current_rx_req); - - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - - while (!list_empty(&dev->rx_buffers)) { - req = container_of(dev->rx_buffers.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } -} - static struct usb_configuration printer_cfg_driver = { .label = "printer", - .unbind = printer_cfg_unbind, .bConfigurationValue = 1, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, }; -static int __init printer_bind_config(struct usb_configuration *c) +static int __init printer_do_config(struct usb_configuration *c) { struct usb_gadget *gadget = c->cdev->gadget; - struct printer_dev *dev; - int status = -ENOMEM; - size_t len; - u32 i; - struct usb_request *req; + int status = 0; usb_ep_autoconfig_reset(gadget); - dev = &usb_printer_gadget; - - dev->function.name = shortname; - dev->function.bind = printer_func_bind; - dev->function.setup = printer_func_setup; - dev->function.unbind = printer_func_unbind; - dev->function.set_alt = printer_func_set_alt; - dev->function.disable = printer_func_disable; - - status = usb_add_function(c, &dev->function); - if (status) - return status; - - /* Setup the sysfs files for the printer gadget. */ - dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, - NULL, "g_printer"); - if (IS_ERR(dev->pdev)) { - ERROR(dev, "Failed to create device: g_printer\n"); - status = PTR_ERR(dev->pdev); - goto fail; - } - - /* - * Register a character device as an interface to a user mode - * program that handles the printer specific functionality. - */ - cdev_init(&dev->printer_cdev, &printer_io_operations); - dev->printer_cdev.owner = THIS_MODULE; - status = cdev_add(&dev->printer_cdev, g_printer_devno, 1); - if (status) { - ERROR(dev, "Failed to open char device\n"); - goto fail; - } - - if (iPNPstring) - strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); - - len = strlen(pnp_string); - pnp_string[0] = (len >> 8) & 0xFF; - pnp_string[1] = len & 0xFF; - usb_gadget_set_selfpowered(gadget); if (gadget_is_otg(gadget)) { @@ -1222,86 +141,64 @@ static int __init printer_bind_config(struct usb_configuration *c) printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - spin_lock_init(&dev->lock); - mutex_init(&dev->lock_printer_io); - INIT_LIST_HEAD(&dev->tx_reqs); - INIT_LIST_HEAD(&dev->tx_reqs_active); - INIT_LIST_HEAD(&dev->rx_reqs); - INIT_LIST_HEAD(&dev->rx_reqs_active); - INIT_LIST_HEAD(&dev->rx_buffers); - init_waitqueue_head(&dev->rx_wait); - init_waitqueue_head(&dev->tx_wait); - init_waitqueue_head(&dev->tx_flush_wait); - - dev->interface = -1; - dev->printer_cdev_open = 0; - dev->printer_status = PRINTER_NOT_ERROR; - dev->current_rx_req = NULL; - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - - for (i = 0; i < QLEN; i++) { - req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); - if (!req) { - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->in_ep, req); - } - return -ENOMEM; - } - list_add(&req->list, &dev->tx_reqs); - } - - for (i = 0; i < QLEN; i++) { - req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL); - if (!req) { - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - return -ENOMEM; - } - list_add(&req->list, &dev->rx_reqs); - } - - /* finish hookup to lower layer ... */ - dev->gadget = gadget; + f_printer = usb_get_function(fi_printer); + if (IS_ERR(f_printer)) + return PTR_ERR(f_printer); - INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); - return 0; + status = usb_add_function(c, f_printer); + if (status < 0) + usb_put_function(f_printer); -fail: - printer_cfg_unbind(c); return status; } -static int printer_unbind(struct usb_composite_dev *cdev) -{ - return 0; -} - static int __init printer_bind(struct usb_composite_dev *cdev) { - int ret; + struct f_printer_opts *opts; + int ret, len; + + fi_printer = usb_get_function_instance("printer"); + if (IS_ERR(fi_printer)) + return PTR_ERR(fi_printer); + + if (iPNPstring) + strlcpy(&pnp_string[2], iPNPstring, PNP_STRING_LEN - 2); + + len = strlen(pnp_string); + pnp_string[0] = (len >> 8) & 0xFF; + pnp_string[1] = len & 0xFF; + + opts = container_of(fi_printer, struct f_printer_opts, func_inst); + opts->minor = 0; + memcpy(opts->pnp_string, pnp_string, PNP_STRING_LEN); + opts->q_len = QLEN; ret = usb_string_ids_tab(cdev, strings); - if (ret < 0) + if (ret < 0) { + usb_put_function_instance(fi_printer); return ret; + } device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; - ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config); - if (ret) + ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); + if (ret) { + usb_put_function_instance(fi_printer); return ret; + } usb_composite_overwrite_options(cdev, &coverwrite); return ret; } +static int __exit printer_unbind(struct usb_composite_dev *cdev) +{ + usb_put_function(f_printer); + usb_put_function_instance(fi_printer); + + return 0; +} + static __refdata struct usb_composite_driver printer_driver = { .name = shortname, .dev = &device_desc, @@ -1311,47 +208,7 @@ static __refdata struct usb_composite_driver printer_driver = { .unbind = printer_unbind, }; -static int __init -init(void) -{ - int status; - - usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); - if (IS_ERR(usb_gadget_class)) { - status = PTR_ERR(usb_gadget_class); - pr_err("unable to create usb_gadget class %d\n", status); - return status; - } - - status = alloc_chrdev_region(&g_printer_devno, 0, 1, - "USB printer gadget"); - if (status) { - pr_err("alloc_chrdev_region %d\n", status); - class_destroy(usb_gadget_class); - return status; - } - - status = usb_composite_probe(&printer_driver); - if (status) { - class_destroy(usb_gadget_class); - unregister_chrdev_region(g_printer_devno, 1); - pr_err("usb_gadget_probe_driver %x\n", status); - } - - return status; -} -module_init(init); - -static void __exit -cleanup(void) -{ - mutex_lock(&usb_printer_gadget.lock_printer_io); - usb_composite_unregister(&printer_driver); - unregister_chrdev_region(g_printer_devno, 1); - class_destroy(usb_gadget_class); - mutex_unlock(&usb_printer_gadget.lock_printer_io); -} -module_exit(cleanup); +module_usb_composite_driver(printer_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Craig Nadler"); diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 3a494168661e..6e0a019aad54 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) goto err_session; } /* - * Now register the TCM vHost virtual I_T Nexus as active with the - * call to __transport_register_session() + * Now register the TCM vHost virtual I_T Nexus as active. */ - __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, + transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, tv_nexus->tvn_se_sess, tv_nexus); tpg->tpg_nexus = tv_nexus; mutex_unlock(&tpg->tpg_mutex); diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c index ff97ac93ac03..5ee95152493c 100644 --- a/drivers/usb/gadget/legacy/zero.c +++ b/drivers/usb/gadget/legacy/zero.c @@ -68,8 +68,6 @@ static struct usb_zero_options gzero_options = { .isoc_maxpacket = GZERO_ISOC_MAXPACKET, .bulk_buflen = GZERO_BULK_BUFLEN, .qlen = GZERO_QLEN, - .int_interval = GZERO_INT_INTERVAL, - .int_maxpacket = GZERO_INT_MAXPACKET, }; /*-------------------------------------------------------------------------*/ @@ -268,21 +266,6 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); -module_param_named(int_interval, gzero_options.int_interval, uint, - S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(int_interval, "1 - 16"); - -module_param_named(int_maxpacket, gzero_options.int_maxpacket, uint, - S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(int_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); - -module_param_named(int_mult, gzero_options.int_mult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(int_mult, "0 - 2 (hs/ss only)"); - -module_param_named(int_maxburst, gzero_options.int_maxburst, uint, - S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(int_maxburst, "0 - 15 (ss only)"); - static struct usb_function *func_lb; static struct usb_function_instance *func_inst_lb; @@ -318,10 +301,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev) ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; ss_opts->isoc_mult = gzero_options.isoc_mult; ss_opts->isoc_maxburst = gzero_options.isoc_maxburst; - ss_opts->int_interval = gzero_options.int_interval; - ss_opts->int_maxpacket = gzero_options.int_maxpacket; - ss_opts->int_mult = gzero_options.int_mult; - ss_opts->int_maxburst = gzero_options.int_maxburst; ss_opts->bulk_buflen = gzero_options.bulk_buflen; func_ss = usb_get_function(func_inst_ss); diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index d79cb35dbf8a..4c01953a0869 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -152,7 +152,7 @@ static int regs_dbg_open(struct inode *inode, struct file *file) spin_lock_irq(&udc->lock); for (i = 0; i < inode->i_size / 4; i++) - data[i] = __raw_readl(udc->regs + i * 4); + data[i] = usba_io_readl(udc->regs + i * 4); spin_unlock_irq(&udc->lock); file->private_data = data; @@ -1249,7 +1249,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, if (crq->wLength != cpu_to_le16(sizeof(status))) goto stall; ep->state = DATA_STAGE_IN; - __raw_writew(status, ep->fifo); + usba_io_writew(status, ep->fifo); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); break; } @@ -1739,7 +1739,72 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) return IRQ_HANDLED; } -static irqreturn_t usba_vbus_irq(int irq, void *devid) +static int start_clock(struct usba_udc *udc) +{ + int ret; + + if (udc->clocked) + return 0; + + ret = clk_prepare_enable(udc->pclk); + if (ret) + return ret; + ret = clk_prepare_enable(udc->hclk); + if (ret) { + clk_disable_unprepare(udc->pclk); + return ret; + } + + udc->clocked = true; + return 0; +} + +static void stop_clock(struct usba_udc *udc) +{ + if (!udc->clocked) + return; + + clk_disable_unprepare(udc->hclk); + clk_disable_unprepare(udc->pclk); + + udc->clocked = false; +} + +static int usba_start(struct usba_udc *udc) +{ + unsigned long flags; + int ret; + + ret = start_clock(udc); + if (ret) + return ret; + + spin_lock_irqsave(&udc->lock, flags); + toggle_bias(udc, 1); + usba_writel(udc, CTRL, USBA_ENABLE_MASK); + usba_int_enb_set(udc, USBA_END_OF_RESET); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static void usba_stop(struct usba_udc *udc) +{ + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + + /* This will also disable the DP pullup */ + toggle_bias(udc, 0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); + spin_unlock_irqrestore(&udc->lock, flags); + + stop_clock(udc); +} + +static irqreturn_t usba_vbus_irq_thread(int irq, void *devid) { struct usba_udc *udc = devid; int vbus; @@ -1747,35 +1812,22 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) /* debounce */ udelay(10); - spin_lock(&udc->lock); - - /* May happen if Vbus pin toggles during probe() */ - if (!udc->driver) - goto out; + mutex_lock(&udc->vbus_mutex); vbus = vbus_is_present(udc); if (vbus != udc->vbus_prev) { if (vbus) { - toggle_bias(udc, 1); - usba_writel(udc, CTRL, USBA_ENABLE_MASK); - usba_int_enb_set(udc, USBA_END_OF_RESET); + usba_start(udc); } else { - udc->gadget.speed = USB_SPEED_UNKNOWN; - reset_all_endpoints(udc); - toggle_bias(udc, 0); - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - if (udc->driver->disconnect) { - spin_unlock(&udc->lock); + usba_stop(udc); + + if (udc->driver->disconnect) udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } } udc->vbus_prev = vbus; } -out: - spin_unlock(&udc->lock); - + mutex_unlock(&udc->vbus_mutex); return IRQ_HANDLED; } @@ -1787,55 +1839,47 @@ static int atmel_usba_start(struct usb_gadget *gadget, unsigned long flags; spin_lock_irqsave(&udc->lock, flags); - udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; spin_unlock_irqrestore(&udc->lock, flags); - ret = clk_prepare_enable(udc->pclk); - if (ret) - return ret; - ret = clk_prepare_enable(udc->hclk); - if (ret) { - clk_disable_unprepare(udc->pclk); - return ret; - } + mutex_lock(&udc->vbus_mutex); - udc->vbus_prev = 0; if (gpio_is_valid(udc->vbus_pin)) enable_irq(gpio_to_irq(udc->vbus_pin)); /* If Vbus is present, enable the controller and wait for reset */ - spin_lock_irqsave(&udc->lock, flags); - if (vbus_is_present(udc) && udc->vbus_prev == 0) { - toggle_bias(udc, 1); - usba_writel(udc, CTRL, USBA_ENABLE_MASK); - usba_int_enb_set(udc, USBA_END_OF_RESET); + udc->vbus_prev = vbus_is_present(udc); + if (udc->vbus_prev) { + ret = usba_start(udc); + if (ret) + goto err; } - spin_unlock_irqrestore(&udc->lock, flags); + mutex_unlock(&udc->vbus_mutex); return 0; + +err: + if (gpio_is_valid(udc->vbus_pin)) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + mutex_unlock(&udc->vbus_mutex); + + spin_lock_irqsave(&udc->lock, flags); + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + udc->driver = NULL; + spin_unlock_irqrestore(&udc->lock, flags); + return ret; } static int atmel_usba_stop(struct usb_gadget *gadget) { struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); - unsigned long flags; if (gpio_is_valid(udc->vbus_pin)) disable_irq(gpio_to_irq(udc->vbus_pin)); - spin_lock_irqsave(&udc->lock, flags); - udc->gadget.speed = USB_SPEED_UNKNOWN; - reset_all_endpoints(udc); - spin_unlock_irqrestore(&udc->lock, flags); - - /* This will also disable the DP pullup */ - toggle_bias(udc, 0); - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - - clk_disable_unprepare(udc->hclk); - clk_disable_unprepare(udc->pclk); + usba_stop(udc); udc->driver = NULL; @@ -2057,6 +2101,7 @@ static int usba_udc_probe(struct platform_device *pdev) return PTR_ERR(hclk); spin_lock_init(&udc->lock); + mutex_init(&udc->vbus_mutex); udc->pdev = pdev; udc->pclk = pclk; udc->hclk = hclk; @@ -2111,17 +2156,17 @@ static int usba_udc_probe(struct platform_device *pdev) if (gpio_is_valid(udc->vbus_pin)) { if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) { - ret = devm_request_irq(&pdev->dev, - gpio_to_irq(udc->vbus_pin), - usba_vbus_irq, 0, + irq_set_status_flags(gpio_to_irq(udc->vbus_pin), + IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(&pdev->dev, + gpio_to_irq(udc->vbus_pin), NULL, + usba_vbus_irq_thread, IRQF_ONESHOT, "atmel_usba_udc", udc); if (ret) { udc->vbus_pin = -ENODEV; dev_warn(&udc->pdev->dev, "failed to request vbus irq; " "assuming always on\n"); - } else { - disable_irq(gpio_to_irq(udc->vbus_pin)); } } else { /* gpio_request fail so use -EINVAL for gpio_is_valid */ @@ -2132,6 +2177,7 @@ static int usba_udc_probe(struct platform_device *pdev) ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (ret) return ret; + device_init_wakeup(&pdev->dev, 1); usba_init_debugfs(udc); for (i = 1; i < udc->num_ep; i++) @@ -2147,6 +2193,7 @@ static int __exit usba_udc_remove(struct platform_device *pdev) udc = platform_get_drvdata(pdev); + device_init_wakeup(&pdev->dev, 0); usb_del_gadget_udc(&udc->gadget); for (i = 1; i < udc->num_ep; i++) @@ -2156,10 +2203,65 @@ static int __exit usba_udc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int usba_udc_suspend(struct device *dev) +{ + struct usba_udc *udc = dev_get_drvdata(dev); + + /* Not started */ + if (!udc->driver) + return 0; + + mutex_lock(&udc->vbus_mutex); + + if (!device_may_wakeup(dev)) { + usba_stop(udc); + goto out; + } + + /* + * Device may wake up. We stay clocked if we failed + * to request vbus irq, assuming always on. + */ + if (gpio_is_valid(udc->vbus_pin)) { + usba_stop(udc); + enable_irq_wake(gpio_to_irq(udc->vbus_pin)); + } + +out: + mutex_unlock(&udc->vbus_mutex); + return 0; +} + +static int usba_udc_resume(struct device *dev) +{ + struct usba_udc *udc = dev_get_drvdata(dev); + + /* Not started */ + if (!udc->driver) + return 0; + + if (device_may_wakeup(dev) && gpio_is_valid(udc->vbus_pin)) + disable_irq_wake(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + mutex_lock(&udc->vbus_mutex); + udc->vbus_prev = vbus_is_present(udc); + if (udc->vbus_prev) + usba_start(udc); + mutex_unlock(&udc->vbus_mutex); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume); + static struct platform_driver udc_driver = { .remove = __exit_p(usba_udc_remove), .driver = { .name = "atmel_usba_udc", + .pm = &usba_udc_pm_ops, .of_match_table = of_match_ptr(atmel_udc_dt_ids), }, }; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index 497cd18836f3..ea448a344767 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h @@ -191,18 +191,28 @@ | USBA_BF(name, value)) /* Register access macros */ +#ifdef CONFIG_AVR32 +#define usba_io_readl __raw_readl +#define usba_io_writel __raw_writel +#define usba_io_writew __raw_writew +#else +#define usba_io_readl readl_relaxed +#define usba_io_writel writel_relaxed +#define usba_io_writew writew_relaxed +#endif + #define usba_readl(udc, reg) \ - __raw_readl((udc)->regs + USBA_##reg) + usba_io_readl((udc)->regs + USBA_##reg) #define usba_writel(udc, reg, value) \ - __raw_writel((value), (udc)->regs + USBA_##reg) + usba_io_writel((value), (udc)->regs + USBA_##reg) #define usba_ep_readl(ep, reg) \ - __raw_readl((ep)->ep_regs + USBA_EPT_##reg) + usba_io_readl((ep)->ep_regs + USBA_EPT_##reg) #define usba_ep_writel(ep, reg, value) \ - __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) + usba_io_writel((value), (ep)->ep_regs + USBA_EPT_##reg) #define usba_dma_readl(ep, reg) \ - __raw_readl((ep)->dma_regs + USBA_DMA_##reg) + usba_io_readl((ep)->dma_regs + USBA_DMA_##reg) #define usba_dma_writel(ep, reg, value) \ - __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + usba_io_writel((value), (ep)->dma_regs + USBA_DMA_##reg) /* Calculate base address for a given endpoint or DMA controller */ #define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) @@ -313,6 +323,9 @@ struct usba_udc { /* Protect hw registers from concurrent modifications */ spinlock_t lock; + /* Mutex to prevent concurrent start or stop */ + struct mutex vbus_mutex; + void __iomem *regs; void __iomem *fifo; @@ -328,6 +341,7 @@ struct usba_udc { struct clk *hclk; struct usba_ep *usba_ep; bool bias_pulse_needed; + bool clocked; u16 devstatus; diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 8dda48445f6f..181112c88f43 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1923,7 +1923,7 @@ static inline void ss_hub_descriptor(struct usb_hub_descriptor *desc) { memset(desc, 0, sizeof *desc); - desc->bDescriptorType = 0x2a; + desc->bDescriptorType = USB_DT_SS_HUB; desc->bDescLength = 12; desc->wHubCharacteristics = cpu_to_le16( HUB_CHAR_INDV_PORT_LPSM | @@ -1936,7 +1936,7 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc) static inline void hub_descriptor(struct usb_hub_descriptor *desc) { memset(desc, 0, sizeof *desc); - desc->bDescriptorType = 0x29; + desc->bDescriptorType = USB_DT_HUB; desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16( HUB_CHAR_INDV_PORT_LPSM | @@ -2631,7 +2631,7 @@ static int __init init(void) return -EINVAL; if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) { - pr_err("Number of emulated UDC must be in range of 1…%d\n", + pr_err("Number of emulated UDC must be in range of 1...%d\n", MAX_NUM_UDC); return -EINVAL; } diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 5b9176e7202a..9e8d842e8c08 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1024,35 +1024,79 @@ static const char proc_node_name [] = "driver/udc"; static void dump_intmask(struct seq_file *m, const char *label, u32 mask) { /* int_status is the same format ... */ - seq_printf(m, - "%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n", - label, mask, - (mask & INT_PWRDETECT) ? " power" : "", - (mask & INT_SYSERROR) ? " sys" : "", - (mask & INT_MSTRDEND) ? " in-dma" : "", - (mask & INT_MSTWRTMOUT) ? " wrtmo" : "", - - (mask & INT_MSTWREND) ? " out-dma" : "", - (mask & INT_MSTWRSET) ? " wrset" : "", - (mask & INT_ERR) ? " err" : "", - (mask & INT_SOF) ? " sof" : "", - - (mask & INT_EP3NAK) ? " ep3nak" : "", - (mask & INT_EP2NAK) ? " ep2nak" : "", - (mask & INT_EP1NAK) ? " ep1nak" : "", - (mask & INT_EP3DATASET) ? " ep3" : "", - - (mask & INT_EP2DATASET) ? " ep2" : "", - (mask & INT_EP1DATASET) ? " ep1" : "", - (mask & INT_STATUSNAK) ? " ep0snak" : "", - (mask & INT_STATUS) ? " ep0status" : "", - - (mask & INT_SETUP) ? " setup" : "", - (mask & INT_ENDPOINT0) ? " ep0" : "", - (mask & INT_USBRESET) ? " reset" : "", - (mask & INT_SUSPEND) ? " suspend" : ""); + seq_printf(m, "%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n", + label, mask, + (mask & INT_PWRDETECT) ? " power" : "", + (mask & INT_SYSERROR) ? " sys" : "", + (mask & INT_MSTRDEND) ? " in-dma" : "", + (mask & INT_MSTWRTMOUT) ? " wrtmo" : "", + + (mask & INT_MSTWREND) ? " out-dma" : "", + (mask & INT_MSTWRSET) ? " wrset" : "", + (mask & INT_ERR) ? " err" : "", + (mask & INT_SOF) ? " sof" : "", + + (mask & INT_EP3NAK) ? " ep3nak" : "", + (mask & INT_EP2NAK) ? " ep2nak" : "", + (mask & INT_EP1NAK) ? " ep1nak" : "", + (mask & INT_EP3DATASET) ? " ep3" : "", + + (mask & INT_EP2DATASET) ? " ep2" : "", + (mask & INT_EP1DATASET) ? " ep1" : "", + (mask & INT_STATUSNAK) ? " ep0snak" : "", + (mask & INT_STATUS) ? " ep0status" : "", + + (mask & INT_SETUP) ? " setup" : "", + (mask & INT_ENDPOINT0) ? " ep0" : "", + (mask & INT_USBRESET) ? " reset" : "", + (mask & INT_SUSPEND) ? " suspend" : ""); +} + +static const char *udc_ep_state(enum ep0state state) +{ + switch (state) { + case EP0_DISCONNECT: + return "ep0_disconnect"; + case EP0_IDLE: + return "ep0_idle"; + case EP0_IN: + return "ep0_in"; + case EP0_OUT: + return "ep0_out"; + case EP0_STATUS: + return "ep0_status"; + case EP0_STALL: + return "ep0_stall"; + case EP0_SUSPEND: + return "ep0_suspend"; + } + + return "ep0_?"; } +static const char *udc_ep_status(u32 status) +{ + switch (status & EPxSTATUS_EP_MASK) { + case EPxSTATUS_EP_READY: + return "ready"; + case EPxSTATUS_EP_DATAIN: + return "packet"; + case EPxSTATUS_EP_FULL: + return "full"; + case EPxSTATUS_EP_TX_ERR: /* host will retry */ + return "tx_err"; + case EPxSTATUS_EP_RX_ERR: + return "rx_err"; + case EPxSTATUS_EP_BUSY: /* ep0 only */ + return "busy"; + case EPxSTATUS_EP_STALL: + return "stall"; + case EPxSTATUS_EP_INVALID: /* these "can't happen" */ + return "invalid"; + } + + return "?"; +} static int udc_proc_read(struct seq_file *m, void *v) { @@ -1068,29 +1112,18 @@ static int udc_proc_read(struct seq_file *m, void *v) tmp = readl(®s->power_detect); is_usb_connected = tmp & PW_DETECT; seq_printf(m, - "%s - %s\n" - "%s version: %s %s\n" - "Gadget driver: %s\n" - "Host %s, %s\n" - "\n", - pci_name(dev->pdev), driver_desc, - driver_name, DRIVER_VERSION, dmastr(), - dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected - ? ((tmp & PW_PULLUP) ? "full speed" : "powered") - : "disconnected", - ({const char *state; - switch(dev->ep0state){ - case EP0_DISCONNECT: state = "ep0_disconnect"; break; - case EP0_IDLE: state = "ep0_idle"; break; - case EP0_IN: state = "ep0_in"; break; - case EP0_OUT: state = "ep0_out"; break; - case EP0_STATUS: state = "ep0_status"; break; - case EP0_STALL: state = "ep0_stall"; break; - case EP0_SUSPEND: state = "ep0_suspend"; break; - default: state = "ep0_?"; break; - } state; }) - ); + "%s - %s\n" + "%s version: %s %s\n" + "Gadget driver: %s\n" + "Host %s, %s\n" + "\n", + pci_name(dev->pdev), driver_desc, + driver_name, DRIVER_VERSION, dmastr(), + dev->driver ? dev->driver->driver.name : "(none)", + is_usb_connected + ? ((tmp & PW_PULLUP) ? "full speed" : "powered") + : "disconnected", + udc_ep_state(dev->ep0state)); dump_intmask(m, "int_status", readl(®s->int_status)); dump_intmask(m, "int_enable", readl(®s->int_enable)); @@ -1099,31 +1132,30 @@ static int udc_proc_read(struct seq_file *m, void *v) goto done; /* registers for (active) device and ep0 */ - if (seq_printf(m, "\nirqs %lu\ndataset %02x " - "single.bcs %02x.%02x state %x addr %u\n", - dev->irqs, readl(®s->DataSet), - readl(®s->EPxSingle), readl(®s->EPxBCS), - readl(®s->UsbState), - readl(®s->address)) < 0) + seq_printf(m, "\nirqs %lu\ndataset %02x single.bcs %02x.%02x state %x addr %u\n", + dev->irqs, readl(®s->DataSet), + readl(®s->EPxSingle), readl(®s->EPxBCS), + readl(®s->UsbState), + readl(®s->address)); + if (seq_has_overflowed(m)) goto done; tmp = readl(®s->dma_master); - if (seq_printf(m, - "dma %03X =" EIGHTBITS "%s %s\n", tmp, - (tmp & MST_EOPB_DIS) ? " eopb-" : "", - (tmp & MST_EOPB_ENA) ? " eopb+" : "", - (tmp & MST_TIMEOUT_DIS) ? " tmo-" : "", - (tmp & MST_TIMEOUT_ENA) ? " tmo+" : "", - - (tmp & MST_RD_EOPB) ? " eopb" : "", - (tmp & MST_RD_RESET) ? " in_reset" : "", - (tmp & MST_WR_RESET) ? " out_reset" : "", - (tmp & MST_RD_ENA) ? " IN" : "", - - (tmp & MST_WR_ENA) ? " OUT" : "", - (tmp & MST_CONNECTION) - ? "ep1in/ep2out" - : "ep1out/ep2in") < 0) + seq_printf(m, "dma %03X =" EIGHTBITS "%s %s\n", + tmp, + (tmp & MST_EOPB_DIS) ? " eopb-" : "", + (tmp & MST_EOPB_ENA) ? " eopb+" : "", + (tmp & MST_TIMEOUT_DIS) ? " tmo-" : "", + (tmp & MST_TIMEOUT_ENA) ? " tmo+" : "", + + (tmp & MST_RD_EOPB) ? " eopb" : "", + (tmp & MST_RD_RESET) ? " in_reset" : "", + (tmp & MST_WR_RESET) ? " out_reset" : "", + (tmp & MST_RD_ENA) ? " IN" : "", + + (tmp & MST_WR_ENA) ? " OUT" : "", + (tmp & MST_CONNECTION) ? "ep1in/ep2out" : "ep1out/ep2in"); + if (seq_has_overflowed(m)) goto done; /* dump endpoint queues */ @@ -1135,44 +1167,23 @@ static int udc_proc_read(struct seq_file *m, void *v) continue; tmp = readl(ep->reg_status); - if (seq_printf(m, - "%s %s max %u %s, irqs %lu, " - "status %02x (%s) " FOURBITS "\n", - ep->ep.name, - ep->is_in ? "in" : "out", - ep->ep.maxpacket, - ep->dma ? "dma" : "pio", - ep->irqs, - tmp, ({ char *s; - switch (tmp & EPxSTATUS_EP_MASK) { - case EPxSTATUS_EP_READY: - s = "ready"; break; - case EPxSTATUS_EP_DATAIN: - s = "packet"; break; - case EPxSTATUS_EP_FULL: - s = "full"; break; - case EPxSTATUS_EP_TX_ERR: // host will retry - s = "tx_err"; break; - case EPxSTATUS_EP_RX_ERR: - s = "rx_err"; break; - case EPxSTATUS_EP_BUSY: /* ep0 only */ - s = "busy"; break; - case EPxSTATUS_EP_STALL: - s = "stall"; break; - case EPxSTATUS_EP_INVALID: // these "can't happen" - s = "invalid"; break; - default: - s = "?"; break; - } s; }), - (tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0", - (tmp & EPxSTATUS_SUSPEND) ? " suspend" : "", - (tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "", - (tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : "" - ) < 0) + seq_printf(m, "%s %s max %u %s, irqs %lu, status %02x (%s) " FOURBITS "\n", + ep->ep.name, + ep->is_in ? "in" : "out", + ep->ep.maxpacket, + ep->dma ? "dma" : "pio", + ep->irqs, + tmp, udc_ep_status(tmp), + (tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0", + (tmp & EPxSTATUS_SUSPEND) ? " suspend" : "", + (tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "", + (tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : ""); + if (seq_has_overflowed(m)) goto done; if (list_empty(&ep->queue)) { - if (seq_puts(m, "\t(nothing queued)\n") < 0) + seq_puts(m, "\t(nothing queued)\n"); + if (seq_has_overflowed(m)) goto done; continue; } @@ -1187,10 +1198,10 @@ static int udc_proc_read(struct seq_file *m, void *v) } else tmp = req->req.actual; - if (seq_printf(m, - "\treq %p len %u/%u buf %p\n", - &req->req, tmp, req->req.length, - req->req.buf) < 0) + seq_printf(m, "\treq %p len %u/%u buf %p\n", + &req->req, tmp, req->req.length, + req->req.buf); + if (seq_has_overflowed(m)) goto done; } } diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 27fd41333f71..3b6a7852822d 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1803,23 +1803,14 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep, req = container_of(_req, struct lpc32xx_request, req); ep = container_of(_ep, struct lpc32xx_ep, ep); - if (!_req || !_req->complete || !_req->buf || + if (!_ep || !_req || !_req->complete || !_req->buf || !list_empty(&req->queue)) return -EINVAL; udc = ep->udc; - if (!_ep) { - dev_dbg(udc->dev, "invalid ep\n"); - return -EINVAL; - } - - - if ((!udc) || (!udc->driver) || - (udc->gadget.speed == USB_SPEED_UNKNOWN)) { - dev_dbg(udc->dev, "invalid device\n"); - return -EINVAL; - } + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + return -EPIPE; if (ep->lep) { struct lpc32xx_usbd_dd_gad *dd; diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index d2c0bf65e345..9871b90195ad 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -80,6 +80,13 @@ static const char *const ep_name[] = { "ep-e", "ep-f", "ep-g", "ep-h", }; +/* Endpoint names for usb3380 advance mode */ +static const char *const ep_name_adv[] = { + ep0name, + "ep1in", "ep2out", "ep3in", "ep4out", + "ep1out", "ep2in", "ep3out", "ep4in", +}; + /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable @@ -138,31 +145,44 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) u32 max, tmp; unsigned long flags; static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; + int ret = 0; ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name || - desc->bDescriptorType != USB_DT_ENDPOINT) + desc->bDescriptorType != USB_DT_ENDPOINT) { + pr_err("%s: failed at line=%d\n", __func__, __LINE__); return -EINVAL; + } dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + ret = -ESHUTDOWN; + goto print_err; + } /* erratum 0119 workaround ties up an endpoint number */ - if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) - return -EDOM; + if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) { + ret = -EDOM; + goto print_err; + } if (dev->quirks & PLX_SUPERSPEED) { - if ((desc->bEndpointAddress & 0x0f) >= 0x0c) - return -EDOM; + if ((desc->bEndpointAddress & 0x0f) >= 0x0c) { + ret = -EDOM; + goto print_err; + } ep->is_in = !!usb_endpoint_dir_in(desc); - if (dev->enhanced_mode && ep->is_in && ep_key[ep->num]) - return -EINVAL; + if (dev->enhanced_mode && ep->is_in && ep_key[ep->num]) { + ret = -EINVAL; + goto print_err; + } } /* sanity check ep-e/ep-f since their fifos are small */ max = usb_endpoint_maxp(desc) & 0x1fff; - if (ep->num > 4 && max > 64 && (dev->quirks & PLX_LEGACY)) - return -ERANGE; + if (ep->num > 4 && max > 64 && (dev->quirks & PLX_LEGACY)) { + ret = -ERANGE; + goto print_err; + } spin_lock_irqsave(&dev->lock, flags); _ep->maxpacket = max & 0x7ff; @@ -192,7 +212,8 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) (dev->gadget.speed == USB_SPEED_HIGH && max != 512) || (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { spin_unlock_irqrestore(&dev->lock, flags); - return -ERANGE; + ret = -ERANGE; + goto print_err; } } ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); @@ -271,7 +292,11 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* pci writes may still be posted */ spin_unlock_irqrestore(&dev->lock, flags); - return 0; + return ret; + +print_err: + dev_err(&ep->dev->pdev->dev, "%s: error=%d\n", __func__, ret); + return ret; } static int handshake(u32 __iomem *ptr, u32 mask, u32 done, int usec) @@ -426,9 +451,10 @@ static int net2280_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) + if (!_ep || !ep->desc || _ep->name == ep0name) { + pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return -EINVAL; - + } spin_lock_irqsave(&ep->dev->lock, flags); nuke(ep); @@ -458,8 +484,10 @@ static struct usb_request struct net2280_ep *ep; struct net2280_request *req; - if (!_ep) + if (!_ep) { + pr_err("%s: Invalid ep\n", __func__); return NULL; + } ep = container_of(_ep, struct net2280_ep, ep); req = kzalloc(sizeof(*req), gfp_flags); @@ -491,8 +519,11 @@ static void net2280_free_request(struct usb_ep *_ep, struct usb_request *_req) struct net2280_request *req; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !_req) + if (!_ep || !_req) { + dev_err(&ep->dev->pdev->dev, "%s: Inavlid ep=%p or req=%p\n", + __func__, _ep, _req); return; + } req = container_of(_req, struct net2280_request, req); WARN_ON(!list_empty(&req->queue)); @@ -896,35 +927,44 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) struct net2280_ep *ep; struct net2280 *dev; unsigned long flags; + int ret = 0; /* we always require a cpu-view buffer, so that we can * always use pio (as fallback or whatever). */ - req = container_of(_req, struct net2280_request, req); - if (!_req || !_req->complete || !_req->buf || - !list_empty(&req->queue)) - return -EINVAL; - if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) - return -EDOM; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) + if (!_ep || (!ep->desc && ep->num != 0)) { + pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return -EINVAL; + } + req = container_of(_req, struct net2280_request, req); + if (!_req || !_req->complete || !_req->buf || + !list_empty(&req->queue)) { + ret = -EINVAL; + goto print_err; + } + if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) { + ret = -EDOM; + goto print_err; + } dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + ret = -ESHUTDOWN; + goto print_err; + } /* FIXME implement PIO fallback for ZLPs with DMA */ - if (ep->dma && _req->length == 0) - return -EOPNOTSUPP; + if (ep->dma && _req->length == 0) { + ret = -EOPNOTSUPP; + goto print_err; + } /* set up dma mapping in case the caller didn't */ if (ep->dma) { - int ret; - ret = usb_gadget_map_request(&dev->gadget, _req, ep->is_in); if (ret) - return ret; + goto print_err; } ep_vdbg(dev, "%s queue req %p, len %d buf %p\n", @@ -1013,7 +1053,11 @@ done: spin_unlock_irqrestore(&dev->lock, flags); /* pci writes may still be posted */ - return 0; + return ret; + +print_err: + dev_err(&ep->dev->pdev->dev, "%s: error=%d\n", __func__, ret); + return ret; } static inline void @@ -1134,8 +1178,11 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) int stopped; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0) || !_req) + if (!_ep || (!ep->desc && ep->num != 0) || !_req) { + pr_err("%s: Invalid ep=%p or ep->desc or req=%p\n", + __func__, _ep, _req); return -EINVAL; + } spin_lock_irqsave(&ep->dev->lock, flags); stopped = ep->stopped; @@ -1157,6 +1204,8 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) } if (&req->req != _req) { spin_unlock_irqrestore(&ep->dev->lock, flags); + dev_err(&ep->dev->pdev->dev, "%s: Request mismatch\n", + __func__); return -EINVAL; } @@ -1214,20 +1263,28 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) int retval = 0; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) + if (!_ep || (!ep->desc && ep->num != 0)) { + pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return -EINVAL; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; + } + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) { + retval = -ESHUTDOWN; + goto print_err; + } if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) - == USB_ENDPOINT_XFER_ISOC) - return -EINVAL; + == USB_ENDPOINT_XFER_ISOC) { + retval = -EINVAL; + goto print_err; + } spin_lock_irqsave(&ep->dev->lock, flags); - if (!list_empty(&ep->queue)) + if (!list_empty(&ep->queue)) { retval = -EAGAIN; - else if (ep->is_in && value && net2280_fifo_status(_ep) != 0) + goto print_unlock; + } else if (ep->is_in && value && net2280_fifo_status(_ep) != 0) { retval = -EAGAIN; - else { + goto print_unlock; + } else { ep_vdbg(ep->dev, "%s %s %s\n", _ep->name, value ? "set" : "clear", wedged ? "wedge" : "halt"); @@ -1251,6 +1308,12 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) spin_unlock_irqrestore(&ep->dev->lock, flags); return retval; + +print_unlock: + spin_unlock_irqrestore(&ep->dev->lock, flags); +print_err: + dev_err(&ep->dev->pdev->dev, "%s: error=%d\n", __func__, retval); + return retval; } static int net2280_set_halt(struct usb_ep *_ep, int value) @@ -1260,8 +1323,10 @@ static int net2280_set_halt(struct usb_ep *_ep, int value) static int net2280_set_wedge(struct usb_ep *_ep) { - if (!_ep || _ep->name == ep0name) + if (!_ep || _ep->name == ep0name) { + pr_err("%s: Invalid ep=%p or ep0\n", __func__, _ep); return -EINVAL; + } return net2280_set_halt_and_wedge(_ep, 1, 1); } @@ -1271,14 +1336,22 @@ static int net2280_fifo_status(struct usb_ep *_ep) u32 avail; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) + if (!_ep || (!ep->desc && ep->num != 0)) { + pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return -ENODEV; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + } + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) { + dev_err(&ep->dev->pdev->dev, + "%s: Invalid driver=%p or speed=%d\n", + __func__, ep->dev->driver, ep->dev->gadget.speed); return -ESHUTDOWN; + } avail = readl(&ep->regs->ep_avail) & (BIT(12) - 1); - if (avail > ep->fifo_size) + if (avail > ep->fifo_size) { + dev_err(&ep->dev->pdev->dev, "%s: Fifo overflow\n", __func__); return -EOVERFLOW; + } if (ep->is_in) avail = ep->fifo_size - avail; return avail; @@ -1289,10 +1362,16 @@ static void net2280_fifo_flush(struct usb_ep *_ep) struct net2280_ep *ep; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) + if (!_ep || (!ep->desc && ep->num != 0)) { + pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + } + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) { + dev_err(&ep->dev->pdev->dev, + "%s: Invalid driver=%p or speed=%d\n", + __func__, ep->dev->driver, ep->dev->gadget.speed); return; + } writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); (void) readl(&ep->regs->ep_rsp); @@ -1977,7 +2056,7 @@ static void usb_reinit_338x(struct net2280 *dev) for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep[i]; - ep->ep.name = ep_name[i]; + ep->ep.name = dev->enhanced_mode ? ep_name_adv[i] : ep_name[i]; ep->dev = dev; ep->num = i; @@ -1989,11 +2068,9 @@ static void usb_reinit_338x(struct net2280 *dev) ep->regs = (struct net2280_ep_regs __iomem *) (((void __iomem *)&dev->epregs[ne[i]]) + ep_reg_addr[i]); - ep->fiforegs = &dev->fiforegs[i]; } else { ep->cfg = &dev->epregs[i]; ep->regs = &dev->epregs[i]; - ep->fiforegs = &dev->fiforegs[i]; } ep->fifo_size = (i != 0) ? 2048 : 512; @@ -2186,7 +2263,6 @@ static int net2280_start(struct usb_gadget *_gadget, dev->ep[i].irqs = 0; /* hook up the driver ... */ - dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; @@ -3052,6 +3128,8 @@ next_endpoints: BIT(PCI_RETRY_ABORT_INTERRUPT)) static void handle_stat1_irqs(struct net2280 *dev, u32 stat) +__releases(dev->lock) +__acquires(dev->lock) { struct net2280_ep *ep; u32 tmp, num, mask, scratch; @@ -3373,8 +3451,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) u32 usbstat; dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *) (base + 0x00b4); - dev->fiforegs = (struct usb338x_fifo_regs __iomem *) - (base + 0x0500); dev->llregs = (struct usb338x_ll_regs __iomem *) (base + 0x0700); dev->ll_lfps_regs = (struct usb338x_ll_lfps_regs __iomem *) diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h index ac8d5a20a378..4dff60d34f73 100644 --- a/drivers/usb/gadget/udc/net2280.h +++ b/drivers/usb/gadget/udc/net2280.h @@ -96,7 +96,6 @@ struct net2280_ep { struct net2280_ep_regs __iomem *regs; struct net2280_dma_regs __iomem *dma; struct net2280_dma *dummy; - struct usb338x_fifo_regs __iomem *fiforegs; dma_addr_t td_dma; /* of dummy */ struct net2280 *dev; unsigned long irqs; @@ -181,7 +180,6 @@ struct net2280 { struct net2280_dma_regs __iomem *dma; struct net2280_dep_regs __iomem *dep; struct net2280_ep_regs __iomem *epregs; - struct usb338x_fifo_regs __iomem *fiforegs; struct usb338x_ll_regs __iomem *llregs; struct usb338x_ll_lfps_regs __iomem *ll_lfps_regs; struct usb338x_ll_tsn_regs __iomem *ll_tsn_regs; diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 6a855fc9bd84..b51226abade6 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -93,50 +93,46 @@ static void handle_ep(struct pxa_ep *ep); static int state_dbg_show(struct seq_file *s, void *p) { struct pxa_udc *udc = s->private; - int pos = 0, ret; u32 tmp; - ret = -ENODEV; if (!udc->driver) - goto out; + return -ENODEV; /* basic device status */ - pos += seq_printf(s, DRIVER_DESC "\n" - "%s version: %s\nGadget driver: %s\n", - driver_name, DRIVER_VERSION, - udc->driver ? udc->driver->driver.name : "(none)"); + seq_printf(s, DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n", + driver_name, DRIVER_VERSION, + udc->driver ? udc->driver->driver.name : "(none)"); tmp = udc_readl(udc, UDCCR); - pos += seq_printf(s, - "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), " - "con=%d,inter=%d,altinter=%d\n", tmp, - (tmp & UDCCR_OEN) ? " oen":"", - (tmp & UDCCR_AALTHNP) ? " aalthnp":"", - (tmp & UDCCR_AHNP) ? " rem" : "", - (tmp & UDCCR_BHNP) ? " rstir" : "", - (tmp & UDCCR_DWRE) ? " dwre" : "", - (tmp & UDCCR_SMAC) ? " smac" : "", - (tmp & UDCCR_EMCE) ? " emce" : "", - (tmp & UDCCR_UDR) ? " udr" : "", - (tmp & UDCCR_UDA) ? " uda" : "", - (tmp & UDCCR_UDE) ? " ude" : "", - (tmp & UDCCR_ACN) >> UDCCR_ACN_S, - (tmp & UDCCR_AIN) >> UDCCR_AIN_S, - (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S); + seq_printf(s, + "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), con=%d,inter=%d,altinter=%d\n", + tmp, + (tmp & UDCCR_OEN) ? " oen":"", + (tmp & UDCCR_AALTHNP) ? " aalthnp":"", + (tmp & UDCCR_AHNP) ? " rem" : "", + (tmp & UDCCR_BHNP) ? " rstir" : "", + (tmp & UDCCR_DWRE) ? " dwre" : "", + (tmp & UDCCR_SMAC) ? " smac" : "", + (tmp & UDCCR_EMCE) ? " emce" : "", + (tmp & UDCCR_UDR) ? " udr" : "", + (tmp & UDCCR_UDA) ? " uda" : "", + (tmp & UDCCR_UDE) ? " ude" : "", + (tmp & UDCCR_ACN) >> UDCCR_ACN_S, + (tmp & UDCCR_AIN) >> UDCCR_AIN_S, + (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S); /* registers for device and ep0 */ - pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n", - udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1)); - pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n", - udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1)); - pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR)); - pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, " - "reconfig=%lu\n", - udc->stats.irqs_reset, udc->stats.irqs_suspend, - udc->stats.irqs_resume, udc->stats.irqs_reconfig); - - ret = 0; -out: - return ret; + seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n", + udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1)); + seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n", + udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1)); + seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR)); + seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, reconfig=%lu\n", + udc->stats.irqs_reset, udc->stats.irqs_suspend, + udc->stats.irqs_resume, udc->stats.irqs_reconfig); + + return 0; } static int queues_dbg_show(struct seq_file *s, void *p) @@ -144,75 +140,67 @@ static int queues_dbg_show(struct seq_file *s, void *p) struct pxa_udc *udc = s->private; struct pxa_ep *ep; struct pxa27x_request *req; - int pos = 0, i, maxpkt, ret; + int i, maxpkt; - ret = -ENODEV; if (!udc->driver) - goto out; + return -ENODEV; /* dump endpoint queues */ for (i = 0; i < NR_PXA_ENDPOINTS; i++) { ep = &udc->pxa_ep[i]; maxpkt = ep->fifo_size; - pos += seq_printf(s, "%-12s max_pkt=%d %s\n", - EPNAME(ep), maxpkt, "pio"); + seq_printf(s, "%-12s max_pkt=%d %s\n", + EPNAME(ep), maxpkt, "pio"); if (list_empty(&ep->queue)) { - pos += seq_printf(s, "\t(nothing queued)\n"); + seq_puts(s, "\t(nothing queued)\n"); continue; } list_for_each_entry(req, &ep->queue, queue) { - pos += seq_printf(s, "\treq %p len %d/%d buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); } } - ret = 0; -out: - return ret; + return 0; } static int eps_dbg_show(struct seq_file *s, void *p) { struct pxa_udc *udc = s->private; struct pxa_ep *ep; - int pos = 0, i, ret; + int i; u32 tmp; - ret = -ENODEV; if (!udc->driver) - goto out; + return -ENODEV; ep = &udc->pxa_ep[0]; tmp = udc_ep_readl(ep, UDCCSR); - pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp, - (tmp & UDCCSR0_SA) ? " sa" : "", - (tmp & UDCCSR0_RNE) ? " rne" : "", - (tmp & UDCCSR0_FST) ? " fst" : "", - (tmp & UDCCSR0_SST) ? " sst" : "", - (tmp & UDCCSR0_DME) ? " dme" : "", - (tmp & UDCCSR0_IPR) ? " ipr" : "", - (tmp & UDCCSR0_OPC) ? " opc" : ""); + seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", + tmp, + (tmp & UDCCSR0_SA) ? " sa" : "", + (tmp & UDCCSR0_RNE) ? " rne" : "", + (tmp & UDCCSR0_FST) ? " fst" : "", + (tmp & UDCCSR0_SST) ? " sst" : "", + (tmp & UDCCSR0_DME) ? " dme" : "", + (tmp & UDCCSR0_IPR) ? " ipr" : "", + (tmp & UDCCSR0_OPC) ? " opc" : ""); for (i = 0; i < NR_PXA_ENDPOINTS; i++) { ep = &udc->pxa_ep[i]; tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR); - pos += seq_printf(s, "%-12s: " - "IN %lu(%lu reqs), OUT %lu(%lu reqs), " - "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, " - "udcbcr=%d\n", - EPNAME(ep), - ep->stats.in_bytes, ep->stats.in_ops, - ep->stats.out_bytes, ep->stats.out_ops, - ep->stats.irqs, - tmp, udc_ep_readl(ep, UDCCSR), - udc_ep_readl(ep, UDCBCR)); + seq_printf(s, "%-12s: IN %lu(%lu reqs), OUT %lu(%lu reqs), irqs=%lu, udccr=0x%08x, udccsr=0x%03x, udcbcr=%d\n", + EPNAME(ep), + ep->stats.in_bytes, ep->stats.in_ops, + ep->stats.out_bytes, ep->stats.out_ops, + ep->stats.irqs, + tmp, udc_ep_readl(ep, UDCCSR), + udc_ep_readl(ep, UDCBCR)); } - ret = 0; -out: - return ret; + return 0; } static int eps_dbg_open(struct inode *inode, struct file *file) @@ -2399,7 +2387,7 @@ static struct pxa_udc memory = { }; #if defined(CONFIG_OF) -static struct of_device_id udc_pxa_dt_ids[] = { +static const struct of_device_id udc_pxa_dt_ids[] = { { .compatible = "marvell,pxa270-udc" }, {} }; diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 5a81cb086b99..d69c35558f68 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -35,6 +35,8 @@ * @dev - the child device to the actual controller * @gadget - the gadget. For use by the class code * @list - for use by the udc class driver + * @vbus - for udcs who care about vbus status, this value is real vbus status; + * for udcs who do not care about vbus status, this value is always true * * This represents the internal data structure which is used by the UDC-class * to hold information about udc driver and gadget together. @@ -44,6 +46,7 @@ struct usb_udc { struct usb_gadget *gadget; struct device dev; struct list_head list; + bool vbus; }; static struct class *udc_class; @@ -128,21 +131,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); static void usb_gadget_state_work(struct work_struct *work) { - struct usb_gadget *gadget = work_to_gadget(work); - struct usb_udc *udc = NULL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->gadget == gadget) - goto found; - mutex_unlock(&udc_lock); - - return; - -found: - mutex_unlock(&udc_lock); + struct usb_gadget *gadget = work_to_gadget(work); + struct usb_udc *udc = gadget->udc; - sysfs_notify(&udc->dev.kobj, NULL, "state"); + if (udc) + sysfs_notify(&udc->dev.kobj, NULL, "state"); } void usb_gadget_set_state(struct usb_gadget *gadget, @@ -155,6 +148,34 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state); /* ------------------------------------------------------------------------- */ +static void usb_udc_connect_control(struct usb_udc *udc) +{ + if (udc->vbus) + usb_gadget_connect(udc->gadget); + else + usb_gadget_disconnect(udc->gadget); +} + +/** + * usb_udc_vbus_handler - updates the udc core vbus status, and try to + * connect or disconnect gadget + * @gadget: The gadget which vbus change occurs + * @status: The vbus status + * + * The udc driver calls it when it wants to connect or disconnect gadget + * according to vbus status. + */ +void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) +{ + struct usb_udc *udc = gadget->udc; + + if (udc) { + udc->vbus = status; + usb_udc_connect_control(udc); + } +} +EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); + /** * usb_gadget_udc_reset - notifies the udc core that bus reset occurs * @gadget: The gadget which bus reset occurs @@ -278,6 +299,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, goto err3; udc->gadget = gadget; + gadget->udc = udc; mutex_lock(&udc_lock); list_add_tail(&udc->list, &udc_list); @@ -287,6 +309,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, goto err4; usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + udc->vbus = true; mutex_unlock(&udc_lock); @@ -348,21 +371,14 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) */ void usb_del_gadget_udc(struct usb_gadget *gadget) { - struct usb_udc *udc = NULL; + struct usb_udc *udc = gadget->udc; - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->gadget == gadget) - goto found; - - dev_err(gadget->dev.parent, "gadget not registered.\n"); - mutex_unlock(&udc_lock); - - return; + if (!udc) + return; -found: dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + mutex_lock(&udc_lock); list_del(&udc->list); mutex_unlock(&udc_lock); @@ -397,7 +413,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri driver->unbind(udc->gadget); goto err1; } - usb_gadget_connect(udc->gadget); + usb_udc_connect_control(udc); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); return 0; |