Commit graph

17 commits

Author SHA1 Message Date
Alexander Kozhinov 1c968a4a8f drivers: usb: device: fix cbprintf_package warning
cbprintf_package complains about char usage for %p
string argument and suggests void * usage.

Signed-off-by: Alexander Kozhinov <ak.alexander.kozhinov@gmail.com>
2024-05-28 18:57:22 +02:00
Manuel Aebischer 25753fef13 drivers: usb_dc_rpi_pico: starting read on transfer EPs
This commit partially reverts a change which was introduced in the
previous commit 5b9a0e5456.
usb_dc_ep_start_read() should also be called on transfer endpoints
like it has been before, otherwise the endpoint will not be armed
after it has been reconfigured.

Signed-off-by: Manuel Aebischer <manuel.aebischer@netmodule.com>
2024-01-09 18:27:44 +01:00
Manuel Aebischer 8cf199fb04 drivers: usb_dc_rpi_pico: previosuly used endpoint may remain locked
When reconfiguring a previously used endpoint, it may still be locked
when a write was taking place when e.g. the host application crashed.
The call to udc_rpi_cancel_endpoint seems to do a proper cleanup of
the endpoint, i.e. the write semaphore will be released.
Fixes #66723.

Signed-off-by: Manuel Aebischer <manuel.aebischer@netmodule.com>
2023-12-21 17:18:49 +00:00
TOKITA Hiroshi 8891f734ec drivers: usb: rpi_pico: Turn on clock on initializing
Turning on clock via clock controller on initializing.

Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
2023-12-20 11:14:24 +01:00
Manuel Aebischer 5b9a0e5456 drivers: usb_dc_rpi_pico: handling of data toggle after endpoint setup
The previous behaviour led to an issue where we already expected data1
on the first transfer instead of data0. The DesignWare USB DC actually
implements the same behaviour. Also, the next_pid flag has to be reset
on setting up the endpoint.
Fixes #66283.

Signed-off-by: Manuel Aebischer <manuel.aebischer@netmodule.com>
2023-12-19 12:45:52 +01:00
Gerard Marull-Paretas 99c19425d1 drivers: usb: device: add missing init.h
Some drivers were missing init.h, required for SYS_INIT.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
2023-08-31 10:21:50 +02:00
Gerard Marull-Paretas a5fd0d184a init: remove the need for a dummy device pointer in SYS_INIT functions
The init infrastructure, found in `init.h`, is currently used by:

- `SYS_INIT`: to call functions before `main`
- `DEVICE_*`: to initialize devices

They are all sorted according to an initialization level + a priority.
`SYS_INIT` calls are really orthogonal to devices, however, the required
function signature requires a `const struct device *dev` as a first
argument. The only reason for that is because the same init machinery is
used by devices, so we have something like:

```c
struct init_entry {
	int (*init)(const struct device *dev);
	/* only set by DEVICE_*, otherwise NULL */
	const struct device *dev;
}
```

As a result, we end up with such weird/ugly pattern:

```c
static int my_init(const struct device *dev)
{
	/* always NULL! add ARG_UNUSED to avoid compiler warning */
	ARG_UNUSED(dev);
	...
}
```

This is really a result of poor internals isolation. This patch proposes
a to make init entries more flexible so that they can accept sytem
initialization calls like this:

```c
static int my_init(void)
{
	...
}
```

This is achieved using a union:

```c
union init_function {
	/* for SYS_INIT, used when init_entry.dev == NULL */
	int (*sys)(void);
	/* for DEVICE*, used when init_entry.dev != NULL */
	int (*dev)(const struct device *dev);
};

struct init_entry {
	/* stores init function (either for SYS_INIT or DEVICE*)
	union init_function init_fn;
	/* stores device pointer for DEVICE*, NULL for SYS_INIT. Allows
	 * to know which union entry to call.
	 */
	const struct device *dev;
}
```

This solution **does not increase ROM usage**, and allows to offer clean
public APIs for both SYS_INIT and DEVICE*. Note that however, init
machinery keeps a coupling with devices.

**NOTE**: This is a breaking change! All `SYS_INIT` functions will need
to be converted to the new signature. See the script offered in the
following commit.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

init: convert SYS_INIT functions to the new signature

Conversion scripted using scripts/utils/migrate_sys_init.py.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

manifest: update projects for SYS_INIT changes

Update modules with updated SYS_INIT calls:

- hal_ti
- lvgl
- sof
- TraceRecorderSource

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

tests: devicetree: devices: adjust test

Adjust test according to the recently introduced SYS_INIT
infrastructure.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>

tests: kernel: threads: adjust SYS_INIT call

Adjust to the new signature: int (*init_fn)(void);

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2023-04-12 14:28:07 +00:00
Purdea Andrei f4e0f9004f drivers: usb_dc_rpi_pico: implement remote wakeup support
This change implements the following, necessary for remote wakeup to be
supported:

- implement usb_dc_wakeup_request() call to trigger remote wakeup
- implement interrupts to detect supsended/resumed state
- implement extra logic to simulate resumed state when the resume
  is a result of remote wakeup. In this case the rp2040 chip doesn't
  send a USB_INTR_DEV_RESUME_FROM_HOST interrupt, or any other
  interrupts when the resume condition is detected to be extended
  by the upstream port, so we need to simulate this event when we
  see activity on the bus.

Signed-off-by: Purdea Andrei <andrei@purdea.ro>
2023-03-06 21:18:38 +01:00
Purdea Andrei 73a800f7dd drivers: usb_dc_rpi_pico: fix stability issue related to control transfers
Description of the bad behaviour before this change:

The arming of the control EP0_OUT endpoint was not kept under
control. It could happen that the EP0_OUT endpoint was left
armed, after the completion of a complete control transfer.

It is clear that the intention was to NOT keep EP0_OUT constantly
armed while idle, because usb_dc_ep_enable() doesn't arm it,
and the intention was for when usb_dc_ep_read() is called to
collect the Setup-Stage 8-byte data, that is when EP0_OUT is armed,
and before this call is performed, the host will keep getting NAKs
for the Data-Stage of the to_device control transfer.

This happens correctly on the first to_device control transfer with
wLength > 0. However, because usb_dc_ep_read_continue() indiscriminately
re-arms all OUT endpoints, in the case of to_device control transfers
with wLength > 0, on the Data-Stage, the endpoint is also re-armed,
which is wrong, because then the endpoint will be left armed after
the control transfer is over.

In this case when a new to_device control transfer starts, the
Data-Stage will be accepted on the first try. This would still
have worked without a failure if the Setup-Stage would have been
processed immediately, but because we process everything in a work
queue at a later time, when the Setup-Stage associated 8-byte data
buffer is read both the Setup-Stage and Data-Stage have arrived.
At the end of handling the Setup-Stage we try to re-arm the EP0_OUT,
which already contains data, thereby corrupting the received length
portion of the buf_ctl register. (Obviously other fields are changed
too, but the length field is the one that first causes chaos, cause
it's written to the maximum, which is 64.) The above mentioned Data-Stage
already has a message in its workqueue for it to be processed, but
it is picked up only after the length field has been corrupted.
Because of this usb_dc_ep_read() thinks there is more data in the buffer
than there really is, and everything becomes de-synchronized, with
later reads accessing uninitialized parts of the buffer.

This sounds like a fundamental failure, that should make it impossible
to operate USB, however the reason this behaviour doesn't make it
impossible to enumerate the device is that this only affects
to_device control transfers with wLength > 0, and during enumeration
there are not many of those happening.
When enumerating a HID keyboard, there is only _one_ of those
happening, and it is the initial setting of the lock light led status.
And that first one succeeds because it's the first one. (However, later
lock light setting control transfers can cause problems, which is how
this problem was encountered.)

The solution in this commit is to keep better control over when EP0_OUT
is armed. This forces the Data-Stage to arrive later (the host will keep
re-trying), and that way the corruption of the buffer control register
is avoided.

Summary of the changes:
 - Rework the logic around deciding wether to re-arm the out endpoint
   after a read. For non-0 endpoint the previous behaviour is kept,
   however for EP0 it is only re-armed if more OUT transactions are
   expected for that SETUP transfer (be it data-stage or status-stage)
 - Force un-arm the EP0_OUT endpoint in case a stall condition is observed.
 - When a setup transfer is received check if EP0_OUT is already armed.
   If armed then log a warning message, and force-disarm it.
 - When a setup req interrupt fires, don't immediately force the next
   read to get it, instead, it will be read only after a setup message
   is extracted from the message queue.
 - When a setup packet is received abort any unfinished previous control
   transfers:
    - cancel any data buffers given to the EP0_IN endpoint
    - drop any new ep0_in writes that are attempted before this newest
      setup packet's associated message is extracted from the message
      queue.
 - In the ISR, check buffer interrupts before setup req interrupts.
   This is to make sure that the final 0-length status message from the
   previous setup packet is consumed before the new setup packet.
   (this is the only case now when both interrupts could be seen as
   having fired by the time the interrupt handler routine executes.

Signed-off-by: Purdea Andrei <andrei@purdea.ro>
Co-authored-by: Johann Fischer
2023-03-02 12:58:24 +01:00
Purdea Andrei 158ee9139c drivers: usb_dc_rpi_pico: cleanup incorrect comment and condition
I believe this comment and condition may have found its way into the
rp2040 driver from other drivers where it makes more sense. For
example for the stm32 driver performing a read on the EP0_IN endpoint
turns it silently into a read on the EP0_OUT endpoint. As far as I can
tell, this really was only used to consume 0-length Status-Stages of
to_host control transfer in the other drivers.

Note that usb_dc_ep_start_read() is never called in an IN endpoint
in the rp2040 driver, and furthermore, even if it would have been
called like that, the current implementation would not do the silent
change into actually performing a read on the EP0_OUT endpoint instead,
so the condition and comment is just wrong.

Note that 0-length Status-Stage of to_host control transfers is
currently consumed in this driver by usb_dc_ep_read_continue().

Signed-off-by: Purdea Andrei <andrei@purdea.ro>
2023-02-11 08:23:03 +09:00
Purdea Andrei 4fcbba2fb1 drivers: usb_dc_rpi_pico: fix toggle data1/0 on to_device control transfers
The data stage of Control transfers that are sent from Host to Device, can
be made out of multiple OUT transactions, if the amount of data to be
transmitted is larger than the endpoint size. When this happens, the DATA
pid should be toggling. The USB Device driver of the pico must correctly
prime the EP0_OUT buffer with the correct data PID, otherwise the hardware
will reject the received transaction.

Before this change the driver used to always prime EP0_OUT with a DATA1
pid.
After this change the driver only uses DATA1 pid after a setup transaction,
and then toggles the pid for each transaction.

Signed-off-by: Purdea Andrei <andrei@purdea.ro>
2023-02-11 08:00:43 +09:00
Purdea Andrei 9a7f9ec0ba drivers: usb_dc_rpi_pico: avoid infinite unhandled irq retriggers
This driver enables a number of interrupts it does not attempt to handle.
This results in "unhandled IRQ: 0x...." messages being printed, and the
interrupt handler retriggers immediately again, and this happens again
and again forver, because nothing ends up clearing the interrupt.

This change implements very limited handling of these interrupts. A custom
warning is logged, and the interrupt is cleared.

This change does not imply that doing this is sufficient. More changes may
need to be implemented to more gracefully re-start transactions or
re-arm some endpoints, but this is one step in the right direction,
and at least the OS doesn't freeze up.

Signed-off-by: Purdea Andrei <andrei@purdea.ro>
2023-02-06 22:07:03 +09:00
Lukas Gehreke 1bd931ab66 drivers: usb_dc_rpi_pico: fixed buffer status handling
The buf_status register is 32 bit wide but was saved in a
uint8_t. This caused some buffers never to be handled which
results in the pico getting stuck in the interrupt handler.

Signed-off-by: Lukas Gehreke <lk.gehreke@gmail.com>
2022-11-11 08:50:09 +00:00
Gerard Marull-Paretas 178bdc4afc include: add missing zephyr/irq.h include
Change automated searching for files using "IRQ_CONNECT()" API not
including <zephyr/irq.h>.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-10-17 22:57:39 +09:00
Marcin Niestroj cf4578bdda drivers: usb_dc_rpi: set thread name
Thread name is useful when debugging or using shell with
CONFIG_THREAD_NAME=y.

Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
2022-09-02 11:00:48 +00:00
Marcin Niestroj 1e982fffd2 drivers: usb_dc_rpi: create thread and connect IRQ during init
So far thread was created as part of usb_dc_attach() by k_thread_create().
This means that if following function were executed:

 * usb_enable()
 * usb_disable()
 * usb_enable()

then k_thread_create() was called second time. This results in undefined
behavior.

Fix above issue by moving k_thread_create() invocation to function called
during system initialization.

While at it, move IRQ_CONNECT() and irq_enable() invocations to init as
well.

Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
2022-09-02 11:00:48 +00:00
Peter Johanson 43b77a2191 drivers: usb: Add RP2040 USB device support.
Add USB device driver for Rasberry Pico family of controllers.

Signed-off-by: Peter Johanson <peter@peterjohanson.com>
2022-05-13 16:28:27 +02:00