diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:40:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:40:19 +0000 |
commit | 9f0fc191371843c4fc000a226b0a26b6c059aacd (patch) | |
tree | 35f8be3ef04506ac891ad001e8c41e535ae8d01d /drivers/usb/gadget/legacy | |
parent | Releasing progress-linux version 6.6.15-2~progress7.99u1. (diff) | |
download | linux-9f0fc191371843c4fc000a226b0a26b6c059aacd.tar.xz linux-9f0fc191371843c4fc000a226b0a26b6c059aacd.zip |
Merging upstream version 6.7.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | drivers/usb/gadget/legacy/inode.c | 19 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/raw_gadget.c | 65 |
2 files changed, 72 insertions, 12 deletions
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index ce9e31f3d2..03179b1880 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -31,6 +31,12 @@ #include <linux/usb/gadgetfs.h> #include <linux/usb/gadget.h> +#include <linux/usb/composite.h> /* for USB_GADGET_DELAYED_STATUS */ + +/* Undef helpers from linux/usb/composite.h as gadgetfs redefines them */ +#undef DBG +#undef ERROR +#undef INFO /* @@ -1511,7 +1517,16 @@ delegate: event->u.setup = *ctrl; ep0_readable (dev); spin_unlock (&dev->lock); - return 0; + /* + * Return USB_GADGET_DELAYED_STATUS as a workaround to + * stop some UDC drivers (e.g. dwc3) from automatically + * proceeding with the status stage for 0-length + * transfers. + * Should be removed once all UDC drivers are fixed to + * always delay the status stage until a response is + * queued to EP0. + */ + return w_length == 0 ? USB_GADGET_DELAYED_STATUS : 0; } } @@ -1969,7 +1984,7 @@ gadgetfs_make_inode (struct super_block *sb, inode->i_mode = mode; inode->i_uid = make_kuid(&init_user_ns, default_uid); inode->i_gid = make_kgid(&init_user_ns, default_gid); - inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); + simple_inode_init_ts(inode); inode->i_private = data; inode->i_fop = fops; } diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index ea106ad665..399fca32a8 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -25,6 +25,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/ch11.h> #include <linux/usb/gadget.h> +#include <linux/usb/composite.h> #include <uapi/linux/usb/raw_gadget.h> @@ -64,7 +65,7 @@ static int raw_event_queue_add(struct raw_event_queue *queue, struct usb_raw_event *event; spin_lock_irqsave(&queue->lock, flags); - if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) { + if (queue->size >= RAW_EVENT_QUEUE_SIZE) { spin_unlock_irqrestore(&queue->lock, flags); return -ENOMEM; } @@ -310,9 +311,10 @@ static int gadget_bind(struct usb_gadget *gadget, dev->eps_num = i; spin_unlock_irqrestore(&dev->lock, flags); + dev_dbg(&gadget->dev, "gadget connected\n"); ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL); if (ret < 0) { - dev_err(&gadget->dev, "failed to queue event\n"); + dev_err(&gadget->dev, "failed to queue connect event\n"); set_gadget_data(gadget, NULL); return ret; } @@ -357,20 +359,65 @@ static int gadget_setup(struct usb_gadget *gadget, ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl); if (ret < 0) - dev_err(&gadget->dev, "failed to queue event\n"); + dev_err(&gadget->dev, "failed to queue control event\n"); goto out; out_unlock: spin_unlock_irqrestore(&dev->lock, flags); out: + if (ret == 0 && ctrl->wLength == 0) { + /* + * Return USB_GADGET_DELAYED_STATUS as a workaround to stop + * some UDC drivers (e.g. dwc3) from automatically proceeding + * with the status stage for 0-length transfers. + * Should be removed once all UDC drivers are fixed to always + * delay the status stage until a response is queued to EP0. + */ + return USB_GADGET_DELAYED_STATUS; + } return ret; } -/* These are currently unused but present in case UDC driver requires them. */ -static void gadget_disconnect(struct usb_gadget *gadget) { } -static void gadget_suspend(struct usb_gadget *gadget) { } -static void gadget_resume(struct usb_gadget *gadget) { } -static void gadget_reset(struct usb_gadget *gadget) { } +static void gadget_disconnect(struct usb_gadget *gadget) +{ + struct raw_dev *dev = get_gadget_data(gadget); + int ret; + + dev_dbg(&gadget->dev, "gadget disconnected\n"); + ret = raw_queue_event(dev, USB_RAW_EVENT_DISCONNECT, 0, NULL); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue disconnect event\n"); +} +static void gadget_suspend(struct usb_gadget *gadget) +{ + struct raw_dev *dev = get_gadget_data(gadget); + int ret; + + dev_dbg(&gadget->dev, "gadget suspended\n"); + ret = raw_queue_event(dev, USB_RAW_EVENT_SUSPEND, 0, NULL); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue suspend event\n"); +} +static void gadget_resume(struct usb_gadget *gadget) +{ + struct raw_dev *dev = get_gadget_data(gadget); + int ret; + + dev_dbg(&gadget->dev, "gadget resumed\n"); + ret = raw_queue_event(dev, USB_RAW_EVENT_RESUME, 0, NULL); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue resume event\n"); +} +static void gadget_reset(struct usb_gadget *gadget) +{ + struct raw_dev *dev = get_gadget_data(gadget); + int ret; + + dev_dbg(&gadget->dev, "gadget reset\n"); + ret = raw_queue_event(dev, USB_RAW_EVENT_RESET, 0, NULL); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue reset event\n"); +} /*----------------------------------------------------------------------*/ @@ -682,7 +729,6 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret); spin_lock_irqsave(&dev->lock, flags); - dev->state = STATE_DEV_FAILED; goto out_queue_failed; } @@ -1069,7 +1115,6 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io, dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret); spin_lock_irqsave(&dev->lock, flags); - dev->state = STATE_DEV_FAILED; goto out_queue_failed; } |