summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/composite.c5
-rw-r--r--drivers/usb/gadget/configfs.c15
-rw-r--r--drivers/usb/gadget/configfs.h11
-rw-r--r--drivers/usb/gadget/function/f_fs.c24
-rw-r--r--drivers/usb/gadget/function/f_hid.c17
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c48
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.h14
-rw-r--r--drivers/usb/gadget/function/f_midi.c68
-rw-r--r--drivers/usb/gadget/function/f_ncm.c2
-rw-r--r--drivers/usb/gadget/function/f_printer.c7
-rw-r--r--drivers/usb/gadget/function/f_rndis.c32
-rw-r--r--drivers/usb/gadget/function/f_uac1.c20
-rw-r--r--drivers/usb/gadget/function/f_uac2.c25
-rw-r--r--drivers/usb/gadget/function/u_audio.c4
-rw-r--r--drivers/usb/gadget/function/u_ether.c2
-rw-r--r--drivers/usb/gadget/function/u_ether.h1
-rw-r--r--drivers/usb/gadget/function/u_ether_configfs.h35
-rw-r--r--drivers/usb/gadget/function/u_fs.h1
-rw-r--r--drivers/usb/gadget/function/u_rndis.h5
-rw-r--r--drivers/usb/gadget/function/u_serial.c2
-rw-r--r--drivers/usb/gadget/legacy/inode.c46
-rw-r--r--drivers/usb/gadget/legacy/mass_storage.c26
-rw-r--r--drivers/usb/gadget/legacy/webcam.c1
-rw-r--r--drivers/usb/gadget/udc/Kconfig6
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c4
-rw-r--r--drivers/usb/gadget/udc/bdc/Kconfig1
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc.h24
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_core.c148
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_dbg.c16
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.c4
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_udc.c7
-rw-r--r--drivers/usb/gadget/udc/core.c23
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c76
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c171
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c4
-rw-r--r--drivers/usb/gadget/udc/snps_udc_plat.c12
39 files changed, 679 insertions, 234 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 35cc641d9f31..31cce7805eb2 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -130,7 +130,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
config U_SERIAL_CONSOLE
bool "Serial gadget console support"
- depends on USB_G_SERIAL
+ depends on USB_U_SERIAL
help
It supports the serial gadget can be used as a console.
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index dd74c99d6ce1..5d061b3d8224 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2026,6 +2026,8 @@ static DEVICE_ATTR_RO(suspended);
static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ struct usb_gadget_strings *gstr = cdev->driver->strings[0];
+ struct usb_string *dev_str = gstr->strings;
/* composite_disconnect() must already have been called
* by the underlying peripheral controller driver!
@@ -2045,6 +2047,9 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
composite_dev_cleanup(cdev);
+ if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer)
+ dev_str[USB_GADGET_MANUFACTURER_IDX].s = "";
+
kfree(cdev->def_manufacturer);
kfree(cdev);
set_gadget_data(gadget, NULL);
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index a22a892de7b7..aeb9f3c40521 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1143,11 +1143,12 @@ static struct configfs_attribute *interf_grp_attrs[] = {
NULL
};
-int usb_os_desc_prepare_interf_dir(struct config_group *parent,
- int n_interf,
- struct usb_os_desc **desc,
- char **names,
- struct module *owner)
+struct config_group *usb_os_desc_prepare_interf_dir(
+ struct config_group *parent,
+ int n_interf,
+ struct usb_os_desc **desc,
+ char **names,
+ struct module *owner)
{
struct config_group *os_desc_group;
struct config_item_type *os_desc_type, *interface_type;
@@ -1159,7 +1160,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL);
if (!vlabuf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
@@ -1184,7 +1185,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
configfs_add_default_group(&d->group, os_desc_group);
}
- return 0;
+ return os_desc_group;
}
EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir);
diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h
index 36c468c4f5e9..540d5e92ed22 100644
--- a/drivers/usb/gadget/configfs.h
+++ b/drivers/usb/gadget/configfs.h
@@ -5,11 +5,12 @@
void unregister_gadget_item(struct config_item *item);
-int usb_os_desc_prepare_interf_dir(struct config_group *parent,
- int n_interf,
- struct usb_os_desc **desc,
- char **names,
- struct module *owner);
+struct config_group *usb_os_desc_prepare_interf_dir(
+ struct config_group *parent,
+ int n_interf,
+ struct usb_os_desc **desc,
+ char **names,
+ struct module *owner);
static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item)
{
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index d21874b35cf6..8b342587f8ad 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -46,7 +46,8 @@
static void ffs_data_get(struct ffs_data *ffs);
static void ffs_data_put(struct ffs_data *ffs);
/* Creates new ffs_data object. */
-static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
+static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
+ __attribute__((malloc));
/* Opened counter handling. */
static void ffs_data_opened(struct ffs_data *ffs);
@@ -780,11 +781,12 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct usb_request *req)
{
struct ffs_io_data *io_data = req->context;
+ struct ffs_data *ffs = io_data->ffs;
ENTER();
INIT_WORK(&io_data->work, ffs_user_copy_worker);
- schedule_work(&io_data->work);
+ queue_work(ffs->io_completion_wq, &io_data->work);
}
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
@@ -961,10 +963,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
/* In the meantime, endpoint got disabled or changed. */
ret = -ESHUTDOWN;
} else if (halt) {
- /* Halt */
- if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
- usb_ep_set_halt(ep->ep);
- ret = -EBADMSG;
+ ret = usb_ep_set_halt(ep->ep);
+ if (!ret)
+ ret = -EBADMSG;
} else if (unlikely(data_len == -EINVAL)) {
/*
* Sanity Check: even though data_len can't be used
@@ -1501,7 +1502,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
if (unlikely(ret < 0))
return ERR_PTR(ret);
- ffs = ffs_data_new();
+ ffs = ffs_data_new(dev_name);
if (unlikely(!ffs))
return ERR_PTR(-ENOMEM);
ffs->file_perms = data.perms;
@@ -1611,6 +1612,7 @@ static void ffs_data_put(struct ffs_data *ffs)
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait) ||
waitqueue_active(&ffs->wait));
+ destroy_workqueue(ffs->io_completion_wq);
kfree(ffs->dev_name);
kfree(ffs);
}
@@ -1643,7 +1645,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
ffs_data_put(ffs);
}
-static struct ffs_data *ffs_data_new(void)
+static struct ffs_data *ffs_data_new(const char *dev_name)
{
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
if (unlikely(!ffs))
@@ -1651,6 +1653,12 @@ static struct ffs_data *ffs_data_new(void)
ENTER();
+ ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
+ if (!ffs->io_completion_wq) {
+ kfree(ffs);
+ return NULL;
+ }
+
refcount_set(&ffs->ref, 1);
atomic_set(&ffs->opened, 0);
ffs->state = FFS_READ_DESCRIPTORS;
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 5eea44823ca0..d8e359ef6eb1 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -44,6 +44,7 @@ struct f_hidg {
/* configuration */
unsigned char bInterfaceSubClass;
unsigned char bInterfaceProtocol;
+ unsigned char protocol;
unsigned short report_desc_length;
char *report_desc;
unsigned short report_length;
@@ -527,7 +528,9 @@ static int hidg_setup(struct usb_function *f,
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
| HID_REQ_GET_PROTOCOL):
VDBG(cdev, "get_protocol\n");
- goto stall;
+ length = min_t(unsigned int, length, 1);
+ ((u8 *) req->buf)[0] = hidg->protocol;
+ goto respond;
break;
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
@@ -539,6 +542,17 @@ static int hidg_setup(struct usb_function *f,
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
| HID_REQ_SET_PROTOCOL):
VDBG(cdev, "set_protocol\n");
+ if (value > HID_REPORT_PROTOCOL)
+ goto stall;
+ length = 0;
+ /*
+ * We assume that programs implementing the Boot protocol
+ * are also compatible with the Report Protocol
+ */
+ if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
+ hidg->protocol = value;
+ goto respond;
+ }
goto stall;
break;
@@ -768,6 +782,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
/* set descriptor dynamic values */
hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
+ hidg->protocol = HID_REPORT_PROTOCOL;
hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
hidg_ss_in_comp_desc.wBytesPerInterval =
cpu_to_le16(hidg->report_length);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index e80b9c123a9d..5153e29870c3 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -307,8 +307,6 @@ struct fsg_common {
struct completion thread_notifier;
struct task_struct *thread_task;
- /* Callback functions. */
- const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;
@@ -686,9 +684,8 @@ static int do_read(struct fsg_common *common)
/* Perform the read */
file_offset_tmp = file_offset;
- nread = vfs_read(curlun->filp,
- (char __user *)bh->buf,
- amount, &file_offset_tmp);
+ nread = kernel_read(curlun->filp, bh->buf, amount,
+ &file_offset_tmp);
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long)file_offset, (int)nread);
if (signal_pending(current))
@@ -883,8 +880,8 @@ static int do_write(struct fsg_common *common)
/* Perform the write */
file_offset_tmp = file_offset;
- nwritten = vfs_write(curlun->filp, (char __user *)bh->buf,
- amount, &file_offset_tmp);
+ nwritten = kernel_write(curlun->filp, bh->buf, amount,
+ &file_offset_tmp);
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
(unsigned long long)file_offset, (int)nwritten);
if (signal_pending(current))
@@ -1021,9 +1018,8 @@ static int do_verify(struct fsg_common *common)
/* Perform the read */
file_offset_tmp = file_offset;
- nread = vfs_read(curlun->filp,
- (char __user *) bh->buf,
- amount, &file_offset_tmp);
+ nread = kernel_read(curlun->filp, bh->buf, amount,
+ &file_offset_tmp);
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
(int) nread);
@@ -2440,6 +2436,7 @@ static void handle_exception(struct fsg_common *common)
static int fsg_main_thread(void *common_)
{
struct fsg_common *common = common_;
+ int i;
/*
* Allow the thread to be killed by a signal, but set the signal mask
@@ -2453,13 +2450,6 @@ static int fsg_main_thread(void *common_)
/* Allow the thread to be frozen */
set_freezable();
- /*
- * Arrange for userspace references to be interpreted as kernel
- * pointers. That way we can pass a kernel pointer to a routine
- * that expects a __user pointer and it will work okay.
- */
- set_fs(get_ds());
-
/* The main loop */
while (common->state != FSG_STATE_TERMINATED) {
if (exception_in_progress(common) || signal_pending(current)) {
@@ -2485,21 +2475,16 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL;
spin_unlock_irq(&common->lock);
- if (!common->ops || !common->ops->thread_exits
- || common->ops->thread_exits(common) < 0) {
- int i;
+ /* Eject media from all LUNs */
- down_write(&common->filesem);
- for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
- struct fsg_lun *curlun = common->luns[i];
- if (!curlun || !fsg_lun_is_open(curlun))
- continue;
+ down_write(&common->filesem);
+ for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
+ struct fsg_lun *curlun = common->luns[i];
+ if (curlun && fsg_lun_is_open(curlun))
fsg_lun_close(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
- up_write(&common->filesem);
}
+ up_write(&common->filesem);
/* Let fsg_unbind() know the thread has exited */
complete_and_exit(&common->thread_notifier, 0);
@@ -2690,13 +2675,6 @@ void fsg_common_remove_luns(struct fsg_common *common)
}
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
-void fsg_common_set_ops(struct fsg_common *common,
- const struct fsg_operations *ops)
-{
- common->ops = ops;
-}
-EXPORT_SYMBOL_GPL(fsg_common_set_ops);
-
void fsg_common_free_buffers(struct fsg_common *common)
{
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h
index d3902313b8ac..dc05ca0c4359 100644
--- a/drivers/usb/gadget/function/f_mass_storage.h
+++ b/drivers/usb/gadget/function/f_mass_storage.h
@@ -60,17 +60,6 @@ struct fsg_module_parameters {
struct fsg_common;
/* FSF callback functions */
-struct fsg_operations {
- /*
- * Callback function to call when thread exits. If no
- * callback is set or it returns value lower then zero MSF
- * will force eject all LUNs it operates on (including those
- * marked as non-removable or with prevent_medium_removal flag
- * set).
- */
- int (*thread_exits)(struct fsg_common *common);
-};
-
struct fsg_lun_opts {
struct config_group group;
struct fsg_lun *lun;
@@ -142,9 +131,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun);
void fsg_common_remove_luns(struct fsg_common *common);
-void fsg_common_set_ops(struct fsg_common *common,
- const struct fsg_operations *ops);
-
int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
unsigned int id, const char *name,
const char **name_pfx);
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index a5719f271bf0..5d3d7941d2c2 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -98,6 +98,7 @@ struct f_midi {
DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
spinlock_t transmit_lock;
unsigned int in_last_port;
+ unsigned char free_ref;
struct gmidi_in_port in_ports_array[/* in_ports */];
};
@@ -108,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f)
}
static void f_midi_transmit(struct f_midi *midi);
+static void f_midi_rmidi_free(struct snd_rawmidi *rmidi);
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
@@ -163,6 +165,13 @@ static struct usb_endpoint_descriptor bulk_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
+static struct usb_ss_ep_comp_descriptor bulk_out_ss_comp_desc = {
+ .bLength = sizeof(bulk_out_ss_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+};
+
/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
static struct usb_ms_endpoint_descriptor_16 ms_out_desc = {
/* .bLength = DYNAMIC */
@@ -180,6 +189,13 @@ static struct usb_endpoint_descriptor bulk_in_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
+static struct usb_ss_ep_comp_descriptor bulk_in_ss_comp_desc = {
+ .bLength = sizeof(bulk_in_ss_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+};
+
/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
/* .bLength = DYNAMIC */
@@ -755,13 +771,13 @@ static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up)
clear_bit(substream->number, &midi->out_triggered);
}
-static struct snd_rawmidi_ops gmidi_in_ops = {
+static const struct snd_rawmidi_ops gmidi_in_ops = {
.open = f_midi_in_open,
.close = f_midi_in_close,
.trigger = f_midi_in_trigger,
};
-static struct snd_rawmidi_ops gmidi_out_ops = {
+static const struct snd_rawmidi_ops gmidi_out_ops = {
.open = f_midi_out_open,
.close = f_midi_out_close,
.trigger = f_midi_out_trigger
@@ -818,6 +834,8 @@ static int f_midi_register_card(struct f_midi *midi)
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = midi;
+ rmidi->private_free = f_midi_rmidi_free;
+ midi->free_ref++;
/*
* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
@@ -853,7 +871,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct f_midi *midi = func_to_midi(f);
struct usb_string *us;
- int status, n, jack = 1, i = 0;
+ int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0;
midi->gadget = cdev->gadget;
tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
@@ -895,7 +913,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
goto fail;
/* allocate temporary function list */
- midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
+ midi_function = kcalloc((MAX_PORTS * 4) + 11, sizeof(*midi_function),
GFP_KERNEL);
if (!midi_function) {
status = -ENOMEM;
@@ -985,6 +1003,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
ms_in_desc.bNumEmbMIDIJack = midi->out_ports;
/* ... and add them to the list */
+ endpoint_descriptor_index = i;
midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;
midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc;
@@ -1009,13 +1028,34 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
goto fail_f_midi;
}
+ if (gadget_is_superspeed(c->cdev->gadget)) {
+ bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024);
+ bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024);
+ i = endpoint_descriptor_index;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &bulk_out_desc;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &bulk_out_ss_comp_desc;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &ms_out_desc;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &bulk_in_desc;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &bulk_in_ss_comp_desc;
+ midi_function[i++] = (struct usb_descriptor_header *)
+ &ms_in_desc;
+ f->ss_descriptors = usb_copy_descriptors(midi_function);
+ if (!f->ss_descriptors)
+ goto fail_f_midi;
+ }
+
kfree(midi_function);
return 0;
fail_f_midi:
kfree(midi_function);
- usb_free_descriptors(f->hs_descriptors);
+ usb_free_all_descriptors(f);
fail:
f_midi_unregister_card(midi);
fail_register:
@@ -1197,14 +1237,21 @@ static void f_midi_free(struct usb_function *f)
midi = func_to_midi(f);
opts = container_of(f->fi, struct f_midi_opts, func_inst);
- kfree(midi->id);
mutex_lock(&opts->lock);
- kfifo_free(&midi->in_req_fifo);
- kfree(midi);
- --opts->refcnt;
+ if (!--midi->free_ref) {
+ kfree(midi->id);
+ kfifo_free(&midi->in_req_fifo);
+ kfree(midi);
+ --opts->refcnt;
+ }
mutex_unlock(&opts->lock);
}
+static void f_midi_rmidi_free(struct snd_rawmidi *rmidi)
+{
+ f_midi_free(rmidi->private_data);
+}
+
static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = f->config->cdev;
@@ -1219,7 +1266,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
card = midi->card;
midi->card = NULL;
if (card)
- snd_card_free(card);
+ snd_card_free_when_closed(card);
usb_free_all_descriptors(f);
}
@@ -1263,6 +1310,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
midi->buflen = opts->buflen;
midi->qlen = opts->qlen;
midi->in_last_port = 0;
+ midi->free_ref = 1;
status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL);
if (status)
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 24e34cfcb4bd..45b334ceaf2e 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -925,8 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
*/
ncm->port.is_zlp_ok =
gadget_is_zlp_supported(cdev->gadget);
- ncm->port.no_skb_reserve =
- gadget_avoids_skb_reserve(cdev->gadget);
ncm->port.cdc_filter = DEFAULT_FILTER;
DBG(cdev, "activate ncm\n");
net = gether_connect(&ncm->port);
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 8df244fc9d80..ea0da35a44e2 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -555,6 +555,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
size_t size; /* Amount of data in a TX request. */
size_t bytes_copied = 0;
struct usb_request *req;
+ int value;
DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
@@ -634,7 +635,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
return -EAGAIN;
}
- if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
+ /* here, we unlock, and only unlock, to avoid deadlock. */
+ spin_unlock(&dev->lock);
+ value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+ spin_lock(&dev->lock);
+ if (value) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 16562e461121..c7c5b3ce1d98 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
}
+ rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
+ rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
+ rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
+
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
@@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);
/* f_rndis_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis);
+/* f_rndis_opts_class */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class);
+
+/* f_rndis_opts_subclass */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass);
+
+/* f_rndis_opts_protocol */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol);
+
static struct configfs_attribute *rndis_attrs[] = {
&rndis_opts_attr_dev_addr,
&rndis_opts_attr_host_addr,
&rndis_opts_attr_qmult,
&rndis_opts_attr_ifname,
+ &rndis_opts_attr_class,
+ &rndis_opts_attr_subclass,
+ &rndis_opts_attr_protocol,
NULL,
};
@@ -892,6 +908,7 @@ static void rndis_free_inst(struct usb_function_instance *f)
free_netdev(opts->net);
}
+ kfree(opts->rndis_interf_group); /* single VLA chunk */
kfree(opts);
}
@@ -900,6 +917,7 @@ static struct usb_function_instance *rndis_alloc_inst(void)
struct f_rndis_opts *opts;
struct usb_os_desc *descs[1];
char *names[1];
+ struct config_group *rndis_interf_group;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
@@ -916,12 +934,22 @@ static struct usb_function_instance *rndis_alloc_inst(void)
}
INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop);
+ opts->class = rndis_iad_descriptor.bFunctionClass;
+ opts->subclass = rndis_iad_descriptor.bFunctionSubClass;
+ opts->protocol = rndis_iad_descriptor.bFunctionProtocol;
+
descs[0] = &opts->rndis_os_desc;
names[0] = "rndis";
config_group_init_type_name(&opts->func_inst.group, "",
&rndis_func_type);
- usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
- names, THIS_MODULE);
+ rndis_interf_group =
+ usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
+ names, THIS_MODULE);
+ if (IS_ERR(rndis_interf_group)) {
+ rndis_free_inst(&opts->func_inst);
+ return ERR_CAST(rndis_interf_group);
+ }
+ opts->rndis_interf_group = rndis_interf_group;
return &opts->func_inst;
}
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 8656f84e17d9..29efbedc91f9 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -92,9 +92,9 @@ static struct uac_input_terminal_descriptor usb_out_it_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
.bTerminalID = USB_OUT_IT_ID,
- .wTerminalType = UAC_TERMINAL_STREAMING,
+ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
- .wChannelConfig = 0x3,
+ .wChannelConfig = cpu_to_le16(0x3),
};
#define IO_OUT_OT_ID 2
@@ -103,7 +103,7 @@ static struct uac1_output_terminal_descriptor io_out_ot_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
.bTerminalID = IO_OUT_OT_ID,
- .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER,
+ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
.bAssocTerminal = 0,
.bSourceID = USB_OUT_IT_ID,
};
@@ -114,9 +114,9 @@ static struct uac_input_terminal_descriptor io_in_it_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
.bTerminalID = IO_IN_IT_ID,
- .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE,
+ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
.bAssocTerminal = 0,
- .wChannelConfig = 0x3,
+ .wChannelConfig = cpu_to_le16(0x3),
};
#define USB_IN_OT_ID 4
@@ -125,7 +125,7 @@ static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
.bTerminalID = USB_IN_OT_ID,
- .wTerminalType = UAC_TERMINAL_STREAMING,
+ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
.bSourceID = IO_IN_IT_ID,
};
@@ -174,7 +174,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = {
.bDescriptorSubtype = UAC_AS_GENERAL,
.bTerminalLink = USB_OUT_IT_ID,
.bDelay = 1,
- .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+ .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
};
static struct uac1_as_header_descriptor as_in_header_desc = {
@@ -183,7 +183,7 @@ static struct uac1_as_header_descriptor as_in_header_desc = {
.bDescriptorSubtype = UAC_AS_GENERAL,
.bTerminalLink = USB_IN_OT_ID,
.bDelay = 1,
- .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+ .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
};
DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
@@ -606,8 +606,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
if (status)
goto fail;
- audio->out_ep_maxpsize = as_out_ep_desc.wMaxPacketSize;
- audio->in_ep_maxpsize = as_in_ep_desc.wMaxPacketSize;
+ audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize);
+ audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize);
audio->params.c_chmask = audio_opts->c_chmask;
audio->params.c_srate = audio_opts->c_srate;
audio->params.c_ssize = audio_opts->c_ssize;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 9082ce261e70..f05c3f3e6103 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -168,7 +168,7 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = {
.bAssocTerminal = 0,
.bCSourceID = USB_OUT_CLK_ID,
.iChannelNames = 0,
- .bmControls = (CONTROL_RDWR << COPY_CTRL),
+ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
/* Input Terminal for I/O-In */
@@ -182,7 +182,7 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
.bAssocTerminal = 0,
.bCSourceID = USB_IN_CLK_ID,
.iChannelNames = 0,
- .bmControls = (CONTROL_RDWR << COPY_CTRL),
+ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
/* Ouput Terminal for USB_IN */
@@ -196,7 +196,7 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
.bAssocTerminal = 0,
.bSourceID = IO_IN_IT_ID,
.bCSourceID = USB_IN_CLK_ID,
- .bmControls = (CONTROL_RDWR << COPY_CTRL),
+ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
/* Ouput Terminal for I/O-Out */
@@ -210,7 +210,7 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
.bAssocTerminal = 0,
.bSourceID = USB_OUT_IT_ID,
.bCSourceID = USB_OUT_CLK_ID,
- .bmControls = (CONTROL_RDWR << COPY_CTRL),
+ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
static struct uac2_ac_header_descriptor ac_hdr_desc = {
@@ -220,9 +220,10 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = {
.bDescriptorSubtype = UAC_MS_HEADER,
.bcdADC = cpu_to_le16(0x200),
.bCategory = UAC2_FUNCTION_IO_BOX,
- .wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc
- + sizeof usb_out_it_desc + sizeof io_in_it_desc
- + sizeof usb_in_ot_desc + sizeof io_out_ot_desc,
+ .wTotalLength = cpu_to_le16(sizeof in_clk_src_desc
+ + sizeof out_clk_src_desc + sizeof usb_out_it_desc
+ + sizeof io_in_it_desc + sizeof usb_in_ot_desc
+ + sizeof io_out_ot_desc),
.bmControls = 0,
};
@@ -569,10 +570,12 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
return ret;
}
- agdev->in_ep_maxpsize = max(fs_epin_desc.wMaxPacketSize,
- hs_epin_desc.wMaxPacketSize);
- agdev->out_ep_maxpsize = max(fs_epout_desc.wMaxPacketSize,
- hs_epout_desc.wMaxPacketSize);
+ agdev->in_ep_maxpsize = max_t(u16,
+ le16_to_cpu(fs_epin_desc.wMaxPacketSize),
+ le16_to_cpu(hs_epin_desc.wMaxPacketSize));
+ agdev->out_ep_maxpsize = max_t(u16,
+ le16_to_cpu(fs_epout_desc.wMaxPacketSize),
+ le16_to_cpu(hs_epout_desc.wMaxPacketSize));
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index 5dd73b9e5172..3971bbab88bd 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -79,7 +79,7 @@ struct snd_uac_chip {
unsigned int p_framesize;
};
-static struct snd_pcm_hardware uac_pcm_hardware = {
+static const struct snd_pcm_hardware uac_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER
| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
@@ -354,7 +354,7 @@ static int uac_pcm_null(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_pcm_ops uac_pcm_ops = {
+static const struct snd_pcm_ops uac_pcm_ops = {
.open = uac_pcm_open,
.close = uac_pcm_null,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index a8b40d07e927..bdbc3fdc7c4f 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1073,7 +1073,7 @@ struct net_device *gether_connect(struct gether *link)
if (result == 0) {
dev->zlp = link->is_zlp_ok;
- dev->no_skb_reserve = link->no_skb_reserve;
+ dev->no_skb_reserve = gadget_avoids_skb_reserve(dev->gadget);
DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult));
dev->header_len = link->header_len;
diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
index 81d94a7ae4b4..c77145bd6b5b 100644
--- a/drivers/usb/gadget/function/u_ether.h
+++ b/drivers/usb/gadget/function/u_ether.h
@@ -64,7 +64,6 @@ struct gether {
struct usb_ep *out_ep;
bool is_zlp_ok;
- bool no_skb_reserve;
u16 cdc_filter;
diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h
index c71133de17e7..e4c3f84af4c3 100644
--- a/drivers/usb/gadget/function/u_ether_configfs.h
+++ b/drivers/usb/gadget/function/u_ether_configfs.h
@@ -153,4 +153,39 @@ out: \
\
CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
+#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \
+ static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
+ char *page) \
+ { \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
+ int ret; \
+ \
+ mutex_lock(&opts->lock); \
+ ret = sprintf(page, "%02x\n", opts->_n_); \
+ mutex_unlock(&opts->lock); \
+ \
+ return ret; \
+ } \
+ \
+ static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\
+ const char *page, \
+ size_t len) \
+ { \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
+ int ret; \
+ u8 val; \
+ \
+ mutex_lock(&opts->lock); \
+ ret = sscanf(page, "%02hhx", &val); \
+ if (ret > 0) { \
+ opts->_n_ = val; \
+ ret = len; \
+ } \
+ mutex_unlock(&opts->lock); \
+ \
+ return ret; \
+ } \
+ \
+ CONFIGFS_ATTR(_f_##_opts_, _n_)
+
#endif /* __U_ETHER_CONFIGFS_H */
diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h
index 540f1c48c1a8..79f70ebf85dc 100644
--- a/drivers/usb/gadget/function/u_fs.h
+++ b/drivers/usb/gadget/function/u_fs.h
@@ -279,6 +279,7 @@ struct ffs_data {
} file_perms;
struct eventfd_ctx *ffs_eventfd;
+ struct workqueue_struct *io_completion_wq;
bool no_disconnect;
struct work_struct reset_work;
diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h
index 4eafd5050545..efdb7ac381d9 100644
--- a/drivers/usb/gadget/function/u_rndis.h
+++ b/drivers/usb/gadget/function/u_rndis.h
@@ -26,9 +26,14 @@ struct f_rndis_opts {
bool bound;
bool borrowed_net;
+ struct config_group *rndis_interf_group;
struct usb_os_desc rndis_os_desc;
char rndis_ext_compat_id[16];
+ u8 class;
+ u8 subclass;
+ u8 protocol;
+
/*
* Read/write access to configfs attributes is handled by configfs.
*
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 9b0805f55ad7..4176216d54be 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -537,7 +537,7 @@ static void gs_rx_push(unsigned long _port)
}
/* push data to (open) tty */
- if (req->actual) {
+ if (req->actual && tty) {
char *packet = req->buf;
unsigned size = req->actual;
unsigned n;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 684900fcfe24..5c28bee327e1 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -28,7 +28,7 @@
#include <linux/aio.h>
#include <linux/uio.h>
#include <linux/refcount.h>
-
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
@@ -116,6 +116,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
refcount_t count;
+ int udc_usage;
enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
@@ -513,9 +514,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
INIT_WORK(&priv->work, ep_user_copy_worker);
schedule_work(&priv->work);
}
- spin_unlock(&epdata->dev->lock);
usb_ep_free_request(ep, req);
+ spin_unlock(&epdata->dev->lock);
put_ep(epdata);
}
@@ -939,9 +940,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
struct usb_request *req = dev->req;
if ((retval = setup_req (ep, req, 0)) == 0) {
+ ++dev->udc_usage;
spin_unlock_irq (&dev->lock);
retval = usb_ep_queue (ep, req, GFP_KERNEL);
spin_lock_irq (&dev->lock);
+ --dev->udc_usage;
}
dev->state = STATE_DEV_CONNECTED;
@@ -983,11 +986,14 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
retval = -EIO;
else {
len = min (len, (size_t)dev->req->actual);
-// FIXME don't call this with the spinlock held ...
+ ++dev->udc_usage;
+ spin_unlock_irq(&dev->lock);
if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
else
retval = len;
+ spin_lock_irq(&dev->lock);
+ --dev->udc_usage;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
}
@@ -1131,6 +1137,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
dev->state = STATE_DEV_CONNECTED;
+ ++dev->udc_usage;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@@ -1142,6 +1149,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
GFP_KERNEL);
}
spin_lock_irq(&dev->lock);
+ --dev->udc_usage;
if (retval < 0) {
clean_req (dev->gadget->ep0, dev->req);
} else
@@ -1243,9 +1251,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
struct usb_gadget *gadget = dev->gadget;
long ret = -ENOTTY;
- if (gadget->ops->ioctl)
+ spin_lock_irq(&dev->lock);
+ if (dev->state == STATE_DEV_OPENED ||
+ dev->state == STATE_DEV_UNBOUND) {
+ /* Not bound to a UDC */
+ } else if (gadget->ops->ioctl) {
+ ++dev->udc_usage;
+ spin_unlock_irq(&dev->lock);
+
ret = gadget->ops->ioctl (gadget, code, value);
+ spin_lock_irq(&dev->lock);
+ --dev->udc_usage;
+ }
+ spin_unlock_irq(&dev->lock);
+
return ret;
}
@@ -1463,10 +1483,12 @@ delegate:
if (value < 0)
break;
+ ++dev->udc_usage;
spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, dev->req,
GFP_KERNEL);
spin_lock (&dev->lock);
+ --dev->udc_usage;
if (value < 0) {
clean_req (gadget->ep0, dev->req);
break;
@@ -1490,8 +1512,12 @@ delegate:
req->length = value;
req->zero = value < w_length;
+ ++dev->udc_usage;
spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
+ spin_lock(&dev->lock);
+ --dev->udc_usage;
+ spin_unlock(&dev->lock);
if (value < 0) {
DBG (dev, "ep_queue --> %d\n", value);
req->status = 0;
@@ -1518,21 +1544,24 @@ static void destroy_ep_files (struct dev_data *dev)
/* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
+ spin_unlock_irq (&dev->lock);
+
dentry = ep->dentry;
ep->dentry = NULL;
parent = d_inode(dentry->d_parent);
/* break link to controller */
+ mutex_lock(&ep->lock);
if (ep->state == STATE_EP_ENABLED)
(void) usb_ep_disable (ep->ep);
ep->state = STATE_EP_UNBOUND;
usb_ep_free_request (ep->ep, ep->req);
ep->ep = NULL;
+ mutex_unlock(&ep->lock);
+
wake_up (&ep->wait);
put_ep (ep);
- spin_unlock_irq (&dev->lock);
-
/* break link to dcache */
inode_lock(parent);
d_delete (dentry);
@@ -1603,6 +1632,11 @@ gadgetfs_unbind (struct usb_gadget *gadget)
spin_lock_irq (&dev->lock);
dev->state = STATE_DEV_UNBOUND;
+ while (dev->udc_usage > 0) {
+ spin_unlock_irq(&dev->lock);
+ usleep_range(1000, 2000);
+ spin_lock_irq(&dev->lock);
+ }
spin_unlock_irq (&dev->lock);
destroy_ep_files (dev);
diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c
index e99ab57ee3e5..fcba59782f26 100644
--- a/drivers/usb/gadget/legacy/mass_storage.c
+++ b/drivers/usb/gadget/legacy/mass_storage.c
@@ -107,15 +107,6 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
-static unsigned long msg_registered;
-static void msg_cleanup(void);
-
-static int msg_thread_exits(struct fsg_common *common)
-{
- msg_cleanup();
- return 0;
-}
-
static int msg_do_config(struct usb_configuration *c)
{
struct fsg_opts *opts;
@@ -154,9 +145,6 @@ static struct usb_configuration msg_config_driver = {
static int msg_bind(struct usb_composite_dev *cdev)
{
- static const struct fsg_operations ops = {
- .thread_exits = msg_thread_exits,
- };
struct fsg_opts *opts;
struct fsg_config config;
int status;
@@ -173,8 +161,6 @@ static int msg_bind(struct usb_composite_dev *cdev)
if (status)
goto fail;
- fsg_common_set_ops(opts->common, &ops);
-
status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
if (status)
goto fail_set_cdev;
@@ -256,18 +242,12 @@ MODULE_LICENSE("GPL");
static int __init msg_init(void)
{
- int ret;
-
- ret = usb_composite_probe(&msg_driver);
- set_bit(0, &msg_registered);
-
- return ret;
+ return usb_composite_probe(&msg_driver);
}
module_init(msg_init);
-static void msg_cleanup(void)
+static void __exit msg_cleanup(void)
{
- if (test_and_clear_bit(0, &msg_registered))
- usb_composite_unregister(&msg_driver);
+ usb_composite_unregister(&msg_driver);
}
module_exit(msg_cleanup);
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index f9661cd627c8..82c13fce9232 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -436,5 +436,4 @@ module_usb_composite_driver(webcam_driver);
MODULE_AUTHOR("Laurent Pinchart");
MODULE_DESCRIPTION("Webcam Video Gadget");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1.0");
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 9ffb11ec9ed9..1e9567091d86 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -192,7 +192,7 @@ config USB_RENESAS_USBHS_UDC
config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST
- depends on EXTCON
+ depends on EXTCON && HAS_DMA
help
Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers.
@@ -257,6 +257,7 @@ config USB_MV_U3D
config USB_SNP_CORE
depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT)
+ depends on HAS_DMA
tristate
help
This enables core driver support for Synopsys USB 2.0 Device
@@ -271,7 +272,8 @@ config USB_SNP_CORE
config USB_SNP_UDC_PLAT
tristate "Synopsys USB 2.0 Device controller"
- depends on (USB_GADGET && OF)
+ depends on USB_GADGET && OF && HAS_DMA
+ depends on EXTCON || EXTCON=n
select USB_GADGET_DUALSPEED
select USB_SNP_CORE
default ARCH_BCM_IPROC
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 98d71400f8a1..a884c022df7a 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -29,6 +29,8 @@
#include <linux/of_gpio.h>
#include "atmel_usba_udc.h"
+#define USBA_VBUS_IRQFLAGS (IRQF_ONESHOT \
+ | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)
#ifdef CONFIG_USB_GADGET_DEBUG_FS
#include <linux/debugfs.h>
@@ -2361,7 +2363,7 @@ static int usba_udc_probe(struct platform_device *pdev)
IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(&pdev->dev,
gpio_to_irq(udc->vbus_pin), NULL,
- usba_vbus_irq_thread, IRQF_ONESHOT,
+ usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,
"atmel_usba_udc", udc);
if (ret) {
udc->vbus_pin = -ENODEV;
diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig
index eb8b55392360..c74ac25dddcd 100644
--- a/drivers/usb/gadget/udc/bdc/Kconfig
+++ b/drivers/usb/gadget/udc/bdc/Kconfig
@@ -1,6 +1,7 @@
config USB_BDC_UDC
tristate "Broadcom USB3.0 device controller IP driver(BDC)"
depends on USB_GADGET && HAS_DMA
+ default ARCH_BRCMSTB
help
BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP
diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h
index 916d47135cac..6df0352cdc50 100644
--- a/drivers/usb/gadget/udc/bdc/bdc.h
+++ b/drivers/usb/gadget/udc/bdc/bdc.h
@@ -27,8 +27,8 @@
#include <linux/usb/gadget.h>
#include <asm/unaligned.h>
-#define BRCM_BDC_NAME "bdc_usb3"
-#define BRCM_BDC_DESC "BDC device controller driver"
+#define BRCM_BDC_NAME "bdc"
+#define BRCM_BDC_DESC "Broadcom USB Device Controller driver"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
@@ -83,14 +83,14 @@
#define BDC_DVCSA 0x50
#define BDC_DVCSB 0x54
-#define BDC_EPSTS0(n) (0x60 + (n * 0x10))
-#define BDC_EPSTS1(n) (0x64 + (n * 0x10))
-#define BDC_EPSTS2(n) (0x68 + (n * 0x10))
-#define BDC_EPSTS3(n) (0x6c + (n * 0x10))
-#define BDC_EPSTS4(n) (0x70 + (n * 0x10))
-#define BDC_EPSTS5(n) (0x74 + (n * 0x10))
-#define BDC_EPSTS6(n) (0x78 + (n * 0x10))
-#define BDC_EPSTS7(n) (0x7c + (n * 0x10))
+#define BDC_EPSTS0 0x60
+#define BDC_EPSTS1 0x64
+#define BDC_EPSTS2 0x68
+#define BDC_EPSTS3 0x6c
+#define BDC_EPSTS4 0x70
+#define BDC_EPSTS5 0x74
+#define BDC_EPSTS6 0x78
+#define BDC_EPSTS7 0x7c
#define BDC_SRRBAL(n) (0x200 + (n * 0x10))
#define BDC_SRRBAH(n) (0x204 + (n * 0x10))
#define BDC_SRRINT(n) (0x208 + (n * 0x10))
@@ -413,6 +413,9 @@ struct bdc {
/* device lock */
spinlock_t lock;
+ /* generic phy */
+ struct phy **phys;
+ int num_phys;
/* num of endpoints for a particular instantiation of IP */
unsigned int num_eps;
/*
@@ -454,6 +457,7 @@ struct bdc {
* Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4
*/
struct delayed_work func_wake_notify;
+ struct clk *clk;
};
static inline u32 bdc_readl(void __iomem *base, u32 offset)
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
index e9bd8d4abca0..7a8af4b916cf 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -24,9 +24,11 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/of.h>
+#include <linux/phy/phy.h>
#include <linux/moduleparam.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/clk.h>
#include "bdc.h"
#include "bdc_dbg.h"
@@ -444,6 +446,43 @@ static int bdc_hw_init(struct bdc *bdc)
return 0;
}
+static int bdc_phy_init(struct bdc *bdc)
+{
+ int phy_num;
+ int ret;
+
+ for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+ ret = phy_init(bdc->phys[phy_num]);
+ if (ret)
+ goto err_exit_phy;
+ ret = phy_power_on(bdc->phys[phy_num]);
+ if (ret) {
+ phy_exit(bdc->phys[phy_num]);
+ goto err_exit_phy;
+ }
+ }
+
+ return 0;
+
+err_exit_phy:
+ while (--phy_num >= 0) {
+ phy_power_off(bdc->phys[phy_num]);
+ phy_exit(bdc->phys[phy_num]);
+ }
+
+ return ret;
+}
+
+static void bdc_phy_exit(struct bdc *bdc)
+{
+ int phy_num;
+
+ for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+ phy_power_off(bdc->phys[phy_num]);
+ phy_exit(bdc->phys[phy_num]);
+ }
+}
+
static int bdc_probe(struct platform_device *pdev)
{
struct bdc *bdc;
@@ -452,12 +491,29 @@ static int bdc_probe(struct platform_device *pdev)
int irq;
u32 temp;
struct device *dev = &pdev->dev;
+ struct clk *clk;
+ int phy_num;
dev_dbg(dev, "%s()\n", __func__);
+
+ clk = devm_clk_get(dev, "sw_usbd");
+ if (IS_ERR(clk)) {
+ dev_info(dev, "Clock not found in Device Tree\n");
+ clk = NULL;
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(dev, "could not enable clock\n");
+ return ret;
+ }
+
bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL);
if (!bdc)
return -ENOMEM;
+ bdc->clk = clk;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bdc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(bdc->regs)) {
@@ -473,35 +529,66 @@ static int bdc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bdc);
bdc->irq = irq;
bdc->dev = dev;
- dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq);
+ dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq);
+
+ bdc->num_phys = of_count_phandle_with_args(dev->of_node,
+ "phys", "#phy-cells");
+ if (bdc->num_phys > 0) {
+ bdc->phys = devm_kcalloc(dev, bdc->num_phys,
+ sizeof(struct phy *), GFP_KERNEL);
+ if (!bdc->phys)
+ return -ENOMEM;
+ } else {
+ bdc->num_phys = 0;
+ }
+ dev_info(dev, "Using %d phy(s)\n", bdc->num_phys);
+
+ for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+ bdc->phys[phy_num] = devm_of_phy_get_by_index(
+ dev, dev->of_node, phy_num);
+ if (IS_ERR(bdc->phys[phy_num])) {
+ ret = PTR_ERR(bdc->phys[phy_num]);
+ dev_err(bdc->dev,
+ "BDC phy specified but not found:%d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = bdc_phy_init(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "BDC phy init failure:%d\n", ret);
+ return ret;
+ }
temp = bdc_readl(bdc->regs, BDC_BDCCAP1);
if ((temp & BDC_P64) &&
!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
- dev_dbg(bdc->dev, "Using 64-bit address\n");
+ dev_dbg(dev, "Using 64-bit address\n");
} else {
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) {
- dev_err(bdc->dev, "No suitable DMA config available, abort\n");
+ dev_err(dev,
+ "No suitable DMA config available, abort\n");
return -ENOTSUPP;
}
- dev_dbg(bdc->dev, "Using 32-bit address\n");
+ dev_dbg(dev, "Using 32-bit address\n");
}
ret = bdc_hw_init(bdc);
if (ret) {
- dev_err(bdc->dev, "BDC init failure:%d\n", ret);
- return ret;
+ dev_err(dev, "BDC init failure:%d\n", ret);
+ goto phycleanup;
}
ret = bdc_udc_init(bdc);
if (ret) {
- dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret);
+ dev_err(dev, "BDC Gadget init failure:%d\n", ret);
goto cleanup;
}
return 0;
cleanup:
bdc_hw_exit(bdc);
-
+phycleanup:
+ bdc_phy_exit(bdc);
return ret;
}
@@ -513,13 +600,56 @@ static int bdc_remove(struct platform_device *pdev)
dev_dbg(bdc->dev, "%s ()\n", __func__);
bdc_udc_exit(bdc);
bdc_hw_exit(bdc);
+ bdc_phy_exit(bdc);
+ clk_disable_unprepare(bdc->clk);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bdc_suspend(struct device *dev)
+{
+ struct bdc *bdc = dev_get_drvdata(dev);
+ clk_disable_unprepare(bdc->clk);
return 0;
}
+static int bdc_resume(struct device *dev)
+{
+ struct bdc *bdc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(bdc->clk);
+ if (ret) {
+ dev_err(bdc->dev, "err enabling the clock\n");
+ return ret;
+ }
+ ret = bdc_reinit(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "err in bdc reinit\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend,
+ bdc_resume);
+
+static const struct of_device_id bdc_of_match[] = {
+ { .compatible = "brcm,bdc-v0.16" },
+ { .compatible = "brcm,bdc" },
+ { /* sentinel */ }
+};
+
static struct platform_driver bdc_driver = {
.driver = {
.name = BRCM_BDC_NAME,
+ .owner = THIS_MODULE,
+ .pm = &bdc_pm_ops,
+ .of_match_table = bdc_of_match,
},
.probe = bdc_probe,
.remove = bdc_remove,
diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c
index 5945dbc47825..ac98f6f681b7 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_dbg.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c
@@ -40,28 +40,28 @@ void bdc_dump_epsts(struct bdc *bdc)
{
u32 temp;
- temp = bdc_readl(bdc->regs, BDC_EPSTS0(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS0);
dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS1(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS1);
dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS2(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS2);
dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS3(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS3);
dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS4(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS4);
dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS5(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS5);
dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS6(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS6);
dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp);
- temp = bdc_readl(bdc->regs, BDC_EPSTS7(0));
+ temp = bdc_readl(bdc->regs, BDC_EPSTS7);
dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp);
}
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
index ff1ef24d1777..bfd8f7ade935 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -777,9 +777,9 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
*/
/* The current hw dequeue pointer */
- tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
+ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0);
deq_ptr_64 = tmp_32;
- tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0));
+ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1);
deq_ptr_64 |= ((u64)tmp_32 << 32);
/* we have the dma addr of next bd that will be fetched by hardware */
diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
index aae7458d8986..c84346146456 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
@@ -249,6 +249,7 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)
disconn = true;
else if ((uspc & BDC_PCS) && !BDC_PST(uspc))
connected = true;
+ clear_flags |= BDC_PCC;
}
/* Change in VBus and VBus is present */
@@ -259,16 +260,16 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)
bdc_softconn(bdc);
usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED);
}
- clear_flags = BDC_VBC;
+ clear_flags |= BDC_VBC;
} else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) {
/* Hot reset, warm reset, 2.0 bus reset or disconn */
dev_dbg(bdc->dev, "Port reset or disconn\n");
bdc_uspc_disconnected(bdc, disconn);
- clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC;
+ clear_flags |= BDC_PRC;
} else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) {
/* Change in Link state */
handle_link_state_change(bdc, uspc);
- clear_flags = BDC_PSC|BDC_PCS;
+ clear_flags |= BDC_PSC;
}
/*
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index e6f04eee95c4..d41d07aae0ce 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -812,6 +812,8 @@ int usb_gadget_map_request_by_dev(struct device *dev,
dev_err(dev, "failed to map buffer\n");
return -EFAULT;
}
+
+ req->dma_mapped = 1;
}
return 0;
@@ -836,9 +838,10 @@ void usb_gadget_unmap_request_by_dev(struct device *dev,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0;
- } else {
+ } else if (req->dma_mapped) {
dma_unmap_single(dev, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->dma_mapped = 0;
}
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
@@ -1130,6 +1133,7 @@ static int check_pending_gadget_drivers(struct usb_udc *udc)
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
+ * Calls the gadget release function in the latter case.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
@@ -1137,10 +1141,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
struct usb_udc *udc;
int ret = -ENOMEM;
- udc = kzalloc(sizeof(*udc), GFP_KERNEL);
- if (!udc)
- goto err1;
-
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
@@ -1150,7 +1150,13 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
else
gadget->dev.release = usb_udc_nop_release;
- ret = device_register(&gadget->dev);
+ device_initialize(&gadget->dev);
+
+ udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ goto err1;
+
+ ret = device_add(&gadget->dev);
if (ret)
goto err2;
@@ -1197,10 +1203,10 @@ err3:
device_del(&gadget->dev);
err2:
- put_device(&gadget->dev);
kfree(udc);
err1:
+ put_device(&gadget->dev);
return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
@@ -1314,8 +1320,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->dev.driver = &driver->driver;
udc->gadget->dev.driver = &driver->driver;
- if (driver->max_speed < udc->gadget->max_speed)
- usb_gadget_udc_set_speed(udc, driver->max_speed);
+ usb_gadget_udc_set_speed(udc, driver->max_speed);
ret = driver->bind(udc->gadget, driver);
if (ret)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 3c3760315910..f04e91ef9e7c 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -237,6 +237,8 @@ struct dummy_hcd {
struct usb_device *udev;
struct list_head urbp_list;
+ struct urbp *next_frame_urbp;
+
u32 stream_en_ep;
u8 num_stream[30 / 2];
@@ -253,11 +255,13 @@ struct dummy {
*/
struct dummy_ep ep[DUMMY_ENDPOINTS];
int address;
+ int callback_usage;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct dummy_request fifo_req;
u8 fifo_buf[FIFO_SIZE];
u16 devstatus;
+ unsigned ints_enabled:1;
unsigned udc_suspended:1;
unsigned pullup:1;
@@ -375,11 +379,10 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
USB_PORT_STAT_CONNECTION) == 0)
dum_hcd->port_status |=
(USB_PORT_STAT_C_CONNECTION << 16);
- if ((dum_hcd->port_status &
- USB_PORT_STAT_ENABLE) == 1 &&
- (dum_hcd->port_status &
- USB_SS_PORT_LS_U0) == 1 &&
- dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+ if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) &&
+ (dum_hcd->port_status &
+ USB_PORT_STAT_LINK_STATE) == USB_SS_PORT_LS_U0 &&
+ dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
dum_hcd->active = 1;
}
} else {
@@ -416,6 +419,7 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
static void set_link_state(struct dummy_hcd *dum_hcd)
{
struct dummy *dum = dum_hcd->dum;
+ unsigned int power_bit;
dum_hcd->active = 0;
if (dum->pullup)
@@ -426,32 +430,43 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
return;
set_link_state_by_speed(dum_hcd);
+ power_bit = (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 ?
+ USB_SS_PORT_STAT_POWER : USB_PORT_STAT_POWER);
if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
dum_hcd->active)
dum_hcd->resuming = 0;
/* Currently !connected or in reset */
- if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+ if ((dum_hcd->port_status & power_bit) == 0 ||
(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
- unsigned disconnect = USB_PORT_STAT_CONNECTION &
+ unsigned int disconnect = power_bit &
dum_hcd->old_status & (~dum_hcd->port_status);
- unsigned reset = USB_PORT_STAT_RESET &
+ unsigned int reset = USB_PORT_STAT_RESET &
(~dum_hcd->old_status) & dum_hcd->port_status;
/* Report reset and disconnect events to the driver */
- if (dum->driver && (disconnect || reset)) {
+ if (dum->ints_enabled && (disconnect || reset)) {
stop_activity(dum);
+ ++dum->callback_usage;
+ spin_unlock(&dum->lock);
if (reset)
usb_gadget_udc_reset(&dum->gadget, dum->driver);
else
dum->driver->disconnect(&dum->gadget);
+ spin_lock(&dum->lock);
+ --dum->callback_usage;
}
- } else if (dum_hcd->active != dum_hcd->old_active) {
+ } else if (dum_hcd->active != dum_hcd->old_active &&
+ dum->ints_enabled) {
+ ++dum->callback_usage;
+ spin_unlock(&dum->lock);
if (dum_hcd->old_active && dum->driver->suspend)
dum->driver->suspend(&dum->gadget);
else if (!dum_hcd->old_active && dum->driver->resume)
dum->driver->resume(&dum->gadget);
+ spin_lock(&dum->lock);
+ --dum->callback_usage;
}
dum_hcd->old_status = dum_hcd->port_status;
@@ -972,8 +987,11 @@ static int dummy_udc_start(struct usb_gadget *g,
* can't enumerate without help from the driver we're binding.
*/
+ spin_lock_irq(&dum->lock);
dum->devstatus = 0;
dum->driver = driver;
+ dum->ints_enabled = 1;
+ spin_unlock_irq(&dum->lock);
return 0;
}
@@ -984,6 +1002,16 @@ static int dummy_udc_stop(struct usb_gadget *g)
struct dummy *dum = dum_hcd->dum;
spin_lock_irq(&dum->lock);
+ dum->ints_enabled = 0;
+ stop_activity(dum);
+
+ /* emulate synchronize_irq(): wait for callbacks to finish */
+ while (dum->callback_usage > 0) {
+ spin_unlock_irq(&dum->lock);
+ usleep_range(1000, 2000);
+ spin_lock_irq(&dum->lock);
+ }
+
dum->driver = NULL;
spin_unlock_irq(&dum->lock);
@@ -1037,7 +1065,12 @@ static int dummy_udc_probe(struct platform_device *pdev)
memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops;
- dum->gadget.max_speed = USB_SPEED_SUPER;
+ if (mod_data.is_super_speed)
+ dum->gadget.max_speed = USB_SPEED_SUPER;
+ else if (mod_data.is_high_speed)
+ dum->gadget.max_speed = USB_SPEED_HIGH;
+ else
+ dum->gadget.max_speed = USB_SPEED_FULL;
dum->gadget.dev.parent = &pdev->dev;
init_dummy_udc_hw(dum);
@@ -1246,6 +1279,8 @@ static int dummy_urb_enqueue(
list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
urb->hcpriv = urbp;
+ if (!dum_hcd->next_frame_urbp)
+ dum_hcd->next_frame_urbp = urbp;
if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */
@@ -1521,6 +1556,8 @@ static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
dum->ss_hcd : dum->hs_hcd)))
return NULL;
+ if (!dum->ints_enabled)
+ return NULL;
if ((address & ~USB_DIR_IN) == 0)
return &dum->ep[0];
for (i = 1; i < DUMMY_ENDPOINTS; i++) {
@@ -1762,6 +1799,7 @@ static void dummy_timer(unsigned long _dum_hcd)
spin_unlock_irqrestore(&dum->lock, flags);
return;
}
+ dum_hcd->next_frame_urbp = NULL;
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
if (!ep_info[i].name)
@@ -1778,6 +1816,10 @@ restart:
int type;
int status = -EINPROGRESS;
+ /* stop when we reach URBs queued after the timer interrupt */
+ if (urbp == dum_hcd->next_frame_urbp)
+ break;
+
urb = urbp->urb;
if (urb->unlinked)
goto return_urb;
@@ -1857,10 +1899,12 @@ restart:
* until setup() returns; no reentrancy issues etc.
*/
if (value > 0) {
+ ++dum->callback_usage;
spin_unlock(&dum->lock);
value = dum->driver->setup(&dum->gadget,
&setup);
spin_lock(&dum->lock);
+ --dum->callback_usage;
if (value >= 0) {
/* no delays (max 64KB data stage) */
@@ -2561,8 +2605,6 @@ static struct hc_driver dummy_hcd = {
.product_desc = "Dummy host controller",
.hcd_priv_size = sizeof(struct dummy_hcd),
- .flags = HCD_USB3 | HCD_SHARED,
-
.reset = dummy_setup,
.start = dummy_start,
.stop = dummy_stop,
@@ -2591,8 +2633,12 @@ static int dummy_hcd_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
dum = *((void **)dev_get_platdata(&pdev->dev));
- if (!mod_data.is_super_speed)
+ if (mod_data.is_super_speed)
+ dummy_hcd.flags = HCD_USB3 | HCD_SHARED;
+ else if (mod_data.is_high_speed)
dummy_hcd.flags = HCD_USB2;
+ else
+ dummy_hcd.flags = HCD_USB11;
hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
if (!hs_hcd)
return -ENOMEM;
@@ -2776,7 +2822,7 @@ static int __init init(void)
if (retval < 0) {
i--;
while (i >= 0)
- platform_device_del(the_udc_pdev[i]);
+ platform_device_del(the_udc_pdev[i--]);
goto err_add_udc;
}
}
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 303328ce59ee..a3e72d690eef 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -62,7 +62,7 @@ static const char *const ep_name[] = {
"ep3",
};
-static struct usb_endpoint_descriptor qe_ep0_desc = {
+static const struct usb_endpoint_descriptor qe_ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 8a708d0a1042..4103bf7cf52a 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -39,7 +39,6 @@
#include "mv_udc.h"
#define DRIVER_DESC "Marvell PXA USB Device Controller driver"
-#define DRIVER_VERSION "8 Nov 2010"
#define ep_dir(ep) (((ep)->ep_num == 0) ? \
((ep)->udc->ep0_dir) : ((ep)->direction))
@@ -2427,5 +2426,4 @@ module_platform_driver(udc_driver);
MODULE_ALIAS("platform:mv-udc");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
-MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index d8278322d5ac..63a206122058 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -8,6 +8,7 @@
* the Free Software Foundation; version 2 of the License.
*/
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
@@ -20,6 +21,8 @@
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -89,6 +92,9 @@
/* USB_COM_CON */
#define USB_COM_CON_CONF BIT(24)
+#define USB_COM_CON_PN_WDATAIF_NL BIT(23)
+#define USB_COM_CON_PN_RDATAIF_NL BIT(22)
+#define USB_COM_CON_PN_LSTTR_PP BIT(21)
#define USB_COM_CON_SPD_MODE BIT(17)
#define USB_COM_CON_EP0_EN BIT(16)
#define USB_COM_CON_DEV_ADDR_SHIFT 8
@@ -344,6 +350,7 @@ struct renesas_usb3 {
bool workaround_for_vbus;
bool extcon_host; /* check id and set EXTCON_USB_HOST */
bool extcon_usb; /* check vbus and set EXTCON_USB */
+ bool forced_b_device;
};
#define gadget_to_renesas_usb3(_gadget) \
@@ -660,7 +667,9 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
spin_lock_irqsave(&usb3->lock, flags);
usb3_set_mode(usb3, host);
usb3_vbus_out(usb3, a_dev);
- if (!host && a_dev) /* for A-Peripheral */
+ /* for A-Peripheral or forced B-device mode */
+ if ((!host && a_dev) ||
+ (usb3->workaround_for_vbus && usb3->forced_b_device))
usb3_connect(usb3);
spin_unlock_irqrestore(&usb3->lock, flags);
}
@@ -674,7 +683,7 @@ static void usb3_check_id(struct renesas_usb3 *usb3)
{
usb3->extcon_host = usb3_is_a_device(usb3);
- if (usb3->extcon_host)
+ if (usb3->extcon_host && !usb3->forced_b_device)
usb3_mode_config(usb3, true, true);
else
usb3_mode_config(usb3, false, false);
@@ -686,6 +695,9 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
{
usb3_init_axi_bridge(usb3);
usb3_init_epc_registers(usb3);
+ usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
+ USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
+ USB3_USB_COM_CON);
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
@@ -832,21 +844,32 @@ static struct renesas_usb3_request *usb3_get_request(struct renesas_usb3_ep
return usb3_req;
}
-static void usb3_request_done(struct renesas_usb3_ep *usb3_ep,
- struct renesas_usb3_request *usb3_req, int status)
+static void __usb3_request_done(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req,
+ int status)
{
struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
- unsigned long flags;
dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
status);
usb3_req->req.status = status;
- spin_lock_irqsave(&usb3->lock, flags);
usb3_ep->started = false;
list_del_init(&usb3_req->queue);
- spin_unlock_irqrestore(&usb3->lock, flags);
+ spin_unlock(&usb3->lock);
usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
+ spin_lock(&usb3->lock);
+}
+
+static void usb3_request_done(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req, int status)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ __usb3_request_done(usb3_ep, usb3_req, status);
+ spin_unlock_irqrestore(&usb3->lock, flags);
}
static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3)
@@ -1015,7 +1038,7 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
usb3_ep->ep.maxpacket);
u8 *buf = usb3_req->req.buf + usb3_req->req.actual;
u32 tmp = 0;
- bool is_last;
+ bool is_last = !len ? true : false;
if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0)
return -EBUSY;
@@ -1036,7 +1059,8 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
usb3_write(usb3, tmp, fifo_reg);
}
- is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
+ if (!is_last)
+ is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
/* Send the data */
usb3_set_px_con_send(usb3_ep, len, is_last);
@@ -1127,7 +1151,8 @@ static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep,
usb3_set_p0_con_for_ctrl_read_data(usb3);
} else {
usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD);
- usb3_set_p0_con_for_ctrl_write_data(usb3);
+ if (usb3_req->req.length)
+ usb3_set_p0_con_for_ctrl_write_data(usb3);
}
usb3_p0_xfer(usb3_ep, usb3_req);
@@ -1369,7 +1394,7 @@ static int renesas_usb3_dma_free_prd(struct renesas_usb3 *usb3,
usb3_for_each_dma(usb3, dma, i) {
if (dma->prd) {
- dma_free_coherent(dev, USB3_DMA_MAX_XFER_SIZE,
+ dma_free_coherent(dev, USB3_DMA_PRD_SIZE,
dma->prd, dma->prd_dma);
dma->prd = NULL;
}
@@ -1409,12 +1434,12 @@ static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep,
int ret = -EAGAIN;
u32 enable_bits = 0;
+ spin_lock_irqsave(&usb3->lock, flags);
if (usb3_ep->halt || usb3_ep->started)
- return;
+ goto out;
if (usb3_req != usb3_req_first)
- return;
+ goto out;
- spin_lock_irqsave(&usb3->lock, flags);
if (usb3_pn_change(usb3, usb3_ep->num) < 0)
goto out;
@@ -2030,7 +2055,16 @@ static u32 usb3_calc_ramarea(int ram_size)
static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep,
const struct usb_endpoint_descriptor *desc)
{
- return usb3_ep->rammap_val | PN_RAMMAP_MPKT(usb_endpoint_maxp(desc));
+ int i;
+ const u32 max_packet_array[] = {8, 16, 32, 64, 512};
+ u32 mpkt = PN_RAMMAP_MPKT(1024);
+
+ for (i = 0; i < ARRAY_SIZE(max_packet_array); i++) {
+ if (usb_endpoint_maxp(desc) <= max_packet_array[i])
+ mpkt = PN_RAMMAP_MPKT(max_packet_array[i]);
+ }
+
+ return usb3_ep->rammap_val | mpkt;
}
static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep,
@@ -2175,7 +2209,7 @@ static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep)
}
}
-static struct usb_ep_ops renesas_usb3_ep_ops = {
+static const struct usb_ep_ops renesas_usb3_ep_ops = {
.enable = renesas_usb3_ep_enable,
.disable = renesas_usb3_ep_disable,
@@ -2266,6 +2300,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
if (!usb3->driver)
return -ENODEV;
+ if (usb3->forced_b_device)
+ return -EBUSY;
+
if (!strncmp(buf, "host", strlen("host")))
new_mode_is_host = true;
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
@@ -2293,6 +2330,70 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(role);
+static int renesas_usb3_b_device_show(struct seq_file *s, void *unused)
+{
+ struct renesas_usb3 *usb3 = s->private;
+
+ seq_printf(s, "%d\n", usb3->forced_b_device);
+
+ return 0;
+}
+
+static int renesas_usb3_b_device_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, renesas_usb3_b_device_show, inode->i_private);
+}
+
+static ssize_t renesas_usb3_b_device_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct renesas_usb3 *usb3 = s->private;
+ char buf[32];
+
+ if (!usb3->driver)
+ return -ENODEV;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "1", 1))
+ usb3->forced_b_device = true;
+ else
+ usb3->forced_b_device = false;
+
+ /* Let this driver call usb3_connect() anyway */
+ usb3_check_id(usb3);
+
+ return count;
+}
+
+static const struct file_operations renesas_usb3_b_device_fops = {
+ .open = renesas_usb3_b_device_open,
+ .write = renesas_usb3_b_device_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3,
+ struct device *dev)
+{
+ struct dentry *root, *file;
+
+ root = debugfs_create_dir(dev_name(dev), NULL);
+ if (IS_ERR_OR_NULL(root)) {
+ dev_info(dev, "%s: Can't create the root\n", __func__);
+ return;
+ }
+
+ file = debugfs_create_file("b_device", 0644, root, usb3,
+ &renesas_usb3_b_device_fops);
+ if (!file)
+ dev_info(dev, "%s: Can't create debugfs mode\n", __func__);
+}
+
/*------- platform_driver ------------------------------------------------*/
static int renesas_usb3_remove(struct platform_device *pdev)
{
@@ -2415,22 +2516,40 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev,
}
}
-static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = {
+static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = {
.ramsize_per_ramif = SZ_16K,
.num_ramif = 2,
.ramsize_per_pipe = SZ_4K,
.workaround_for_vbus = true,
};
+static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = {
+ .ramsize_per_ramif = SZ_16K,
+ .num_ramif = 4,
+ .ramsize_per_pipe = SZ_4K,
+};
+
static const struct of_device_id usb3_of_match[] = {
{
.compatible = "renesas,r8a7795-usb3-peri",
- .data = &renesas_usb3_priv_r8a7795,
+ .data = &renesas_usb3_priv_gen3,
+ },
+ {
+ .compatible = "renesas,rcar-gen3-usb3-peri",
+ .data = &renesas_usb3_priv_gen3,
},
{ },
};
MODULE_DEVICE_TABLE(of, usb3_of_match);
+static const struct soc_device_attribute renesas_usb3_quirks_match[] = {
+ {
+ .soc_id = "r8a7795", .revision = "ES1.*",
+ .data = &renesas_usb3_priv_r8a7795_es1,
+ },
+ { /* sentinel */ },
+};
+
static const unsigned int renesas_usb3_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
@@ -2444,15 +2563,23 @@ static int renesas_usb3_probe(struct platform_device *pdev)
const struct of_device_id *match;
int irq, ret;
const struct renesas_usb3_priv *priv;
+ const struct soc_device_attribute *attr;
match = of_match_node(usb3_of_match, pdev->dev.of_node);
if (!match)
return -ENODEV;
- priv = match->data;
+
+ attr = soc_device_match(renesas_usb3_quirks_match);
+ if (attr)
+ priv = attr->data;
+ else
+ priv = match->data;
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -ENODEV;
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+ return irq;
+ }
usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
if (!usb3)
@@ -2510,6 +2637,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
usb3->workaround_for_vbus = priv->workaround_for_vbus;
+ renesas_usb3_debugfs_init(usb3, &pdev->dev);
+
dev_info(&pdev->dev, "probed\n");
return 0;
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index 4643a01262b4..394abd5d65c0 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -51,7 +51,6 @@
#include "s3c2410_udc.h"
#define DRIVER_DESC "S3C2410 USB Device Controller Gadget"
-#define DRIVER_VERSION "29 Apr 2007"
#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \
"Arnaud Patard <arnaud.patard@rtp-net.org>"
@@ -1996,7 +1995,7 @@ static int __init udc_init(void)
{
int retval;
- dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+ dprintk(DEBUG_NORMAL, "%s\n", gadget_name);
s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
if (IS_ERR(s3c2410_udc_debugfs_root)) {
@@ -2027,5 +2026,4 @@ module_exit(udc_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c
index 2e11f19e07ae..e8a5fdaee37d 100644
--- a/drivers/usb/gadget/udc/snps_udc_plat.c
+++ b/drivers/usb/gadget/udc/snps_udc_plat.c
@@ -28,7 +28,7 @@
/* description */
#define UDC_MOD_DESCRIPTION "Synopsys UDC platform driver"
-void start_udc(struct udc *udc)
+static void start_udc(struct udc *udc)
{
if (udc->driver) {
dev_info(udc->dev, "Connecting...\n");
@@ -38,7 +38,7 @@ void start_udc(struct udc *udc)
}
}
-void stop_udc(struct udc *udc)
+static void stop_udc(struct udc *udc)
{
int tmp;
u32 reg;
@@ -76,7 +76,7 @@ void stop_udc(struct udc *udc)
dev_info(udc->dev, "Device disconnected\n");
}
-void udc_drd_work(struct work_struct *work)
+static void udc_drd_work(struct work_struct *work)
{
struct udc *udc;
@@ -184,7 +184,7 @@ static int udc_plat_probe(struct platform_device *pdev)
goto exit_phy;
}
- ret = extcon_get_cable_state_(udc->edev, EXTCON_USB);
+ ret = extcon_get_state(udc->edev, EXTCON_USB);
if (ret < 0) {
dev_err(dev, "Can't get cable state\n");
goto exit_extcon;
@@ -273,7 +273,7 @@ static int udc_plat_suspend(struct device *dev)
udc = dev_get_drvdata(dev);
stop_udc(udc);
- if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) {
+ if (extcon_get_state(udc->edev, EXTCON_USB) > 0) {
dev_dbg(udc->dev, "device -> idle\n");
stop_udc(udc);
}
@@ -303,7 +303,7 @@ static int udc_plat_resume(struct device *dev)
return ret;
}
- if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) {
+ if (extcon_get_state(udc->edev, EXTCON_USB) > 0) {
dev_dbg(udc->dev, "idle -> device\n");
start_udc(udc);
}
OpenPOWER on IntegriCloud