726 Commits

Author SHA1 Message Date
sakumisu
76b3720445 docs: release v1.6.0
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
bad94dfc67 update(class/cdc): change serial state macro
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
2783329509 chore: replace tab with space
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
3181819214 update(class/gamepad): use hid intf init api
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
12b3eca447 chore: update kconfig
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
1a3343bc11 update(port/ehci): set roothub speed to high
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:53 +08:00
sakumisu
0c86f1f5ff update(port/dwc2/usb_glue_infineon): add some check for m55
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-28 13:15:31 +08:00
sakumisu
e44d44f5b6 update(demo): remove all old desc api
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-24 17:39:42 +08:00
sakumisu
0ca521a1d0 update(port/dwc2/usb_dc_dwc2): move read setup into USB_OTG_GINTSTS_ENUMDNE irq
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-22 21:05:15 +08:00
sakumisu
309aa2ffd8 feat(port/dwc2): add infineon glue
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-22 21:01:32 +08:00
sakumisu
013f51312a update(port/dwc2): add usbd_dwc2_get_system_clock to replace SystemCoreClock
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-22 21:00:41 +08:00
sakumisu
2a20e074b3 update(port/dwc2): add check for fifo value with power on value
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-20 21:31:53 +08:00
MDLZCOOL
1528b533cf feat(musb): add support for ti microcontroller with musb ip 2026-01-18 18:48:14 +08:00
MDLZCOOL
e414833589 fix(musb): fix musb_pipe_alloc missing bus parameter, and fix host checks in irq
Includes:

- add `struct usbh_bus *bus` parameter to `musb_pipe_alloc`
- correct call in `usbh_submit_urb`
- correct host checks in irq
2026-01-18 18:47:55 +08:00
SunJ
1de6b93045 refactor(osal): replace NuttX internal APIs with POSIX APIs
Replace nxsched_self() and nxsched_set_priority() with
standard POSIX sched_getparam() and sched_setparam() in
usb_osal_thread_schedule_other().

This improves portability and follows POSIX standards for
thread priority management.

Change-Id: I2e637268f77e200fbdee3e7713cba1b115976696
Signed-off-by: SunJ <jsun@bouffalolab.com>
2026-01-13 17:43:29 +08:00
sakumisu
43cf82642c update(port/dwc2/usb_dc_dwc2): remove __UNALIGNED_UINT32_READ and __UNALIGNED_UINT32_WRITE because buf is always align4, only receive one setup packet
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-12 18:39:09 +08:00
HakumenJean
8d7a98fc9d Update T113S3 glue 2026-01-08 16:26:15 +08:00
sakumisu
ce32f73100 docs: fix typo 2026-01-07 22:37:14 +08:00
sakumisu
44d92be013 update(platform): remove net class weak api, check CONFIG_USBHOST_PLATFORM_* macro is defined or not in usbh_lwip.c
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-05 21:31:41 +08:00
sakumisu
d172c89eef fix(port/dwc2/usb_hc_dwc2): restart split transfer with dwc2_xxx_urb_init, do not use dwc2_chan_reenable api
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-05 21:22:09 +08:00
Alvin
9cbe4502e7 fix(bluetooth): Correct HCI packet type from SCO to ISO in USB host. 2026-01-05 17:46:15 +08:00
sakumisu
d50159638d fix(demo): fix cdc ecm string check
Signed-off-by: sakumisu <1203593632@qq.com>
2026-01-04 21:50:44 +08:00
sakumisu
fb6dbb442e docs: update net rst and readme
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-31 14:47:15 +08:00
sakumisu
7a2089f032 feat(class/gamepad): add gamepad device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-29 21:33:48 +08:00
sakumisu
be5ba641dd fix(port/dwc2/usb_hc_dwc2): fix incorrect HFIR_RELOAD_CTRL setting
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-26 21:55:12 +08:00
sakumisu
7317913efa fix: fix winusb string and audio macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-26 12:41:31 +08:00
sakumisu
94d1c6b1be fix(core/otg): fix deinit flag and mode check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-22 16:15:55 +08:00
sakumisu
3f23af5ad7 fix(serial): add default handler for gsm
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-21 21:12:15 +08:00
MDLZCOOL
34166b361a fix(rp2040): add rp2040 support to scons 2025-12-19 11:07:27 +08:00
sakumisu
a5f765d46e ci: add lshid cmd
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-18 22:09:48 +08:00
sakumisu
43b8237713 update(demo): format with macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-18 22:09:48 +08:00
sakumisu
20199f08c4 docs: update cache qa
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-18 22:09:48 +08:00
sakumisu
8c01a6ea46 update(usbh_gsm): add ml307r vid
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-18 22:09:43 +08:00
sakumisu
55ef0f6309 style: change \t to space
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-17 20:43:42 +08:00
sakumisu
587339b733 feat(class/hid): add hid report parse api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-17 20:43:15 +08:00
sakumisu
a6ffbd3600 fix(usbh_serial): fix serial iobuffer size, remove length limit of write
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-17 20:42:45 +08:00
sakumisu
baf2a56c93 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-17 14:23:38 +08:00
sakumisu
7b9b396ab4 fix(usbh_cp210x): remove ununsed code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-15 20:54:05 +08:00
sakumisu
3a1f3c3ba4 update: update host demo macros without value
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-15 20:53:45 +08:00
MDLZCOOL
1cbe3c5957 fix(serial): fix host serial framework support for rt-thread 2025-12-15 09:23:03 +08:00
MDLZCOOL
11b91a0283 fix(usbh_serial): don't resubmit the read urb when rx short packet 2025-12-14 08:51:51 +08:00
MDLZCOOL
b1ca0406a5 fix(usbh_ch34x): program baudrate registers after divisor calculation 2025-12-14 08:51:51 +08:00
MDLZCOOL
799ae48f7c feat(usbh_serial): Use Ping-Pong Buffer to Decrease Packet Loss 2025-12-14 08:51:51 +08:00
sakumisu
da2263728a refactor(serial): add host serial framework
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-12 22:45:10 +08:00
sakumisu
707e865627 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-12 22:43:35 +08:00
sakumisu
e951fd01c8 chore(cmake): fix cdc symbol name
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-12 22:33:06 +08:00
sakumisu
bf1d9db9a1 update(demo): format uac demos with macros
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-05 18:33:09 +08:00
sakumisu
a20f53c6de update(demo): add more descriptor init macros
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-04 10:55:01 +08:00
sakumisu
006123c296 update: remove old bl616 wifi driver, add new api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-03 17:27:28 +08:00
sakumisu
670bde3671 fix(core): fix warnings
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-03 13:38:49 +08:00
sakumisu
7098d42b87 update(port/dwc2/usb_hc_dwc2): reset channel with dwc2_halt in deinit
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-01 20:31:59 +08:00
sakumisu
e257e6ce5c update: remove ununsed bl616 wifi driver
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-01 12:36:14 +08:00
sakumisu
41ffa44a3f docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-01 12:28:55 +08:00
sakumisu
9efc8af07b update(demo): add comment for uac
Signed-off-by: sakumisu <1203593632@qq.com>
2025-12-01 12:28:27 +08:00
sakumisu
3e28c528a4 update(class/hub): remove hport sources safely
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-28 11:45:20 +08:00
sakumisu
e10b44f64e feat(core/usbh_core): support custom config index
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-27 22:43:56 +08:00
sakumisu
b1bbc9d39d update(port/musb/usb_hc_musb): reenable pipe alloc & free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-27 22:36:53 +08:00
sakumisu
31b79434ce docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-26 18:24:45 +08:00
sakumisu
f9a8b29b8a docs: bump version to v1.5.3
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 15:29:53 +08:00
sakumisu
a8939d5d7b update: remove ununsed osal
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 15:29:53 +08:00
Zhihong Chen
5641a2b882 port: update hpmicro port files for otg
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-11-25 15:29:53 +08:00
sakumisu
1cc9877b39 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 15:29:53 +08:00
sakumisu
62fbc1ffee refactor(otg): refactor otg framework
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 15:29:52 +08:00
sakumisu
d68064e4e3 feat(class): support more match flags for cdc acm & rndis
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 15:29:01 +08:00
sakumisu
47cc574730 update(core): change assert with USB_ASSERT_MSG
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-24 20:36:23 +08:00
sakumisu
510b34aa3c update(platform/daplink): sync with cherrydap
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-24 20:36:23 +08:00
sakumisu
5917aff5f5 fix(osal/usb_osal_ucosiii): fix msleep opt
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-23 21:36:45 +08:00
sakumisu
449ea2664e feat(core/usbh_core): support interfacenum match flag
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-20 22:49:41 +08:00
sakumisu
21633d2138 update(port/dwc2/usb_glue_st): increase ep1 tx fifo for audio demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-19 22:22:35 +08:00
sakumisu
9ebc004aa4 update(core/usbh_core): print interface num when load driver
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-13 22:04:20 +08:00
sakumisu
9433ed3da5 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-13 22:03:36 +08:00
sakumisu
729136ea80 refactor(core/usbh_core): refactor lsusb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-11 22:46:20 +08:00
sakumisu
a2352bffdb ci: update bl & hpm demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-10 20:34:55 +08:00
sakumisu
9a1ead9e8a fix(port/dwc2/usb_dc_dwc2): invalid cache before all read setup
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-09 22:29:18 +08:00
蒙蒙plus
bb2a50712b fix(usb_dc_dwc2): add unaligned read/write macros for IAR compiler 2025-11-07 15:40:18 +08:00
Rbb666
eec89fd768 fix:Fix RNDIS DHCP dependency,and delay implementation 2025-11-07 15:35:58 +08:00
sakumisu
e453e72bf1 fix(osal/usb_osal_threadx): delete self in another thread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:40:47 +08:00
sakumisu
316c46e797 update(platform/rtthread): change LWIP_NO_RX_THREAD check error to warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:40:09 +08:00
sakumisu
5a4b68608b ci: enable all class
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:39:24 +08:00
sakumisu
cddc373eb2 feat(platform/idf): add fatfs port for host msc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 22:58:09 +08:00
sakumisu
cf85c8851a fix(osal/usb_osal_ucosiii): lock before free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:50:51 +08:00
sakumisu
39bff0fb10 fix(class/hub): delete thread before delete mq
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:50:43 +08:00
sakumisu
d0a8f5b2d0 update(platform/rtthread): add more check for chip cache
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:38:57 +08:00
sakumisu
d482b7c738 update(core/usbh_core): add retry for control transfer, some devices are flakey
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:01:12 +08:00
sakumisu
1d3b7fb203 fix(osal/usb_osal_ucosiii): memset after malloc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 21:21:37 +08:00
sakumisu
0c220ea127 chore: add build ci
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 21:21:26 +08:00
sakumisu
922ff0be42 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-31 22:20:42 +08:00
sakumisu
855898d134 update(port/chipidea): add dcache support for device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-30 21:33:23 +08:00
sakumisu
dd46b8ce39 feat: support custom ep0 mps
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-22 20:34:22 +08:00
sakumisu
76e7c1e163 feat(demo): add mongoose rndis demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-16 18:38:58 +08:00
MDLZCOOL
3e3b08b152 refactor(usb_osal_threadx): optimize the creation and deletion of threads
- Allocate only once at `usb_osal_thread_create`.
- Fixed a null pointer crash in `usb_osal_thread_delete`.
- Standardized the return value of `usb_osal_sem_give`.
2025-10-15 22:40:06 -07:00
sakumisu
2e37b620b4 update(port/hpmicro): add dcache support for device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-11 20:29:54 +08:00
sakumisu
31fcee272d update(demo/cdc_acm_rttchardev): add finsh & console switch with usb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-11 20:28:54 +08:00
sakumisu
3aa8420342 update(platform): remove CONFIG_USB_DCACHE_ENABLE, always check align size
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-11 20:26:19 +08:00
sakumisu
498ba9b4e1 feat(osal): add ucosiii osal
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:28:41 +08:00
sakumisu
825e5b1f9e update(port/dwc2/usb_glue_hc): update hc port
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:28:13 +08:00
sakumisu
ec82b8a36c update(hub/usbh_hub): add check for nports
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:27:17 +08:00
sakumisu
5fcbbcd93a fix: fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:26:48 +08:00
sakumisu
c25171d69f fix(port/ehci): clear iaad status before set
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-27 22:20:10 +08:00
sakumisu
bfb55eeb36 feat(class/video/usbh_video): support bulk mode
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-27 20:58:45 +08:00
LiPeng
5ea75a14d0 fix: Remove usb component private requirement for idf v6 2025-09-11 17:00:45 +08:00
LiPeng
e748e55f4d bugfix: Fix some compilation errors 2025-09-01 20:06:25 +08:00
LiPeng
55ce05f270 bugfix: Fix support for idf versions lower than 5.3 2025-09-01 15:35:51 +08:00
Egahp
5d5b61a606 feat: host add event callback mechanism similar to device
* fix: fix warning for speed_table
* fix(port/dwc2/usb_hc_dwc2): add roothub.speed init
* feat(usbh_core): add event_callback
* fix(usbh_hub): fix event device reset port
* fix(usbh_hub): remove event init when init failed
* feat(usbh_core): add default dummy_event_callback
* fix(usbh_hub): emit reset event only on successful reset
* fix(usbh_core): emit interface start only on successful connect class driver
* feat(usbh_core): change event_callback to typedef
* feat(port): update port usbh init params
* doc: update usbh_initialize desc
* fix(usbh_core): check result from ret == 0 change to ret >= 0
---------

Signed-off-by: egahp <2687434412@qq.com>
2025-08-30 19:24:02 +08:00
sakumisu
257b1d4d20 fix(demo): fix missing ecm mac address string
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-27 21:23:35 +08:00
sakumisu
8c47395904 docs: remove ununsed code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-27 21:21:09 +08:00
sakumisu
5130d22766 refactor(core/usbh_core): refactor devaddr allocation, use auto increment
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-27 21:19:43 +08:00
sakumisu
6256260203 style: remove printf with USB_LOG_XXX
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-27 21:01:34 +08:00
HalfSweet
f0d93dcdc1 feat: Add MUSB IP without multipoint feature support 2025-08-11 22:05:55 +08:00
sakumisu
4d6b12c704 docs: release v1.5.2
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-07 21:49:51 +08:00
sakumisu
5d2a7ca6bc fix(port/musb/usb_hc_musb): add rxmap & txmap config
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-07 21:11:05 +08:00
sakumisu
3ab47e0295 feat(port): add urb->complete in usbh_kill_urb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-06 21:24:59 +08:00
sakumisu
2081360f2c update(port/dwc2): add mode check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-05 21:46:01 +08:00
sakumisu
8cf12c1958 update(port/musb): add mode check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-05 21:27:45 +08:00
sakumisu
c0f544dafe fix(class/mtp): fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-04 21:56:57 +08:00
sakumisu
599b11ef1a update(osal/idf): change xtaskcreate to xTaskCreatePinnedToCore
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-04 21:47:55 +08:00
sakumisu
7037fd0e8d update(port/dwc2/usb_hc_dwc2): only clean & invalid buffer in usbh_submit_urb, do not clean&invalid many times
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-02 21:09:50 +08:00
sakumisu
3905eff2f4 docs: update readme
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-02 17:55:46 +08:00
sakumisu
20ceaced92 update(core/usbh_core): check string support and then get string desc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-01 21:38:47 +08:00
sakumisu
9ddcbf58ca update(port/dwc2/usb_hc_dwc2): only set errorcode before urb waitup because split transfer will do many times
Signed-off-by: sakumisu <1203593632@qq.com>
2025-08-01 21:13:46 +08:00
sakumisu
6e9e769e10 docs: update image
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-31 21:23:02 +08:00
sakumisu
65288c9d5b update(port/dwc2/usb_hc_dwc2): stop split transfer when intr nak, follow with nosplit intr transfer
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-31 21:22:48 +08:00
sakumisu
4ab097d9dc fix(common/usb_util): fix missing __ICCARM_V8 define
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-31 18:15:42 +08:00
sakumisu
f994422c41 chore(scons): export hpmicro dir
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-31 18:14:49 +08:00
egahp
5ae04f1273 fix(port/dwc2/usb_dwc2_param): fix macro literal types
Signed-off-by: egahp <2687434412@qq.com>
2025-07-31 14:11:28 +08:00
sakumisu
e574ea8ae3 Revert "fix(port): reset sem when pipe free"
This reverts commit ccd4354960.
2025-07-30 22:50:21 +08:00
sakumisu
f949e16564 update(port/dwc2/usb_hc_dwc2): add new api for split transfer, make code simple
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-30 22:21:54 +08:00
sakumisu
1bec84471e docs: update img
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-29 18:22:38 +08:00
sakumisu
1f065cec44 update(port/musb/usb_hc_musb): check urb for iso to support iso later
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 22:08:20 +08:00
sakumisu
3b1853ceb5 fix(platform/rtthread): change RT_USING_CACHE to CONFIG_USB_DCACHE_ENABLE
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 21:23:23 +08:00
sakumisu
72d19ec8cc update(usb_config): change CONFIG_USBHOST_MAX_INTF_ALTSETTINGS to 2 as default to avoid -Warray-bounds warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 21:03:55 +08:00
sakumisu
90de3354b5 update(port/musb): If ep control register group exists, do not use epidx register
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 20:20:16 +08:00
sakumisu
3784ddc389 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 19:15:33 +08:00
sakumisu
81d8f22e05 update(port): remove all ips CONFIG_USBDEV_EP_NUM & CONFIG_USBHOST_PIPE_NUM
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 19:06:37 +08:00
sakumisu
3b04facd09 revert: revert 1a68d94c some changes
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-28 14:18:18 +08:00
sakumisu
8dd3106e62 update(common/usb_hc): change interval u16 to u32 for us
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 21:25:27 +08:00
sakumisu
9e4122f2a0 fix(osal/idf): fix esp timer handle
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 21:22:18 +08:00
sakumisu
083ec57384 update(core/usbh_core): do not assert when parse desc fail, just return error
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 21:06:19 +08:00
sakumisu
ccd4354960 fix(port): reset sem when pipe free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 20:58:47 +08:00
sakumisu
60ac6fe3ad fix(port/ehci): remove usb_osal_msleep in critical section
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 20:46:12 +08:00
udoudou
0986e8b5ec Fix the bug that dwc2_halt may cause hardware abnormality 2025-07-27 20:30:08 +08:00
udoudou
ae2a24642b Fix a bug where the channel might not be released 2025-07-27 20:30:08 +08:00
udoudou
1a68d94c32 add reset port timeout check for dwc2 2025-07-27 20:30:08 +08:00
sakumisu
c102f4adfa update(usb_config): change CONFIG_USBHOST_MAX_INTF_ALTSETTINGS to 1 as default for less memory usage
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 10:26:31 +08:00
sakumisu
d589b9417d update(osal/idf): change freertos timer to esp_timer
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-27 10:21:00 +08:00
sakumisu
7b39de9630 update(port/dwc2/usb_glue_kendryte): update dwc2 param
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-26 16:48:12 +08:00
sakumisu
6702ab9225 update(port/dwc2): invalid data before start read
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-26 16:11:47 +08:00
sakumisu
ecb98f399d update: add output_len param for usbh_get_string_desc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-25 22:37:25 +08:00
sakumisu
a9ec951c93 update(common/usb_hc): change interval u8 to u16 for us
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-25 22:24:35 +08:00
sakumisu
9de28f9342 style: format log
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-25 18:45:38 +08:00
sakumisu
dc7e53d79f fix(port/dwc2/usb_hc_dwc2): exit porten loop check when device disconnets
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-24 21:03:22 +08:00
sakumisu
d3a5aae7af fix(class/hub/usbh_hub): fix port to port+1
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-24 21:00:21 +08:00
Matthew
7153fb9756 fix(platform/rtthread): add RT_DEVICE_FLAG_INT_RX falg to device 2025-07-24 18:29:34 +08:00
Matthew
0e31b40407 fix(platform/rtthread): restart read at usbd_cdc_acm_bulk_out 2025-07-24 18:29:34 +08:00
sakumisu
fa5a9fbcaa update(platform/rtthread): remove align size check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-22 20:24:41 +08:00
sakumisu
68b28a43f3 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-22 18:20:37 +08:00
sakumisu
ddda03c4cb update(port): remove CONFIG_USBDEV_EP_NUM & CONFIG_USBHOST_PIPE_NUM for some ips because they are constant
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-21 21:22:54 +08:00
sakumisu
96ab19e398 fix(core/usbh_core): change 2ms to 10ms because some platform's tick is 100hz then 2ms = 0ms, refs: #342
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-20 21:29:48 +08:00
sakumisu
2783793b17 fix(port/dwc2/usb_hc_dwc2): check buf is valid then using dcache clean
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-20 21:25:20 +08:00
sakumisu
e499871a59 fix(port/dwc2/usb_glue_st): reduce f4 total size for some specific f4 chips
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-19 10:08:52 +08:00
Derek Konigsberg
7c38af1b04 Clear error code after intentionally ignoring it
In the case of handling a stall on a max lun request, we need to clear the error code in `ret` after ignoring it. This is necessary so the connect function won't fail.

Fix #339
2025-07-19 09:20:49 +08:00
sakumisu
cc3e91e8d7 fix(port/dwc2/usb_hc_dwc2): invalid indata before urb done
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-18 23:16:41 +08:00
sakumisu
a95e06a951 update(cherrymp): update local ringbuf
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-18 22:50:48 +08:00
sakumisu
502c88084c update: remove zephyr bluetooth submodule
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-18 22:46:55 +08:00
sakumisu
a9f0374fa7 style: format code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-18 22:36:23 +08:00
sakumisu
56c864b008 fix(port/dwc2/usb_hc_dwc2): fix control split transfer with short packet
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-18 21:36:19 +08:00
sakumisu
80f0f97efa fix(port/dwc2/usb_glue_at): fix host rx size
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-17 23:01:32 +08:00
sakumisu
4fdbe4ed26 docs: update image
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-17 22:23:45 +08:00
sakumisu
1e8e440721 fix(demo): ignore zero bytes for bl ip
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-16 22:54:21 +08:00
sakumisu
605a967282 style: remove some logs
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-16 22:17:19 +08:00
sakumisu
7a357a10da feat(port/dwc2): support ep mult
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-16 21:49:54 +08:00
LiPeng
d58037e3d4 Add FS support for ESP32-P4 2025-07-14 20:50:16 +08:00
sakumisu
f3b5025b64 update(cherryusb): update to v1.5.1
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-14 11:49:37 +08:00
sakumisu
e32486f9a8 feat: support sifli
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-13 20:25:58 +08:00
sakumisu
064507bfe8 update(core/usbd_core): add ep0 state log
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-13 17:17:38 +08:00
sakumisu
e61141a45e update(port/dwc2/usb_dc_dwc2): use usbd_get_ep0_next_state for reading setup
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-13 17:17:19 +08:00
sakumisu
4ce8c507b0 update(demo): remove ep num check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-13 16:39:33 +08:00
sakumisu
85e420eb54 update(port/fsdev): assert for fsdev log
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-13 16:39:20 +08:00
sakumisu
40a052ba7f chore(kconfig): add more config
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-11 18:34:46 +08:00
sakumisu
3249811a90 fix(port/dwc2/usb_dc_dwc2): align with CONFIG_USB_ALIGN_SIZE not only 32
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-11 18:34:26 +08:00
sakumisu
c5b1e1af27 fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-11 15:16:01 +08:00
sakumisu
78a802faa6 update(port/dwc2/usb_glue_at): update at glue with dwc2 param
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-10 21:52:58 +08:00
sakumisu
811550ad25 chore(port/dwc2): update readme
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-10 21:52:14 +08:00
mlwang
4093a3b01d fix(port/ehci): Fix the urb leak when there is no data in the control transmission 2025-07-10 21:45:45 +08:00
MDLZCOOL
9de928d6af Modify kconfig for better template choose 2025-07-10 20:19:16 +08:00
sakumisu
5a94ed80cb feat(port/dwc2): add user fifo config api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-07 20:28:14 +08:00
sakumisu
22e150a8e6 refactor(port/dwc2): support custom config for each dwc2 usb port
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-05 16:39:54 +08:00
sakumisu
8e0ff856fe update(class/mtp): support obj remove & add event
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-03 20:54:30 +08:00
FanhuaCloud
739db92ef0 fix:(port/ch58x/usb_ch58x_dc_usbfs.c) fix out endpoint cannot receive bug 2025-07-03 16:15:08 +08:00
sakumisu
53e42e6ceb fix(platform/rtthread/usbh_serial): remove unused variable
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-02 20:17:20 +08:00
sakumisu
832e4c45fb fix(class/hub): change urb interval unit to us
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-01 21:21:59 +08:00
sakumisu
52ea7e8dcf fix(demo): fix webusb desc len
Signed-off-by: sakumisu <1203593632@qq.com>
2025-07-01 09:51:56 +08:00
sakumisu
5a3b87e08c feat(demo): add mavlink with cdc acm
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-26 18:28:46 +08:00
sakumisu
6f1228c029 fix(platform/rtthread): change ssize_t to rt_ssize_t
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-25 15:10:44 +08:00
sakumisu
e96e5fd9ca feat(platform/rtthread): support cdc acm chardev
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-25 14:07:06 +08:00
sakumisu
9d4faca7db fix(vendor/serial/usbh_ftdi): fix missing break
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-24 18:21:09 +08:00
sakumisu
c22615ea6f feat(platform/rtthread): support adb shell and serial framework
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-24 18:20:38 +08:00
sakumisu
749cd8531f docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-24 18:05:08 +08:00
sakumisu
734cacb177 fix(port/dwc2/usb_glue_st): fix GCCFG in stm32h7rs
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-23 22:20:17 +08:00
sakumisu
1f7070f5c9 revert(port/dwc2/usb_hc_dwc2): revert 4f831f58 change
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-23 20:12:34 +08:00
sakumisu
8d8f3e757e fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-19 20:02:19 +08:00
KK
5e890a078f msc: add support for SCSI_CMD_SYNCHCACHE10 (0x35) to fix unsupported command error 2025-06-17 16:18:03 +08:00
sakumisu
e530d86af7 docs: update version message
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-16 20:30:31 +08:00
sakumisu
300907dd4c update(platform/rtthread): move cache check into usb_check.c
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-16 20:30:23 +08:00
sakumisu
0916749a32 update(idf): increase host stack size
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-14 22:56:30 +08:00
sakumisu
9d29fece51 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-14 21:44:54 +08:00
马龙伟
8df2be2a52 add usb net under idf platform 2025-06-14 21:02:54 +08:00
sakumisu
7f3ddf5d83 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-13 21:55:37 +08:00
sakumisu
6a226e3e3c refactor(port/ch32): classify ch32 port
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-12 21:35:51 +08:00
sakumisu
8b63acd46c update(port/bl): add fs support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-12 20:45:53 +08:00
sakumisu
f7094028b8 fix(idf): fix p4 config
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-05 22:12:26 +08:00
sakumisu
5f9d06a9f5 update(platform/fatfs): change memalign to aligned_alloc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-05 12:40:54 +08:00
sakumisu
537ccfd945 fix(osal/usb_osal_rtthread): up version to v5.2.0 to use RT_SCHED_PRIV(self).current_priority
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 17:48:46 +08:00
sakumisu
6973ec73d9 update(cherryusb_config_template): update align size
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 16:17:18 +08:00
LiPeng
1feaed024e Fix esp32-p4 cache operation adaptation issue 2025-06-04 16:11:32 +08:00
sakumisu
88cbed9807 update(platform): make msc host with fs common for dcache
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 15:33:49 +08:00
sakumisu
1d95077161 feat(dcache): update dcache api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 15:33:42 +08:00
sakumisu
06a0c4393b feat(platform/zephyr): support msc host with disk
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 15:08:50 +08:00
sakumisu
6b7d755d3a update(class/hub/usbh_hub): reduce critical section range
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-04 13:08:51 +08:00
sakumisu
078e7d1be0 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 23:11:14 +08:00
sakumisu
ac4e4c569d feat(port/dwc2): add dcache api for esp & st
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 22:46:48 +08:00
sakumisu
b6650bdbc6 feat(port/dwc2/usb_dc_dwc2): support dcache
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 22:46:39 +08:00
sakumisu
bff8a632a9 feat(class): add usb_osal_thread_schedule_other to allow the applications which use the struct usbh_xxx to exit properly before free struct usbh_xxx
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 22:43:35 +08:00
sakumisu
a8bf2687bd update(core/usbd_core): include dcache & osal header
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 22:43:35 +08:00
sakumisu
0251e3a145 update(port/dwc2): implement usbd_dwc2_delay_ms with nop delay
Signed-off-by: sakumisu <1203593632@qq.com>
2025-06-03 22:43:35 +08:00
sakumisu
f7c354b4eb docs: update image
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-30 19:00:41 +08:00
sakumisu
ff42a6f2ea update(demo): add usbd_audio_set_sampling_freq and usbd_audio_get_sampling_freq for audio demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-30 17:11:26 +08:00
sakumisu
ca71e7411e fix(osal/usb_osal_liteos_m): fix task delete when thread is null
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-30 14:36:02 +08:00
sakumisu
16858c105a fix(port/dwc2/usb_hc_dwc2): fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-29 20:35:44 +08:00
sakumisu
8c5026e9cb fix overflow warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-29 10:51:49 +08:00
sakumisu
8a81d81435 update(class/video): change headerlen to 12 for 4 byte align, fix encoding
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-29 10:47:10 +08:00
sakumisu
c75e62c1e9 fix(idf): fix p4 config
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 22:33:00 +08:00
sakumisu
5a6023118e fix(port/chipidea): fix qtd buffer setting
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 22:32:54 +08:00
sakumisu
51ad3717c5 chore(cmake): disable bluetooth
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 21:24:56 +08:00
sakumisu
0ee859d339 docs: update usage, disable log
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 21:24:39 +08:00
sakumisu
e6d81344c3 refactor(class/video/usbd_video): zero copy for video data transfer
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 17:34:44 +08:00
sakumisu
af6df63acb fix(port/ch32): clear intflag first, set nak before handling ep in
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-28 12:26:26 +08:00
sakumisu
b4fb10ee98 update(core/usbd_core): clear configuration in disconnect callback
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-27 20:34:18 +08:00
sakumisu
e3c50cde10 fix(platform/usbd_fatfs_mtp): DIR with dynamic
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-27 20:34:18 +08:00
sakumisu
e65b8c0614 docs: update readme
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-27 20:34:18 +08:00
sakumisu
f9189b4278 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-26 22:10:25 +08:00
sakumisu
51ea604ded update(demo): add ep num check for some templates
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-26 21:54:47 +08:00
sakumisu
fe24f8d4ba feat(class/mtp): support mtp device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-26 21:54:32 +08:00
sakumisu
5fed8b7d05 update: sync code from rtthread master
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-20 18:46:18 +08:00
sakumisu
45ccc810d2 fix(demo): move dhcp_start in init
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-20 18:45:51 +08:00
sakumisu
7e5713ab89 chore: bump version to v1.5.0
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-19 17:22:23 +08:00
sakumisu
05e5730cc2 update: enable CONFIG_USBDEV_ADVANCE_DESC as default
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-19 17:22:23 +08:00
Zhihong Chen
d6f912c48d fix zephyr build warning
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-05-19 14:56:39 +08:00
Zhihong Chen
7465a59eaa [update] port: hpmicro: update port files
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-05-19 14:56:39 +08:00
sakumisu
e301e1f0a9 update(port/fsdev): assert for fsdev iso
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 20:51:37 +08:00
sakumisu
401dded10a docs: update format
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 20:27:06 +08:00
sakumisu
03fc8b668a fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 20:22:48 +08:00
sakumisu
edc0c95db2 refactor(port/nxp): combine nxp mcx glue for chipdea & ehci
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 20:20:54 +08:00
sakumisu
10e7fb60b4 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 18:15:49 +08:00
sakumisu
619fb4fa5b fix(class/vendor/ftdi): fix ftdi baudrate caculation
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 18:12:11 +08:00
sakumisu
eadcf7530b refacor(port/hpmicro): move hpmicro glue into hpmicro directory
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 17:23:35 +08:00
sakumisu
43692c0ba2 chore: update zephyr code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-15 09:47:59 +08:00
sakumisu
383d9b3141 docs: add actions
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-14 22:43:24 +08:00
chenzhihong007
01a25c7d93 [port] hpmicro: update usb_dc_hpm.c (#317)
- use USB_NOCACHE_RAM_SECTION instead of ATTR_PLACE_AT_NONCACHEABLE

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-05-14 15:00:43 +08:00
sakumisu
5e45d15292 fix(port/ehci/usb_hc_ehci): fix qtd->hw.alt_next_qtd should be 1 not zero
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-14 14:56:43 +08:00
sakumisu
b19f70575a feat: add nationstech support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-13 23:15:48 +08:00
sakumisu
4f831f58ef fix(port/dwc2/usb_hc_dwc2): do not disable channel for non-split periodic channels in buffer dma
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-13 19:38:47 +08:00
sakumisu
684041f285 fix(core/usbd_core): add check for desc callback
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-13 14:42:18 +08:00
sakumisu
dbfcdb55af docs: update version rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-13 11:14:49 +08:00
sakumisu
dd4c4fe180 update(port/dwc2): check crstdone with bit29 after dwc2 4.20a version
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-13 11:14:20 +08:00
sakumisu
3a028f7acf update(port/ehci/usb_glue_t113): update clock config
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-12 21:03:40 +08:00
chenzhihong007
8c100cdccd [update] port: hpmicro: update usb_dc_hpm.c (#316)
- update usb_dc_hpm.c

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-05-12 11:01:08 +08:00
sakumisu
6064c0beef docs: update show
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-11 22:57:45 +08:00
sakumisu
dc5e8dc5ed feat(port/dwc2/usb_hc_dwc2): support external hs hub with fs/ls device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-11 22:43:49 +08:00
sumengqi
4d3770b5d0 fix:(port/ch32/usb_dc_usbhs.c) fix isochronous in endpoint config bug (#314)
* fix:(port/ch32/usb_dc_usbhs.c) fix isochronous in endpoint config bug
2025-05-11 09:09:06 +08:00
sakumisu
336aa91d24 update(port): add sof support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-10 21:26:53 +08:00
sakumisu
7a0e8cae1a update(port/musb/usb_hc_musb): flush and disable ep intr in usbh_kill_urb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-10 17:48:34 +08:00
sakumisu
a92b5488b0 chore(kconfig): update rtthread pkg & master kconfig
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-10 17:07:13 +08:00
sakumisu
5253d5aa6b update(port): add USB_ASSERT_MSG for ep num check
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-10 17:07:03 +08:00
sakumisu
8393ed986a chore(cmake): add CONFIG_CHERRYUSB check, update custom file cmake
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 18:55:16 +08:00
sakumisu
19f7548b60 update(cherryusb_config_template): update macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 18:21:47 +08:00
sakumisu
ba2f91f24c fix(port/musb/usb_dc_musb): enable USB_TXCSRH1_MODE for in ep
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 18:10:45 +08:00
sakumisu
2d8c4ca56a chore(cmake): move hpm config at last
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 16:59:54 +08:00
sakumisu
0ba374253b update(common/usb_memcpy): add CONFIG_USB_MEMCPY_DISABLE macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 16:47:23 +08:00
sakumisu
7affefe7f9 chore: add zephyr module
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 16:42:23 +08:00
sakumisu
910f1f64ad docs: update usage
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 16:16:49 +08:00
sakumisu
96cbbfc1be docs: add performance show
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-09 13:35:23 +08:00
sumengqi
9d06a940f0 fix:(port/ch32/usb_dc_usbhs.c) Add isochronous out transfer support and fix endpoint config bug (#310)
* fix:(port/ch32/usb_dc_usbhs.c) Add isochronous out transfer support and fix endpoint config bug
2025-05-09 10:03:16 +08:00
sakumisu
c659bdc604 update(demo): update rndis & ecm device for rtthread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-08 22:48:35 +08:00
sakumisu
40f164e81e chore: music file too big, remove it
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-08 22:31:01 +08:00
sakumisu
e0289d79f9 update(demo): wait done in linkoutput_fn for rndis & ecm, retransmission in lwip costs too much time
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-08 22:30:52 +08:00
sakumisu
6516a470c8 update(port/ch32): update irqhandler name
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-07 22:07:22 +08:00
sakumisu
bf2ba7324a update(class): replace ecm & rndis USB_ERR_NOTDEV with USB_ERR_NOTCONN
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-07 19:48:39 +08:00
sakumisu
cf22bcf252 update(class/wireless/usbd_rndis): use usbd_rndis_start_write for usbd_rndis_eth_tx
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-07 18:09:19 +08:00
sakumisu
d122f2d8f7 update(demo): include dnserver & dhserver config for rndis & ecm
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-07 18:00:20 +08:00
Runcheng Lu
d012974a0e platform: lvgl: update features and support both LVGL 8 and LVGL 9
Signed-off-by: Runcheng Lu <runcheng.lu@hpmicro.com>
2025-05-07 09:21:31 +08:00
Runcheng Lu
609305a28f class: hid: Fix typo: MODIFER → MODIFIER
Signed-off-by: Runcheng Lu <runcheng.lu@hpmicro.com>
2025-05-07 09:21:31 +08:00
sakumisu
d4dfb03afc update: add USB_ASSERT_MSG for common case
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 22:34:41 +08:00
sakumisu
a41000a000 update(port/aic): sync code from luban lite
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 21:45:03 +08:00
sakumisu
e29d87bb20 update(osal): rename ticks to timeout_ms
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 18:16:04 +08:00
sakumisu
93a8457700 feat(osal/usb_osal_zephyr): add zephyr osal
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 18:09:43 +08:00
sakumisu
3f736a3622 chore: update cmake & kconfig & scons
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 18:09:06 +08:00
sakumisu
ccbe0232dc update(osal/usb_osal_nuttx): update timer driver
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 18:08:36 +08:00
sakumisu
9aa7a76353 update(port/dwc2/usb_glue_st): change USB_OTG_HS_PERIPH_BASE to 0x40040000UL
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-06 18:07:57 +08:00
sakumisu
8bc602dc74 docs: update note
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-05 22:41:18 +08:00
sakumisu
51ef13d217 fix(port/bl): enable PDS_REG_USB_IDDIG bit for device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-05-05 18:59:51 +08:00
sakumisu
7d93f7d0f0 chore(cmake): update cmake
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-30 23:00:35 +08:00
sakumisu
5990e5c607 update(demo/usb_host): add fatfs speed test
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-30 21:38:09 +08:00
sakumisu
577ebd0999 fix unused warnings
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-30 21:37:50 +08:00
sakumisu
c27458d71a update(platform): update platform code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-30 10:11:04 +08:00
sakumisu
644ac2b37f update(common/usb_log): update USB_ASSERT
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-29 18:01:35 +08:00
sakumisu
d3de69ae38 update(class/wireless/usbd_rndis): enable indicate msg for sending connect status
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-29 16:25:45 +08:00
sakumisu
33dd56b7ce update(port/ehci): use static qtd pool for qtd alloc & free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-29 16:25:45 +08:00
sakumisu
8aad86f66b update(class): add weak api to avoid undefine symbol(not use such class but add)
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-28 21:32:19 +08:00
sakumisu
0c3a64516d update(rtthread): add check for use dfs
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-26 17:22:47 +08:00
sakumisu
95d968bd57 feat(port/fsdev/usb_glue_st): implement low level api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-25 21:10:34 +08:00
sakumisu
4edd86c872 fix(port/dwc2/usb_hc_dwc2): change packet uint8_t to uint16_t
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-24 19:33:21 +08:00
sakumisu
166795bd72 feat(port/dwc2/usb_glue_st): implement low level api for device and host
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-24 19:32:29 +08:00
sakumisu
a838edb3e6 fix wformat warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-23 21:38:54 +08:00
sakumisu
894b80d9ed fix(port/dwc2/usb_hc_dwc2): enlarge pktcnt to 0x3ff, GHWCFG3(bit4:6) = 6, GHWCFG3(bit0:3) = 8
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-23 18:21:31 +08:00
minlewang
4c8d448ca2 cmake_format (#305)
cmake: Format CMake files using cmake_format and add a .cmake_format.json file.

Co-authored-by: mlwang <mlwang@bouffalolab.com>
2025-04-23 10:39:29 +08:00
chenzhihong007
4897d6d622 port: hpmicro: update isr processing (#304)
- update isr processing

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-04-23 09:43:52 +08:00
sakumisu
e0fedaa956 refactor(class/usbd_msc): replace cherryrb with only variable
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-22 14:59:32 +08:00
sakumisu
d10b88c1a1 feat(core/usbd_core): add ep0_next_state to record control transfer state
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-21 18:23:30 +08:00
sakumisu
dd8ec4bbcf fix wformat warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-19 23:01:59 +08:00
sakumisu
e6fb6af4a9 feat(class/usbh_hid): add usbh_hid_get_protocol api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-17 11:32:31 +08:00
sakumisu
947f8530ef feat(platform/lvgl): enable hid boot protocol
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-17 11:29:18 +08:00
sakumisu
73c8062518 docs: fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-16 20:19:47 +08:00
sakumisu
3f190b127d feat(platform): add filex support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-16 18:21:38 +08:00
sakumisu
215db93943 feat(platform): add lvgl mouse&keyboard support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-15 12:05:23 +08:00
sakumisu
c916f63bc3 docs: fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-13 19:11:28 +08:00
sakumisu
8392ba6810 fix(scons): fix pusb2 path
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-12 21:06:34 +08:00
sakumisu
e5989ee41a update(demo): use largest frequence from table
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-12 17:21:33 +08:00
sakumisu
364eb60396 update(demo): enable feedback trasnfer when USING_FEEDBACK=1
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-12 16:39:08 +08:00
sakumisu
dae76cb7bd update(class/hid/usbd_hid): remove ununsed api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-04-09 22:27:20 +08:00
huohongpeng
339a99a728 osal: add liteos_m osal (#301)
- support liteos_m

Signed-off-by: Hongpeng Huo <hongpeng.huo@hpmicro.com>
2025-04-04 13:57:22 +08:00
sakumisu
6f25f797ed feat(port/kinetis): add mm32f5 support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-29 15:37:03 +08:00
sakumisu
9a26c50900 fix: fix wformat warnings
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 22:39:30 +08:00
sakumisu
91684e0677 update: change memcpy with usb_memcpy, fuck newlib with memcpy unalign bug
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 22:39:22 +08:00
sakumisu
4a9c90ddc0 docs: update link
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 22:39:10 +08:00
sakumisu
83695e77cf update: add usb align up for every buffer when use dcache clean&invalid api
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 13:29:04 +08:00
sakumisu
5666fcb540 update(port/ohci): add pad for ed&td cachemaintain, add CONFIG_USB_OHCI_DESC_DCACHE_ENABLE for ed&td
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 13:29:04 +08:00
sakumisu
e9257baa5d update(port/ehci): add pad for qh&qtd cachemaintain, add CONFIG_USB_EHCI_DESC_DCACHE_ENABLE for qh&qtd&itd
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-28 13:29:04 +08:00
MDLZCOOL
f48fa44368 docs: 更新 README 文件结构和内容 (#300)
* docs: 更新 README 文件结构和内容

- 统一文字,英文文档中不应该出现中文字符
- 在 README.md 中添加简体中文和繁体中文版本的链接
- 重新组织 README.md 的结构,优化标题层级
- 删除冗余的空行和不必要的标点符号

* docs: 更新 README 文件结构和内容

- 统一文字,英文文档中不应该出现中文字符
- 在 README.md 中添加简体中文和繁体中文版本的链接
- 重新组织 README.md 的结构,优化标题层级
- 删除冗余的空行和不必要的标点符号

* docs: 更新文档格式和内容

- 调整表格格式,使其更加规范和易读

* docs:修复 README 文件中的徽章链接

- 修复docs中没有正确闭合的标签

* docs: 移除了 README_zh-TW.md

* docs: 移除 README_zh-CN.md 重新添加 README_zh.md 文件
2025-03-28 13:27:52 +08:00
Zhihong Chen
d9c0d27174 ehci: update config to improve performance
- update config to improve performance

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-03-28 13:27:23 +08:00
sakumisu
44dc3c00f6 docs: release v1.4.3
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-04 18:54:30 +08:00
sakumisu
4d5aa30778 update(cherrymp): remove malloc free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-04 17:13:02 +08:00
sakumisu
e581097309 fix(core/usbd_core): fix two bugs
- fix current_desc_len += p[DESC_bLength] before p+= p[DESC_bLength]
- fix reset all eps when alt_setting=0

Signed-off-by: sakumisu <1203593632@qq.com>
2025-03-04 17:13:02 +08:00
sakumisu
6378fb88d0 update(port/kinetis): add MCXA156 support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-26 20:49:09 +08:00
sakumisu
db0f5475b4 fix(port/ch32): add EPn_SET_TX_LEN for mps
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-25 22:16:09 +08:00
Chen Leeren
27c307abed Add ch585 usbhs dc 2025-02-25 22:14:09 +08:00
Chen Leeren
374e6d6e4d Fix ch58x fs ip send bug 2025-02-25 22:14:09 +08:00
sakumisu
c09ceb2537 fix(demo): split feedback caculate macro with AUDIO_FREQ_TO_FEEDBACK_XS and AUDIO_FEEDBACK_TO_BUF_XS
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-25 22:12:16 +08:00
sakumisu
56afada2cc chore: fix wformat warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-22 21:48:25 +08:00
sakumisu
8ac0b65b30 fix(port/dwc2/usb_glue_st): set GCCFG zero in host for stm32h7rs
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-22 19:12:51 +08:00
sakumisu
68434ccf7d update(demo): add cdc simple transfer for winusb2.0+cdc demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-16 20:29:05 +08:00
sakumisu
17a591f719 update(osal/idf): reduce tx fifo for more space for ep5 & ep6
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-16 20:26:30 +08:00
sakumisu
23d2327a52 fix(core/usbd_core): fix return with break in ep0 thread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-12 13:01:12 +08:00
sakumisu
de7a73bc2f update(port/dwc2/usb_glue_esp): add freertos/task.h for old esp-idf
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-11 21:28:50 +08:00
sakumisu
147dc4ab5d fix(core/usbh_core): check hport is valid in usbh_control_transfer
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-09 21:53:12 +08:00
sakumisu
20c298b6ba docs: update readme
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-09 15:33:53 +08:00
sakumisu
0c5d2ad729 feat(class/hid): add HID_X_DESCRIPTOR_INIT macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-08 22:59:09 +08:00
sakumisu
e90b29c2e7 feat(port/ehci): add t113 glue
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-08 22:45:23 +08:00
sakumisu
ac6db49d00 fix(core/usbh_core): return valid hport which is connected
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-07 20:15:08 +08:00
sakumisu
43e6b5b1b1 fix(demo): fix typo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-06 20:10:17 +08:00
sakumisu
40122200d1 chore: add more header path
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-05 22:49:13 +08:00
sakumisu
e85d898503 update(demo): add CONFIG_USBDEV_ADVANCE_DESC template
Signed-off-by: sakumisu <1203593632@qq.com>
2025-02-01 19:23:22 +08:00
sakumisu
e592a548e9 feat(core/usbd_core): add ep0 setup handler into thread feature 2025-02-01 14:45:02 +08:00
sakumisu
afc9213cd1 fix(port/dwc2/usb_hc_dwc2): fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 23:37:11 +08:00
sakumisu
0826c164da chore(kconfig): add rp2040
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 20:01:27 +08:00
sakumisu
609c85db68 update(platform/rtthread/usbh_dfs): move mount into another thread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 19:56:39 +08:00
sakumisu
d3aafb2174 update(port/rp2040/usb_hc_rp2040): add lock for ep0
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 15:19:34 +08:00
sakumisu
95baa7845c chore: fix wformat warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 13:18:50 +08:00
sakumisu
c827c2e50b update(class/msc/usbh_msc): move msc scsi commands out to prevent blocking enum thread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-26 12:50:48 +08:00
sakumisu
49d9775a1b feat(port/rp2040): update rp2040 host driver, use irq_add_shared_handler to register irq handler
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-25 19:11:27 +08:00
sakumisu
5573472397 fix(port/musb/usb_hc_musb): fix musb_write_packet size with urb->transfer_buffer_length
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-25 19:08:15 +08:00
sakumisu
fd033f25c5 feat(core/usbh_core): add usbh_printf_setup api for debug
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-25 19:08:15 +08:00
sakumisu
3e9f2b7777 docs: update hpmicro logo 2025-01-24 17:45:39 +08:00
sakumisu
efbfc9d70f update(port/template): update template
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-23 23:04:34 +08:00
sakumisu
f447de38dc update(port/rp2040): init ep_control & buffer_control in usb_dc_init
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-23 22:28:31 +08:00
sakumisu
8f44b8bad8 feat(platform/nuttx): update fs & net & cdcacm support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-23 17:58:53 +08:00
sakumisu
c399be3ea2 feat(common): add usb_phyaddr2ramaddr & usb_ramaddr2phyaddr macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-22 17:54:54 +08:00
chenzhihong007
1aa2d038aa osal: fix rtthread usb_osal_thread_delete() API (#288)
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-01-22 10:28:55 +08:00
sakumisu
6769eac6e0 feat(osal): add argument macro for different os, especially for nuttx
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-20 18:23:59 +08:00
sakumisu
646e84bedc update(platform/nuttx): add more macros check for net and msc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-20 18:20:21 +08:00
sakumisu
322595b910 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-19 21:23:26 +08:00
sakumisu
ea27f5b238 feat(port/rp2040): update rp2040 driver to latest
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-19 20:46:12 +08:00
sakumisu
d4940ebd22 update(nimble): remove nimble submodule, because it costs time to pull
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-19 17:38:43 +08:00
sakumisu
e1398982f3 update(platform/usbd_msc_blkdev): add rtt blkdev for msc here
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-19 17:34:32 +08:00
sakumisu
76b7a0172b update(class/wireless/usbd_rndis): support transfer api for enet & wireless without lwip
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-16 18:17:50 +08:00
sakumisu
6c3b828e77 update(class/msc/usbh_msc): add retry macro
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-16 16:49:58 +08:00
sakumisu
0a295ee5eb fix(audio): fix audio feedback value caculation
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-16 16:29:13 +08:00
chenzhihong007
5b74cecc4a [update] class: msc host: update msc host class stack (#285)
- use CONFIG_USBHOST_MSC_TIMEOUT as inquiry timeout
- separate cbw/csw from g_msc_buf
- try again ready check when device not ready
- print errcode in error log

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-01-16 10:48:11 +08:00
sakumisu
99e2e6bfd4 feat(core/otg): add otg framework
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-15 17:11:27 +08:00
sakumisu
64394bf246 update: add USBH_IRQHandler & USBD_IRQHandler function declaration
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-15 17:10:19 +08:00
sakumisu
1a1b475523 update(port): add ehci/ohci/dwc2 dcache support
Signed-off-by: sakumisu <1203593632@qq.com>
2025-01-15 17:09:22 +08:00
sakumisu
a1ac569236 update(demo): add macro for caculating feedback value 2025-01-13 21:28:06 +08:00
sakumisu
570d2b5ff8 feat(demo): add feedback for audio v1 speaker template 2024-12-28 17:48:54 +08:00
sakumisu
cc9c226aba feat(demo): add feedback for audio v2 speaker template 2024-12-28 16:50:25 +08:00
sakumisu
1be34f4d36 fix(core/usbd_core): fix ep config for more eps when call usbd_set_interface 2024-12-28 16:43:19 +08:00
sakumisu
515b83e0f8 docs: release v1.4.2 2024-12-23 20:04:02 +08:00
sakumisu
be6537637c chore: fix missing license 2024-12-23 20:01:05 +08:00
yangpeng
e6801fcbb8 修复VID/PID匹配逻辑 2024-12-20 16:37:59 +08:00
sakumisu
75e6dc6300 update(port/dwc2/usb_glue_gd): add check for ep 2024-12-19 21:20:33 +08:00
sakumisu
effee4d4c2 update(port/dwc2/usb_glue_at): import system_core_clock 2024-12-16 21:30:26 +08:00
sakumisu
05b46c8bad update(port/dwc2/usb_glue_st): support stm32h7rs 2024-12-16 20:55:02 +08:00
sakumisu
ddc19a9d65 update(port/dwc2/usb_dc_dwc2): support up to 16 endpoints 2024-12-16 20:53:52 +08:00
sakumisu
886f1ec6b4 fix warning 2024-12-09 20:53:02 +08:00
sakumisu
7980cb056c docs: update rst 2024-12-09 20:18:07 +08:00
sakumisu
f86443a70b update(port/ohci): update ohci common code 2024-12-09 20:17:50 +08:00
sakumisu
bfc1139d80 docs: add vendor rst 2024-12-04 23:04:12 +08:00
sakumisu
8d2afc1540 update(port/ehci/usb_glue_aic): add check for CONFIG_USB_OHCI_HCOR_OFFSET 2024-12-04 22:47:08 +08:00
sakumisu
87b8a4ad7f docs: update rst 2024-12-01 20:59:32 +08:00
sakumisu
9ff35e9020 update(port/dwc2/usb_hc_dwc2): do not support hs hub with ls/fs device 2024-11-29 22:42:54 +08:00
sakumisu
a03a9cd481 chore: add canaan logo 2024-11-29 22:41:56 +08:00
sakumisu
88d57eb99b update(cherrymp): use own osal 2024-11-28 18:25:47 +08:00
sakumisu
5850e27743 update(port/fsdev): add check for iso, we do not support 2024-11-27 22:14:05 +08:00
sakumisu
015aa77487 docs: update rst 2024-11-27 20:17:05 +08:00
sakumisu
4416dfa5cf fix(class/cdc/usbd_cdc_ecm): fix missing return 2024-11-27 19:37:42 +08:00
sakumisu
d874bed6aa chore: add missing license 2024-11-26 21:27:22 +08:00
sakumisu
7f75da270f update(cherrymp): change mq to sem for fast run 2024-11-26 21:04:14 +08:00
sakumisu
1a39169f6e update(port/dwc2/usb_dc_dwc2): clear crst bit because some mcu cannot be self-clearing, refs:#276 2024-11-25 21:03:51 +08:00
Zhihong Chen
82a0d243f8 usbd_video: use pingpang buffer to improve tx performance
- use pingpang buffer to improve tx performance

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-11-25 16:55:28 +08:00
sakumisu
ac3be8cb3a update(class/audio): change volume unit with dB, fix uac2.0 volume range 2024-11-25 16:21:25 +08:00
sakumisu
a72ecd2202 update: change memcpy to fast memcpy 2024-11-24 23:04:27 +08:00
sakumisu
c6bdacee6d docs: add share rst 2024-11-21 21:42:03 +08:00
sakumisu
ea03856337 fix warning 2024-11-21 21:00:10 +08:00
sakumisu
1c1217f8fa fix(port/dwc2/usb_dc_dwc2): do not clear other intr bits 2024-11-21 20:57:24 +08:00
Zhihong Chen
093a1836f0 demo: video_static_h264_template.c: fix end brace
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-11-18 17:31:02 +08:00
Zhihong Chen
70ef616676 HPMicro: update hpmicro port files
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-11-18 17:31:02 +08:00
sakumisu
6517919bd2 refactor(class/video/usbd_video): refactor video stream transfer, support n frames in one transfer 2024-11-16 22:35:58 +08:00
sakumisu
2b72d8c6d8 chore(scons): add kendryte config 2024-11-13 22:44:44 +08:00
sakumisu
261502f3b2 fix(cherrymp): fix bool to uint32_t 2024-11-13 22:44:38 +08:00
sakumisu
e3ff8ffe6a update(demo): set hid busy before write 2024-11-13 21:49:58 +08:00
sakumisu
24fc172ad8 update(demo/usbd_rndis): update send & recv done api, add check for this demo 2024-11-11 21:50:13 +08:00
sakumisu
58d552d03d update(class/cdc/usbd_cdc_ecm): support transfer api for enet & wireless without lwip 2024-11-11 21:48:13 +08:00
sakumisu
d0edc30c11 update(demo/usb_host): move test macro before run api 2024-11-11 21:44:33 +08:00
sakumisu
6ea1e2f94f update(osal/freertos): update usb_osal_mq_recv and usb_osal_mq_send for isr api 2024-11-06 20:14:35 +08:00
sakumisu
037c2a8323 update(platform/rtthread): remove unused idle task check 2024-11-04 20:07:43 +08:00
sakumisu
608ee773de chore(cmake): update idf config for lwip & freertos 2024-11-04 20:07:19 +08:00
sakumisu
c51a6f35a6 feat(class/aoa): add usb aoa host 2024-10-31 21:45:19 +08:00
sakumisu
a13bee0663 feat(core/usbh_core): add usbh_find_hubport api 2024-10-31 21:45:19 +08:00
sakumisu
fd1baa62df update(osal/usb_osal_thread): implement usb_osal_sem_reset 2024-10-31 21:45:19 +08:00
sakumisu
6e6fdda62a update(port/ehci/usb_glue_aic): remove lsusb shell, add check for ehci configflag 2024-10-31 21:45:19 +08:00
Dozingfiretruck
f02ff21cfb add:cherryusb_config_template.h add CONFIG_USB_HS configuration description 2024-10-31 12:28:32 +08:00
sakumisu
d6aae26371 update(class/audio/usbh_auido): update audio volume and mute api, caculate volume with volume min & max 2024-10-30 22:19:37 +08:00
sakumisu
77136aa743 update(core/usbd_core): implement USB_REQUEST_GET_INTERFACE request, refs:#268 2024-10-30 22:19:14 +08:00
sakumisu
4784017f56 chore: update comment 2024-10-30 21:04:06 +08:00
electretmike
149fb046bc fix: rename class to class_code, for c++ compatibility (#269)
Co-authored-by: Michiel van Leeuwen <michiel@embeddedacoustics.com>
2024-10-30 15:11:46 +08:00
sakumisu
f437b3e51c docs: release v1.4.1 2024-10-20 20:49:36 +08:00
sakumisu
65151b9534 feat(class/video/usbd_video): add usbd_video_stream_start_write api for video split tranfer, every transfer with one ep_mps 2024-10-18 17:18:51 +08:00
sakumisu
05315b7ea5 fix(port/dwc2/usb_hc_dwc2): fix check typo 2024-10-17 09:21:31 +08:00
sakumisu
f1a1434047 chore(platform/usbh_lwip): remove Double quotation marks 2024-10-11 21:53:24 +08:00
sakumisu
a20e312b55 update(port/kinetis): update mcx glue for mcxa153/mcxc444 2024-10-11 20:02:39 +08:00
sakumisu
83b5d842c7 docs: fix some translations 2024-10-10 21:39:40 +08:00
sakumisu
e425b992be feat(port/kinetis): add kinetis usbip 2024-10-10 21:30:42 +08:00
HalfSweet
0b81f3b2a2 Update start.rst 2024-10-10 21:23:58 +08:00
HalfSweet
287eb130ac Update deploy-docs.yml 2024-10-10 21:23:58 +08:00
sakumisu
525884a00f feat(class/audio/usb_audio): add audio altsetting desc init macros 2024-09-30 16:46:58 +08:00
sakumisu
2c52445639 update(platform/none/usbh_lwip): remove freertos, use osal api 2024-09-28 14:37:36 +08:00
sakumisu
df888eb9bc update(class/wireless/usbh_rndis): reduce rndis control buffer 2024-09-28 14:32:13 +08:00
Derek Konigsberg
5a15f714f5 Reduce size of HID class request buffer
With the change from cherry-embedded#260, this buffer no longer needs to be so large.  It can be reduced to the save a lot of memory.
2024-09-28 00:27:38 +08:00
sakumisu
bb79408275 Create cppcheck.yml 2024-09-27 22:16:32 +08:00
sakumisu
2b6eebcbb2 fix(class/msc/usbh_msc): when device stalls by usbh_msc_get_maxlun, ingore error and set lun=0, refs:#259 2024-09-27 19:03:33 +08:00
sakumisu
ab59beebd4 update(class/hid/usbh_hid): export usbh_hid_get_report_descriptor api, refs:#260 2024-09-27 19:03:33 +08:00
sakumisu
c377747e67 docs: update rst 2024-09-27 19:03:33 +08:00
sakumisu
2f14ee7a7b update(port/dwc2/usb_dc_dwc2): enlarge CONFIG_USB_DWC2_TX1_FIFO_SIZE for video demo and export CONFIG_USB_DWC2_DMA_ENABLE 2024-09-27 19:03:33 +08:00
sakumisu
0d65bbc6ba fix(core/usbd_core): reset endpoint only for altsetting 0, refs:#258 2024-09-27 19:02:28 +08:00
sakumisu
76bbd09fed fix(port/dwc2/usb_dc_dwc2): set multi packet for iso in tx empty process, every transfer will reset this bits, so we need restore it. remove ununsed iso imcomplete isr 2024-09-26 21:22:36 +08:00
HalfSweet
a8ef0c4cac fix: action running permissions 2024-09-24 21:59:05 +08:00
HalfSweet
b461f4e2d1 Add issue template (#257) 2024-09-24 21:52:15 +08:00
HalfSweet
5fb7d4d0e9 Add Github Action for Documentation Builds (#256) 2024-09-24 20:14:31 +08:00
sakumisu
8cb95b04cf chore(cmake): fix cdc acm config name 2024-09-19 20:57:23 +08:00
sakumisu
df7ecdf019 docs: update memory usage 2024-09-19 20:57:05 +08:00
sakumisu
68bf529608 fix(class/msc/usbd_msc): fix warning and add check for CONFIG_USBDEV_MSC_MAX_BUFSIZE 2024-09-19 20:25:11 +08:00
sakumisu
02340e0f44 chore: static code analysis 2024-09-19 09:50:18 +08:00
CCHhui
171b36e766 fix(core/usbh_core): Fix raw_config_desc heap out of bounds 2024-09-16 22:48:35 +08:00
sakumisu
0371bb921c docs: update rst 2024-09-11 22:26:29 +08:00
sakumisu
7ec7891fe4 update(demo): set bNumConfigurations with zero in Device Qualifier Descriptor, we do not request other speed desc as default 2024-09-09 22:48:18 +08:00
sakumisu
da391c6cf9 docs: update rst framework 2024-09-08 22:12:35 +08:00
sakumisu
b56b67182a refactor(class/audio/usbh_audio): refactor getting audio control info 2024-09-08 22:12:29 +08:00
sakumisu
e6fde5efab fix(port/dwc2): fix dwc2 rx fifo size, remove divided by 4 2024-09-08 22:11:38 +08:00
sakumisu
0487af6900 fix(port/dwc2): reset dma burst then modify, clear HCINT intstatus first 2024-09-08 22:11:38 +08:00
wangyz1997
be2880a7e8 fix(port/dwc2): fix typo 2024-09-08 22:11:38 +08:00
sakumisu
97e2a38b4a chore(cmake): do not use env variable 2024-09-08 22:11:38 +08:00
sakumisu
a139a70782 update(usbh_core): add terminate char for raw_config_desc 2024-09-07 22:43:43 +08:00
sakumisu
cb6a0c2ad6 chore(cherrymp): add license 2024-09-07 22:42:27 +08:00
sakumisu
bacacdb32c update: remove uvc queue 2024-09-06 22:24:16 +08:00
sakumisu
0323ffb424 update(class/cdc): set cdc acm bFunctionProtocol to 0x00 2024-09-04 22:06:14 +08:00
sakumisu
89e93f6c93 chore(scons): fix missing libpath 2024-09-02 18:57:15 +08:00
sakumisu
1deab668ef fix(port/ehci/usb_glue_ma35d0): fix typo 2024-09-02 18:54:53 +08:00
sakumisu
fbe2e3f8a3 fix(class/msc/usbd_msc): fix missing return value 2024-09-02 18:54:11 +08:00
sakumisu
d03dfe43ca update(port/dwc2/usb_hc_dwc2): power enable at last for common with other host ip 2024-09-01 11:59:11 +08:00
sakumisu
e42e99e975 update(platform/usbh_lwip): check lwip min stack size 2024-08-31 21:01:36 +08:00
sakumisu
8a7979378d update(osal): add error log and assert when alloc fail, and stop working 2024-08-31 18:23:00 +08:00
sakumisu
a8a5d95f8f fix(platform/rtthread/usbh_dfs): fix mem free 2024-08-31 16:08:10 +08:00
sakumisu
02ac1db3ff docs: update logo 2024-08-30 20:35:35 +08:00
tyustli
0d561ea313 Update usb_dc_dwc2.c
According to DS, the status register is W1C, |= will read the register first, write 1 to the corresponding bit, then write the register, if there is more than one status, it will be cleared by mistake. I'm not sure if other IP dcd's have the same problem?
2024-08-29 09:43:11 +08:00
sakumisu
e603389638 docs: release v1.4.0 2024-08-26 19:53:58 +08:00
sakumisu
b932cc5803 chore(cmake): update chipidea and threadx 2024-08-26 19:53:58 +08:00
sakumisu
5f43dc8662 feat(osal): add threadx port 2024-08-26 19:53:58 +08:00
Zhihong Chen
f5ce56990c usbd_core: add usb_device_is_suspend() API
- add usb_device_is_suspend() API

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-08-26 11:10:28 +08:00
sakumisu
f517adcf6d fix(port/bl): overflow check 2024-08-25 20:19:33 +08:00
sakumisu
2a563dc41f feat(port/chipidea): add chipidea port, add nxp mxc glue for chipidea and ehci 2024-08-25 20:19:25 +08:00
sakumisu
b045a1d490 fix(core/usbh_core.c): fix error name 2024-08-24 15:53:19 +08:00
sakumisu
563fbf58e1 update(port/hpm): check resume in port change 2024-08-23 22:36:14 +08:00
sakumisu
8435f1af32 chore(cmake): use config to enable lwip port 2024-08-23 22:36:03 +08:00
Zhihong Chen
2726e2e7b6 port: hpmicro: add USBH_USE_CUSTOM_ISR add USBD_USE_CUSTOM_ISR to control isr
- add USBH_USE_CUSTOM_ISR add USBD_USE_CUSTOM_ISR to control isr

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-08-23 13:57:45 +08:00
sakumisu
e8b22163bb update(port/dwc2/usb_dc_dwc2): add busid for functions to support multi ip 2024-08-22 20:36:28 +08:00
sakumisu
35da8d6747 fix: fix -Wunused-parameter warning with -Wextra cflag 2024-08-21 20:08:47 +08:00
sakumisu
43dc854b4d docs: update doc 2024-08-21 20:04:18 +08:00
sakumisu
f0fc75179e update(class/hid/usbh_hid): read report size from hid desc 2024-08-18 20:54:39 +08:00
sakumisu
f1e7043384 chore(kconfig): change description 2024-08-18 15:22:27 +08:00
sakumisu
e4954d4194 feat: add usb adb device with cherrysh 2024-08-17 21:06:06 +08:00
Zhihong Chen
07c6c296ed HPMicro: update usb_dc_hpm.c
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-08-16 21:32:09 +08:00
Zhihong Chen
500367dd82 port: ehci: should not be clear CSC/PEC/OCC flag when usb_hc_init()
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-08-16 21:32:09 +08:00
sakumisu
1efc29be5f feat(common): add usb_hexdump for test 2024-08-16 14:23:14 +08:00
sakumisu
143a5ce3fd refactor: move CHERRYUSB_VERSION and CHERRYUSB_VERSION_STR into usb_version.h 2024-08-16 14:16:45 +08:00
sakumisu
b171b28a75 refactor(class/cdc): rename usbd_cdc to usbd_cdc_acm 2024-08-16 14:16:08 +08:00
udoudou
668e414917 Fix IDF compilation error 2024-08-16 00:18:30 +08:00
sakumisu
03f8711b20 update(cherrymp): rename to cherrymp 2024-08-15 17:51:54 +08:00
sakumisu
393756f111 fix(class): use different buffer for cdc_acm,hid,msc,serial 2024-08-15 17:34:02 +08:00
sakumisu
4a252c3f73 update: idf config update 2024-08-14 21:56:40 +08:00
Yang Xijing
4b2000b405 Correct spelling errors. 2024-08-14 17:29:18 +08:00
sakumisu
9720eb2f76 docs: update png 2024-08-13 21:57:43 +08:00
sakumisu
68badf6f4c fix(port/dwc2): check idle when flush fifo, add delay for dwc2_set_mode 2024-08-13 18:10:36 +08:00
sakumisu
907d23871e fix(class/hid): fix typo 2024-08-13 18:10:07 +08:00
sakumisu
70944027c5 chore: update cmake and kconfig 2024-08-12 22:28:45 +08:00
sakumisu
a41da8928e feat(osal): import idf osal from udoudou/esp_cherryusb 2024-08-12 22:27:29 +08:00
sakumisu
bbcc767465 update(demo): change uint32_t to uintptr_t for 64bit cpu register 2024-08-09 22:49:46 +08:00
sakumisu
72e8eb7d84 feat(demo/msc_ram_template): add api for msc polling 2024-08-09 22:47:25 +08:00
zhugengyu
18d9c21553 Add PUSB2 and XHCI driver and RTOS glue (#236) 2024-08-09 22:43:22 +08:00
sakumisu
cbd6955bde fix(class/msc/usbd_msc): fix spelling 2024-08-08 18:11:23 +08:00
sakumisu
b4bbe69d12 feat(class/msc/usbd_msc): add msc polling mode to move read & write from isr to while1 2024-08-08 18:03:30 +08:00
Kevincoooool
e1cbccc58a Modifying the USB Int Source to support esp32p4 2024-08-07 12:08:10 +08:00
LiPeng
dfc90da28a Fix the bug that USBD_EVENT_DEINIT was not notified correctly 2024-08-06 14:10:07 +08:00
wangzongqiang
8451bc64bb change hid_mouse_report 2024-08-05 16:05:40 +08:00
sakumisu
3fc30cd058 update(demo/bootuf2): use flash cache 2024-07-30 20:27:25 +08:00
sakumisu
e95387c558 update(port/hpm/usb_dc_hpm): remove phcd clear 2024-07-30 19:53:21 +08:00
sakumisu
35a76f58bb update(port/hpm/usb_dc_hpm): enable resume handler 2024-07-30 18:12:46 +08:00
sakumisu
564d568732 fix(core/usbd_core): fix self powered check 2024-07-30 17:46:02 +08:00
sakumisu
9394f1f8d6 feat(port/dwc2): import kendryte glue from k230_sdk 2024-07-27 19:28:07 +08:00
sakumisu
bef45dc360 feat(port): add remote wakeup api 2024-07-26 22:02:01 +08:00
sakumisu
50b62c946d feat(core/usbd_core): support webusb 2024-07-25 21:39:36 +08:00
sakumisu
b399ff63ce feat(demo): add uf2 demo 2024-07-23 23:08:37 +08:00
sakumisu
4c4ee7f003 chore(docs): update rst 2024-07-23 20:13:28 +08:00
sakumisu
1c2fd3407a refactor(osal): use osal malloc and free, remove usb_malloc & usb_free macro 2024-07-23 19:37:54 +08:00
sakumisu
1927566dfc chore(docs): update rst 2024-07-21 17:44:57 +08:00
sakumisu
b7556b2ddc feat(class/vendor/wifi/usbh_bl616): add bl616 usbwifi driver 2024-07-19 23:23:32 +08:00
charschu
f1058c5e1a fix(port/dwc2/usb_dc_dwc2): fix lost ep0 setup intstatus by clear, for dwc2 version 4.3 2024-07-18 13:26:33 +08:00
sakumisu
643578e5be update(port/musb/usb_hc_musb): add portpower bit for commit e4b56cee 2024-07-15 18:09:55 +08:00
sakumisu
390e24fbe5 fix typo 2024-07-15 18:09:55 +08:00
sakumisu
ba02a48873 fix(demo/winusb1.0_template): fix WINUSB_IFx_WCIDProperties array 2024-07-15 18:09:55 +08:00
Till Harbaum
c766cbe91e Add host driver for XBOX controllers 2024-07-15 17:54:12 +08:00
Till Harbaum
9dd52fddf0 Workaround for BL616 power control 2024-07-15 17:01:57 +08:00
sakumisu
9c14ea19a9 fix(port/bl): fix test mode api 2024-07-13 10:13:37 +08:00
sakumisu
218fa8e85d update(demo/hid_mouse_template): draw circle to test report rate 2024-07-13 10:13:37 +08:00
sakumisu
eb147d7276 fix: fix typo 2024-07-13 10:13:37 +08:00
HaoboGu
c0bfbf7952 doc(readme): fix typo 2024-07-11 21:53:16 +08:00
sakumisu
1a9c1481f4 feat(core/usbd_core): support get hid desc request(0x21), support get status for remote wakeup & self powered 2024-07-11 13:58:16 +08:00
sakumisu
3d3c6bb5a2 fix(kconfig): fix spelling 2024-07-10 20:28:45 +08:00
Zhihong Chen
a942ec85a8 port: ehci: update init and deinit
- update init and deinit

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-07-09 21:11:36 +08:00
liuhy
a4a06573ea fix(port/musb/usb_dc_musb.c): usbd_ep_is_stalled api err. 2024-07-09 16:10:04 +08:00
sakumisu
7fab3c29f0 feat(port): implement usbd_ep_is_stalled api 2024-07-08 21:54:39 +08:00
sakumisu
4f3a3f496e feat(wifi/bl616): add bl616 usbwifi 2024-07-07 12:10:17 +08:00
sakumisu
e4b56cee89 update(hub): update hub macros and hub params for usb3.0 2024-07-07 12:07:12 +08:00
sakumisu
53114c0f16 refactor(e(o)hci): rename usb_hc_e(o)hci to usb_e(o)hci_reg, usb_hc_e(o)hci_priv to usb_hc_e(o)hci 2024-07-04 21:35:59 +08:00
sakumisu
29aaf56396 chore: release v1.3.1 2024-06-28 16:34:28 +08:00
sakumisu
c24eea6077 fix(port): enter section before alloc pipe 2024-06-28 16:33:45 +08:00
sakumisu
8fa517016e feat: add dhcp-server and dns-server module 2024-06-28 16:33:45 +08:00
sakumisu
35807fb9d9 fix(demo/cdc_ecm_template): device tcp/ip stack mac can't same as host 2024-06-28 16:33:45 +08:00
aozima
6e7502ec07 fix(demo/cdc_rndis_template): device tcp/ip stack mac can't same as host. 2024-06-28 16:33:45 +08:00
sakumisu
ab7ef4b116 chore(sconscript): update musb config 2024-06-25 18:08:42 +08:00
sakumisu
adee4b6727 update(class/vendor/net/usbh_asix): ignore the remain data that len is less than 4 2024-06-25 17:48:35 +08:00
sakumisu
6c92681e48 refactor(platform): add usbh_xxx_get_eth_txbuf api, especially for lwip pbuf list 2024-06-25 17:18:19 +08:00
sakumisu
31cd834ded chore(sconscript): fix spelling 2024-06-24 21:23:50 +08:00
sakumisu
a1274bad0a update(platform/rtthread/usbh_dfs): add hpm6e00 chip 2024-06-24 21:23:32 +08:00
sakumisu
c377ebfc61 update(class/video/usbd_video): make payload fill api common 2024-06-23 22:46:51 +08:00
sakumisu
1decfd0365 update(class/hub/usbh_hub): enumerate in order 2024-06-23 14:48:07 +08:00
sakumisu
dc0070b054 update(class/msc/usbh_msc): add MSC_INQUIRY_TIMEOUT to break quickly in inquiry stage 2024-06-23 14:46:50 +08:00
sakumisu
755d067650 update: check class->hport validity 2024-06-23 14:16:57 +08:00
sakumisu
69fe1598ed update(core/usbd_core): increase intf array from 8 to 16 2024-06-23 13:50:23 +08:00
sakumisu
0f8ec31981 update rst for malloc free 2024-06-22 19:33:43 +08:00
sakumisu
3bf74d2101 fix(common/usb_memcpy): fix warning in 64bit 2024-06-22 17:19:20 +08:00
sakumisu
10437a7d13 update(core/usbh_core): do not use slist, we use recursion 2024-06-22 15:44:09 +08:00
sakumisu
a1ab76dd3e chore(sconscript): add hc32 config 2024-06-22 00:23:48 +08:00
sakumisu
27394f5759 fix(demo/video_audiov1_hid_template): fix typo 2024-06-22 00:14:23 +08:00
yjun
740627cf3c update(demo/video): using endpoint desc init macro in video demo 2024-06-17 22:24:13 +08:00
yjun
7a26ad5082 update(class/video): add xu descriptor definition 2024-06-17 22:24:13 +08:00
yjun
ff2070d14b fix(class/video): vc header descriptor definition 2024-06-17 22:24:13 +08:00
sakumisu
0cb245e6d3 fix(common/usb_memcpy): fix missing USB_MEMCPY_H 2024-06-17 21:09:06 +08:00
sakumisu
556bf91879 fix(class/video/usb_video): fix missing bDescriptorSubType in vc header descriptor 2024-06-17 18:37:31 +08:00
sakumisu
5d87a750ac fix(core/usbh_core): fix missing free devaddr caused by 935325 2024-06-17 18:37:22 +08:00
sakumisu
8a4f210ee7 fix memcpy to strncpy 2024-06-16 23:40:15 +08:00
sakumisu
82f11fa647 fix(demo): fix missing usbh_int_urb_fill, musb will modify urb->transfer_buffer_length, this is a patch for musb 2024-06-16 22:24:08 +08:00
sakumisu
47e6ed1c75 fix(class/audio/usbh_audio): fix sample frequence 2024-06-16 20:59:46 +08:00
sakumisu
b4d54d2aa6 fix(core/usbh_core): fix get mult 2024-06-16 18:11:04 +08:00
sakumisu
96db9b96da update h264 macro 2024-06-16 16:08:01 +08:00
sakumisu
62da380c25 feat(demo): add uvc_uac_hid template 2024-06-16 10:03:22 +08:00
sakumisu
66e3ffb90d update readme 2024-06-15 21:31:36 +08:00
sakumisu
afa77ec20b update(video): add more video desc macros, like h264, yuv, add vc endpoint to choose, add yuv template 2024-06-15 17:54:56 +08:00
sakumisu
0f8c145d93 update(port/musb): config fifo from fifo table, add beken and es32 glue 2024-06-15 13:33:28 +08:00
sakumisu
3cf2d6da31 fix warning 2024-06-14 22:17:16 +08:00
sakumisu
bf9a236c9a fix(demo/hid_custom_inout_template): add missing macros 2024-06-14 20:45:47 +08:00
sakumisu
bf8e092627 remove print log for device, because we do not allow printf in isr 2024-06-14 10:02:12 +08:00
sakumisu
e9a7eb9eeb fix warning 2024-06-14 00:25:07 +08:00
sakumisu
277f3940f6 remove ununsed code 2024-06-14 00:25:02 +08:00
sakumisu
bf54bc2ff1 update(port/ehci): use static iso pool for iso urb to reduce alloc time 2024-06-11 21:59:37 +08:00
sakumisu
77af563898 add comments for dwc2 fifo macro 2024-06-11 21:58:17 +08:00
sakumisu
f57234e668 update port readme 2024-06-09 15:44:52 +08:00
sakumisu
3429f833f3 update(port/musb/usb_dc_musb): remove ununsed code 2024-06-09 15:27:21 +08:00
jinsc
9d265f2398 已在hc32f4a0上测试usbd的usb_glue_hc.c 2024-06-08 19:12:25 +08:00
sakumisu
935325175f remove old xhci patch 2024-06-07 21:51:33 +08:00
sakumisu
6fd87902b5 remove old version 2024-06-07 10:29:44 +08:00
sakumisu
b1660f743f update rst 2024-06-06 22:53:51 +08:00
sakumisu
f197716f52 update(port/dwc2/usb_hc_dwc2): add check for fifo with ep mps 2024-06-06 21:48:56 +08:00
sakumisu
62ed025ddc fix(port/musb/usbh_hc_musb): fix missing leave critical when return with error 2024-06-06 20:28:49 +08:00
yukelab
883c0a5dc5 review cdc-ecm enum success but comunication error
1. review usbd_cdc_ecm_eth_tx send data fail
2. review CDC_ECM_DESCRIPTOR_INIT macro wMaxSegmentSize parameter error
2024-06-05 14:39:00 +08:00
sakumisu
cf0137686d fix(class/cdc/usbd_cdc_ecm): fix build error 2024-06-05 10:19:20 +08:00
sakumisu
48a125b28d fix spelling 2024-06-01 23:13:26 +08:00
sakumisu
e2877d3fe0 update(demo/usb_host): remove ununsed net class 2024-06-01 23:10:04 +08:00
sakumisu
3429f73a65 update: add comments for net process, support len > 16K for ncm/rndis/asix/rtl8152 2024-06-01 18:54:51 +08:00
sakumisu
3c102bd265 update readme 2024-05-31 23:01:12 +08:00
sakumisu
ba098529af update(class/wireless/usbd_rndis): print max pkts and size in init msg resp 2024-05-31 22:44:19 +08:00
sakumisu
2d63b52d0b feat: use fast memcpy for net 2024-05-31 22:31:43 +08:00
sakumisu
5f28438eec fix(class/wireless/usbd_rndis): change total size to 1558 2024-05-30 16:29:45 +08:00
Chen Leeren
edf4e5c7fc Unify the number of endpoint names and fix a data receiving bug 2024-05-27 22:03:07 +08:00
sakumisu
865d2f5d96 refactor(platform): update platform support 2024-05-24 22:49:18 +08:00
sakumisu
3336919e0d release v1.3.0 2024-05-22 18:51:41 +08:00
sakumisu
8b070570a7 fix(port/ehci): fix missing busid 2024-05-22 18:51:41 +08:00
sakumisu
af792eabab fix typo 2024-05-21 16:08:28 +08:00
sakumisu
3be08d16f7 update(port/dwc2): rename struct name to avoid duplicate definitions 2024-05-21 11:50:49 +08:00
sakumisu
5dafdcb895 fix warning 2024-05-21 10:10:31 +08:00
sakumisu
f24c37d3aa update(class/wireless/usbd_rndis): remove ununsed speed field 2024-05-20 18:15:01 +08:00
Zhihong Chen
a7a7afc6bb port: HPMicro: update usb_glue_hpm
- update usb_glue_hpm

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-05-18 10:17:57 +08:00
sakumisu
66b893e64f update: add langid in string desc 2024-05-17 22:18:21 +08:00
sakumisu
3a3de9cb69 update: format log 2024-05-17 17:22:25 +08:00
sakumisu
13e4670f3d update: remove internal configs, you should get config from usb_config.h 2024-05-17 17:04:53 +08:00
sakumisu
1d9a36b61c update(docs): update rst 2024-05-17 17:03:50 +08:00
sakumisu
b1c81a92f5 fix warning 2024-05-16 20:47:37 +08:00
sakumisu
af92236cf4 refactor(core/usbd_core): process string internal, you can use like \"cherryusb\" now 2024-05-16 11:19:58 +08:00
sakumisu
0985a7e5fa fix(port/usb_hc_ehci): clear iaad status 2024-05-16 10:13:52 +08:00
sakumisu
8b805ee6d7 fix(dwc2): check those chips with 1.25KB fifo 2024-05-15 23:07:46 +08:00
sakumisu
5e6bd78f80 update(dwc2): change rx fifo to 1024/4 as default 2024-05-15 22:37:57 +08:00
sakumisu
f2133f5ca2 update(docs): update rst 2024-05-15 12:10:38 +08:00
sakumisu
9657585f1f update(core/usbh_core): remove ununsed urb memset 2024-05-15 09:57:21 +08:00
sakumisu
a225ee383b update(demo/midi): add read api 2024-05-14 21:34:50 +08:00
sakumisu
60747ce435 update(port/musb): add sunxi glue for check 2024-05-14 21:34:15 +08:00
sakumisu
490cac1a0f fix(class): change ifdef to if for LWIP_TCPIP_CORE_LOCKING_INPUT 2024-05-14 13:59:39 +08:00
sakumisu
207fb7b128 update(usbh_ncm/usbh_rndis): limit read size to 16K 2024-05-14 13:53:58 +08:00
sakumisu
d23a8a8d00 update: get mps by usbd_get_ep_mps 2024-05-14 11:33:11 +08:00
sakumisu
4243394225 fix(demo): remove duplicate macro 2024-05-14 11:32:56 +08:00
sakumisu
62c9c8b747 update(demo/usb_host): change eth name index 2024-05-12 20:50:29 +08:00
sakumisu
7b38b4b323 update(demo/usb_host): disable keep timer(no need) 2024-05-12 20:47:42 +08:00
sakumisu
e1aa49e086 fix typo 2024-05-12 20:47:34 +08:00
sakumisu
fabeebd4c5 fix(class/vendor/net/usbh_asix): fix write cmd param 2024-05-12 20:47:34 +08:00
sakumisu
58550b3ed5 update: rename ecm and asix eth macro name 2024-05-12 20:47:34 +08:00
sakumisu
363533be4c update(class/vendor/net/usbh_rtl8152): update eth rx/tx size 2024-05-12 20:47:34 +08:00
sakumisu
074662a50d fix(class/wireless/usbh_rndis): when last data is dummy byte, ignore it 2024-05-12 20:47:33 +08:00
sakumisu
532e05e293 fix nuttx timeout 2024-05-11 15:59:25 +08:00
sakumisu
b55d40e512 change CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE to 1580 default 2024-05-11 14:01:42 +08:00
Zhihong Chen
263a66ed9b port: HPMicro: update hpm usb deivce port file
- update hpm usb deivce port file

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-05-10 12:27:54 +08:00
sakumisu
775ac135de bugfix by ccef9b92 2024-05-10 11:36:17 +08:00
sakumisu
aecae9434b add kconfig template 2024-05-10 10:12:48 +08:00
sakumisu
5a7042fe15 import aic dcd port 2024-05-10 10:12:42 +08:00
sakumisu
18c4454228 add nuttx osal 2024-05-09 10:45:27 +08:00
sakumisu
cd8b103a71 update rtt config check 2024-05-08 19:28:20 +08:00
sakumisu
8ecbd32483 remove qh with iaad 2024-05-08 17:17:57 +08:00
sakumisu
d0f79ff668 update host demo to support multi class 2024-05-05 13:34:36 +08:00
sakumisu
7272ccfc02 update company support 2024-05-05 12:12:00 +08:00
sakumisu
e081642c76 add pl2303 host driver 2024-05-05 11:38:25 +08:00
sakumisu
b51da4fbf9 remove ununsed code 2024-05-04 20:09:04 +08:00
sakumisu
97c5e37453 add check for rtt config 2024-05-04 15:49:54 +08:00
sakumisu
cdd308f3e8 fix typo 2024-05-04 15:48:45 +08:00
sakumisu
6db4fbba4c add check for hpm 2024-05-04 14:21:13 +08:00
sakumisu
102801e45c add comments for macros 2024-05-03 20:34:13 +08:00
sakumisu
0ceb7ef885 zero copy when enables LWIP_TCPIP_CORE_LOCKING_INPUT 2024-05-03 19:53:22 +08:00
sakumisu
ae5a9d1e57 check if eth rx packet is overflow 2024-05-03 19:19:17 +08:00
sakumisu
7ebcafe158 adjust code order 2024-05-03 18:57:09 +08:00
sakumisu
81cebaf78c add vendor serial into cmake 2024-05-03 18:55:12 +08:00
sakumisu
5fec929b93 support id table for multi vid pid 2024-05-03 18:54:36 +08:00
sakumisu
4bf0e126af move usbh_hubport_release api to core 2024-05-03 18:00:59 +08:00
sakumisu
ccef9b92cc bugfix for 183d49, add CONFIG_USBDEV_EP0_INDATA_NO_COPY 2024-05-03 14:07:26 +08:00
Zhihong Chen
9cb992bed7 add USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT and USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT macros
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-04-30 20:05:57 +08:00
sakumisu
183d49efbd copy data into ep0 buffer at a unified location 2024-04-30 14:21:31 +08:00
sakumisu
8d18a8b6e5 change CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE to 2048 default 2024-04-30 14:10:17 +08:00
sakumisu
5f79fdc865 include ehci port path in cmake 2024-04-30 14:08:13 +08:00
sakumisu
2f5f2b906f add usbd_get_ep_mult api 2024-04-29 14:11:24 +08:00
sakumisu
0556ae199b add config for cdc ncm transfer size 2024-04-29 11:46:31 +08:00
sakumisu
2da4edf76b remove port param in usbd_get_port_speed 2024-04-29 11:35:29 +08:00
sakumisu
45e9a2fde8 add usbd_get_ep_mps api 2024-04-29 11:32:54 +08:00
sakumisu
5b72907f6d simplify code for get device qualifier desc 2024-04-29 11:29:52 +08:00
sakumisu
6abe6befa8 fix rndis msg when mss is larger than rndis rx size 2024-04-28 19:54:53 +08:00
sakumisu
7ee77b42ee check class_driver is null 2024-04-25 21:20:24 +08:00
sakumisu
404225ade4 change INFO to DBG 2024-04-25 21:17:56 +08:00
sakumisu
694b201ff7 move get speed before get device desc 2024-04-25 21:11:55 +08:00
sakumisu
23e2787a43 add user_data param in host class for users 2024-04-24 22:40:55 +08:00
sakumisu
a3302584ce remove dfu exe,use url instead 2024-04-24 22:27:52 +08:00
sakumisu
8625e4409e support speed get in when enables CONFIG_USBDEV_ADVANCE_DESC 2024-04-24 22:10:47 +08:00
sakumisu
190fb36c43 add hid host report api 2024-04-23 22:02:16 +08:00
sakumisu
a24d2bdc07 fix rndis send dummy 2024-04-23 21:30:59 +08:00
sakumisu
ceaf0923c5 fix caculate precision 2024-04-23 16:33:02 +08:00
sakumisu
2cb6c598c1 update missing license 2024-04-23 13:04:41 +08:00
sakumisu
4e6b0d0923 format code 2024-04-23 10:52:45 +08:00
sakumisu
017eb5560d fix missing busid 2024-04-19 13:03:54 +08:00
sakumisu
b97fc903c0 clear urb timeout after take sem, follow 76f58b93 2024-04-19 11:52:04 +08:00
sakumisu
81ddf9bded change ep0 buffer to 512 2024-04-18 22:06:20 +08:00
sakumisu
8995cf9568 move rndis config macros into template 2024-04-18 21:27:34 +08:00
sakumisu
76f58b93fe do not clear timeout in irq,urb init will sometime call irq before take sem 2024-04-18 21:11:36 +08:00
sakumisu
70c7f1ccbd use only one dhcp timer, delete timer when stop 2024-04-17 22:09:48 +08:00
sakumisu
29c72f3455 update msh cmd and scons 2024-04-16 22:18:25 +08:00
sakumisu
51b9640489 add missing license 2024-04-16 22:11:30 +08:00
sakumisu
32f96f4248 remove duplicate h7 config 2024-04-16 21:52:52 +08:00
sakumisu
e3886fe99d format comment 2024-04-16 21:48:11 +08:00
zhaofx4534
d8714d8169 enable bit21(VBUSSIG) in gd chips 2024-04-15 21:36:58 +08:00
sakumisu
9d5479e0c3 list all porting macros into template for use 2024-04-14 19:53:20 +08:00
sakumisu
ed8a3ceca3 add ifndef for test macros 2024-04-14 19:36:34 +08:00
sakumisu
3592794393 import bouffalo dcd 2024-04-14 19:35:48 +08:00
Zhihong Chen
4357a1d7d1 osal: freeRTOS: fix enter/exit critical
- fix enter/exit critical

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-04-13 11:08:53 +08:00
sakumisu
c1cb6e397b move queue files 2024-04-11 10:14:43 +08:00
sakumisu
c8be4d6fd3 change INFO to RAW 2024-04-07 23:31:04 +08:00
sakumisu
725d635c76 add cherryrb and cherry pool 2024-04-07 23:30:51 +08:00
sakumisu
1eef5f3e35 add config index to select multi configs 2024-04-07 16:53:53 +08:00
sakumisu
1dd45e3e5a update rst for ld 2024-04-07 13:26:03 +08:00
sakumisu
8119a500b2 change CONFIG_USB_DWC2_ULPI_PHY to CONFIG_USB_HS, support stm32f723 2024-04-07 13:20:33 +08:00
sakumisu
c5f2ffa6f9 export ehci config macros 2024-04-07 13:17:01 +08:00
sakumisu
db10c62b59 read ehci hcor offset from hccr caplength 2024-04-06 20:19:53 +08:00
sakumisu
808cd454a3 init ohci for ehci 2024-04-04 16:43:05 +08:00
sakumisu
a41c66c2c3 change rt_ssize_t to ssize_t, compatible with older rtt version 2024-04-04 12:56:43 +08:00
sakumisu
6ef086a085 add check for dwc2 fifo with ep mps 2024-04-03 15:44:43 +08:00
sakumisu
5494b0e99a add check for wTotalLength 2024-04-03 11:27:28 +08:00
530 changed files with 68145 additions and 128815 deletions

311
.cmake-format.json Normal file
View File

@@ -0,0 +1,311 @@
{
"_help_parse": "Options affecting listfile parsing",
"parse": {
"_help_additional_commands": [
"Specify structure for custom cmake functions"
],
"additional_commands": {
"foo": {
"flags": [
"BAR",
"BAZ"
],
"kwargs": {
"HEADERS": "*",
"SOURCES": "*",
"DEPENDS": "*"
}
}
},
"_help_override_spec": [
"Override configurations per-command where available"
],
"override_spec": {},
"_help_vartags": [
"Specify variable tags."
],
"vartags": [],
"_help_proptags": [
"Specify property tags."
],
"proptags": []
},
"_help_format": "Options affecting formatting.",
"format": {
"_help_disable": [
"Disable formatting entirely, making cmake-format a no-op"
],
"disable": false,
"_help_line_width": [
"How wide to allow formatted cmake files"
],
"line_width": 120,
"_help_tab_size": [
"How many spaces to tab for indent"
],
"tab_size": 4,
"_help_use_tabchars": [
"If true, lines are indented using tab characters (utf-8",
"0x09) instead of <tab_size> space characters (utf-8 0x20).",
"In cases where the layout would require a fractional tab",
"character, the behavior of the fractional indentation is",
"governed by <fractional_tab_policy>"
],
"use_tabchars": false,
"_help_fractional_tab_policy": [
"If <use_tabchars> is True, then the value of this variable",
"indicates how fractional indentions are handled during",
"whitespace replacement. If set to 'use-space', fractional",
"indentation is left as spaces (utf-8 0x20). If set to",
"`round-up` fractional indentation is replaced with a single",
"tab character (utf-8 0x09) effectively shifting the column",
"to the next tabstop"
],
"fractional_tab_policy": "use-space",
"_help_max_subgroups_hwrap": [
"If an argument group contains more than this many sub-groups",
"(parg or kwarg groups) then force it to a vertical layout."
],
"max_subgroups_hwrap": 2,
"_help_max_pargs_hwrap": [
"If a positional argument group contains more than this many",
"arguments, then force it to a vertical layout."
],
"max_pargs_hwrap": 6,
"_help_max_rows_cmdline": [
"If a cmdline positional group consumes more than this many",
"lines without nesting, then invalidate the layout (and nest)"
],
"max_rows_cmdline": 2,
"_help_separate_ctrl_name_with_space": [
"If true, separate flow control names from their parentheses",
"with a space"
],
"separate_ctrl_name_with_space": false,
"_help_separate_fn_name_with_space": [
"If true, separate function names from parentheses with a",
"space"
],
"separate_fn_name_with_space": false,
"_help_dangle_parens": [
"If a statement is wrapped to more than one line, than dangle",
"the closing parenthesis on its own line."
],
"dangle_parens": true,
"_help_dangle_align": [
"If the trailing parenthesis must be 'dangled' on its on",
"line, then align it to this reference: `prefix`: the start",
"of the statement, `prefix-indent`: the start of the",
"statement, plus one indentation level, `child`: align to",
"the column of the arguments"
],
"dangle_align": "prefix",
"_help_min_prefix_chars": [
"If the statement spelling length (including space and",
"parenthesis) is smaller than this amount, then force reject",
"nested layouts."
],
"min_prefix_chars": 4,
"_help_max_prefix_chars": [
"If the statement spelling length (including space and",
"parenthesis) is larger than the tab width by more than this",
"amount, then force reject un-nested layouts."
],
"max_prefix_chars": 10,
"_help_max_lines_hwrap": [
"If a candidate layout is wrapped horizontally but it exceeds",
"this many lines, then reject the layout."
],
"max_lines_hwrap": 2,
"_help_line_ending": [
"What style line endings to use in the output."
],
"line_ending": "unix",
"_help_command_case": [
"Format command names consistently as 'lower' or 'upper' case"
],
"command_case": "canonical",
"_help_keyword_case": [
"Format keywords consistently as 'lower' or 'upper' case"
],
"keyword_case": "unchanged",
"_help_always_wrap": [
"A list of command names which should always be wrapped"
],
"always_wrap": [],
"_help_enable_sort": [
"If true, the argument lists which are known to be sortable",
"will be sorted lexicographicall"
],
"enable_sort": true,
"_help_autosort": [
"If true, the parsers may infer whether or not an argument",
"list is sortable (without annotation)."
],
"autosort": false,
"_help_require_valid_layout": [
"By default, if cmake-format cannot successfully fit",
"everything into the desired linewidth it will apply the",
"last, most agressive attempt that it made. If this flag is",
"True, however, cmake-format will print error, exit with non-",
"zero status code, and write-out nothing"
],
"require_valid_layout": false,
"_help_layout_passes": [
"A dictionary mapping layout nodes to a list of wrap",
"decisions. See the documentation for more information."
],
"layout_passes": {}
},
"_help_markup": "Options affecting comment reflow and formatting.",
"markup": {
"_help_bullet_char": [
"What character to use for bulleted lists"
],
"bullet_char": "*",
"_help_enum_char": [
"What character to use as punctuation after numerals in an",
"enumerated list"
],
"enum_char": ".",
"_help_first_comment_is_literal": [
"If comment markup is enabled, don't reflow the first comment",
"block in each listfile. Use this to preserve formatting of",
"your copyright/license statements."
],
"first_comment_is_literal": true,
"_help_literal_comment_pattern": [
"If comment markup is enabled, don't reflow any comment block",
"which matches this (regex) pattern. Default is `None`",
"(disabled)."
],
"literal_comment_pattern": null,
"_help_fence_pattern": [
"Regular expression to match preformat fences in comments",
"default= ``r'^\\s*([`~]{3}[`~]*)(.*)$'``"
],
"fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$",
"_help_ruler_pattern": [
"Regular expression to match rulers in comments default=",
"``r'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'``"
],
"ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$",
"_help_explicit_trailing_pattern": [
"If a comment line matches starts with this pattern then it",
"is explicitly a trailing comment for the preceeding",
"argument. Default is '#<'"
],
"explicit_trailing_pattern": "#<",
"_help_hashruler_min_length": [
"If a comment line starts with at least this many consecutive",
"hash characters, then don't lstrip() them off. This allows",
"for lazy hash rulers where the first hash char is not",
"separated by space"
],
"hashruler_min_length": 10,
"_help_canonicalize_hashrulers": [
"If true, then insert a space between the first hash char and",
"remaining hash chars in a hash ruler, and normalize its",
"length to fill the column"
],
"canonicalize_hashrulers": true,
"_help_enable_markup": [
"enable comment markup parsing and reflow"
],
"enable_markup": true
},
"_help_lint": "Options affecting the linter",
"lint": {
"_help_disabled_codes": [
"a list of lint codes to disable"
],
"disabled_codes": [],
"_help_function_pattern": [
"regular expression pattern describing valid function names"
],
"function_pattern": "[0-9a-z_]+",
"_help_macro_pattern": [
"regular expression pattern describing valid macro names"
],
"macro_pattern": "[0-9A-Z_]+",
"_help_global_var_pattern": [
"regular expression pattern describing valid names for",
"variables with global (cache) scope"
],
"global_var_pattern": "[A-Z][0-9A-Z_]+",
"_help_internal_var_pattern": [
"regular expression pattern describing valid names for",
"variables with global scope (but internal semantic)"
],
"internal_var_pattern": "_[A-Z][0-9A-Z_]+",
"_help_local_var_pattern": [
"regular expression pattern describing valid names for",
"variables with local scope"
],
"local_var_pattern": "[a-z][a-z0-9_]+",
"_help_private_var_pattern": [
"regular expression pattern describing valid names for",
"privatedirectory variables"
],
"private_var_pattern": "_[0-9a-z_]+",
"_help_public_var_pattern": [
"regular expression pattern describing valid names for public",
"directory variables"
],
"public_var_pattern": "[A-Z][0-9A-Z_]+",
"_help_argument_var_pattern": [
"regular expression pattern describing valid names for",
"function/macro arguments and loop variables."
],
"argument_var_pattern": "[a-z][a-z0-9_]+",
"_help_keyword_pattern": [
"regular expression pattern describing valid names for",
"keywords used in functions or macros"
],
"keyword_pattern": "[A-Z][0-9A-Z_]+",
"_help_max_conditionals_custom_parser": [
"In the heuristic for C0201, how many conditionals to match",
"within a loop in before considering the loop a parser."
],
"max_conditionals_custom_parser": 2,
"_help_min_statement_spacing": [
"Require at least this many newlines between statements"
],
"min_statement_spacing": 1,
"_help_max_statement_spacing": [
"Require no more than this many newlines between statements"
],
"max_statement_spacing": 2,
"max_returns": 6,
"max_branches": 12,
"max_arguments": 5,
"max_localvars": 15,
"max_statements": 50
},
"_help_encode": "Options affecting file encoding",
"encode": {
"_help_emit_byteorder_mark": [
"If true, emit the unicode byte-order mark (BOM) at the start",
"of the file"
],
"emit_byteorder_mark": false,
"_help_input_encoding": [
"Specify the encoding of the input file. Defaults to utf-8"
],
"input_encoding": "utf-8",
"_help_output_encoding": [
"Specify the encoding of the output file. Defaults to utf-8.",
"Note that cmake only claims to support utf-8 so be careful",
"when using anything else"
],
"output_encoding": "utf-8"
},
"_help_misc": "Miscellaneous configurations options.",
"misc": {
"_help_per_command": [
"A dictionary containing any per-command configuration",
"overrides. Currently only `command_case` is supported."
],
"per_command": {}
}
}

85
.github/ISSUE_TEMPLATE/1-bug-report.yml vendored Normal file
View File

@@ -0,0 +1,85 @@
name: "🐞 上报bug / Bug report"
description: "提交bug以让改进软件功能 / Create a report to help us improve"
labels: ["peding"]
body:
- type: markdown
attributes:
value: |
感谢上报新的问题请填写以下信息以帮助我们更好地理解问题。请注意如果您不按模板填写issue那您的issue可能会被关闭或者删除
我们的工作语言是中文或者英文请使用这两种语言之一填写issue。
Thank you for reporting a new issue! Please fill in the following information to help us better understand the problem. Please note that if you do not fill in the issue according to the template, your issue may be closed or deleted!
Our working languages are Chinese or English, please use one of these two languages to fill in the issue.
- type: textarea
id: bug-description
attributes:
label: 描述一下这个bug / Describe the bug
description: 请使用简介并详细的语句来描述这个bug。 / A clear and concise description of what the bug is.
placeholder: 我准备……我想要……但是实际上它……了 / I am doing ... What I expect is ... What actually happening is ...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: 复现步骤 / To Reproduce
description: 按照下面的步骤可以复现bug / Steps to reproduce the behavior
placeholder: 首先……然后……接着…… / Go to '...', Click on '....', Scroll down to '....'
validations:
required: true
- type: textarea
id: target
attributes:
label: 设备信息 / Target Device
description: 您使用的板子/芯片型号、使用的引脚、以及USB IP类型 / Your target board/chip model, the pins you used, and the type of USB IP you used
placeholder: |-
板子型号HPM5301EVKLite
引脚PA24 PA25
USB IP/
validations:
required: true
- type: textarea
id: log
attributes:
label: 日志 / Log
description: 请提供输出 log
placeholder: |-
[D/USB] EP0 send 18 bytes, 0 remained
[D/USB] EP0 recv out status
[D/USB] EP0 send 0 bytes, 0 remained
[D/USB] EP0 send 18 bytes, 0 remained
[D/USB] EP0 recv out status
validations:
required: true
- type: markdown
attributes:
value: |
以下的部分仅在移植的时候需要填写,如果不是移植问题,请忽略这部分。
The following section is only required when porting, if it is not a porting issue, please ignore this section.
- type: textarea
id: configure
attributes:
label: 配置 / Configuration
description: 请确认 USB 中断,时钟,引脚,寄存器地址是否正确,并截图 / Please confirm that the USB interrupt, clock, pin, and register address are correct, and provide a screenshot
- type: textarea
id: USBIrq
attributes:
label: USB中断 / USB Interrupt
description: 请确认是否能进入USB中断
- type: textarea
id: cache
attributes:
label: 缓存 / Cache
description: 芯片是否带有 cache功能是否做了 no cache 处理,并截图 / Whether the chip has a cache function, whether no cache processing is done, and provide a screenshot
- type: checkboxes
id: bussiness
attributes:
label: 商业 / Business
description: 是否流片并销售 / Whether it is mass-produced and sold
options:
- label: 是 / Yes

83
.github/workflows/build_tests.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: Build Tests
on:
push:
branches:
- master
- release/v1.5
pull_request:
branches:
- master
- release/v1.5
jobs:
build_hpmicro:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build
- name: Download hpm_sdk
run: |
cd ~
git clone https://github.com/hpmicro/hpm_sdk.git
- name: Download RISC-V toolchain
run: |
cd ~
wget https://github.com/hpmicro/riscv-gnu-toolchain/releases/download/2023.10.18/rv32imac_zicsr_zifencei_multilib_b_ext-linux.tar.gz
tar -xzf rv32imac_zicsr_zifencei_multilib_b_ext-linux.tar.gz
- name: Build hpm demo
run: |
cd tests/hpmicro
export HPM_SDK_BASE=~/hpm_sdk
export GNURISCV_TOOLCHAIN_PATH=~/rv32imac_zicsr_zifencei_multilib_b_ext-linux
export HPM_SDK_TOOLCHAIN_VARIANT=
cmake -S . -B build -GNinja -DBOARD=hpm6800evk -DHPM_BUILD_TYPE=flash_sdram_xip -DCMAKE_BUILD_TYPE=debug -DEXTRA_C_FLAGS="-Werror";cmake --build build
build_bouffalolab:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y cmake make
- name: Download bouffalo_sdk
run: |
cd ~
git clone https://github.com/bouffalolab/bouffalo_sdk.git
- name: Download RISC-V toolchain
run: |
cd ~
git clone https://github.com/bouffalolab/toolchain_gcc_t-head_linux.git
- name: Build bouffalo demo
run: |
cd tests/bouffalolab
export BL_SDK_BASE=~/bouffalo_sdk
export PATH=~/toolchain_gcc_t-head_linux/bin:$PATH
make CHIP=bl616 BOARD=bl616dk -j12
build_espressif:
strategy:
matrix:
idf_ver: ["latest"]
runs-on: ubuntu-latest
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Build espressif demo
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager ruamel.yaml idf-build-apps --upgrade
idf-build-apps build -p ./tests/espressif --recursive --target esp32s3

17
.github/workflows/cppcheck.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Cppcheck action
on:
push:
pull_request:
jobs:
build:
name: cppcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: cppcheck
shell: bash
run: |
sudo apt install cppcheck
cppcheck --enable=warning,portability,performance --language=c --platform=unix32 --std=c99 --force . -i third_party/ -i class/template -i port/template/

28
.github/workflows/deploy-docs.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Deploy docs
on:
push:
branches:
- master
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- uses: ammaraskar/sphinx-action@8.0.2
with:
docs-folder: "docs/"
- uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
folder: docs/build/html

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vscode
build
**/Drivers/**
**/MDK-ARM/DebugConfig/**
**/MDK-ARM/RTE/**

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "third_party/zephyr_bluetooth-2.7.5/zephyr_bluetooth"]
path = third_party/zephyr_bluetooth-2.7.5/zephyr_bluetooth
url = https://github.com/sakumisu/zephyr_bluetooth.git
[submodule "third_party/nimble-1.6.0/nimble"]
path = third_party/nimble-1.6.0/nimble
url = https://github.com/sakumisu/mynewt-nimble.git

217
CMakeLists.txt Normal file
View File

@@ -0,0 +1,217 @@
cmake_minimum_required(VERSION 3.15)
if(CONFIG_CHERRYUSB OR ESP_PLATFORM)
if(BL_SDK_BASE)
message(STATUS "enable cherryusb in bouffalo_sdk")
set(CONFIG_CHERRYUSB_DEVICE_CDC_ACM 1)
set(CONFIG_CHERRYUSB_DEVICE_HID 1)
set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_NCM 1)
set(CONFIG_CHERRYUSB_HOST_HID 1)
set(CONFIG_CHERRYUSB_HOST_MSC 1)
set(CONFIG_CHERRYUSB_HOST_VIDEO 1)
set(CONFIG_CHERRYUSB_HOST_AUDIO 1)
set(CONFIG_CHERRYUSB_HOST_CDC_RNDIS 1)
# set(CONFIG_CHERRYUSB_HOST_BLUETOOTH 1)
set(CONFIG_CHERRYUSB_HOST_ASIX 1)
set(CONFIG_CHERRYUSB_HOST_RTL8152 1)
set(CONFIG_CHERRYUSB_HOST_CH34X 1)
set(CONFIG_CHERRYUSB_HOST_CP210X 1)
set(CONFIG_CHERRYUSB_HOST_FTDI 1)
set(CONFIG_CHERRYUSB_HOST_PL2303 1)
set(CONFIG_CHERRYUSB_HOST_GSM 1)
set(CONFIG_CHERRYUSB_DEVICE_BL 1)
set(CONFIG_CHERRYUSB_HOST_EHCI_BL 1)
set(CONFIG_CHERRYUSB_OSAL "freertos")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
list(REMOVE_DUPLICATES cherryusb_srcs)
list(REMOVE_DUPLICATES cherryusb_incs)
sdk_generate_library(cherryusb)
sdk_add_include_directories(${cherryusb_incs})
sdk_library_add_sources(${cherryusb_srcs})
elseif(ESP_PLATFORM)
message(STATUS "enable cherryusb in esp-idf")
set(CONFIG_CHERRYUSB_DEVICE_DWC2_ESP 1)
set(CONFIG_CHERRYUSB_HOST_DWC2_ESP 1)
set(CONFIG_CHERRYUSB_OSAL "idf")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
list(REMOVE_DUPLICATES cherryusb_srcs)
list(REMOVE_DUPLICATES cherryusb_incs)
set(ldfragments "osal/idf/linker.lf")
if(CONFIG_CHERRYUSB_HOST_CDC_ECM
OR CONFIG_CHERRYUSB_HOST_CDC_RNDIS
OR CONFIG_CHERRYUSB_HOST_CDC_NCM
OR CONFIG_CHERRYUSB_HOST_ASIX
OR CONFIG_CHERRYUSB_HOST_RTL8152
)
idf_component_get_property(lwip lwip COMPONENT_LIB)
target_compile_definitions(${lwip} PRIVATE "-DPBUF_POOL_BUFSIZE=1600")
endif()
idf_component_get_property(freertos_include freertos ORIG_INCLUDE_PATH)
if(CONFIG_CHERRYUSB_HOST_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/idf/usbh_fatfs.c)
endif()
set(priv_req esp_mm esp_netif esp_timer fatfs)
if(${IDF_VERSION_MAJOR} LESS 6)
list(APPEND priv_req usb)
endif()
idf_component_register(
SRCS
${cherryusb_srcs}
INCLUDE_DIRS
${cherryusb_incs}
${freertos_include}
PRIV_REQUIRES
${priv_req}
LDFRAGMENTS
${ldfragments}
)
if(CONFIG_CHERRYUSB_HOST)
target_linker_script(${COMPONENT_LIB} INTERFACE "osal/idf/usbh_class_info.ld")
# 强制链接器不删除符号
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_acm_none_class_info")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_data_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_HID)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u hid_custom_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_MSC)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u msc_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_ECM)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_ecm_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_RNDIS)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u rndis_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_NCM)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_ncm_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_VIDEO)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u video_ctrl_class_info")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u video_streaming_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_AUDIO)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u audio_ctrl_intf_class_info")
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u audio_streaming_intf_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_BLUETOOTH)
if(CONFIG_USBHOST_BLUETOOTH_HCI_H4)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u bluetooth_h4_nrf_class_info")
else()
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u bluetooth_class_info")
endif()
endif()
if(CONFIG_CHERRYUSB_HOST_ASIX)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u asix_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_RTL8152)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u rtl8152_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_FTDI)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ftdi_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_CH34X)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ch34x_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_CP210X)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cp210x_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_PL2303)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u pl2303_class_info")
endif()
if(CONFIG_CHERRYUSB_HOST_GSM)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u gsm_class_info")
endif()
endif()
if(CONFIG_CHERRYUSB)
set_source_files_properties("class/audio/usbd_audio.c" PROPERTIES COMPILE_FLAGS -Wno-maybe-uninitialized)
endif()
elseif(ZEPHYR_BASE)
message(STATUS "enable cherryusb in zephyr")
set(CONFIG_CHERRYUSB_OSAL "zephyr")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
list(REMOVE_DUPLICATES cherryusb_srcs)
list(REMOVE_DUPLICATES cherryusb_incs)
if (CONFIG_SHELL)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/zephyr/usb_cmd.c)
endif ()
if (CONFIG_FILE_SYSTEM AND CONFIG_CHERRYUSB_HOST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/zephyr/usbh_msc_disk.c)
endif ()
zephyr_library()
if(cherryusb_incs)
zephyr_include_directories(${cherryusb_incs})
endif()
if(cherryusb_srcs)
zephyr_library_sources(${cherryusb_srcs})
endif()
if (CONFIG_CHERRYUSB_HOST)
zephyr_linker_sources(SECTIONS zephyr/usbh_class_info.ld)
endif()
elseif(HPM_SDK_BASE)
message(STATUS "enable cherryusb in hpm_sdk")
set(CONFIG_CHERRYUSB_DEVICE_CDC_ACM 1)
set(CONFIG_CHERRYUSB_DEVICE_HID 1)
set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_NCM 1)
set(CONFIG_CHERRYUSB_HOST_HID 1)
set(CONFIG_CHERRYUSB_HOST_MSC 1)
set(CONFIG_CHERRYUSB_HOST_VIDEO 1)
set(CONFIG_CHERRYUSB_HOST_AUDIO 1)
set(CONFIG_CHERRYUSB_HOST_CDC_RNDIS 1)
# set(CONFIG_CHERRYUSB_HOST_BLUETOOTH 1)
set(CONFIG_CHERRYUSB_HOST_ASIX 1)
set(CONFIG_CHERRYUSB_HOST_RTL8152 1)
set(CONFIG_CHERRYUSB_HOST_CH34X 1)
set(CONFIG_CHERRYUSB_HOST_CP210X 1)
set(CONFIG_CHERRYUSB_HOST_FTDI 1)
set(CONFIG_CHERRYUSB_HOST_PL2303 1)
set(CONFIG_CHERRYUSB_HOST_GSM 1)
set(CONFIG_CHERRYUSB_DEVICE_HPM 1)
set(CONFIG_CHERRYUSB_HOST_EHCI_HPM 1)
set(CONFIG_CHERRYUSB_OSAL "freertos")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
list(REMOVE_DUPLICATES cherryusb_srcs)
list(REMOVE_DUPLICATES cherryusb_incs)
sdk_inc(${cherryusb_incs})
sdk_src(${cherryusb_srcs})
endif()
endif()

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

468
Kconfig Normal file
View File

@@ -0,0 +1,468 @@
# Kconfig file for CherryUSB
menuconfig CHERRYUSB
bool "CherryUSB Configuration"
default n
if CHERRYUSB
menuconfig CHERRYUSB_DEVICE
bool "Enable usb device mode"
default n
if CHERRYUSB_DEVICE
choice CHERRYUSB_DEVICE_SPEED
prompt "Select usb device speed"
default CHERRYUSB_DEVICE_SPEED_FS
config CHERRYUSB_DEVICE_SPEED_FS
bool "FS"
config CHERRYUSB_DEVICE_SPEED_HS
bool "HS"
config CHERRYUSB_DEVICE_SPEED_AUTO
bool "AUTO"
endchoice
choice CHERRYUSB_DEVICE_IP
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
default CHERRYUSB_DEVICE_CUSTOM
config CHERRYUSB_DEVICE_CUSTOM
bool "CUSTOM (Implement it yourself)"
config CHERRYUSB_DEVICE_FSDEV_ST
bool "fsdev_st"
config CHERRYUSB_DEVICE_FSDEV_CUSTOM
bool "fsdev_custom"
config CHERRYUSB_DEVICE_DWC2_ST
bool "dwc2_st"
config CHERRYUSB_DEVICE_DWC2_ESP
bool "dwc2_esp"
config CHERRYUSB_DEVICE_DWC2_KENDRYTE
bool "dwc2_kendryte"
config CHERRYUSB_DEVICE_DWC2_INFINEON
bool "dwc2_infineon"
config CHERRYUSB_DEVICE_DWC2_AT
bool "dwc2_at"
config CHERRYUSB_DEVICE_DWC2_HC
bool "dwc2_hc"
config CHERRYUSB_DEVICE_DWC2_NATION
bool "dwc2_nation"
config CHERRYUSB_DEVICE_DWC2_GD
bool "dwc2_gd"
config CHERRYUSB_DEVICE_DWC2_CUSTOM
bool "dwc2_custom"
config CHERRYUSB_DEVICE_MUSB_ES
bool "musb_es"
config CHERRYUSB_DEVICE_MUSB_SUNXI
bool "musb_sunxi"
config CHERRYUSB_DEVICE_MUSB_BK
bool "musb_bk"
config CHERRYUSB_DEVICE_MUSB_SIFLI
bool "musb_sifli"
config CHERRYUSB_DEVICE_MUSB_CUSTOM
bool "musb_custom"
config CHERRYUSB_DEVICE_CHIPIDEA_MCX
bool "chipidea_mcx"
config CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM
bool "chipidea_custom"
config CHERRYUSB_DEVICE_KINETIS_MCX
bool "kinetis_mcx"
config CHERRYUSB_DEVICE_KINETIS_MM32
bool "kinetis_mm32"
config CHERRYUSB_DEVICE_KINETIS_CUSTOM
bool "kinetis_custom"
config CHERRYUSB_DEVICE_BL
bool "bouffalo"
config CHERRYUSB_DEVICE_HPM
bool "hpm"
config CHERRYUSB_DEVICE_AIC
bool "aic"
config CHERRYUSB_DEVICE_RP2040
bool "rp2040"
config CHERRYUSB_DEVICE_CH32
bool "ch32"
config CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
endchoice
config CHERRYUSB_DEVICE_CDC_ACM
bool
prompt "Enable usb cdc acm device"
default n
config CHERRYUSB_DEVICE_HID
bool
prompt "Enable usb hid device"
default n
config CHERRYUSB_DEVICE_MSC
bool
prompt "Enable usb msc device"
default n
config CHERRYUSB_DEVICE_AUDIO
bool
prompt "Enable usb audio device"
default n
config CHERRYUSB_DEVICE_VIDEO
bool
prompt "Enable usb video device"
default n
config CHERRYUSB_DEVICE_CDC_RNDIS
bool
prompt "Enable usb cdc rndis device"
default n
config CHERRYUSB_DEVICE_CDC_ECM
bool
prompt "Enable usb cdc ecm device"
default n
config CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
depends on !IDF_CMAKE
default n
config CHERRYUSB_DEVICE_MTP
bool
prompt "Enable usb mtp device, it is commercial charge"
default n
config CHERRYUSB_DEVICE_ADB
bool
prompt "Enable usb adb device"
default n
config CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
config USBDEV_REQUEST_BUFFER_LEN
int
prompt "Set device control transfer max buffer size"
default 512
config USBDEV_MSC_MAX_BUFSIZE
int
prompt "Set usb msc device max buffer size"
default 512
help
Set the maximum buffer size for usb msc device, it is used to transfer data.
you can change it to a larger value if you need larger speed but must be a power of blocksize.
config USBDEV_RNDIS_USING_LWIP
bool
prompt "Enable usb rndis device with lwip for lan"
default n
config USBDEV_CDC_ECM_USING_LWIP
bool
prompt "Enable usb cdc ecm device with lwip for lan"
default n
choice CHERRYUSB_DEVICE_TEMPLATE
prompt "Select usb device template, please select class driver first"
default CHERRYUSB_DEVICE_TEMPLATE_NONE
config CHERRYUSB_DEVICE_TEMPLATE_NONE
bool
prompt "none (Implement it yourself)"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
bool
prompt "cdc_acm"
depends on CHERRYUSB_DEVICE_CDC_ACM
config CHERRYUSB_DEVICE_TEMPLATE_MSC
bool
prompt "msc_ram"
depends on CHERRYUSB_DEVICE_MSC
config CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
bool
prompt "hid_keyboard"
depends on CHERRYUSB_DEVICE_HID
config CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
bool
prompt "hid_mouse"
depends on CHERRYUSB_DEVICE_HID
config CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
bool
prompt "hid_custom"
depends on CHERRYUSB_DEVICE_HID
config CHERRYUSB_DEVICE_TEMPLATE_VIDEO
bool
prompt "video"
depends on CHERRYUSB_DEVICE_VIDEO
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
bool
prompt "audio_v1_mic_speaker_multichan"
depends on CHERRYUSB_DEVICE_AUDIO
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
bool
prompt "audio_v2_mic_speaker_multichan"
depends on CHERRYUSB_DEVICE_AUDIO
config CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
bool
prompt "cdc_rndis"
depends on CHERRYUSB_DEVICE_CDC_RNDIS
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
bool
prompt "cdc_ecm"
depends on CHERRYUSB_DEVICE_CDC_ECM
config CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
bool
prompt "cdc_ncm"
depends on CHERRYUSB_DEVICE_CDC_NCM
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
bool
prompt "cdc_acm_msc"
depends on CHERRYUSB_DEVICE_CDC_ACM && CHERRYUSB_DEVICE_MSC
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
bool
prompt "cdc_acm_msc_hid"
depends on CHERRYUSB_DEVICE_CDC_ACM && CHERRYUSB_DEVICE_MSC && CHERRYUSB_DEVICE_HID
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
bool
prompt "winusbv1"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
bool
prompt "winusbv2"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
bool
prompt "winusbv2_cdc"
depends on CHERRYUSB_DEVICE_CDC_ACM
config CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
bool
prompt "webusb_hid"
depends on CHERRYUSB_DEVICE_HID
endchoice
endif
menuconfig CHERRYUSB_HOST
bool "Enable usb host mode"
default n
if CHERRYUSB_HOST
choice CHERRYUSB_HOST_IP
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
default CHERRYUSB_HOST_CUSTOM
config CHERRYUSB_HOST_CUSTOM
bool "CUSTOM (Implement it yourself)"
config CHERRYUSB_HOST_EHCI_BL
bool "ehci_bouffalo"
config CHERRYUSB_HOST_EHCI_HPM
bool "ehci_hpm"
config CHERRYUSB_HOST_EHCI_AIC
bool "ehci_aic"
config CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
config CHERRYUSB_HOST_EHCI_NUC980
bool "ehci_nuc980"
config CHERRYUSB_HOST_EHCI_MA35D0
bool "ehci_ma35d0"
config CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config CHERRYUSB_HOST_DWC2_ST
bool "dwc2_st"
config CHERRYUSB_HOST_DWC2_ESP
bool "dwc2_esp"
config CHERRYUSB_HOST_DWC2_KENDRYTE
bool "dwc2_kendryte"
config CHERRYUSB_HOST_DWC2_INFINEON
bool "dwc2_infineon"
config CHERRYUSB_HOST_DWC2_AT
bool "dwc2_at, f405 only"
config CHERRYUSB_HOST_DWC2_HC
bool "dwc2_hc"
config CHERRYUSB_HOST_DWC2_NATION
bool "dwc2_nation"
config CHERRYUSB_HOST_DWC2_CUSTOM
bool "dwc2_custom"
config CHERRYUSB_HOST_MUSB_ES
bool "musb_es"
config CHERRYUSB_HOST_MUSB_SUNXI
bool "musb_sunxi"
config CHERRYUSB_HOST_MUSB_BK
bool "musb_bk"
config CHERRYUSB_HOST_MUSB_SIFLI
bool "musb_sifli"
config CHERRYUSB_HOST_MUSB_CUSTOM
bool "musb_custom"
config CHERRYUSB_HOST_PUSB2
bool "pusb2"
config CHERRYUSB_HOST_XHCI_PHYTIUM
bool "xhci_phytium"
config CHERRYUSB_HOST_XHCI_CUSTOM
bool "xhci"
config CHERRYUSB_HOST_KINETIS_MCX
bool "kinetis_mcx"
config CHERRYUSB_HOST_KINETIS_MM32
bool "kinetis_mm32"
config CHERRYUSB_HOST_KINETIS_CUSTOM
bool "kinetis_custom"
config CHERRYUSB_HOST_RP2040
bool "rp2040"
endchoice
config CHERRYUSB_HOST_CDC_ACM
bool
prompt "Enable usb cdc acm driver"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_HID
bool
prompt "Enable usb hid driver"
default n
config CHERRYUSB_HOST_MSC
bool
prompt "Enable usb msc driver"
default n
config CHERRYUSB_HOST_CDC_ECM
bool
prompt "Enable usb cdc ecm driver"
select USBHOST_PLATFORM_CDC_ECM
default n
config CHERRYUSB_HOST_CDC_RNDIS
bool
prompt "Enable usb rndis driver"
select USBHOST_PLATFORM_CDC_RNDIS
default n
config CHERRYUSB_HOST_CDC_NCM
bool
prompt "Enable usb cdc ncm driver"
select USBHOST_PLATFORM_CDC_NCM
default n
config CHERRYUSB_HOST_VIDEO
bool
prompt "Enable usb video driver, it is commercial charge"
default n
config CHERRYUSB_HOST_AUDIO
bool
prompt "Enable usb audio driver, it is commercial charge"
default n
config CHERRYUSB_HOST_BLUETOOTH
bool
prompt "Enable usb bluetooth driver"
depends on !IDF_CMAKE
default n
config CHERRYUSB_HOST_ASIX
bool
prompt "Enable usb asix driver"
select USBHOST_PLATFORM_ASIX
default n
config CHERRYUSB_HOST_RTL8152
bool
prompt "Enable usb rtl8152 driver"
select USBHOST_PLATFORM_RTL8152
default n
config CHERRYUSB_HOST_FTDI
bool
prompt "Enable usb ftdi driver"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_CH34X
bool
prompt "Enable usb ch34x driver"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_CP210X
bool
prompt "Enable usb cp210x driver"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_PL2303
bool
prompt "Enable usb pl2303 driver"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_GSM
bool
prompt "Enable usb gsm driver for 4g module"
select USBHOST_SERIAL
default n
config CHERRYUSB_HOST_AOA
bool
prompt "Enable usb aoa driver"
default n
config USBHOST_SERIAL
bool
config USBHOST_PLATFORM_CDC_ECM
bool
config USBHOST_PLATFORM_CDC_RNDIS
bool
config USBHOST_PLATFORM_CDC_NCM
bool
config USBHOST_PLATFORM_ASIX
bool
config USBHOST_PLATFORM_RTL8152
bool
config USBHOST_PSC_PRIO
int
prompt "Set hubport change thread priority, 0 is the max priority"
default 0
config USBHOST_PSC_STACKSIZE
int
prompt "Set hubport change thread stacksize"
default 4096
config USBHOST_REQUEST_BUFFER_LEN
int
prompt "Set host control transfer max buffer size"
default 512
config USBHOST_CONTROL_TRANSFER_TIMEOUT
int
prompt "Set host control transfer timeout, unit is ms"
default 500
config USBHOST_SERIAL_RX_SIZE
int
prompt "Set host serial rx max buffer size"
default 2048
menu "Select USB host template, please select class driver first"
config TEST_USBH_SERIAL
bool
prompt "demo for test serial"
default n
depends on CHERRYUSB_HOST_CDC_ACM || CHERRYUSB_HOST_FTDI || CHERRYUSB_HOST_CH34X || CHERRYUSB_HOST_CP210X || CHERRYUSB_HOST_PL2303
config TEST_USBH_HID
bool
prompt "demo for test hid"
default n
depends on CHERRYUSB_HOST_HID
config TEST_USBH_MSC
bool
prompt "demo for test msc"
default n
depends on CHERRYUSB_HOST_MSC
config TEST_USBH_NET
bool
prompt "demo for test net, no demo for this, you can use lwip api to test"
default n
depends on CHERRYUSB_HOST_CDC_ECM || CHERRYUSB_HOST_CDC_RNDIS || CHERRYUSB_HOST_CDC_NCM || CHERRYUSB_HOST_ASIX || CHERRYUSB_HOST_RTL8152
endmenu
endif
endif

495
Kconfig.rtt Normal file
View File

@@ -0,0 +1,495 @@
# Kconfig file for package CherryUSB
menuconfig RT_USING_CHERRYUSB
bool "Using USB with CherryUSB"
default n
if RT_USING_CHERRYUSB
menuconfig RT_CHERRYUSB_DEVICE
bool "Enable usb device mode"
default n
if RT_CHERRYUSB_DEVICE
choice CHERRYUSB_DEVICE_SPEED
prompt "Select usb device speed"
default RT_CHERRYUSB_DEVICE_SPEED_FS
config RT_CHERRYUSB_DEVICE_SPEED_FS
bool "FS"
config RT_CHERRYUSB_DEVICE_SPEED_HS
bool "HS"
config RT_CHERRYUSB_DEVICE_SPEED_AUTO
bool "AUTO"
endchoice
choice CHERRYUSB_DEVICE_IP
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
default RT_CHERRYUSB_DEVICE_CUSTOM
config RT_CHERRYUSB_DEVICE_CUSTOM
bool "CUSTOM (Implement it yourself)"
config RT_CHERRYUSB_DEVICE_FSDEV_ST
bool "fsdev_st"
config RT_CHERRYUSB_DEVICE_FSDEV_CUSTOM
bool "fsdev_custom"
config RT_CHERRYUSB_DEVICE_DWC2_ST
bool "dwc2_st"
config RT_CHERRYUSB_DEVICE_DWC2_ESP
bool "dwc2_esp"
config RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE
bool "dwc2_kendryte"
config RT_CHERRYUSB_DEVICE_DWC2_INFINEON
bool "dwc2_infineon"
config RT_CHERRYUSB_DEVICE_DWC2_AT
bool "dwc2_at"
config RT_CHERRYUSB_DEVICE_DWC2_HC
bool "dwc2_hc"
config RT_CHERRYUSB_DEVICE_DWC2_NATION
bool "dwc2_nation"
config RT_CHERRYUSB_DEVICE_DWC2_GD
bool "dwc2_gd"
config RT_CHERRYUSB_DEVICE_DWC2_CUSTOM
bool "dwc2_custom"
config RT_CHERRYUSB_DEVICE_MUSB_ES
bool "musb_es"
config RT_CHERRYUSB_DEVICE_MUSB_SUNXI
bool "musb_sunxi"
config RT_CHERRYUSB_DEVICE_MUSB_BK
bool "musb_bk"
config RT_CHERRYUSB_DEVICE_MUSB_SIFLI
bool "musb_sifli"
config RT_CHERRYUSB_DEVICE_MUSB_CUSTOM
bool "musb_custom"
config RT_CHERRYUSB_DEVICE_CHIPIDEA_MCX
bool "chipidea_mcx"
config RT_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM
bool "chipidea_custom"
config RT_CHERRYUSB_DEVICE_KINETIS_MCX
bool "kinetis_mcx"
config RT_CHERRYUSB_DEVICE_KINETIS_MM32
bool "kinetis_mm32"
config RT_CHERRYUSB_DEVICE_KINETIS_CUSTOM
bool "kinetis_custom"
config RT_CHERRYUSB_DEVICE_BL
bool "bouffalo"
config RT_CHERRYUSB_DEVICE_HPM
bool "hpm"
config RT_CHERRYUSB_DEVICE_AIC
bool "aic"
config RT_CHERRYUSB_DEVICE_RP2040
bool "rp2040"
config RT_CHERRYUSB_DEVICE_CH32
bool "ch32"
config RT_CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
config RT_CHERRYUSB_DEVICE_NRF5X
bool "nrf5x"
endchoice
config RT_CHERRYUSB_DEVICE_CDC_ACM
bool
prompt "Enable usb cdc acm device"
default n
config RT_CHERRYUSB_DEVICE_HID
bool
prompt "Enable usb hid device"
default n
config RT_CHERRYUSB_DEVICE_MSC
bool
prompt "Enable usb msc device"
default n
config RT_CHERRYUSB_DEVICE_AUDIO
bool
prompt "Enable usb audio device"
default n
config RT_CHERRYUSB_DEVICE_VIDEO
bool
prompt "Enable usb video device"
default n
config RT_CHERRYUSB_DEVICE_CDC_RNDIS
bool
prompt "Enable usb cdc rndis device"
default n
config RT_CHERRYUSB_DEVICE_CDC_ECM
bool
prompt "Enable usb cdc ecm device"
default n
config RT_CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
default n
config RT_CHERRYUSB_DEVICE_MTP
bool
prompt "Enable usb mtp device, it is commercial charge"
default n
config RT_CHERRYUSB_DEVICE_ADB
bool
prompt "Enable usb adb device"
default n
config RT_CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
bool
prompt "Enable chardev for cdc acm device"
default n
config CONFIG_USBDEV_REQUEST_BUFFER_LEN
int
prompt "Set device control transfer max buffer size"
default 512
config CONFIG_USBDEV_MSC_MAX_BUFSIZE
int
prompt "Set usb msc device max buffer size"
default 512
help
Set the maximum buffer size for usb msc device, it is used to transfer data.
you can change it to a larger value if you need larger speed but must be a power of blocksize.
config CONFIG_USBDEV_RNDIS_USING_LWIP
bool
prompt "Enable usb rndis device with lwip for lan"
default n
config CONFIG_USBDEV_CDC_ECM_USING_LWIP
bool
prompt "Enable usb cdc ecm device with lwip for lan"
default n
choice CHERRYUSB_DEVICE_TEMPLATE
prompt "Select usb device template, please select class driver first"
default RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
config RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
bool
prompt "none (Implement it yourself)"
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
bool
prompt "cdc_acm"
depends on RT_CHERRYUSB_DEVICE_CDC_ACM
config RT_CHERRYUSB_DEVICE_TEMPLATE_MSC
bool
prompt "msc_ram"
depends on RT_CHERRYUSB_DEVICE_MSC
config RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
bool
prompt "msc_blkdev"
depends on RT_CHERRYUSB_DEVICE_MSC
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
bool
prompt "hid_keyboard"
depends on RT_CHERRYUSB_DEVICE_HID
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
bool
prompt "hid_mouse"
depends on RT_CHERRYUSB_DEVICE_HID
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
bool
prompt "hid_custom"
depends on RT_CHERRYUSB_DEVICE_HID
config RT_CHERRYUSB_DEVICE_TEMPLATE_VIDEO
bool
prompt "video"
depends on RT_CHERRYUSB_DEVICE_VIDEO
config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
bool
prompt "audio_v1_mic_speaker_multichan"
depends on RT_CHERRYUSB_DEVICE_AUDIO
config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
bool
prompt "audio_v2_mic_speaker_multichan"
depends on RT_CHERRYUSB_DEVICE_AUDIO
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
bool
prompt "cdc_rndis"
depends on RT_CHERRYUSB_DEVICE_CDC_RNDIS
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
bool
prompt "cdc_ecm"
depends on RT_CHERRYUSB_DEVICE_CDC_ECM
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
bool
prompt "cdc_ncm"
depends on RT_CHERRYUSB_DEVICE_CDC_NCM
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
bool
prompt "cdc_acm_msc"
depends on RT_CHERRYUSB_DEVICE_CDC_ACM && RT_CHERRYUSB_DEVICE_MSC
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
bool
prompt "cdc_acm_msc_hid"
depends on RT_CHERRYUSB_DEVICE_CDC_ACM && RT_CHERRYUSB_DEVICE_MSC && RT_CHERRYUSB_DEVICE_HID
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
bool
prompt "winusbv1"
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
bool
prompt "winusbv2"
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
bool
prompt "winusbv2_cdc"
depends on RT_CHERRYUSB_DEVICE_CDC_ACM
config RT_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
bool
prompt "webusb_hid"
depends on RT_CHERRYUSB_DEVICE_HID
config RT_CHERRYUSB_DEVICE_TEMPLATE_ADB
bool
prompt "adb"
depends on RT_CHERRYUSB_DEVICE_ADB
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV
bool
prompt "cdc_acm_chardev"
depends on RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
endchoice
config CONFIG_USBDEV_MSC_BLOCK_DEV_NAME
string "usb device msc block device name"
depends on RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
default "sd0"
endif
menuconfig RT_CHERRYUSB_HOST
bool "Enable usb host mode"
default n
if RT_CHERRYUSB_HOST
choice CHERRYUSB_HOST_IP
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
default RT_CHERRYUSB_HOST_CUSTOM
config RT_CHERRYUSB_HOST_CUSTOM
bool "CUSTOM (Implement it yourself)"
config RT_CHERRYUSB_HOST_EHCI_BL
bool "ehci_bouffalo"
config RT_CHERRYUSB_HOST_EHCI_HPM
bool "ehci_hpm"
config RT_CHERRYUSB_HOST_EHCI_AIC
bool "ehci_aic"
config RT_CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
config RT_CHERRYUSB_HOST_EHCI_NUC980
bool "ehci_nuc980"
config RT_CHERRYUSB_HOST_EHCI_MA35D0
bool "ehci_ma35d0"
config RT_CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config RT_CHERRYUSB_HOST_DWC2_ST
bool "dwc2_st"
config RT_CHERRYUSB_HOST_DWC2_ESP
bool "dwc2_esp"
config RT_CHERRYUSB_HOST_DWC2_KENDRYTE
bool "dwc2_kendryte"
config RT_CHERRYUSB_HOST_DWC2_INFINEON
bool "dwc2_infineon"
config RT_CHERRYUSB_HOST_DWC2_AT
bool "dwc2_at, f405 only"
config RT_CHERRYUSB_HOST_DWC2_HC
bool "dwc2_hc"
config RT_CHERRYUSB_HOST_DWC2_NATION
bool "dwc2_nation"
config RT_CHERRYUSB_HOST_DWC2_CUSTOM
bool "dwc2_custom"
config RT_CHERRYUSB_HOST_MUSB_ES
bool "musb_es"
config RT_CHERRYUSB_HOST_MUSB_SUNXI
bool "musb_sunxi"
config RT_CHERRYUSB_HOST_MUSB_BK
bool "musb_bk"
config RT_CHERRYUSB_HOST_MUSB_SIFLI
bool "musb_sifli"
config RT_CHERRYUSB_HOST_MUSB_CUSTOM
bool "musb_custom"
config RT_CHERRYUSB_HOST_PUSB2
bool "pusb2"
config RT_CHERRYUSB_HOST_XHCI
bool "xhci"
config RT_CHERRYUSB_HOST_RP2040
bool "rp2040"
endchoice
config RT_CHERRYUSB_HOST_CDC_ACM
bool
prompt "Enable usb cdc acm driver"
select CONFIG_USBHOST_SERIAL
default n
config RT_CHERRYUSB_HOST_HID
bool
prompt "Enable usb hid driver"
default n
config RT_CHERRYUSB_HOST_MSC
bool
prompt "Enable usb msc driver"
default n
select RT_USING_DFS
select RT_USING_DFS_ELMFAT
config RT_CHERRYUSB_HOST_CDC_ECM
bool
prompt "Enable usb cdc ecm driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_ECM
default n
config RT_CHERRYUSB_HOST_CDC_RNDIS
bool
prompt "Enable usb rndis driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_RNDIS
default n
config RT_CHERRYUSB_HOST_CDC_NCM
bool
prompt "Enable usb cdc ncm driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_NCM
default n
config RT_CHERRYUSB_HOST_VIDEO
bool
prompt "Enable usb video driver, it is commercial charge"
default n
config RT_CHERRYUSB_HOST_AUDIO
bool
prompt "Enable usb audio driver, it is commercial charge"
default n
config RT_CHERRYUSB_HOST_BLUETOOTH
bool
prompt "Enable usb bluetooth driver"
default n
config RT_CHERRYUSB_HOST_ASIX
bool
prompt "Enable usb asix driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_ASIX
default n
config RT_CHERRYUSB_HOST_RTL8152
bool
prompt "Enable usb rtl8152 driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_RTL8152
default n
config RT_CHERRYUSB_HOST_FTDI
bool
prompt "Enable usb ftdi driver"
select CONFIG_USBHOST_SERIAL
default n
config RT_CHERRYUSB_HOST_CH34X
bool
prompt "Enable usb ch34x driver"
select CONFIG_USBHOST_SERIAL
default n
config RT_CHERRYUSB_HOST_CP210X
bool
prompt "Enable usb cp210x driver"
select CONFIG_USBHOST_SERIAL
default n
config RT_CHERRYUSB_HOST_PL2303
bool
prompt "Enable usb pl2303 driver"
select CONFIG_USBHOST_SERIAL
default n
config RT_CHERRYUSB_HOST_GSM
bool
prompt "Enable usb gsm driver for 4g module"
select CONFIG_USBHOST_SERIAL
default n
config CONFIG_USBHOST_SERIAL
bool
config CONFIG_USBHOST_PLATFORM_CDC_ECM
bool
config CONFIG_USBHOST_PLATFORM_CDC_RNDIS
bool
config CONFIG_USBHOST_PLATFORM_CDC_NCM
bool
config CONFIG_USBHOST_PLATFORM_ASIX
bool
config CONFIG_USBHOST_PLATFORM_RTL8152
bool
config CONFIG_USBHOST_PSC_PRIO
int
prompt "Set hubport change thread priority, 0 is the max priority"
default 0
config CONFIG_USBHOST_PSC_STACKSIZE
int
prompt "Set hubport change thread stacksize"
default 4096
config CONFIG_USBHOST_REQUEST_BUFFER_LEN
int
prompt "Set host control transfer max buffer size"
default 512
config CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
int
prompt "Set host control transfer timeout, unit is ms"
default 500
config CONFIG_USBHOST_SERIAL_RX_SIZE
int
prompt "Set host serial rx max buffer size"
default 2048
config RT_LWIP_PBUF_POOL_BUFSIZE
int "The size of each pbuf in the pbuf pool"
range 1500 2000
default 1600
config CONFIG_USB_DFS_MOUNT_POINT
string "usb host dfs mount point"
depends on RT_CHERRYUSB_HOST_MSC
default "/"
menu "Select USB host template, please select class driver first"
config RT_TEST_USBH_SERIAL
bool
prompt "demo for test seial, cannot enable this demo, you can use rt-thread device api to test"
default n
depends on CONFIG_USBHOST_SERIAL
config RT_TEST_USBH_HID
int
prompt "demo for test hid"
default 0
depends on RT_CHERRYUSB_HOST_HID
config RT_TEST_USBH_MSC
bool
prompt "demo for test msc, cannot enable this demo, you can use rt-thread dfs api to test"
default n
depends on RT_CHERRYUSB_HOST_MSC
config RT_TEST_USBH_NET
bool
prompt "demo for test net, cannot enable this demo, you can use lwip api to test"
default n
depends on RT_CHERRYUSB_HOST_CDC_ECM || RT_CHERRYUSB_HOST_CDC_RNDIS || RT_CHERRYUSB_HOST_CDC_NCM || RT_CHERRYUSB_HOST_ASIX || RT_CHERRYUSB_HOST_RTL8152
endmenu
endif
endif

536
Kconfig.rttpkg Normal file
View File

@@ -0,0 +1,536 @@
# Kconfig file for package CherryUSB
menuconfig PKG_USING_CHERRYUSB
depends on RT_VER_NUM < 0x50200
bool "CherryUSB: tiny and portable USB host/device stack for embedded system with USB IP"
default n
if PKG_USING_CHERRYUSB
menuconfig PKG_CHERRYUSB_DEVICE
bool "Enable usb device mode"
default n
if PKG_CHERRYUSB_DEVICE
choice CHERRYUSB_DEVICE_SPEED
prompt "Select usb device speed"
default PKG_CHERRYUSB_DEVICE_SPEED_FS
config PKG_CHERRYUSB_DEVICE_SPEED_FS
bool "FS"
config PKG_CHERRYUSB_DEVICE_SPEED_HS
bool "HS"
config PKG_CHERRYUSB_DEVICE_SPEED_AUTO
bool "AUTO"
endchoice
choice CHERRYUSB_DEVICE_IP
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
default PKG_CHERRYUSB_DEVICE_CUSTOM
config PKG_CHERRYUSB_DEVICE_CUSTOM
bool "CUSTOM (Implement it yourself)"
config PKG_CHERRYUSB_DEVICE_FSDEV_ST
bool "fsdev_st"
config PKG_CHERRYUSB_DEVICE_FSDEV_CUSTOM
bool "fsdev_custom"
config PKG_CHERRYUSB_DEVICE_DWC2_ST
bool "dwc2_st"
config PKG_CHERRYUSB_DEVICE_DWC2_ESP
bool "dwc2_esp"
config PKG_CHERRYUSB_DEVICE_DWC2_KENDRYTE
bool "dwc2_kendryte"
config PKG_CHERRYUSB_DEVICE_DWC2_INFINEON
bool "dwc2_infineon"
config PKG_CHERRYUSB_DEVICE_DWC2_AT
bool "dwc2_at"
config PKG_CHERRYUSB_DEVICE_DWC2_HC
bool "dwc2_hc"
config PKG_CHERRYUSB_DEVICE_DWC2_NATION
bool "dwc2_nation"
config PKG_CHERRYUSB_DEVICE_DWC2_GD
bool "dwc2_gd"
config PKG_CHERRYUSB_DEVICE_DWC2_CUSTOM
bool "dwc2_custom"
config PKG_CHERRYUSB_DEVICE_MUSB_ES
bool "musb_es"
config PKG_CHERRYUSB_DEVICE_MUSB_SUNXI
bool "musb_sunxi"
config PKG_CHERRYUSB_DEVICE_MUSB_BK
bool "musb_bk"
config PKG_CHERRYUSB_DEVICE_MUSB_SIFLI
bool "musb_sifli"
config PKG_CHERRYUSB_DEVICE_MUSB_CUSTOM
bool "musb_custom"
config PKG_CHERRYUSB_DEVICE_CHIPIDEA_MCX
bool "chipidea_mcx"
config PKG_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM
bool "chipidea_custom"
config PKG_CHERRYUSB_DEVICE_KINETIS_MCX
bool "kinetis_mcx"
config PKG_CHERRYUSB_DEVICE_KINETIS_MM32
bool "kinetis_mm32"
config PKG_CHERRYUSB_DEVICE_KINETIS_CUSTOM
bool "kinetis_custom"
config PKG_CHERRYUSB_DEVICE_BL
bool "bouffalo"
config PKG_CHERRYUSB_DEVICE_HPM
bool "hpm"
config PKG_CHERRYUSB_DEVICE_AIC
bool "aic"
config PKG_CHERRYUSB_DEVICE_RP2040
bool "rp2040"
config PKG_CHERRYUSB_DEVICE_CH32
bool "ch32"
config PKG_CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
endchoice
config PKG_CHERRYUSB_DEVICE_CDC_ACM
bool
prompt "Enable usb cdc acm device"
default n
config PKG_CHERRYUSB_DEVICE_HID
bool
prompt "Enable usb hid device"
default n
config PKG_CHERRYUSB_DEVICE_MSC
bool
prompt "Enable usb msc device"
default n
config PKG_CHERRYUSB_DEVICE_AUDIO
bool
prompt "Enable usb audio device"
default n
config PKG_CHERRYUSB_DEVICE_VIDEO
bool
prompt "Enable usb video device"
default n
config PKG_CHERRYUSB_DEVICE_CDC_RNDIS
bool
prompt "Enable usb cdc rndis device"
default n
config PKG_CHERRYUSB_DEVICE_CDC_ECM
bool
prompt "Enable usb cdc ecm device"
default n
config PKG_CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
default n
config PKG_CHERRYUSB_DEVICE_MTP
bool
prompt "Enable usb mtp device, it is commercial charge"
default n
config PKG_CHERRYUSB_DEVICE_ADB
bool
prompt "Enable usb adb device"
default n
config PKG_CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
config PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
bool
prompt "Enable chardev for cdc acm device"
default n
config CONFIG_USBDEV_REQUEST_BUFFER_LEN
int
prompt "Set device control transfer max buffer size"
default 512
config CONFIG_USBDEV_MSC_MAX_BUFSIZE
int
prompt "Set usb msc device max buffer size"
default 512
help
Set the maximum buffer size for usb msc device, it is used to transfer data.
you can change it to a larger value if you need larger speed but must be a power of blocksize.
config CONFIG_USBDEV_RNDIS_USING_LWIP
bool
prompt "Enable usb rndis device with lwip for lan"
default n
config CONFIG_USBDEV_CDC_ECM_USING_LWIP
bool
prompt "Enable usb cdc ecm device with lwip for lan"
default n
choice CHERRYUSB_DEVICE_TEMPLATE
prompt "Select usb device template, please select class driver first"
default PKG_CHERRYUSB_DEVICE_TEMPLATE_NONE
config PKG_CHERRYUSB_DEVICE_TEMPLATE_NONE
bool
prompt "none (Implement it yourself)"
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
bool
prompt "cdc_acm"
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM
config PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC
bool
prompt "msc_ram"
depends on PKG_CHERRYUSB_DEVICE_MSC
config PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
bool
prompt "msc_blkdev"
depends on PKG_CHERRYUSB_DEVICE_MSC
config PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
bool
prompt "hid_keyboard"
depends on PKG_CHERRYUSB_DEVICE_HID
config PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
bool
prompt "hid_mouse"
depends on PKG_CHERRYUSB_DEVICE_HID
config PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
bool
prompt "hid_custom"
depends on PKG_CHERRYUSB_DEVICE_HID
config PKG_CHERRYUSB_DEVICE_TEMPLATE_VIDEO
bool
prompt "video"
depends on PKG_CHERRYUSB_DEVICE_VIDEO
config PKG_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
bool
prompt "audio_v1_mic_speaker_multichan"
depends on PKG_CHERRYUSB_DEVICE_AUDIO
config PKG_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
bool
prompt "audio_v2_mic_speaker_multichan"
depends on PKG_CHERRYUSB_DEVICE_AUDIO
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
bool
prompt "cdc_rndis"
depends on PKG_CHERRYUSB_DEVICE_CDC_RNDIS
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
bool
prompt "cdc_ecm"
depends on PKG_CHERRYUSB_DEVICE_CDC_ECM
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
bool
prompt "cdc_ncm"
depends on PKG_CHERRYUSB_DEVICE_CDC_NCM
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
bool
prompt "cdc_acm_msc"
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM && PKG_CHERRYUSB_DEVICE_MSC
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
bool
prompt "cdc_acm_msc_hid"
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM && PKG_CHERRYUSB_DEVICE_MSC && PKG_CHERRYUSB_DEVICE_HID
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
bool
prompt "winusbv1"
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
bool
prompt "winusbv2"
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
bool
prompt "winusbv2_cdc"
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
bool
prompt "webusb_hid"
depends on PKG_CHERRYUSB_DEVICE_HID
config PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB
bool
prompt "adb"
depends on PKG_CHERRYUSB_DEVICE_ADB
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV
bool
prompt "cdc_acm_chardev"
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
endchoice
config CONFIG_USBDEV_MSC_BLOCK_DEV_NAME
string "usb device msc block device name"
depends on PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
default "sd0"
endif
menuconfig PKG_CHERRYUSB_HOST
bool "Enable usb host mode"
default n
if PKG_CHERRYUSB_HOST
choice CHERRYUSB_HOST_IP
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
default PKG_CHERRYUSB_HOST_CUSTOM
config PKG_CHERRYUSB_HOST_CUSTOM
bool "CUSTOM (Implement it yourself)"
config PKG_CHERRYUSB_HOST_EHCI_BL
bool "ehci_bouffalo"
config PKG_CHERRYUSB_HOST_EHCI_HPM
bool "ehci_hpm"
config PKG_CHERRYUSB_HOST_EHCI_AIC
bool "ehci_aic"
config PKG_CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
config PKG_CHERRYUSB_HOST_EHCI_NUC980
bool "ehci_nuc980"
config PKG_CHERRYUSB_HOST_EHCI_MA35D0
bool "ehci_ma35d0"
config PKG_CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config PKG_CHERRYUSB_HOST_DWC2_ST
bool "dwc2_st"
config PKG_CHERRYUSB_HOST_DWC2_ESP
bool "dwc2_esp"
config PKG_CHERRYUSB_HOST_DWC2_KENDRYTE
bool "dwc2_kendryte"
config PKG_CHERRYUSB_HOST_DWC2_INFINEON
bool "dwc2_infineon"
config PKG_CHERRYUSB_HOST_DWC2_AT
bool "dwc2_at, f405 only"
config PKG_CHERRYUSB_HOST_DWC2_HC
bool "dwc2_hc"
config PKG_CHERRYUSB_HOST_DWC2_NATION
bool "dwc2_nation"
config PKG_CHERRYUSB_HOST_DWC2_CUSTOM
bool "dwc2_custom"
config PKG_CHERRYUSB_HOST_MUSB_ES
bool "musb_es"
config PKG_CHERRYUSB_HOST_MUSB_SUNXI
bool "musb_sunxi"
config PKG_CHERRYUSB_HOST_MUSB_BK
bool "musb_bk"
config PKG_CHERRYUSB_HOST_MUSB_SIFLI
bool "musb_sifli"
config PKG_CHERRYUSB_HOST_MUSB_CUSTOM
bool "musb_custom"
config PKG_CHERRYUSB_HOST_PUSB2
bool "pusb2"
config PKG_CHERRYUSB_HOST_XHCI
bool "xhci"
config PKG_CHERRYUSB_HOST_RP2040
bool "rp2040"
endchoice
config PKG_CHERRYUSB_HOST_CDC_ACM
bool
prompt "Enable usb cdc acm driver"
select CONFIG_USBHOST_SERIAL
default n
config PKG_CHERRYUSB_HOST_HID
bool
prompt "Enable usb hid driver"
default n
config PKG_CHERRYUSB_HOST_MSC
bool
prompt "Enable usb msc driver"
default n
select RT_USING_DFS
select RT_USING_DFS_ELMFAT
config PKG_CHERRYUSB_HOST_CDC_ECM
bool
prompt "Enable usb cdc ecm driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_ECM
default n
config PKG_CHERRYUSB_HOST_CDC_RNDIS
bool
prompt "Enable usb rndis driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_RNDIS
default n
config PKG_CHERRYUSB_HOST_CDC_NCM
bool
prompt "Enable usb cdc ncm driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_CDC_NCM
default n
config PKG_CHERRYUSB_HOST_VIDEO
bool
prompt "Enable usb video driver, it is commercial charge"
default n
config PKG_CHERRYUSB_HOST_AUDIO
bool
prompt "Enable usb audio driver, it is commercial charge"
default n
config PKG_CHERRYUSB_HOST_BLUETOOTH
bool
prompt "Enable usb bluetooth driver"
default n
config PKG_CHERRYUSB_HOST_ASIX
bool
prompt "Enable usb asix driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_ASIX
default n
config PKG_CHERRYUSB_HOST_RTL8152
bool
prompt "Enable usb rtl8152 driver"
select RT_USING_LWIP
select CONFIG_USBHOST_PLATFORM_RTL8152
default n
config PKG_CHERRYUSB_HOST_FTDI
bool
prompt "Enable usb ftdi driver"
select CONFIG_USBHOST_SERIAL
default n
config PKG_CHERRYUSB_HOST_CH34X
bool
prompt "Enable usb ch34x driver"
select CONFIG_USBHOST_SERIAL
default n
config PKG_CHERRYUSB_HOST_CP210X
bool
prompt "Enable usb cp210x driver"
select CONFIG_USBHOST_SERIAL
default n
config PKG_CHERRYUSB_HOST_PL2303
bool
prompt "Enable usb pl2303 driver"
select CONFIG_USBHOST_SERIAL
default n
config PKG_CHERRYUSB_HOST_GSM
bool
prompt "Enable usb gsm driver for 4g module"
select CONFIG_USBHOST_SERIAL
default n
config CONFIG_USBHOST_SERIAL
bool
config CONFIG_USBHOST_PLATFORM_CDC_ECM
bool
config CONFIG_USBHOST_PLATFORM_CDC_RNDIS
bool
config CONFIG_USBHOST_PLATFORM_CDC_NCM
bool
config CONFIG_USBHOST_PLATFORM_ASIX
bool
config CONFIG_USBHOST_PLATFORM_RTL8152
bool
config CONFIG_USBHOST_PSC_PRIO
int
prompt "Set hubport change thread priority, 0 is the max priority"
default 0
config CONFIG_USBHOST_PSC_STACKSIZE
int
prompt "Set hubport change thread stacksize"
default 4096
config CONFIG_USBHOST_REQUEST_BUFFER_LEN
int
prompt "Set host control transfer max buffer size"
default 512
config CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
int
prompt "Set host control transfer timeout, unit is ms"
default 500
config CONFIG_USBHOST_SERIAL_RX_SIZE
int
prompt "Set host serial rx max buffer size"
default 2048
config RT_LWIP_PBUF_POOL_BUFSIZE
int "The size of each pbuf in the pbuf pool"
range 1500 2000
default 1600
config CONFIG_USB_DFS_MOUNT_POINT
string "usb host dfs mount point"
depends on RT_CHERRYUSB_HOST_MSC
default "/"
menu "Select USB host template, please select class driver first"
config PKG_TEST_USBH_SERIAL
bool
prompt "demo for test seial, cannot enable this demo, you can use rt-thread device api to test"
default n
depends on CONFIG_USBHOST_SERIAL
config PKG_TEST_USBH_HID
int
prompt "demo for test hid"
default 0
depends on PKG_CHERRYUSB_HOST_HID
config PKG_TEST_USBH_MSC
bool
prompt "demo for test msc, cannot enable this demo, you can use rt-thread dfs api to test"
default n
depends on PKG_CHERRYUSB_HOST_MSC
config PKG_TEST_USBH_NET
bool
prompt "demo for test net, cannot enable this demo, you can use lwip api to test"
default n
depends on PKG_CHERRYUSB_HOST_CDC_ECM || PKG_CHERRYUSB_HOST_CDC_RNDIS || PKG_CHERRYUSB_HOST_CDC_NCM || PKG_CHERRYUSB_HOST_ASIX || PKG_CHERRYUSB_HOST_RTL8152
endmenu
endif
config PKG_CHERRYUSB_PATH
string
default "/packages/system/CherryUSB"
choice
prompt "Version"
default PKG_USING_CHERRYUSB_V010503
help
Select the package version
config PKG_USING_CHERRYUSB_LATEST_VERSION
bool "latest"
config PKG_USING_CHERRYUSB_V010600
bool "v1.6.0"
config PKG_USING_CHERRYUSB_V010503
bool "v1.5.3.99"
config PKG_USING_CHERRYUSB_V010502
bool "v1.5.2"
config PKG_USING_CHERRYUSB_V010500
bool "v1.5.0"
config PKG_USING_CHERRYUSB_V010403
bool "v1.4.3"
config PKG_USING_CHERRYUSB_V010301
bool "v1.3.1"
config PKG_USING_CHERRYUSB_V010200
bool "v1.2.0"
config PKG_USING_CHERRYUSB_V001002
bool "v0.10.2"
endchoice
config PKG_CHERRYUSB_VER
string
default "latest" if PKG_USING_CHERRYUSB_LATEST_VERSION
default "v1.6.0" if PKG_USING_CHERRYUSB_V010600
default "v1.5.3.99" if PKG_USING_CHERRYUSB_V010503
default "v1.5.2" if PKG_USING_CHERRYUSB_V010502
default "v1.5.0" if PKG_USING_CHERRYUSB_V010500
default "v1.4.3" if PKG_USING_CHERRYUSB_V010403
default "v1.3.1" if PKG_USING_CHERRYUSB_V010301
default "v1.2.0" if PKG_USING_CHERRYUSB_V010200
default "v0.10.2" if PKG_USING_CHERRYUSB_V001002
endif

184
README.md
View File

@@ -1,12 +1,18 @@
# CherryUSB
**English | [简体中文](README_zh.md)**
[中文版](./README_zh.md)
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">CherryUSB</h1>
<p align="center">
<a href="https://github.com/cherry-embedded/CherryUSB/releases"><img src="https://img.shields.io/github/release/cherry-embedded/CherryUSB.svg"></a>
<a href="https://github.com/cherry-embedded/CherryUSB/blob/master/LICENSE"><img src="https://img.shields.io/github/license/cherry-embedded/CherryUSB.svg?style=flat-square"></a>
<a href="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml"><img src="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml/badge.svg"> </a>
<a href="https://discord.com/invite/wFfvrSAey8"><img src="https://img.shields.io/badge/Discord-blue?logo=discord&style=flat-square"> </a>
</p>
CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP.
CherryUSB is a tiny and beautiful, high performance and portable USB host and device stack for embedded system with USB IP.
![CherryUSB](CherryUSB.svg)
## Why choose
## Why choose CherryUSB
### Easy to study USB
@@ -17,12 +23,12 @@ In order to make it easier for users to learn USB basics, enumeration, driver lo
- Class-drivers and porting-drivers are templating and simplification
- Clear API classification (slave: initialisation, registration api, command callback api, data sending and receiving api; host: initialisation, lookup api, data sending and receiving api)
### Easy to use USB
### Easy to use USB
In order to facilitate the use of the USB interface and to take into account the fact that users have learned about uart and dma, the following advantages have been designed for the data sending and receiving class of interface:
- Equivalent to using uart tx dma/uart rx dma
- There is no limit to the length of send and receive, the user does not need to care about the USB packetization process (the porting driver does the packetization process)
- There is no limit to the length of send and receive, the user does not need to care about the USB packetization process (the porting driver does it)
### Easy to bring out USB performance
@@ -32,31 +38,20 @@ Taking into account USB performance issues and trying to achieve the theoretical
- Memory zero copy
- If IP has DMA then uses DMA mode (DMA with hardware packetization)
- Unlimited length make it easier to interface with hardware DMA and take advantage of DMA
- Subcontracting function is handled in interrupt
- Packetization is handled in interrupt
## Directoy Structure
Performance showhttps://cherryusb.cherry-embedded.org/show/
```
.
├── class
├── common
├── core
├── demo
├── docs
├── osal
├── packet capture
└── port
└── tools
```
## Directory Structure
| Directory | Description |
|:-------------:|:---------------------------:|
|class | usb class driver |
|common | usb spec macros and utils |
|core | usb core implementation |
|demo | different chips demo |
|demo | usb device and host demo |
|osal | os wrapper |
|platform | class support for other os |
|docs | doc for guiding |
|port | usb dcd and hcd porting |
|tools | tool url |
@@ -65,87 +60,98 @@ Taking into account USB performance issues and trying to achieve the theoretical
CherryUSB Device Stack provides a unified framework of functions for standard device requests, CLASS requests, VENDOR requests and custom special requests. The object-oriented and chained approach allows the user to quickly get started with composite devices without having to worry about the underlying logic. At the same time, a standard dcd porting interface has been standardised for adapting different USB IPs to achieve ip-oriented programming.
CherryUSB Device Stack has the following functions
CherryUSB Device Stack has the following functions:
- Support USB2.0 full and high speed, USB3.0 super speed
- Support USB2.0 full and high speed(USB3.0 super speed TODO)
- Support endpoint irq callback register by users, let users do whatever they wants in endpoint irq callback.
- Support Composite Device
- Support Communication Device Class (CDC_ACM, CDC_ECM)
- Support Human Interface Device (HID)
- Support Mass Storage Class (MSC)
- Support USB VIDEO CLASS (UVC1.0UVC1.5)
- Support USB AUDIO CLASS (UAC1.0UAC2.0)
- Support USB VIDEO CLASS (UVC1.0, UVC1.5)
- Support USB AUDIO CLASS (UAC1.0, UAC2.0)
- Support Device Firmware Upgrade CLASS (DFU)
- Support USB MIDI CLASS (MIDI)
- Support Remote NDIS (RNDIS)
- Support WINUSB1.0、WINUSB2.0(with BOS)
- Support Media Transfer Protocol (MTP)
- Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
- Support Vendor class
- Support UF2
- Support Android Debug Bridge (Only support shell)
- Support multi device with the same USB IP
CherryUSB Device Stack resource usage (GCC 10.2 with -O2):
CherryUSB Device Stack resource usage (GCC 10.2 with -O2, disable log):
| file | FLASH (Byte) | No Cache RAM (Byte) | RAM (Byte) | Heap (Byte) |
|:-------------:|:--------------:|:-------------------------:|:-------------:|:----------------:|
|usbd_core.c | 3516 | 256(default) + 320 | 0 | 0 |
|usbd_cdc.c | 392 | 0 | 0 | 0 |
|usbd_msc.c | 2839 | 128 + 512(default) | 16 | 0 |
|usbd_hid.c | 364 | 0 | 0 | 0 |
|usbd_audio.c | 1455 | 0 | 0 | 0 |
|usbd_video.c | 2494 | 0 | 84 | 0 |
|usbd_rndis.c | 2109 | 3340 | 76 | 0 |
|usbd_core.c | ~4500 | (512(default) + 320) * bus | 0 | 0 |
|usbd_cdc_acm.c | ~900 | 0 | 0 | 0 |
|usbd_msc.c | ~5000 | (128 + 512(default)) * bus | 16 * bus | 0 |
|usbd_hid.c | ~300 | 0 | 0 | 0 |
|usbd_audio.c | ~4000 | 0 | 0 | 0 |
|usbd_video.c | ~7000 | 0 | 132 * bus | 0 |
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
## Host Stack Overview
The CherryUSB Host Stack has a standard enumeration implementation for devices mounted on roothubs and external hubs, and a standard interface for different Classes to indicate what the Class driver needs to do after enumeration and after disconnection. A standard hcd porting interface has also been standardised for adapting different USB IPs for IP-oriented programming. Finally, the host stack is managed using os, and provides osal to make a adaptation for different os.
The CherryUSB Host Stack has a standard enumeration implementation for devices mounted on root hubs and external hubs, and a standard interface for different Classes to indicate what the Class driver needs to do after enumeration and after disconnection. A standard hcd porting interface has also been standardised for adapting different USB IPs for IP-oriented programming. Finally, the host stack is managed using os, and provides osal to make a adaptation for different os.
CherryUSB Host Stack has the following functions
CherryUSB Host Stack has the following functions:
- Support low speed, full speed, high speed and super speed devices
- Automatic loading of supported Class drivers
- Support blocking transfers and asynchronous transfers
- Support Composite Device
- Multi-level HUB support, expandable up to 7 levels(Testing hub with 10 ports works well,only support dwc2 and ehci now)
- Support Communication Device Class (CDC_ACM, CDC_ECM)
- Multi-level HUB support, expandable up to 7 levels(Testing hub with 10 ports works well,only support dwc2/ehci/xhci/rp2040)
- Support Communication Device Class (CDC_ACM, CDC_ECM, CDC_NCM)
- Support Human Interface Device (HID)
- Support Mass Storage Class (MSC)
- Support USB Video CLASS (commercial charge)
- Support USB Audio CLASS (commercial charge)
- Support USB Video CLASS (UVC1.0, UVC1.5)
- Support USB Audio CLASS (UAC1.0)
- Support Remote NDIS (RNDIS)
- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
- Support Vendor class
- Support Vendor Serial Class(CH34X、CP210X、PL2303、FTDI、GSM)
- Support Vendor network Class(RTL8152、AX88772)
- Support USB modeswitch
- Support Android Open Accessory
- Support multi host with the same USB IP
The CherryUSB Host stack also provides the lsusb function, which allows you to view information about all mounted devices, including those on external hubs, with the help of a shell plugin.
CherryUSB Host Stack resource usage (GCC 10.2 with -O2):
CherryUSB Host Stack resource usage (GCC 10.2 with -O2, disable log):
| file | FLASH (Byte) | No Cache RAM (Byte) | RAM (Byte) | Heap (Byte) |
|:-------------:|:--------------:|:-------------------------------:|:---------------------------:|:------------:|
|usbh_core.c | ~7700 | 512 + 8 * (1+x) *n | 28 | 0 |
|usbh_hub.c | ~5600 | 32 + 4* (1+x) | 12 + sizeof(struct usbh_hub) * (1+x) | 0 |
|usbh_cdc_acm.c | ~1200 | 7 | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2500 | 32 | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~1000 | 128 | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~3700 | 128 | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~3100 | 128 | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~3900 | 4096 + 2 * 2048 | sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~2500 | 2 * 1514 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_bluetooth.c | ~2300 | 2 * 2048(default) | sizeof(struct usbh_bluetooth) * 1 | 0 |
|usbh_core.c | ~4500 | (512(default) + 8 * (1+x) *n) * bus | sizeof(struct usbh_hub) * bus | raw_config_desc |
|usbh_hub.c | ~3500 | (32 + 4 * (1+x)) * bus | 12 + sizeof(struct usbh_hub) * x | 0 |
|usbh_cdc_acm.c | ~600 | 7 * x | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2000 | 128 * x | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~800 | 64 * x | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~5000 | 128 * x | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~4000 | 128 * x | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~3000 | 512 + 2 * 2048(default)| sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~1500 | 2 * 1514 + 16 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_cdc_ncm.c | ~2000 | 2 * 2048(default) + 16 + 32 | sizeof(struct usbh_cdc_ncm) * 1| 0 |
|usbh_bluetooth.c | ~1000 | 2 * 2048(default) | sizeof(struct usbh_bluetooth) * 1 | 0 |
|usbh_asix.c | ~7000 | 2 * 2048(default) + 16 + 32 | sizeof(struct usbh_asix) * 1 | 0 |
|usbh_rtl8152.c | ~9000 | 16K+ 2K(default) + 2 + 32 | sizeof(struct usbh_rtl8152) * 1 | 0 |
Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affected by the following macros
Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affected by the following macros:
```
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
```
x is affected by the following macros
x is affected by the following macros:
```
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
@@ -158,46 +164,70 @@ Only standard and commercial USB IP are listed.
| IP | device | host | Support status |
|:----------------:|:----------:|:--------:|:--------------:|
| OHCI(intel) | none | OHCI | × |
| OHCI(intel) | none | OHCI | |
| EHCI(intel) | none | EHCI | √ |
| XHCI(intel) | none | XHCI | √ |
| UHCI(intel) | none | UHCI | × |
| UHCI(intel) | none | UHCI | × |
| DWC2(synopsys) | DWC2 | DWC2 | √ |
| MUSB(mentor) | MUSB | MUSB | √ |
| FOTG210(faraday)| FOTG210 | EHCI | √ |
| CHIPIDEA(synopsys)| CHIPIDEA | EHCI | √ |
| CDNS2(cadence) | CDNS2 | CDNS2 | √ |
| CDNS3(cadence) | CDNS3 | XHCI | × |
| DWC3(synopsys) | DWC3 | XHCI | × |
## Documentation Tutorial
Quickly start, USB basic concepts, API manual, Class basic concepts and examples, see [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
Quickly start, USB basic concepts, API manual, Class basic concepts and examples, see [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/).
## Video Tutorial
USB basic concepts and how the CherryUSB Device stack is implemented, see [CherryUSB Device Stack Tutorial](https://www.bilibili.com/video/BV1Ef4y1t73d).
CherryUSB Cheese (>= V1.4.3): https://www.bilibili.com/cheese/play/ss707687201 .
## Graphical Config Tool
## Descriptor Generator Tool
[chryusb_configurator](https://github.com/Egahp/chryusb_configurator) is written in **electron + vite2 + ts** frameworkcurrently used to automate the generation of descriptor arrays, with additional functionality to be added later.
Cherry Descriptor: https://desc.cherry-embedded.org/en
## Demo Repo
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Support status |
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Long-term |
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Long-term |
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Long-term |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2 | Long-term |
|artinchip | d12x/d13x/d21x | dwc2/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|Espressif | esp32s2/esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|<= v0.10.2 | No more updated |
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
## Package Support
CherryUSB package is available as follows:
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
## Commercial Support
Refer to https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html.
## Contact
CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
## Company Support
Thanks to the following companies for their support (in no particular order):
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />

View File

@@ -1,12 +1,18 @@
# CherryUSB
**[English](README.md) | 简体中文**
[English](./README.md)
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">CherryUSB</h1>
<p align="center">
<a href="https://github.com/cherry-embedded/CherryUSB/releases"><img src="https://img.shields.io/github/release/cherry-embedded/CherryUSB.svg"></a>
<a href="https://github.com/cherry-embedded/CherryUSB/blob/master/LICENSE"><img src="https://img.shields.io/github/license/cherry-embedded/CherryUSB.svg?style=flat-square"></a>
<a href="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml"><img src="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml/badge.svg"> </a>
<a href="https://discord.com/invite/wFfvrSAey8"><img src="https://img.shields.io/badge/Discord-blue?logo=discord&style=flat-square"> </a>
</p>
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统带 USB IP)的高性能 USB 主从协议栈。
![CherryUSB](CherryUSB.svg)
## 为什么选择
## 为什么选择 CherryUSB
### 易于学习 USB
@@ -22,7 +28,7 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带
为了方便用户使用 USB 接口,考虑到用户学习过 uart 和 dma因此设计的数据收发类接口具备以下优点
- 等价于使用 uart tx dma/uart rx dma
- 收发长度没有限制,用户不需要关心 USB 分包过程porting 驱动做分包过程
- 收发长度没有限制,用户不需要关心 USB 分包过程(分包过程在 porting 中处理
### 易于发挥 USB 性能
@@ -32,30 +38,21 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带
- Memory zero copy
- IP 如果带 DMA 则使用 DMA 模式DMA 带硬件分包功能)
- 长度无限制,方便对接硬件 DMA 并且发挥 DMA 的优势
- 分包功能在中断中处理
- 分包过程在中断中执行
性能展示https://cherryusb.cherry-embedded.org/show/
## 目录结构
```
.
├── class
├── common
├── core
├── demo
├── docs
├── osal
└── port
└── tools
```
| 目录名 | 描述 |
|:-------------:|:-------------------------------:|
|class | usb class 类主从驱动 |
|common | usb spec 定义、常用宏、标准接口定义 |
|core | usb 主从协议栈核心实现 |
|demo | 示例 |
|demo | 主从 class demo |
|docs | 文档 |
|osal | os 封装层 |
|platform | 其他 os 全家桶适配 |
|port | usb 主从需要实现的 porting 接口 |
|tools | 工具链接 |
@@ -65,7 +62,7 @@ CherryUSB Device 协议栈对标准设备请求、CLASS 请求、VENDOR 请求
CherryUSB Device 协议栈当前实现以下功能:
- 支持 USB2.0 全速和高速设备USB3.0 超速设备
- 支持 USB2.0 全速和高速设备USB3.0 超高速 TODO
- 支持端点中断注册功能porting 给用户自己处理中断里的数据
- 支持复合设备
- 支持 Communication Device Class (CDC_ACM, CDC_ECM)
@@ -76,59 +73,70 @@ CherryUSB Device 协议栈当前实现以下功能:
- 支持 Device Firmware Upgrade CLASS (DFU)
- 支持 USB MIDI CLASS (MIDI)
- 支持 Remote NDIS (RNDIS)
- 支持 WINUSB1.0、WINUSB2.0(带 BOS )
- 支持 Media Transfer Protocol (MTP)
- 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
- 支持 Vendor 类 class
- 支持 UF2
- 支持 Android Debug Bridge (Only support shell)
- 支持相同 USB IP 的多从机
CherryUSB Device 协议栈资源占用说明GCC 10.2 with -O2
| file | FLASH (Byte) | No Cache RAM (Byte) | RAM (Byte) | Heap (Byte) |
|:-------------:|:--------------:|:-------------------------:|:-------------:|:----------------:|
|usbd_core.c | 3516 | 256(default) + 320 | 0 | 0 |
|usbd_cdc.c | 392 | 0 | 0 | 0 |
|usbd_msc.c | 2839 | 128 + 512(default) | 16 | 0 |
|usbd_hid.c | 364 | 0 | 0 | 0 |
|usbd_audio.c | 1455 | 0 | 0 | 0 |
|usbd_video.c | 2494 | 0 | 84 | 0 |
|usbd_rndis.c | 2109 | 3340 | 76 | 0 |
|usbd_core.c | ~4500 | (512(default) + 320) * bus | 0 | 0 |
|usbd_cdc_acm.c | ~900 | 0 | 0 | 0 |
|usbd_msc.c | ~5000 | (128 + 512(default)) * bus | 16 * bus | 0 |
|usbd_hid.c | ~300 | 0 | 0 | 0 |
|usbd_audio.c | ~4000 | 0 | 0 | 0 |
|usbd_video.c | ~7000 | 0 | 132 * bus | 0 |
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
## Host 协议栈简介
CherryUSB Host 协议栈对挂载在 roothub、外部 hub 上的设备规范了一套标准的枚举实现,对不同的 Class 类也规范了一套标准接口,用来指示在枚举后和断开连接后该 Class 驱动需要做的事情。同时,规范了一套标准的 hcd porting 接口,用于适配不同的 USB IP达到面向 IP 编程。最后,协议栈使用 OS 管理,并提供了 osal 用来适配不同的 os。
CherryUSB Host 协议栈对挂载在 root hub、外部 hub 上的设备规范了一套标准的枚举实现,对不同的 Class 类也规范了一套标准接口,用来指示在枚举后和断开连接后该 Class 驱动需要做的事情。同时,规范了一套标准的 hcd porting 接口,用于适配不同的 USB IP达到面向 IP 编程。最后,协议栈使用 OS 管理,并提供了 osal 用来适配不同的 os。
CherryUSB Host 协议栈当前实现以下功能:
- 支持 low speedfull speedhigh speed 和 super speed 设备
- 自动加载支持的Class 驱动
- 支持阻塞式传输和异步传输
- 支持复合设备
- 支持多级 HUB,最高可拓展到 7 级(目前测试 1拖 10 没有问题,当前仅支持 dwc2ehci)
- 支持 Communication Device Class (CDC_ACM, CDC_ECM)
- 支持多级 HUB最高可拓展到 7 级(目前测试 1拖 10 没有问题,仅支持 dwc2/ehci/xhci/rp2040)
- 支持 Communication Device Class (CDC_ACM, CDC_ECM, CDC_NCM)
- 支持 Human Interface Device (HID)
- 支持 Mass Storage Class (MSC)
- Support USB Video CLASS(商业收费)
- Support USB Audio CLASS(商业收费)
- Support USB Video CLASS (UVC1.0、UVC1.5)
- Support USB Audio CLASS (UAC1.0)
- 支持 Remote NDIS (RNDIS)
- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
- 支持 Vendor 类 class
- 支持 Vendor Serial 类(CH34X、CP210X、PL2303、FTDI、GSM)
- 支持 Vendor network 类(RTL8152、AX88772)
- 支持 USB modeswitch
- 支持 Android Open Accessory
- 支持相同 USB IP 的多主机
同时CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
CherryUSB Host 协议栈资源占用说明GCC 10.2 with -O2
CherryUSB Host 协议栈资源占用说明GCC 10.2 with -O2,关闭 log
| file | FLASH (Byte) | No Cache RAM (Byte) | RAM (Byte) | Heap (Byte) |
|:-------------:|:--------------:|:-------------------------------:|:---------------------------:|:------------:|
|usbh_core.c | ~7700 | 512 + 8 * (1+x) *n | 28 | 0 |
|usbh_hub.c | ~5600 | 32 + 4* (1+x) | 12 + sizeof(struct usbh_hub) * (1+x) | 0 |
|usbh_cdc_acm.c | ~1200 | 7 | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2500 | 32 | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~1000 | 128 | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~3700 | 128 | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~3100 | 128 | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~3900 | 4096 + 2 * 2048 | sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~2500 | 2 * 1514 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_bluetooth.c | ~2300 | 2 * 2048(default) | sizeof(struct usbh_bluetooth) * 1 | 0 |
|usbh_core.c | ~4500 | (512(default) + 8 * (1+x) *n) * bus | sizeof(struct usbh_hub) * bus | raw_config_desc |
|usbh_hub.c | ~3500 | (32 + 4 * (1+x)) * bus | 12 + sizeof(struct usbh_hub) * x | 0 |
|usbh_cdc_acm.c | ~600 | 7 * x | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2000 | 128 * x | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~800 | 64 * x | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~5000 | 128 * x | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~4000 | 128 * x | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~3000 | 512 + 2 * 2048(default)| sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~1500 | 2 * 1514 + 16 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_cdc_ncm.c | ~2000 | 2 * 2048(default) + 16 + 32 | sizeof(struct usbh_cdc_ncm) * 1| 0 |
|usbh_bluetooth.c | ~1000 | 2 * 2048(default) | sizeof(struct usbh_bluetooth) * 1 | 0 |
|usbh_asix.c | ~7000 | 2 * 2048(default) + 16 + 32 | sizeof(struct usbh_asix) * 1 | 0 |
|usbh_rtl8152.c | ~9000 | 16K+ 2K(default) + 2 + 32 | sizeof(struct usbh_rtl8152) * 1 | 0 |
其中,`sizeof(struct usbh_hub)``sizeof(struct usbh_hubport)` 受以下宏影响:
@@ -136,14 +144,14 @@ CherryUSB Host 协议栈资源占用说明GCC 10.2 with -O2
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
```
x 受以下宏影响:
```
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
@@ -156,48 +164,72 @@ x 受以下宏影响:
| IP | device | host | Support status |
|:----------------:|:----------:|:--------:|:--------------:|
| OHCI(intel) | none | OHCI | × |
| OHCI(intel) | none | OHCI | |
| EHCI(intel) | none | EHCI | √ |
| XHCI(intel) | none | XHCI | √ |
| UHCI(intel) | none | UHCI | × |
| UHCI(intel) | none | UHCI | × |
| DWC2(synopsys) | DWC2 | DWC2 | √ |
| MUSB(mentor) | MUSB | MUSB | √ |
| FOTG210(faraday)| FOTG210 | EHCI | √ |
| CHIPIDEA(synopsys)| CHIPIDEA | EHCI | √ |
| CDNS2(cadence) | CDNS2 | CDNS2 | √ |
| CDNS3(cadence) | CDNS3 | XHCI | × |
| DWC3(synopsys) | DWC3 | XHCI | × |
## 文档教程
CherryUSB 快速入门、USB 基本概念API 手册Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
CherryUSB 快速入门、USB 基本概念API 手册Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
## 视频教程
- USB 基本知识点与 CherryUSB Device 协议栈是如何编写的使用v0.4.1 版本),参考 https://www.bilibili.com/video/BV1Ef4y1t73d.
- CherryUSB 腾讯会议使用v1.1.0 版本),参考 https://www.bilibili.com/video/BV16x421y7mM.
CherryUSB 课程(>= V1.4.3https://www.bilibili.com/cheese/play/ss707687201 。
## 图形化界面配置工具
## 描述符生成工具
[chryusb_configurator](https://github.com/Egahp/chryusb_configurator) 采用 **electron + vite2 + ts** 框架编写,当前用于自动化生成描述符数组,后续会增加其他功能。
Cherry Descriptor: https://desc.cherry-embedded.org/zh
## 示例仓库
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Support status |
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Long-term |
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Long-term |
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Long-term |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2 | Long-term |
|artinchip | d12x/d13x/d21x | dwc2/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|Espressif | esp32s2/esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|<= v0.10.2 | No more updated |
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
## Contact
## 软件包支持
CherryUSB QQ 群:642693751
CherryUSB 微信群:与我联系后邀请加入
CherryUSB 软件包可以通过以下方式获取:
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
## 商业支持
参考 https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html 。
## 联系
CherryUSB QQ群642693751
CherryUSB 微信群:与我联系后邀请加入
## 支持企业
感谢以下企业支持(顺序不分先后):
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />

View File

@@ -1,20 +1,26 @@
from building import *
cwd = GetCurrentDir()
path = [cwd + '/common']
path = [cwd]
path += [cwd + '/common']
path += [cwd + '/core']
path += [cwd + '/class/hub']
path += [cwd + '/class/cdc']
path += [cwd + '/class/msc']
path += [cwd + '/class/hid']
path += [cwd + '/class/audio']
path += [cwd + '/class/video']
path += [cwd + '/class/wireless']
path += [cwd + '/class/dfu']
path += [cwd + '/class/midi']
path += [cwd + '/class/adb']
path += [cwd + '/class/dfu']
path += [cwd + '/class/serial']
path += [cwd + '/class/vendor/net']
path += [cwd + '/class/vendor/serial']
path += [cwd + '/class/vendor/wifi']
src = []
LIBS = []
LIBPATH = []
CPPDEFINES = []
# USB DEVICE
@@ -23,17 +29,13 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('core/usbd_core.c')
src += Glob('osal/usb_osal_rtthread.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_SPEED_HS']):
CPPDEFINES+=['CONFIG_USB_HS']
if GetDepend(['PKG_CHERRYUSB_DEVICE_BL']):
CPPDEFINES += ['CONFIG_CHERRYUSB']
if GetDepend(['PKG_CHERRYUSB_DEVICE_CH32']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
src += Glob('port/ch32/usb_dc_usbhs.c')
else:
src += Glob('port/ch32/usb_dc_usbfs.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_FSDEV']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_FSDEV_ST']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
src += Glob('port/fsdev/usb_glue_st.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_FSDEV_CUSTOM']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_ST']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
@@ -41,31 +43,83 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_ESP']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_esp.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_KENDRYTE']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_kendryte.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_INFINEON']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_infineon.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_AT']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_at.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_AIC']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_HC']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_aic.c')
src += Glob('port/dwc2/usb_glue_hc.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_NATION']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_nation.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_GD']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_gd.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_CUSTOM']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_STANDARD']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_ES']):
src += Glob('port/musb/usb_dc_musb.c')
src += Glob('port/musb/usb_glue_es.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_SUNXI']):
src += Glob('port/musb/usb_dc_musb.c')
CPPDEFINES += ['CONFIG_USB_MUSB_SUNXI']
src += Glob('port/musb/usb_glue_sunxi.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_BK']):
src += Glob('port/musb/usb_dc_musb.c')
src += Glob('port/musb/usb_glue_bk.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_SIFLI']):
src += Glob('port/musb/usb_dc_musb.c')
src += Glob('port/musb/usb_glue_sifli.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_CUSTOM']):
src += Glob('port/musb/usb_dc_musb.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CHIPIDEA_MCX']):
path += [cwd + '/port/chipidea']
src += Glob('port/chipidea/usb_dc_chipidea.c')
src += Glob('port/nxp/usb_glue_mcx.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM']):
path += [cwd + '/port/chipidea']
src += Glob('port/chipidea/usb_dc_chipidea.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_KINETIS_MCX']):
src += Glob('port/kinetis/usb_dc_kinetis.c')
src += Glob('port/kinetis/usb_glue_mcx.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_KINETIS_CUSTOM']):
src += Glob('port/kinetis/usb_dc_kinetis.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_BL']):
src += Glob('port/bouffalolab/usb_dc_bl.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_HPM']):
src += Glob('port/hpm/usb_dc_hpm.c')
path += [cwd + '/port/hpmicro']
src += Glob('port/hpmicro/usb_dc_hpm.c')
src += Glob('port/hpmicro/usb_glue_hpm.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_AIC']):
src += Glob('port/aic/usb_dc_aic.c')
src += Glob('port/aic/usb_dc_aic_ll.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CH32']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
src += Glob('port/ch32/usb_dc_usbhs.c')
else:
src += Glob('port/ch32/usb_dc_usbfs.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_PUSB2']):
path += [cwd + '/port/pusb2/common']
path += [cwd + '/port/pusb2/fpusb2']
src += Glob('port/pusb2/fpusb2' + '/*.c')
src += Glob('port/pusb2/usb_dc_pusb2.c')
path += [cwd + '/port/pusb2/rt-thread']
src += Glob('port/pusb2/rt-thread/usb_dc_glue_phytium.c')
if GetDepend(['ARCH_ARMV8']):
LIBPATH = [cwd + '/port/pusb2']
LIBS = ['libpusb2_dc_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/pusb2']
LIBS = ['libpusb2_dc_a32_softfp_neon.a']
if GetDepend(['PKG_CHERRYUSB_DEVICE_NRF5X']):
src += Glob('port/nrf5x/usb_dc_nrf5x.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_RP2040']):
path += [cwd + '/port/rp2040']
src += Glob('port/rp2040/usb_dc_rp2040.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_ACM']):
src += Glob('class/cdc/usbd_cdc.c')
src += Glob('class/cdc/usbd_cdc_acm.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_HID']):
src += Glob('class/hid/usbd_hid.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC']):
@@ -80,12 +134,18 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('class/cdc/usbd_cdc_ecm.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_NCM']):
src += Glob('class/cdc/usbd_cdc_ncm.c')
if GetDepend(['PKG_CHERRYUSB_USING_DFU']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_DFU']):
src += Glob('class/dfu/usbd_dfu.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_ADB']):
src += Glob('class/adb/usbd_adb.c')
src += Glob('platform/rtthread/usbd_adb_shell.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV']):
src += Glob('platform/rtthread/usbd_serial.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM']):
src += Glob('demo/cdc_acm_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC']) or GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV']):
src += Glob('demo/msc_ram_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE']):
src += Glob('demo/hid_mouse_template.c')
@@ -111,14 +171,19 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('demo/cdc_acm_hid_msc_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1']):
src += Glob('demo/winusb1.0_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2']):
src += Glob('demo/winusb2.0_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC']):
src += Glob('demo/winusb2.0_cdc_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID']):
src += Glob('demo/winusb2.0_hid_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID']):
src += Glob('demo/webusb_hid_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB']):
src += Glob('demo/adb/usbd_adb_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV']):
src += Glob('demo/cdc_acm_rttchardev_template.c')
# USB HOST
if GetDepend(['PKG_CHERRYUSB_HOST']):
path += [cwd + '/class/hub']
src += Glob('core/usbh_core.c')
src += Glob('class/hub/usbh_hub.c')
src += Glob('osal/usb_osal_rtthread.c')
@@ -127,15 +192,24 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_bouffalo.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']):
path += [cwd + '/port/hpmicro']
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_hpm.c')
src += Glob('port/hpmicro/usb_hc_hpm.c')
src += Glob('port/hpmicro/usb_glue_hpm.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_AIC']):
path += [cwd + '/port/ehci']
path += [cwd + '/port/ohci']
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_aic.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980']):
src += Glob('port/ohci/usb_hc_ohci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_MCX']):
path += [cwd + '/port/chipidea']
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/nxp/usb_glue_mcx.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUC980']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_nuc980.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0']):
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_MA35D0']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_ma35d0.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_CUSTOM']):
@@ -146,27 +220,71 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_ESP']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_esp.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_KENDRYTE']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_kendryte.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_INFINEON']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_infineon.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_AT']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_at.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_HC']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_hc.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_NATION']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_nation.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_CUSTOM']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_STANDARD']):
src += Glob('port/musb/usb_hc_musb.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_ES']):
src += Glob('port/musb/usb_hc_musb.c')
src += Glob('port/musb/usb_glue_es.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_SUNXI']):
src += Glob('port/musb/usb_hc_musb.c')
CPPDEFINES += ['CONFIG_USB_MUSB_SUNXI']
src += Glob('port/musb/usb_glue_sunxi.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_BK']):
src += Glob('port/musb/usb_hc_musb.c')
src += Glob('port/musb/usb_glue_bk.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_SIFLI']):
src += Glob('port/musb/usb_hc_musb.c')
src += Glob('port/musb/usb_glue_sifli.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_CUSTOM']):
src += Glob('port/musb/usb_hc_musb.c')
if GetDepend(['PKG_CHERRYUSB_HOST_XHCI']):
src += Glob('port/xhci/usb_hc_xhci.c')
src += Glob('port/xhci/xhci_dbg.c')
src += Glob('port/xhci/xhci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_KINETIS_MCX']):
src += Glob('port/kinetis/usb_hc_kinetis.c')
src += Glob('port/kinetis/usb_glue_mcx.c')
if GetDepend(['PKG_CHERRYUSB_HOST_KINETIS_CUSTOM']):
src += Glob('port/kinetis/usb_hc_kinetis.c')
if GetDepend(['PKG_CHERRYUSB_HOST_PUSB2']):
path += [cwd + '/port/pusb2/common']
path += [cwd + '/port/pusb2/fpusb2']
src += Glob('port/pusb2/fpusb2' + '/*.c')
src += Glob('port/pusb2/usb_hc_pusb2.c')
path += [cwd + '/port/pusb2/rt-thread']
src += Glob('port/pusb2/rt-thread/usb_hc_glue_phytium.c')
if GetDepend(['ARCH_ARMV8']):
LIBPATH = [cwd + '/port/pusb2']
LIBS = ['libpusb2_hc_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/pusb2']
LIBS = ['libpusb2_hc_a32_softfp_neon.a']
if GetDepend(['PKG_CHERRYUSB_HOST_XHCI']):
path += [cwd + '/port/xhci/phytium/rt-thread']
src += Glob('port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c')
src += Glob('port/xhci/phytium/rt-thread/usb_glue_phytium.c')
if GetDepend(['ARCH_ARMV8']):
LIBPATH = [cwd + '/port/xhci/phytium']
LIBS = ['libxhci_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/xhci/phytium']
LIBS = ['libxhci_a32_softfp_neon.a']
if GetDepend(['PKG_CHERRYUSB_HOST_RP2040']):
path += [cwd + '/port/rp2040']
src += Glob('port/rp2040/usb_hc_rp2040.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ACM']):
src += Glob('class/cdc/usbh_cdc_acm.c')
src += Glob('class/serial/usbh_cdc_acm.c')
if GetDepend(['PKG_CHERRYUSB_HOST_HID']):
src += Glob('class/hid/usbh_hid.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
@@ -188,19 +306,41 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
if GetDepend(['PKG_CHERRYUSB_HOST_RTL8152']):
src += Glob('class/vendor/net/usbh_rtl8152.c')
if GetDepend(['PKG_CHERRYUSB_HOST_FTDI']):
src += Glob('class/vendor/serial/usbh_ftdi.c')
src += Glob('class/serial/usbh_ftdi.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CH34X']):
src += Glob('class/vendor/serial/usbh_ch34x.c')
src += Glob('class/serial/usbh_ch34x.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CP210X']):
src += Glob('class/vendor/serial/usbh_cp210x.c')
src += Glob('class/serial/usbh_cp210x.c')
if GetDepend(['PKG_CHERRYUSB_HOST_PL2303']):
src += Glob('class/serial/usbh_pl2303.c')
if GetDepend(['PKG_CHERRYUSB_HOST_TEMPLATE']):
if GetDepend(['PKG_TEST_USBH_HID']):
CPPDEFINES+=['CONFIG_TEST_USBH_HID']
src += Glob('demo/usb_host.c')
if GetDepend('RT_USING_DFS'):
src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ACM']) \
or GetDepend(['PKG_CHERRYUSB_HOST_FTDI']) \
or GetDepend(['PKG_CHERRYUSB_HOST_CH34X']) \
or GetDepend(['PKG_CHERRYUSB_HOST_CP210X']) \
or GetDepend(['PKG_CHERRYUSB_HOST_PL2303']) \
or GetDepend(['PKG_CHERRYUSB_HOST_GSM']):
src += Glob('class/serial/usbh_serial.c')
src += Glob('platform/rtthread/usbh_rtserial.c')
if GetDepend('RT_USING_DFS') and GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
src += Glob('platform/rtthread/usbh_dfs.c')
if GetDepend('PKG_CHERRYUSB_HOST_CDC_ECM') \
or GetDepend('PKG_CHERRYUSB_HOST_CDC_RNDIS') \
or GetDepend('PKG_CHERRYUSB_HOST_CDC_NCM') \
or GetDepend('PKG_CHERRYUSB_HOST_ASIX') \
or GetDepend('PKG_CHERRYUSB_HOST_RTL8152'):
src += Glob('platform/rtthread/usbh_lwip.c')
src += Glob('platform/rtthread/usb_msh.c')
src += Glob('platform/rtthread/usb_check.c')
group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], LIBS = LIBS, LIBPATH=LIBPATH, CPPPATH = path, CPPDEFINES = CPPDEFINES)
Return('group')

View File

@@ -1,5 +1,5 @@
VERSION_MAJOR = 1
VERSION_MINOR = 2
PATCHLEVEL = 99
VERSION_MINOR = 6
PATCHLEVEL = 0
VERSION_TWEAK = 0
EXTRAVERSION = 0

View File

@@ -1,14 +1,18 @@
#
#
# Copyright (c) 2024, sakumisu
#
#
# SPDX-License-Identifier: Apache-2.0
#
#
# cmake-format: off
# set(CONFIG_CHERRYUSB_DEVICE 1)
# set(CONFIG_CHERRYUSB_DEVICE_CDC 1)
# set(CONFIG_CHERRYUSB_DEVICE_HID 1)
# set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
# set(CONFIG_CHERRYUSB_DEVICE_DCD "dwc2_st")
# set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
# set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
# set(CONFIG_CHERRYUSB_DEVICE_DWC2_ST 1)
# set(CONFIG_CHERRYUSB_HOST 1)
# set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
@@ -22,198 +26,363 @@
# set(CONFIG_CHERRYUSB_HOST_BLUETOOTH 1)
# set(CONFIG_CHERRYUSB_HOST_ASIX 1)
# set(CONFIG_CHERRYUSB_HOST_RTL8152 1)
# set(CONFIG_CHERRYUSB_OSAL "freertos")
# set(CONFIG_CHERRYUSB_HOST_HCD "ehci_xxx")
# set(CONFIG_CHERRYUSB_HOST_DWC2_ST 1)
list(APPEND cherryusb_incs
${CMAKE_CURRENT_LIST_DIR}/common
${CMAKE_CURRENT_LIST_DIR}/core
${CMAKE_CURRENT_LIST_DIR}/class/hub
${CMAKE_CURRENT_LIST_DIR}/class/cdc
${CMAKE_CURRENT_LIST_DIR}/class/hid
${CMAKE_CURRENT_LIST_DIR}/class/msc
${CMAKE_CURRENT_LIST_DIR}/class/audio
${CMAKE_CURRENT_LIST_DIR}/class/video
${CMAKE_CURRENT_LIST_DIR}/class/wireless
${CMAKE_CURRENT_LIST_DIR}/class/midi
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
# set(CONFIG_CHERRYUSB_OSAL "freertos")
# cmake-format: on
list(
APPEND
cherryusb_incs
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/common
${CMAKE_CURRENT_LIST_DIR}/core
${CMAKE_CURRENT_LIST_DIR}/class/hub
${CMAKE_CURRENT_LIST_DIR}/class/cdc
${CMAKE_CURRENT_LIST_DIR}/class/hid
${CMAKE_CURRENT_LIST_DIR}/class/msc
${CMAKE_CURRENT_LIST_DIR}/class/audio
${CMAKE_CURRENT_LIST_DIR}/class/video
${CMAKE_CURRENT_LIST_DIR}/class/wireless
${CMAKE_CURRENT_LIST_DIR}/class/midi
${CMAKE_CURRENT_LIST_DIR}/class/adb
${CMAKE_CURRENT_LIST_DIR}/class/dfu
${CMAKE_CURRENT_LIST_DIR}/class/serial
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
${CMAKE_CURRENT_LIST_DIR}/class/aoa
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
)
if(CONFIG_CHERRYUSB_DEVICE)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbd_core.c)
if(CONFIG_CHERRYUSB_DEVICE_CDC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc.c)
if(CONFIG_CHERRYUSB_DEVICE_CDC_ACM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_acm.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_HID)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbd_hid.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbd_hid.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbd_msc.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbd_msc.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_AUDIO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbd_audio.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbd_audio.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_VIDEO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbd_video.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbd_video.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_CDC_ECM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ecm.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ecm.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_CDC_NCM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ncm.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ncm.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_CDC_RNDIS)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbd_rndis.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbd_rndis.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_DFU)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/dfu/usbd_dfu.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/dfu/usbd_dfu.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_ADB)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_GAMEPAD)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/gamepad/usbd_gamepad.c)
endif()
if(DEFINED CONFIG_CHERRYUSB_DEVICE_DCD)
if("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_st")
if(CONFIG_CHERRYUSB_DEVICE_FSDEV_ST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_glue_st.c)
elseif(CONFIG_CHERRYUSB_DEVICE_FSDEV_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_ST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_st.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_esp")
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_ESP)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_esp.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_aic")
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_KENDRYTE)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_aic.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_at")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_kendryte.c)
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_AT)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_at.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "fsdev")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "hpm")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpm/usb_dc_hpm.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "musb")
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_HC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_hc.c)
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_GD)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_gd.c)
elseif(CONFIG_CHERRYUSB_DEVICE_DWC2_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
elseif(CONFIG_CHERRYUSB_DEVICE_MUSB_ES)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
endif()
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_es.c)
elseif(CONFIG_CHERRYUSB_DEVICE_MUSB_SUNXI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_sunxi.c)
elseif(CONFIG_CHERRYUSB_DEVICE_MUSB_BK)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_bk.c)
elseif(CONFIG_CHERRYUSB_DEVICE_MUSB_SIFLI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_sifli.c)
elseif(CONFIG_CHERRYUSB_DEVICE_MUSB_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
elseif(CONFIG_CHERRYUSB_DEVICE_CHIPIDEA_MCX)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/chipidea/usb_dc_chipidea.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/nxp/usb_glue_mcx.c)
elseif(CONFIG_CHERRYUSB_DEVICE_KINETIS_MCX)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_dc_kinetis.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_glue_mcx.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/chipidea)
elseif(CONFIG_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/chipidea/usb_dc_chipidea.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/chipidea)
elseif(CONFIG_CHERRYUSB_DEVICE_HPM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro/usb_dc_hpm.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro/usb_glue_hpm.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro)
elseif(CONFIG_CHERRYUSB_DEVICE_BL)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/bouffalolab/usb_dc_bl.c)
elseif(CONFIG_CHERRYUSB_DEVICE_AIC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/aic/usb_dc_aic.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/aic/usb_dc_aic_ll.c)
elseif(CONFIG_CHERRYUSB_DEVICE_RP2040)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/rp2040/usb_dc_rp2040.c)
endif()
endif()
if(CONFIG_CHERRYUSB_HOST)
list(APPEND cherryusb_srcs
${CMAKE_CURRENT_LIST_DIR}/core/usbh_core.c
${CMAKE_CURRENT_LIST_DIR}/class/hub/usbh_hub.c
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbh_core.c
${CMAKE_CURRENT_LIST_DIR}/class/hub/usbh_hub.c
)
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_acm.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_cdc_acm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_ECM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ecm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_NCM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ncm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_HID)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbh_hid.c)
endif()
if(CONFIG_CHERRYUSB_HOST_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbh_msc.c)
if(CONFIG_CHERRYUSB_HOST_MSC_FATFS)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/port/fatfs_usbh.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/diskio.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ff.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffsystem.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffunicode.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source)
endif()
endif()
if(CONFIG_CHERRYUSB_HOST_VIDEO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbh_video.c)
endif()
if(CONFIG_CHERRYUSB_HOST_AUDIO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbh_audio.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ecm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_RNDIS)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_rndis.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_rndis.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_NCM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ncm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_HID)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbh_hid.c)
endif()
if(CONFIG_CHERRYUSB_HOST_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbh_msc.c)
if(CONFIG_CHERRYUSB_HOST_MSC_FATFS)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/port/fatfs_usbh.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/diskio.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ff.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffsystem.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffunicode.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source)
endif()
endif()
if(CONFIG_CHERRYUSB_HOST_VIDEO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbh_video.c)
endif()
if(CONFIG_CHERRYUSB_HOST_AUDIO)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbh_audio.c)
endif()
if(CONFIG_CHERRYUSB_HOST_BLUETOOTH)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_bluetooth.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_bluetooth.c)
set(BLUETOOTH_PATH ${CMAKE_CURRENT_LIST_DIR}/third_party/zephyr_bluetooth-2.7.5)
set(BLUETOOTH_PATH ${CMAKE_CURRENT_LIST_DIR}/third_party/zephyr_bluetooth-2.7.5)
list(APPEND cherryusb_srcs
${BLUETOOTH_PATH}/ble_hci_usbh.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/beacon/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_hr/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_ht/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/central_multilink.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/handsfree/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/ibeacon/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/cts.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_csc/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_dis/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_esp/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/hog.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hr/src/main.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/main.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/hts.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/peripheral_identity.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ots/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_sc_only/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/scan_adv/src/main.c
)
list(
APPEND
cherryusb_srcs
${BLUETOOTH_PATH}/ble_hci_usbh.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/beacon/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_hr/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_ht/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/central_multilink.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/handsfree/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/ibeacon/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/cts.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_csc/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_dis/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_esp/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/hog.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hr/src/main.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/main.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/hts.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/peripheral_identity.c
# ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ots/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_sc_only/src/main.c
${BLUETOOTH_PATH}/zephyr_bluetooth/examples/scan_adv/src/main.c
)
include(${BLUETOOTH_PATH}/zephyr_bluetooth/zephyr_bluetooth.cmake)
list(APPEND cherryusb_srcs ${zephyr_bluetooth_srcs})
list(APPEND cherryusb_incs ${zephyr_bluetooth_incs})
include(${BLUETOOTH_PATH}/zephyr_bluetooth/zephyr_bluetooth.cmake)
list(APPEND cherryusb_srcs ${zephyr_bluetooth_srcs})
list(APPEND cherryusb_incs ${zephyr_bluetooth_incs})
endif()
if(CONFIG_CHERRYUSB_HOST_ASIX)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_asix.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_asix.c)
endif()
if(CONFIG_CHERRYUSB_HOST_RTL8152)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_rtl8152.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_rtl8152.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CH34X)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ch34x.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CP210X)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_cp210x.c)
endif()
if(CONFIG_CHERRYUSB_HOST_FTDI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ftdi.c)
endif()
if(CONFIG_CHERRYUSB_HOST_PL2303)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_pl2303.c)
endif()
if(CONFIG_CHERRYUSB_HOST_GSM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_gsm.c)
endif()
if(CONFIG_CHERRYUSB_HOST_AOA)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/aoa/usbh_aoa.c)
endif()
if(DEFINED CONFIG_CHERRYUSB_HOST_HCD)
if("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_bouffalo")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
#list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_bouffalo.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_hpm")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
#list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_hpm.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_aic")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
#list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_aic.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_nuvoton")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
#list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_nuvoton.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "dwc2_st")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_st.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "dwc2_esp")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_esp.c)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "musb")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
if(CONFIG_CHERRYUSB_HOST_CDC_ACM
OR CONFIG_CHERRYUSB_HOST_CH34X
OR CONFIG_CHERRYUSB_HOST_CP210X
OR CONFIG_CHERRYUSB_HOST_FTDI
OR CONFIG_CHERRYUSB_HOST_PL2303
OR CONFIG_CHERRYUSB_HOST_GSM
)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_serial.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CDC_ECM
OR CONFIG_CHERRYUSB_HOST_CDC_RNDIS
OR CONFIG_CHERRYUSB_HOST_CDC_NCM
OR CONFIG_CHERRYUSB_HOST_ASIX
OR CONFIG_CHERRYUSB_HOST_RTL8152
)
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "idf")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/idf/usbh_net.c)
else()
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/lwip/usbh_lwip.c)
endif()
endif()
if(CONFIG_CHERRYUSB_HOST_EHCI_BL)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_bouffalo.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_HPM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro/usb_hc_hpm.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro/usb_glue_hpm.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/hpmicro)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_AIC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ohci/usb_hc_ohci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_aic.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ohci)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_MCX)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/nxp/usb_glue_mcx.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/chipidea)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
elseif(CONFIG_CHERRYUSB_HOST_DWC2_ST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_st.c)
elseif(CONFIG_CHERRYUSB_HOST_DWC2_ESP)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_esp.c)
elseif(CONFIG_CHERRYUSB_HOST_DWC2_KENDRYTE)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_kendryte.c)
elseif(CONFIG_CHERRYUSB_HOST_DWC2_HC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_hc.c)
elseif(CONFIG_CHERRYUSB_HOST_DWC2_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
elseif(CONFIG_CHERRYUSB_HOST_MUSB_ES)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_es.c)
elseif(CONFIG_CHERRYUSB_HOST_MUSB_SUNXI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_sunxi.c)
elseif(CONFIG_CHERRYUSB_HOST_MUSB_BK)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_bk.c)
elseif(CONFIG_CHERRYUSB_HOST_MUSB_SIFLI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_sifli.c)
elseif(CONFIG_CHERRYUSB_HOST_MUSB_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_glue_bk.c)
elseif(CONFIG_CHERRYUSB_HOST_KINETIS_MCX)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_hc_kinetis.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_glue_mcx.c)
elseif(CONFIG_CHERRYUSB_HOST_KINETIS_CUSTOM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_hc_kinetis.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/kinetis/usb_glue_mcx.c)
elseif(CONFIG_CHERRYUSB_HOST_RP2040)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/rp2040/usb_hc_rp2040.c)
endif()
if(CONFIG_TEST_USBH_SERIAL OR CONFIG_TEST_USBH_HID OR CONFIG_TEST_USBH_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/demo/usb_host.c)
endif()
endif()
if(CONFIG_CHERRYUSB_DEVICE AND CONFIG_CHERRYUSB_HOST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbotg_core.c)
endif()
if(DEFINED CONFIG_CHERRYUSB_OSAL)
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_freertos.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_freertos.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "rtthread")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_rtthread.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "yoc")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_yoc.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_rtthread.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "idf")
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/osal/idf)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/idf/usb_osal_idf.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "threadx")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_threadx.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "zephyr")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_zephyr.c)
endif()
endif()
endif()
if(CONFIG_CHERRYRB)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherryrb/chry_ringbuffer.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherryrb)
endif()
if(CONFIG_CHERRYMP)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp)
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool_osal_freertos.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "rtthread")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool_osal_rtthread.c)
endif()
endif()

View File

@@ -6,15 +6,15 @@
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
#define CHERRYUSB_VERSION 0x010200
#define CHERRYUSB_VERSION_STR "v1.2.0"
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#ifdef __RTTHREAD__
#include <rtthread.h>
#define usb_malloc(size) malloc(size)
#define usb_free(ptr) free(ptr)
#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
#else
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#endif
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
@@ -23,23 +23,34 @@
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
/* data align size when use dma */
#ifndef CONFIG_USB_ALIGN_SIZE
// #define CONFIG_USB_DCACHE_ENABLE
/* data align size when use dma or use dcache */
#ifdef CONFIG_USB_DCACHE_ENABLE
#define CONFIG_USB_ALIGN_SIZE 32 // 32 or 64
#else
#define CONFIG_USB_ALIGN_SIZE 4
#endif
/* attribute data into no cache ram */
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
/* use usb_memcpy default for high performance but cost more flash memory.
* And, arm libc has a bug that memcpy() may cause data misalignment when the size is not a multiple of 4.
*/
// #define CONFIG_USB_MEMCPY_DISABLE
/* ================= USB Device Stack Configuration ================ */
#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* Ep0 max transfer buffer, specially for receiving data from ep0 out */
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 256
/* Setup packet log for debug */
// #define CONFIG_USBDEV_SETUP_LOG_PRINT
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
*/
// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
/* Check if the input descriptor is correct */
// #define CONFIG_USBDEV_DESC_CHECK
@@ -47,6 +58,20 @@
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
/* enable advance desc register api */
#define CONFIG_USBDEV_ADVANCE_DESC
/* move ep0 setup handler from isr to thread */
// #define CONFIG_USBDEV_EP0_THREAD
#ifndef CONFIG_USBDEV_EP0_PRIO
#define CONFIG_USBDEV_EP0_PRIO 4
#endif
#ifndef CONFIG_USBDEV_EP0_STACKSIZE
#define CONFIG_USBDEV_EP0_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
@@ -67,6 +92,10 @@
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
/* move msc read & write from isr to while(1), you should call usbd_msc_polling in while(1) */
// #define CONFIG_USBDEV_MSC_POLLING
/* move msc read & write from isr to thread */
// #define CONFIG_USBDEV_MSC_THREAD
#ifndef CONFIG_USBDEV_MSC_PRIO
@@ -77,12 +106,35 @@
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_BUFSIZE
#define CONFIG_USBDEV_MTP_MAX_BUFSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_OBJECTS
#define CONFIG_USBDEV_MTP_MAX_OBJECTS 256
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_PATHNAME
#define CONFIG_USBDEV_MTP_MAX_PATHNAME 256
#endif
#define CONFIG_USBDEV_MTP_THREAD
#ifndef CONFIG_USBDEV_MTP_PRIO
#define CONFIG_USBDEV_MTP_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MTP_STACKSIZE
#define CONFIG_USBDEV_MTP_STACKSIZE 4096
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1536
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
@@ -94,18 +146,18 @@
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_BUS 1
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
@@ -123,19 +175,72 @@
//#define CONFIG_USBHOST_GET_STRING_DESC
// #define CONFIG_USBHOST_MSOS_ENABLE
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
/* Ep0 max transfer buffer */
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
#endif
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
#endif
#ifndef CONFIG_USBHOST_SERIAL_RX_SIZE
#define CONFIG_USBHOST_SERIAL_RX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
#endif
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
@@ -148,22 +253,76 @@
/* ================ USB Device Port Configuration ================*/
#ifndef CONFIG_USBDEV_EP_NUM
#define CONFIG_USBDEV_EP_NUM 8
#ifndef CONFIG_USBDEV_MAX_BUS
#define CONFIG_USBDEV_MAX_BUS 1
#endif
// #define CONFIG_USBDEV_SOF_ENABLE
/* ---------------- FSDEV Configuration ---------------- */
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
/* ---------------- DWC2 Configuration ---------------- */
/* enable dwc2 buffer dma mode for device
* in xxx32 chips, only pb14/pb15 can support dma mode, pa11/pa12 is not supported(only a few supports, but we ignore them)
*/
// #define CONFIG_USB_DWC2_DMA_ENABLE
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_EP_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Host Port Configuration ==================*/
#ifndef CONFIG_USBHOST_MAX_BUS
#define CONFIG_USBHOST_MAX_BUS 1
#endif
// #define CONFIG_USBHOST_PIPE_NUM 10
/* ================ EHCI Configuration ================ */
/* ---------------- EHCI Configuration ---------------- */
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
#define CONFIG_USB_EHCI_HCOR_OFFSET (0x10)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
#define CONFIG_USB_EHCI_QH_NUM 10
#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3)
#define CONFIG_USB_EHCI_ITD_NUM 4
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
// #define CONFIG_USB_EHCI_CONFIGFLAG
// #define CONFIG_USB_EHCI_PORT_POWER
// #define CONFIG_USB_EHCI_PRINT_HW_PARAM
// #define CONFIG_USB_EHCI_ISO
// #define CONFIG_USB_EHCI_WITH_OHCI
// #define CONFIG_USB_EHCI_DESC_DCACHE_ENABLE
/* ---------------- OHCI Configuration ---------------- */
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
#define CONFIG_USB_OHCI_ED_NUM 10
#define CONFIG_USB_OHCI_TD_NUM 3
// #define CONFIG_USB_OHCI_DESC_DCACHE_ENABLE
/* ---------------- XHCI Configuration ---------------- */
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- DWC2 Configuration ---------------- */
// nothing to define
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_PIPE_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
// #define CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode,
* the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS.
*
* in xxx32 chips, only pb14/pb15 can support hs mode, pa11/pa12 is not supported(only a few supports, but we ignore them).
*/
// #define CONFIG_USB_HS
#ifndef usb_phyaddr2ramaddr
#define usb_phyaddr2ramaddr(addr) (addr)
#endif
#ifndef usb_ramaddr2phyaddr
#define usb_ramaddr2phyaddr(addr) (addr)
#endif
/* Enable OTG support, only support hpmicro now */
// #define CONFIG_USB_OTG_ENABLE
#endif

310
class/adb/usbd_adb.c Normal file
View File

@@ -0,0 +1,310 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_adb.h"
#define ADB_OUT_EP_IDX 0
#define ADB_IN_EP_IDX 1
#define ADB_STATE_READ_MSG 0
#define ADB_STATE_READ_DATA 1
#define ADB_STATE_WRITE_MSG 2
#define ADB_STATE_WRITE_DATA 3
#define ADB_STATE_AWRITE_MSG 4
#define ADB_STATE_AWRITE_DATA 5
#define MAX_PAYLOAD_V1 (4 * 1024)
#define MAX_PAYLOAD_V2 (256 * 1024)
#define MAX_PAYLOAD MAX_PAYLOAD_V1
#define A_VERSION 0x01000000
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
#define A_OPEN 0x4e45504f
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
#define A_WRTE 0x45545257
#define A_AUTH 0x48545541
struct adb_msg {
uint32_t command; /* command identifier constant (A_CNXN, ...) */
uint32_t arg0; /* first argument */
uint32_t arg1; /* second argument */
uint32_t data_length; /* length of payload (0 is allowed) */
uint32_t data_crc32; /* crc32 of data payload */
uint32_t magic; /* command ^ 0xffffffff */
};
struct adb_packet {
USB_MEM_ALIGNX struct adb_msg msg;
USB_MEM_ALIGNX uint8_t payload[USB_ALIGN_UP(MAX_PAYLOAD, CONFIG_USB_ALIGN_SIZE)];
};
struct usbd_adb {
uint8_t state;
uint8_t common_state;
uint8_t write_state;
bool writable;
uint32_t localid;
uint32_t shell_remoteid;
uint32_t file_remoteid;
} adb_client;
static struct usbd_endpoint adb_ep_data[2];
USB_NOCACHE_RAM_SECTION struct adb_packet tx_packet;
USB_NOCACHE_RAM_SECTION struct adb_packet rx_packet;
static inline uint32_t adb_packet_checksum(struct adb_packet *packet)
{
uint32_t sum = 0;
uint32_t i;
for (i = 0; i < packet->msg.data_length; ++i) {
sum += (uint32_t)(packet->payload[i]);
}
return sum;
}
static uint32_t usbd_adb_get_remoteid(uint32_t localid)
{
if (localid == ADB_SHELL_LOALID) {
return adb_client.shell_remoteid;
} else {
return adb_client.file_remoteid;
}
}
static void adb_send_msg(struct adb_packet *packet)
{
adb_client.common_state = ADB_STATE_WRITE_MSG;
packet->msg.data_crc32 = adb_packet_checksum(packet);
packet->msg.magic = packet->msg.command ^ 0xffffffff;
usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
}
static void adb_send_okay(struct adb_packet *packet, uint32_t localid)
{
packet->msg.command = A_OKAY;
packet->msg.arg0 = localid;
packet->msg.arg1 = usbd_adb_get_remoteid(localid);
packet->msg.data_length = 0;
adb_send_msg(&tx_packet);
}
static void adb_send_close(struct adb_packet *packet, uint32_t localid, uint32_t remoteid)
{
packet->msg.command = A_CLSE;
packet->msg.arg0 = localid;
packet->msg.arg1 = remoteid;
packet->msg.data_length = 0;
adb_send_msg(&tx_packet);
}
void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)ep;
if (adb_client.common_state == ADB_STATE_READ_MSG) {
if (nbytes != sizeof(struct adb_msg)) {
USB_LOG_ERR("invalid adb msg size:%d\r\n", (unsigned int)nbytes);
return;
}
USB_LOG_DBG("command:%x arg0:%x arg1:%x len:%d\r\n",
rx_packet.msg.command,
rx_packet.msg.arg0,
rx_packet.msg.arg1,
rx_packet.msg.data_length);
if (rx_packet.msg.data_length) {
/* setup next out ep read transfer */
adb_client.common_state = ADB_STATE_READ_DATA;
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, rx_packet.payload, rx_packet.msg.data_length);
} else {
if (rx_packet.msg.command == A_CLSE) {
adb_client.writable = false;
usbd_adb_notify_write_done();
USB_LOG_INFO("Close remoteid:%x\r\n", rx_packet.msg.arg0);
}
adb_client.common_state = ADB_STATE_READ_MSG;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
}
} else if (adb_client.common_state == ADB_STATE_READ_DATA) {
switch (rx_packet.msg.command) {
case A_SYNC:
break;
case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
char *support_feature = "device::"
"ro.product.name=cherryadb;"
"ro.product.model=cherrysh;"
"ro.product.device=cherryadb;"
"features=cmd,shell_v1";
tx_packet.msg.command = A_CNXN;
tx_packet.msg.arg0 = A_VERSION;
tx_packet.msg.arg1 = MAX_PAYLOAD;
tx_packet.msg.data_length = strlen(support_feature);
memcpy(tx_packet.payload, support_feature, strlen(support_feature));
adb_send_msg(&tx_packet);
adb_client.writable = false;
break;
case A_OPEN: /* OPEN(local-id, 0, "destination") */
rx_packet.payload[rx_packet.msg.data_length] = '\0';
if (strncmp((const char *)rx_packet.payload, "shell:", 6) == 0) {
adb_client.localid = ADB_SHELL_LOALID;
adb_client.shell_remoteid = rx_packet.msg.arg0;
adb_send_okay(&tx_packet, ADB_SHELL_LOALID);
USB_LOG_INFO("Open shell service, remoteid:%x\r\n", rx_packet.msg.arg0);
} else if (strncmp((const char *)rx_packet.payload, "sync:", 5) == 0) {
adb_client.localid = ADB_FILE_LOALID;
adb_client.file_remoteid = rx_packet.msg.arg0;
adb_send_okay(&tx_packet, ADB_FILE_LOALID);
USB_LOG_INFO("Open file service, remoteid:%x\r\n", rx_packet.msg.arg0);
}
break;
case A_OKAY:
break;
case A_CLSE:
break;
case A_WRTE: /* WRITE(local-id, remote-id, "data") */
if ((rx_packet.msg.arg0 == adb_client.shell_remoteid) && (rx_packet.msg.arg1 == ADB_SHELL_LOALID)) {
adb_send_okay(&tx_packet, rx_packet.msg.arg1);
} else if ((rx_packet.msg.arg0 == adb_client.file_remoteid) && (rx_packet.msg.arg1 == ADB_FILE_LOALID)) {
adb_send_okay(&tx_packet, rx_packet.msg.arg1);
} else {
adb_send_close(&tx_packet, 0, rx_packet.msg.arg0);
}
break;
case A_AUTH:
break;
default:
break;
}
}
}
void usbd_adb_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)ep;
(void)nbytes;
if (adb_client.common_state == ADB_STATE_WRITE_MSG) {
if (tx_packet.msg.data_length) {
adb_client.common_state = ADB_STATE_WRITE_DATA;
usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
} else {
if (rx_packet.msg.command == A_WRTE) {
adb_client.writable = true;
if (adb_client.localid == ADB_SHELL_LOALID) {
usbd_adb_notify_shell_read(rx_packet.payload, rx_packet.msg.data_length);
} else {
}
}
adb_client.common_state = ADB_STATE_READ_MSG;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
}
} else if (adb_client.common_state == ADB_STATE_WRITE_DATA) {
adb_client.common_state = ADB_STATE_READ_MSG;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
} else if (adb_client.write_state == ADB_STATE_AWRITE_MSG) {
if (tx_packet.msg.data_length) {
adb_client.write_state = ADB_STATE_AWRITE_DATA;
usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
} else {
}
} else if (adb_client.write_state == ADB_STATE_AWRITE_DATA) {
usbd_adb_notify_write_done();
}
}
void adb_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
(void)arg;
switch (event) {
case USBD_EVENT_INIT:
break;
case USBD_EVENT_DEINIT:
break;
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONFIGURED:
adb_client.common_state = ADB_STATE_READ_MSG;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
break;
default:
break;
}
}
struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep)
{
(void)busid;
intf->class_interface_handler = NULL;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
intf->notify_handler = adb_notify_handler;
adb_ep_data[ADB_OUT_EP_IDX].ep_addr = out_ep;
adb_ep_data[ADB_OUT_EP_IDX].ep_cb = usbd_adb_bulk_out;
adb_ep_data[ADB_IN_EP_IDX].ep_addr = in_ep;
adb_ep_data[ADB_IN_EP_IDX].ep_cb = usbd_adb_bulk_in;
usbd_add_endpoint(busid, &adb_ep_data[ADB_OUT_EP_IDX]);
usbd_add_endpoint(busid, &adb_ep_data[ADB_IN_EP_IDX]);
return intf;
}
bool usbd_adb_can_write(void)
{
return adb_client.writable;
}
int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len)
{
struct adb_packet *packet;
packet = &tx_packet;
packet->msg.command = A_WRTE;
packet->msg.arg0 = localid;
packet->msg.arg1 = usbd_adb_get_remoteid(localid);
packet->msg.data_length = len;
memcpy(packet->payload, data, len);
packet->msg.data_crc32 = adb_packet_checksum(packet);
packet->msg.magic = packet->msg.command ^ 0xffffffff;
adb_client.write_state = ADB_STATE_AWRITE_MSG;
usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
return 0;
}
void usbd_adb_close(uint32_t localid)
{
adb_send_close(&tx_packet, 0, usbd_adb_get_remoteid(localid));
}

38
class/adb/usbd_adb.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_ADB_H
#define USBD_ADB_H
#include <stdint.h>
#define ADB_SHELL_LOALID 0x01
#define ADB_FILE_LOALID 0x02
// clang-format off
#define ADB_DESCRIPTOR_INIT(bFirstInterface, in_ep, out_ep, wMaxPacketSize) \
USB_INTERFACE_DESCRIPTOR_INIT(bFirstInterface, 0x00, 0x02, 0xff, 0x42, 0x01, 0x02), \
USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x02, wMaxPacketSize, 0x00), \
USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, 0x02, wMaxPacketSize, 0x00)
// clang-format on
#ifdef __cplusplus
extern "C" {
#endif
struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep);
void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len);
void usbd_adb_notify_file_read(uint8_t *data, uint32_t len);
void usbd_adb_notify_write_done(void);
bool usbd_adb_can_write(void);
int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len);
void usbd_adb_close(uint32_t localid);
#ifdef __cplusplus
}
#endif
#endif /* USBD_ADB_H */

48
class/aoa/usb_aoa.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USB_AOA_H
#define USB_AOA_H
//AOA 1.0
#define AOA_ACCESSORY_VENDOR_ID 0x18D1
#define AOA_ACCESSORY_PRODUCT_ID 0x2D00
#define AOA_ACCESSORY_ADB_PRODUCT_ID 0x2D01
//AOA 2.0
#define AOA_AUDIO_PRODUCT_ID 0x2D02
#define AOA_AUDIO_ADB_PRODUCT_ID 0x2D03
#define AOA_ACCESSORY_AUDIO_PRODUCT_ID 0x2D04
#define AOA_ACCESSORY_AUDIO_ADB_PRODUCT_ID 0x2D05
//AOA 1.0
#define AOA_ACCESSORY_GET_PROTOCOL 51
#define AOA_ACCESSORY_SEND_STRING 52
#define AOA_ACCESSORY_START 53
//AOA 2.0
#define AOA_ACCESSORY_REGISTER_HID 54
#define AOA_ACCESSORY_UNREGISTER_HID 55
#define AOA_ACCESSORY_SET_HID_REPORT_DESC 56
#define AOA_ACCESSORY_SEND_HID_EVENT 57
#define AOA_ACCESSORY_SET_AUDIO_MODE 58
#define AOA_ACCESSORY_STRING_MANUFACTURER 0
#define AOA_ACCESSORY_STRING_MODEL 1
#define AOA_ACCESSORY_STRING_DESCRIPTION 2
#define AOA_ACCESSORY_STRING_VERSION 3
#define AOA_ACCESSORY_STRING_URI 4
#define AOA_ACCESSORY_STRING_SERIAL 5
struct aoa_string_info {
char acc_manufacturer[64];
char acc_model[64];
char acc_description[64];
char acc_version[64];
char acc_uri[64];
char acc_serial[64];
};
#endif /* USB_AOA_H */

285
class/aoa/usbh_aoa.c Normal file
View File

@@ -0,0 +1,285 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_aoa.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_aoa"
#include "usb_log.h"
#define DEV_FORMAT "/dev/aoa"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_aoa_buffer[USB_ALIGN_UP(128, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_aoa g_aoa_class;
int usbh_aoa_switch(struct usbh_hubport *hport, struct aoa_string_info *info)
{
struct usb_setup_packet *setup;
int ret;
setup = hport->setup;
if (setup == NULL) {
return -USB_ERR_INVAL;
}
USB_LOG_INFO("Try switch into aoa mode\r\n");
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_GET_PROTOCOL;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 2;
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("AOA version: v%d.%d\r\n", g_aoa_buffer[0], g_aoa_buffer[1]);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_MANUFACTURER;
setup->wLength = strlen(info->acc_manufacturer) + 1;
memcpy(g_aoa_buffer, info->acc_manufacturer, strlen(info->acc_manufacturer));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_MODEL;
setup->wLength = strlen(info->acc_model) + 1;
memcpy(g_aoa_buffer, info->acc_model, strlen(info->acc_model));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_DESCRIPTION;
setup->wLength = strlen(info->acc_description) + 1;
memcpy(g_aoa_buffer, info->acc_description, strlen(info->acc_description));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_VERSION;
setup->wLength = strlen(info->acc_version) + 1;
memcpy(g_aoa_buffer, info->acc_version, strlen(info->acc_version));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_URI;
setup->wLength = strlen(info->acc_uri) + 1;
memcpy(g_aoa_buffer, info->acc_uri, strlen(info->acc_uri));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
setup->wValue = 0;
setup->wIndex = AOA_ACCESSORY_STRING_SERIAL;
setup->wLength = strlen(info->acc_serial) + 1;
memcpy(g_aoa_buffer, info->acc_serial, strlen(info->acc_serial));
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_START;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 0;
ret = usbh_control_transfer(hport, setup, NULL);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Switch into aoa mode success, wait usb device restart...\r\n");
return 0;
}
int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *report, uint32_t report_len)
{
struct usb_setup_packet *setup;
int ret;
uint8_t len;
uint32_t offset;
if (!aoa_class || !aoa_class->hport) {
return -USB_ERR_INVAL;
}
setup = aoa_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_REGISTER_HID;
setup->wValue = id;
setup->wIndex = report_len;
setup->wLength = 0;
ret = usbh_control_transfer(aoa_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
offset = 0;
while (report_len > 0) {
len = report_len > 64 ? 64 : report_len;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SET_HID_REPORT_DESC;
setup->wValue = id;
setup->wIndex = offset;
setup->wLength = len;
memcpy(g_aoa_buffer, report + offset, len);
ret = usbh_control_transfer(aoa_class->hport, setup, g_aoa_buffer);
if (ret < 0) {
return ret;
}
offset += len;
report_len -= len;
}
return ret;
}
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len)
{
struct usb_setup_packet *setup;
if (!aoa_class || !aoa_class->hport) {
return -USB_ERR_INVAL;
}
setup = aoa_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = AOA_ACCESSORY_SEND_HID_EVENT;
setup->wValue = id;
setup->wIndex = 0;
setup->wLength = event_len;
memcpy(g_aoa_buffer, event, event_len);
return usbh_control_transfer(aoa_class->hport, setup, event);
}
static int usbh_aoa_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
struct usbh_aoa *aoa_class = &g_aoa_class;
memset(aoa_class, 0, sizeof(struct usbh_aoa));
aoa_class->hport = hport;
aoa_class->intf = intf;
hport->config.intf[intf].priv = aoa_class;
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(aoa_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(aoa_class->bulkout, ep_desc);
}
}
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register AOA Class:%s\r\n", hport->config.intf[intf].devname);
usbh_aoa_run(aoa_class);
return 0;
}
static int usbh_aoa_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_aoa *aoa_class = (struct usbh_aoa *)hport->config.intf[intf].priv;
if (aoa_class) {
if (aoa_class->bulkin) {
usbh_kill_urb(&aoa_class->bulkin_urb);
}
if (aoa_class->bulkout) {
usbh_kill_urb(&aoa_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister AOA Class:%s\r\n", hport->config.intf[intf].devname);
usbh_aoa_stop(aoa_class);
}
memset(aoa_class, 0, sizeof(struct usbh_aoa));
}
return ret;
}
__WEAK void usbh_aoa_run(struct usbh_aoa *aoa_class)
{
(void)aoa_class;
}
__WEAK void usbh_aoa_stop(struct usbh_aoa *aoa_class)
{
(void)aoa_class;
}
static const uint16_t aoa_id_table[][2] = {
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_PRODUCT_ID },
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_ADB_PRODUCT_ID },
{ AOA_ACCESSORY_VENDOR_ID, AOA_AUDIO_PRODUCT_ID },
{ AOA_ACCESSORY_VENDOR_ID, AOA_AUDIO_ADB_PRODUCT_ID },
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_AUDIO_PRODUCT_ID },
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_AUDIO_ADB_PRODUCT_ID },
{ 0, 0 },
};
const struct usbh_class_driver aoa_class_driver = {
.driver_name = "aoa",
.connect = usbh_aoa_connect,
.disconnect = usbh_aoa_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info aoa_intf_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0x00,
.id_table = aoa_id_table,
.class_driver = &aoa_class_driver
};

40
class/aoa/usbh_aoa.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_AOA_H
#define USBH_AOA_H
#include "usb_aoa.h"
struct usbh_aoa {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
uint8_t intf;
uint8_t minor;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_aoa_switch(struct usbh_hubport *hport, struct aoa_string_info *info);
int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *report, uint32_t report_len);
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len);
void usbh_aoa_run(struct usbh_aoa *aoa_class);
void usbh_aoa_stop(struct usbh_aoa *aoa_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_AOA_H */

View File

@@ -88,18 +88,6 @@
#define AUDIO_ENDPOINT_UNDEFINED 0x00U
#define AUDIO_ENDPOINT_GENERAL 0x01U
/* Feature Unit Control Bits */
#define AUDIO_CONTROL_MUTE 0x0001
#define AUDIO_CONTROL_VOLUME 0x0002
#define AUDIO_CONTROL_BASS 0x0004
#define AUDIO_CONTROL_MID 0x0008
#define AUDIO_CONTROL_TREBLE 0x0010
#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020
#define AUDIO_CONTROL_AUTOMATIC_GAIN 0x0040
#define AUDIO_CONTROL_DEALY 0x0080
#define AUDIO_CONTROL_BASS_BOOST 0x0100
#define AUDIO_CONTROL_LOUDNESS 0x0200
/* Encoder Type Codes */
#define AUDIO_ENCODER_UNDEF 0x00
#define AUDIO_ENCODER_OTHER 0x01
@@ -132,11 +120,11 @@
#define AUDIO_FORMAT_ALAW 0x0004
#define AUDIO_FORMAT_MULAW 0x0005
#define AUDIO_V2_FORMAT_PCM 0x00000001
#define AUDIO_V2_FORMAT_PCM8 0x00000002
#define AUDIO_V2_FORMAT_IEEE_FLOAT 0x00000004
#define AUDIO_V2_FORMAT_ALAW 0x00000008
#define AUDIO_V2_FORMAT_MULAW 0x00000010
#define AUDIO_V2_FORMAT_PCM 0x00000001
#define AUDIO_V2_FORMAT_PCM8 0x00000002
#define AUDIO_V2_FORMAT_IEEE_FLOAT 0x00000004
#define AUDIO_V2_FORMAT_ALAW 0x00000008
#define AUDIO_V2_FORMAT_MULAW 0x00000010
/* bmChannelConfig: a bitmap field that indicates which spatial locations
* are occupied by the channels present in the cluster. The bit allocations
@@ -245,22 +233,34 @@
#define AUDIO_FU_CONTROL_OVERFLOW 0x0f
#define AUDIO_FU_CONTROL_LATENCY 0x10
#define AUDIO_V2_FU_CONTROL_UNDEF 0x00
#define AUDIO_V2_FU_CONTROL_MUTE (0x03 << 0)
#define AUDIO_V2_FU_CONTROL_VOLUME (0x03 << 2)
#define AUDIO_V2_FU_CONTROL_BASS (0x03 << 4)
#define AUDIO_V2_FU_CONTROL_MID (0x03 << 6)
#define AUDIO_V2_FU_CONTROL_TREBLE (0x03 << 8)
#define AUDIO_V2_FU_CONTROL_EQUALIZER (0x03 << 10)
#define AUDIO_V2_FU_CONTROL_AGC (0x03 << 12)
#define AUDIO_V2_FU_CONTROL_DELAY (0x03 << 14)
#define AUDIO_V2_FU_CONTROL_BASS_BOOST (0x03 << 16)
#define AUDIO_V2_FU_CONTROL_LOUDNESS (0x03 << 18)
#define AUDIO_V2_FU_CONTROL_INP_GAIN (0x03 << 20)
#define AUDIO_V2_FU_CONTROL_INP_GAIN_PAD (0x03 << 22)
#define AUDIO_V2_FU_CONTROL_PHASE_INVERT (0x03 << 24)
#define AUDIO_V2_FU_CONTROL_UNDERFLOW (0x03 << 26)
#define AUDIO_V2_FU_CONTROL_OVERFLOW (0x03 << 28)
/* Feature Unit Control Bits */
#define AUDIO_CONTROL_MUTE 0x0001
#define AUDIO_CONTROL_VOLUME 0x0002
#define AUDIO_CONTROL_BASS 0x0004
#define AUDIO_CONTROL_MID 0x0008
#define AUDIO_CONTROL_TREBLE 0x0010
#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020
#define AUDIO_CONTROL_AUTOMATIC_GAIN 0x0040
#define AUDIO_CONTROL_DEALY 0x0080
#define AUDIO_CONTROL_BASS_BOOST 0x0100
#define AUDIO_CONTROL_LOUDNESS 0x0200
#define AUDIO_V2_CONTROL_UNDEF 0x00
#define AUDIO_V2_CONTROL_MUTE (0x03 << 0)
#define AUDIO_V2_CONTROL_VOLUME (0x03 << 2)
#define AUDIO_V2_CONTROL_BASS (0x03 << 4)
#define AUDIO_V2_CONTROL_MID (0x03 << 6)
#define AUDIO_V2_CONTROL_TREBLE (0x03 << 8)
#define AUDIO_V2_CONTROL_EQUALIZER (0x03 << 10)
#define AUDIO_V2_CONTROL_AGC (0x03 << 12)
#define AUDIO_V2_CONTROL_DELAY (0x03 << 14)
#define AUDIO_V2_CONTROL_BASS_BOOST (0x03 << 16)
#define AUDIO_V2_CONTROL_LOUDNESS (0x03 << 18)
#define AUDIO_V2_CONTROL_INP_GAIN (0x03 << 20)
#define AUDIO_V2_CONTROL_INP_GAIN_PAD (0x03 << 22)
#define AUDIO_V2_CONTROL_PHASE_INVERT (0x03 << 24)
#define AUDIO_V2_CONTROL_UNDERFLOW (0x03 << 26)
#define AUDIO_V2_CONTROL_OVERFLOW (0x03 << 28)
/* Parametric Equalizer Section Effect Unit Control Selectors */
#define AUDIO_PE_CONTROL_UNDEF 0x00
@@ -605,7 +605,7 @@ struct audio_cs_if_ac_header_descriptor {
uint8_t baInterfaceNr[];
} __PACKED;
#define AUDIO_SIZEOF_AC_HEADER_DESC(n) (8 + n)
#define AUDIO_SIZEOF_AC_HEADER_DESC(bInCollection) (8 + (bInCollection))
struct audio_cs_if_ac_input_terminal_descriptor {
uint8_t bLength;
@@ -646,7 +646,19 @@ struct audio_cs_if_ac_feature_unit_descriptor {
uint8_t iFeature;
} __PACKED;
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels, bControlSize) (7 + ((bNrChannels) + 1) * (bControlSize))
struct audio_cs_if_ac_selector_unit_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bUnitID;
uint8_t bNrInPins;
uint8_t baSourceID[1];
uint8_t iSelector;
} __PACKED;
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(bNrInPins) (6 + (bNrInPins))
struct audio_cs_if_as_general_descriptor {
uint8_t bLength;
@@ -671,7 +683,7 @@ struct audio_cs_if_as_format_type_descriptor {
uint8_t tSamFreq[3];
} __PACKED;
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(n) (8 + 3 * n)
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(bSamFreqType) (8 + 3 * (bSamFreqType))
struct audio_ep_descriptor {
uint8_t bLength;
@@ -726,7 +738,7 @@ struct audio_cs_ep_ep_general_descriptor {
PP_NARG(__VA_ARGS__), /* bInCollection */ \
__VA_ARGS__ /* baInterfaceNr */
#define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n)
#define AUDIO_AC_DESCRIPTOR_LEN(bInCollection) (0x08 + 0x09 + 0x08 + bInCollection)
#define AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bNrChannels, wChannelConfig) \
0x0C, /* bLength */ \
@@ -810,21 +822,121 @@ struct audio_cs_ep_ep_general_descriptor {
0x00, /* wLockDelay */ \
0x00
#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT(bInterfaceNumber, bNumEndpoints) \
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bSubFrameSize, bBitResolution, bEndpointAddress, wMaxPacketSize, bInterval, bFeedbackEndpointAddress, ...) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
bNumEndpoints, /* bNumEndpoints */ \
0x00, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_MIDISTREAMING, /* bInterfaceSubClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
0x00, /* iInterface */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
0x01, /* bAlternateSetting */ \
0x02, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
0x00, /* iInterface */ \
0x07, /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \
bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \
0x01, /* bDelay */ \
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag : AUDIO_FORMAT_PCM */ \
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \
AUDIO_FORMAT_TYPE_I, /* bFormatType */ \
bNrChannels, /* bNrChannels */ \
bSubFrameSize, /* bSubFrameSize : Bytes per audio subframe */ \
bBitResolution, /* bBitResolution : bits per sample */ \
(PP_NARG(__VA_ARGS__)/3), /* bSamFreqType : only one frequency supported */ \
__VA_ARGS__, /* tSamFreq : Audio sampling frequency coded on 3 bytes */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
bEndpointAddress, /* bEndpointAddress : IN endpoint 1 */ \
0x05, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
bInterval, /* bInterval : one packet per frame */ \
0x00, /* bRefresh */ \
bFeedbackEndpointAddress, /* bSynchAddress */ \
0x07, /* bLength */ \
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \
AUDIO_EP_CONTROL_SAMPLING_FEQ, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \
0x00, /* bLockDelayUnits */ \
0x00, /* wLockDelay */ \
0x00, \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
bFeedbackEndpointAddress, /* bFeedbackEndpointAddress Revise Dir to bEndpointAddress */ \
0x11, /* bmAttributes: TransferType=Isochronous SyncType=None EndpointType=Feedback */ \
WBVAL(4), /* XXXX wMaxPacketSize in Bytes */ \
bInterval, /* bInterval */ \
0x03, /* bRefresh, 8ms */ \
0x00 /* bSynchAddress */
#define AUDIO_AS_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07 + 0x09)
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bTerminalLink, bNrChannels, bSubFrameSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval, ...) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
bAlternateSetting, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
0x00, /* iInterface */ \
0x07, /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \
bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \
0x01, /* bDelay */ \
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag : AUDIO_FORMAT_PCM */ \
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \
AUDIO_FORMAT_TYPE_I, /* bFormatType */ \
bNrChannels, /* bNrChannels */ \
bSubFrameSize, /* bSubFrameSize : Bytes per audio subframe */ \
bBitResolution, /* bBitResolution : bits per sample */ \
(PP_NARG(__VA_ARGS__)/3), /* bSamFreqType : only one frequency supported */ \
__VA_ARGS__, /* tSamFreq : Audio sampling frequency coded on 3 bytes */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
bEndpointAddress, /* bEndpointAddress : IN endpoint 1 */ \
bmAttributes, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
bInterval, /* bInterval : one packet per frame */ \
0x00, /* bRefresh */ \
0x00, /* bSynchAddress */ \
0x07, /* bLength */ \
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \
AUDIO_EP_CONTROL_SAMPLING_FEQ, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \
0x00, /* bLockDelayUnits */ \
0x00, /* wLockDelay */ \
0x00
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
#define AUDIO_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
0x00 /* iInterface */
#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT_LEN 0x09
struct audio_v2_channel_cluster_descriptor {
uint8_t bNrChannels;
uint32_t bmChannelConfig;
@@ -868,7 +980,7 @@ struct audio_v2_cs_if_ac_clock_selector_descriptor {
uint8_t iClockSelector;
} __PACKED;
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(n) (7 + n)
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(bNrInPins) (7 + (bNrInPins))
struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
uint8_t bLength;
@@ -880,7 +992,7 @@ struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
uint8_t iClockMultiplier;
} __PACKED;
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC() (7)
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC (7)
struct audio_v2_cs_if_ac_input_terminal_descriptor {
uint8_t bLength;
@@ -924,7 +1036,7 @@ struct audio_v2_cs_if_ac_feature_unit_descriptor {
uint8_t iFeature;
} __PACKED;
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(ch) (6 + (ch + 1) * 4)
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels) (6 + ((bNrChannels) + 1) * 4)
struct audio_v2_cs_if_as_general_descriptor {
uint8_t bLength;
@@ -999,7 +1111,7 @@ struct audio_v2_control_range3_param_block {
WBVAL(wTotalLength), /* wTotalLength */ \
bmControls /* bmControls */ \
#define AUDIO_V2_AC_DESCRIPTOR_INIT_LEN (0x08 + 0x09 + 0x09)
#define AUDIO_V2_AC_DESCRIPTOR_LEN (0x08 + 0x09 + 0x09)
#define AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(bClockID, bmAttributes, bmControls) \
0x08, /* bLength */ \
@@ -1096,6 +1208,58 @@ struct audio_v2_control_range3_param_block {
0x00, /* wLockDelay */ \
0x00
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bTerminalLink, bNrChannels, bmChannelConfig, bSubslotSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
bAlternateSetting, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOLv20, /* bInterfaceProtocol */ \
0x00, /* iInterface */ \
0x10, /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \
bTerminalLink, /* bTerminalLink : Unit ID of the Output or Input Terminal*/ \
0x00, /* bmControls */ \
AUDIO_FORMAT_TYPE_I, /* bFormatType : AUDIO_FORMAT_TYPE_I */ \
DBVAL(AUDIO_V2_FORMAT_PCM), /* bmFormats PCM */ \
bNrChannels, /* bNrChannels */ \
DBVAL(bmChannelConfig), /* bmChannelConfig */ \
0x00, /* iChannelNames */ \
0x06, /* bLength */ \
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \
AUDIO_FORMAT_TYPE_I, /* bFormatType */ \
bSubslotSize, /* bSubslotSize */ \
bBitResolution, /* bBitResolution */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
bEndpointAddress, /* bEndpointAddress 3 out endpoint for Audio */ \
bmAttributes, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* XXXX wMaxPacketSize in Bytes (SampleRate * SlotByteSize * NumChannels) */ \
bInterval, /* bInterval */ \
0x08, /* bLength */ \
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \
0x00, /* bmAttributes */ \
0x00, /* bmControls */ \
0x00, /* bLockDelayUnits */ \
0x00, /* wLockDelay */ \
0x00
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOLv20, /* bInterfaceProtocol */ \
0x00 /* iInterface */
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bmChannelConfig, bSubslotSize, bBitResolution, bEndpointAddress, wMaxPacketSize, bInterval, bFeedbackEndpointAddress) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
@@ -1150,16 +1314,33 @@ struct audio_v2_control_range3_param_block {
bFeedbackEndpointAddress, /* bFeedbackEndpointAddress Revise Dir to bEndpointAddress */ \
0x11, /* bmAttributes: TransferType=Isochronous SyncType=None EndpointType=Feedback */ \
WBVAL(4), /* XXXX wMaxPacketSize in Bytes */ \
bInterval /* bInterval */ \
bInterval /* bInterval */
// clang-format on
#define AUDIO_V2_AS_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
#define AUDIO_V2_AS_DESCRIPTOR_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_LEN (0x09)
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
#define AUDIO_SAMPLE_FREQ_NUM(num) (uint8_t)(num), (uint8_t)((num >> 8))
#define AUDIO_SAMPLE_FREQ_3B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
#define AUDIO_SAMPLE_FREQ_4B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), \
(uint8_t)((frq >> 16)), (uint8_t)((frq >> 24))
/* format 10.14 */
#define AUDIO_FREQ_TO_FEEDBACK_FS(freq) ((freq << 10) / 1000)
#define AUDIO_FEEDBACK_TO_BUF_FS(buf, feedback) \
buf[0] = ((feedback << 4) & 0xFFU); \
buf[1] = (((feedback << 4) >> 8U) & 0xFFU); \
buf[2] = (((feedback << 4) >> 16U) & 0xFFU)
/* format 16.16 */
#define AUDIO_FREQ_TO_FEEDBACK_HS(freq) ((freq << 13) / 1000)
#define AUDIO_FEEDBACK_TO_BUF_HS(buf, feedback) \
buf[0] = (((feedback & 0x00001FFFu) << 3) & 0xFFu); \
buf[1] = ((((feedback & 0x00001FFFu) << 3) >> 8) & 0xFFu); \
buf[2] = (((feedback & 0x01FFE000u) >> 13) & 0xFFu); \
buf[3] = (((feedback & 0x01FFE000u) >> 21) & 0xFFu)
#endif /* USB_AUDIO_H */

View File

@@ -62,7 +62,7 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
setup->bRequest);
uint8_t entity_id;
uint8_t ep;
uint8_t ep = 0;
uint8_t subtype = 0x01;
uint8_t control_selector;
uint8_t ch;
@@ -136,27 +136,26 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
memcpy(&volume, *data, *len);
if (volume < 0x8000) {
volume_db = volume / 256;
} else if (volume > 0x8000) {
volume_db = (0xffff - volume + 1) / -256;
} else {
volume_db = (volume - 0x10000) / 256;
}
volume_db += 128; /* 0 ~ 255 */
USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%04x\r\n", ep, ch, volume);
USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
usbd_audio_set_volume(busid, ep, ch, volume_db);
break;
case AUDIO_REQUEST_GET_CUR:
volume_db = usbd_audio_get_volume(busid, ep, ch);
volume_db -= 128;
if (volume_db >= 0) {
volume = volume_db * 256;
} else {
volume = volume_db * 256 + 0xffff + 1;
volume = volume_db * 256 + 0x10000;
}
USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
memcpy(*data, &volume, 2);
*len = 2;
break;
case AUDIO_REQUEST_GET_MIN:
(*data)[0] = 0x00; /* -2560/256 dB */
(*data)[1] = 0xdb;
(*data)[0] = 0x00; /* -100 dB */
(*data)[1] = 0x9c;
*len = 2;
break;
case AUDIO_REQUEST_GET_MAX:
@@ -165,7 +164,7 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
*len = 2;
break;
case AUDIO_REQUEST_GET_RES:
(*data)[0] = 0x00; /* -256/256 dB */
(*data)[0] = 0x00; /* 1 dB */
(*data)[1] = 0x01;
*len = 2;
break;
@@ -178,22 +177,31 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
case AUDIO_REQUEST_CUR:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
volume_db = usbd_audio_get_volume(busid, ep, ch);
volume = volume_db;
if (volume_db >= 0) {
volume = volume_db * 256;
} else {
volume = volume_db * 256 + 0x10000;
}
USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
memcpy(*data, &volume, 2);
*len = 2;
} else {
memcpy(&volume, *data, *len);
volume_db = volume;
USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%02x\r\n", ep, ch, volume);
if (volume < 0x8000) {
volume_db = volume / 256;
} else {
volume_db = (volume - 0x10000) / 256;
}
USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
usbd_audio_set_volume(busid, ep, ch, volume_db);
}
break;
case AUDIO_REQUEST_RANGE:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
*((uint16_t *)(*data + 0)) = 1;
*((uint16_t *)(*data + 2)) = 0;
*((uint16_t *)(*data + 4)) = 100;
*((uint16_t *)(*data + 6)) = 1;
*((uint16_t *)(*data + 2)) = 0x9c00; /* MIN -100 dB */
*((uint16_t *)(*data + 4)) = 0x0000; /* MAX 0 dB */
*((uint16_t *)(*data + 6)) = 0x100; /* RES 1 dB */
*len = 8;
} else {
}
@@ -287,7 +295,7 @@ static void audio_notify_handler(uint8_t busid, uint8_t event, void *arg)
}
}
struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
struct usbd_interface *intf,
uint16_t uac_version,
struct audio_entity_info *table,
@@ -312,33 +320,70 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
return intf;
}
__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume)
__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db)
{
(void)busid;
(void)ep;
(void)ch;
(void)volume_db;
}
__WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
{
(void)busid;
(void)ep;
(void)ch;
return 0;
}
__WEAK void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute)
{
(void)busid;
(void)ep;
(void)ch;
(void)mute;
}
__WEAK bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch)
{
(void)busid;
(void)ep;
(void)ch;
return 0;
}
__WEAK void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq)
{
(void)busid;
(void)ep;
(void)sampling_freq;
}
__WEAK uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
{
(void)busid;
(void)ep;
return 0;
}
__WEAK void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table)
{
(void)busid;
(void)ep;
(void)sampling_freq_table;
}
__WEAK void usbd_audio_open(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
}
__WEAK void usbd_audio_close(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
}

View File

@@ -27,7 +27,7 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface
void usbd_audio_open(uint8_t busid, uint8_t intf);
void usbd_audio_close(uint8_t busid, uint8_t intf);
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume);
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch);

View File

@@ -21,22 +21,18 @@
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
#ifndef CONFIG_USBHOST_MAX_AUDIO_CLASS
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 4
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[128];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[USB_ALIGN_UP(128, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_audio *usbh_audio_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
g_audio_class[devno].minor = devno;
return &g_audio_class[devno];
@@ -47,17 +43,17 @@ static struct usbh_audio *usbh_audio_class_alloc(void)
static void usbh_audio_class_free(struct usbh_audio *audio_class)
{
int devno = audio_class->minor;
uint8_t devno = audio_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(audio_class, 0, sizeof(struct usbh_audio));
}
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq)
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution)
{
struct usb_setup_packet *setup = audio_class->hport->setup;
struct usb_setup_packet *setup;
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
@@ -65,24 +61,33 @@ int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t s
uint8_t intf = 0xff;
uint8_t altsetting = 1;
if (!audio_class || !audio_class->hport) {
return -USB_ERR_INVAL;
}
setup = audio_class->hport->setup;
if (audio_class->is_opened) {
return 0;
}
for (uint8_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
if (audio_class->module[i].altsetting[j].sampfreq[k] == samp_freq) {
intf = audio_class->module[i].data_intf;
altsetting = j;
goto freq_found;
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
intf = audio_class->as_msg_table[i].stream_intf;
for (uint8_t j = 1; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
if (audio_class->as_msg_table[i].as_format[j].bBitResolution == bitresolution) {
for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
uint32_t freq = 0;
memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
if (freq == samp_freq) {
altsetting = j;
goto freq_found;
}
}
}
}
}
}
return -USB_ERR_NODEV;
freq_found:
@@ -100,16 +105,18 @@ freq_found:
ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
setup->bRequest = AUDIO_REQUEST_SET_CUR;
setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
setup->wIndex = ep_desc->bEndpointAddress;
setup->wLength = 3;
if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].ep_attr & AUDIO_EP_CONTROL_SAMPLING_FEQ) {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
setup->bRequest = AUDIO_REQUEST_SET_CUR;
setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
setup->wIndex = ep_desc->bEndpointAddress;
setup->wLength = 3;
memcpy(g_audio_buf, &samp_freq, 3);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
memcpy(g_audio_buf, &samp_freq, 3);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
}
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
@@ -122,22 +129,27 @@ freq_found:
USBH_EP_INIT(audio_class->isoout, ep_desc);
}
USB_LOG_INFO("Open audio module :%s, altsetting: %u\r\n", name, altsetting);
USB_LOG_INFO("Open audio stream :%s, altsetting: %u\r\n", name, altsetting);
audio_class->is_opened = true;
return ret;
}
int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
{
struct usb_setup_packet *setup = audio_class->hport->setup;
struct usb_setup_packet *setup;
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint8_t intf = 0xff;
uint8_t altsetting = 1;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->module[i].data_intf;
if (!audio_class || !audio_class->hport) {
return -USB_ERR_INVAL;
}
setup = audio_class->hport->setup;
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
intf = audio_class->as_msg_table[i].stream_intf;
}
}
@@ -145,7 +157,17 @@ int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
return -USB_ERR_NODEV;
}
USB_LOG_INFO("Close audio module :%s\r\n", name);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = intf;
setup->wLength = 0;
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Close audio stream :%s\r\n", name);
audio_class->is_opened = false;
ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
@@ -159,104 +181,195 @@ int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
}
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = intf;
setup->wLength = 0;
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
return ret;
}
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume)
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db)
{
struct usb_setup_packet *setup = audio_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
uint8_t intf = 0xff;
uint8_t feature_id = 0xff;
uint8_t intf;
uint16_t volume_hex;
int volume_min_db;
int volume_max_db;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
if (!audio_class || !audio_class->hport) {
return -USB_ERR_INVAL;
}
if ((volume_db > 127) || (volume_db < -127)) {
return -USB_ERR_INVAL;
}
setup = audio_class->hport->setup;
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
intf = audio_class->as_msg_table[i].stream_intf;
}
}
if (intf == 0xff) {
if (feature_id == 0xff) {
return -USB_ERR_NODEV;
}
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_GET_CUR;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur, g_audio_buf, 2);
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_GET_MIN;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min, g_audio_buf, 2);
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_GET_MAX;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max, g_audio_buf, 2);
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_GET_RES;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_res, g_audio_buf, 2);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_SET_CUR;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
setup->wIndex = (feature_id << 8) | intf;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 2;
volume_hex = -0xDB00 / 100 * volume + 0xdb00;
if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min < 0x8000) {
volume_min_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min / 256;
} else {
volume_min_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min - 0x10000) / 256;
}
if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max < 0x8000) {
volume_max_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max / 256;
} else {
volume_max_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max - 0x10000) / 256;
}
USB_LOG_INFO("Get ch:%u dB range: %ddB ~ %ddB\r\n", ch, volume_min_db, volume_max_db);
if (volume_db >= 0) {
volume_hex = volume_db * 256;
if (volume_hex > audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max) {
return -USB_ERR_RANGE;
}
} else {
volume_hex = volume_db * 256 + 0x10000;
if (volume_hex < audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min) {
return -USB_ERR_RANGE;
}
}
memcpy(g_audio_buf, &volume_hex, 2);
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur = volume_hex;
return ret;
}
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
{
struct usb_setup_packet *setup = audio_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
uint8_t intf = 0xff;
uint8_t feature_id = 0xff;
uint8_t intf = 0xff;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
if (!audio_class || !audio_class->hport) {
return -USB_ERR_INVAL;
}
setup = audio_class->hport->setup;
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
intf = audio_class->as_msg_table[i].stream_intf;
}
}
if (intf == 0xff) {
if (feature_id == 0xff) {
return -USB_ERR_NODEV;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_SET_CUR;
setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
setup->wIndex = (feature_id << 8) | intf;
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
setup->wLength = 1;
memcpy(g_audio_buf, &mute, 1);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].mute = mute;
return ret;
}
void usbh_audio_list_module(struct usbh_audio *audio_class)
{
USB_LOG_INFO("============= Audio module information ===================\r\n");
USB_LOG_INFO("bcdADC :%04x\r\n", audio_class->bcdADC);
USB_LOG_INFO("Num of modules :%u\r\n", audio_class->module_num);
USB_LOG_INFO("Num of altsettings:%u\r\n", audio_class->num_of_intf_altsettings);
USB_LOG_RAW("bcdADC :%04x\r\n", audio_class->bcdADC);
USB_LOG_RAW("Num of audio stream :%u\r\n", audio_class->stream_intf_num);
for (uint8_t i = 0; i < audio_class->module_num; i++) {
USB_LOG_INFO(" module name :%s\r\n", audio_class->module[i].name);
USB_LOG_INFO(" module feature unit id :%d\r\n", audio_class->module[i].feature_unit_id);
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
USB_LOG_RAW("\tstream name :%s\r\n", audio_class->as_msg_table[i].stream_name);
USB_LOG_RAW("\tstream intf :%u\r\n", audio_class->as_msg_table[i].stream_intf);
USB_LOG_RAW("\tNum of altsetting :%u\r\n", audio_class->as_msg_table[i].num_of_altsetting);
for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
for (uint8_t j = 0; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
if (j == 0) {
USB_LOG_INFO(" Ingore altsetting 0\r\n");
USB_LOG_RAW("\t\tIngore altsetting 0\r\n");
continue;
}
USB_LOG_INFO(" Altsetting %u\r\n", j);
USB_LOG_INFO(" module channels :%u\r\n", audio_class->module[i].altsetting[j].channels);
//USB_LOG_INFO(" module format_type :%u\r\n",audio_class->module[i].altsetting[j].format_type);
USB_LOG_INFO(" module bitresolution :%u\r\n", audio_class->module[i].altsetting[j].bitresolution);
USB_LOG_INFO(" module sampfreq num :%u\r\n", audio_class->module[i].altsetting[j].sampfreq_num);
USB_LOG_RAW("\t\tAltsetting :%u\r\n", j);
USB_LOG_RAW("\t\t\tbNrChannels :%u\r\n", audio_class->as_msg_table[i].as_format[j].bNrChannels);
USB_LOG_RAW("\t\t\tbBitResolution :%u\r\n", audio_class->as_msg_table[i].as_format[j].bBitResolution);
USB_LOG_RAW("\t\t\tbSamFreqType :%u\r\n", audio_class->as_msg_table[i].as_format[j].bSamFreqType);
for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
USB_LOG_INFO(" module sampfreq :%d hz\r\n", audio_class->module[i].altsetting[j].sampfreq[k]);
for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
uint32_t freq = 0;
memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
USB_LOG_RAW("\t\t\t\tSampleFreq :%u\r\n", freq);
}
}
}
@@ -267,14 +380,14 @@ void usbh_audio_list_module(struct usbh_audio *audio_class)
static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
{
int ret;
uint8_t cur_iface = 0xff;
uint8_t cur_iface_count = 0xff;
uint8_t cur_alt_setting = 0xff;
uint8_t cur_iface = 0;
uint8_t cur_iface_count = 0;
uint8_t cur_alt_setting = 0;
uint8_t input_offset = 0;
uint8_t output_offset = 0;
uint8_t feature_unit_offset = 0;
uint8_t format_offset = 0;
uint8_t *p;
struct usbh_audio_ac_msg ac_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
struct usbh_audio *audio_class = usbh_audio_class_alloc();
if (audio_class == NULL) {
@@ -284,8 +397,6 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
audio_class->hport = hport;
audio_class->ctrl_intf = intf;
audio_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
hport->config.intf[intf].priv = audio_class;
p = hport->raw_config_desc;
@@ -311,72 +422,49 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
case AUDIO_CONTROL_INPUT_TERMINAL: {
struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
audio_class->module[input_offset].input_terminal_id = desc->bTerminalID;
audio_class->module[input_offset].input_terminal_type = desc->wTerminalType;
audio_class->module[input_offset].input_channel_config = desc->wChannelConfig;
if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
audio_class->module[input_offset].terminal_link_id = desc->bTerminalID;
}
if (desc->wTerminalType == AUDIO_INTERM_MIC) {
audio_class->module[input_offset].name = "mic";
}
memcpy(&ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
input_offset++;
} break;
break;
case AUDIO_CONTROL_OUTPUT_TERMINAL: {
struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
audio_class->module[output_offset].output_terminal_id = desc->bTerminalID;
audio_class->module[output_offset].output_terminal_type = desc->wTerminalType;
if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
audio_class->module[output_offset].terminal_link_id = desc->bTerminalID;
}
if (desc->wTerminalType == AUDIO_OUTTERM_SPEAKER) {
audio_class->module[output_offset].name = "speaker";
}
memcpy(&ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
output_offset++;
} break;
case AUDIO_CONTROL_FEATURE_UNIT: {
struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
audio_class->module[feature_unit_offset].feature_unit_id = desc->bUnitID;
audio_class->module[feature_unit_offset].feature_unit_controlsize = desc->bControlSize;
for (uint8_t j = 0; j < desc->bControlSize; j++) {
audio_class->module[feature_unit_offset].feature_unit_controls[j] = p[6 + j];
}
memcpy(&ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
feature_unit_offset++;
} break;
case AUDIO_CONTROL_PROCESSING_UNIT:
default:
USB_LOG_ERR("Do not support %02x subtype\r\n", p[DESC_bDescriptorSubType]);
return -USB_ERR_NOTSUPP;
}
} else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
switch (p[DESC_bDescriptorSubType]) {
case AUDIO_STREAMING_GENERAL: {
struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p;
break;
/* all altsetting have the same general */
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].stream_intf = cur_iface;
memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_general, desc, sizeof(struct audio_cs_if_as_general_descriptor));
} break;
case AUDIO_STREAMING_FORMAT_TYPE: {
struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].num_of_altsetting = (cur_alt_setting + 1);
memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, desc->bLength);
} break;
default:
break;
}
} else if ((cur_iface < (audio_class->ctrl_intf + cur_iface_count)) && (cur_iface > audio_class->ctrl_intf)) {
switch (p[DESC_bDescriptorSubType]) {
case AUDIO_STREAMING_GENERAL:
break;
case AUDIO_STREAMING_FORMAT_TYPE: {
struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
audio_class->module[format_offset].data_intf = cur_iface;
audio_class->module[format_offset].altsetting[cur_alt_setting].channels = desc->bNrChannels;
audio_class->module[format_offset].altsetting[cur_alt_setting].format_type = desc->bFormatType;
audio_class->module[format_offset].altsetting[cur_alt_setting].bitresolution = desc->bBitResolution;
audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq_num = desc->bSamFreqType;
for (uint8_t j = 0; j < desc->bSamFreqType; j++) {
audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq[j] = (uint32_t)(p[10 + j] << 16) |
(uint32_t)(p[9 + j] << 8) |
(uint32_t)(p[8 + j] << 0);
}
if (cur_alt_setting == (hport->config.intf[intf + 1].altsetting_num - 1)) {
format_offset++;
}
} break;
default:
break;
}
break;
case AUDIO_ENDPOINT_DESCRIPTOR_TYPE:
if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) {
struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p;
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes;
}
}
break;
@@ -387,16 +475,98 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
p += p[DESC_bLength];
}
if ((input_offset != output_offset) && (input_offset != feature_unit_offset) && (input_offset != format_offset)) {
if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
USB_LOG_ERR("Audio control descriptor is invalid\r\n");
return -USB_ERR_INVAL;
}
audio_class->module_num = input_offset;
if (cur_iface_count == 0xff) {
USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n");
return -USB_ERR_INVAL;
}
for (size_t i = 0; i < audio_class->module_num; i++) {
ret = usbh_audio_close(audio_class, audio_class->module[i].name);
audio_class->stream_intf_num = input_offset;
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
/* Search 0x0101 in input or output desc */
for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_input.bTerminalID) {
/* INPUT --> FEATURE UNIT --> OUTPUT */
audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[streamidx].ac_input.bTerminalID;
/* Search input terminal id in feature desc */
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
if (ac_msg_table[streamidx].ac_input.bTerminalID == ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
/* Search feature unit id in output desc */
for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
if (ac_msg_table[featureidx].ac_feature_unit.bUnitID == ac_msg_table[outputid].ac_output.bSourceID) {
audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[outputid].ac_output.bTerminalID;
switch (ac_msg_table[outputid].ac_output.wTerminalType) {
case AUDIO_OUTTERM_SPEAKER:
audio_class->as_msg_table[i].stream_name = "speaker";
break;
case AUDIO_OUTTERM_HEADPHONES:
audio_class->as_msg_table[i].stream_name = "headphoens";
break;
case AUDIO_OUTTERM_HEADDISPLAY:
audio_class->as_msg_table[i].stream_name = "headdisplay";
break;
default:
audio_class->as_msg_table[i].stream_name = "unknown";
break;
}
break;
}
}
break;
}
}
} else if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_output.bTerminalID) {
/* OUTPUT --> FEATURE UNIT --> INPUT */
audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[streamidx].ac_output.bTerminalID;
/* Search output terminal id in feature desc */
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
if (ac_msg_table[streamidx].ac_output.bSourceID == ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
/* Search feature unit id in input desc */
for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
if (ac_msg_table[featureidx].ac_feature_unit.bSourceID == ac_msg_table[inputid].ac_input.bTerminalID) {
audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[inputid].ac_input.bTerminalID;
switch (ac_msg_table[inputid].ac_input.wTerminalType) {
case AUDIO_INTERM_MIC:
audio_class->as_msg_table[i].stream_name = "mic";
break;
default:
audio_class->as_msg_table[i].stream_name = "unknown";
break;
}
break;
}
}
break;
}
}
}
}
}
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
if (audio_class->as_msg_table[i].stream_name == NULL) {
USB_LOG_ERR("Audio stream search fail\r\n");
return -USB_ERR_NODEV;
}
}
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
if (ret < 0) {
USB_LOG_ERR("Fail to close audio module :%s\r\n", audio_class->module[i].name);
USB_LOG_ERR("Fail to close audio stream :%s\r\n", audio_class->as_msg_table[i].stream_name);
return ret;
}
}
@@ -424,6 +594,7 @@ static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
usbh_audio_stop(audio_class);
}
@@ -436,20 +607,26 @@ static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
__WEAK void usbh_audio_run(struct usbh_audio *audio_class)
{
(void)audio_class;
}
__WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
{
(void)audio_class;
}
const struct usbh_class_driver audio_ctrl_class_driver = {
@@ -466,20 +643,18 @@ const struct usbh_class_driver audio_streaming_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
.class = USB_DEVICE_CLASS_AUDIO,
.subclass = AUDIO_SUBCLASS_AUDIOCONTROL,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOCONTROL,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.class_driver = &audio_ctrl_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
.class = USB_DEVICE_CLASS_AUDIO,
.subclass = AUDIO_SUBCLASS_AUDIOSTREAMING,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.class_driver = &audio_streaming_class_driver
};

View File

@@ -8,34 +8,31 @@
#include "usb_audio.h"
struct usbh_audio_format_type {
uint8_t channels;
uint8_t format_type;
uint8_t bitresolution;
uint8_t sampfreq_num;
uint32_t sampfreq[3];
#ifndef CONFIG_USBHOST_AUDIO_MAX_STREAMS
#define CONFIG_USBHOST_AUDIO_MAX_STREAMS 3
#endif
struct usbh_audio_ac_msg {
struct audio_cs_if_ac_input_terminal_descriptor ac_input;
struct audio_cs_if_ac_feature_unit_descriptor ac_feature_unit;
struct audio_cs_if_ac_output_terminal_descriptor ac_output;
};
/**
* bSourceID in feature_unit = input_terminal_id
* bSourceID in output_terminal = feature_unit_id
* terminal_link_id = input_terminal_id or output_terminal_id (if input_terminal_type or output_terminal_type is 0x0101)
*
*
*/
struct usbh_audio_module {
const char *name;
uint8_t data_intf;
struct usbh_audio_as_msg {
const char *stream_name;
uint8_t stream_intf;
uint8_t input_terminal_id;
uint16_t input_terminal_type;
uint16_t input_channel_config;
uint8_t feature_terminal_id;
uint8_t output_terminal_id;
uint16_t output_terminal_type;
uint8_t feature_unit_id;
uint8_t feature_unit_controlsize;
uint8_t feature_unit_controls[8];
uint8_t terminal_link_id;
struct usbh_audio_format_type altsetting[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
uint8_t ep_attr;
uint8_t num_of_altsetting;
uint16_t volume_min;
uint16_t volume_max;
uint16_t volume_res;
uint16_t volume_cur;
bool mute;
struct audio_cs_if_as_general_descriptor as_general;
struct audio_cs_if_as_format_type_descriptor as_format[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
};
struct usbh_audio {
@@ -50,18 +47,19 @@ struct usbh_audio {
bool is_opened;
uint16_t bcdADC;
uint8_t bInCollection;
uint8_t num_of_intf_altsettings;
struct usbh_audio_module module[2];
uint8_t module_num;
uint8_t stream_intf_num;
struct usbh_audio_as_msg as_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq);
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution);
int usbh_audio_close(struct usbh_audio *audio_class, const char *name);
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume);
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db);
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute);
void usbh_audio_run(struct usbh_audio *audio_class);

View File

@@ -217,12 +217,12 @@
#define CDC_SERIAL_STATE_BREAK (1 << 2) /* state of break detection */
#define CDC_SERIAL_STATE_BREAK_Pos (2)
#define CDC_SERIAL_STATE_BREAK_Msk (1 << CDC_SERIAL_STATE_BREAK_Pos)
#define CDC_SERIAL_STATE_TX_CARRIER (1 << 1) /* state of transmission carrier */
#define CDC_SERIAL_STATE_TX_CARRIER_Pos (1)
#define CDC_SERIAL_STATE_TX_CARRIER_Msk (1 << CDC_SERIAL_STATE_TX_CARRIER_Pos)
#define CDC_SERIAL_STATE_RX_CARRIER (1 << 0) /* state of receiver carrier */
#define CDC_SERIAL_STATE_RX_CARRIER_Pos (0)
#define CDC_SERIAL_STATE_RX_CARRIER_Msk (1 << CDC_SERIAL_STATE_RX_CARRIER_Pos)
#define CDC_SERIAL_STATE_DSR (1 << 1) /* state of transmission carrier */
#define CDC_SERIAL_STATE_DSR_Pos (1)
#define CDC_SERIAL_STATE_DSR_Msk (1 << CDC_SERIAL_STATE_DSR_Pos)
#define CDC_SERIAL_STATE_DCD (1 << 0) /* state of receiver carrier */
#define CDC_SERIAL_STATE_DCD_Pos (0)
#define CDC_SERIAL_STATE_DCD_Msk (1 << CDC_SERIAL_STATE_DCD_Pos)
#define CDC_ECM_XMIT_OK (1 << 0)
#define CDC_ECM_RVC_OK (1 << 1)
@@ -421,7 +421,7 @@ struct cdc_ncm_ndp16 {
0x02, /* bInterfaceCount */ \
USB_DEVICE_CLASS_CDC, /* bFunctionClass */ \
CDC_ABSTRACT_CONTROL_MODEL, /* bFunctionSubClass */ \
CDC_COMMON_PROTOCOL_AT_COMMANDS, /* bFunctionProtocol */ \
CDC_COMMON_PROTOCOL_NONE, /* bFunctionProtocol */ \
0x00, /* iFunction */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
@@ -430,7 +430,7 @@ struct cdc_ncm_ndp16 {
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_CDC, /* bInterfaceClass */ \
CDC_ABSTRACT_CONTROL_MODEL, /* bInterfaceSubClass */ \
CDC_COMMON_PROTOCOL_AT_COMMANDS, /* bInterfaceProtocol */ \
CDC_COMMON_PROTOCOL_NONE, /* bInterfaceProtocol */ \
str_idx, /* iInterface */ \
0x05, /* bLength */ \
CDC_CS_INTERFACE, /* bDescriptorType */ \
@@ -489,8 +489,8 @@ struct cdc_ncm_ndp16 {
bFirstInterface, /* bFirstInterface */ \
0x02, /* bInterfaceCount */ \
USB_DEVICE_CLASS_WIRELESS, /* bFunctionClass */ \
CDC_DIRECT_LINE_CONTROL_MODEL, /* bFunctionSubClass */ \
CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101_AND_ANNEXO, /* bFunctionProtocol */ \
0x01, /* bFunctionSubClass */ \
0x03, /* bFunctionProtocol */ \
0x00, /* iFunction */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
@@ -498,8 +498,8 @@ struct cdc_ncm_ndp16 {
0x00, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_WIRELESS, /* bInterfaceClass */ \
CDC_DIRECT_LINE_CONTROL_MODEL, /* bInterfaceSubClass */ \
CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101_AND_ANNEXO, /* bInterfaceProtocol */ \
0x01, /* bInterfaceSubClass */ \
0x03, /* bInterfaceProtocol */ \
str_idx, /* iInterface */ \
0x05, /* bLength */ \
CDC_CS_INTERFACE, /* bDescriptorType */ \
@@ -524,7 +524,7 @@ struct cdc_ncm_ndp16 {
int_ep, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
0x08, 0x00, /* wMaxPacketSize */ \
0x10, /* bInterval */ \
0x05, /* bInterval */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
@@ -551,10 +551,9 @@ struct cdc_ncm_ndp16 {
#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF)
/*Length of template descriptor: 71 bytes*/
#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
// clang-format off
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
/* Interface Associate */ \
0x08, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
@@ -587,16 +586,16 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\
CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\
str_idx, /* Device's MAC string index */\
DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\
WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
int_ep, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
0x10, 0x00, /* wMaxPacketSize */ \
0x10, /* bInterval */ \
0x05, /* bInterval */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
@@ -621,10 +620,9 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
// clang-format on
/*Length of template descriptor: 77 bytes*/
#define CDC_NCM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
#define CDC_NCM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
// clang-format off
#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
/* Interface Associate */ \
0x08, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
@@ -657,10 +655,10 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\
CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\
str_idx, /* Device's MAC string index */\
DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\
WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
0x06, \
CDC_CS_INTERFACE, \
CDC_FUNC_DESC_NCM, \

View File

@@ -1,29 +1,13 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_CDC_H
#define USBD_CDC_H
#include "usb_cdc.h"
// legacy for old version
#ifdef __cplusplus
extern "C" {
#endif
#include "usbd_cdc_acm.h"
/* Init cdc acm interface driver */
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf);
/* Setup request command callback api */
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr);
void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts);
void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf);
#ifdef __cplusplus
}
#endif
#endif /* USBD_CDC_H */
#endif

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_cdc.h"
#include "usbd_cdc_acm.h"
const char *stop_name[] = { "1", "1.5", "2" };
const char *parity_name[] = { "N", "O", "E", "M", "S" };
@@ -42,7 +42,7 @@ static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_set
memcpy(&line_coding, *data, setup->wLength);
USB_LOG_DBG("Set intf:%d linecoding <%d %d %s %s>\r\n",
intf_num,
line_coding.dwDTERate,
(unsigned int)line_coding.dwDTERate,
line_coding.bDataBits,
parity_name[line_coding.bParityType],
stop_name[line_coding.bCharFormat]);
@@ -67,7 +67,7 @@ static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_set
*len = 7;
USB_LOG_DBG("Get intf:%d linecoding %d %d %d %d\r\n",
intf_num,
line_coding.dwDTERate,
(unsigned int)line_coding.dwDTERate,
line_coding.bCharFormat,
line_coding.bParityType,
line_coding.bDataBits);
@@ -85,6 +85,8 @@ static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_set
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf)
{
(void)busid;
intf->class_interface_handler = cdc_acm_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
@@ -95,10 +97,16 @@ struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interfa
__WEAK void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void)busid;
(void)intf;
(void)line_coding;
}
__WEAK void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void)busid;
(void)intf;
line_coding->dwDTERate = 2000000;
line_coding->bDataBits = 8;
line_coding->bParityType = 0;
@@ -107,12 +115,20 @@ __WEAK void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc
__WEAK void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
{
(void)busid;
(void)intf;
(void)dtr;
}
__WEAK void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts)
{
(void)busid;
(void)intf;
(void)rts;
}
__WEAK void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
}

29
class/cdc/usbd_cdc_acm.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_CDC_ACM_H
#define USBD_CDC_ACM_H
#include "usb_cdc.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Init cdc acm interface driver */
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf);
/* Setup request command callback api */
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr);
void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts);
void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf);
#ifdef __cplusplus
}
#endif
#endif /* USBD_CDC_ACM_H */

View File

@@ -7,23 +7,21 @@
#include "usbd_cdc_ecm.h"
#define CDC_ECM_OUT_EP_IDX 0
#define CDC_ECM_IN_EP_IDX 1
#define CDC_ECM_INT_EP_IDX 2
#define CDC_ECM_IN_EP_IDX 1
#define CDC_ECM_INT_EP_IDX 2
/* Ethernet Maximum Segment size, typically 1514 bytes */
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1536U
/* Describe EndPoints configuration */
static struct usbd_endpoint cdc_ecm_ep_data[3];
#ifdef CONFIG_USB_HS
#define CDC_ECM_MAX_PACKET_SIZE 512
#else
#define CDC_ECM_MAX_PACKET_SIZE 64
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[USB_ALIGN_UP(CONFIG_CDC_ECM_ETH_MAX_SEGSZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[USB_ALIGN_UP(CONFIG_CDC_ECM_ETH_MAX_SEGSZE, CONFIG_USB_ALIGN_SIZE)];
#endif
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
volatile uint32_t g_cdc_ecm_rx_data_length = 0;
volatile uint32_t g_cdc_ecm_tx_data_length = 0;
@@ -74,8 +72,10 @@ void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed
break;
}
if (bytes2send) {
usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
if (usb_device_is_configured(0)) {
if (bytes2send) {
usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
}
}
}
@@ -85,21 +85,25 @@ static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_set
"bRequest 0x%02x\r\n",
setup->bRequest);
(void)busid;
(void)data;
(void)len;
g_cmd_intf = LO_BYTE(setup->wIndex);
switch (setup->bRequest) {
case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
/* bit0 Promiscuous
/* bit0 Promiscuous
* bit1 ALL Multicast
* bit2 Directed
* bit3 Broadcast
* bit4 Multicast
*/
if (g_current_net_status == 0) {
g_current_net_status = 1;
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
}
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
g_connect_speed_table[0] = 100000000; /* 100 Mbps */
g_connect_speed_table[1] = 100000000; /* 100 Mbps */
usbd_cdc_ecm_set_connect(true, g_connect_speed_table);
#endif
break;
default:
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
@@ -111,15 +115,19 @@ static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_set
void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
(void)busid;
(void)arg;
switch (event) {
case USBD_EVENT_RESET:
g_current_net_status = 0;
g_cdc_ecm_rx_data_length = 0;
g_cdc_ecm_tx_data_length = 0;
g_cdc_ecm_rx_data_buffer = NULL;
break;
case USBD_EVENT_CONFIGURED:
usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
#endif
break;
default:
@@ -129,36 +137,45 @@ void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
void cdc_ecm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
g_cdc_ecm_rx_data_length += nbytes;
(void)busid;
if (nbytes < CDC_ECM_MAX_PACKET_SIZE) {
g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer;
usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
} else {
usbd_ep_start_read(0, ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
}
g_cdc_ecm_rx_data_length = nbytes;
usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_data_length);
}
void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
if ((nbytes % CDC_ECM_MAX_PACKET_SIZE) == 0 && nbytes) {
(void)busid;
if ((nbytes % usbd_get_ep_mps(0, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(0, ep, NULL, 0);
} else {
usbd_cdc_ecm_data_send_done(g_cdc_ecm_tx_data_length);
g_cdc_ecm_tx_data_length = 0;
}
}
void cdc_ecm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
if (g_current_net_status == 1) {
g_current_net_status = 2;
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table);
(void)busid;
(void)ep;
(void)nbytes;
if (g_current_net_status == 2) {
g_current_net_status = 3;
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE, 0, g_connect_speed_table);
} else {
g_current_net_status = 0;
}
}
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
if (g_cdc_ecm_tx_data_length > 0) {
return -USB_ERR_BUSY;
}
@@ -166,14 +183,17 @@ int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
g_cdc_ecm_tx_data_length = len;
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, g_cdc_ecm_tx_data_length);
return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, len);
}
void usbd_cdc_ecm_start_read_next(void)
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
g_cdc_ecm_rx_data_length = 0;
g_cdc_ecm_rx_data_buffer = NULL;
usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, CDC_ECM_MAX_PACKET_SIZE);
return usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, buf, len);
}
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
@@ -181,19 +201,19 @@ struct pbuf *usbd_cdc_ecm_eth_rx(void)
{
struct pbuf *p;
if (g_cdc_ecm_rx_data_buffer == NULL) {
if (g_cdc_ecm_rx_data_length == 0) {
return NULL;
}
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
if (p == NULL) {
usbd_cdc_ecm_start_read_next();
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
return NULL;
}
memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
usb_memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
p->len = g_cdc_ecm_rx_data_length;
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
usbd_cdc_ecm_start_read_next();
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
return p;
}
@@ -202,6 +222,10 @@ int usbd_cdc_ecm_eth_tx(struct pbuf *p)
struct pbuf *q;
uint8_t *buffer;
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
if (g_cdc_ecm_tx_data_length > 0) {
return -USB_ERR_BUSY;
}
@@ -212,13 +236,11 @@ int usbd_cdc_ecm_eth_tx(struct pbuf *p)
buffer = g_cdc_ecm_tx_buffer;
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
usb_memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
g_cdc_ecm_tx_data_length = p->tot_len;
return usbd_cdc_ecm_start_write(g_cdc_ecm_tx_buffer, g_cdc_ecm_tx_data_length);
return usbd_cdc_ecm_start_write(g_cdc_ecm_tx_buffer, p->tot_len);
}
#endif
@@ -243,11 +265,30 @@ struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const
return intf;
}
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
int usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2])
{
memcpy(g_connect_speed_table, speed, 8);
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
if (connect) {
g_current_net_status = 2;
memcpy(g_connect_speed_table, speed, 8);
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
} else {
g_current_net_status = 1;
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_DISCONNECTED, NULL);
}
return 0;
}
__WEAK void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len)
__WEAK void usbd_cdc_ecm_data_recv_done(uint32_t len)
{
}
(void)len;
}
__WEAK void usbd_cdc_ecm_data_send_done(uint32_t len)
{
(void)len;
}

View File

@@ -12,21 +12,15 @@
extern "C" {
#endif
/* Ethernet Maximum Segment size, typically 1514 bytes */
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
/* Init cdc ecm interface driver */
struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep);
/* Setup request command callback api */
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]);
int usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2]);
/* Api for eth only without any net stack */
uint8_t *usbd_cdc_ecm_get_tx_buffer(void);
void usbd_cdc_ecm_send_done(void);
void usbd_cdc_ecm_data_recv_done(uint32_t len);
void usbd_cdc_ecm_data_send_done(uint32_t len);
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len);
void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len);
void usbd_cdc_ecm_start_read_next(void);
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len);
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
#include "lwip/netif.h"

View File

@@ -1,265 +0,0 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_cdc_acm.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_cdc_acm"
#include "usb_log.h"
#define DEV_FORMAT "/dev/ttyACM%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_acm_buf[64];
static struct usbh_cdc_acm g_cdc_acm_class[CONFIG_USBHOST_MAX_CDC_ACM_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_cdc_acm *usbh_cdc_acm_class_alloc(void)
{
int devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CDC_ACM_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
memset(&g_cdc_acm_class[devno], 0, sizeof(struct usbh_cdc_acm));
g_cdc_acm_class[devno].minor = devno;
return &g_cdc_acm_class[devno];
}
}
return NULL;
}
static void usbh_cdc_acm_class_free(struct usbh_cdc_acm *cdc_acm_class)
{
int devno = cdc_acm_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
}
memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
}
int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 7;
memcpy(g_cdc_acm_buf, line_coding, sizeof(struct cdc_line_coding));
return usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf);
}
int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
int ret;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 7;
ret = usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf);
if (ret < 0) {
return ret;
}
memcpy(line_coding, g_cdc_acm_buf, sizeof(struct cdc_line_coding));
return ret;
}
int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts)
{
struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
setup->wValue = (dtr << 0) | (rts << 1);
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 0;
return usbh_control_transfer(cdc_acm_class->hport, setup, NULL);
}
static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_cdc_acm *cdc_acm_class = usbh_cdc_acm_class_alloc();
if (cdc_acm_class == NULL) {
USB_LOG_ERR("Fail to alloc cdc_acm_class\r\n");
return -USB_ERR_NOMEM;
}
cdc_acm_class->hport = hport;
cdc_acm_class->intf = intf;
hport->config.intf[intf].priv = cdc_acm_class;
hport->config.intf[intf + 1].priv = NULL;
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
USBH_EP_INIT(cdc_acm_class->intin, ep_desc);
#endif
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(cdc_acm_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(cdc_acm_class->bulkout, ep_desc);
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor);
USB_LOG_INFO("Register CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
#if 0
USB_LOG_INFO("Test cdc acm rx and tx and rx for 5 times, baudrate is 115200\r\n");
struct cdc_line_coding linecoding;
uint8_t count = 5;
linecoding.dwDTERate = 115200;
linecoding.bDataBits = 8;
linecoding.bParityType = 0;
linecoding.bCharFormat = 0;
usbh_cdc_acm_set_line_coding(cdc_acm_class, &linecoding);
usbh_cdc_acm_set_line_state(cdc_acm_class, true, false);
memset(g_cdc_acm_buf, 'a', sizeof(g_cdc_acm_buf));
ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff);
USB_LOG_RAW("out ret:%d\r\n", ret);
while (count--) {
ret = usbh_cdc_acm_bulk_in_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff);
USB_LOG_RAW("in ret:%d\r\n", ret);
if (ret > 0) {
for (uint32_t i = 0; i < ret; i++) {
USB_LOG_RAW("%02x ", g_cdc_acm_buf[i]);
}
}
USB_LOG_RAW("\r\n");
}
#endif
usbh_cdc_acm_run(cdc_acm_class);
return ret;
}
static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
if (cdc_acm_class) {
if (cdc_acm_class->bulkin) {
usbh_kill_urb(&cdc_acm_class->bulkin_urb);
}
if (cdc_acm_class->bulkout) {
usbh_kill_urb(&cdc_acm_class->bulkout_urb);
}
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
if (cdc_acm_class->intin) {
usbh_kill_urb(&cdc_acm_class->intin_urb);
}
#endif
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_acm_stop(cdc_acm_class);
}
usbh_cdc_acm_class_free(cdc_acm_class);
}
return ret;
}
int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cdc_acm_class->bulkin_urb;
usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cdc_acm_class->bulkout_urb;
usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;
}
static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;
}
__WEAK void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
}
__WEAK void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
{
}
const struct usbh_class_driver cdc_acm_class_driver = {
.driver_name = "cdc_acm",
.connect = usbh_cdc_acm_connect,
.disconnect = usbh_cdc_acm_disconnect
};
const struct usbh_class_driver cdc_data_class_driver = {
.driver_name = "cdc_data",
.connect = usbh_cdc_data_connect,
.disconnect = usbh_cdc_data_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_CDC,
.subclass = CDC_ABSTRACT_CONTROL_MODEL,
.protocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
.vid = 0x00,
.pid = 0x00,
.class_driver = &cdc_acm_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_CDC_DATA,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.class_driver = &cdc_data_class_driver
};

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CDC_ACM_H
#define USBH_CDC_ACM_H
#include "usb_cdc.h"
struct usbh_cdc_acm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint (optional) */
#endif
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
struct usbh_urb intin_urb;
#endif
struct cdc_line_coding linecoding;
uint8_t intf;
uint8_t minor;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts);
int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class);
void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_CDC_ACM_H */

View File

@@ -21,18 +21,23 @@
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER 0x000C
#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE 1514U
#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER 0x000C
#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE 1514U
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_cdc_ecm g_cdc_ecm_class;
static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value)
{
struct usb_setup_packet *setup = cdc_ecm_class->hport->setup;
struct usb_setup_packet *setup;
if (!cdc_ecm_class || !cdc_ecm_class->hport) {
return -USB_ERR_INVAL;
}
setup = cdc_ecm_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_ETHERNET_PACKET_FILTER;
@@ -116,7 +121,7 @@ get_mac:
}
memset(mac_buffer, 0, 12);
ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer, 12);
if (ret < 0) {
return ret;
}
@@ -139,8 +144,8 @@ get_mac:
cdc_ecm_class->mac[4],
cdc_ecm_class->mac[5]);
if (cdc_ecm_class->max_segment_size > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE) {
USB_LOG_ERR("CDC ECM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE, cdc_ecm_class->max_segment_size);
if (cdc_ecm_class->max_segment_size > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE) {
USB_LOG_ERR("CDC ECM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, cdc_ecm_class->max_segment_size);
} else {
USB_LOG_INFO("CDC ECM Max Segment Size:%u\r\n", cdc_ecm_class->max_segment_size);
}
@@ -176,7 +181,7 @@ get_mac:
}
}
/* bit0 Promiscuous
/* bit0 Promiscuous
* bit1 ALL Multicast
* bit2 Directed
* bit3 Broadcast
@@ -188,7 +193,7 @@ get_mac:
}
USB_LOG_INFO("Set CDC ECM packet filter:%04x\r\n", CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
@@ -216,6 +221,7 @@ static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_ecm_stop(cdc_ecm_class);
}
@@ -226,14 +232,12 @@ static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
void usbh_cdc_ecm_rx_thread(void *argument)
void usbh_cdc_ecm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_cdc_ecm_rx_length;
int ret;
err_t err;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create cdc ecm rx thread\r\n");
// clang-format off
find_class:
@@ -249,36 +253,33 @@ find_class:
usb_osal_msleep(100);
goto find_class;
}
usb_osal_msleep(128);
}
g_cdc_ecm_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize), USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkin, g_cdc_ecm_rx_buffer, CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
if (ret < 0) {
goto find_class;
}
g_cdc_ecm_rx_length += g_cdc_ecm_class.bulkin_urb.actual_length;
g_cdc_ecm_rx_length = g_cdc_ecm_class.bulkin_urb.actual_length;
if (g_cdc_ecm_class.bulkin_urb.actual_length != USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize)) {
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize).
* Short packet is zero, check if g_cdc_ecm_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 512 < 1514.
* This case is always true
*/
if (g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize) ||
(g_cdc_ecm_class.bulkin_urb.actual_length < CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE)) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_length, PBUF_POOL);
if (p != NULL) {
memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
g_cdc_ecm_rx_length = 0;
usbh_cdc_ecm_eth_input(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
} else {
g_cdc_ecm_rx_length = 0;
USB_LOG_ERR("No memory to alloc pbuf for cdc ecm rx\r\n");
}
g_cdc_ecm_rx_length = 0;
} else {
/* read continue util read short packet */
/* There's no way to run here. */
}
}
// clang-format off
@@ -288,38 +289,21 @@ delete:
// clang-format on
}
err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_cdc_ecm_get_eth_txbuf(void)
{
int ret;
struct pbuf *q;
uint8_t *buffer = g_cdc_ecm_tx_buffer;
return g_cdc_ecm_tx_buffer;
}
int usbh_cdc_ecm_eth_output(uint32_t buflen)
{
if (g_cdc_ecm_class.connect_status == false) {
return ERR_BUF;
return -USB_ERR_NOTCONN;
}
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
USB_LOG_DBG("txlen:%d\r\n", buflen);
USB_LOG_DBG("txlen:%d\r\n", p->tot_len);
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
}
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
{
}
__WEAK void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
{
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
return usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
}
const struct usbh_class_driver cdc_ecm_class_driver = {
@@ -330,10 +314,9 @@ const struct usbh_class_driver cdc_ecm_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ecm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_CDC,
.subclass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
.protocol = CDC_COMMON_PROTOCOL_NONE,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
.id_table = NULL,
.class_driver = &cdc_ecm_class_driver
};

View File

@@ -8,9 +8,6 @@
#include "usb_cdc.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct usbh_cdc_ecm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -23,15 +20,13 @@ struct usbh_cdc_ecm {
uint8_t ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
uint8_t minor;
uint8_t mac[6];
bool connect_status;
uint16_t max_segment_size;
uint32_t speed[2];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
void *user_data;
};
#ifdef __cplusplus
@@ -43,8 +38,10 @@ int usbh_cdc_ecm_get_connect_status(struct usbh_cdc_ecm *cdc_ecm_class);
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class);
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class);
err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p);
void usbh_cdc_ecm_rx_thread(void *argument);
uint8_t *usbh_cdc_ecm_get_eth_txbuf(void);
int usbh_cdc_ecm_eth_output(uint32_t buflen);
void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_cdc_ecm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#ifdef __cplusplus
}

View File

@@ -10,32 +10,37 @@
#define USB_DBG_TAG "usbh_cdc_ncm"
#include "usb_log.h"
#define DEV_FORMAT "/dev/cdc_ncm"
#define DEV_FORMAT "/dev/cdc_ncm"
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
/* interface descriptor field offsets */
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE 1514U
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[2048];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[2048];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_inttx_buffer[16];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_buf[32];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_buf[USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_cdc_ncm g_cdc_ncm_class;
static int usbh_cdc_ncm_get_ntb_parameters(struct usbh_cdc_ncm *cdc_ncm_class, struct cdc_ncm_ntb_parameters *param)
{
struct usb_setup_packet *setup = cdc_ncm_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
if (!cdc_ncm_class || !cdc_ncm_class->hport) {
return -USB_ERR_INVAL;
}
setup = cdc_ncm_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_NTB_PARAMETERS;
setup->wValue = 0;
@@ -43,11 +48,11 @@ static int usbh_cdc_ncm_get_ntb_parameters(struct usbh_cdc_ncm *cdc_ncm_class, s
setup->wLength = 28;
ret = usbh_control_transfer(cdc_ncm_class->hport, setup, g_cdc_ncm_buf);
if (ret < 0) {
if (ret < 8) {
return ret;
}
memcpy((uint8_t *)param, g_cdc_ncm_buf, ret - 8);
memcpy((uint8_t *)param, g_cdc_ncm_buf, MIN(ret - 8, sizeof(struct cdc_ncm_ntb_parameters)));
return 0;
}
@@ -57,12 +62,12 @@ static void print_ntb_parameters(struct cdc_ncm_ntb_parameters *param)
USB_LOG_RAW("wLength: 0x%02x \r\n", param->wLength);
USB_LOG_RAW("bmNtbFormatsSupported: %s \r\n", param->bmNtbFormatsSupported ? "NTB16" : "NTB32");
USB_LOG_RAW("dwNtbInMaxSize: 0x%04x \r\n", param->dwNtbInMaxSize);
USB_LOG_RAW("dwNtbInMaxSize: 0x%08x \r\n", (unsigned int)param->dwNtbInMaxSize);
USB_LOG_RAW("wNdbInDivisor: 0x%02x \r\n", param->wNdbInDivisor);
USB_LOG_RAW("wNdbInPayloadRemainder: 0x%02x \r\n", param->wNdbInPayloadRemainder);
USB_LOG_RAW("wNdbInAlignment: 0x%02x \r\n", param->wNdbInAlignment);
USB_LOG_RAW("dwNtbOutMaxSize: 0x%04x \r\n", param->dwNtbOutMaxSize);
USB_LOG_RAW("dwNtbOutMaxSize: 0x%08x \r\n", (unsigned int)param->dwNtbOutMaxSize);
USB_LOG_RAW("wNdbOutDivisor: 0x%02x \r\n", param->wNdbOutDivisor);
USB_LOG_RAW("wNdbOutPayloadRemainder: 0x%02x \r\n", param->wNdbOutPayloadRemainder);
USB_LOG_RAW("wNdbOutAlignment: 0x%02x \r\n", param->wNdbOutAlignment);
@@ -143,7 +148,7 @@ get_mac:
}
memset(mac_buffer, 0, 12);
ret = usbh_get_string_desc(cdc_ncm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
ret = usbh_get_string_desc(cdc_ncm_class->hport, mac_str_idx, (uint8_t *)mac_buffer, 12);
if (ret < 0) {
return ret;
}
@@ -206,7 +211,7 @@ get_mac:
}
}
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register CDC NCM Class:%s\r\n", hport->config.intf[intf].devname);
@@ -234,6 +239,7 @@ static int usbh_cdc_ncm_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister CDC NCM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_ncm_stop(cdc_ncm_class);
}
@@ -244,14 +250,17 @@ static int usbh_cdc_ncm_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
void usbh_cdc_ncm_rx_thread(void *argument)
void usbh_cdc_ncm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_cdc_ncm_rx_length;
int ret;
err_t err;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
#if CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE <= (16 * 1024)
uint32_t transfer_size = CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE;
#else
uint32_t transfer_size = (16 * 1024);
#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create cdc ncm rx thread\r\n");
// clang-format off
find_class:
@@ -271,7 +280,7 @@ find_class:
g_cdc_ncm_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkin_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkin, &g_cdc_ncm_rx_buffer[g_cdc_ncm_rx_length], USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize), USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkin_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkin, &g_cdc_ncm_rx_buffer[g_cdc_ncm_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ncm_class.bulkin_urb);
if (ret < 0) {
goto find_class;
@@ -279,7 +288,12 @@ find_class:
g_cdc_ncm_rx_length += g_cdc_ncm_class.bulkin_urb.actual_length;
if (g_cdc_ncm_class.bulkin_urb.actual_length != USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize)) {
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_cdc_ncm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize).
* Short packet is zero, check if g_cdc_ncm_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
*/
if ((g_cdc_ncm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize)) ||
(g_cdc_ncm_class.bulkin_urb.actual_length < transfer_size)) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ncm_rx_length);
struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_rx_buffer[0];
@@ -306,23 +320,22 @@ find_class:
if (ndp16_datagram->wDatagramIndex && ndp16_datagram->wDatagramLength) {
USB_LOG_DBG("ndp16_datagram index:%02x, length:%02x\r\n", ndp16_datagram->wDatagramIndex, ndp16_datagram->wDatagramLength);
p = pbuf_alloc(PBUF_RAW, ndp16_datagram->wDatagramLength, PBUF_POOL);
if (p != NULL) {
memcpy(p->payload, (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex], ndp16_datagram->wDatagramLength);
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
} else {
USB_LOG_ERR("No memory to alloc pbuf for cdc ncm rx\r\n");
}
uint8_t *buf = (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex];
usbh_cdc_ncm_eth_input(buf, ndp16_datagram->wDatagramLength);
}
}
g_cdc_ncm_rx_length = 0;
} else {
#if CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE <= (16 * 1024)
if (g_cdc_ncm_rx_length == CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
#else
if ((g_cdc_ncm_rx_length + (16 * 1024)) > CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
#endif
USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE\r\n");
while (1) {
}
}
}
}
// clang-format off
@@ -332,24 +345,26 @@ delete:
// clang-format on
}
err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_cdc_ncm_get_eth_txbuf(void)
{
return &g_cdc_ncm_tx_buffer[16];
}
int usbh_cdc_ncm_eth_output(uint32_t buflen)
{
int ret;
struct pbuf *q;
uint8_t *buffer;
struct cdc_ncm_ndp16_datagram *ndp16_datagram;
if (g_cdc_ncm_class.connect_status == false) {
return ERR_BUF;
return -USB_ERR_NOTCONN;
}
struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_tx_buffer[0];
nth16->dwSignature = CDC_NCM_NTH16_SIGNATURE;
nth16->wHeaderLength = 12;
nth16->wSequence = g_cdc_ncm_class.bulkout_sequence++;
nth16->wBlockLength = 16 + 16 + USB_ALIGN_UP(p->tot_len, 4);
nth16->wNdpIndex = 16 + USB_ALIGN_UP(p->tot_len, 4);
nth16->wBlockLength = 16 + 16 + USB_ALIGN_UP(buflen, 4);
nth16->wNdpIndex = 16 + USB_ALIGN_UP(buflen, 4);
struct cdc_ncm_ndp16 *ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex];
@@ -359,36 +374,16 @@ err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 0];
ndp16_datagram->wDatagramIndex = 16;
ndp16_datagram->wDatagramLength = p->tot_len;
ndp16_datagram->wDatagramLength = buflen;
ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 1];
ndp16_datagram->wDatagramIndex = 0;
ndp16_datagram->wDatagramLength = 0;
buffer = &g_cdc_ncm_tx_buffer[16];
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
USB_LOG_DBG("txlen:%d\r\n", nth16->wBlockLength);
usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkout_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkout, g_cdc_ncm_tx_buffer, nth16->wBlockLength, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
}
__WEAK void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
{
}
__WEAK void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
{
return usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
}
const struct usbh_class_driver cdc_ncm_class_driver = {
@@ -399,10 +394,9 @@ const struct usbh_class_driver cdc_ncm_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ncm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_CDC,
.subclass = CDC_NETWORK_CONTROL_MODEL,
.protocol = CDC_COMMON_PROTOCOL_NONE,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_NETWORK_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
.id_table = NULL,
.class_driver = &cdc_ncm_class_driver
};

View File

@@ -8,9 +8,6 @@
#include "usb_cdc.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct usbh_cdc_ncm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -33,9 +30,7 @@ struct usbh_cdc_ncm {
uint16_t max_segment_size;
uint32_t speed[2];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
void *user_data;
};
#ifdef __cplusplus
@@ -47,8 +42,10 @@ int usbh_cdc_ncm_get_connect_status(struct usbh_cdc_ncm *cdc_ncm_class);
void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class);
void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class);
err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p);
void usbh_cdc_ncm_rx_thread(void *argument);
uint8_t *usbh_cdc_ncm_get_eth_txbuf(void);
int usbh_cdc_ncm_eth_output(uint32_t buflen);
void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_cdc_ncm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#ifdef __cplusplus
}

View File

@@ -106,7 +106,6 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
{
struct usb_setup_packet *req = setup;
uint32_t addr;
uint8_t *phaddr;
/* Data setup request */
if (req->wLength > 0U) {
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
@@ -143,7 +142,7 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
/* Return the physical address where data are stored */
phaddr = dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
/* Send the status data over EP0 */
memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);

224
class/gamepad/usb_gamepad.h Normal file
View File

@@ -0,0 +1,224 @@
/*
* Copyright (c) 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USB_GAMEPAD_H
#define USB_GAMEPAD_H
#include "usb_hid.h"
/*
* GAMEPAD BUTTON LAYOUT
*
* ____________________________ __
* / [__L2__] [__R2__] \ |
* / [__ L1 __] [__ R1 __] \ | Triggers
* __/________________________________\__ __|
* / _ \ |
* / /\ __ (B4) \ |
* / || __ |A1| __ _ _ \ | Main Pad
* | <===DP===> |S1| |S2| (B3) -|- (B2)| |
* \ || ¯¯ ¯¯ _ / |
* /\ \/ / \ / \ (B1) /\ __|
* / \________ | LS | ____ | RS | _______/ \ |
* | / \ \___/ / \ \___/ / \ | | Sticks
* | / \_____/ \_____/ \ | __|
* | / L3 R3 \ |
* \_____/ \_____/
*
* |________|______| |______|___________|
* D-Pad Left Right Face
* Stick Stick Buttons
*
* Extended: A2=Touchpad/Capture A3=Mute L4/R4=Paddles
*/
// W3C Gamepad API standard button order
// Bit position = W3C button index (trivial conversion: 1 << index)
//
// Gamepad XInput Switch PS3/4/5 DInput
// ------ ------ ------ ------- ------
// Face buttons (right cluster)
#define USB_GAMEPAD_BUTTON_B1 (1 << 0) // A B Cross 2
#define USB_GAMEPAD_BUTTON_B2 (1 << 1) // B A Circle 3
#define USB_GAMEPAD_BUTTON_B3 (1 << 2) // X Y Square 1
#define USB_GAMEPAD_BUTTON_B4 (1 << 3) // Y X Triangle 4
// Shoulder buttons
#define USB_GAMEPAD_BUTTON_L1 (1 << 4) // LB L L1 5
#define USB_GAMEPAD_BUTTON_R1 (1 << 5) // RB R R1 6
#define USB_GAMEPAD_BUTTON_L2 (1 << 6) // LT ZL L2 7
#define USB_GAMEPAD_BUTTON_R2 (1 << 7) // RT ZR R2 8
// Center cluster
#define USB_GAMEPAD_BUTTON_S1 (1 << 8) // Back - Select 9
#define USB_GAMEPAD_BUTTON_S2 (1 << 9) // Start + Start 10
// Stick clicks
#define USB_GAMEPAD_BUTTON_L3 (1 << 10) // LS LS L3 11
#define USB_GAMEPAD_BUTTON_R3 (1 << 11) // RS RS R3 12
// D-pad
#define USB_GAMEPAD_BUTTON_DU (1 << 12) // D-Up D-Up D-Up Hat
#define USB_GAMEPAD_BUTTON_DD (1 << 13) // D-Down D-Down D-Down Hat
#define USB_GAMEPAD_BUTTON_DL (1 << 14) // D-Left D-Left D-Left Hat
#define USB_GAMEPAD_BUTTON_DR (1 << 15) // D-Right D-Right D-Right Hat
// Auxiliary
#define USB_GAMEPAD_BUTTON_A1 (1 << 16) // Guide Home PS 13
#define USB_GAMEPAD_BUTTON_A2 (1 << 17) // - Capture Touchpad 14
#define USB_GAMEPAD_BUTTON_A3 (1 << 18) // - - Mute -
#define USB_GAMEPAD_BUTTON_A4 (1 << 19) // - - - -
// Paddles (extended)
#define USB_GAMEPAD_BUTTON_L4 (1 << 20) // P1 - - -
#define USB_GAMEPAD_BUTTON_R4 (1 << 21) // P2 - - -
#define XINPUT_VID 0x045E // Microsoft
#define XINPUT_PID 0x028E // Xbox 360 Controller
#define XINPUT_BCD_DEVICE 0x0114 // v1.14
/* XInput (Xbox 360) USB */
// XInput Interface Class/Subclass/Protocol
#define XINPUT_INTERFACE_CLASS 0xFF
#define XINPUT_INTERFACE_SUBCLASS 0x5D
#define XINPUT_INTERFACE_PROTOCOL 0x01
#define XINPUT_BUTTON_MASK_UP (1U << 0)
#define XINPUT_BUTTON_MASK_DOWN (1U << 1)
#define XINPUT_BUTTON_MASK_LEFT (1U << 2)
#define XINPUT_BUTTON_MASK_RIGHT (1U << 3)
#define XINPUT_BUTTON_MASK_START (1U << 4)
#define XINPUT_BUTTON_MASK_BACK (1U << 5)
#define XINPUT_BUTTON_MASK_L3 (1U << 6)
#define XINPUT_BUTTON_MASK_R3 (1U << 7)
#define XINPUT_BUTTON_MASK_LB (1U << 8)
#define XINPUT_BUTTON_MASK_RB (1U << 9)
#define XINPUT_BUTTON_MASK_GUIDE (1U << 10)
//#define XINPUT_BUTTON_MASK_UNUSED (1U << 11)
#define XINPUT_BUTTON_MASK_A (1U << 12)
#define XINPUT_BUTTON_MASK_B (1U << 13)
#define XINPUT_BUTTON_MASK_X (1U << 14)
#define XINPUT_BUTTON_MASK_Y (1U << 15)
// LED patterns for report_id 0x01
#define XINPUT_LED_OFF 0x00
#define XINPUT_LED_BLINK 0x01
#define XINPUT_LED_FLASH_1 0x02
#define XINPUT_LED_FLASH_2 0x03
#define XINPUT_LED_FLASH_3 0x04
#define XINPUT_LED_FLASH_4 0x05
#define XINPUT_LED_ON_1 0x06
#define XINPUT_LED_ON_2 0x07
#define XINPUT_LED_ON_3 0x08
#define XINPUT_LED_ON_4 0x09
#define XINPUT_LED_ROTATE 0x0A
#define XINPUT_LED_BLINK_SLOW 0x0B
#define XINPUT_LED_BLINK_SLOW_1 0x0C
#define XINPUT_LED_BLINK_SLOW_2 0x0D
struct xinput_in_report {
uint8_t report_id; /* Always 0x00 */
uint8_t report_size; /* Always 0x14 (20) */
uint16_t buttons; /* DPAD, Start, Back, L3, R3, LB, RB, Guide, A, B, X, Y */
uint8_t lt; /* Left trigger (0-255) */
uint8_t rt; /* Right trigger (0-255) */
int16_t lx; /* Left stick X (-32768 to 32767) */
int16_t ly; /* Left stick Y (-32768 to 32767) */
int16_t rx; /* Right stick X (-32768 to 32767) */
int16_t ry; /* Right stick Y (-32768 to 32767) */
uint8_t reserved[6]; /* Reserved/padding */
} __PACKED;
struct xinput_out_report {
uint8_t report_id; // 0x00 = rumble, 0x01 = LED
uint8_t report_size; // 0x08
uint8_t led; // LED pattern (0x00 for rumble)
uint8_t rumble_l; // Left motor (large, 0-255)
uint8_t rumble_r; // Right motor (small, 0-255)
uint8_t reserved[3]; // Padding
} __PACKED;
// clang-format off
#define XINPUT_DESCRIPTOR_LEN (9 + 16 + 7 + 7)
#define XINPUT_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep) \
USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, 0x02, 0xff, 0x5d, 0x01, 0x00), /* XInput proprietary descriptor (0x21) */ \
16, 0x21, 0x00, 0x01, 0x01, 0x24, in_ep, 0x14, 0x03, 0x00, 0x03, 0x13, out_ep, 0x00, 0x03, 0x00, \
USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x03, 32, 0x01), \
USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, 0x03, 32, 0x08)
// clang-format on
#define SWITCH_VID 0x0F0D // 0x057E Nintendo Pro Controller
#define SWITCH_PID 0x0092 // 0x2009
#define SWITCH_BCD_DEVICE 0x0100 // v1.00
// Button masks (16-bit)
#define SWITCH_MASK_Y (1U << 0)
#define SWITCH_MASK_B (1U << 1)
#define SWITCH_MASK_A (1U << 2)
#define SWITCH_MASK_X (1U << 3)
#define SWITCH_MASK_L (1U << 4)
#define SWITCH_MASK_R (1U << 5)
#define SWITCH_MASK_ZL (1U << 6)
#define SWITCH_MASK_ZR (1U << 7)
#define SWITCH_MASK_MINUS (1U << 8)
#define SWITCH_MASK_PLUS (1U << 9)
#define SWITCH_MASK_L3 (1U << 10)
#define SWITCH_MASK_R3 (1U << 11)
#define SWITCH_MASK_HOME (1U << 12)
#define SWITCH_MASK_CAPTURE (1U << 13)
// D-pad / Hat switch values
#define SWITCH_HAT_UP 0x00
#define SWITCH_HAT_UP_RIGHT 0x01
#define SWITCH_HAT_RIGHT 0x02
#define SWITCH_HAT_DOWN_RIGHT 0x03
#define SWITCH_HAT_DOWN 0x04
#define SWITCH_HAT_DOWN_LEFT 0x05
#define SWITCH_HAT_LEFT 0x06
#define SWITCH_HAT_UP_LEFT 0x07
#define SWITCH_HAT_CENTER 0x08
// Analog stick range
#define SWITCH_JOYSTICK_MIN 0x00
#define SWITCH_JOYSTICK_MID 0x80
#define SWITCH_JOYSTICK_MAX 0xFF
struct switch_in_report {
uint16_t buttons; // 16 button bits
uint8_t hat; // D-pad (hat switch, 0-8)
uint8_t lx; // Left stick X (0-255, 128 = center)
uint8_t ly; // Left stick Y (0-255, 128 = center)
uint8_t rx; // Right stick X (0-255, 128 = center)
uint8_t ry; // Right stick Y (0-255, 128 = center)
uint8_t vendor; // Vendor-specific byte
} __PACKED;
struct switch_out_report {
uint8_t data[8]; // Vendor-specific rumble data
} __PACKED;
#define HID_SWITCH_REPORT_DESC_SIZE 86
// clang-format off
#define SWITCH_DESCRIPTOR_LEN HID_CUSTOM_INOUT_DESCRIPTOR_LEN
#define SWITCH_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep) \
HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, HID_SWITCH_REPORT_DESC_SIZE, out_ep, in_ep, 64, 0x01)
// clang-format on
struct usb_gamepad_report {
uint32_t buttons;
uint8_t lt;
uint8_t rt;
uint8_t lx;
uint8_t ly;
uint8_t rx;
uint8_t ry;
};
#endif /* USB_GAMEPAD_H */

View File

@@ -0,0 +1,209 @@
/*
* Copyright (c) 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_hid.h"
#include "usbd_gamepad.h"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_report_buffer[64];
static int xinput_vendor_class_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
struct xinput_in_report xinput_report;
memset(&xinput_report, 0, sizeof(xinput_report));
xinput_report.report_size = 20;
memcpy(*data, &xinput_report, sizeof(xinput_report));
*len = sizeof(xinput_report);
return 0;
}
int usbd_gamepad_xinput_send_report(uint8_t ep, struct usb_gamepad_report *report)
{
struct xinput_in_report *xinput_report;
xinput_report = (struct xinput_in_report *)gamepad_report_buffer;
memset(xinput_report, 0, sizeof(xinput_report));
xinput_report->report_size = 20;
if (report->buttons & USB_GAMEPAD_BUTTON_DU)
xinput_report->buttons |= XINPUT_BUTTON_MASK_UP;
if (report->buttons & USB_GAMEPAD_BUTTON_DD)
xinput_report->buttons |= XINPUT_BUTTON_MASK_DOWN;
if (report->buttons & USB_GAMEPAD_BUTTON_DL)
xinput_report->buttons |= XINPUT_BUTTON_MASK_LEFT;
if (report->buttons & USB_GAMEPAD_BUTTON_DR)
xinput_report->buttons |= XINPUT_BUTTON_MASK_RIGHT;
if (report->buttons & USB_GAMEPAD_BUTTON_S2)
xinput_report->buttons |= XINPUT_BUTTON_MASK_START;
if (report->buttons & USB_GAMEPAD_BUTTON_S1)
xinput_report->buttons |= XINPUT_BUTTON_MASK_BACK;
if (report->buttons & USB_GAMEPAD_BUTTON_L3)
xinput_report->buttons |= XINPUT_BUTTON_MASK_L3;
if (report->buttons & USB_GAMEPAD_BUTTON_R3)
xinput_report->buttons |= XINPUT_BUTTON_MASK_R3;
if (report->buttons & USB_GAMEPAD_BUTTON_L1)
xinput_report->buttons |= XINPUT_BUTTON_MASK_LB;
if (report->buttons & USB_GAMEPAD_BUTTON_R1)
xinput_report->buttons |= XINPUT_BUTTON_MASK_RB;
if (report->buttons & USB_GAMEPAD_BUTTON_A1)
xinput_report->buttons |= XINPUT_BUTTON_MASK_GUIDE;
if (report->buttons & USB_GAMEPAD_BUTTON_B1)
xinput_report->buttons |= XINPUT_BUTTON_MASK_A;
if (report->buttons & USB_GAMEPAD_BUTTON_B2)
xinput_report->buttons |= XINPUT_BUTTON_MASK_B;
if (report->buttons & USB_GAMEPAD_BUTTON_B3)
xinput_report->buttons |= XINPUT_BUTTON_MASK_X;
if (report->buttons & USB_GAMEPAD_BUTTON_B4)
xinput_report->buttons |= XINPUT_BUTTON_MASK_Y;
// Analog triggers (0-255), fall back to digital if analog is 0 but button pressed
xinput_report->lt = report->lt;
xinput_report->rt = report->rt;
if (xinput_report->lt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_L2))
xinput_report->lt = 0xFF;
if (xinput_report->rt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_R2))
xinput_report->rt = 0xFF;
return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct xinput_in_report));
}
// Convert gamepad dpad mask to switch hat value
static uint8_t convert_dpad_to_switch_hat(uint32_t buttons)
{
// Joypad uses active-high (1 = pressed)
uint8_t up = (buttons & USB_GAMEPAD_BUTTON_DU) ? 1 : 0;
uint8_t down = (buttons & USB_GAMEPAD_BUTTON_DD) ? 1 : 0;
uint8_t left = (buttons & USB_GAMEPAD_BUTTON_DL) ? 1 : 0;
uint8_t right = (buttons & USB_GAMEPAD_BUTTON_DR) ? 1 : 0;
if (up && right)
return SWITCH_HAT_UP_RIGHT;
if (up && left)
return SWITCH_HAT_UP_LEFT;
if (down && right)
return SWITCH_HAT_DOWN_RIGHT;
if (down && left)
return SWITCH_HAT_DOWN_LEFT;
if (up)
return SWITCH_HAT_UP;
if (down)
return SWITCH_HAT_DOWN;
if (left)
return SWITCH_HAT_LEFT;
if (right)
return SWITCH_HAT_RIGHT;
return SWITCH_HAT_CENTER;
}
int usbd_gamepad_switch_send_report(uint8_t ep, struct usb_gamepad_report *report)
{
struct switch_in_report *switch_report;
switch_report = (struct switch_in_report *)gamepad_report_buffer;
memset(switch_report, 0, sizeof(switch_report));
if (report->buttons & USB_GAMEPAD_BUTTON_S1)
switch_report->buttons |= SWITCH_MASK_MINUS;
if (report->buttons & USB_GAMEPAD_BUTTON_S2)
switch_report->buttons |= SWITCH_MASK_PLUS;
if (report->buttons & USB_GAMEPAD_BUTTON_L1)
switch_report->buttons |= SWITCH_MASK_L;
if (report->buttons & USB_GAMEPAD_BUTTON_R1)
switch_report->buttons |= SWITCH_MASK_R;
if (report->buttons & USB_GAMEPAD_BUTTON_L2)
switch_report->buttons |= SWITCH_MASK_ZL;
if (report->buttons & USB_GAMEPAD_BUTTON_R2)
switch_report->buttons |= SWITCH_MASK_ZR;
if (report->buttons & USB_GAMEPAD_BUTTON_L3)
switch_report->buttons |= SWITCH_MASK_L3;
if (report->buttons & USB_GAMEPAD_BUTTON_R3)
switch_report->buttons |= SWITCH_MASK_R3;
if (report->buttons & USB_GAMEPAD_BUTTON_A1)
switch_report->buttons |= SWITCH_MASK_HOME;
if (report->buttons & USB_GAMEPAD_BUTTON_A2)
switch_report->buttons |= SWITCH_MASK_CAPTURE;
if (report->buttons & USB_GAMEPAD_BUTTON_B1)
switch_report->buttons |= SWITCH_MASK_B;
if (report->buttons & USB_GAMEPAD_BUTTON_B2)
switch_report->buttons |= SWITCH_MASK_A;
if (report->buttons & USB_GAMEPAD_BUTTON_B3)
switch_report->buttons |= SWITCH_MASK_Y;
if (report->buttons & USB_GAMEPAD_BUTTON_B4)
switch_report->buttons |= SWITCH_MASK_X;
switch_report->hat = convert_dpad_to_switch_hat(report->buttons);
// Analog sticks (HID convention: 0=up, 255=down - no inversion needed)
switch_report->lx = report->lx;
switch_report->ly = report->ly;
switch_report->rx = report->rx;
switch_report->ry = report->ry;
switch_report->vendor = 0;
return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct switch_in_report));
}
struct usbd_interface *usbd_gamepad_xinput_init_intf(struct usbd_interface *intf)
{
intf->class_interface_handler = NULL;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = xinput_vendor_class_request_handler;
intf->notify_handler = NULL;
return intf;
}
static const uint8_t hid_switch_report_desc[HID_SWITCH_REPORT_DESC_SIZE] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x10, // Report Count (16)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button 1)
0x29, 0x10, // Usage Maximum (Button 16)
0x81, 0x02, // Input (Data,Var,Abs)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (Eng Rot:Angular Pos)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,Null)
0x65, 0x00, // Unit (None)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const) - 4-bit padding
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X) - Left Stick X
0x09, 0x31, // Usage (Y) - Left Stick Y
0x09, 0x32, // Usage (Z) - Right Stick X
0x09, 0x35, // Usage (Rz) - Right Stick Y
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined)
0x09, 0x20, // Usage (0x20)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs) - Vendor byte
0x0A, 0x21, 0x26, // Usage (0x2621)
0x95, 0x08, // Report Count (8)
0x91, 0x02, // Output (Data,Var,Abs) - Rumble
0xC0, // End Collection
};
struct usbd_interface *usbd_gamepad_switch_init_intf(struct usbd_interface *intf)
{
return usbd_hid_init_intf(0, intf, hid_switch_report_desc, HID_SWITCH_REPORT_DESC_SIZE);
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_GAMEPAD_H
#define USBD_GAMEPAD_H
#include "usb_gamepad.h"
#define USBD_GAMEPAD_MODE_XINPUT 0
#define USBD_GAMEPAD_MODE_SWITCH 1
#define USBD_GAMEPAD_MODE_XBOXONE 2
#define USBD_GAMEPAD_MODE_PS4 3
struct usbd_interface *usbd_gamepad_xinput_init_intf(struct usbd_interface *intf);
struct usbd_interface *usbd_gamepad_switch_init_intf(struct usbd_interface *intf);
int usbd_gamepad_xinput_send_report(uint8_t ep, struct usb_gamepad_report *report);
int usbd_gamepad_switch_send_report(uint8_t ep, struct usb_gamepad_report *report);
#endif /* USBD_GAMEPAD_H */

View File

@@ -35,7 +35,7 @@
#define HID_REPORT_OUTPUT 0x02
#define HID_REPORT_FEATURE 0x03
/* HID Descriptor ***********************************************************/
/* HID Descriptor */
#define HID_COUNTRY_NONE 0x00 /* Not Supported */
#define HID_COUNTRY_ARABIC 0x01 /* Arabic */
@@ -74,109 +74,124 @@
#define HID_COUNTRY_YUGOSLAVIA 0x34 /* Yugoslavia */
#define HID_COUNTRY_TURKISHF 0x35 /* Turkish-F */
/* HID report items */
#define HID_REPORT_ITEM_SIZE_MASK 0x03
#define HID_REPORT_ITEM_SIZE_0 0x00 /* No data follows */
#define HID_REPORT_ITEM_SIZE_1 0x01 /* 1 byte of data follows */
#define HID_REPORT_ITEM_SIZE_2 0x02 /* 2 bytes of data follow */
#define HID_REPORT_ITEM_SIZE_4 0x03 /* 4 bytes of data follow */
#define HID_REPORT_ITEM_TYPE_MASK 0x0c
#define HID_REPORT_ITEM_TYPE_MAIN 0x00
#define HID_REPORT_ITEM_TYPE_GLOBAL 0x04
#define HID_REPORT_ITEM_TYPE_LOCAL 0x08
#define HID_REPORT_ITEM_TAG_MASK 0xf0
/* HID report See specification at
* https://www.usb.org/sites/default/files/hid1_11.pdf
* https://www.usb.org/sites/default/files/hut1_22.pdf
*/
#define HID_SIZE_MASK (0x3 << 0)
#define HID_TYPE_MASK (0x3 << 2)
#define HID_TAG_MASK (0xF << 4)
#define HID_ITEMTYPE_MAIN (0x0 << 2)
#define HID_ITEMTYPE_GLOBAL (0x1 << 2)
#define HID_ITEMTYPE_LOCAL (0x2 << 2)
#define HID_ITEMTYPE_LONG (0x3 << 2)
/* Main Items (HID 6.2.2.4) */
#define HID_MAIN_ITEM_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */
#define HID_MAIN_ITEM_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */
#define HID_MAIN_ITEM_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */
#define HID_MAIN_ITEM_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */
#define HID_MAIN_ITEM_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */
#define HID_MAIN_ITEM_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */
#define HID_MAIN_ITEM_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */
#define HID_MAIN_ITEM_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */
#define HID_MAIN_ITEM_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */
#define HID_MAINITEM_TAG_INPUT (0x08 << 4)
#define HID_MAINITEM_TAG_OUTPUT (0x09 << 4)
#define HID_MAINITEM_TAG_COLLECTION (0x0a << 4)
#define HID_MAINITEM_TAG_FEATURE (0x0b << 4)
#define HID_MAINITEM_TAG_ENDCOLLECTION (0x0c << 4)
#define HID_MAIN_ITEM_SIZE(pfx) ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
#define HID_MAIN_ITEM_INPUT_PREFIX 0x80
#define HID_MAIN_ITEM_INPUT_CONSTANT HID_MAIN_ITEM_CONSTANT
#define HID_MAIN_ITEM_INPUT_VARIABLE HID_MAIN_ITEM_VARIABLE
#define HID_MAIN_ITEM_INPUT_RELATIVE HID_MAIN_ITEM_RELATIVE
#define HID_MAIN_ITEM_INPUT_WRAP HID_MAIN_ITEM_WRAP
#define HID_MAIN_ITEM_INPUT_NONLINEAR HID_MAIN_ITEM_NONLINEAR
#define HID_MAIN_ITEM_INPUT_NOPREFERRED HID_MAIN_ITEM_NOPREFERRED
#define HID_MAIN_ITEM_INPUT_NULLSTATE HID_MAIN_ITEM_NULLSTATE
#define HID_MAIN_ITEM_INPUT_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
#define HID_MAINITEM_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */
#define HID_MAINITEM_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */
#define HID_MAINITEM_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */
#define HID_MAINITEM_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */
#define HID_MAINITEM_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */
#define HID_MAINITEM_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */
#define HID_MAINITEM_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */
#define HID_MAINITEM_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */
#define HID_MAINITEM_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */
#define HID_MAIN_ITEM_OUTPUT_PREFIX 0x90
#define HID_MAIN_ITEM_OUTPUT_CONSTANT HID_MAIN_ITEM_CONSTANT
#define HID_MAIN_ITEM_OUTPUT_VARIABLE HID_MAIN_ITEM_VARIABLE
#define HID_MAIN_ITEM_OUTPUT_RELATIVE HID_MAIN_ITEM_RELATIVE
#define HID_MAIN_ITEM_OUTPUT_WRAP HID_MAIN_ITEM_WRAP
#define HID_MAIN_ITEM_OUTPUT_NONLINEAR HID_MAIN_ITEM_NONLINEAR
#define HID_MAIN_ITEM_OUTPUT_NOPREFERRED HID_MAIN_ITEM_NOPREFERRED
#define HID_MAIN_ITEM_OUTPUT_NULLSTATE HID_MAIN_ITEM_NULLSTATE
#define HID_MAIN_ITEM_OUTPUT_VOLATILE HID_MAIN_ITEM_VOLATILE
#define HID_MAIN_ITEM_OUTPUT_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
#define HID_MAIN_ITEM_FEATURE_PREFIX 0xb0
#define HID_MAIN_ITEM_FEATURE_CONSTANT HID_MAIN_ITEM_CONSTANT
#define HID_MAIN_ITEM_FEATURE_VARIABLE HID_MAIN_ITEM_VARIABLE
#define HID_MAIN_ITEM_FEATURE_RELATIVE HID_MAIN_ITEM_RELATIVE
#define HID_MAIN_ITEM_FEATURE_WRAP HID_MAIN_ITEM_WRAP
#define HID_MAIN_ITEM_FEATURE_NONLINEAR HID_MAIN_ITEM_NONLINEAR
#define HID_MAIN_ITEM_FEATURE_NOPREFERRED HID_MAIN_ITEM_NOPREFERRED
#define HID_MAIN_ITEM_FEATURE_NULLSTATE HID_MAIN_ITEM_NULLSTATE
#define HID_MAIN_ITEM_FEATURE_VOLATILE HID_MAIN_ITEM_VOLATILE
#define HID_MAIN_ITEM_FEATURE_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
#define HID_MAIN_ITEM_COLLECTION_PREFIX 0xa0
#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0x00 /* Physical (group of axes) */
#define HID_MAIN_ITEM_COLLECTION_APPL 0x01 /* Application (mouse, keyboard) */
#define HID_MAIN_ITEM_COLLECTION_LOGICAL 0x02 /* Logical (interrelated data) */
#define HID_MAIN_ITEM_COLLECTION_REPORT 0x03 /* Report */
#define HID_MAIN_ITEM_COLLECTION_ARRAY 0x04 /* Named Array */
#define HID_MAIN_ITEM_COLLECTION_SWITCH 0x05 /* Usage Switch */
#define HID_MAIN_ITEM_COLLECTION_MODIFIER 0x06 /* Usage Modifier */
#define HID_MAIN_ITEM_ENDCOLLECTION_PREFIX 0xc0
#define HID_MAINITEM_COLLECTION_PHYSICAL 0x00 /* Physical (group of axes) */
#define HID_MAINITEM_COLLECTION_APPL 0x01 /* Application (mouse, keyboard) */
#define HID_MAINITEM_COLLECTION_LOGICAL 0x02 /* Logical (interrelated data) */
#define HID_MAINITEM_COLLECTION_REPORT 0x03 /* Report */
#define HID_MAINITEM_COLLECTION_ARRAY 0x04 /* Named Array */
#define HID_MAINITEM_COLLECTION_SWITCH 0x05 /* Usage Switch */
#define HID_MAINITEM_COLLECTION_MODIFIER 0x06 /* Usage Modifier */
/* Global Items (HID 6.2.2.7) */
#define HID_GLOBAL_ITEM_SIZE(pfx) ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
#define HID_GLOBAL_ITEM_USAGEPAGE_PREFIX 0x04 /* Usage Page */
#define HID_GLOBAL_ITEM_LOGICALMIN_PREFIX 0x14 /* Logical Minimum */
#define HID_GLOBAL_ITEM_LOGICALMAX_PREFIX 0x24 /* Logical Maximum */
#define HID_GLOBAL_ITEM_PHYSICALMIN_PREFIX 0x34 /* Physical Minimum */
#define HID_GLOBAL_ITEM_PHYSMICALAX_PREFIX 0x44 /* Physical Maximum */
#define HID_GLOBAL_ITEM_UNITEXP_PREFIX 0x54 /* Unit Exponent */
#define HID_GLOBAL_ITEM_UNIT_PREFIX 0x64 /* Unit */
#define HID_GLOBAL_ITEM_REPORTSIZE_PREFIX 0x74 /* Report Size */
#define HID_GLOBAL_ITEM_REPORTID_PREFIX 0x84 /* Report ID */
#define HID_GLOBAL_ITEM_REPORTCOUNT_PREFIX 0x94 /* Report Count */
#define HID_GLOBAL_ITEM_PUSH_PREFIX 0xa4 /* Push */
#define HID_GLOBAL_ITEM_POP_PREFIX 0xb4 /* Pop */
#define HID_GLOBALITEM_TAG_USAGE_PAGE (0x00 << 4)
#define HID_GLOBALITEM_TAG_LOGICAL_MIN (0x01 << 4)
#define HID_GLOBALITEM_TAG_LOGICAL_MAX (0x02 << 4)
#define HID_GLOBALITEM_TAG_PHYSICAL_MIN (0x03 << 4)
#define HID_GLOBALITEM_TAG_PHYSICAL_MAX (0x04 << 4)
#define HID_GLOBALITEM_TAG_UNIT_EXP (0x05 << 4)
#define HID_GLOBALITEM_TAG_UNIT (0x06 << 4)
#define HID_GLOBALITEM_TAG_REPORT_SIZE (0x07 << 4)
#define HID_GLOBALITEM_TAG_REPORT_ID (0x08 << 4)
#define HID_GLOBALITEM_TAG_REPORT_COUNT (0x09 << 4)
#define HID_GLOBALITEM_TAG_PUSH (0x0a << 4)
#define HID_GLOBALITEM_TAG_POP (0x0b << 4)
/* Local Items (HID 6.2.2.8) */
#define HID_LOCAL_ITEM_SIZE(pfx) ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
#define HID_LOCAL_ITEM_USAGE_PREFIX 0x08 /* Usage */
#define HID_LOCAL_ITEM_USAGEMIN_PREFIX 0x18 /* Usage Minimum */
#define HID_LOCAL_ITEM_USAGEMAX_PREFIX 0x28 /* Usage Maximum */
#define HID_LOCAL_ITEM_DESIGNATORIDX_PREFIX 0x38 /* Designator Index */
#define HID_LOCAL_ITEM_DESIGNATORMIN_PREFIX 0x48 /* Designator Minimum */
#define HID_LOCAL_ITEM_DESIGNATORMAX_PREFIX 0x58 /* Designator Maximum */
#define HID_LOCAL_ITEM_STRINGIDX_PREFIX 0x78 /* String Index */
#define HID_LOCAL_ITEM_STRINGMIN_PREFIX 0x88 /* String Minimum */
#define HID_LOCAL_ITEM_STRINGMAX_PREFIX 0x98 /* xx */
#define HID_LOCAL_ITEM_DELIMITER_PREFIX 0xa8 /* Delimiter */
#define HID_LOCALITEM_TAG_USAGE (0x00 << 4)
#define HID_LOCALITEM_TAG_USAGE_MIN (0x01 << 4)
#define HID_LOCALITEM_TAG_USAGE_MAX (0x02 << 4)
#define HID_LOCALITEM_TAG_DESIG_INDEX (0x03 << 4)
#define HID_LOCALITEM_TAG_DESIG_MIN (0x04 << 4)
#define HID_LOCALITEM_TAG_DESIG_MAX (0x05 << 4)
/* No 6 in spec */
#define HID_LOCALITEM_TAG_STRING_INDEX (0x07 << 4)
#define HID_LOCALITEM_TAG_STRING_MIN (0x08 << 4)
#define HID_LOCALITEM_TAG_STRING_MAX (0x09 << 4)
#define HID_LOCALITEM_TAG_DELIMITER (0x0a << 4) /* Also listed as reserved in spec! */
/* Usage pages (HuT 3) */
#define HID_USAGE_PAGE_UNDEFINED 0x00 /* Undefined */
#define HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS 0x01 /* Generic Desktop Controls */
#define HID_USAGE_PAGE_SIMULATION_CONTROLS 0x02 /* Simulation Controls */
#define HID_USAGE_PAGE_VR_CONTROLS 0x03 /* VR Controls */
#define HID_USAGE_PAGE_SPORT_CONTROLS 0x04 /* Sport Controls */
#define HID_USAGE_PAGE_GAME_CONTROLS 0x05 /* Game Controls */
#define HID_USAGE_PAGE_GENERIC_DEVICE_CONTROLS 0x06 /* Generic Device Controls */
#define HID_USAGE_PAGE_KEYBOARD_KEYPAD 0x07 /* Keyboard/Keypad */
#define HID_USAGE_PAGE_LED 0x08 /* LEDs */
#define HID_USAGE_PAGE_BUTTON 0x09 /* Button */
#define HID_USAGE_PAGE_ORDINAL 0x0a /* Ordinal */
#define HID_USAGE_PAGE_TELEPHONY 0x0b /* Telephony */
#define HID_USAGE_PAGE_CONSUMER 0x0c /* Consumer */
#define HID_USAGE_PAGE_DIGITIZER 0x0d /* Digitizer */
#define HID_USAGE_PAGE_HAPTICS /* 0x0e Reserved */
#define HID_USAGE_PAGE_PID 0x0f /* PID Page Physical Interface Device */
#define HID_USAGE_PAGE_UNICODE 0x10 /* Unicode */
#define HID_USAGE_PAGE_SOC 0x11 /* Sensor Orientation Category */
#define HID_USAGE_PAGE_EYE_AND_HEAD_TRACKER 0x12 /* Eye and Head Tracker */
/* 0x13 Reserved */
#define HID_USAGE_PAGE_ALPHA_DISPLAY 0x14 /* Alphanumeric Display */
/* 0x15-3f Reserved */
#define HID_USAGE_PAGE_MEDICAL 0x40 /* Medical Instruments */
#define HID_USAGE_PAGE_BRAILLE_DISPLAY 0x41 /* Braille Display */
/* 0x42-0x58 Reserved */
#define HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION 0x59 /* Lighting and Illumination */
/* 0x5a-0x7f Reserved */
#define HID_USAGE_PAGE_USB_MONITOR 0x80 /* USB Monitor */
#define HID_USAGE_PAGE_USB_ENUMERATED_VALUES 0x81 /* USB Enumerated Values */
#define HID_USAGE_PAGE_VESA_VIRTUAL_CONTROLS 0x82 /* VESA Virtual Controls */
#define HID_USAGE_PAGE_POWER_DEVICE 0x84 /* Power Device */
#define HID_USAGE_PAGE_BATTERY_SYSTEM 0x85 /* Battery System */
#define HID_USAGE_PAGE_BARCODE_SCANNER 0x8c /* Bar Code Scanner page */
#define HID_USAGE_PAGE_SCALE 0x8d /* Scale page */
#define HID_USAGE_PAGE_MSR 0x8e /* Magnetic Stripe Reading (MSR) Devices */
#define HID_USAGE_PAGE_POS 0x8f /* Point of Sale devices */
#define HID_USAGE_PAGE_CAMERA_CONTROL 0x90 /* Camera Control Page */
#define HID_USAGE_PAGE_ARCADE 0x91
#define HID_USAGE_PAGE_GAMING_DEVICE 0x92
#define HID_USAGE_PAGE_FIDO_ALLIANCE 0xF1D0
#define HID_USAGE_PAGE_VENDOR_PAGE_HBYTE 0xFF00
/* Modifier Keys (HID 8.3) */
#define HID_MODIFER_LCTRL (1 << 0) /* Left Ctrl */
#define HID_MODIFER_LSHIFT (1 << 1) /* Left Shift */
#define HID_MODIFER_LALT (1 << 2) /* Left Alt */
#define HID_MODIFER_LGUI (1 << 3) /* Left GUI */
#define HID_MODIFER_RCTRL (1 << 4) /* Right Ctrl */
#define HID_MODIFER_RSHIFT (1 << 5) /* Right Shift */
#define HID_MODIFER_RALT (1 << 6) /* Right Alt */
#define HID_MODIFER_RGUI (1 << 7) /* Right GUI */
#define HID_MODIFIER_LCTRL (1 << 0) /* Left Ctrl */
#define HID_MODIFIER_LSHIFT (1 << 1) /* Left Shift */
#define HID_MODIFIER_LALT (1 << 2) /* Left Alt */
#define HID_MODIFIER_LGUI (1 << 3) /* Left GUI */
#define HID_MODIFIER_RCTRL (1 << 4) /* Right Ctrl */
#define HID_MODIFIER_RSHIFT (1 << 5) /* Right Shift */
#define HID_MODIFIER_RALT (1 << 6) /* Right Alt */
#define HID_MODIFIER_RGUI (1 << 7) /* Right GUI */
/* Keyboard output report (1 byte) (HID B.1) */
#define HID_KBD_OUTPUT_REPORT_NUMLOCK (1 << 0)
@@ -191,11 +206,11 @@
#define HID_MOUSE_INPUT_REPORT_BUTTON3 (1 << 2)
#define HID_MOUSE_INPUT_REPORT_BUTTON_MASK (7)
#define HID_MOUSE_INPUT_BUTTON_LEFT (1 << 0)
#define HID_MOUSE_INPUT_BUTTON_RIGHT (1 << 1)
#define HID_MOUSE_INPUT_BUTTON_MIDDLE (1 << 2)
#define HID_MOUSE_INPUT_BUTTON_BACKWARD (1 << 3)
#define HID_MOUSE_INPUT_BUTTON_FORWARD (1 << 4)
#define HID_MOUSE_INPUT_BUTTON_LEFT (1 << 0)
#define HID_MOUSE_INPUT_BUTTON_RIGHT (1 << 1)
#define HID_MOUSE_INPUT_BUTTON_MIDDLE (1 << 2)
#define HID_MOUSE_INPUT_BUTTON_BACKWARD (1 << 3)
#define HID_MOUSE_INPUT_BUTTON_FORWARD (1 << 4)
/* Joystick input report (4 bytes) (HID D.1) */
#define HID_JS_INPUT_REPORT_HATSWITCH_SHIFT (0)
@@ -205,50 +220,18 @@
#define HID_JS_INPUT_REPORT_BUTTON3 (1 << 6)
#define HID_JS_INPUT_REPORT_BUTTON4 (1 << 7)
/* Usage pages (HuT 3) */
#define HID_USAGE_PAGE_UNDEFINED 0x00 /* Undefined */
#define HID_USAGE_PAGE_GENERIC_DCTRL 0x01 /* Generic Desktop Controls */
#define HID_USAGE_PAGE_SIMCTRL 0x02 /* Simulation Controls */
#define HID_USAGE_PAGE_VRCTRL 0x03 /* VR Controls */
#define HID_USAGE_PAGE_SPORTCTRL 0x04 /* Sport Controls */
#define HID_USAGE_PAGE_GAMECTRL 0x05 /* Game Controls */
#define HID_USAGE_PAGE_GENERIC_DEVCTRL 0x06 /* Generic Device Controls */
#define HID_USAGE_PAGE_KBD 0x07 /* Keyboard/Keypad */
#define HID_USAGE_PAGE_LEDS 0x08 /* LEDs */
#define HID_USAGE_PAGE_BUTTON 0x09 /* Button */
#define HID_USAGE_PAGE_ORDINAL 0x0a /* Ordinal */
#define HID_USAGE_PAGE_TELEPHONY 0x0b /* Telephony */
#define HID_USAGE_PAGE_CONSUMER 0x0c /* Consumer */
#define HID_USAGE_PAGE_DIGITIZER 0x0d /* Digitizer */
/* 0x0e Reserved */
#define HID_USAGE_PAGE_PIDPAGE 0x0f /* PID Page Physical Interface Device */
#define HID_USAGE_PAGE_UNICODE 0x10 /* Unicode */
/* 0x11-13 Reserved */
#define HID_USAGE_PAGE_ALPHA_DISPLAY 0x14 /* Alphanumeric Display */
/* 0x15-3f Reserved */
#define HID_USAGE_PAGE_MEDICAL 0x40 /* Medical Instruments */
/* 0x41-7f Reserved */
/* 0x80-83 Monitor Devices */
/* 0x84-87 Power Devices */
/* 0x88-8b Reserved */
#define HID_USAGE_PAGE_BARCODE_SCANNER 0x8c /* Bar Code Scanner page */
#define HID_USAGE_PAGE_SCALE 0x8d /* Scale page */
#define HID_USAGE_PAGE_MSR 0x8e /* Magnetic Stripe Reading (MSR) Devices */
#define HID_USAGE_PAGE_POS 0x8f /* Point of Sale devices */
#define HID_USAGE_PAGE_CAMERA_CTRL 0x90 /* Camera Control Page */
/* Generic Desktop Page Usage IDs (HuT 4) */
#define HID_DESKTOP_USAGE_UNDEFINED 0x00 /* Undefined */
#define HID_DESKTOP_USAGE_POINTER 0x01 /* Pointer */
#define HID_DESKTOP_USAGE_MOUSE 0x02 /* Mouse */
/* 0x03 Reserved */
/* 0x03 Reserved */
#define HID_DESKTOP_USAGE_JOYSTICK 0x04 /* Joystick */
#define HID_DESKTOP_USAGE_GAMEPAD 0x05 /* Game Pad */
#define HID_DESKTOP_USAGE_KEYBOARD 0x06 /* Keyboard */
#define HID_DESKTOP_USAGE_KEYPAD 0x07 /* Keypad */
#define HID_DESKTOP_USAGE_MULTIAXIS 0x08 /* Multi-axis Controller */
#define HID_DESKTOP_USAGE_TABLET 0x09 /* Tablet PC System Controls */
/* 0x0a-2f Reserved */
/* 0x0a-2f Reserved */
#define HID_DESKTOP_USAGE_X 0x30 /* X */
#define HID_DESKTOP_USAGE_Y 0x31 /* Y */
#define HID_DESKTOP_USAGE_Z 0x32 /* Z */
@@ -264,7 +247,7 @@
#define HID_DESKTOP_USAGE_MOTION 0x3c /* Motion Wakeup */
#define HID_DESKTOP_USAGE_START 0x3d /* Start */
#define HID_DESKTOP_USAGE_SELECT 0x3e /* Select */
/* 0x3f Reserved */
/* 0x3f Reserved */
#define HID_DESKTOP_USAGE_VX 0x40 /* Vx */
#define HID_DESKTOP_USAGE_VY 0x41 /* Vy */
#define HID_DESKTOP_USAGE_VZ 0x42 /* Vz */
@@ -274,7 +257,7 @@
#define HID_DESKTOP_USAGE_VNO 0x46 /* Vno */
#define HID_DESKTOP_USAGE_FEATURE 0x47 /* Feature Notification */
#define HID_DESKTOP_USAGE_RESOLUTION 0x48 /* Resolution Multiplier */
/* 0x49-7f Reserved */
/* 0x49-7f Reserved */
#define HID_DESKTOP_USAGE_CONTROL 0x80 /* System Control */
#define HID_DESKTOP_USAGE_POWERDOWN 0x81 /* System Power Down */
#define HID_DESKTOP_USAGE_SLEEP 0x82 /* System Sleep */
@@ -295,7 +278,7 @@
#define HID_DESKTOP_USAGE_DPAD_DOWN 0x91 /* D-pad Down */
#define HID_DESKTOP_USAGE_DPAD_RIGHT 0x92 /* D-pad Right */
#define HID_DESKTOP_USAGE_DPAD_LEFT 0x93 /* D-pad Left */
/* 0x94-9f Reserved */
/* 0x94-9f Reserved */
#define HID_DESKTOP_USAGE_DOCK 0xa0 /* System Dock */
#define HID_DESKTOP_USAGE_UNDOCK 0xa1 /* System Undock */
#define HID_DESKTOP_USAGE_SETUP 0xa2 /* System Setup */
@@ -305,7 +288,7 @@
#define HID_DESKTOP_USAGE_APP_DEBUG_BREAK 0xa6 /* Application Debugger Break */
#define HID_DESKTOP_USAGE_MUTE 0xa7 /* System Speaker Mute */
#define HID_DESKTOP_USAGE_HIBERNATE 0xa8 /* System Hibernate */
/* 0xa9-af Reserved */
/* 0xa9-af Reserved */
#define HID_DESKTOP_USAGE_DISPLAY_INVERT 0xb0 /* System Display Invert */
#define HID_DESKTOP_USAGE_DISPALY_INTERNAL 0xb1 /* System Display Internal */
#define HID_DESKTOP_USAGE_DISPLAY_EXTERNAL 0xb2 /* System Display External */
@@ -314,7 +297,7 @@
#define HID_DESKTOP_USAGE_DISPLAY_TOGGLE 0xb5 /* System Display Toggle Int/Ext */
#define HID_DESKTOP_USAGE_DISPLAY_SWAP 0xb6 /* System Display Swap */
#define HID_DESKTOP_USAGE_ 0xb7 /* System Display LCD Autoscale */
/* 0xb8-ffff Reserved */
/* 0xb8-ffff Reserved */
/* Keyboard usage IDs (HuT 10) */
#define HID_KBD_USAGE_NONE 0x00 /* Reserved (no event indicated) */
@@ -529,16 +512,16 @@
/* HID Report Definitions */
struct usb_hid_class_subdescriptor {
uint8_t bDescriptorType;/* Class descriptor type (See 7.1) */
uint16_t wDescriptorLength;/* Size of the report descriptor */
uint8_t bDescriptorType; /* Class descriptor type (See 7.1) */
uint16_t wDescriptorLength; /* Size of the report descriptor */
} __PACKED;
struct usb_hid_descriptor {
uint8_t bLength; /* Size of the HID descriptor */
uint8_t bDescriptorType;/* HID descriptor type */
uint16_t bcdHID;/* HID class specification release */
uint8_t bCountryCode;/* Country code */
uint8_t bNumDescriptors;/* Number of descriptors (>=1) */
uint8_t bLength; /* Size of the HID descriptor */
uint8_t bDescriptorType; /* HID descriptor type */
uint16_t bcdHID; /* HID class specification release */
uint8_t bCountryCode; /* Country code */
uint8_t bNumDescriptors; /* Number of descriptors (>=1) */
/*
* Specification says at least one Class Descriptor needs to
@@ -550,36 +533,120 @@ struct usb_hid_descriptor {
/* Standard Reports *********************************************************/
/* Keyboard input report (8 bytes) (HID B.1) */
struct usb_hid_kbd_report
{
uint8_t modifier; /* Modifier keys. See HID_MODIFER_* definitions */
uint8_t reserved;
uint8_t key[6]; /* Keycode 1-6 */
struct usb_hid_kbd_report {
uint8_t modifier; /* Modifier keys. See HID_MODIFER_* definitions */
uint8_t reserved;
uint8_t key[6]; /* Keycode 1-6 */
};
/* Keyboard output report (1 byte) (HID B.1),
* see USBHID_KBDOUT_* definitions
* see HID_KBD_OUTPUT_* definitions
*/
/* Mouse input report (HID B.2) */
struct usb_hid_mouse_report
{
uint8_t buttons; /* See HID_MOUSE_INPUT_BUTTON_* definitions */
uint8_t xdisp; /* X displacement */
uint8_t ydisp; /* y displacement */
struct usb_hid_mouse_report {
uint8_t buttons; /* See HID_MOUSE_INPUT_BUTTON_* definitions */
int8_t xdisp; /* X displacement */
int8_t ydisp; /* y displacement */
/* Device specific additional bytes may follow */
#ifdef CONFIG_INPUT_MOUSE_WHEEL
uint8_t wdisp; /* Wheel displacement */
#endif
uint8_t wdisp; /* Wheel displacement */
};
/* Joystick input report (1 bytes) (HID D.1) */
struct usb_hid_js_report
{
uint8_t xpos; /* X position */
uint8_t ypos; /* X position */
uint8_t buttons; /* See USBHID_JSIN_* definitions */
uint8_t throttle; /* Throttle */
struct usb_hid_js_report {
int8_t xpos; /* X position */
int8_t ypos; /* X position */
uint8_t buttons; /* See USBHID_JSIN_* definitions */
uint8_t throttle; /* Throttle */
};
// clang-format off
#define HID_MOUSE_DESCRIPTOR_LEN (9 + 9 + 7)
#define HID_MOUSE_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, int_ep, wMaxPacketSize, bInterval) \
0x09, /* bLength: Interface Descriptor size */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
bInterfaceNumber, /* bInterfaceNumber: Number of Interface */ \
0x00, /* bAlternateSetting: Alternate setting */ \
0x01, /* bNumEndpoints */ \
0x03, /* bInterfaceClass: HID */ \
bInterfaceSubClass, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ \
0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ \
0x00, /* iInterface: Index of string descriptor */ \
0x09, /* bLength: HID Descriptor size */ \
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ \
0x11, /* bcdHID: HID Class Spec release number */ \
0x01, \
0x00, /* bCountryCode: Hardware target country */ \
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ \
0x22, /* bDescriptorType */ \
WBVAL(wItemLength), /* wItemLength: Total length of Report descriptor */ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
int_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
bInterval /* bInterval: Polling Interval */
#define HID_KEYBOARD_DESCRIPTOR_LEN (9 + 9 + 7)
#define HID_KEYBOARD_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, int_ep, wMaxPacketSize, bInterval) \
0x09, /* bLength: Interface Descriptor size */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
bInterfaceNumber, /* bInterfaceNumber: Number of Interface */ \
0x00, /* bAlternateSetting: Alternate setting */ \
0x01, /* bNumEndpoints */ \
0x03, /* bInterfaceClass: HID */ \
bInterfaceSubClass, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ \
0x01, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ \
0x00, /* iInterface: Index of string descriptor */ \
0x09, /* bLength: HID Descriptor size */ \
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ \
0x11, /* bcdHID: HID Class Spec release number */ \
0x01, \
0x00, /* bCountryCode: Hardware target country */ \
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ \
0x22, /* bDescriptorType */ \
WBVAL(wItemLength), /* wItemLength: Total length of Report descriptor */ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
int_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
bInterval /* bInterval: Polling Interval */
#define HID_CUSTOM_INOUT_DESCRIPTOR_LEN (9 + 9 + 7 + 7)
#define HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, out_ep, in_ep, wMaxPacketSize, bInterval) \
0x09, /* bLength: Interface Descriptor size */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
bInterfaceNumber, /* bInterfaceNumber: Number of Interface */ \
0x00, /* bAlternateSetting: Alternate setting */ \
0x02, /* bNumEndpoints */ \
0x03, /* bInterfaceClass: HID */ \
bInterfaceSubClass, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ \
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ \
0x00, /* iInterface: Index of string descriptor */ \
0x09, /* bLength: HID Descriptor size */ \
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ \
0x11, /* bcdHID: HID Class Spec release number */ \
0x01, \
0x00, /* bCountryCode: Hardware target country */ \
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ \
0x22, /* bDescriptorType */ \
WBVAL(wItemLength), /* wItemLength: Total length of Report descriptor */ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
out_ep, /* bEndpointAddress: Endpoint Address (OUT) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
bInterval, /* bInterval: Polling Interval */ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
in_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
bInterval /* bInterval: Polling Interval */
// clang-format on
#endif /* USB_HID_H */

View File

@@ -50,6 +50,8 @@ static int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_p
struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len)
{
(void)busid;
intf->class_interface_handler = hid_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
@@ -60,30 +62,65 @@ struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *
return intf;
}
/*
* Appendix G: HID Request Support Requirements
*
* The following table enumerates the requests that need to be supported by various types of HID class devices.
* Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
* ------------------------------------------------------------------------------------------
* Boot Mouse Required Optional Optional Optional Required Required
* Non-Boot Mouse Required Optional Optional Optional Optional Optional
* Boot Keyboard Required Optional Required Required Required Required
* Non-Boot Keybrd Required Optional Required Required Optional Optional
* Other Device Required Optional Optional Optional Optional Optional
*/
__WEAK void usbd_hid_get_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len)
{
(void)busid;
(void)intf;
(void)report_id;
(void)report_type;
(*data[0]) = 0;
*len = 1;
}
__WEAK uint8_t usbd_hid_get_idle(uint8_t busid, uint8_t intf, uint8_t report_id)
{
(void)busid;
(void)intf;
(void)report_id;
return 0;
}
__WEAK uint8_t usbd_hid_get_protocol(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
return 0;
}
__WEAK void usbd_hid_set_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t *report, uint32_t report_len)
{
(void)busid;
(void)intf;
(void)report_id;
(void)report_type;
(void)report;
(void)report_len;
}
__WEAK void usbd_hid_set_idle(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t duration)
{
(void)busid;
(void)intf;
(void)report_id;
(void)duration;
}
__WEAK void usbd_hid_set_protocol(uint8_t busid, uint8_t intf, uint8_t protocol)
{
(void)busid;
(void)intf;
(void)protocol;
}

View File

@@ -15,10 +15,6 @@ extern "C" {
/* Init hid interface driver */
struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
/* Register desc api */
void usbd_hid_descriptor_register(uint8_t busid, uint8_t intf_num, const uint8_t *desc);
void usbd_hid_report_descriptor_register(uint8_t busid, uint8_t intf_num, const uint8_t *desc, uint32_t desc_len);
/* Setup request command callback api */
void usbd_hid_get_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len);
uint8_t usbd_hid_get_idle(uint8_t busid, uint8_t intf, uint8_t report_id);

View File

@@ -12,18 +12,26 @@
#define DEV_FORMAT "/dev/input%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[128];
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
/* interface descriptor field offsets */
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[CONFIG_USBHOST_MAX_HID_CLASS][USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_hid g_hid_class[CONFIG_USBHOST_MAX_HID_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_hid *usbh_hid_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_HID_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_hid_class[devno], 0, sizeof(struct usbh_hid));
g_hid_class[devno].minor = devno;
return &g_hid_class[devno];
@@ -34,36 +42,40 @@ static struct usbh_hid *usbh_hid_class_alloc(void)
static void usbh_hid_class_free(struct usbh_hid *hid_class)
{
int devno = hid_class->minor;
uint8_t devno = hid_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(hid_class, 0, sizeof(struct usbh_hid));
}
static int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer)
int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer, uint32_t buflen)
{
struct usb_setup_packet *setup = hid_class->hport->setup;
int ret;
struct usb_setup_packet *setup;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
setup->wIndex = hid_class->intf;
setup->wLength = 128;
setup->wLength = buflen;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
if (ret < 0) {
return ret;
}
memcpy(buffer, g_hid_buf, ret - 8);
return ret;
return usbh_control_transfer(hid_class->hport, setup, buffer);
}
int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration)
{
struct usb_setup_packet *setup = hid_class->hport->setup;
struct usb_setup_packet *setup;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_SET_IDLE;
@@ -76,26 +88,36 @@ int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t dur
int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
{
struct usb_setup_packet *setup = hid_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_GET_IDLE;
setup->wValue = 0;
setup->wIndex = hid_class->intf;
setup->wLength = 1;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
if (ret < 0) {
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
if (ret < 8) {
return ret;
}
memcpy(buffer, g_hid_buf, 1);
memcpy(buffer, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
return ret;
}
int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
{
struct usb_setup_packet *setup = hid_class->hport->setup;
struct usb_setup_packet *setup;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_SET_PROTOCOL;
@@ -106,10 +128,72 @@ int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
return usbh_control_transfer(hid_class->hport, setup, NULL);
}
int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol)
{
struct usb_setup_packet *setup;
int ret;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_GET_PROTOCOL;
setup->wValue = 0;
setup->wIndex = hid_class->intf;
setup->wLength = 1;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
if (ret < 8) {
return ret;
}
memcpy(protocol, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
return ret;
}
int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
{
struct usb_setup_packet *setup;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_SET_REPORT;
setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
setup->wIndex = 0;
setup->wLength = buflen;
return usbh_control_transfer(hid_class->hport, setup, buffer);
}
int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
{
struct usb_setup_packet *setup;
if (!hid_class || !hid_class->hport) {
return -USB_ERR_INVAL;
}
setup = hid_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = HID_REQUEST_GET_REPORT;
setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
setup->wIndex = 0;
setup->wLength = buflen;
return usbh_control_transfer(hid_class->hport, setup, buffer);
}
int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint8_t cur_iface = 0xff;
uint8_t *p;
bool found = false;
struct usbh_hid *hid_class = usbh_hid_class_alloc();
if (hid_class == NULL) {
@@ -122,22 +206,42 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
hport->config.intf[intf].priv = hid_class;
// /* 0x0 = boot protocol, 0x1 = report protocol */
// ret = usbh_hid_set_protocol(hid_class, 0x1);
// if (ret < 0) {
// return ret;
// }
p = hport->raw_config_desc;
while (p[DESC_bLength]) {
switch (p[DESC_bDescriptorType]) {
case USB_DESCRIPTOR_TYPE_INTERFACE:
cur_iface = p[INTF_DESC_bInterfaceNumber];
if (cur_iface == intf) {
hid_class->protocol = p[7];
struct usb_hid_descriptor *desc = (struct usb_hid_descriptor *)(p + 9);
ret = usbh_hid_set_idle(hid_class, 0, 0);
if (ret < 0) {
USB_LOG_WRN("Do not support set idle\r\n");
if (desc->bDescriptorType != HID_DESCRIPTOR_TYPE_HID) {
USB_LOG_ERR("HID descriptor not found\r\n");
return -USB_ERR_INVAL;
}
if (desc->subdesc[0].bDescriptorType != HID_DESCRIPTOR_TYPE_HID_REPORT) {
USB_LOG_ERR("HID report descriptor not found\r\n");
return -USB_ERR_INVAL;
}
hid_class->report_size = desc->subdesc[0].wDescriptorLength;
found = true;
goto found;
}
break;
default:
break;
}
/* skip to next descriptor */
p += p[DESC_bLength];
}
ret = usbh_hid_get_report_descriptor(hid_class, hid_class->report_desc);
if (ret < 0) {
return ret;
if (found == false) {
USB_LOG_ERR("HID interface not found\r\n");
return -USB_ERR_INVAL;
}
found:
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
@@ -152,7 +256,7 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
usbh_hid_run(hid_class);
return ret;
return 0;
}
int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
@@ -171,6 +275,7 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister HID Class:%s\r\n", hport->config.intf[intf].devname);
usbh_hid_stop(hid_class);
}
@@ -181,12 +286,435 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
static uint32_t hid_get_itemval(const uint8_t *data, unsigned int idx, unsigned int size)
{
uint32_t value = 0;
for (unsigned int i = 1; i <= size; i++)
value |= data[idx + i] << (8 * (i - 1));
return value;
}
struct hid_report *usbh_hid_report_parse(const uint8_t *data, uint32_t report_len, uint32_t max_usages)
{
uint32_t i = 0;
uint32_t itemtag, itemtype, itemsize;
uint32_t itemval;
struct hid_report_field field;
uint32_t usage_page = 0, usage = 0, usage_min = 0, usage_max = 0, flags = 0;
uint32_t *usages;
struct hid_report *hid_report;
hid_report = usb_osal_malloc(sizeof(struct hid_report));
if (!hid_report) {
USB_LOG_ERR("hid report malloc failed\r\n");
return NULL;
}
usages = usb_osal_malloc(sizeof(uint32_t) * max_usages);
if (!usages) {
USB_LOG_ERR("hid usages malloc failed\r\n");
goto err;
}
memset(hid_report, 0, sizeof(struct hid_report));
memset(&field, 0, sizeof(struct hid_report_field));
while (i < report_len) {
itemtag = data[i] & HID_TAG_MASK;
itemtype = data[i] & HID_TYPE_MASK;
itemsize = data[i] & HID_SIZE_MASK;
if (itemsize == 3) /* HID spec: 6.2.2.2 - Short Items */
itemsize = 4;
itemval = hid_get_itemval(data, i, itemsize);
USB_LOG_DBG("itemtype 0x%02x, itemtag 0x%02x, itemsize %d, itemval 0x%08x\r\n",
itemtype, itemtag, itemsize, itemval);
switch (itemtype) {
case HID_ITEMTYPE_MAIN:
switch (itemtag) {
case HID_MAINITEM_TAG_INPUT:
if ((flags & HID_REPORT_FLAG_REQUIRED_MASK) != HID_REPORT_FLAG_REQUIRED_MASK)
goto err;
if (hid_report->input_count >= CONFIG_USBHOST_HID_MAX_INPUT) {
USB_LOG_ERR("hid input fields exceed max limit\r\n");
goto err;
}
field.flags = flags;
field.properties = itemval;
field.usage_page = usage_page;
memcpy(&hid_report->input_fields[hid_report->input_count], &field, sizeof(struct hid_report_field));
if (field.usage_count > 0) {
hid_report->input_fields[hid_report->input_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
if (!hid_report->input_fields[hid_report->input_count].usages) {
USB_LOG_ERR("hid input usages malloc failed\r\n");
goto err;
}
memcpy(hid_report->input_fields[hid_report->input_count].usages, usages, sizeof(uint32_t) * field.usage_count);
}
hid_report->input_count++;
/* only keep the global items */
flags &= HID_REPORT_FLAG_GLOBAL_MASK;
memset(&field, 0, sizeof(struct hid_report_field));
break;
case HID_MAINITEM_TAG_OUTPUT:
if ((flags & HID_REPORT_FLAG_REQUIRED_MASK) != HID_REPORT_FLAG_REQUIRED_MASK)
goto err;
if (hid_report->output_count >= CONFIG_USBHOST_HID_MAX_OUTPUT) {
USB_LOG_ERR("hid output fields exceed max limit\r\n");
goto err;
}
field.flags = flags;
field.properties = itemval;
field.usage_page = usage_page;
memcpy(&hid_report->output_fields[hid_report->output_count], &field, sizeof(struct hid_report_field));
if (field.usage_count > 0) {
hid_report->output_fields[hid_report->output_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
if (!hid_report->output_fields[hid_report->output_count].usages) {
USB_LOG_ERR("hid output usages malloc failed\r\n");
goto err;
}
memcpy(hid_report->output_fields[hid_report->output_count].usages, usages, sizeof(uint32_t) * field.usage_count);
}
hid_report->output_count++;
/* only keep the global items */
flags &= HID_REPORT_FLAG_GLOBAL_MASK;
memset(&field, 0, sizeof(struct hid_report_field));
break;
case HID_MAINITEM_TAG_COLLECTION:
memset(&field, 0, sizeof(struct hid_report_field));
break;
case HID_MAINITEM_TAG_FEATURE:
if (hid_report->feature_count >= CONFIG_USBHOST_HID_MAX_FEATURE) {
USB_LOG_ERR("hid feature fields exceed max limit\r\n");
goto err;
}
field.flags = flags;
field.properties = itemval;
field.usage_page = usage_page;
memcpy(&hid_report->feature_fields[hid_report->feature_count], &field, sizeof(struct hid_report_field));
if (field.usage_count > 0) {
hid_report->feature_fields[hid_report->feature_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
if (!hid_report->feature_fields[hid_report->feature_count].usages) {
USB_LOG_ERR("hid feature usages malloc failed\r\n");
goto err;
}
memcpy(hid_report->feature_fields[hid_report->feature_count].usages, usages, sizeof(uint32_t) * field.usage_count);
}
hid_report->feature_count++;
memset(&field, 0, sizeof(struct hid_report_field));
break;
case HID_MAINITEM_TAG_ENDCOLLECTION:
break;
default:
goto err;
}
break;
case HID_ITEMTYPE_GLOBAL:
switch (itemtag) {
case HID_GLOBALITEM_TAG_USAGE_PAGE:
usage_page = itemval;
if (usage_page > UINT16_MAX)
goto err;
flags |= HID_REPORT_FLAG_USAGE_PAGE;
break;
case HID_GLOBALITEM_TAG_LOGICAL_MIN:
field.logical_min = (int32_t)itemval;
flags |= HID_REPORT_FLAG_LOGICAL_MIN;
break;
case HID_GLOBALITEM_TAG_LOGICAL_MAX:
field.logical_max = (int32_t)itemval;
flags |= HID_REPORT_FLAG_LOGICAL_MAX;
break;
case HID_GLOBALITEM_TAG_REPORT_SIZE:
field.report_size = itemval;
flags |= HID_REPORT_FLAG_REPORT_SIZE;
break;
case HID_GLOBALITEM_TAG_REPORT_COUNT:
field.report_count = itemval;
flags |= HID_REPORT_FLAG_REPORT_COUNT;
break;
case HID_GLOBALITEM_TAG_REPORT_ID:
hid_report->uses_report_id = true;
field.report_id = itemval;
flags |= HID_REPORT_FLAG_REPORT_ID;
break;
default:
goto err;
}
break;
case HID_ITEMTYPE_LOCAL:
switch (itemtag) {
case HID_LOCALITEM_TAG_USAGE:
usage = itemval;
/* Extended usage (size 4) combines both usage page and id */
if (itemsize != 4) {
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
goto err;
usage |= usage_page << 16;
}
usages[field.usage_count++] = usage;
break;
case HID_LOCALITEM_TAG_USAGE_MIN:
usage_min = itemval;
if (itemsize == 4) {
/* Usage max must be extended as well */
flags |= HID_REPORT_FLAG_EXTENDED_USAGE;
} else {
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
goto err;
usage_min |= usage_page << 16;
}
field.usage_min = usage_min;
flags |= HID_REPORT_FLAG_USAGE_MIN;
break;
case HID_LOCALITEM_TAG_USAGE_MAX:
if (!(flags & HID_REPORT_FLAG_USAGE_MIN))
goto err;
usage_max = itemval;
if (flags & HID_REPORT_FLAG_EXTENDED_USAGE) {
/* Fail if max is not extended usage (HID spec 6.2.2.8) */
if (itemsize != 4)
goto err;
} else if (itemsize == 4) {
/* Fail because min wasn't extended, but max is */
goto err;
} else {
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
goto err;
usage_max |= usage_page << 16;
}
/* Usage min and max must be on the same page */
if (USAGE_PAGE(usage_min) != USAGE_PAGE(usage_max)) {
goto err;
}
if (usage_min > usage_max) {
goto err;
}
for (uint32_t j = usage_min; j <= usage_max; j++) {
usages[field.usage_count++] = j;
}
field.usage_max = usage_max;
flags |= HID_REPORT_FLAG_USAGE_MAX;
flags &= ~(HID_REPORT_FLAG_USAGE_MIN | HID_REPORT_FLAG_EXTENDED_USAGE);
break;
default:
goto err;
}
break;
default:
goto err;
}
i += (1 + itemsize);
}
usb_osal_free(usages);
return hid_report;
err:
if (hid_report) {
usb_osal_free(hid_report);
for (uint32_t j = 0; j < hid_report->input_count; j++)
usb_osal_free(hid_report->input_fields[j].usages);
for (uint32_t j = 0; j < hid_report->output_count; j++)
usb_osal_free(hid_report->output_fields[j].usages);
for (uint32_t j = 0; j < hid_report->feature_count; j++)
usb_osal_free(hid_report->feature_fields[j].usages);
}
if (usages)
usb_osal_free(usages);
return NULL;
}
void usbh_hid_report_free(struct hid_report *hid_report)
{
if (hid_report) {
for (uint32_t j = 0; j < hid_report->input_count; j++)
usb_osal_free(hid_report->input_fields[j].usages);
for (uint32_t j = 0; j < hid_report->output_count; j++)
usb_osal_free(hid_report->output_fields[j].usages);
for (uint32_t j = 0; j < hid_report->feature_count; j++)
usb_osal_free(hid_report->feature_fields[j].usages);
usb_osal_free(hid_report);
}
}
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_report_buf[2048];
static const char *hid_property_string(uint32_t value)
{
uint32_t off = 0;
static char buffer[160];
memset(buffer, 0, sizeof(buffer));
if (value & HID_MAINITEM_CONSTANT)
off += snprintf(buffer + off, sizeof(buffer) - off, "Constant, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "Data, ");
if (value & HID_MAINITEM_VARIABLE)
off += snprintf(buffer + off, sizeof(buffer) - off, "Variable, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "Array, ");
if (value & HID_MAINITEM_RELATIVE)
off += snprintf(buffer + off, sizeof(buffer) - off, "Relative, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "Absolute, ");
if (value & HID_MAINITEM_WRAP)
off += snprintf(buffer + off, sizeof(buffer) - off, "Wrap, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "NoWrap, ");
if (value & HID_MAINITEM_NONLINEAR)
off += snprintf(buffer + off, sizeof(buffer) - off, "NonLinear, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "Linear, ");
if (value & HID_MAINITEM_NOPREFERRED)
off += snprintf(buffer + off, sizeof(buffer) - off, "NoPreferred, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "Preferred, ");
if (value & HID_MAINITEM_NULLSTATE)
off += snprintf(buffer + off, sizeof(buffer) - off, "NullState, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "NoNullState, ");
if (value & HID_MAINITEM_VOLATILE)
off += snprintf(buffer + off, sizeof(buffer) - off, "Volatile, ");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "NonVolatile, ");
if (value & HID_MAINITEM_BUFFEREDBYTES)
off += snprintf(buffer + off, sizeof(buffer) - off, "BufferedBytes");
else
off += snprintf(buffer + off, sizeof(buffer) - off, "BitField");
return buffer;
}
static void usbh_hid_field_info_print(uint32_t idx, struct hid_report_field *field)
{
USB_LOG_RAW(" Field %u:\r\n", idx);
USB_LOG_RAW(" Usage Page: 0x%04x\r\n", (unsigned int)field->usage_page);
USB_LOG_RAW(" Report ID: %u\r\n", (unsigned int)field->report_id);
USB_LOG_RAW(" Report Size: %ubit\r\n", (unsigned int)field->report_size);
USB_LOG_RAW(" Report Count: %u\r\n", (unsigned int)field->report_count);
USB_LOG_RAW(" Logical Min: %d\r\n", field->logical_min);
USB_LOG_RAW(" Logical Max: %d\r\n", field->logical_max);
USB_LOG_RAW(" Usage Count: %u\r\n", (unsigned int)field->usage_count);
if (field->usage_count > 0) {
if (field->usage_count == 1) {
USB_LOG_RAW(" Usage: 0x%04x\r\n", USAGE_ID(field->usages[0]));
} else {
USB_LOG_RAW(" Usages(0x%04x ~ 0x%04x)\r\n", USAGE_ID(field->usage_min), USAGE_ID(field->usage_max));
}
}
USB_LOG_RAW(" Flags: 0x%04x\r\n", (unsigned int)field->flags);
USB_LOG_RAW(" Properties: 0x%04x(%s)\r\n", (unsigned int)field->properties, hid_property_string(field->properties));
}
int lshid(int argc, char **argv)
{
struct usbh_hid *hid_class;
struct hid_report *hid_report;
int ret;
if (argc < 2) {
USB_LOG_ERR("please input correct command: lshid path\r\n");
return -1;
}
hid_class = usbh_find_class_instance(argv[1]);
if (!hid_class) {
USB_LOG_ERR("cannot find hid device\r\n");
return -1;
}
if (hid_class->report_size > sizeof(g_hid_report_buf)) {
USB_LOG_ERR("hid report buffer is too small\r\n");
return -1;
}
ret = usbh_hid_get_report_descriptor(hid_class, g_hid_report_buf, hid_class->report_size);
if (ret < 0) {
USB_LOG_ERR("get hid report descriptor failed, errcode: %d\r\n", ret);
return -1;
}
hid_report = usbh_hid_report_parse(g_hid_report_buf, hid_class->report_size, 1024);
if (hid_report) {
USB_LOG_RAW("HID report parsed successfully\r\n");
USB_LOG_RAW("Input fields: %u\r\n", (unsigned int)hid_report->input_count);
for (uint32_t i = 0; i < hid_report->input_count; i++) {
struct hid_report_field *field = &hid_report->input_fields[i];
usbh_hid_field_info_print(i, field);
}
USB_LOG_RAW("Output fields: %u\r\n", (unsigned int)hid_report->output_count);
for (uint32_t i = 0; i < hid_report->output_count; i++) {
struct hid_report_field *field = &hid_report->output_fields[i];
usbh_hid_field_info_print(i, field);
}
USB_LOG_RAW("Feature fields: %u\r\n", (unsigned int)hid_report->feature_count);
for (uint32_t i = 0; i < hid_report->feature_count; i++) {
struct hid_report_field *field = &hid_report->feature_fields[i];
usbh_hid_field_info_print(i, field);
}
usbh_hid_report_free(hid_report);
} else {
USB_LOG_ERR("HID report parsed failed\r\n");
}
return 0;
}
__WEAK void usbh_hid_run(struct usbh_hid *hid_class)
{
(void)hid_class;
}
__WEAK void usbh_hid_stop(struct usbh_hid *hid_class)
{
(void)hid_class;
}
const struct usbh_class_driver hid_class_driver = {
@@ -197,10 +725,9 @@ const struct usbh_class_driver hid_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_HID,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_HID,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.class_driver = &hid_class_driver
};

View File

@@ -8,6 +8,82 @@
#include "usb_hid.h"
/* local items */
#define HID_REPORT_FLAG_USAGE_MIN (1 << 0)
#define HID_REPORT_FLAG_USAGE_MAX (1 << 1)
/* global items */
#define HID_REPORT_FLAG_REPORT_ID (1 << 2)
#define HID_REPORT_FLAG_REPORT_COUNT (1 << 3)
#define HID_REPORT_FLAG_REPORT_SIZE (1 << 4)
#define HID_REPORT_FLAG_LOGICAL_MIN (1 << 5)
#define HID_REPORT_FLAG_LOGICAL_MAX (1 << 6)
#define HID_REPORT_FLAG_USAGE_PAGE (1 << 7)
/* main items */
#define HID_REPORT_FLAG_INPUT (1 << 8)
#define HID_REPORT_FLAG_OUTPUT (1 << 9)
#define HID_REPORT_FLAG_FEATURE (1 << 10)
#define HID_REPORT_FLAG_EXTENDED_USAGE (1 << 11)
/* masks */
#define HID_REPORT_FLAG_GLOBAL_MASK (HID_REPORT_FLAG_REPORT_ID | \
HID_REPORT_FLAG_REPORT_COUNT | \
HID_REPORT_FLAG_REPORT_SIZE | \
HID_REPORT_FLAG_LOGICAL_MIN | \
HID_REPORT_FLAG_LOGICAL_MAX | \
HID_REPORT_FLAG_USAGE_PAGE)
#define HID_REPORT_FLAG_REQUIRED_MASK (HID_REPORT_FLAG_REPORT_COUNT | \
HID_REPORT_FLAG_REPORT_SIZE | \
HID_REPORT_FLAG_LOGICAL_MIN | \
HID_REPORT_FLAG_LOGICAL_MAX)
#define USAGE_ID(usage) (usage & 0x0000FFFF)
#define USAGE_PAGE(usage) ((usage & 0xFFFF0000) >> 16)
#ifndef CONFIG_USBHOST_HID_MAX_INPUT
#define CONFIG_USBHOST_HID_MAX_INPUT 16
#endif
#ifndef CONFIG_USBHOST_HID_MAX_OUTPUT
#define CONFIG_USBHOST_HID_MAX_OUTPUT 16
#endif
#ifndef CONFIG_USBHOST_HID_MAX_FEATURE
#define CONFIG_USBHOST_HID_MAX_FEATURE 16
#endif
struct hid_report_field {
uint32_t *usages; /* usage page + usage */
uint32_t usage_count;
uint32_t usage_page;
uint32_t report_id; /* optional */
uint32_t report_count;
uint32_t report_size;
int32_t logical_min;
int32_t logical_max;
uint32_t properties;
uint32_t usage_min;
uint32_t usage_max;
uint32_t flags;
};
struct hid_report {
bool uses_report_id;
uint32_t input_count;
struct hid_report_field input_fields[CONFIG_USBHOST_HID_MAX_INPUT];
uint32_t output_count;
struct hid_report_field output_fields[CONFIG_USBHOST_HID_MAX_OUTPUT];
uint32_t feature_count;
struct hid_report_field feature_fields[CONFIG_USBHOST_HID_MAX_FEATURE];
};
struct usbh_hid {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
@@ -15,21 +91,35 @@ struct usbh_hid {
struct usbh_urb intin_urb; /* INTR IN urb */
struct usbh_urb intout_urb; /* INTR OUT urb */
uint8_t report_desc[128];
uint16_t report_size;
uint8_t protocol;
uint8_t intf; /* interface number */
uint8_t minor;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer, uint32_t buflen);
int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration);
int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer);
int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol);
int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol);
int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen);
int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen);
struct hid_report *usbh_hid_report_parse(const uint8_t *data, uint32_t report_len, uint32_t max_usages);
void usbh_hid_report_free(struct hid_report *hid_report);
void usbh_hid_run(struct usbh_hid *hid_class);
void usbh_hid_stop(struct usbh_hid *hid_class);
int lshid(int argc, char **argv);
#ifdef __cplusplus
}
#endif

View File

@@ -10,6 +10,12 @@
#define HUB_DESCRIPTOR_TYPE_HUB 0x29
#define HUB_DESCRIPTOR_TYPE_HUB3 0x2A
#define HUB_MAX_DEPTH 5
#define HUB_SUBCLASS 0x00
#define HUB_PROTOCOL_STT 0x01
#define HUB_PROTOCOL_MTT 0x02
/* Hub class requests */
#define HUB_REQUEST_GET_STATUS USB_REQUEST_GET_STATUS
#define HUB_REQUEST_CLEAR_FEATURE USB_REQUEST_CLEAR_FEATURE
@@ -27,23 +33,31 @@
#define HUB_FEATURE_HUB_C_OVERCURRENT (0x1)
/* Port features */
#define HUB_PORT_FEATURE_CONNECTION (0x00)
#define HUB_PORT_FEATURE_ENABLE (0x01)
#define HUB_PORT_FEATURE_SUSPEND (0x02)
#define HUB_PORT_FEATURE_OVERCURRENT (0x03)
#define HUB_PORT_FEATURE_RESET (0x04)
#define HUB_PORT_FEATURE_L1 (0x05)
#define HUB_PORT_FEATURE_POWER (0x08)
#define HUB_PORT_FEATURE_LOWSPEED (0x09)
#define HUB_PORT_FEATURE_HIGHSPEED (0x0a)
#define HUB_PORT_FEATURE_CONNECTION (0x00)
#define HUB_PORT_FEATURE_ENABLE (0x01)
#define HUB_PORT_FEATURE_SUSPEND (0x02)
#define HUB_PORT_FEATURE_OVERCURRENT (0x03)
#define HUB_PORT_FEATURE_RESET (0x04)
#define HUB_PORT_FEATURE_L1 (0x05) /* USB 2.0 only */
#define HUB_PORT_FEATURE_POWER (0x08) /* USB 2.0 only */
#define HUB_PORT_FEATURE_POWER_SS (0x09) /* USB 3.0 only */
/* This is a bit tricky because HUB_PORT_FEATURE_POWER_SS and
HUB_PORT_FEATURE_LOWSPEED share the same bit. */
#define HUB_PORT_FEATURE_LOWSPEED (0x09) /* USB 2.0 only */
#define HUB_PORT_FEATURE_HIGHSPEED (0x0a) /* USB 2.0 only */
#define HUB_PORT_FEATURE_TEST (0x0b) /* USB 2.0 only */
#define HUB_PORT_FEATURE_INDICATOR (0x0c) /* USB 2.0 only */
/* Port status change (wPortChange) */
#define HUB_PORT_FEATURE_C_CONNECTION (0x10)
#define HUB_PORT_FEATURE_C_ENABLE (0x11)
#define HUB_PORT_FEATURE_C_SUSPEND (0x12)
#define HUB_PORT_FEATURE_C_ENABLE (0x11) /* USB 2.0 only */
#define HUB_PORT_FEATURE_C_SUSPEND (0x12) /* USB 2.0 only */
#define HUB_PORT_FEATURE_C_OVER_CURREN (0x13)
#define HUB_PORT_FEATURE_C_RESET (0x14)
#define HUB_PORT_FEATURE_TEST (0x15)
#define HUB_PORT_FEATURE_INDICATOR (0x16)
#define HUB_PORT_FEATURE_C_PORTL1 (0x17)
#define HUB_PORT_FEATURE_C_BH_RESET (0x15) /* USB 3.0 only */
#define HUB_PORT_FEATURE_C_LINK_STATE (0x16) /* USB 3.0 only */
#define HUB_PORT_FEATURE_C_CONFIG_ERR (0x17) /* USB 3.0 only */
/* Hub status */
#define HUB_STATUS_LOCALPOWER (1 << 0)
@@ -56,23 +70,42 @@
/* Hub port status */
#define HUB_PORT_STATUS_CONNECTION (1 << 0)
#define HUB_PORT_STATUS_ENABLE (1 << 1)
#define HUB_PORT_STATUS_SUSPEND (1 << 2)
#define HUB_PORT_STATUS_SUSPEND (1 << 2) /* USB 2.0 only */
#define HUB_PORT_STATUS_OVERCURRENT (1 << 3)
#define HUB_PORT_STATUS_RESET (1 << 4)
#define HUB_PORT_STATUS_L1 (1 << 5)
#define HUB_PORT_STATUS_POWER (1 << 8)
#define HUB_PORT_STATUS_LOW_SPEED (1 << 9)
#define HUB_PORT_STATUS_HIGH_SPEED (1 << 10)
#define HUB_PORT_STATUS_TEST (1 << 11)
#define HUB_PORT_STATUS_INDICATOR (1 << 12)
#define HUB_PORT_STATUS_L1 (1 << 5) /* USB 2.0 only */
/* Port Link State (PORT_LINK_STATE), USB 3.0 only */
#define HUB_PORT_STATUS_LS_U0 (0x00 << 5)
#define HUB_PORT_STATUS_LS_U1 (0x01 << 5)
#define HUB_PORT_STATUS_LS_U2 (0x02 << 5)
#define HUB_PORT_STATUS_LS_U3 (0x03 << 5)
#define HUB_PORT_STATUS_LS_SS_DISABLED (0x04 << 5)
#define HUB_PORT_STATUS_LS_RX_DETECT (0x05 << 5)
#define HUB_PORT_STATUS_LS_SS_INACTIVE (0x06 << 5)
#define HUB_PORT_STATUS_LS_POLLING (0x07 << 5)
#define HUB_PORT_STATUS_LS_RECOVERY (0x08 << 5)
#define HUB_PORT_STATUS_LS_HOT_RESET (0x09 << 5)
#define HUB_PORT_STATUS_LS_COMP_MOD (0x0a << 5)
#define HUB_PORT_STATUS_LS_LOOPBACK (0x0b << 5)
#define HUB_PORT_STATUS_POWER (1 << 8)
#define HUB_PORT_STATUS_POWER_SS (1 << 9) /* USB 3.0 only */
#define HUB_PORT_STATUS_LOW_SPEED (1 << 9) /* USB 2.0 only */
#define HUB_PORT_STATUS_HIGH_SPEED (1 << 10) /* USB 2.0 only */
#define HUB_PORT_STATUS_TEST (1 << 11) /* USB 2.0 only */
#define HUB_PORT_STATUS_INDICATOR (1 << 12) /* USB 2.0 only */
/* Hub port status change */
#define HUB_PORT_STATUS_C_CONNECTION (1 << 0)
#define HUB_PORT_STATUS_C_ENABLE (1 << 1)
#define HUB_PORT_STATUS_C_SUSPEND (1 << 2)
#define HUB_PORT_STATUS_C_ENABLE (1 << 1) /* USB 2.0 only */
#define HUB_PORT_STATUS_C_SUSPEND (1 << 2) /* USB 2.0 only */
#define HUB_PORT_STATUS_C_OVERCURRENT (1 << 3)
#define HUB_PORT_STATUS_C_RESET (1 << 4)
#define HUB_PORT_STATUS_C_L1 (1 << 5)
#define HUB_PORT_STATUS_C_L1 (1 << 5) /* USB 2.0 only */
#define HUB_PORT_STATUS_C_BH_RESET (1 << 5) /* USB 3.0 only */
#define HUB_PORT_STATUS_C_PORTLINK (1 << 6) /* USB 3.0 only */
#define HUB_PORT_STATUS_C_CONFIGERR (1 << 7) /* USB 3.0 only */
/* Hub characteristics */
#define HUB_CHAR_LPSM_SHIFT (0) /* Bits 0-1: Logical Power Switching Mode */
@@ -106,6 +139,21 @@ struct usb_hub_descriptor {
#define USB_SIZEOF_HUB_DESC 9
/* Super speed Hub descriptor */
struct usb_hub_ss_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
uint16_t wHubCharacteristics;
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
uint8_t bHubHdrDecLat;
uint16_t wHubDelay;
uint8_t DeviceRemovable;
} __PACKED;
#define USB_SIZEOF_HUB_SS_DESC 11
/* Hub status */
struct hub_status {
uint16_t wPortStatus;

View File

@@ -22,29 +22,22 @@
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_BUS][CONFIG_USBHOST_MAX_EXTHUBS + 1][USB_ALIGN_UP(1, CONFIG_USB_ALIGN_SIZE)];
extern int usbh_free_devaddr(struct usbh_hubport *hport);
extern int usbh_enumerate(struct usbh_hubport *hport);
extern void usbh_hubport_release(struct usbh_hubport *hport);
static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
#ifdef CONFIG_USBHOST_XHCI
struct usbh_hubport *usbh_get_roothub_port(unsigned int port)
{
return &roothub.child[port - 1];
}
#endif
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static struct usbh_hub g_hub_class[CONFIG_USBHOST_MAX_EXTHUBS];
static uint32_t g_devinuse = 0;
static struct usbh_hub *usbh_hub_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_EXTHUBS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_hub_class[devno], 0, sizeof(struct usbh_hub));
g_hub_class[devno].index = EXTHUB_FIRST_INDEX + devno;
return &g_hub_class[devno];
@@ -55,16 +48,14 @@ static struct usbh_hub *usbh_hub_class_alloc(void)
static void usbh_hub_class_free(struct usbh_hub *hub_class)
{
int devno = hub_class->index - EXTHUB_FIRST_INDEX;
uint8_t devno = hub_class->index - EXTHUB_FIRST_INDEX;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(hub_class, 0, sizeof(struct usbh_hub));
}
#endif
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
{
struct usb_setup_packet *setup;
@@ -74,15 +65,7 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
/* TODO: hub descriptor has some difference between USB 2.0 and USB 3.x,
and we havn't handle the difference here */
if ((hub->parent->speed == USB_SPEED_SUPER) ||
(hub->parent->speed == USB_SPEED_SUPER_PLUS)) {
setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
} else {
setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
}
setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_HUB_DESC;
@@ -91,11 +74,11 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
if (ret < 0) {
return ret;
}
memcpy(buffer, g_hub_buf, USB_SIZEOF_HUB_DESC);
memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_DESC);
return ret;
}
#if 0
static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
static int _usbh_hub_get_hub_ss_descriptor(struct usbh_hub *hub, uint8_t *buffer)
{
struct usb_setup_packet *setup;
int ret;
@@ -103,20 +86,20 @@ static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
setup = hub->parent->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = HUB_REQUEST_GET_STATUS;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 2;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_HUB_SS_DESC;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
if (ret < 0) {
return ret;
}
memcpy(buffer, g_hub_buf, 2);
memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_SS_DESC);
return ret;
}
#endif
#endif
static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
{
@@ -169,6 +152,7 @@ static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t f
return usbh_control_transfer(hub->parent, setup, NULL);
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
{
struct usb_setup_packet *setup;
@@ -184,9 +168,10 @@ static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
return usbh_control_transfer(hub->parent, setup, NULL);
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
{
(void)length;
if (desc->bLength != USB_SIZEOF_HUB_DESC) {
USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
return -1;
@@ -194,15 +179,38 @@ static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length
USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
return -2;
} else {
USB_LOG_RAW("Hub Descriptor:\r\n");
USB_LOG_RAW("bLength: 0x%02x \r\n", desc->bLength);
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
USB_LOG_RAW("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
USB_LOG_RAW("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
USB_LOG_RAW("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
USB_LOG_RAW("PortPwrCtrlMask: 0x%02x \r\n", desc->PortPwrCtrlMask);
USB_LOG_DBG("Hub Descriptor:\r\n");
USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
USB_LOG_DBG("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
USB_LOG_DBG("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
USB_LOG_DBG("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
USB_LOG_DBG("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
USB_LOG_DBG("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
USB_LOG_DBG("PortPwrCtrlMask: 0x%02x \r\n", desc->PortPwrCtrlMask);
}
return 0;
}
static int parse_hub_ss_descriptor(struct usb_hub_ss_descriptor *desc, uint16_t length)
{
(void)length;
if (desc->bLength < USB_SIZEOF_HUB_SS_DESC) {
USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
return -1;
} else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB3) {
USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
return -2;
} else {
USB_LOG_DBG("SuperSpeed Hub Descriptor:\r\n");
USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength);
USB_LOG_DBG("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
USB_LOG_DBG("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
USB_LOG_DBG("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
USB_LOG_DBG("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
USB_LOG_DBG("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
USB_LOG_DBG("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
}
return 0;
}
@@ -230,6 +238,7 @@ int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
{
struct usb_setup_packet roothub_setup;
struct usb_setup_packet *setup;
int ret;
if (hub->is_roothub) {
setup = &roothub_setup;
@@ -238,9 +247,22 @@ int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
setup->wValue = feature;
setup->wIndex = port;
setup->wLength = 0;
return usbh_roothub_control(hub->bus, setup, NULL);
ret = usbh_roothub_control(hub->bus, setup, NULL);
if ((feature == HUB_PORT_FEATURE_RESET) && (ret >= 0)) {
hub->bus->event_handler(hub->bus->busid, hub->index, port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_RESET);
}
return ret;
} else {
return _usbh_hub_set_feature(hub, port, feature);
ret = _usbh_hub_set_feature(hub, port, feature);
if ((feature == HUB_PORT_FEATURE_RESET) && (ret >= 0)) {
hub->bus->event_handler(hub->bus->busid, hub->index, port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_RESET);
}
return ret;
}
}
@@ -262,6 +284,7 @@ int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
}
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
{
struct usb_setup_packet roothub_setup;
@@ -280,23 +303,6 @@ static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
}
}
static void usbh_hubport_release(struct usbh_hubport *child)
{
if (child->connected) {
child->connected = false;
usbh_free_devaddr(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
usbh_kill_urb(&child->ep0_urb);
usb_osal_mutex_delete(child->mutex);
}
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static void hub_int_complete_callback(void *arg, int nbytes)
{
struct usbh_hub *hub = (struct usbh_hub *)arg;
@@ -334,22 +340,70 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
hub->hub_addr = hport->dev_addr;
hub->parent = hport;
hub->bus = hport->bus;
hub->speed = hport->speed;
hport->self = hub;
hport->config.intf[intf].priv = hub;
ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
if (ret < 0) {
return ret;
if (hport->depth > HUB_MAX_DEPTH) {
USB_LOG_ERR("Hub depth(%d) is overflow\r\n", hport->depth);
return -USB_ERR_INVAL;
}
parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
/*
* Super-Speed hubs need to know their depth to be able to
* parse the bits of the route-string that correspond to
* their downstream port number.
*
*/
if ((hport->depth != 0) && (hport->speed == USB_SPEED_SUPER)) {
ret = usbh_hub_set_depth(hub, hport->depth - 1);
if (ret < 0) {
USB_LOG_ERR("Unable to set hub depth \r\n");
return ret;
}
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
/* Get hub descriptor. */
if (hport->speed == USB_SPEED_SUPER) {
ret = _usbh_hub_get_hub_ss_descriptor(hub, (uint8_t *)&hub->hub_ss_desc);
if (ret < 0) {
return ret;
}
parse_hub_ss_descriptor(&hub->hub_ss_desc, USB_SIZEOF_HUB_SS_DESC);
hub->nports = hub->hub_ss_desc.bNbrPorts;
hub->powerdelay = hub->hub_ss_desc.bPwrOn2PwrGood * 2;
hub->tt_think = 0U;
} else {
ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
if (ret < 0) {
return ret;
}
parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
hub->nports = hub->hub_desc.bNbrPorts;
hub->powerdelay = hub->hub_desc.bPwrOn2PwrGood * 2;
hub->tt_think = ((hub->hub_desc.wHubCharacteristics & HUB_CHAR_TTTT_MASK) >> 5);
}
if (hub->nports > CONFIG_USBHOST_MAX_EHPORTS) {
USB_LOG_ERR("Hub nports %u overflow\r\n", hub->nports);
return -USB_ERR_NOMEM;
}
for (uint8_t port = 0; port < hub->nports; port++) {
hub->child[port].port = port + 1;
hub->child[port].parent = hub;
hub->child[port].bus = hport->bus;
}
if (hport->device_desc.bDeviceProtocol == HUB_PROTOCOL_MTT) {
hub->ismtt = 1;
} else {
hub->ismtt = 0;
}
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(hub->intin, ep_desc);
@@ -357,30 +411,18 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
return -1;
}
if (hport->speed == USB_SPEED_SUPER) {
uint16_t depth = 0;
struct usbh_hubport *parent = hport->parent->parent;
while (parent) {
depth++;
parent = parent->parent->parent;
}
ret = usbh_hub_set_depth(hub, depth);
if (ret < 0) {
return ret;
}
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
for (uint8_t port = 0; port < hub->nports; port++) {
ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
if (ret < 0) {
return ret;
}
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
usb_osal_msleep(hub->powerdelay);
for (uint8_t port = 0; port < hub->nports; port++) {
ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
USB_LOG_DBG("port %u, status:0x%03x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
if (ret < 0) {
return ret;
}
@@ -389,13 +431,15 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
hub->connected = true;
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hub->index);
usb_slist_add_tail(&hub->bus->hub_list, &hub->list);
USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
hub->int_buffer = g_hub_intbuf[hub->bus->busid][hub->index - 1];
hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed), hub_int_timeout, hub, 0);
hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed) / 1000, hub_int_timeout, hub, 0);
if (hub->int_timer == NULL) {
USB_LOG_ERR("No memory to alloc int_timer\r\n");
return -USB_ERR_NOMEM;
}
usb_osal_timer_start(hub->int_timer);
return 0;
}
@@ -412,9 +456,11 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_kill_urb(&hub->intin_urb);
}
usb_osal_timer_delete(hub->int_timer);
if (hub->int_timer) {
usb_osal_timer_delete(hub->int_timer);
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
for (uint8_t port = 0; port < hub->nports; port++) {
child = &hub->child[port];
usbh_hubport_release(child);
child->parent = NULL;
@@ -422,7 +468,6 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister HUB Class:%s\r\n", hport->config.intf[intf].devname);
usb_slist_remove(&hub->bus->hub_list, &hub->list);
}
usbh_hub_class_free(hub);
@@ -431,38 +476,30 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
#endif
static void usbh_hubport_enumerate_thread(void *argument)
{
struct usbh_hubport *child = (struct usbh_hubport *)argument;
if (usbh_enumerate(child) < 0) {
/** release child sources */
usbh_hubport_release(child);
USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
}
usb_osal_thread_delete(NULL);
}
static void usbh_hub_events(struct usbh_hub *hub)
{
struct usbh_hubport *child;
struct hub_port_status port_status;
uint8_t portchange_index;
uint16_t portchange_index;
uint16_t portstatus;
uint16_t portchange;
uint16_t mask;
uint16_t feat;
uint8_t speed;
int ret;
size_t flags;
(void)speed_table;
if (!hub->connected) {
return;
}
portchange_index = hub->int_buffer[0];
hub->int_buffer[0] &= ~portchange_index;
flags = usb_osal_enter_critical_section();
memcpy(&portchange_index, hub->int_buffer, 2);
usb_osal_leave_critical_section(flags);
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
for (uint8_t port = 0; port < hub->nports; port++) {
USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
if (!(portchange_index & (1 << (port + 1)))) {
@@ -481,7 +518,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
portstatus = port_status.wPortStatus;
portchange = port_status.wPortChange;
USB_LOG_DBG("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
USB_LOG_DBG("port %u, status:0x%03x, change:0x%02x\r\n", port + 1, portstatus, portchange);
/* First, clear all change bits */
mask = 1;
@@ -516,7 +553,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
portstatus = port_status.wPortStatus;
portchange = port_status.wPortChange;
USB_LOG_DBG("Port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
USB_LOG_DBG("Port %u, status:0x%03x, change:0x%02x\r\n", port + 1, portstatus, portchange);
if (!(portchange & HUB_PORT_STATUS_C_CONNECTION) &&
((portstatus & HUB_PORT_STATUS_CONNECTION) == connection)) {
@@ -544,9 +581,11 @@ static void usbh_hub_events(struct usbh_hub *hub)
/* Last, check connect status */
if (portstatus & HUB_PORT_STATUS_CONNECTION) {
hub->bus->event_handler(hub->bus->busid, hub->index, port + 1, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_CONNECTED);
ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_RESET);
if (ret < 0) {
USB_LOG_ERR("Failed to reset port %u,errorcode:%d\r\n", port, ret);
USB_LOG_ERR("Failed to reset port %u, errorcode: %d\r\n", port + 1, ret);
continue;
}
@@ -560,37 +599,36 @@ static void usbh_hub_events(struct usbh_hub *hub)
portstatus = port_status.wPortStatus;
portchange = port_status.wPortChange;
USB_LOG_DBG("Port %u, status:0x%03x, change:0x%02x\r\n", port + 1, portstatus, portchange);
if (!(portstatus & HUB_PORT_STATUS_RESET) && (portstatus & HUB_PORT_STATUS_ENABLE)) {
if (portchange & HUB_PORT_STATUS_C_RESET) {
ret = usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_RESET);
if (ret < 0) {
USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port, ret);
USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port + 1, ret);
continue;
}
}
if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
speed = USB_SPEED_HIGH;
} else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
speed = USB_SPEED_LOW;
}
#ifdef CONFIG_USBHOST_XHCI
else {
extern uint8_t usbh_get_port_speed(struct usbh_hub * hub, const uint8_t port);
/* USB3.0 speed cannot get from portstatus, checkout port speed instead */
uint8_t super_speed = usbh_get_port_speed(hub, port + 1);
if (super_speed > USB_SPEED_HIGH) {
/* assert that when using USB 3.0 ports, attached device must also be USB 3.0 speed */
speed = super_speed;
/*
* Figure out device speed. This is a bit tricky because
* HUB_PORT_STATUS_POWER_SS and HUB_PORT_STATUS_LOW_SPEED share the same bit.
*/
if (portstatus & HUB_PORT_STATUS_POWER) {
if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
speed = USB_SPEED_HIGH;
} else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
speed = USB_SPEED_LOW;
} else {
speed = USB_SPEED_FULL;
}
} else if (portstatus & HUB_PORT_STATUS_POWER_SS) {
speed = USB_SPEED_SUPER;
} else {
USB_LOG_WRN("Port %u does not enable power\r\n", port + 1);
continue;
}
#else
else {
speed = USB_SPEED_FULL;
}
#endif
child = &hub->child[port];
/** release child sources first */
@@ -598,6 +636,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
memset(child, 0, sizeof(struct usbh_hubport));
child->parent = hub;
child->depth = (hub->parent ? hub->parent->depth : 0) + 1;
child->connected = true;
child->port = port + 1;
child->speed = speed;
@@ -606,8 +645,11 @@ static void usbh_hub_events(struct usbh_hub *hub)
USB_LOG_INFO("New %s device on Bus %u, Hub %u, Port %u connected\r\n", speed_table[speed], hub->bus->busid, hub->index, port + 1);
/* create disposable thread to enumerate device on current hport, do not block hub thread */
usb_osal_thread_create("usbh_enum", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hubport_enumerate_thread, (void *)child);
if (usbh_enumerate(child) < 0) {
/** release child sources */
usbh_hubport_release(child);
USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
}
} else {
child = &hub->child[port];
/** release child sources */
@@ -622,7 +664,6 @@ static void usbh_hub_events(struct usbh_hub *hub)
child = &hub->child[port];
/** release child sources */
usbh_hubport_release(child);
USB_LOG_INFO("Device on Bus %u, Hub %u, Port %u disconnected\r\n", hub->bus->busid, hub->index, port + 1);
}
}
}
@@ -633,20 +674,23 @@ static void usbh_hub_events(struct usbh_hub *hub)
}
}
static void usbh_hub_thread(void *argument)
static void usbh_hub_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
struct usbh_hub *hub;
int ret = 0;
struct usbh_bus *bus = (struct usbh_bus *)argument;
struct usbh_bus *bus = (struct usbh_bus *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
usb_hc_init(bus);
bus->event_handler(bus->busid, USB_HUB_INDEX_ANY, USB_HUB_PORT_ANY, USB_INTERFACE_ANY, USBH_EVENT_INIT);
while (1) {
ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
continue;
}
usb_osal_mutex_take(bus->mutex);
usbh_hub_events(hub);
usb_osal_mutex_give(bus->mutex);
}
}
@@ -658,6 +702,17 @@ void usbh_hub_thread_wakeup(struct usbh_hub *hub)
int usbh_hub_initialize(struct usbh_bus *bus)
{
char thread_name[32] = { 0 };
struct usbh_hub *hub;
hub = &bus->hcd.roothub;
hub->connected = true;
hub->index = 1;
hub->is_roothub = true;
hub->parent = NULL;
hub->hub_addr = 1;
hub->nports = CONFIG_USBHOST_MAX_RHPORTS;
hub->int_buffer = bus->hcd.roothub_intbuf;
hub->bus = bus;
bus->hub_mq = usb_osal_mq_create(7);
if (bus->hub_mq == NULL) {
@@ -665,6 +720,12 @@ int usbh_hub_initialize(struct usbh_bus *bus)
return -1;
}
bus->mutex = usb_osal_mutex_create();
if (bus->mutex == NULL) {
USB_LOG_ERR("Failed to create bus mutex\r\n");
return -1;
}
snprintf(thread_name, 32, "usbh_hub%u", bus->busid);
bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus);
if (bus->hub_thread == NULL) {
@@ -676,30 +737,24 @@ int usbh_hub_initialize(struct usbh_bus *bus)
int usbh_hub_deinitialize(struct usbh_bus *bus)
{
usb_slist_t *hub_list;
struct usbh_hubport *hport;
size_t flags;
struct usbh_hub *hub;
flags = usb_osal_enter_critical_section();
usb_osal_mutex_take(bus->mutex);
hub = &bus->hcd.roothub;
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
usb_slist_for_each(hub_list, &bus->hub_list)
{
struct usbh_hub *hub = usb_slist_entry(hub_list, struct usbh_hub, list);
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hport = &hub->child[port];
usbh_hubport_release(hport);
}
usbh_hubport_release(hport);
}
usb_hc_deinit(bus);
usb_osal_leave_critical_section(flags);
usb_osal_mq_delete(bus->hub_mq);
usb_osal_thread_delete(bus->hub_thread);
usb_osal_mq_delete(bus->hub_mq);
usb_osal_mutex_give(bus->mutex);
usb_osal_mutex_delete(bus->mutex);
return 0;
}
@@ -712,11 +767,10 @@ const struct usbh_class_driver hub_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_HUB,
.subclass = 0,
.protocol = 0,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_HUB,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.id_table = NULL,
.class_driver = &hub_class_driver
};
#endif

View File

@@ -10,10 +10,6 @@
struct usbh_hub;
#define USBH_HUB_MAX_PORTS 4
/* Maximum size of an interrupt IN transfer */
#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -6,6 +6,8 @@
#ifndef USB_MIDI_H
#define USB_MIDI_H
#include "usb_audio.h"
/* bDescriptorSubType */
#define MIDI_VC_HEADER_DESCRIPTOR_SUBTYPE 0x01U
#define MIDI_MS_HEADER_DESCRIPTOR_SUBTYPE 0x01U
@@ -201,6 +203,19 @@ struct midi_cs_ep_ms_general_descriptor {
#define MIDI_SIZEOF_MS_GENERAL_DESC(n) (4 + n)
// clang-format off
#define MIDI_STANDARD_DESCRIPTOR_INIT(bInterfaceNumber, bNumEndpoints) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bInterfaceNumber, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
bNumEndpoints, /* bNumEndpoints */ \
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
AUDIO_SUBCLASS_MIDISTREAMING, /* bInterfaceSubClass */ \
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
0x00 /* iInterface */
#define MIDI_STANDARD_DESCRIPTOR_LEN 0x09
#define MIDI_CS_HEADER_DESCRIPTOR_INIT(wTotalLength) \
0x07, /* bLength */ \
USB_CS_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \

View File

@@ -7,9 +7,10 @@
#include "usbd_core.h"
#include "usbd_msc.h"
#include "usb_scsi.h"
#if defined(CONFIG_USBDEV_MSC_THREAD)
#include "usb_osal.h"
#endif
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbd_msc"
#include "usb_log.h"
#define MSD_OUT_EP_IDX 0
#define MSD_IN_EP_IDX 1
@@ -33,7 +34,7 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
USB_MEM_ALIGNX struct CBW cbw;
USB_MEM_ALIGNX struct CSW csw;
bool readonly;
USB_MEM_ALIGNX bool readonly;
bool popup;
uint8_t sKey; /* Sense key */
uint8_t ASC; /* Additional Sense Code */
@@ -50,11 +51,14 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
usb_osal_mq_t usbd_msc_mq;
usb_osal_thread_t usbd_msc_thread;
uint32_t nbytes;
#elif defined(CONFIG_USBDEV_MSC_POLLING)
uint32_t event;
uint32_t nbytes;
#endif
} g_usbd_msc[CONFIG_USBDEV_MAX_BUS];
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbdev_msc_thread(void *argument);
static void usbdev_msc_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#endif
static void usdb_msc_set_max_lun(uint8_t busid)
@@ -94,21 +98,25 @@ static int msc_storage_class_interface_request_handler(uint8_t busid, struct usb
void msc_storage_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
(void)arg;
switch (event) {
case USBD_EVENT_INIT:
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
g_usbd_msc[busid].usbd_msc_mq = usb_osal_mq_create(1);
if (g_usbd_msc[busid].usbd_msc_mq == NULL) {
USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_mq\r\n");
}
g_usbd_msc[busid].usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, (void *)busid);
g_usbd_msc[busid].usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, (void *)(uint32_t)busid);
if (g_usbd_msc[busid].usbd_msc_thread == NULL) {
USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_thread\r\n");
}
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].event = 0;
#endif
break;
case USBD_EVENT_DEINIT:
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
if (g_usbd_msc[busid].usbd_msc_mq) {
usb_osal_mq_delete(g_usbd_msc[busid].usbd_msc_mq);
}
@@ -500,31 +508,32 @@ static bool SCSI_readCapacity10(uint8_t busid, uint8_t **data, uint32_t *len)
static bool SCSI_read10(uint8_t busid, uint8_t **data, uint32_t *len)
{
(void)data;
(void)len;
if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x80U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
return false;
}
g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
g_usbd_msc[busid].nsectors = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
SCSI_SetSenseData(busid, SCSI_KCQIR_LBAOUTOFRANGE);
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
if (g_usbd_msc[busid].cbw.dDataLength != (g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN])) {
USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
return false;
}
g_usbd_msc[busid].stage = MSC_DATA_IN;
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
return true;
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].event = MSC_DATA_IN;
return true;
#else
return SCSI_processRead(busid);
#endif
@@ -532,31 +541,32 @@ static bool SCSI_read10(uint8_t busid, uint8_t **data, uint32_t *len)
static bool SCSI_read12(uint8_t busid, uint8_t **data, uint32_t *len)
{
(void)data;
(void)len;
if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x80U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
return false;
}
g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
g_usbd_msc[busid].nsectors = GET_BE32(&g_usbd_msc[busid].cbw.CB[6]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
SCSI_SetSenseData(busid, SCSI_KCQIR_LBAOUTOFRANGE);
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
if (g_usbd_msc[busid].cbw.dDataLength != (g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN])) {
USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
return false;
}
g_usbd_msc[busid].stage = MSC_DATA_IN;
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
return true;
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].event = MSC_DATA_IN;
return true;
#else
return SCSI_processRead(busid);
#endif
@@ -565,20 +575,20 @@ static bool SCSI_read12(uint8_t busid, uint8_t **data, uint32_t *len)
static bool SCSI_write10(uint8_t busid, uint8_t **data, uint32_t *len)
{
uint32_t data_len = 0;
(void)data;
(void)len;
if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
return false;
}
g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
g_usbd_msc[busid].nsectors = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
data_len = g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
@@ -594,20 +604,20 @@ static bool SCSI_write10(uint8_t busid, uint8_t **data, uint32_t *len)
static bool SCSI_write12(uint8_t busid, uint8_t **data, uint32_t *len)
{
uint32_t data_len = 0;
(void)data;
(void)len;
if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
return false;
}
g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
g_usbd_msc[busid].nsectors = GET_BE32(&g_usbd_msc[busid].cbw.CB[6]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
data_len = g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
@@ -619,52 +629,6 @@ static bool SCSI_write12(uint8_t busid, uint8_t **data, uint32_t *len)
usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, data_len);
return true;
}
/* do not use verify to reduce code size */
#if 0
static bool SCSI_verify10(uint8_t busid, uint8_t **data, uint32_t *len)
{
/* Logical Block Address of First Block */
uint32_t lba = 0;
uint32_t blk_num = 0;
if ((g_usbd_msc[busid].cbw.CB[1] & 0x02U) == 0x00U) {
return true;
}
if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
return false;
}
if ((g_usbd_msc[busid].cbw.CB[1] & 0x02U) == 0x02U) {
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDFIELDINCBA);
return false; /* Error, Verify Mode Not supported*/
}
lba = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]);
USB_LOG_DBG("lba: 0x%x\r\n", lba);
g_usbd_msc[busid].scsi_blk_addr = lba * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
/* Number of Blocks to transfer */
blk_num = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]);
USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
g_usbd_msc[busid].scsi_blk_len = blk_num * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
if ((lba + blk_num) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
if (g_usbd_msc[busid].cbw.dDataLength != g_usbd_msc[busid].scsi_blk_len) {
return false;
}
g_usbd_msc[busid].stage = MSC_DATA_OUT;
return true;
}
#endif
static bool SCSI_processRead(uint8_t busid)
{
@@ -695,6 +659,7 @@ static bool SCSI_processRead(uint8_t busid)
static bool SCSI_processWrite(uint8_t busid, uint32_t nbytes)
{
uint32_t data_len = 0;
USB_LOG_DBG("write lba:%d\r\n", g_usbd_msc[busid].start_sector);
if (usbd_msc_sector_write(busid, g_usbd_msc[busid].cbw.bLUN, g_usbd_msc[busid].start_sector, g_usbd_msc[busid].block_buffer, nbytes) != 0) {
@@ -777,13 +742,13 @@ static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes)
ret = SCSI_write12(busid, NULL, 0);
break;
case SCSI_CMD_VERIFY10:
//ret = SCSI_verify10(NULL, 0);
ret = false;
break;
case SCSI_CMD_SYNCHCACHE10:
ret = true;
break;
default:
SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
USB_LOG_WRN("unsupported cmd:0x%02x\r\n", g_usbd_msc[busid].cbw.CB[0]);
ret = false;
break;
}
@@ -791,7 +756,7 @@ static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes)
if (ret) {
if (g_usbd_msc[busid].stage == MSC_READ_CBW) {
if (len2send) {
USB_LOG_DBG("Send info len:%d\r\n", len2send);
USB_LOG_DBG("Send info len: %d\r\n", len2send);
usbd_msc_send_info(busid, buf2send, len2send);
} else {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_PASSED);
@@ -803,10 +768,12 @@ static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes)
void mass_storage_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)ep;
switch (g_usbd_msc[busid].stage) {
case MSC_READ_CBW:
if (SCSI_CBWDecode(busid, nbytes) == false) {
USB_LOG_ERR("Command:0x%02x decode err\r\n", g_usbd_msc[busid].cbw.CB[0]);
USB_LOG_ERR("Command: 0x%02x decode err\r\n", g_usbd_msc[busid].cbw.CB[0]);
usbd_msc_bot_abort(busid);
return;
}
@@ -815,9 +782,12 @@ void mass_storage_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
switch (g_usbd_msc[busid].cbw.CB[0]) {
case SCSI_CMD_WRITE10:
case SCSI_CMD_WRITE12:
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
g_usbd_msc[busid].nbytes = nbytes;
usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_OUT);
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].nbytes = nbytes;
g_usbd_msc[busid].event = MSC_DATA_OUT;
#else
if (SCSI_processWrite(busid, nbytes) == false) {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
@@ -835,13 +805,18 @@ void mass_storage_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
void mass_storage_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)ep;
(void)nbytes;
switch (g_usbd_msc[busid].stage) {
case MSC_DATA_IN:
switch (g_usbd_msc[busid].cbw.CB[0]) {
case SCSI_CMD_READ10:
case SCSI_CMD_READ12:
#ifdef CONFIG_USBDEV_MSC_THREAD
#if defined(CONFIG_USBDEV_MSC_THREAD)
usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].event = MSC_DATA_IN;
#else
if (SCSI_processRead(busid) == false) {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
@@ -870,19 +845,39 @@ void mass_storage_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
}
}
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbdev_msc_thread(void *argument)
#if defined(CONFIG_USBDEV_MSC_THREAD)
static void usbdev_msc_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uintptr_t event;
int ret;
uint8_t busid = (uint8_t)argument;
uint8_t busid = (uint8_t)CONFIG_USB_OSAL_THREAD_GET_ARGV;
while (1) {
ret = usb_osal_mq_recv(g_usbd_msc[busid].usbd_msc_mq, (uintptr_t *)&event, USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
continue;
}
USB_LOG_DBG("%d\r\n", event);
if (event == MSC_DATA_OUT) {
if (SCSI_processWrite(busid, g_usbd_msc[busid].nbytes) == false) {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
}
} else if (event == MSC_DATA_IN) {
if (SCSI_processRead(busid) == false) {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
}
} else {
}
}
}
#elif defined(CONFIG_USBDEV_MSC_POLLING)
void usbd_msc_polling(uint8_t busid)
{
uint8_t event;
event = g_usbd_msc[busid].event;
if (event != 0) {
g_usbd_msc[busid].event = 0;
if (event == MSC_DATA_OUT) {
if (SCSI_processWrite(busid, g_usbd_msc[busid].nbytes) == false) {
usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
@@ -918,9 +913,10 @@ struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *
for (uint8_t i = 0u; i <= g_usbd_msc[busid].max_lun; i++) {
usbd_msc_get_cap(busid, i, &g_usbd_msc[busid].scsi_blk_nbr[i], &g_usbd_msc[busid].scsi_blk_size[i]);
if (g_usbd_msc[busid].scsi_blk_size[i] > CONFIG_USBDEV_MSC_MAX_BUFSIZE) {
USB_LOG_ERR("msc block buffer overflow\r\n");
return NULL;
if (CONFIG_USBDEV_MSC_MAX_BUFSIZE % g_usbd_msc[busid].scsi_blk_size[i]) {
USB_LOG_ERR("CONFIG_USBDEV_MSC_MAX_BUFSIZE must be a multiple of block size\r\n");
while (1) {
}
}
}
@@ -932,7 +928,38 @@ void usbd_msc_set_readonly(uint8_t busid, bool readonly)
g_usbd_msc[busid].readonly = readonly;
}
bool usbd_msc_set_popup(uint8_t busid)
bool usbd_msc_get_popup(uint8_t busid)
{
return g_usbd_msc[busid].popup;
}
__WEAK void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
(void)busid;
(void)lun;
*block_num = 0;
*block_size = 0;
}
__WEAK int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
(void)sector;
(void)buffer;
(void)length;
return 0;
}
__WEAK int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
(void)sector;
(void)buffer;
(void)length;
return 0;
}

View File

@@ -23,7 +23,9 @@ int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *b
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
void usbd_msc_set_readonly(uint8_t busid, bool readonly);
bool usbd_msc_set_popup(uint8_t busid);
bool usbd_msc_get_popup(uint8_t busid);
void usbd_msc_polling(uint8_t busid);
#ifdef __cplusplus
}

View File

@@ -13,7 +13,12 @@
#define DEV_FORMAT "/dev/sd%c"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_buf[64];
#ifndef CONFIG_USBHOST_MSC_READY_CHECK_TIMES
#define CONFIG_USBHOST_MSC_READY_CHECK_TIMES 10
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_cbw_csw[CONFIG_USBHOST_MAX_MSC_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_buf[CONFIG_USBHOST_MAX_MSC_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_msc g_msc_class[CONFIG_USBHOST_MAX_MSC_CLASS];
static uint32_t g_devinuse = 0;
@@ -21,11 +26,11 @@ static struct usbh_msc_modeswitch_config *g_msc_modeswitch_config = NULL;
static struct usbh_msc *usbh_msc_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_MSC_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_msc_class[devno], 0, sizeof(struct usbh_msc));
g_msc_class[devno].sdchar = 'a' + devno;
return &g_msc_class[devno];
@@ -36,17 +41,22 @@ static struct usbh_msc *usbh_msc_class_alloc(void)
static void usbh_msc_class_free(struct usbh_msc *msc_class)
{
int devno = msc_class->sdchar - 'a';
uint8_t devno = msc_class->sdchar - 'a';
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(msc_class, 0, sizeof(struct usbh_msc));
}
static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
{
struct usb_setup_packet *setup = msc_class->hport->setup;
struct usb_setup_packet *setup;
if (!msc_class || !msc_class->hport) {
return -USB_ERR_INVAL;
}
setup = msc_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = MSC_REQUEST_GET_MAX_LUN;
@@ -80,6 +90,8 @@ static void usbh_msc_cbw_dump(struct CBW *cbw)
static void usbh_msc_csw_dump(struct CSW *csw)
{
(void)csw;
USB_LOG_DBG("CSW:\r\n");
USB_LOG_DBG(" signature: 0x%08x\r\n", (unsigned int)csw->dSignature);
USB_LOG_DBG(" tag: 0x%08x\r\n", (unsigned int)csw->dTag);
@@ -113,44 +125,44 @@ static inline int usbh_msc_bulk_out_transfer(struct usbh_msc *msc_class, uint8_t
return ret;
}
static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, struct CSW *csw, uint8_t *buffer)
static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, struct CSW *csw, uint8_t *buffer, uint32_t timeout)
{
int nbytes;
usbh_msc_cbw_dump(cbw);
/* Send the CBW */
nbytes = usbh_msc_bulk_out_transfer(msc_class, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
nbytes = usbh_msc_bulk_out_transfer(msc_class, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, timeout);
if (nbytes < 0) {
USB_LOG_ERR("cbw transfer error\r\n");
USB_LOG_ERR("cbw transfer error: %d\r\n", nbytes);
goto __err_exit;
}
if (cbw->dDataLength != 0) {
if (cbw->CB[0] == SCSI_CMD_WRITE10) {
nbytes = usbh_msc_bulk_out_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
nbytes = usbh_msc_bulk_out_transfer(msc_class, buffer, cbw->dDataLength, timeout);
} else if (cbw->CB[0] == SCSI_CMD_READCAPACITY10) {
nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, timeout);
if (nbytes >= 0) {
/* Save the capacity information */
msc_class->blocknum = GET_BE32(&buffer[0]) + 1;
msc_class->blocksize = GET_BE32(&buffer[4]);
}
} else {
nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, timeout);
}
if (nbytes < 0) {
USB_LOG_ERR("msc data transfer error\r\n");
USB_LOG_ERR("msc data transfer error: %d\r\n", nbytes);
goto __err_exit;
}
}
/* Receive the CSW */
memset(csw, 0, USB_SIZEOF_MSC_CSW);
nbytes = usbh_msc_bulk_in_transfer(msc_class, (uint8_t *)csw, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
nbytes = usbh_msc_bulk_in_transfer(msc_class, (uint8_t *)csw, USB_SIZEOF_MSC_CSW, timeout);
if (nbytes < 0) {
USB_LOG_ERR("csw transfer error\r\n");
USB_LOG_ERR("csw transfer error: %d\r\n", nbytes);
goto __err_exit;
}
@@ -175,14 +187,14 @@ static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
cbw->bCBLength = SCSICMD_TESTUNITREADY_SIZEOF;
cbw->CB[0] = SCSI_CMD_TESTUNITREADY;
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, NULL);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], NULL, CONFIG_USBHOST_MSC_TIMEOUT);
}
static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
@@ -190,7 +202,7 @@ static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -200,7 +212,7 @@ static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
cbw->CB[0] = SCSI_CMD_REQUESTSENSE;
cbw->CB[4] = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], CONFIG_USBHOST_MSC_TIMEOUT);
}
static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
@@ -208,7 +220,7 @@ static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -218,7 +230,7 @@ static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
cbw->CB[0] = SCSI_CMD_INQUIRY;
cbw->CB[4] = SCSIRESP_INQUIRY_SIZEOF;
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], CONFIG_USBHOST_MSC_TIMEOUT);
}
static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
@@ -226,7 +238,7 @@ static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -235,7 +247,7 @@ static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
cbw->bCBLength = SCSICMD_READCAPACITY10_SIZEOF;
cbw->CB[0] = SCSI_CMD_READCAPACITY10;
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], CONFIG_USBHOST_MSC_TIMEOUT);
}
static inline void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
@@ -243,18 +255,18 @@ static inline void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memcpy(g_msc_buf, message, 31);
memcpy(g_msc_cbw_csw[msc_class->sdchar - 'a'], message, 31);
usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, NULL);
usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], NULL, CONFIG_USBHOST_MSC_TIMEOUT);
}
static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
struct usbh_msc_modeswitch_config *config;
int ret;
struct usbh_msc *msc_class = usbh_msc_class_alloc();
if (msc_class == NULL) {
@@ -267,12 +279,18 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
hport->config.intf[intf].priv = msc_class;
ret = usbh_msc_get_maxlun(msc_class, g_msc_buf);
ret = usbh_msc_get_maxlun(msc_class, g_msc_buf[msc_class->sdchar - 'a']);
if (ret < 0) {
return ret;
if (ret == -USB_ERR_STALL) {
USB_LOG_WRN("Device does not support multiple LUNs\r\n");
g_msc_buf[msc_class->sdchar - 'a'][0] = 0;
ret = 0;
} else {
return ret;
}
}
USB_LOG_INFO("Get max LUN:%u\r\n", g_msc_buf[0] + 1);
USB_LOG_INFO("Get max LUN:%u\r\n", g_msc_buf[msc_class->sdchar - 'a'][0] + 1);
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
@@ -301,34 +319,6 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
}
}
ret = usbh_msc_scsi_testunitready(msc_class);
if (ret < 0) {
ret = usbh_msc_scsi_requestsense(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_testunitready\r\n");
return ret;
}
}
ret = usbh_msc_scsi_inquiry(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_inquiry\r\n");
return ret;
}
ret = usbh_msc_scsi_readcapacity10(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_readcapacity10\r\n");
return ret;
}
if (msc_class->blocksize > 0) {
USB_LOG_INFO("Capacity info:\r\n");
USB_LOG_INFO("Block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
} else {
USB_LOG_ERR("Invalid block size\r\n");
return -USB_ERR_RANGE;
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);
USB_LOG_INFO("Register MSC Class:%s\r\n", hport->config.intf[intf].devname);
@@ -353,6 +343,7 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister MSC Class:%s\r\n", hport->config.intf[intf].devname);
usbh_msc_stop(msc_class);
}
@@ -363,13 +354,52 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
int usbh_msc_scsi_init(struct usbh_msc *msc_class)
{
int ret;
uint16_t cnt;
cnt = 0;
while (usbh_msc_scsi_testunitready(msc_class) < 0) {
USB_LOG_WRN("Device not ready, try again...\r\n");
ret = usbh_msc_scsi_requestsense(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_testunitready\r\n");
}
cnt++;
if (cnt > CONFIG_USBHOST_MSC_READY_CHECK_TIMES) {
return -USB_ERR_NODEV;
}
}
ret = usbh_msc_scsi_inquiry(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_inquiry\r\n");
return ret;
}
ret = usbh_msc_scsi_readcapacity10(msc_class);
if (ret < 0) {
USB_LOG_ERR("Fail to scsi_readcapacity10\r\n");
return ret;
}
if (msc_class->blocksize > 0) {
USB_LOG_INFO("Capacity info:\r\n");
USB_LOG_INFO("Block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
} else {
USB_LOG_ERR("Invalid block size\r\n");
return -USB_ERR_RANGE;
}
return 0;
}
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
{
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -380,7 +410,7 @@ int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, con
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], (uint8_t *)buffer, CONFIG_USBHOST_MSC_TIMEOUT);
}
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
@@ -388,7 +418,7 @@ int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, cons
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
cbw = (struct CBW *)g_msc_cbw_csw[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -400,7 +430,7 @@ int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, cons
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_cbw_csw[msc_class->sdchar - 'a'], (uint8_t *)buffer, CONFIG_USBHOST_MSC_TIMEOUT);
}
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
@@ -414,10 +444,12 @@ void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
__WEAK void usbh_msc_run(struct usbh_msc *msc_class)
{
(void)msc_class;
}
__WEAK void usbh_msc_stop(struct usbh_msc *msc_class)
{
(void)msc_class;
}
const struct usbh_class_driver msc_class_driver = {
@@ -428,10 +460,9 @@ const struct usbh_class_driver msc_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info msc_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_MASS_STORAGE,
.subclass = MSC_SUBCLASS_SCSI,
.protocol = MSC_PROTOCOL_BULK_ONLY,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_MASS_STORAGE,
.bInterfaceSubClass = MSC_SUBCLASS_SCSI,
.bInterfaceProtocol = MSC_PROTOCOL_BULK_ONLY,
.id_table = NULL,
.class_driver = &msc_class_driver
};

View File

@@ -20,6 +20,8 @@ struct usbh_msc {
uint8_t sdchar;
uint32_t blocknum; /* Number of blocks on the USB mass storage device */
uint16_t blocksize; /* Block size of USB mass storage device */
void *user_data;
};
struct usbh_msc_modeswitch_config {
@@ -30,6 +32,7 @@ struct usbh_msc_modeswitch_config {
};
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config);
int usbh_msc_scsi_init(struct usbh_msc *msc_class);
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);

682
class/mtp/usb_mtp.h Normal file
View File

@@ -0,0 +1,682 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USB_MTP_H
#define USB_MTP_H
// clang-format off
#define MTP_STANDARD_VERSION 100
// Container Types
#define MTP_CONTAINER_TYPE_UNDEFINED 0
#define MTP_CONTAINER_TYPE_COMMAND 1
#define MTP_CONTAINER_TYPE_DATA 2
#define MTP_CONTAINER_TYPE_RESPONSE 3
#define MTP_CONTAINER_TYPE_EVENT 4
// Container Offsets
#define MTP_CONTAINER_LENGTH_OFFSET 0
#define MTP_CONTAINER_TYPE_OFFSET 4
#define MTP_CONTAINER_CODE_OFFSET 6
#define MTP_CONTAINER_TRANSACTION_ID_OFFSET 8
#define MTP_CONTAINER_PARAMETER_OFFSET 12
#define MTP_CONTAINER_HEADER_SIZE 12
// Maximum buffer size for a MTP packet.
#define MTP_BUFFER_SIZE 16384
// MTP Data Types
#define MTP_TYPE_UNDEFINED 0x0000 // Undefined
#define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer
#define MTP_TYPE_UINT8 0x0002 // Unsigned 8-bit integer
#define MTP_TYPE_INT16 0x0003 // Signed 16-bit integer
#define MTP_TYPE_UINT16 0x0004 // Unsigned 16-bit integer
#define MTP_TYPE_INT32 0x0005 // Signed 32-bit integer
#define MTP_TYPE_UINT32 0x0006 // Unsigned 32-bit integer
#define MTP_TYPE_INT64 0x0007 // Signed 64-bit integer
#define MTP_TYPE_UINT64 0x0008 // Unsigned 64-bit integer
#define MTP_TYPE_INT128 0x0009 // Signed 128-bit integer
#define MTP_TYPE_UINT128 0x000A // Unsigned 128-bit integer
#define MTP_TYPE_AINT8 0x4001 // Array of signed 8-bit integers
#define MTP_TYPE_AUINT8 0x4002 // Array of unsigned 8-bit integers
#define MTP_TYPE_AINT16 0x4003 // Array of signed 16-bit integers
#define MTP_TYPE_AUINT16 0x4004 // Array of unsigned 16-bit integers
#define MTP_TYPE_AINT32 0x4005 // Array of signed 32-bit integers
#define MTP_TYPE_AUINT32 0x4006 // Array of unsigned 32-bit integers
#define MTP_TYPE_AINT64 0x4007 // Array of signed 64-bit integers
#define MTP_TYPE_AUINT64 0x4008 // Array of unsigned 64-bit integers
#define MTP_TYPE_AINT128 0x4009 // Array of signed 128-bit integers
#define MTP_TYPE_AUINT128 0x400A // Array of unsigned 128-bit integers
#define MTP_TYPE_STR 0xFFFF // Variable-length Unicode string
// MTP Format Codes
#define MTP_FORMAT_UNDEFINED 0x3000 // Undefined object
#define MTP_FORMAT_ASSOCIATION 0x3001 // Association (for example, a folder)
#define MTP_FORMAT_SCRIPT 0x3002 // Device model-specific script
#define MTP_FORMAT_EXECUTABLE 0x3003 // Device model-specific binary executable
#define MTP_FORMAT_TEXT 0x3004 // Text file
#define MTP_FORMAT_HTML 0x3005 // Hypertext Markup Language file (text)
#define MTP_FORMAT_DPOF 0x3006 // Digital Print Order Format file (text)
#define MTP_FORMAT_AIFF 0x3007 // Audio clip
#define MTP_FORMAT_WAV 0x3008 // Audio clip
#define MTP_FORMAT_MP3 0x3009 // Audio clip
#define MTP_FORMAT_AVI 0x300A // Video clip
#define MTP_FORMAT_MPEG 0x300B // Video clip
#define MTP_FORMAT_ASF 0x300C // Microsoft Advanced Streaming Format (video)
#define MTP_FORMAT_DEFINED 0x3800 // Unknown image object
#define MTP_FORMAT_EXIF_JPEG 0x3801 // Exchangeable File Format, JEIDA standard
#define MTP_FORMAT_TIFF_EP 0x3802 // Tag Image File Format for Electronic Photography
#define MTP_FORMAT_FLASHPIX 0x3803 // Structured Storage Image Format
#define MTP_FORMAT_BMP 0x3804 // Microsoft Windows Bitmap file
#define MTP_FORMAT_CIFF 0x3805 // Canon Camera Image File Format
#define MTP_FORMAT_GIF 0x3807 // Graphics Interchange Format
#define MTP_FORMAT_JFIF 0x3808 // JPEG File Interchange Format
#define MTP_FORMAT_CD 0x3809 // PhotoCD Image Pac
#define MTP_FORMAT_PICT 0x380A // Quickdraw Image Format
#define MTP_FORMAT_PNG 0x380B // Portable Network Graphics
#define MTP_FORMAT_TIFF 0x380D // Tag Image File Format
#define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts)
#define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format
#define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format
#define MTP_FORMAT_DNG 0x3811 // Digital Negative
#define MTP_FORMAT_HEIF 0x3812 // HEIF images
#define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802
#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
#define MTP_FORMAT_UNDEFINED_AUDIO 0xB900
#define MTP_FORMAT_WMA 0xB901
#define MTP_FORMAT_OGG 0xB902
#define MTP_FORMAT_AAC 0xB903
#define MTP_FORMAT_AUDIBLE 0xB904
#define MTP_FORMAT_FLAC 0xB906
#define MTP_FORMAT_UNDEFINED_VIDEO 0xB980
#define MTP_FORMAT_WMV 0xB981
#define MTP_FORMAT_MP4_CONTAINER 0xB982 // ISO 14496-1
#define MTP_FORMAT_MP2 0xB983
#define MTP_FORMAT_3GP_CONTAINER 0xB984 // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d).
#define MTP_FORMAT_UNDEFINED_COLLECTION 0xBA00
#define MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01
#define MTP_FORMAT_ABSTRACT_IMAGE_ALBUM 0xBA02
#define MTP_FORMAT_ABSTRACT_AUDIO_ALBUM 0xBA03
#define MTP_FORMAT_ABSTRACT_VIDEO_ALBUM 0xBA04
#define MTP_FORMAT_ABSTRACT_AV_PLAYLIST 0xBA05
#define MTP_FORMAT_ABSTRACT_CONTACT_GROUP 0xBA06
#define MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER 0xBA07
#define MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION 0xBA08
#define MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST 0xBA09
#define MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST 0xBA0A
#define MTP_FORMAT_ABSTRACT_MEDIACAST 0xBA0B // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content
#define MTP_FORMAT_WPL_PLAYLIST 0xBA10
#define MTP_FORMAT_M3U_PLAYLIST 0xBA11
#define MTP_FORMAT_MPL_PLAYLIST 0xBA12
#define MTP_FORMAT_ASX_PLAYLIST 0xBA13
#define MTP_FORMAT_PLS_PLAYLIST 0xBA14
#define MTP_FORMAT_UNDEFINED_DOCUMENT 0xBA80
#define MTP_FORMAT_ABSTRACT_DOCUMENT 0xBA81
#define MTP_FORMAT_XML_DOCUMENT 0xBA82
#define MTP_FORMAT_MS_WORD_DOCUMENT 0xBA83
#define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT 0xBA84
#define MTP_FORMAT_MS_EXCEL_SPREADSHEET 0xBA85
#define MTP_FORMAT_MS_POWERPOINT_PRESENTATION 0xBA86
#define MTP_FORMAT_UNDEFINED_MESSAGE 0xBB00
#define MTP_FORMAT_ABSTRACT_MESSSAGE 0xBB01
#define MTP_FORMAT_UNDEFINED_CONTACT 0xBB80
#define MTP_FORMAT_ABSTRACT_CONTACT 0xBB81
#define MTP_FORMAT_VCARD_2 0xBB82
// MTP Object Property Codes
#define MTP_PROPERTY_STORAGE_ID 0xDC01
#define MTP_PROPERTY_OBJECT_FORMAT 0xDC02
#define MTP_PROPERTY_PROTECTION_STATUS 0xDC03
#define MTP_PROPERTY_OBJECT_SIZE 0xDC04
#define MTP_PROPERTY_ASSOCIATION_TYPE 0xDC05
#define MTP_PROPERTY_ASSOCIATION_DESC 0xDC06
#define MTP_PROPERTY_OBJECT_FILE_NAME 0xDC07
#define MTP_PROPERTY_DATE_CREATED 0xDC08
#define MTP_PROPERTY_DATE_MODIFIED 0xDC09
#define MTP_PROPERTY_KEYWORDS 0xDC0A
#define MTP_PROPERTY_PARENT_OBJECT 0xDC0B
#define MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS 0xDC0C
#define MTP_PROPERTY_HIDDEN 0xDC0D
#define MTP_PROPERTY_SYSTEM_OBJECT 0xDC0E
#define MTP_PROPERTY_PERSISTENT_UID 0xDC41
#define MTP_PROPERTY_SYNC_ID 0xDC42
#define MTP_PROPERTY_PROPERTY_BAG 0xDC43
#define MTP_PROPERTY_NAME 0xDC44
#define MTP_PROPERTY_CREATED_BY 0xDC45
#define MTP_PROPERTY_ARTIST 0xDC46
#define MTP_PROPERTY_DATE_AUTHORED 0xDC47
#define MTP_PROPERTY_DESCRIPTION 0xDC48
#define MTP_PROPERTY_URL_REFERENCE 0xDC49
#define MTP_PROPERTY_LANGUAGE_LOCALE 0xDC4A
#define MTP_PROPERTY_COPYRIGHT_INFORMATION 0xDC4B
#define MTP_PROPERTY_SOURCE 0xDC4C
#define MTP_PROPERTY_ORIGIN_LOCATION 0xDC4D
#define MTP_PROPERTY_DATE_ADDED 0xDC4E
#define MTP_PROPERTY_NON_CONSUMABLE 0xDC4F
#define MTP_PROPERTY_CORRUPT_UNPLAYABLE 0xDC50
#define MTP_PROPERTY_PRODUCER_SERIAL_NUMBER 0xDC51
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT 0xDC81
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE 0xDC82
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT 0xDC83
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH 0xDC84
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION 0xDC85
#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA 0xDC86
#define MTP_PROPERTY_WIDTH 0xDC87
#define MTP_PROPERTY_HEIGHT 0xDC88
#define MTP_PROPERTY_DURATION 0xDC89
#define MTP_PROPERTY_RATING 0xDC8A
#define MTP_PROPERTY_TRACK 0xDC8B
#define MTP_PROPERTY_GENRE 0xDC8C
#define MTP_PROPERTY_CREDITS 0xDC8D
#define MTP_PROPERTY_LYRICS 0xDC8E
#define MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID 0xDC8F
#define MTP_PROPERTY_PRODUCED_BY 0xDC90
#define MTP_PROPERTY_USE_COUNT 0xDC91
#define MTP_PROPERTY_SKIP_COUNT 0xDC92
#define MTP_PROPERTY_LAST_ACCESSED 0xDC93
#define MTP_PROPERTY_PARENTAL_RATING 0xDC94
#define MTP_PROPERTY_META_GENRE 0xDC95
#define MTP_PROPERTY_COMPOSER 0xDC96
#define MTP_PROPERTY_EFFECTIVE_RATING 0xDC97
#define MTP_PROPERTY_SUBTITLE 0xDC98
#define MTP_PROPERTY_ORIGINAL_RELEASE_DATE 0xDC99
#define MTP_PROPERTY_ALBUM_NAME 0xDC9A
#define MTP_PROPERTY_ALBUM_ARTIST 0xDC9B
#define MTP_PROPERTY_MOOD 0xDC9C
#define MTP_PROPERTY_DRM_STATUS 0xDC9D
#define MTP_PROPERTY_SUB_DESCRIPTION 0xDC9E
#define MTP_PROPERTY_IS_CROPPED 0xDCD1
#define MTP_PROPERTY_IS_COLOUR_CORRECTED 0xDCD2
#define MTP_PROPERTY_IMAGE_BIT_DEPTH 0xDCD3
#define MTP_PROPERTY_F_NUMBER 0xDCD4
#define MTP_PROPERTY_EXPOSURE_TIME 0xDCD5
#define MTP_PROPERTY_EXPOSURE_INDEX 0xDCD6
#define MTP_PROPERTY_TOTAL_BITRATE 0xDE91
#define MTP_PROPERTY_BITRATE_TYPE 0xDE92
#define MTP_PROPERTY_SAMPLE_RATE 0xDE93
#define MTP_PROPERTY_NUMBER_OF_CHANNELS 0xDE94
#define MTP_PROPERTY_AUDIO_BIT_DEPTH 0xDE95
#define MTP_PROPERTY_SCAN_TYPE 0xDE97
#define MTP_PROPERTY_AUDIO_WAVE_CODEC 0xDE99
#define MTP_PROPERTY_AUDIO_BITRATE 0xDE9A
#define MTP_PROPERTY_VIDEO_FOURCC_CODEC 0xDE9B
#define MTP_PROPERTY_VIDEO_BITRATE 0xDE9C
#define MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS 0xDE9D
#define MTP_PROPERTY_KEYFRAME_DISTANCE 0xDE9E
#define MTP_PROPERTY_BUFFER_SIZE 0xDE9F
#define MTP_PROPERTY_ENCODING_QUALITY 0xDEA0
#define MTP_PROPERTY_ENCODING_PROFILE 0xDEA1
#define MTP_PROPERTY_DISPLAY_NAME 0xDCE0
#define MTP_PROPERTY_BODY_TEXT 0xDCE1
#define MTP_PROPERTY_SUBJECT 0xDCE2
#define MTP_PROPERTY_PRIORITY 0xDCE3
#define MTP_PROPERTY_GIVEN_NAME 0xDD00
#define MTP_PROPERTY_MIDDLE_NAMES 0xDD01
#define MTP_PROPERTY_FAMILY_NAME 0xDD02
#define MTP_PROPERTY_PREFIX 0xDD03
#define MTP_PROPERTY_SUFFIX 0xDD04
#define MTP_PROPERTY_PHONETIC_GIVEN_NAME 0xDD05
#define MTP_PROPERTY_PHONETIC_FAMILY_NAME 0xDD06
#define MTP_PROPERTY_EMAIL_PRIMARY 0xDD07
#define MTP_PROPERTY_EMAIL_PERSONAL_1 0xDD08
#define MTP_PROPERTY_EMAIL_PERSONAL_2 0xDD09
#define MTP_PROPERTY_EMAIL_BUSINESS_1 0xDD0A
#define MTP_PROPERTY_EMAIL_BUSINESS_2 0xDD0B
#define MTP_PROPERTY_EMAIL_OTHERS 0xDD0C
#define MTP_PROPERTY_PHONE_NUMBER_PRIMARY 0xDD0D
#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL 0xDD0E
#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2 0xDD0F
#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS 0xDD10
#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2 0xDD11
#define MTP_PROPERTY_PHONE_NUMBER_MOBILE 0xDD12
#define MTP_PROPERTY_PHONE_NUMBER_MOBILE_2 0xDD13
#define MTP_PROPERTY_FAX_NUMBER_PRIMARY 0xDD14
#define MTP_PROPERTY_FAX_NUMBER_PERSONAL 0xDD15
#define MTP_PROPERTY_FAX_NUMBER_BUSINESS 0xDD16
#define MTP_PROPERTY_PAGER_NUMBER 0xDD17
#define MTP_PROPERTY_PHONE_NUMBER_OTHERS 0xDD18
#define MTP_PROPERTY_PRIMARY_WEB_ADDRESS 0xDD19
#define MTP_PROPERTY_PERSONAL_WEB_ADDRESS 0xDD1A
#define MTP_PROPERTY_BUSINESS_WEB_ADDRESS 0xDD1B
#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS 0xDD1C
#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2 0xDD1D
#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3 0xDD1E
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL 0xDD1F
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1 0xDD20
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2 0xDD21
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY 0xDD22
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION 0xDD23
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE 0xDD24
#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY 0xDD25
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL 0xDD26
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1 0xDD27
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2 0xDD28
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY 0xDD29
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION 0xDD2A
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE 0xDD2B
#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY 0xDD2C
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL 0xDD2D
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1 0xDD2E
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2 0xDD2F
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY 0xDD30
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION 0xDD31
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE 0xDD32
#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY 0xDD33
#define MTP_PROPERTY_ORGANIZATION_NAME 0xDD34
#define MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME 0xDD35
#define MTP_PROPERTY_ROLE 0xDD36
#define MTP_PROPERTY_BIRTHDATE 0xDD37
#define MTP_PROPERTY_MESSAGE_TO 0xDD40
#define MTP_PROPERTY_MESSAGE_CC 0xDD41
#define MTP_PROPERTY_MESSAGE_BCC 0xDD42
#define MTP_PROPERTY_MESSAGE_READ 0xDD43
#define MTP_PROPERTY_MESSAGE_RECEIVED_TIME 0xDD44
#define MTP_PROPERTY_MESSAGE_SENDER 0xDD45
#define MTP_PROPERTY_ACTIVITY_BEGIN_TIME 0xDD50
#define MTP_PROPERTY_ACTIVITY_END_TIME 0xDD51
#define MTP_PROPERTY_ACTIVITY_LOCATION 0xDD52
#define MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES 0xDD54
#define MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES 0xDD55
#define MTP_PROPERTY_ACTIVITY_RESOURCES 0xDD56
#define MTP_PROPERTY_ACTIVITY_ACCEPTED 0xDD57
#define MTP_PROPERTY_ACTIVITY_TENTATIVE 0xDD58
#define MTP_PROPERTY_ACTIVITY_DECLINED 0xDD59
#define MTP_PROPERTY_ACTIVITY_REMAINDER_TIME 0xDD5A
#define MTP_PROPERTY_ACTIVITY_OWNER 0xDD5B
#define MTP_PROPERTY_ACTIVITY_STATUS 0xDD5C
#define MTP_PROPERTY_OWNER 0xDD5D
#define MTP_PROPERTY_EDITOR 0xDD5E
#define MTP_PROPERTY_WEBMASTER 0xDD5F
#define MTP_PROPERTY_URL_SOURCE 0xDD60
#define MTP_PROPERTY_URL_DESTINATION 0xDD61
#define MTP_PROPERTY_TIME_BOOKMARK 0xDD62
#define MTP_PROPERTY_OBJECT_BOOKMARK 0xDD63
#define MTP_PROPERTY_BYTE_BOOKMARK 0xDD64
#define MTP_PROPERTY_LAST_BUILD_DATE 0xDD70
#define MTP_PROPERTY_TIME_TO_LIVE 0xDD71
#define MTP_PROPERTY_MEDIA_GUID 0xDD72
// MTP Device Property Codes
#define MTP_DEVICE_PROPERTY_UNDEFINED 0x5000
#define MTP_DEVICE_PROPERTY_BATTERY_LEVEL 0x5001
#define MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE 0x5002
#define MTP_DEVICE_PROPERTY_IMAGE_SIZE 0x5003
#define MTP_DEVICE_PROPERTY_COMPRESSION_SETTING 0x5004
#define MTP_DEVICE_PROPERTY_WHITE_BALANCE 0x5005
#define MTP_DEVICE_PROPERTY_RGB_GAIN 0x5006
#define MTP_DEVICE_PROPERTY_F_NUMBER 0x5007
#define MTP_DEVICE_PROPERTY_FOCAL_LENGTH 0x5008
#define MTP_DEVICE_PROPERTY_FOCUS_DISTANCE 0x5009
#define MTP_DEVICE_PROPERTY_FOCUS_MODE 0x500A
#define MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE 0x500B
#define MTP_DEVICE_PROPERTY_FLASH_MODE 0x500C
#define MTP_DEVICE_PROPERTY_EXPOSURE_TIME 0x500D
#define MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE 0x500E
#define MTP_DEVICE_PROPERTY_EXPOSURE_INDEX 0x500F
#define MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION 0x5010
#define MTP_DEVICE_PROPERTY_DATETIME 0x5011
#define MTP_DEVICE_PROPERTY_CAPTURE_DELAY 0x5012
#define MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE 0x5013
#define MTP_DEVICE_PROPERTY_CONTRAST 0x5014
#define MTP_DEVICE_PROPERTY_SHARPNESS 0x5015
#define MTP_DEVICE_PROPERTY_DIGITAL_ZOOM 0x5016
#define MTP_DEVICE_PROPERTY_EFFECT_MODE 0x5017
#define MTP_DEVICE_PROPERTY_BURST_NUMBER 0x5018
#define MTP_DEVICE_PROPERTY_BURST_INTERVAL 0x5019
#define MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER 0x501A
#define MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL 0x501B
#define MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE 0x501C
#define MTP_DEVICE_PROPERTY_UPLOAD_URL 0x501D
#define MTP_DEVICE_PROPERTY_ARTIST 0x501E
#define MTP_DEVICE_PROPERTY_COPYRIGHT_INFO 0x501F
#define MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER 0xD401
#define MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME 0xD402
#define MTP_DEVICE_PROPERTY_VOLUME 0xD403
#define MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED 0xD404
#define MTP_DEVICE_PROPERTY_DEVICE_ICON 0xD405
#define MTP_DEVICE_PROPERTY_PLAYBACK_RATE 0xD410
#define MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT 0xD411
#define MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX 0xD412
#define MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO 0xD406
#define MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE 0xD407
// MTP Operation Codes
#define MTP_OPERATION_GET_DEVICE_INFO 0x1001
#define MTP_OPERATION_OPEN_SESSION 0x1002
#define MTP_OPERATION_CLOSE_SESSION 0x1003
#define MTP_OPERATION_GET_STORAGE_IDS 0x1004
#define MTP_OPERATION_GET_STORAGE_INFO 0x1005
#define MTP_OPERATION_GET_NUM_OBJECTS 0x1006
#define MTP_OPERATION_GET_OBJECT_HANDLES 0x1007
#define MTP_OPERATION_GET_OBJECT_INFO 0x1008
#define MTP_OPERATION_GET_OBJECT 0x1009
#define MTP_OPERATION_GET_THUMB 0x100A
#define MTP_OPERATION_DELETE_OBJECT 0x100B
#define MTP_OPERATION_SEND_OBJECT_INFO 0x100C
#define MTP_OPERATION_SEND_OBJECT 0x100D
#define MTP_OPERATION_INITIATE_CAPTURE 0x100E
#define MTP_OPERATION_FORMAT_STORE 0x100F
#define MTP_OPERATION_RESET_DEVICE 0x1010
#define MTP_OPERATION_SELF_TEST 0x1011
#define MTP_OPERATION_SET_OBJECT_PROTECTION 0x1012
#define MTP_OPERATION_POWER_DOWN 0x1013
#define MTP_OPERATION_GET_DEVICE_PROP_DESC 0x1014
#define MTP_OPERATION_GET_DEVICE_PROP_VALUE 0x1015
#define MTP_OPERATION_SET_DEVICE_PROP_VALUE 0x1016
#define MTP_OPERATION_RESET_DEVICE_PROP_VALUE 0x1017
#define MTP_OPERATION_TERMINATE_OPEN_CAPTURE 0x1018
#define MTP_OPERATION_MOVE_OBJECT 0x1019
#define MTP_OPERATION_COPY_OBJECT 0x101A
#define MTP_OPERATION_GET_PARTIAL_OBJECT 0x101B
#define MTP_OPERATION_INITIATE_OPEN_CAPTURE 0x101C
#define MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED 0x9801
#define MTP_OPERATION_GET_OBJECT_PROP_DESC 0x9802
#define MTP_OPERATION_GET_OBJECT_PROP_VALUE 0x9803
#define MTP_OPERATION_SET_OBJECT_PROP_VALUE 0x9804
#define MTP_OPERATION_GET_OBJECT_PROP_LIST 0x9805
#define MTP_OPERATION_SET_OBJECT_PROP_LIST 0x9806
#define MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC 0x9807
#define MTP_OPERATION_SEND_OBJECT_PROP_LIST 0x9808
#define MTP_OPERATION_GET_OBJECT_REFERENCES 0x9810
#define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811
#define MTP_OPERATION_SKIP 0x9820
// Android extensions for direct file IO
// Same as GetPartialObject, but with 64 bit offset
#define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1
// Same as GetPartialObject64, but copying host to device
#define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2
// Truncates file to 64 bit length
#define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3
// Must be called before using SendPartialObject and TruncateObject
#define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4
// Called to commit changes made by SendPartialObject and TruncateObject
#define MTP_OPERATION_END_EDIT_OBJECT 0x95C5
// MTP Response Codes
#define MTP_RESPONSE_UNDEFINED 0x2000
#define MTP_RESPONSE_OK 0x2001
#define MTP_RESPONSE_GENERAL_ERROR 0x2002
#define MTP_RESPONSE_SESSION_NOT_OPEN 0x2003
#define MTP_RESPONSE_INVALID_TRANSACTION_ID 0x2004
#define MTP_RESPONSE_OPERATION_NOT_SUPPORTED 0x2005
#define MTP_RESPONSE_PARAMETER_NOT_SUPPORTED 0x2006
#define MTP_RESPONSE_INCOMPLETE_TRANSFER 0x2007
#define MTP_RESPONSE_INVALID_STORAGE_ID 0x2008
#define MTP_RESPONSE_INVALID_OBJECT_HANDLE 0x2009
#define MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED 0x200A
#define MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE 0x200B
#define MTP_RESPONSE_STORAGE_FULL 0x200C
#define MTP_RESPONSE_OBJECT_WRITE_PROTECTED 0x200D
#define MTP_RESPONSE_STORE_READ_ONLY 0x200E
#define MTP_RESPONSE_ACCESS_DENIED 0x200F
#define MTP_RESPONSE_NO_THUMBNAIL_PRESENT 0x2010
#define MTP_RESPONSE_SELF_TEST_FAILED 0x2011
#define MTP_RESPONSE_PARTIAL_DELETION 0x2012
#define MTP_RESPONSE_STORE_NOT_AVAILABLE 0x2013
#define MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED 0x2014
#define MTP_RESPONSE_NO_VALID_OBJECT_INFO 0x2015
#define MTP_RESPONSE_INVALID_CODE_FORMAT 0x2016
#define MTP_RESPONSE_UNKNOWN_VENDOR_CODE 0x2017
#define MTP_RESPONSE_CAPTURE_ALREADY_TERMINATED 0x2018
#define MTP_RESPONSE_DEVICE_BUSY 0x2019
#define MTP_RESPONSE_INVALID_PARENT_OBJECT 0x201A
#define MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT 0x201B
#define MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE 0x201C
#define MTP_RESPONSE_INVALID_PARAMETER 0x201D
#define MTP_RESPONSE_SESSION_ALREADY_OPEN 0x201E
#define MTP_RESPONSE_TRANSACTION_CANCELLED 0x201F
#define MTP_RESPONSE_SPECIFICATION_OF_DESTINATION_UNSUPPORTED 0x2020
#define MTP_RESPONSE_INVALID_OBJECT_PROP_CODE 0xA801
#define MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT 0xA802
#define MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE 0xA803
#define MTP_RESPONSE_INVALID_OBJECT_REFERENCE 0xA804
#define MTP_RESPONSE_GROUP_NOT_SUPPORTED 0xA805
#define MTP_RESPONSE_INVALID_DATASET 0xA806
#define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED 0xA807
#define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED 0xA808
#define MTP_RESPONSE_OBJECT_TOO_LARGE 0xA809
#define MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED 0xA80A
#define MTP_RESPONSE_NO_RESPONSE 0xFFFF
// MTP Event Codes
#define MTP_EVENT_UNDEFINED 0x4000
#define MTP_EVENT_CANCEL_TRANSACTION 0x4001
#define MTP_EVENT_OBJECT_ADDED 0x4002
#define MTP_EVENT_OBJECT_REMOVED 0x4003
#define MTP_EVENT_STORE_ADDED 0x4004
#define MTP_EVENT_STORE_REMOVED 0x4005
#define MTP_EVENT_DEVICE_PROP_CHANGED 0x4006
#define MTP_EVENT_OBJECT_INFO_CHANGED 0x4007
#define MTP_EVENT_DEVICE_INFO_CHANGED 0x4008
#define MTP_EVENT_REQUEST_OBJECT_TRANSFER 0x4009
#define MTP_EVENT_STORE_FULL 0x400A
#define MTP_EVENT_DEVICE_RESET 0x400B
#define MTP_EVENT_STORAGE_INFO_CHANGED 0x400C
#define MTP_EVENT_CAPTURE_COMPLETE 0x400D
#define MTP_EVENT_UNREPORTED_STATUS 0x400E
#define MTP_EVENT_OBJECT_PROP_CHANGED 0xC801
#define MTP_EVENT_OBJECT_PROP_DESC_CHANGED 0xC802
#define MTP_EVENT_OBJECT_REFERENCES_CHANGED 0xC803
// Storage Type
#define MTP_STORAGE_FIXED_ROM 0x0001
#define MTP_STORAGE_REMOVABLE_ROM 0x0002
#define MTP_STORAGE_FIXED_RAM 0x0003
#define MTP_STORAGE_REMOVABLE_RAM 0x0004
// Storage File System
#define MTP_STORAGE_FILESYSTEM_FLAT 0x0001
#define MTP_STORAGE_FILESYSTEM_HIERARCHICAL 0x0002
#define MTP_STORAGE_FILESYSTEM_DCF 0x0003
// Storage Access Capability
#define MTP_STORAGE_READ_WRITE 0x0000
#define MTP_STORAGE_READ_ONLY_WITHOUT_DELETE 0x0001
#define MTP_STORAGE_READ_ONLY_WITH_DELETE 0x0002
// Association Type
#define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000
#define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001
// MTP class reqeusts
#define MTP_REQUEST_CANCEL 0x64
#define MTP_REQUEST_GET_EXT_EVENT_DATA 0x65
#define MTP_REQUEST_RESET 0x66
#define MTP_REQUEST_GET_DEVICE_STATUS 0x67
// clang-format on
#define USB_MTP_CLASS 0x06
#define USB_MTP_SUB_CLASS 0x01U
#define USB_MTP_PROTOCOL 0x01U
struct mtp_header {
uint32_t conlen;
uint16_t contype;
uint16_t code;
uint32_t trans_id;
uint32_t param[];
};
struct mtp_string {
uint8_t len;
uint16_t string[255];
};
struct mtp_device_info {
uint16_t StandardVersion;
uint32_t VendorExtensionID;
uint16_t VendorExtensionVersion;
uint8_t VendorExtensionDesc_len;
uint16_t VendorExtensionDesc[255];
uint16_t FunctionalMode;
uint32_t OperationsSupported_len;
uint16_t OperationsSupported[255];
uint32_t EventsSupported_len;
uint16_t EventsSupported[255];
uint32_t DevicePropertiesSupported_len;
uint16_t DevicePropertiesSupported[255];
uint32_t CaptureFormats_len;
uint16_t CaptureFormats[255];
uint32_t ImageFormats_len;
uint16_t ImageFormats[255];
uint8_t Manufacturer_len;
uint16_t Manufacturer[255];
uint8_t Model_len;
uint16_t Model[255];
uint8_t DeviceVersion_len;
uint16_t DeviceVersion[255];
uint8_t SerialNumber_len;
uint16_t SerialNumber[255];
} __PACKED;
struct mtp_object_props_support {
uint32_t ObjectPropCode_len;
uint16_t ObjectPropCode[255];
} __PACKED;
struct mtp_device_prop_desc {
uint16_t DevicePropertyCode;
uint16_t DataType;
uint8_t GetSet;
uint16_t DefaultValue[1];
uint16_t CurrentValue[1];
uint8_t FormFlag;
} __PACKED;
struct mtp_storage_id {
uint32_t StorageIDS_len;
uint32_t StorageIDS[255];
} __PACKED;
struct mtp_storage_info {
uint16_t StorageType;
uint16_t FilesystemType;
uint16_t AccessCapability;
uint64_t MaxCapability;
uint64_t FreeSpaceInBytes;
uint32_t FreeSpaceInObjects;
uint8_t StorageDescription_len;
uint8_t StorageDescription[255];
uint8_t VolumeIdentifier_len;
uint8_t VolumeIdentifier[255];
} __PACKED;
struct mtp_object_handles {
uint32_t ObjectHandle_len;
uint32_t ObjectHandle[255];
} __PACKED;
struct mtp_object_prop_desc {
uint16_t ObjectPropertyCode;
uint16_t DataType;
uint8_t GetSet;
uint8_t DefValue[16];
uint32_t GroupCode;
uint8_t FormFlag;
} __PACKED;
struct mtp_object_prop_element {
uint32_t ObjectHandle;
uint16_t PropertyCode;
uint16_t Datatype;
uint8_t value[8];
} __PACKED;
struct mtp_object_prop_list {
uint32_t element_len;
struct mtp_object_prop_element element[1];
} __PACKED;
struct mtp_object_info {
uint32_t StorageId;
uint16_t ObjectFormat;
uint16_t ProtectionStatus;
uint32_t ObjectCompressedSize;
uint16_t ThumbFormat;
uint32_t ThumbCompressedSize;
uint32_t ThumbPixWidth;
uint32_t ThumbPixHeight;
uint32_t ImagePixWidth;
uint32_t ImagePixHeight;
uint32_t ImageBitDepth;
uint32_t ParentObject;
uint16_t AssociationType;
uint32_t AssociationDesc;
uint32_t SequenceNumber;
uint8_t Filename_len;
uint16_t Filename[CONFIG_USBDEV_MTP_MAX_PATHNAME];
uint8_t CaptureDate[6];
uint8_t ModificationDate[6];
} __PACKED;
struct mtp_object {
uint32_t storage_id;
uint32_t handle;
uint32_t parent_handle;
uint16_t format;
bool is_dir;
bool is_readonly;
bool is_hidden;
uint32_t file_size;
uint32_t file_full_name_length;
char file_full_name[CONFIG_USBDEV_MTP_MAX_PATHNAME];
bool in_use;
};
/*Length of template descriptor: 30 bytes*/
#define MTP_DESCRIPTOR_LEN (9 + 7 + 7 + 7)
// clang-format off
#define MTP_DESCRIPTOR_INIT(bFirstInterface, out_ep, in_ep, int_ep, wMaxPacketSize, str_idx) \
/* Interface */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bFirstInterface, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x03, /* bNumEndpoints */ \
USB_DEVICE_CLASS_IMAGE, /* bInterfaceClass */ \
USB_MTP_SUB_CLASS, /* bInterfaceSubClass */ \
USB_MTP_PROTOCOL, /* bInterfaceProtocol */ \
str_idx, /* iInterface */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
out_ep, /* bEndpointAddress */ \
0x02, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
0x00, /* bInterval */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
in_ep, /* bEndpointAddress */ \
0x02, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
0x00, /* bInterval */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
int_ep, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
WBVAL(0x1c), /* wMaxPacketSize */ \
0x06 /* bInterval */
// clang-format on
#endif

65
class/mtp/usbd_mtp.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_MTP_H
#define USBD_MTP_H
#include "usb_mtp.h"
#include <sys/stat.h>
#include <fcntl.h>
/* gcc toolchain does not implement dirent.h, so we define our own MTP_DIR and mtp_dirent */
typedef void MTP_DIR;
struct mtp_statfs {
size_t f_bsize; /* block size */
size_t f_blocks; /* total data blocks in file system */
size_t f_bfree; /* free blocks in file system */
};
struct mtp_dirent {
uint8_t d_type; /* The type of the file */
uint8_t d_namlen; /* The length of the not including the terminating null file name */
uint16_t d_reclen; /* length of this record */
char d_name[CONFIG_USBDEV_MTP_MAX_PATHNAME]; /* The null-terminated file name */
};
#ifdef __cplusplus
extern "C" {
#endif
struct usbd_interface *usbd_mtp_init_intf(struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep,
const uint8_t int_ep);
int usbd_mtp_notify_object_add(const char *path);
int usbd_mtp_notify_object_remove(const char *path);
const char *usbd_mtp_fs_root_path(void);
const char *usbd_mtp_fs_description(void);
int usbd_mtp_mkdir(const char *path);
int usbd_mtp_rmdir(const char *path);
MTP_DIR *usbd_mtp_opendir(const char *name);
int usbd_mtp_closedir(MTP_DIR *d);
struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *d);
int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf);
int usbd_mtp_stat(const char *file, struct stat *buf);
int usbd_mtp_open(const char *path, uint8_t mode);
int usbd_mtp_close(int fd);
int usbd_mtp_read(int fd, void *buf, size_t len);
int usbd_mtp_write(int fd, const void *buf, size_t len);
int usbd_mtp_unlink(const char *path);
#ifdef __cplusplus
}
#endif
#endif /* USBD_MTP_H */

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_MTP_SUPPORT_H
#define USBD_MTP_SUPPORT_H
#define MTP_VERSION 100
typedef struct _profile_property {
uint16_t prop_code;
uint16_t data_type;
uint8_t getset;
uint64_t default_value;
uint32_t group_code;
uint8_t form_flag;
uint16_t format_code;
} profile_property;
typedef struct _format_property {
uint16_t format_code;
uint16_t *properties;
} formats_property;
const char mtp_extension_string[] = "microsoft.com: 1.0; android.com: 1.0;";
const uint16_t supported_op[] = {
MTP_OPERATION_GET_DEVICE_INFO, //0x1001
MTP_OPERATION_OPEN_SESSION, //0x1002
MTP_OPERATION_CLOSE_SESSION, //0x1003
MTP_OPERATION_GET_STORAGE_IDS, //0x1004
MTP_OPERATION_GET_STORAGE_INFO, //0x1005
//MTP_OPERATION_GET_NUM_OBJECTS ,//0x1006
MTP_OPERATION_GET_OBJECT_HANDLES, //0x1007
MTP_OPERATION_GET_OBJECT_INFO, //0x1008
MTP_OPERATION_GET_OBJECT, //0x1009
//MTP_OPERATION_GET_THUMB ,//0x100A
MTP_OPERATION_DELETE_OBJECT, //0x100B
MTP_OPERATION_SEND_OBJECT_INFO, //0x100C
MTP_OPERATION_SEND_OBJECT, //0x100D
MTP_OPERATION_GET_DEVICE_PROP_DESC, //0x1014
// MTP_OPERATION_GET_DEVICE_PROP_VALUE ,//0x1015
// MTP_OPERATION_SET_DEVICE_PROP_VALUE ,//0x1016
//MTP_OPERATION_RESET_DEVICE_PROP_VALUE ,//0x1017
// MTP_OPERATION_GET_PARTIAL_OBJECT ,//0x101B
MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED, //0x9801
// MTP_OPERATION_GET_OBJECT_PROP_DESC, //0x9802
// MTP_OPERATION_GET_OBJECT_PROP_VALUE ,//0x9803
// MTP_OPERATION_SET_OBJECT_PROP_VALUE ,//0x9804
// MTP_OPERATION_GET_OBJECT_PROP_LIST ,//0x9805
//MTP_OPERATION_GET_OBJECT_REFERENCES ,//0x9810
//MTP_OPERATION_SET_OBJECT_REFERENCES ,//0x9811
// MTP_OPERATION_GET_PARTIAL_OBJECT_64 ,//0x95C1
// MTP_OPERATION_SEND_PARTIAL_OBJECT ,//0x95C2
// MTP_OPERATION_TRUNCATE_OBJECT ,//0x95C3
// MTP_OPERATION_BEGIN_EDIT_OBJECT ,//0x95C4
// MTP_OPERATION_END_EDIT_OBJECT //0x95C5
};
int supported_op_size = sizeof(supported_op);
const uint16_t supported_event[] = {
MTP_EVENT_OBJECT_ADDED, // 0x4002
MTP_EVENT_OBJECT_REMOVED, // 0x4003
MTP_EVENT_STORE_ADDED, // 0x4004
MTP_EVENT_STORE_REMOVED, // 0x4005
MTP_EVENT_STORAGE_INFO_CHANGED, // 0x400C
MTP_EVENT_OBJECT_INFO_CHANGED, // 0x4007
MTP_EVENT_DEVICE_PROP_CHANGED, // 0x4006
MTP_EVENT_OBJECT_PROP_CHANGED // 0xC801
};
int supported_event_size = sizeof(supported_event);
const formats_property support_format_properties[] = {
// format code prop code
{ MTP_FORMAT_UNDEFINED, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF } },
{ MTP_FORMAT_ASSOCIATION, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF } }
#if 0
{ MTP_FORMAT_TEXT , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_HTML , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_MP4_CONTAINER, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_3GP_CONTAINER, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_WAV , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER,
MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE,
0xFFFF}
},
{ MTP_FORMAT_MP3 , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER,
MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE,
0xFFFF}
},
{ MTP_FORMAT_MPEG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_EXIF_JPEG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_BMP , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_GIF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_JFIF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH,
MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_WMA , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
0xFFFF}
},
{ MTP_FORMAT_OGG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
0xFFFF}
},
{ MTP_FORMAT_AAC , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION,
MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE,
MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE,
0xFFFF}
},
{ MTP_FORMAT_ABSTRACT_AV_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_WPL_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_M3U_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_PLS_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_XML_DOCUMENT, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_FLAC , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_AVI , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_ASF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME,
MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED,
0xFFFF}
},
{ MTP_FORMAT_MS_WORD_DOCUMENT, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_MS_EXCEL_SPREADSHEET, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
},
{ MTP_FORMAT_MS_POWERPOINT_PRESENTATION, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE,
MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID,
MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,
0xFFFF}
}
#endif
,
{ 0xFFFF, (uint16_t[]){ 0xFFFF } }
};
const profile_property support_object_properties[] = {
// prop_code data_type getset default_value group_code form_flag format_code
{ MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000001, 0x00, 0xFFFF },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_UNDEFINED, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASSOCIATION, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_TEXT, 0x000000000, 0x00, MTP_FORMAT_TEXT },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_HTML, 0x000000000, 0x00, MTP_FORMAT_HTML },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WAV, 0x000000000, 0x00, MTP_FORMAT_WAV },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP3, 0x000000000, 0x00, MTP_FORMAT_MP3 },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG, 0x000000000, 0x00, MTP_FORMAT_MPEG },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_EXIF_JPEG, 0x000000000, 0x00, MTP_FORMAT_EXIF_JPEG },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_BMP, 0x000000000, 0x00, MTP_FORMAT_BMP },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AIFF, 0x000000000, 0x00, MTP_FORMAT_AIFF },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG, 0x000000000, 0x00, MTP_FORMAT_MPEG },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WMA, 0x000000000, 0x00, MTP_FORMAT_WMA },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_OGG, 0x000000000, 0x00, MTP_FORMAT_OGG },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AAC, 0x000000000, 0x00, MTP_FORMAT_AAC },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP4_CONTAINER, 0x000000000, 0x00, MTP_FORMAT_MP4_CONTAINER },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_3GP_CONTAINER, 0x000000000, 0x00, MTP_FORMAT_3GP_CONTAINER },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ABSTRACT_AV_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_ABSTRACT_AV_PLAYLIST },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WPL_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_WPL_PLAYLIST },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_M3U_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_M3U_PLAYLIST },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_PLS_PLAYLIST, 0x000000000, 0x00, MTP_FORMAT_PLS_PLAYLIST },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_XML_DOCUMENT, 0x000000000, 0x00, MTP_FORMAT_XML_DOCUMENT },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_FLAC, 0x000000000, 0x00, MTP_FORMAT_FLAC },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AVI, 0x000000000, 0x00, MTP_FORMAT_AVI },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASF, 0x000000000, 0x00, MTP_FORMAT_ASF },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_WORD_DOCUMENT, 0x000000000, 0x00, MTP_FORMAT_MS_WORD_DOCUMENT },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_EXCEL_SPREADSHEET, 0x000000000, 0x00, MTP_FORMAT_MS_EXCEL_SPREADSHEET },
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_POWERPOINT_PRESENTATION, 0x000000000, 0x00, MTP_FORMAT_MS_POWERPOINT_PRESENTATION },
{ MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_ASSOCIATION },
{ MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
{ MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00, 0x000000000, 0x00, MTP_FORMAT_UNDEFINED },
//{MTP_PROPERTY_ASSOCIATION_TYPE, MTP_TYPE_UINT16, 0x00, 0x0001 , 0x000000000 , 0x00 , 0xFFFF },
{ MTP_PROPERTY_ASSOCIATION_DESC, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00, 0xFFFF },
{ MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, 0xFFFF },
{ MTP_PROPERTY_HIDDEN, MTP_TYPE_UINT16, 0x00, 0x0000, 0x000000000, 0x00, 0xFFFF },
{ 0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00 }
};
const profile_property support_device_properties[] = {
// prop_code data_type getset default_value group_code form_flag
//{MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 },
//{MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 },
{ MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT16, 0x00, 0x00000000, 0x000000000, 0x00 },
{ MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR, 0x00, 0x00000000, 0x000000000, 0x00 },
{ 0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000, 0x000000000, 0x00 }
};
#endif

266
class/serial/usbh_cdc_acm.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* Copyright (c) 2022 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#include "usbh_cdc_acm.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_cdc_acm"
#include "usb_log.h"
struct usbh_cdc_acm {
struct usb_endpoint_descriptor *intin;
struct usbh_urb intin_urb;
struct usb_osal_timer *modem_timer;
uint16_t modem_status;
};
static int usbh_cdc_acm_attach(struct usbh_serial *serial)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
struct usbh_cdc_acm *cdc_acm_class = usb_osal_malloc(sizeof(struct usbh_cdc_acm));
if (!cdc_acm_class) {
USB_LOG_ERR("No memory for cdc_acm_class\r\n");
return -USB_ERR_NOMEM;
}
memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
serial->priv = cdc_acm_class;
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(cdc_acm_class->intin, ep_desc);
break;
} else {
}
}
}
if (!cdc_acm_class->intin) {
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
ret = -USB_ERR_NODEV;
goto errout;
}
return 0;
errout:
serial->priv = NULL;
usb_osal_free(cdc_acm_class);
return ret;
}
static void usbh_cdc_acm_detach(struct usbh_serial *serial)
{
struct usbh_cdc_acm *cdc_acm_class;
if (!serial || !serial->priv) {
return;
}
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
if (cdc_acm_class->intin) {
usbh_kill_urb(&cdc_acm_class->intin_urb);
}
serial->priv = NULL;
usb_osal_free(cdc_acm_class);
}
static int usbh_cdc_acm_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 7;
memcpy(serial->iobuffer, line_coding, sizeof(struct cdc_line_coding));
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
}
static int usbh_cdc_acm_get_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return ret;
}
memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding));
return ret;
}
static int usbh_cdc_acm_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
setup->wValue = (dtr << 0) | (rts << 1);
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_cdc_acm_get_modem_status(struct usbh_serial *serial)
{
struct usbh_cdc_acm *cdc_acm_class;
uintptr_t flags;
uint16_t status;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
status = (cdc_acm_class->modem_status & CDC_SERIAL_STATE_DSR ? USBH_SERIAL_TIOCM_DSR : 0) |
(cdc_acm_class->modem_status & CDC_SERIAL_STATE_RING ? USBH_SERIAL_TIOCM_RI : 0) |
(cdc_acm_class->modem_status & CDC_SERIAL_STATE_DCD ? USBH_SERIAL_TIOCM_CD : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
usb_osal_leave_critical_section(flags);
return status;
}
#ifdef CONFIG_USBH_SERIAL_GET_MODEM_STATUS
static int __usbh_cdc_acm_get_modem_status(struct usbh_serial *serial)
{
struct usbh_cdc_acm *cdc_acm_class;
struct cdc_acm_notification *notification;
uint16_t difference;
uintptr_t flags;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
usbh_int_urb_fill(&cdc_acm_class->intin_urb, serial->hport, cdc_acm_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], cdc_acm_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
ret = usbh_submit_urb(&cdc_acm_class->intin_urb);
if (ret < 0) {
return ret;
}
if (cdc_acm_class->intin_urb.actual_length < sizeof(struct cdc_acm_notification)) {
return -USB_ERR_INVAL;
}
notification = (struct cdc_acm_notification *)&serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
if (notification->bNotificationType != CDC_NOTIFICATION_SERIAL_STATE) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
difference = cdc_acm_class->modem_status ^ notification->data;
cdc_acm_class->modem_status = notification->data;
if (difference & CDC_SERIAL_STATE_DSR)
serial->iocount.dsr++;
if (difference & CDC_SERIAL_STATE_DCD)
serial->iocount.dcd++;
if (notification->data & CDC_SERIAL_STATE_BREAK)
serial->iocount.brk++;
if (notification->data & CDC_SERIAL_STATE_FRAMING)
serial->iocount.frame++;
if (notification->data & CDC_SERIAL_STATE_PARITY)
serial->iocount.parity++;
if (notification->data & CDC_SERIAL_STATE_OVERRUN)
serial->iocount.overrun++;
usb_osal_leave_critical_section(flags);
return ret;
}
#endif
static const struct usbh_serial_driver cdc_acm_driver = {
.driver_name = "cdc_acm",
.ignore_rx_header = 0,
.ignore_tx_header = 0,
.attach = usbh_cdc_acm_attach,
.detach = usbh_cdc_acm_detach,
.set_flow_control = NULL,
.set_line_coding = usbh_cdc_acm_set_line_coding,
.get_line_coding = usbh_cdc_acm_get_line_coding,
.set_line_state = usbh_cdc_acm_set_line_state,
.get_modem_status = usbh_cdc_acm_get_modem_status,
};
static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &cdc_acm_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
const struct usbh_class_driver cdc_acm_class_driver = {
.driver_name = "cdc_acm",
.connect = usbh_cdc_acm_connect,
.disconnect = usbh_cdc_acm_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_none_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
.id_table = NULL,
.class_driver = &cdc_acm_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_at_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
.id_table = NULL,
.class_driver = &cdc_acm_class_driver
};

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2022 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CDC_ACM_H
#define USBH_CDC_ACM_H
#include "usb_cdc.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBH_CDC_ACM_H */

409
class/serial/usbh_ch34x.c Normal file
View File

@@ -0,0 +1,409 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#include "usbh_ch34x.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_ch43x"
#include "usb_log.h"
struct usbh_ch34x {
struct usb_endpoint_descriptor *intin;
struct usbh_urb intin_urb;
struct usb_osal_timer *modem_timer;
uint16_t modem_status;
};
/* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
{
uint8_t a;
uint8_t b;
uint32_t c;
switch (baudrate) {
case 921600:
a = 0xf3;
b = 7;
break;
case 307200:
a = 0xd9;
b = 7;
break;
default:
if (baudrate > 6000000 / 255) {
b = 3;
c = 6000000;
} else if (baudrate > 750000 / 255) {
b = 2;
c = 750000;
} else if (baudrate > 93750 / 255) {
b = 1;
c = 93750;
} else {
b = 0;
c = 11719;
}
a = (uint8_t)(c / baudrate);
if (a == 0 || a == 0xFF) {
return -USB_ERR_INVAL;
}
if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
a++;
}
a = (uint8_t)(256 - a);
break;
}
*factor = a;
*divisor = b;
return 0;
}
static int usbh_ch34x_control_out(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = bRequest;
setup->wValue = wValue;
setup->wIndex = wIndex;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ch34x_control_in(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t size)
{
struct usb_setup_packet *setup;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = bRequest;
setup->wValue = wValue;
setup->wIndex = wIndex;
setup->wLength = size;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return ret;
}
memcpy(data, serial->iobuffer, size);
return ret;
}
static int usbh_ch34x_get_version(struct usbh_serial *serial)
{
int ret;
uint8_t buf[2];
ret = usbh_ch34x_control_in(serial, CH34X_READ_VERSION, 0, 0, buf, 2);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("chip version: 0x%02x\r\n", buf[0]);
return ret;
}
static int usbh_ch34x_attach(struct usbh_serial *serial)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
struct usbh_ch34x *ch34x_class = usb_osal_malloc(sizeof(struct usbh_ch34x));
if (!ch34x_class) {
USB_LOG_ERR("No memory for ch34x_class\r\n");
return -USB_ERR_NOMEM;
}
memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
serial->priv = ch34x_class;
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(ch34x_class->intin, ep_desc);
break;
} else {
}
}
}
if (!ch34x_class->intin) {
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
ret = -USB_ERR_NODEV;
goto errout;
}
ret = usbh_ch34x_get_version(serial);
ret |= usbh_ch34x_control_out(serial, CH34X_SERIAL_INIT, 0, 0);
ret |= usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x1312, 0xd982);
ret |= usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x0f2c, 0x0007);
if (ret < 0) {
goto errout;
}
return 0;
errout:
serial->priv = NULL;
usb_osal_free(ch34x_class);
return ret;
}
static void usbh_ch34x_detach(struct usbh_serial *serial)
{
struct usbh_ch34x *ch34x_class;
if (!serial || !serial->priv) {
return;
}
ch34x_class = (struct usbh_ch34x *)serial->priv;
if (ch34x_class->intin) {
usbh_kill_urb(&ch34x_class->intin_urb);
}
serial->priv = NULL;
usb_osal_free(ch34x_class);
}
static int usbh_ch34x_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
{
return usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x2727, hardctrl ? 0x0101 : 0x0000);
}
static int usbh_ch34x_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
uint16_t reg_value = 0;
uint16_t value = 0;
uint16_t index = 0;
uint8_t factor = 0;
uint8_t divisor = 0;
switch (line_coding->bParityType) {
case 0:
break;
case 1:
reg_value |= CH341_L_PO;
break;
case 2:
reg_value |= CH341_L_PE;
break;
case 3:
reg_value |= CH341_L_PM;
break;
case 4:
reg_value |= CH341_L_PS;
break;
default:
return -USB_ERR_INVAL;
}
switch (line_coding->bDataBits) {
case 5:
reg_value |= CH341_L_D5;
break;
case 6:
reg_value |= CH341_L_D6;
break;
case 7:
reg_value |= CH341_L_D7;
break;
case 8:
reg_value |= CH341_L_D8;
break;
default:
return -USB_ERR_INVAL;
}
if (line_coding->bCharFormat == 2) {
reg_value |= CH341_L_SB;
}
usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
reg_value |= 0xC0;
value |= 0x9c;
value |= reg_value << 8;
index |= 0x80 | divisor;
index |= (uint16_t)factor << 8;
return usbh_ch34x_control_out(serial, CH34X_SERIAL_INIT, value, index);
}
static int usbh_ch34x_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
uint16_t value = 0;
uint8_t control = 0;
control = (dtr << 5) | (rts << 6);
value = (uint8_t)~control;
return usbh_ch34x_control_out(serial, CH34X_MODEM_CTRL, value, 0x0000);
}
static int usbh_ch34x_get_modem_status(struct usbh_serial *serial)
{
struct usbh_ch34x *ch34x_class;
uintptr_t flags;
uint16_t status;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
ch34x_class = (struct usbh_ch34x *)serial->priv;
status = (ch34x_class->modem_status & CH341_CTI_DS ? USBH_SERIAL_TIOCM_DSR : 0) |
(ch34x_class->modem_status & CH341_CTI_C ? USBH_SERIAL_TIOCM_CTS : 0) |
(ch34x_class->modem_status & CH341_CTRL_RI ? USBH_SERIAL_TIOCM_RI : 0) |
(ch34x_class->modem_status & CH341_CTI_DC ? USBH_SERIAL_TIOCM_CD : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
usb_osal_leave_critical_section(flags);
return status;
}
#ifdef CONFIG_USBH_SERIAL_GET_MODEM_STATUS
static int __usbh_ch34x_get_modem_status(struct usbh_serial *serial, uint16_t *status)
{
struct usbh_ch34x *ch34x_class;
uint8_t type = 0;
uint8_t data = 0;
uint16_t difference;
uintptr_t flags;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
ch34x_class = (struct usbh_ch34x *)serial->priv;
usbh_int_urb_fill(&ch34x_class->intin_urb, serial->hport, ch34x_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], ch34x_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
ret = usbh_submit_urb(&ch34x_class->intin_urb);
if (ret < 0) {
return ret;
}
if (ret < 4) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
type = serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
if (type & CH341_CTT_M) {
data = ~serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET + 2] & CH341_CTI_ST;
difference = data ^ (ch34x_class->modem_status & CH341_CTI_ST);
ch34x_class->modem_status = data;
if (difference) {
if (difference & CH341_CTI_C) {
serial->iocount.cts++;
}
if (difference & CH341_CTI_DS) {
serial->iocount.dsr++;
}
if (difference & CH341_CTRL_RI) {
serial->iocount.rng++;
}
if (difference & CH341_CTI_DC) {
serial->iocount.dcd++;
}
}
}
if (type & CH341_CTT_O) {
serial->iocount.overrun++;
}
if ((type & CH341_CTT_F) == CH341_CTT_F) {
serial->iocount.frame++;
}
if (type & CH341_CTT_P) {
serial->iocount.parity++;
}
usb_osal_leave_critical_section(flags);
return ret;
}
#endif
static const struct usbh_serial_driver ch34x_driver = {
.driver_name = "ch34x",
.ignore_rx_header = 0,
.ignore_tx_header = 0,
.attach = usbh_ch34x_attach,
.detach = usbh_ch34x_detach,
.set_flow_control = usbh_ch34x_set_flow_ctrl,
.set_line_coding = usbh_ch34x_set_line_coding,
.get_line_coding = NULL,
.set_line_state = usbh_ch34x_set_line_state,
.get_modem_status = usbh_ch34x_get_modem_status,
};
static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &ch34x_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
static const uint16_t ch34x_id_table[][2] = {
{ 0x1A86, 0x7523 }, /* ch340 chip */
{ 0x1A86, 0x7522 }, /* ch340k chip */
{ 0x1A86, 0x5523 }, /* ch341 chip */
{ 0x1A86, 0xe523 }, /* ch330 chip */
{ 0x4348, 0x5523 }, /* ch340 custom chip */
{ 0, 0 },
};
const struct usbh_class_driver ch34x_class_driver = {
.driver_name = "ch34x",
.connect = usbh_ch34x_connect,
.disconnect = usbh_ch34x_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = ch34x_id_table,
.class_driver = &ch34x_class_driver
};

56
class/serial/usbh_ch34x.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CH34X_H
#define USBH_CH34X_H
#include "usb_cdc.h"
/* Requests */
#define CH34X_READ_VERSION 0x5F
#define CH34X_WRITE_REG 0x9A
#define CH34X_READ_REG 0x95
#define CH34X_SERIAL_INIT 0xA1
#define CH34X_MODEM_CTRL 0xA4
// modem control bits
#define CH34X_BIT_RTS (1 << 6)
#define CH34X_BIT_DTR (1 << 5)
#define CH341_CTO_O 0x10
#define CH341_CTO_D 0x20
#define CH341_CTO_R 0x40
#define CH341_CTI_C 0x01
#define CH341_CTI_DS 0x02
#define CH341_CTRL_RI 0x04
#define CH341_CTI_DC 0x08
#define CH341_CTI_ST 0x0f
#define CH341_CTT_M BIT(3)
#define CH341_CTT_F (BIT(2) | BIT(6))
#define CH341_CTT_P BIT(2)
#define CH341_CTT_O BIT(1)
#define CH341_L_ER 0x80
#define CH341_L_ET 0x40
#define CH341_L_PS 0x38
#define CH341_L_PM 0x28
#define CH341_L_PE 0x18
#define CH341_L_PO 0x08
#define CH341_L_SB 0x04
#define CH341_L_D8 0x03
#define CH341_L_D7 0x02
#define CH341_L_D6 0x01
#define CH341_L_D5 0x00
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBH_CH34X_H */

507
class/serial/usbh_cp210x.c Normal file
View File

@@ -0,0 +1,507 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#include "usbh_cp210x.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_cp210x"
#include "usb_log.h"
struct usbh_cp210x {
uint8_t partnum;
uint32_t fw_version;
uint32_t min_speed;
uint32_t max_speed;
bool use_actual_rate;
bool no_flow_control;
bool no_event_mode;
};
struct cp210x_rate {
uint32_t rate;
uint32_t high;
};
static const struct cp210x_rate cp210x_an205_table1[] = {
{ 300, 300 },
{ 600, 600 },
{ 1200, 1200 },
{ 1800, 1800 },
{ 2400, 2400 },
{ 4000, 4000 },
{ 4800, 4803 },
{ 7200, 7207 },
{ 9600, 9612 },
{ 14400, 14428 },
{ 16000, 16062 },
{ 19200, 19250 },
{ 28800, 28912 },
{ 38400, 38601 },
{ 51200, 51558 },
{ 56000, 56280 },
{ 57600, 58053 },
{ 64000, 64111 },
{ 76800, 77608 },
{ 115200, 117028 },
{ 128000, 129347 },
{ 153600, 156868 },
{ 230400, 237832 },
{ 250000, 254234 },
{ 256000, 273066 },
{ 460800, 491520 },
{ 500000, 567138 },
{ 576000, 670254 },
{ 921600, 0xffffffff }
};
/*
* Quantises the baud rate as per AN205 Table 1
*/
static uint32_t cp210x_get_an205_rate(uint32_t baud)
{
int i;
for (i = 0; i < ARRAY_SIZE(cp210x_an205_table1); ++i) {
if (baud <= cp210x_an205_table1[i].high)
break;
}
return cp210x_an205_table1[i].rate;
}
static uint32_t cp210x_get_actual_rate(uint32_t baud)
{
unsigned int prescale = 1;
unsigned int div;
if (baud <= 365)
prescale = 4;
div = DIV_ROUND_CLOSEST(48000000, 2 * prescale * baud);
baud = 48000000 / (2 * prescale * div);
return baud;
}
static void usbh_cp210x_init_max_speed(struct usbh_serial *serial)
{
struct usbh_cp210x *cp210x_class;
if (!serial || !serial->hport || !serial->priv) {
return;
}
cp210x_class = (struct usbh_cp210x *)serial->priv;
bool use_actual_rate = false;
uint32_t min = 300;
uint32_t max;
switch (cp210x_class->partnum) {
case CP210X_PARTNUM_CP2101:
max = 921600;
break;
case CP210X_PARTNUM_CP2102:
case CP210X_PARTNUM_CP2103:
max = 1000000;
break;
case CP210X_PARTNUM_CP2104:
use_actual_rate = true;
max = 2000000;
break;
case CP210X_PARTNUM_CP2108:
max = 2000000;
break;
case CP210X_PARTNUM_CP2105:
if (serial->intf == 0) {
use_actual_rate = true;
max = 2000000; /* ECI */
} else {
min = 2400;
max = 921600; /* SCI */
}
break;
case CP210X_PARTNUM_CP2102N_QFN28:
case CP210X_PARTNUM_CP2102N_QFN24:
case CP210X_PARTNUM_CP2102N_QFN20:
use_actual_rate = true;
max = 3000000;
break;
default:
max = 2000000;
break;
}
cp210x_class->min_speed = min;
cp210x_class->max_speed = max;
cp210x_class->use_actual_rate = use_actual_rate;
}
static int usbh_cp210x_control_out(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t size)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = bRequest;
setup->wValue = wValue;
setup->wIndex = wIndex;
setup->wLength = size;
if (data && size) {
memcpy(serial->iobuffer, data, size);
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
} else {
return usbh_control_transfer(serial->hport, setup, NULL);
}
}
static int usbh_cp210x_control_in(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t size)
{
struct usb_setup_packet *setup;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = bRequest;
setup->wValue = wValue;
setup->wIndex = wIndex;
setup->wLength = size;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return ret;
}
memcpy(data, serial->iobuffer, size);
return ret;
}
static int usbh_cp210x_get_partnum(struct usbh_serial *serial)
{
uint8_t version[3];
struct usbh_cp210x *cp210x_class;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
cp210x_class = (struct usbh_cp210x *)serial->priv;
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_PARTNUM, serial->intf, (uint8_t *)&cp210x_class->partnum, 1);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("chip partnum: 0x%02x\r\n", cp210x_class->partnum);
switch (cp210x_class->partnum) {
case CP210X_PARTNUM_CP2102:
break;
case CP210X_PARTNUM_CP2105:
case CP210X_PARTNUM_CP2108:
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_FW_VER_2N, serial->intf, version, 3);
if (ret < 0) {
return ret;
}
cp210x_class->fw_version = version[0] << 16 | version[1] << 8 | version[2];
break;
case CP210X_PARTNUM_CP2102N_QFN28:
case CP210X_PARTNUM_CP2102N_QFN24:
case CP210X_PARTNUM_CP2102N_QFN20:
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_FW_VER_2N, serial->intf, version, 3);
if (ret < 0) {
return ret;
}
cp210x_class->fw_version = version[0] << 16 | version[1] << 8 | version[2];
if (cp210x_class->fw_version <= 0x10004)
cp210x_class->no_flow_control = true;
break;
default:
break;
}
return ret;
}
static int usbh_cp210x_enable(struct usbh_serial *serial)
{
return usbh_cp210x_control_out(serial, CP210X_IFC_ENABLE, 1, serial->intf, NULL, 0);
}
static int usbh_cp210x_set_chars(struct usbh_serial *serial)
{
struct cp210x_special_chars chars = { 0 };
return usbh_cp210x_control_out(serial, CP210X_SET_CHARS, 0, serial->intf, (uint8_t *)&chars, sizeof(struct cp210x_special_chars));
}
// static int usbh_cp210x_get_common_status(struct usbh_serial *serial, struct cp210x_comm_status *status)
// {
// return usbh_cp210x_control_in(serial, CP210X_GET_COMM_STATUS, 0, serial->intf, (uint8_t *)status, sizeof(struct cp210x_comm_status));
// }
static int usbh_cp210x_set_baudrate(struct usbh_serial *serial, uint32_t baudrate)
{
struct usb_setup_packet *setup;
struct usbh_cp210x *cp210x_class;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
cp210x_class = (struct usbh_cp210x *)serial->priv;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_BAUDRATE;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 4;
if (cp210x_class->use_actual_rate)
baudrate = cp210x_get_actual_rate(baudrate);
else if (baudrate < 1000000)
baudrate = cp210x_get_an205_rate(baudrate);
memcpy(serial->iobuffer, (uint8_t *)&baudrate, 4);
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
}
static int usbh_cp210x_set_data_format(struct usbh_serial *serial, uint8_t databits, uint8_t parity, uint8_t stopbits)
{
struct usb_setup_packet *setup;
uint16_t value;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
value = ((databits & 0x0F) << 8) | ((parity & 0x0f) << 4) | ((stopbits & 0x03) << 0);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_LINE_CTL;
setup->wValue = value;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_cp210x_attach(struct usbh_serial *serial)
{
int ret;
struct usbh_cp210x *cp210x_class = usb_osal_malloc(sizeof(struct usbh_cp210x));
if (!cp210x_class) {
return -USB_ERR_NOMEM;
}
memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
serial->priv = cp210x_class;
ret = usbh_cp210x_get_partnum(serial);
usbh_cp210x_init_max_speed(serial);
ret |= usbh_cp210x_enable(serial);
ret |= usbh_cp210x_set_chars(serial);
if (ret < 0) {
goto errout;
}
return 0;
errout:
serial->priv = NULL;
usb_osal_free(cp210x_class);
return ret;
}
static void usbh_cp210x_detach(struct usbh_serial *serial)
{
if (serial && serial->priv) {
serial->priv = NULL;
usb_osal_free(serial->priv);
}
}
int usbh_cp210x_set_flow_ctrl(struct usbh_serial *serial, bool enable)
{
struct cp210x_flow_ctl flow_ctl = { 0 };
uint32_t flow_repl;
uint32_t ctl_hs;
int ret;
ret = usbh_cp210x_control_in(serial, CP210X_GET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
if (ret < 0) {
return ret;
}
ctl_hs = flow_ctl.lControlHandshake;
flow_repl = flow_ctl.lFlowReplace;
ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
flow_repl &= ~CP210X_SERIAL_AUTO_RECEIVE;
flow_repl &= ~CP210X_SERIAL_AUTO_TRANSMIT;
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
if (enable) {
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
} else {
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
}
flow_ctl.lControlHandshake = ctl_hs;
flow_ctl.lFlowReplace = flow_repl;
return usbh_cp210x_control_out(serial, CP210X_SET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
}
int usbh_cp210x_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
int ret;
ret = usbh_cp210x_set_baudrate(serial, line_coding->dwDTERate);
if (ret < 0) {
return ret;
}
return usbh_cp210x_set_data_format(serial, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat);
}
int usbh_cp210x_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
struct cp210x_flow_ctl flow_ctl = { 0 };
uint32_t flow_repl;
uint32_t ctl_hs;
uint16_t control = 0;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
if (serial->rtscts) {
ret = usbh_cp210x_control_in(serial, CP210X_GET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
if (ret < 0) {
return ret;
}
ctl_hs = flow_ctl.lControlHandshake;
flow_repl = flow_ctl.lFlowReplace;
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
if (dtr)
ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
else
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
if (rts)
flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
else
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
flow_ctl.lControlHandshake = ctl_hs;
flow_ctl.lFlowReplace = flow_repl;
return usbh_cp210x_control_out(serial, CP210X_SET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
} else {
if (dtr) {
control |= CP210X_CONTROL_DTR;
}
if (rts) {
control |= CP210X_CONTROL_RTS;
}
control |= CP210X_CONTROL_WRITE_DTR;
control |= CP210X_CONTROL_WRITE_RTS;
return usbh_cp210x_control_out(serial, CP210X_SET_MHS, control, serial->intf, NULL, 0);
}
}
static int usbh_cp210x_get_modem_status(struct usbh_serial *serial)
{
int ret;
uint8_t control;
uint16_t status;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
ret = usbh_cp210x_control_in(serial, CP210X_GET_MDMSTS, 0, serial->intf, (uint8_t *)&control, 1);
if (ret < 0) {
return ret;
}
status = ((control & CP210X_CONTROL_DTR) ? USBH_SERIAL_TIOCM_DTR : 0) |
((control & CP210X_CONTROL_RTS) ? USBH_SERIAL_TIOCM_RTS : 0) |
((control & CP210X_CONTROL_CTS) ? USBH_SERIAL_TIOCM_CTS : 0) |
((control & CP210X_CONTROL_DSR) ? USBH_SERIAL_TIOCM_DSR : 0) |
((control & CP210X_CONTROL_RING) ? USBH_SERIAL_TIOCM_RI : 0) |
((control & CP210X_CONTROL_DCD) ? USBH_SERIAL_TIOCM_CD : 0);
return status;
}
static const struct usbh_serial_driver cp210x_driver = {
.driver_name = "cp210x",
.ignore_rx_header = 0,
.ignore_tx_header = 0,
.attach = usbh_cp210x_attach,
.detach = usbh_cp210x_detach,
.set_flow_control = usbh_cp210x_set_flow_ctrl,
.set_line_coding = usbh_cp210x_set_line_coding,
.get_line_coding = NULL,
.set_line_state = usbh_cp210x_set_line_state,
.get_modem_status = usbh_cp210x_get_modem_status,
};
static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &cp210x_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
static const uint16_t cp210x_id_table[][2] = {
{ 0x10C4, 0xEA60 },
{ 0, 0 },
};
const struct usbh_class_driver cp210x_class_driver = {
.driver_name = "cp210x",
.connect = usbh_cp210x_connect,
.disconnect = usbh_cp210x_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = cp210x_id_table,
.class_driver = &cp210x_class_driver
};

187
class/serial/usbh_cp210x.h Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CP210X_H
#define USBH_CP210X_H
#include "usb_cdc.h"
/* Requests */
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits
#define CP210X_GET_LINE_CTL 0x04
#define CP210X_SET_BREAK 0x05
#define CP210X_IMM_CHAR 0x06
#define CP210X_SET_MHS 0x07 // Set DTR, RTS
#define CP210X_GET_MDMSTS 0x08
#define CP210X_SET_XON 0x09
#define CP210X_SET_XOFF 0x0A
#define CP210X_SET_EVENTMASK 0x0B
#define CP210X_GET_EVENTMASK 0x0C
#define CP210X_SET_CHAR 0x0D
#define CP210X_GET_CHARS 0x0E
#define CP210X_GET_PROPS 0x0F
#define CP210X_GET_COMM_STATUS 0x10
#define CP210X_RESET 0x11
#define CP210X_PURGE 0x12
#define CP210X_SET_FLOW 0x13
#define CP210X_GET_FLOW 0x14
#define CP210X_EMBED_EVENTS 0x15
#define CP210X_GET_EVENTSTATE 0x16
#define CP210X_SET_CHARS 0x19
#define CP210X_GET_BAUDRATE 0x1D
#define CP210X_SET_BAUDRATE 0x1E // Set baudrate
#define CP210X_VENDOR_SPECIFIC 0xFF
/* CP210X_VENDOR_SPECIFIC values */
#define CP210X_GET_FW_VER 0x000E
#define CP210X_READ_2NCONFIG 0x000E
#define CP210X_GET_FW_VER_2N 0x0010
#define CP210X_READ_LATCH 0x00C2
#define CP210X_GET_PARTNUM 0x370B
#define CP210X_GET_PORTCONFIG 0x370C
#define CP210X_GET_DEVICEMODE 0x3711
#define CP210X_WRITE_LATCH 0x37E1
/* CP210X_IFC_ENABLE */
#define CP210X_UART_ENABLE 0x0001
#define CP210X_UART_DISABLE 0x0000
/* CP210X_(SET|GET)_BAUDDIV */
#define CP210X_BAUD_RATE_GEN_FREQ 0x384000
/* CP210X_(SET|GET)_LINE_CTL */
#define CP210X_BITS_DATA_MASK 0X0f00
#define CP210X_BITS_DATA_5 0X0500
#define CP210X_BITS_DATA_6 0X0600
#define CP210X_BITS_DATA_7 0X0700
#define CP210X_BITS_DATA_8 0X0800
#define CP210X_BITS_DATA_9 0X0900
#define CP210X_BITS_PARITY_MASK 0x00f0
#define CP210X_BITS_PARITY_NONE 0x0000
#define CP210X_BITS_PARITY_ODD 0x0010
#define CP210X_BITS_PARITY_EVEN 0x0020
#define CP210X_BITS_PARITY_MARK 0x0030
#define CP210X_BITS_PARITY_SPACE 0x0040
#define CP210X_BITS_STOP_MASK 0x000f
#define CP210X_BITS_STOP_1 0x0000
#define CP210X_BITS_STOP_1_5 0x0001
#define CP210X_BITS_STOP_2 0x0002
/* CP210X_SET_BREAK */
#define CP210X_BREAK_ON 0x0001
#define CP210X_BREAK_OFF 0x0000
/* CP210X_(SET_MHS|GET_MDMSTS) */
#define CP210X_CONTROL_DTR 0x0001
#define CP210X_CONTROL_RTS 0x0002
#define CP210X_CONTROL_CTS 0x0010
#define CP210X_CONTROL_DSR 0x0020
#define CP210X_CONTROL_RING 0x0040
#define CP210X_CONTROL_DCD 0x0080
#define CP210X_CONTROL_WRITE_DTR 0x0100
#define CP210X_CONTROL_WRITE_RTS 0x0200
/* CP210X_(GET|SET)_CHARS */
struct cp210x_special_chars {
uint8_t bEofChar;
uint8_t bErrorChar;
uint8_t bBreakChar;
uint8_t bEventChar;
uint8_t bXonChar;
uint8_t bXoffChar;
};
/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
struct cp210x_comm_status {
uint32_t ulErrors;
uint32_t ulHoldReasons;
uint32_t ulAmountInInQueue;
uint32_t ulAmountInOutQueue;
uint8_t bEofReceived;
uint8_t bWaitForImmediate;
uint8_t bReserved;
} __PACKED;
/*
* CP210X_PURGE - 16 bits passed in wValue of USB request.
* SiLabs app note AN571 gives a strange description of the 4 bits:
* bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
* writing 1 to all, however, purges cp2108 well enough to avoid the hang.
*/
#define PURGE_ALL 0x000f
/* CP210X_EMBED_EVENTS */
#define CP210X_ESCCHAR 0xec
#define CP210X_LSR_OVERRUN BIT(1)
#define CP210X_LSR_PARITY BIT(2)
#define CP210X_LSR_FRAME BIT(3)
#define CP210X_LSR_BREAK BIT(4)
/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
struct cp210x_flow_ctl {
uint32_t lControlHandshake;
uint32_t lFlowReplace;
uint32_t lXonLimit;
uint32_t lXoffLimit;
};
/* cp210x_flow_ctl::ulControlHandshake */
#define CP210X_SERIAL_DTR_MASK (0x03 << 0)
#define CP210X_SERIAL_DTR_INACTIVE (0 << 0)
#define CP210X_SERIAL_DTR_ACTIVE (1 << 0)
#define CP210X_SERIAL_DTR_FLOW_CTL (2 << 0)
#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
/* cp210x_flow_ctl::ulFlowReplace */
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
#define CP210X_SERIAL_ERROR_CHAR BIT(2)
#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
#define CP210X_SERIAL_BREAK_CHAR BIT(4)
#define CP210X_SERIAL_RTS_MASK (0x03 << 6)
#define CP210X_SERIAL_RTS_INACTIVE (0 << 6)
#define CP210X_SERIAL_RTS_ACTIVE (1 << 6)
#define CP210X_SERIAL_RTS_FLOW_CTL (2 << 6)
#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
struct cp210x_pin_mode {
uint8_t eci;
uint8_t sci;
};
#define CP210X_PIN_MODE_MODEM 0
#define CP210X_PIN_MODE_GPIO BIT(0)
/* Part number definitions */
#define CP210X_PARTNUM_CP2101 0x01
#define CP210X_PARTNUM_CP2102 0x02
#define CP210X_PARTNUM_CP2103 0x03
#define CP210X_PARTNUM_CP2104 0x04
#define CP210X_PARTNUM_CP2105 0x05
#define CP210X_PARTNUM_CP2108 0x08
#define CP210X_PARTNUM_CP2102N_QFN28 0x20
#define CP210X_PARTNUM_CP2102N_QFN24 0x21
#define CP210X_PARTNUM_CP2102N_QFN20 0x22
#define CP210X_PARTNUM_UNKNOWN 0xFF
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBH_CP210X_H */

407
class/serial/usbh_ftdi.c Normal file
View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#include "usbh_ftdi.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_ftdi"
#include "usb_log.h"
enum ftdi_chip_type {
SIO,
FT232A,
FT232B,
FT2232C,
FT232R,
FT232H,
FT2232H,
FT4232H,
FT4232HA,
FT232HP,
FT233HP,
FT2232HP,
FT2233HP,
FT4232HP,
FT4233HP,
FTX,
};
static const char *ftdi_chip_name[] = {
[SIO] = "SIO", /* the serial part of FT8U100AX */
[FT232A] = "FT232A",
[FT232B] = "FT232B",
[FT2232C] = "FT2232C/D",
[FT232R] = "FT232R",
[FT232H] = "FT232H",
[FT2232H] = "FT2232H",
[FT4232H] = "FT4232H",
[FT4232HA] = "FT4232HA",
[FT232HP] = "FT232HP",
[FT233HP] = "FT233HP",
[FT2232HP] = "FT2232HP",
[FT2233HP] = "FT2233HP",
[FT4232HP] = "FT4232HP",
[FT4233HP] = "FT4233HP",
[FTX] = "FT-X",
};
struct usbh_ftdi {
enum ftdi_chip_type chip_type;
};
static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, int base)
{
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
uint32_t divisor;
/* divisor shifted 3 bits to the left */
int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
divisor = divisor3 >> 3;
divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
if (divisor == 1) /* 1.0 */
divisor = 0;
else if (divisor == 0x4001) /* 1.5 */
divisor = 1;
return divisor;
}
static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud)
{
return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
}
static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, int base)
{
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
uint32_t divisor;
int divisor3;
/* hi-speed baud rate is 10-bit sampling instead of 16-bit */
divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
divisor = divisor3 >> 3;
divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
if (divisor == 1) /* 1.0 */
divisor = 0;
else if (divisor == 0x4001) /* 1.5 */
divisor = 1;
/*
* Set this bit to turn off a divide by 2.5 on baud rate generator
* This enables baud rates up to 12Mbaud but cannot reach below 1200
* baud with this bit set
*/
divisor |= 0x00020000;
return divisor;
}
static uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud)
{
return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
}
int usbh_ftdi_reset(struct usbh_serial *serial)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_RESET;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_set_baudrate(struct usbh_serial *serial, uint32_t baudrate)
{
struct usb_setup_packet *setup;
struct usbh_ftdi *ftdi_class;
uint32_t div_value;
uint16_t value;
uint8_t baudrate_high;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
ftdi_class = (struct usbh_ftdi *)serial->priv;
switch (ftdi_class->chip_type) {
case FT232B:
case FT2232C:
case FT232R:
if (baudrate > 3000000) {
return -USB_ERR_INVAL;
}
div_value = ftdi_232bm_baud_to_divisor(baudrate);
break;
default:
if ((baudrate <= 12000000) && (baudrate >= 1200)) {
div_value = ftdi_2232h_baud_to_divisor(baudrate);
} else if (baudrate < 1200) {
div_value = ftdi_232bm_baud_to_divisor(baudrate);
} else {
return -USB_ERR_INVAL;
}
break;
}
value = div_value & 0xFFFF;
baudrate_high = (div_value >> 16) & 0xff;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_SET_BAUDRATE;
setup->wValue = value;
setup->wIndex = (baudrate_high << 8) | serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_set_data_format(struct usbh_serial *serial, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
{
/**
* D0-D7 databits BITS_7=7, BITS_8=8
* D8-D10 parity NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
* D11-D12 STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
* D14 BREAK_OFF=0, BREAK_ON=1
**/
struct usb_setup_packet *setup;
uint16_t value;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_SET_DATA;
setup->wValue = value;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_set_latency_timer(struct usbh_serial *serial, uint16_t value)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_SET_LATENCY_TIMER;
setup->wValue = value;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_attach(struct usbh_serial *serial)
{
uint16_t version;
uint8_t chip_type;
int ret;
version = serial->hport->device_desc.bcdDevice;
switch (version) {
case 0x400:
chip_type = FT232B;
break;
case 0x500:
chip_type = FT2232C;
break;
case 0x600:
chip_type = FT232R;
break;
case 0x700:
chip_type = FT2232H;
break;
case 0x900:
chip_type = FT232H;
break;
default:
USB_LOG_ERR("Unsupported FTDI chip version: 0x%04x\r\n", version);
return -USB_ERR_NOTSUPP;
}
USB_LOG_INFO("chip name: %s\r\n", ftdi_chip_name[chip_type]);
struct usbh_ftdi *ftdi_class = usb_osal_malloc(sizeof(struct usbh_ftdi));
if (!ftdi_class) {
USB_LOG_ERR("No memory for ftdi_class\r\n");
return -USB_ERR_NOMEM;
}
memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
serial->priv = ftdi_class;
ftdi_class->chip_type = chip_type;
ret = usbh_ftdi_set_latency_timer(serial, 0x10);
if (ret < 0) {
goto errout;
}
return 0;
errout:
serial->priv = NULL;
usb_osal_free(ftdi_class);
return ret;
}
static void usbh_ftdi_detach(struct usbh_serial *serial)
{
if (serial && serial->priv) {
serial->priv = NULL;
usb_osal_free(serial->priv);
}
}
static int usbh_ftdi_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_SET_FLOW_CTRL;
setup->wValue = hardctrl ? FTDI_SIO_RTS_CTS_HS : FTDI_SIO_DISABLE_FLOW_CTRL;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
int ret = usbh_ftdi_set_baudrate(serial, line_coding->dwDTERate);
if (ret < 0) {
return ret;
}
return usbh_ftdi_set_data_format(serial, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
}
static int usbh_ftdi_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
struct usb_setup_packet *setup;
uint16_t value = 0;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
value = ((dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_SET_MODEM_CTRL;
setup->wValue = value;
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_ftdi_get_modem_status(struct usbh_serial *serial)
{
struct usb_setup_packet *setup;
uint16_t status = 0;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = FTDI_SIO_GET_MODEM_STATUS;
setup->wValue = 0x0000;
setup->wIndex = serial->intf;
setup->wLength = 2;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return 0;
}
status = (serial->iobuffer[0] & FTDI_SIO_DSR_MASK ? USBH_SERIAL_TIOCM_DSR : 0) |
(serial->iobuffer[0] & FTDI_SIO_CTS_MASK ? USBH_SERIAL_TIOCM_CTS : 0) |
(serial->iobuffer[0] & FTDI_SIO_RI_MASK ? USBH_SERIAL_TIOCM_RI : 0) |
(serial->iobuffer[0] & FTDI_SIO_RLSD_MASK ? USBH_SERIAL_TIOCM_CD : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
return status;
}
static const struct usbh_serial_driver ftdi_driver = {
.driver_name = "ftdi",
.ignore_rx_header = 2,
.ignore_tx_header = 0,
.attach = usbh_ftdi_attach,
.detach = usbh_ftdi_detach,
.set_flow_control = usbh_ftdi_set_flow_ctrl,
.set_line_coding = usbh_ftdi_set_line_coding,
.get_line_coding = NULL,
.set_line_state = usbh_ftdi_set_line_state,
.get_modem_status = usbh_ftdi_get_modem_status,
};
static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &ftdi_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
static const uint16_t ftdi_id_table[][2] = {
{ 0x0403, 0x6001 },
{ 0x0403, 0x6010 },
{ 0x0403, 0x6014 },
{ 0, 0 },
};
const struct usbh_class_driver ftdi_class_driver = {
.driver_name = "ftdi",
.connect = usbh_ftdi_connect,
.disconnect = usbh_ftdi_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = ftdi_id_table,
.class_driver = &ftdi_class_driver
};

341
class/serial/usbh_ftdi.h Normal file
View File

@@ -0,0 +1,341 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_FTDI_H
#define USBH_FTDI_H
#include "usb_cdc.h"
#define FTDI_VID 0x0403 /* Vendor Id */
/* FTDI device PIDs */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
#define FTDI_FT2233HP_PID 0x6040 /* Dual channel hi-speed device with PD */
#define FTDI_FT4233HP_PID 0x6041 /* Quad channel hi-speed device with PD */
#define FTDI_FT2232HP_PID 0x6042 /* Dual channel hi-speed device with PD */
#define FTDI_FT4232HP_PID 0x6043 /* Quad channel hi-speed device with PD */
#define FTDI_FT233HP_PID 0x6044 /* Dual channel hi-speed device with PD */
#define FTDI_FT232HP_PID 0x6045 /* Dual channel hi-speed device with PD */
#define FTDI_FT4232HA_PID 0x6048 /* Quad channel automotive grade hi-speed device */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
/* Requests */
#define FTDI_SIO_RESET 0x00 /* Reset the port */
#define FTDI_SIO_SET_MODEM_CTRL 0x01 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 0x02 /* Set flow control register */
#define FTDI_SIO_SET_BAUDRATE 0x03 /* Set baud rate */
#define FTDI_SIO_SET_DATA 0x04 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_MODEM_STATUS 0x05
#define FTDI_SIO_SET_EVENT_CHAR 0x06
#define FTDI_SIO_SET_ERROR_CHAR 0x07
#define FTDI_SIO_SET_LATENCY_TIMER 0x09
#define FTDI_SIO_GET_LATENCY_TIMER 0x0A
#define FTDI_SIO_SET_BITMODE 0x0B
#define FTDI_SIO_READ_PINS 0x0C
#define FTDI_SIO_READ_EEPROM 0x90
#define FTDI_SIO_WRITE_EEPROM 0x91
#define FTDI_SIO_ERASE_EEPROM 0x92
/* Channel indices for FT2232, FT2232H and FT4232H devices */
#define FTDI_SIO_CHANNEL_A 1
#define FTDI_SIO_CHANNEL_B 2
#define FTDI_SIO_CHANNEL_C 3
#define FTDI_SIO_CHANNEL_D 4
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_RESET
* wValue: Control Value
* 0 = Reset SIO
* 1 = Purge RX buffer
* 2 = Purge TX buffer
* wIndex: Port
* wLength: 0
* Data: None
*
* The Reset SIO command has this effect:
*
* Sets flow control set to 'none'
* Event char = $0D
* Event trigger = disabled
* Purge RX buffer
* Purge TX buffer
* Clear DTR
* Clear RTS
* baud and data format not reset
*
* The Purge RX and TX buffer commands affect nothing except the buffers
*
*/
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_BAUDRATE
* wValue: BaudDivisor value - see below
* wIndex: Port
* wLength: 0
* Data: None
* The BaudDivisor values are calculated as follows:
* - BaseClock is either 12000000 or 48000000 depending on the device.
* FIXME: I wish I knew how to detect old chips to select proper base clock!
* - BaudDivisor is a fixed point number encoded in a funny way.
* (--WRONG WAY OF THINKING--)
* BaudDivisor is a fixed point number encoded with following bit weighs:
* (-2)(-1)(13..0). It is a radical with a denominator of 4, so values
* end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...).
* (--THE REALITY--)
* The both-bits-set has quite different meaning from 0.75 - the chip
* designers have decided it to mean 0.125 instead of 0.75.
* This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates
* and Flow Control Consideration for USB to RS232".
* - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should
* automagically re-encode the resulting value to take fractions into
* consideration.
* As all values are integers, some bit twiddling is in order:
* BaudDivisor = (BaseClock / 16 / BaudRate) |
* (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5
* : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000 // 0.25
* : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000 // 0.125
* : 0)
*
* For the FT232BM, a 17th divisor bit was introduced to encode the multiples
* of 0.125 missing from the FT8U232AM. Bits 16 to 14 are coded as follows
* (the first four codes are the same as for the FT8U232AM, where bit 16 is
* always 0):
* 000 - add .000 to divisor
* 001 - add .500 to divisor
* 010 - add .250 to divisor
* 011 - add .125 to divisor
* 100 - add .375 to divisor
* 101 - add .625 to divisor
* 110 - add .750 to divisor
* 111 - add .875 to divisor
* Bits 15 to 0 of the 17-bit divisor are placed in the urb value. Bit 16 is
* placed in bit 0 of the urb index.
*
* Note that there are a couple of special cases to support the highest baud
* rates. If the calculated divisor value is 1, this needs to be replaced with
* 0. Additionally for the FT232BM, if the calculated divisor value is 0x4001
* (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is
* not supported by the FT8U232AM).
*/
enum ftdi_sio_baudrate {
ftdi_sio_b300 = 0,
ftdi_sio_b600 = 1,
ftdi_sio_b1200 = 2,
ftdi_sio_b2400 = 3,
ftdi_sio_b4800 = 4,
ftdi_sio_b9600 = 5,
ftdi_sio_b19200 = 6,
ftdi_sio_b38400 = 7,
ftdi_sio_b57600 = 8,
ftdi_sio_b115200 = 9
};
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_DATA
* wValue: Data characteristics (see below)
* wIndex: Port
* wLength: 0
* Data: No
*
* Data characteristics
*
* B0..7 Number of data bits
* B8..10 Parity
* 0 = None
* 1 = Odd
* 2 = Even
* 3 = Mark
* 4 = Space
* B11..13 Stop Bits
* 0 = 1
* 1 = 1.5
* 2 = 2
* B14
* 1 = TX ON (break)
* 0 = TX OFF (normal state)
* B15 Reserved
*
*/
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_MODEM_CTRL
* wValue: ControlValue (see below)
* wIndex: Port
* wLength: 0
* Data: None
*
* NOTE: If the device is in RTS/CTS flow control, the RTS set by this
* command will be IGNORED without an error being returned
* Also - you can not set DTR and RTS with one control message
*
* ControlValue
* B0 DTR state
* 0 = reset
* 1 = set
* B1 RTS state
* 0 = reset
* 1 = set
* B2..7 Reserved
* B8 DTR state enable
* 0 = ignore
* 1 = use DTR state
* B9 RTS state enable
* 0 = ignore
* 1 = use RTS state
* B10..15 Reserved
*
*/
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
/*
* BmRequestType: 0100 0000b
* bRequest: FTDI_SIO_SET_FLOW_CTRL
* wValue: Xoff/Xon
* wIndex: Protocol/Port - hIndex is protocol / lIndex is port
* wLength: 0
* Data: None
*
* hIndex protocol is:
* B0 Output handshaking using RTS/CTS
* 0 = disabled
* 1 = enabled
* B1 Output handshaking using DTR/DSR
* 0 = disabled
* 1 = enabled
* B2 Xon/Xoff handshaking
* 0 = disabled
* 1 = enabled
*
* A value of zero in the hIndex field disables handshaking
*
* If Xon/Xoff handshaking is specified, the hValue field should contain the
* XOFF character and the lValue field contains the XON character.
*/
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_SIO_GET_MODEM_STATUS
* wValue: zero
* wIndex: Port
* wLength: 1
* Data: Status
*
* One byte of data is returned
* B0..3 0
* B4 CTS
* 0 = inactive
* 1 = active
* B5 DSR
* 0 = inactive
* 1 = active
* B6 Ring Indicator (RI)
* 0 = inactive
* 1 = active
* B7 Receive Line Signal Detect (RLSD)
* 0 = inactive
* 1 = active
*/
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */
#define FTDI_SIO_BITMODE_RESET 0x00
#define FTDI_SIO_BITMODE_CBUS 0x20
/*
* IN Endpoint
*
* The device reserves the first two bytes of data on this endpoint to contain
* the current values of the modem and line status registers. In the absence of
* data, the device generates a message consisting of these two status bytes
* every 40 ms
*
* Byte 0: Modem Status
*
* Offset Description
* B0 Reserved - must be 1
* B1 Reserved - must be 0
* B2 Reserved - must be 0
* B3 Reserved - must be 0
* B4 Clear to Send (CTS)
* B5 Data Set Ready (DSR)
* B6 Ring Indicator (RI)
* B7 Receive Line Signal Detect (RLSD)
*
* Byte 1: Line Status
*
* Offset Description
* B0 Data Ready (DR)
* B1 Overrun Error (OE)
* B2 Parity Error (PE)
* B3 Framing Error (FE)
* B4 Break Interrupt (BI)
* B5 Transmitter Holding Register (THRE)
* B6 Transmitter Empty (TEMT)
* B7 Error in RCVR FIFO
*
*/
#define FTDI_RS0_CTS (1 << 4)
#define FTDI_RS0_DSR (1 << 5)
#define FTDI_RS0_RI (1 << 6)
#define FTDI_RS0_RLSD (1 << 7)
#define FTDI_RS_DR 1
#define FTDI_RS_OE (1 << 1)
#define FTDI_RS_PE (1 << 2)
#define FTDI_RS_FE (1 << 3)
#define FTDI_RS_BI (1 << 4)
#define FTDI_RS_THRE (1 << 5)
#define FTDI_RS_TEMT (1 << 6)
#define FTDI_RS_FIFO (1 << 7)
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBH_FTDI_H */

131
class/serial/usbh_gsm.c Normal file
View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_gsm"
#include "usb_log.h"
struct usbh_gsm {
struct usb_endpoint_descriptor *intin;
struct usbh_urb intin_urb;
struct usb_osal_timer *modem_timer;
uint16_t modem_status;
};
static int usbh_gsm_attach(struct usbh_serial *serial)
{
struct usb_endpoint_descriptor *ep_desc;
struct usbh_gsm *gsm_class = usb_osal_malloc(sizeof(struct usbh_gsm));
if (!gsm_class) {
USB_LOG_ERR("No memory for gsm_class\r\n");
return -USB_ERR_NOMEM;
}
memset(gsm_class, 0, sizeof(struct usbh_gsm));
serial->priv = gsm_class;
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(gsm_class->intin, ep_desc);
break;
} else {
}
}
}
if (!gsm_class->intin) {
USB_LOG_WRN("Do not find interrupt endpoint, so disable modem status monitor\r\n");
}
return 0;
}
static void usbh_gsm_detach(struct usbh_serial *serial)
{
struct usbh_gsm *gsm_class;
if (!serial || !serial->priv) {
return;
}
gsm_class = (struct usbh_gsm *)serial->priv;
if (gsm_class->intin) {
usbh_kill_urb(&gsm_class->intin_urb);
}
serial->priv = NULL;
usb_osal_free(gsm_class);
}
static int usbh_gsm_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
return 0;
}
static int usbh_gsm_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
return 0;
}
static const struct usbh_serial_driver gsm_driver = {
.driver_name = "gsm",
.ignore_rx_header = 0,
.ignore_tx_header = 0,
.attach = usbh_gsm_attach,
.detach = usbh_gsm_detach,
.set_flow_control = NULL,
.set_line_coding = usbh_gsm_set_line_coding,
.get_line_coding = NULL,
.set_line_state = usbh_gsm_set_line_state,
.get_modem_status = NULL,
};
static int usbh_gsm_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &gsm_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_gsm_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
const struct usbh_class_driver gsm_class_driver = {
.driver_name = "gsm",
.connect = usbh_gsm_connect,
.disconnect = usbh_gsm_disconnect
};
static const uint16_t gsm_id_table[][2] = {
{ 0x2C7C, 0x0120 }, /* Quectel EC20 */
{ 0x2C7C, 0x0121 }, /* Quectel EC21 */
{ 0x2C7C, 0x0125 }, /* Quectel EC25 */
{ 0x2C7C, 0x0191 }, /* Quectel EG91 */
{ 0x2C7C, 0x0195 }, /* Quectel EG95 */
{ 0x2C7C, 0x6002 }, /* Quectel EC200/EC600/EC800/EG91x */
{ 0x1E0E, 0x9001 }, /* SIMCOM SIM7600 */
{ 0x2ECC, 0x3012 }, /* Chinamobile ML307R */
{ 0, 0 },
};
CLASS_INFO_DEFINE const struct usbh_class_info gsm_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = gsm_id_table,
.class_driver = &gsm_class_driver
};

726
class/serial/usbh_pl2303.c Normal file
View File

@@ -0,0 +1,726 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
* Copyright (c) 2024, Derek Konigsberg
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#include "usbh_pl2303.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_pl2303"
#include "usb_log.h"
#define UART_STATE_INDEX 8
#define UART_STATE_MSR_MASK 0x8b
#define UART_STATE_TRANSIENT_MASK 0x74
#define UART_DCD 0x01
#define UART_DSR 0x02
#define UART_BREAK_ERROR 0x04
#define UART_RING 0x08
#define UART_FRAME_ERROR 0x10
#define UART_PARITY_ERROR 0x20
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
struct pl2303_type_data {
const char *name;
uint32_t max_baud_rate;
unsigned long quirks;
unsigned int no_autoxonxoff : 1;
unsigned int no_divisors : 1;
unsigned int alt_divisors : 1;
};
enum pl2303_type {
TYPE_H,
TYPE_HX,
TYPE_TA,
TYPE_TB,
TYPE_HXD,
TYPE_HXN,
TYPE_COUNT
};
struct usbh_pl2303 {
enum pl2303_type chip_type;
uint32_t quirks;
struct usb_endpoint_descriptor *intin;
struct usbh_urb intin_urb;
struct usb_osal_timer *modem_timer;
uint16_t modem_status;
};
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
[TYPE_H] = {
.name = "PL2303H",
.max_baud_rate = 1228800,
.quirks = PL2303_QUIRK_LEGACY,
.no_autoxonxoff = true,
},
[TYPE_HX] = {
.name = "PL2303HX",
.max_baud_rate = 6000000,
},
[TYPE_TA] = {
.name = "PL2303TA",
.max_baud_rate = 6000000,
.alt_divisors = true,
},
[TYPE_TB] = {
.name = "PL2303TB",
.max_baud_rate = 12000000,
.alt_divisors = true,
},
[TYPE_HXD] = {
.name = "PL2303HXD",
.max_baud_rate = 12000000,
},
[TYPE_HXN] = {
.name = "PL2303G",
.max_baud_rate = 12000000,
.no_divisors = true,
},
};
/*
* Returns the nearest supported baud rate that can be set directly without
* using divisors.
*/
static uint32_t pl2303_get_supported_baud_rate(uint32_t baud)
{
static const uint32_t baud_sup[] = {
75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
614400, 921600, 1228800, 2457600, 3000000, 6000000
};
unsigned i;
for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
if (baud_sup[i] > baud)
break;
}
if (i == ARRAY_SIZE(baud_sup))
baud = baud_sup[i - 1];
else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
baud = baud_sup[i - 1];
else
baud = baud_sup[i];
return baud;
}
/*
* NOTE: If unsupported baud rates are set directly, the PL2303 seems to
* use 9600 baud.
*/
static uint32_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
uint32_t baud)
{
memcpy(buf, &baud, 4);
return baud;
}
static uint32_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4],
uint32_t baud)
{
unsigned int baseline, mantissa, exponent;
/*
* Apparently, for the TA version the formula is:
* baudrate = 12M * 32 / (mantissa * 2^exponent)
* where
* mantissa = buf[10:0]
* exponent = buf[15:13 16]
*/
baseline = 12000000 * 32;
mantissa = baseline / baud;
if (mantissa == 0)
mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */
exponent = 0;
while (mantissa >= 2048) {
if (exponent < 15) {
mantissa >>= 1; /* divide by 2 */
exponent++;
} else {
/* Exponent is maxed. Trim mantissa and leave. */
mantissa = 2047;
break;
}
}
buf[3] = 0x80;
buf[2] = exponent & 0x01;
buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8;
buf[0] = mantissa & 0xff;
/* Calculate and return the exact baud rate. */
baud = (baseline / mantissa) >> exponent;
return baud;
}
static uint32_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
uint32_t baud)
{
unsigned int baseline, mantissa, exponent;
/*
* Apparently the formula is:
* baudrate = 12M * 32 / (mantissa * 4^exponent)
* where
* mantissa = buf[8:0]
* exponent = buf[11:9]
*/
baseline = 12000000 * 32;
mantissa = baseline / baud;
if (mantissa == 0)
mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */
exponent = 0;
while (mantissa >= 512) {
if (exponent < 7) {
mantissa >>= 2; /* divide by 4 */
exponent++;
} else {
/* Exponent is maxed. Trim mantissa and leave. */
mantissa = 511;
break;
}
}
buf[3] = 0x80;
buf[2] = 0;
buf[1] = exponent << 1 | mantissa >> 8;
buf[0] = mantissa & 0xff;
/* Calculate and return the exact baud rate. */
baud = (baseline / mantissa) >> (exponent << 1);
return baud;
}
static int pl2303_vendor_write(struct usbh_serial *serial, uint16_t wValue, uint16_t wIndex)
{
struct usb_setup_packet *setup;
struct usbh_pl2303 *pl2303_class;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
pl2303_class = (struct usbh_pl2303 *)serial->priv;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = pl2303_class->chip_type == TYPE_HXN ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST;
setup->wValue = wValue;
setup->wIndex = wIndex;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int pl2303_vendor_read(struct usbh_serial *serial, uint16_t wValue, uint8_t *data)
{
struct usb_setup_packet *setup;
struct usbh_pl2303 *pl2303_class;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
pl2303_class = (struct usbh_pl2303 *)serial->priv;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = pl2303_class->chip_type == TYPE_HXN ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST;
setup->wValue = wValue;
setup->wIndex = 0;
setup->wLength = 1;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return ret;
}
memcpy(data, serial->iobuffer, 1);
return ret;
}
static bool pl2303_supports_hx_status(struct usbh_serial *serial)
{
int ret;
uint8_t buf;
ret = pl2303_vendor_read(serial, PL2303_READ_TYPE_HX_STATUS, &buf);
if (ret < 0) {
return false;
}
return true;
}
static bool pl2303_is_hxd_clone(struct usbh_serial *serial)
{
struct usb_setup_packet *setup;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return false;
}
return true;
}
static int pl2303_update_reg(struct usbh_serial *serial, uint8_t reg, uint8_t mask, uint8_t val)
{
int ret;
uint8_t buf[1];
struct usbh_pl2303 *pl2303_class;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
pl2303_class = (struct usbh_pl2303 *)serial->priv;
if (pl2303_class->chip_type == TYPE_HXN)
ret = pl2303_vendor_read(serial, reg, buf);
else
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
if (ret < 0) {
return ret;
}
*buf &= ~mask;
*buf |= val & mask;
return pl2303_vendor_write(serial, reg, *buf);
}
static int usbh_pl2303_get_chiptype(struct usbh_serial *serial)
{
if (serial->hport->device_desc.bDeviceClass == 0x02) {
return TYPE_H; /* variant 0 */
}
if (serial->hport->device_desc.bMaxPacketSize0 != 0x40) {
if (serial->hport->device_desc.bDeviceClass == 0x00 || serial->hport->device_desc.bDeviceClass == 0xff)
return TYPE_H; /* variant 1 */
return TYPE_H; /* variant 0 */
}
switch (serial->hport->device_desc.bcdUSB) {
case 0x101:
/* USB 1.0.1? Let's assume they meant 1.1... */
case 0x110:
switch (serial->hport->device_desc.bcdDevice) {
case 0x300:
return TYPE_HX;
case 0x400:
return TYPE_HXD;
default:
return TYPE_HX;
}
break;
case 0x200:
switch (serial->hport->device_desc.bcdDevice) {
case 0x100: /* GC */
case 0x105:
return TYPE_HXN;
case 0x300: /* GT / TA */
if (pl2303_supports_hx_status(serial))
return TYPE_TA;
__attribute__((fallthrough));
case 0x305:
case 0x400: /* GL */
case 0x405:
return TYPE_HXN;
case 0x500: /* GE / TB */
if (pl2303_supports_hx_status(serial))
return TYPE_TB;
__attribute__((fallthrough));
case 0x505:
case 0x600: /* GS */
case 0x605:
case 0x700: /* GR */
case 0x705:
case 0x905: /* GT-2AB */
case 0x1005: /* GC-Q20 */
return TYPE_HXN;
}
break;
}
USB_LOG_ERR("Unsupported PL2303 Device\r\n");
return -USB_ERR_NOTSUPP;
}
static int usbh_pl2303_attach(struct usbh_serial *serial)
{
struct usbh_pl2303 *pl2303_class;
struct usb_endpoint_descriptor *ep_desc;
uint8_t type;
int ret;
ret = usbh_pl2303_get_chiptype(serial);
if (ret < 0) {
return ret;
}
pl2303_class = usb_osal_malloc(sizeof(struct usbh_pl2303));
if (pl2303_class == NULL) {
USB_LOG_ERR("Fail to alloc pl2303_class\r\n");
return -USB_ERR_NOMEM;
}
memset(pl2303_class, 0, sizeof(struct usbh_pl2303));
serial->priv = pl2303_class;
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(pl2303_class->intin, ep_desc);
break;
} else {
}
}
}
if (!pl2303_class->intin) {
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
ret = -USB_ERR_NODEV;
goto errout;
}
type = (uint8_t)ret;
pl2303_class->chip_type = type;
pl2303_class->quirks = pl2303_type_data[pl2303_class->chip_type].quirks;
USB_LOG_INFO("chip type: %s\r\n", pl2303_type_data[pl2303_class->chip_type].name);
if (type == TYPE_HXD && pl2303_is_hxd_clone(serial)) {
pl2303_class->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE;
}
if (type != TYPE_HXN) {
uint8_t buf[1];
ret = pl2303_vendor_read(serial, 0x8484, buf);
ret |= pl2303_vendor_write(serial, 0x0404, 0);
ret |= pl2303_vendor_read(serial, 0x8484, buf);
ret |= pl2303_vendor_read(serial, 0x8383, buf);
ret |= pl2303_vendor_read(serial, 0x8484, buf);
ret |= pl2303_vendor_write(serial, 0x0404, 1);
ret |= pl2303_vendor_read(serial, 0x8484, buf);
ret |= pl2303_vendor_read(serial, 0x8383, buf);
ret |= pl2303_vendor_write(serial, 0, 1);
ret |= pl2303_vendor_write(serial, 1, 0);
if (pl2303_class->quirks & PL2303_QUIRK_LEGACY)
ret |= pl2303_vendor_write(serial, 2, 0x24);
else
ret |= pl2303_vendor_write(serial, 2, 0x44);
} else {
ret = 0;
}
if (ret < 0) {
USB_LOG_ERR("pl2303 init failed\r\n");
goto errout;
}
return 0;
errout:
serial->priv = NULL;
usb_osal_free(pl2303_class);
return ret;
}
static void usbh_pl2303_detach(struct usbh_serial *serial)
{
struct usbh_pl2303 *pl2303_class;
if (!serial || !serial->priv) {
return;
}
pl2303_class = (struct usbh_pl2303 *)serial->priv;
if (pl2303_class->intin) {
usbh_kill_urb(&pl2303_class->intin_urb);
}
serial->priv = NULL;
usb_osal_free(pl2303_class);
}
static int usbh_pl2303_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
{
struct usbh_pl2303 *pl2303_class;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
pl2303_class = (struct usbh_pl2303 *)serial->priv;
if (hardctrl) {
if (pl2303_class->quirks & PL2303_QUIRK_LEGACY) {
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
} else if (pl2303_class->chip_type == TYPE_HXN) {
return pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_RTS_CTS);
} else {
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
}
} else {
if (pl2303_class->chip_type == TYPE_HXN) {
return pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_NONE);
} else {
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
}
}
}
static int usbh_pl2303_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
struct usbh_pl2303 *pl2303_class;
uint32_t baud;
uint32_t baud_sup;
uint8_t buf[7];
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
pl2303_class = (struct usbh_pl2303 *)serial->priv;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 7;
baud = line_coding->dwDTERate;
if (pl2303_type_data[pl2303_class->chip_type].max_baud_rate) {
baud = MIN(baud, pl2303_type_data[pl2303_class->chip_type].max_baud_rate);
}
/*
* Use direct method for supported baud rates, otherwise use divisors.
* Newer chip types do not support divisor encoding.
*/
if (pl2303_type_data[pl2303_class->chip_type].no_divisors)
baud_sup = baud;
else
baud_sup = pl2303_get_supported_baud_rate(baud);
if (baud == baud_sup)
baud = pl2303_encode_baud_rate_direct(buf, baud);
else if (pl2303_type_data[pl2303_class->chip_type].alt_divisors)
baud = pl2303_encode_baud_rate_divisor_alt(buf, baud);
else
baud = pl2303_encode_baud_rate_divisor(buf, baud);
buf[4] = line_coding->bCharFormat;
buf[5] = line_coding->bParityType;
buf[6] = line_coding->bDataBits;
memcpy(serial->iobuffer, buf, sizeof(struct cdc_line_coding));
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
}
static int usbh_pl2303_get_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
int ret;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
setup->wValue = 0;
setup->wIndex = serial->intf;
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
if (ret < 0) {
return ret;
}
memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding));
return ret;
}
static int usbh_pl2303_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
{
struct usb_setup_packet *setup;
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
setup = serial->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
setup->wValue = (dtr << 0) | (rts << 1);
setup->wIndex = serial->intf;
setup->wLength = 0;
return usbh_control_transfer(serial->hport, setup, NULL);
}
static int usbh_pl2303_get_modem_status(struct usbh_serial *serial)
{
struct usbh_pl2303 *pl2303_class;
uintptr_t flags;
uint16_t status;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
pl2303_class = (struct usbh_pl2303 *)serial->priv;
status = (pl2303_class->modem_status & UART_DSR ? USBH_SERIAL_TIOCM_DSR : 0) |
(pl2303_class->modem_status & UART_CTS ? USBH_SERIAL_TIOCM_CTS : 0) |
(pl2303_class->modem_status & UART_RING ? USBH_SERIAL_TIOCM_RI : 0) |
(pl2303_class->modem_status & UART_DCD ? USBH_SERIAL_TIOCM_CD : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
usb_osal_leave_critical_section(flags);
return status;
}
#ifdef CONFIG_USBH_SERIAL_GET_MODEM_STATUS
static int __usbh_pl2303_get_modem_status(struct usbh_serial *serial)
{
struct usbh_pl2303 *pl2303_class;
uint8_t status = 0;
uint16_t difference;
uintptr_t flags;
int ret;
if (!serial || !serial->hport || !serial->priv) {
return -USB_ERR_INVAL;
}
pl2303_class = (struct usbh_pl2303 *)serial->priv;
usbh_int_urb_fill(&pl2303_class->intin_urb, serial->hport, pl2303_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], pl2303_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
ret = usbh_submit_urb(&pl2303_class->intin_urb);
if (ret < 0) {
return ret;
}
if (ret < 1) {
return -USB_ERR_INVAL;
}
flags = usb_osal_enter_critical_section();
status = serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
difference = pl2303_class->modem_status ^ status;
pl2303_class->modem_status = status;
if (status & UART_BREAK_ERROR)
serial->iocount.brk++;
if (difference & UART_STATE_MSR_MASK) {
if (difference & UART_CTS)
serial->iocount.cts++;
if (difference & UART_DSR)
serial->iocount.dsr++;
if (difference & UART_RING)
serial->iocount.rng++;
if (difference & UART_DCD) {
serial->iocount.dcd++;
}
}
usb_osal_leave_critical_section(flags);
return ret;
}
#endif
static const struct usbh_serial_driver pl2303_driver = {
.driver_name = "pl2303",
.ignore_rx_header = 0,
.ignore_tx_header = 0,
.attach = usbh_pl2303_attach,
.detach = usbh_pl2303_detach,
.set_flow_control = usbh_pl2303_set_flow_ctrl,
.set_line_coding = usbh_pl2303_set_line_coding,
.get_line_coding = usbh_pl2303_get_line_coding,
.set_line_state = usbh_pl2303_set_line_state,
.get_modem_status = usbh_pl2303_get_modem_status,
};
static int usbh_pl2303_connect(struct usbh_hubport *hport, uint8_t intf)
{
return usbh_serial_probe(hport, intf, &pl2303_driver) ? 0 : -USB_ERR_NOMEM;
}
static int usbh_pl2303_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial) {
usbh_serial_remove(serial);
}
return 0;
}
static const uint16_t pl2303_id_table[][2] = {
{ 0x067B, 0x2303 }, // PL2303 Serial (ATEN/IOGEAR UC232A)
{ 0x067B, 0x2304 }, // PL2303HXN Serial, type TB
{ 0x067B, 0x23A3 }, // PL2303HXN Serial, type GC
{ 0x067B, 0x23B3 }, // PL2303HXN Serial, type GB
{ 0x067B, 0x23C3 }, // PL2303HXN Serial, type GT
{ 0x067B, 0x23D3 }, // PL2303HXN Serial, type GL
{ 0x067B, 0x23E3 }, // PL2303HXN Serial, type GE
{ 0x067B, 0x23F3 }, // PL2303HXN Serial, type GS
{ 0, 0 },
};
const struct usbh_class_driver pl2303_class_driver = {
.driver_name = "pl2303",
.connect = usbh_pl2303_connect,
.disconnect = usbh_pl2303_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info pl2303_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = pl2303_id_table,
.class_driver = &pl2303_class_driver
};

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 ~ 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_PL2303_H
#define USBH_PL2303_H
#include "usb_cdc.h"
#define PL2303_VENDOR_WRITE_REQUEST 0x01
#define PL2303_VENDOR_WRITE_NREQUEST 0x80
#define PL2303_VENDOR_READ_REQUEST 0x01
#define PL2303_VENDOR_READ_NREQUEST 0x81
#define PL2303_FLOWCTRL_MASK 0xf0
#define PL2303_READ_TYPE_HX_STATUS 0x8080
#define PL2303_HXN_RESET_REG 0x07
#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
#define PL2303_HXN_FLOWCTRL_REG 0x0a
#define PL2303_HXN_FLOWCTRL_MASK 0x1c
#define PL2303_HXN_FLOWCTRL_NONE 0x1c
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0)
#define PL2303_QUIRK_LEGACY BIT(1)
#define PL2303_QUIRK_ENDPOINT_HACK BIT(2)
#define PL2303_QUIRK_NO_BREAK_GETLINE BIT(3)
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBH_PL2303_H */

743
class/serial/usbh_serial.c Normal file
View File

@@ -0,0 +1,743 @@
/*
* Copyright (c) 2025, sakumisu
* Copyright (c) 2025, MDLZCOOL
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_serial.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_serial"
#include "usb_log.h"
#define DEV_FORMAT_VENDOR "/dev/ttyUSB%d"
#define DEV_FORMAT_CDC_ACM "/dev/ttyACM%d"
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS];
static uint32_t g_devinuse = 0;
static uint32_t g_cdcacm_devinuse = 0;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + USBH_SERIAL_RX2_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)];
/* refer to cherryrb */
static int usbh_serial_ringbuffer_init(usbh_serial_ringbuf_t *rb, void *pool, uint32_t size)
{
if (NULL == rb) {
return -1;
}
if (NULL == pool) {
return -1;
}
if ((size < 2) || (size & (size - 1))) {
return -1;
}
rb->in = 0;
rb->out = 0;
rb->mask = size - 1;
rb->pool = pool;
return 0;
}
static void usbh_serial_ringbuffer_reset(usbh_serial_ringbuf_t *rb)
{
rb->in = 0;
rb->out = 0;
}
static uint32_t usbh_serial_ringbuffer_get_used(usbh_serial_ringbuf_t *rb)
{
return rb->in - rb->out;
}
static uint32_t usbh_serial_ringbuffer_write(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
{
uint32_t unused;
uint32_t offset;
uint32_t remain;
unused = (rb->mask + 1) - (rb->in - rb->out);
if (size > unused) {
size = unused;
}
offset = rb->in & rb->mask;
remain = rb->mask + 1 - offset;
remain = remain > size ? size : remain;
memcpy(((uint8_t *)(rb->pool)) + offset, data, remain);
memcpy(rb->pool, (uint8_t *)data + remain, size - remain);
rb->in += size;
return size;
}
static uint32_t usbh_serial_ringbuffer_peek(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
{
uint32_t used;
uint32_t offset;
uint32_t remain;
used = rb->in - rb->out;
if (size > used) {
size = used;
}
offset = rb->out & rb->mask;
remain = rb->mask + 1 - offset;
remain = remain > size ? size : remain;
memcpy(data, ((uint8_t *)(rb->pool)) + offset, remain);
memcpy((uint8_t *)data + remain, rb->pool, size - remain);
return size;
}
static uint32_t usbh_serial_ringbuffer_read(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
{
size = usbh_serial_ringbuffer_peek(rb, data, size);
rb->out += size;
return size;
}
static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm)
{
uint8_t devno;
uint8_t devno2;
for (devno = 0; devno < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_serial_class[devno], 0, sizeof(struct usbh_serial));
g_serial_class[devno].minor = devno;
g_serial_class[devno].cdc_minor = -1;
g_serial_class[devno].iobuffer = g_serial_iobuffer[devno];
g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0);
if (is_cdcacm) {
for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) {
if ((g_cdcacm_devinuse & (1U << devno2)) == 0) {
g_cdcacm_devinuse |= (1U << devno2);
g_serial_class[devno].cdc_minor = devno2;
return &g_serial_class[devno];
}
}
g_devinuse &= ~(1U << devno);
return NULL;
} else {
return &g_serial_class[devno];
}
}
}
return NULL;
}
static void usbh_serial_free(struct usbh_serial *serial)
{
uint8_t devno = serial->minor;
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
if (serial->cdc_minor >= 0) {
g_cdcacm_devinuse &= ~(1U << serial->cdc_minor);
}
if (g_serial_class[devno].rx_complete_sem) {
usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem);
}
}
static void usbh_serial_callback(void *arg, int nbytes)
{
struct usbh_serial *serial = (struct usbh_serial *)arg;
int ret;
if (nbytes < 0) {
if (nbytes != -USB_ERR_SHUTDOWN) {
USB_LOG_ERR("serial transfer error: %d\n", nbytes);
}
serial->rx_errorcode = nbytes;
usb_osal_sem_give(serial->rx_complete_sem);
return;
}
if (nbytes < serial->driver->ignore_rx_header) {
USB_LOG_ERR("serial rx short packet: %d\n", nbytes);
serial->rx_errorcode = -USB_ERR_IO;
usb_osal_sem_give(serial->rx_complete_sem);
return;
}
if (nbytes >= serial->driver->ignore_rx_header) {
/* resubmit the read urb */
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
0, usbh_serial_callback, serial);
ret = usbh_submit_urb(&serial->bulkin_urb);
if (ret < 0) {
USB_LOG_ERR("serial submit failed: %d\n", ret);
serial->rx_errorcode = ret;
usb_osal_sem_give(serial->rx_complete_sem);
return;
}
usbh_serial_ringbuffer_write(&serial->rx_rb,
&serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
(nbytes - serial->driver->ignore_rx_header));
if (serial->rx_complete_callback) {
serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
}
serial->rx_buf_index ^= 1;
serial->rx_errorcode = 0;
usb_osal_sem_give(serial->rx_complete_sem);
}
}
struct usbh_serial *usbh_serial_probe(struct usbh_hubport *hport, uint8_t intf,
const struct usbh_serial_driver *driver)
{
struct usb_endpoint_descriptor *ep_desc;
struct usbh_serial *serial;
bool is_cdcacm = false;
int ret;
if (strcmp(driver->driver_name, "cdc_acm") == 0) {
is_cdcacm = true;
}
serial = usbh_serial_alloc(is_cdcacm);
if (serial == NULL) {
USB_LOG_ERR("Fail to alloc serial class\r\n");
return NULL;
}
serial->hport = hport;
serial->intf = intf;
serial->driver = driver;
if (driver->attach) {
ret = driver->attach(serial);
if (ret < 0) {
USB_LOG_ERR("Serial attach failed: %d\r\n", ret);
usbh_serial_free(serial);
return NULL;
}
}
if (is_cdcacm) {
intf = intf + 1; /* data interface */
}
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_BULK) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(serial->bulkin, ep_desc);
} else {
USBH_EP_INIT(serial->bulkout, ep_desc);
}
}
}
if (is_cdcacm) {
intf = intf - 1; /* data interface */
}
if (!serial->bulkin || !serial->bulkout) {
USB_LOG_ERR("Serial bulk in/out endpoint not found\r\n");
usbh_serial_free(serial);
return NULL;
}
if (is_cdcacm) {
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_CDC_ACM, serial->cdc_minor);
} else {
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_VENDOR, serial->minor);
}
hport->config.intf[intf].priv = serial;
USB_LOG_INFO("Register Serial Class: %s (%s)\r\n", hport->config.intf[intf].devname, driver->driver_name);
usbh_serial_run(serial);
return serial;
}
void usbh_serial_remove(struct usbh_serial *serial)
{
if (!serial || !serial->hport)
return;
usbh_serial_close(serial);
if (serial->driver && serial->driver->detach) {
serial->driver->detach(serial);
}
if (serial->hport->config.intf[serial->intf].priv) {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Serial Class: %s (%s)\r\n", serial->hport->config.intf[serial->intf].devname, serial->driver->driver_name);
usbh_serial_stop(serial);
}
usbh_serial_free(serial);
}
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags)
{
struct usbh_serial *serial;
int ret;
serial = usbh_find_class_instance(devname);
if (!serial) {
return NULL;
}
if (serial->ref_count != 0) {
USB_LOG_ERR("Device busy: %s\r\n", devname);
return NULL;
}
if (serial && serial->driver && serial->driver->open) {
ret = serial->driver->open(serial);
if (ret < 0) {
return NULL;
}
}
usbh_serial_ringbuffer_init(&serial->rx_rb, serial->rx_rb_pool, CONFIG_USBHOST_SERIAL_RX_SIZE);
serial->ref_count++;
serial->open_flags = open_flags;
return serial;
}
int usbh_serial_close(struct usbh_serial *serial)
{
if (!serial || !serial->hport) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return 0;
}
if (serial->bulkin) {
usbh_kill_urb(&serial->bulkin_urb);
}
if (serial->bulkout) {
usbh_kill_urb(&serial->bulkout_urb);
}
if (serial && serial->driver && serial->driver->set_flow_control && serial->rtscts) {
serial->driver->set_flow_control(serial, false);
}
if (serial && serial->driver && serial->driver->close) {
serial->driver->close(serial);
}
serial->ref_count--;
serial->rtscts = false;
return 0;
}
static int usbh_serial_tiocmset(struct usbh_serial *serial, uint32_t set, uint32_t clear)
{
int ret;
uint16_t line_state;
bool dtr;
bool rts;
if (!serial || !serial->hport || !serial->hport->connected) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
line_state = serial->line_state;
clear &= ~set; /* 'set' takes precedence over 'clear' */
if (set & USBH_SERIAL_TIOCM_DTR) {
line_state |= USBH_SERIAL_TIOCM_DTR;
}
if (set & USBH_SERIAL_TIOCM_RTS) {
line_state |= USBH_SERIAL_TIOCM_RTS;
}
if (clear & USBH_SERIAL_TIOCM_DTR) {
line_state &= ~USBH_SERIAL_TIOCM_DTR;
}
if (clear & USBH_SERIAL_TIOCM_RTS) {
line_state &= ~USBH_SERIAL_TIOCM_RTS;
}
dtr = (line_state & USBH_SERIAL_TIOCM_DTR) ? true : false;
rts = (line_state & USBH_SERIAL_TIOCM_RTS) ? true : false;
if (serial && serial->driver && serial->driver->set_line_state) {
ret = serial->driver->set_line_state(serial, dtr, rts);
} else {
return -USB_ERR_NOTSUPP;
}
serial->line_state = line_state;
return ret;
}
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg)
{
int ret;
if (!serial || !serial->hport || !serial->hport->connected) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
switch (cmd) {
case USBH_SERIAL_CMD_SET_ATTR: {
struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
struct cdc_line_coding line_coding;
line_coding.dwDTERate = termios->baudrate;
line_coding.bCharFormat = termios->stopbits;
line_coding.bParityType = termios->parity;
line_coding.bDataBits = termios->databits;
if (serial->bulkin) {
usbh_kill_urb(&serial->bulkin_urb);
}
if (serial->bulkout) {
usbh_kill_urb(&serial->bulkout_urb);
}
if (serial && serial->driver && serial->driver->set_line_coding) {
ret = serial->driver->set_line_coding(serial, &line_coding);
if (ret < 0) {
return ret;
}
} else {
return -USB_ERR_NOTSUPP;
}
memcpy(&serial->line_coding, &line_coding, sizeof(struct cdc_line_coding));
if (serial && serial->driver && serial->driver->set_flow_control) {
ret = serial->driver->set_flow_control(serial, termios->rtscts);
}
serial->rtscts = termios->rtscts;
serial->rx_timeout_ms = termios->rx_timeout;
ret = usbh_serial_tiocmset(serial, USBH_SERIAL_TIOCM_DTR | USBH_SERIAL_TIOCM_RTS, 0);
if (ret < 0) {
return ret;
}
usbh_serial_ringbuffer_reset(&serial->rx_rb);
usb_osal_sem_reset(serial->rx_complete_sem);
serial->rx_buf_index = 0;
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
0, usbh_serial_callback, serial);
ret = usbh_submit_urb(&serial->bulkin_urb);
return ret;
} break;
case USBH_SERIAL_CMD_GET_ATTR: {
struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
struct cdc_line_coding line_coding;
if (serial && serial->driver && serial->driver->get_line_coding) {
return serial->driver->get_line_coding(serial, &line_coding);
} else {
memcpy(&line_coding, &serial->line_coding, sizeof(struct cdc_line_coding));
}
termios->baudrate = line_coding.dwDTERate;
termios->stopbits = line_coding.bCharFormat;
termios->parity = line_coding.bParityType;
termios->databits = line_coding.bDataBits;
termios->rtscts = serial->rtscts;
termios->rx_timeout = serial->rx_timeout_ms;
return 0;
} break;
case USBH_SERIAL_CMD_IOCMBIS: {
uint32_t flags = *(uint32_t *)arg;
return usbh_serial_tiocmset(serial, flags, 0);
} break;
case USBH_SERIAL_CMD_IOCMBIC: {
uint32_t flags = *(uint32_t *)arg;
return usbh_serial_tiocmset(serial, 0, flags);
} break;
case USBH_SERIAL_CMD_TIOCMSET: {
uint32_t flags = *(uint32_t *)arg;
uint32_t set = 0;
uint32_t clear = 0;
set |= (flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
set |= (flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
clear |= !(flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
clear |= !(flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
return usbh_serial_tiocmset(serial, set, clear);
} break;
case USBH_SERIAL_CMD_TIOCMGET: {
uint32_t *flags = (uint32_t *)arg;
int status;
if (serial && serial->driver && serial->driver->get_modem_status) {
status = serial->driver->get_modem_status(serial);
if (status < 0) {
return status;
}
} else {
return -USB_ERR_NOTSUPP;
}
*flags = status;
} break;
default:
break;
}
return -USB_ERR_NOTSUPP;
}
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen)
{
int ret;
struct usbh_urb *urb;
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
urb = &serial->bulkout_urb;
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, (uint8_t *)buffer, buflen, 0xffffffff, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen)
{
int ret;
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !serial->line_coding.dwDTERate) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) {
return usbh_serial_ringbuffer_read(&serial->rx_rb, buffer, buflen);
} else {
if (usbh_serial_ringbuffer_get_used(&serial->rx_rb) == 0) {
ret = usb_osal_sem_take(serial->rx_complete_sem, serial->rx_timeout_ms == 0 ? USB_OSAL_WAITING_FOREVER : serial->rx_timeout_ms);
if (ret < 0) {
return ret;
}
if (serial->rx_errorcode < 0) {
return serial->rx_errorcode;
}
}
return usbh_serial_ringbuffer_read(&serial->rx_rb, buffer, buflen);
}
}
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
{
struct usbh_urb *urb;
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout || !complete || serial->line_coding.dwDTERate) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
urb = &serial->bulkout_urb;
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, buffer, buflen,
0, complete, serial);
return usbh_submit_urb(urb);
}
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
{
struct usbh_urb *urb;
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !complete || serial->line_coding.dwDTERate) {
return -USB_ERR_INVAL;
}
if (serial->ref_count == 0) {
return -USB_ERR_NODEV;
}
if (buflen % serial->bulkin->wMaxPacketSize) {
return -USB_ERR_INVAL;
}
urb = &serial->bulkin_urb;
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkin, buffer, MIN(buflen, serial->bulkin->wMaxPacketSize),
0, complete, serial);
return usbh_submit_urb(urb);
}
void usbh_serial_help(void)
{
USB_LOG_RAW("USB host serial test\r\n"
"Usage: usbh_serial <ttypath> [options]...\r\n"
"\r\n"
"-b <baud> set serial baudrate\r\n"
"-t <dtr> <rts> set rts and dtr\r\n"
"-w string write string\r\n"
"-r read data and dump\r\n"
"-x close serial device\r\n"
"\r\n");
}
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_testbuffer[512];
int usbh_serial(int argc, char **argv)
{
static struct usbh_serial *serial;
int ret;
if (argc < 3) {
usbh_serial_help();
return 0;
}
if (serial) {
if (!serial->hport || !serial->hport->connected) {
serial = NULL;
}
}
if (!serial) {
serial = usbh_serial_open(argv[1], USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
if (!serial) {
USB_LOG_ERR("Fail to open serial device: %s\r\n", argv[1]);
return -USB_ERR_INVAL;
}
}
if (strncmp(argv[2], "-b", 2) == 0 && argc >= 4) {
struct usbh_serial_termios termios;
memset(&termios, 0, sizeof(termios));
termios.baudrate = atoi(argv[3]);
termios.stopbits = 0;
termios.parity = 0;
termios.databits = 8;
termios.rtscts = false;
termios.rx_timeout = 0;
usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
} else if (strncmp(argv[2], "-t", 2) == 0 && argc >= 5) {
uint32_t flags;
flags = atoi(argv[3]) ? USBH_SERIAL_TIOCM_DTR : 0;
flags |= atoi(argv[4]) ? USBH_SERIAL_TIOCM_RTS : 0;
usbh_serial_control(serial, USBH_SERIAL_CMD_TIOCMSET, &flags);
USB_LOG_INFO("Set DTR: %d, RTS: %d\r\n", atoi(argv[3]), atoi(argv[4]));
} else if (strncmp(argv[2], "-w", 2) == 0 && argc >= 4) {
memcpy(g_serial_testbuffer, argv[3], MIN(strlen(argv[3]), sizeof(g_serial_testbuffer)));
uint32_t len = snprintf((char *)g_serial_testbuffer, sizeof(g_serial_testbuffer), "%s\r\n", argv[3]);
ret = usbh_serial_write(serial, g_serial_testbuffer, len);
if (ret >= 0) {
USB_LOG_INFO("Write %d bytes\r\n", ret);
} else {
USB_LOG_ERR("Write failed: %d\r\n", ret);
}
} else if (strncmp(argv[2], "-r", 2) == 0) {
ret = usbh_serial_read(serial, g_serial_testbuffer, sizeof(g_serial_testbuffer));
if (ret >= 0) {
usb_hexdump(g_serial_testbuffer, ret);
USB_LOG_INFO("Read %d bytes\r\n", ret);
} else {
USB_LOG_ERR("Read failed: %d\r\n", ret);
}
} else if (strncmp(argv[2], "-x", 2) == 0) {
usbh_serial_close(serial);
serial = NULL;
} else {
usbh_serial_help();
}
return 0;
}
__WEAK void usbh_serial_run(struct usbh_serial *serial)
{
(void)serial;
}
__WEAK void usbh_serial_stop(struct usbh_serial *serial)
{
(void)serial;
}
static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
const struct usbh_class_driver cdc_data_class_driver = {
.driver_name = "cdc_data",
.connect = usbh_cdc_data_connect,
.disconnect = usbh_cdc_data_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = USB_DEVICE_CLASS_CDC_DATA,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.class_driver = &cdc_data_class_driver
};

182
class/serial/usbh_serial.h Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2025, sakumisu
* Copyright (c) 2025, MDLZCOOL
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_SERIAL_H
#define USBH_SERIAL_H
#include "usb_cdc.h"
#define USBH_SERIAL_CTRL_NOCACHE_OFFSET 0
#define USBH_SERIAL_CTRL_NOCACHE_SIZE 32
#define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE)
#define USBH_SERIAL_INT_NOCACHE_SIZE 32
#define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
#define USBH_SERIAL_RX_NOCACHE_SIZE 512
#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
#define USBH_SERIAL_RX2_NOCACHE_SIZE 512
#define USBH_SERIAL_DATABITS_5 5
#define USBH_SERIAL_DATABITS_6 6
#define USBH_SERIAL_DATABITS_7 7
#define USBH_SERIAL_DATABITS_8 8
#define USBH_SERIAL_PARITY_NONE 0
#define USBH_SERIAL_PARITY_ODD 1
#define USBH_SERIAL_PARITY_EVEN 2
#define USBH_SERIAL_PARITY_MARK 3
#define USBH_SERIAL_PARITY_SPACE 4
#define USBH_SERIAL_STOPBITS_1 0
#define USBH_SERIAL_STOPBITS_1_5 1
#define USBH_SERIAL_STOPBITS_2 2
/* modem lines */
#define USBH_SERIAL_TIOCM_LE 0x001 /* line enable */
#define USBH_SERIAL_TIOCM_DTR 0x002 /* data terminal ready */
#define USBH_SERIAL_TIOCM_RTS 0x004 /* request to send */
#define USBH_SERIAL_TIOCM_ST 0x010 /* secondary transmit */
#define USBH_SERIAL_TIOCM_SR 0x020 /* secondary receive */
#define USBH_SERIAL_TIOCM_CTS 0x040 /* clear to send */
#define USBH_SERIAL_TIOCM_CAR 0x100 /* carrier detect */
#define USBH_SERIAL_TIOCM_CD USBH_SERIAL_TIOCM_CAR
#define USBH_SERIAL_TIOCM_RNG 0x200 /* ring */
#define USBH_SERIAL_TIOCM_RI USBH_SERIAL_TIOCM_RNG
#define USBH_SERIAL_TIOCM_DSR 0x400 /* data set ready */
#define USBH_SERIAL_TIOCM_OUT1 0x2000
#define USBH_SERIAL_TIOCM_OUT2 0x4000
#define USBH_SERIAL_TIOCM_LOOP 0x8000
#define USBH_SERIAL_O_RDONLY 0x0000 /* open for reading only */
#define USBH_SERIAL_O_WRONLY 0x0001 /* open for writing only */
#define USBH_SERIAL_O_RDWR 0x0002 /* open for reading and writing */
#define USBH_SERIAL_O_ACCMODE 0x0003 /* mask for above modes, from 4.4BSD https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/fcntl.h */
#define USBH_SERIAL_O_NONBLOCK 0x0004 /* non-blocking I/O, from BSD apple https://opensource.apple.com/source/xnu/xnu-1228.0.2/bsd/sys/fcntl.h */
#define USBH_SERIAL_CMD_SET_ATTR 0
#define USBH_SERIAL_CMD_GET_ATTR 1
#define USBH_SERIAL_CMD_IOCMBIS 2
#define USBH_SERIAL_CMD_IOCMBIC 3
#define USBH_SERIAL_CMD_TIOCMSET 4
#define USBH_SERIAL_CMD_TIOCMGET 5
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t in; /*!< Define the write pointer. */
uint32_t out; /*!< Define the read pointer. */
uint32_t mask; /*!< Define the write and read pointer mask. */
void *pool; /*!< Define the memory pointer. */
} usbh_serial_ringbuf_t;
/*
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
*/
struct usbh_serial_async_icount {
uint32_t cts, dsr, rng, dcd, tx, rx;
uint32_t frame, parity, overrun, brk;
uint32_t buf_overrun;
};
struct usbh_serial_termios {
uint32_t baudrate;
uint8_t databits;
uint8_t parity;
uint8_t stopbits;
bool rtscts; /* hardware flow control */
uint32_t rx_timeout;
};
struct usbh_serial;
typedef void (*usbh_serial_rx_complete_callback_t)(struct usbh_serial *serial, int nbytes);
/**
* @brief Serial Driver Operations
*/
struct usbh_serial_driver {
const char *driver_name;
uint8_t ignore_tx_header;
uint8_t ignore_rx_header;
int (*attach)(struct usbh_serial *serial);
void (*detach)(struct usbh_serial *serial);
int (*open)(struct usbh_serial *serial);
void (*close)(struct usbh_serial *serial);
int (*set_flow_control)(struct usbh_serial *serial, bool enable);
int (*set_line_coding)(struct usbh_serial *serial, struct cdc_line_coding *line_coding);
int (*get_line_coding)(struct usbh_serial *serial, struct cdc_line_coding *line_coding);
int (*set_line_state)(struct usbh_serial *serial, bool dtr, bool rts);
int (*get_modem_status)(struct usbh_serial *serial);
};
/**
* @brief Serial Instance
*/
struct usbh_serial {
struct usbh_hubport *hport;
uint8_t intf; /* Interface Number */
int minor; /* Serial Port Number (/dev/ttyUSBx or /dev/ttyACMx) */
int cdc_minor; /* Serial Port Number (/dev/ttyACMx) */
uint8_t *iobuffer; /* I/O buffer for serial transfers */
uint8_t ref_count; /* Reference Count */
uint32_t open_flags;
uint32_t rx_timeout_ms;
struct cdc_line_coding line_coding;
uint16_t line_state;
bool rtscts; /* hardware flow control */
struct usbh_serial_async_icount iocount;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
const struct usbh_serial_driver *driver;
usbh_serial_ringbuf_t rx_rb;
uint8_t rx_rb_pool[CONFIG_USBHOST_SERIAL_RX_SIZE];
usb_osal_sem_t rx_complete_sem;
uint8_t rx_buf_index;
int rx_errorcode;
usbh_serial_rx_complete_callback_t rx_complete_callback;
void *priv; /* Private Data */
void *user_data; /* User Data */
};
/* internal api */
struct usbh_serial *usbh_serial_probe(struct usbh_hubport *hport, uint8_t intf, const struct usbh_serial_driver *driver);
void usbh_serial_remove(struct usbh_serial *serial);
/* public api */
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags);
int usbh_serial_close(struct usbh_serial *serial);
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg);
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen);
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen);
/* cdc only api */
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
/* public weak api */
void usbh_serial_run(struct usbh_serial *serial);
void usbh_serial_stop(struct usbh_serial *serial);
int usbh_serial(int argc, char **argv);
#ifdef __cplusplus
}
#endif
#endif /* USBH_SERIAL_H */

View File

@@ -9,11 +9,11 @@ static uint32_t g_devinuse = 0;
static struct usbh_xxx *usbh_xxx_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CUSTOM_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_xxx_class[devno], 0, sizeof(struct usbh_xxx));
g_xxx_class[devno].minor = devno;
return &g_xxx_class[devno];
@@ -24,10 +24,10 @@ static struct usbh_xxx *usbh_xxx_class_alloc(void)
static void usbh_xxx_class_free(struct usbh_xxx *xxx_class)
{
int devno = xxx_class->minor;
uint8_t devno = xxx_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(xxx_class, 0, sizeof(struct usbh_xxx));
}
@@ -89,10 +89,9 @@ static const struct usbh_class_driver xxx_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = 0,
.subclass = 0,
.protocol = 0,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = 0,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.id_table = NULL,
.class_driver = &xxx_class_driver
};

View File

@@ -12,6 +12,8 @@ struct usbh_xxx {
uint8_t intf; /* interface number */
uint8_t minor;
void *user_data;
};
void usbh_xxx_run(struct usbh_xxx *xxx_class);

View File

@@ -14,12 +14,12 @@
#define DEV_FORMAT "/dev/asix"
static struct usbh_asix g_asix_class;
#define CONFIG_USBHOST_ASIX_ETH_MAX_SEGSZE (1514U + 8)
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_rx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_tx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_inttx_buffer[16];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_buf[32];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_buf[USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
#define ETH_ALEN 6
@@ -56,9 +56,14 @@ static int usbh_asix_read_cmd(struct usbh_asix *asix_class,
void *data,
uint16_t size)
{
struct usb_setup_packet *setup = asix_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
if (!asix_class || !asix_class->hport) {
return -USB_ERR_INVAL;
}
setup = asix_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = cmd;
setup->wValue = value;
@@ -66,10 +71,10 @@ static int usbh_asix_read_cmd(struct usbh_asix *asix_class,
setup->wLength = size;
ret = usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
if (ret < 0) {
if (ret < 8) {
return ret;
}
memcpy(data, g_asix_buf, ret - 8);
memcpy(data, g_asix_buf, MIN(ret - 8, size));
return ret;
}
@@ -81,7 +86,12 @@ static int usbh_asix_write_cmd(struct usbh_asix *asix_class,
void *data,
uint16_t size)
{
struct usb_setup_packet *setup = asix_class->hport->setup;
struct usb_setup_packet *setup;
if (!asix_class || !asix_class->hport) {
return -USB_ERR_INVAL;
}
setup = asix_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = cmd;
@@ -89,9 +99,12 @@ static int usbh_asix_write_cmd(struct usbh_asix *asix_class,
setup->wIndex = index;
setup->wLength = size;
memcpy(g_asix_buf, data, size);
return usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
if (data && size) {
memcpy(g_asix_buf, data, size);
return usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
} else {
return usbh_control_transfer(asix_class->hport, setup, NULL);
}
}
static int usbh_asix_mdio_write(struct usbh_asix *asix_class, int phy_id, int loc, int val)
@@ -263,6 +276,15 @@ static int usbh_asix_write_gpio(struct usbh_asix *asix_class, uint16_t value, in
static void usbh_asix_set_multicast(struct usbh_asix *asix_class)
{
uint16_t rx_ctl = AX_DEFAULT_RX_CTL | AX_RX_CTL_AM;
#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE == 4096
rx_ctl |= AX_RX_CTL_MFB_4096;
#elif CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE == 8192
rx_ctl |= AX_RX_CTL_MFB_8192;
#elif CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE == 16384
rx_ctl |= AX_RX_CTL_MFB_16384;
#else
rx_ctl |= AX_RX_CTL_MFB_2048;
#endif
const uint8_t multi_filter[] = { 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x40 };
usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MULTI_FILTER, 0, 0, (uint8_t *)multi_filter, AX_MCAST_FILTER_SIZE);
@@ -358,7 +380,7 @@ static int usbh_ax88772a_hw_reset(struct usbh_asix *asix_class)
if (ret < 0)
goto out;
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_PHY_SELECT, asix_class->embd_phy | AX_PHYSEL_SSEN, 0, 0, NULL);
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_PHY_SELECT, asix_class->embd_phy | AX_PHYSEL_SSEN, 0, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Select PHY #1 failed: %d\r\n", ret);
goto out;
@@ -422,7 +444,7 @@ static int usbh_ax88772a_hw_reset(struct usbh_asix *asix_class)
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, NULL);
AX88772_IPG2_DEFAULT, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Write IPG,IPG1,IPG2 failed: %d\r\n", ret);
goto out;
@@ -589,7 +611,7 @@ static int usbh_asix_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Init %s done\r\n", asix_class->name);
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register ASIX Class:%s\r\n", hport->config.intf[intf].devname);
usbh_asix_run(asix_class);
@@ -616,6 +638,7 @@ static int usbh_asix_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister ASIX Class:%s\r\n", hport->config.intf[intf].devname);
usbh_asix_stop(asix_class);
}
@@ -649,16 +672,20 @@ int usbh_asix_get_connect_status(struct usbh_asix *asix_class)
return 0;
}
void usbh_asix_rx_thread(void *argument)
void usbh_asix_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_asix_rx_length;
int ret;
err_t err;
uint16_t len;
uint16_t len_crc;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
uint32_t data_offset;
#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE <= (16 * 1024)
uint32_t transfer_size = CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE;
#else
uint32_t transfer_size = (16 * 1024);
#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create asix rx thread\r\n");
// clang-format off
find_class:
@@ -674,11 +701,12 @@ find_class:
usb_osal_msleep(100);
goto find_class;
}
usb_osal_msleep(128);
}
g_asix_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_asix_class.bulkin_urb, g_asix_class.hport, g_asix_class.bulkin, &g_asix_rx_buffer[g_asix_rx_length], USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize), USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_asix_class.bulkin_urb, g_asix_class.hport, g_asix_class.bulkin, &g_asix_rx_buffer[g_asix_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_asix_class.bulkin_urb);
if (ret < 0) {
goto find_class;
@@ -686,31 +714,44 @@ find_class:
g_asix_rx_length += g_asix_class.bulkin_urb.actual_length;
if (g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize)) {
len = ((uint16_t)g_asix_rx_buffer[0] | ((uint16_t)(g_asix_rx_buffer[1]) << 8)) & 0x7ff;
len_crc = g_asix_rx_buffer[2] | ((uint16_t)(g_asix_rx_buffer[3]) << 8);
if (len != (~len_crc & 0x7ff)) {
USB_LOG_ERR("asix rx header error\r\n");
continue;
}
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize).
* Short packet is zero, check if g_asix_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
*/
if (g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize) ||
(g_asix_class.bulkin_urb.actual_length < transfer_size)) {
USB_LOG_DBG("rxlen:%d\r\n", g_asix_rx_length);
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
memcpy(p->payload, (uint8_t *)&g_asix_rx_buffer[4], len);
g_asix_rx_length = 0;
data_offset = 0;
while (g_asix_rx_length > 0) {
len = ((uint16_t)g_asix_rx_buffer[data_offset + 0] | ((uint16_t)(g_asix_rx_buffer[data_offset + 1]) << 8)) & 0x7ff;
len_crc = g_asix_rx_buffer[data_offset + 2] | ((uint16_t)(g_asix_rx_buffer[data_offset + 3]) << 8);
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
if (len != (~len_crc & 0x7ff)) {
USB_LOG_ERR("rx header error\r\n");
g_asix_rx_length = 0;
continue;
}
uint8_t *buf = (uint8_t *)&g_asix_rx_buffer[data_offset + 4];
usbh_asix_eth_input(buf, len);
g_asix_rx_length -= (len + 4);
data_offset += (len + 4);
if (g_asix_rx_length < 4) {
g_asix_rx_length = 0;
}
} else {
g_asix_rx_length = 0;
USB_LOG_ERR("No memory to alloc pbuf for asix rx\r\n");
}
} else {
#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE <= (16 * 1024)
if (g_asix_rx_length == CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE) {
#else
if ((g_asix_rx_length + (16 * 1024)) > CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE) {
#endif
USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE\r\n");
while (1) {
}
}
}
}
// clang-format off
@@ -720,55 +761,45 @@ delete:
// clang-format on
}
err_t usbh_asix_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_asix_get_eth_txbuf(void)
{
return &g_asix_tx_buffer[4];
}
int usbh_asix_eth_output(uint32_t buflen)
{
int ret;
struct pbuf *q;
uint16_t actual_len;
uint8_t *buffer = &g_asix_tx_buffer[4];
if (g_asix_class.connect_status == false) {
return ERR_BUF;
return -USB_ERR_NOTCONN;
}
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
g_asix_tx_buffer[0] = p->tot_len & 0xff;
g_asix_tx_buffer[1] = (p->tot_len >> 8) & 0xff;
g_asix_tx_buffer[0] = buflen & 0xff;
g_asix_tx_buffer[1] = (buflen >> 8) & 0xff;
g_asix_tx_buffer[2] = ~g_asix_tx_buffer[0];
g_asix_tx_buffer[3] = ~g_asix_tx_buffer[1];
if (!(p->tot_len + 4) % USB_GET_MAXPACKETSIZE(g_asix_class.bulkout->wMaxPacketSize)) {
USB_LOG_DBG("txlen:%d\r\n", p->tot_len + 8);
g_asix_tx_buffer[p->tot_len + 4 + 0] = 0x00;
g_asix_tx_buffer[p->tot_len + 4 + 1] = 0x00;
g_asix_tx_buffer[p->tot_len + 4 + 2] = 0xff;
g_asix_tx_buffer[p->tot_len + 4 + 3] = 0xff;
actual_len = p->tot_len + 8;
if (!(buflen + 4) % USB_GET_MAXPACKETSIZE(g_asix_class.bulkout->wMaxPacketSize)) {
USB_LOG_DBG("txlen:%d\r\n", buflen + 8);
g_asix_tx_buffer[buflen + 4 + 0] = 0x00;
g_asix_tx_buffer[buflen + 4 + 1] = 0x00;
g_asix_tx_buffer[buflen + 4 + 2] = 0xff;
g_asix_tx_buffer[buflen + 4 + 3] = 0xff;
actual_len = buflen + 8;
} else {
USB_LOG_DBG("txlen:%d\r\n", p->tot_len + 4);
actual_len = p->tot_len + 4;
USB_LOG_DBG("txlen:%d\r\n", buflen + 4);
actual_len = buflen + 4;
}
usbh_bulk_urb_fill(&g_asix_class.bulkout_urb, g_asix_class.hport, g_asix_class.bulkout, g_asix_tx_buffer, actual_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_asix_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
return usbh_submit_urb(&g_asix_class.bulkout_urb);
}
__WEAK void usbh_asix_run(struct usbh_asix *asix_class)
{
}
__WEAK void usbh_asix_stop(struct usbh_asix *asix_class)
{
}
static const uint16_t asix_id_table[][2] = {
{ 0x0B95, 0x772B },
{ 0x0B95, 0x7720 },
{ 0, 0 },
};
static const struct usbh_class_driver asix_class_driver = {
.driver_name = "asix",
@@ -776,22 +807,11 @@ static const struct usbh_class_driver asix_class_driver = {
.disconnect = usbh_asix_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info ax88772b_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x0B95,
.pid = 0x772B,
CLASS_INFO_DEFINE const struct usbh_class_info asix_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = asix_id_table,
.class_driver = &asix_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info ax88772_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x0B95,
.pid = 0x7720,
.class_driver = &asix_class_driver
};
};

View File

@@ -6,9 +6,6 @@
#ifndef USBH_ASIX_H
#define USBH_ASIX_H
#include "lwip/netif.h"
#include "lwip/pbuf.h"
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
@@ -156,9 +153,7 @@ struct usbh_asix {
bool connect_status;
uint8_t mac[6];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
void *user_data;
};
#ifdef __cplusplus
@@ -170,8 +165,10 @@ int usbh_asix_get_connect_status(struct usbh_asix *asix_class);
void usbh_asix_run(struct usbh_asix *asix_class);
void usbh_asix_stop(struct usbh_asix *asix_class);
void usbh_asix_rx_thread(void *argument);
err_t usbh_asix_linkoutput(struct netif *netif, struct pbuf *p);
uint8_t *usbh_asix_get_eth_txbuf(void);
int usbh_asix_eth_output(uint32_t buflen);
void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_asix_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#ifdef __cplusplus
}

View File

@@ -12,13 +12,11 @@
#define DEV_FORMAT "/dev/rtl8152"
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SEGSZE (16 * 1024)
#define CONFIG_USBHOST_RTL8152_ETH_MAX_SEGSZE (2048)
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_inttx_buffer[USB_ALIGN_UP(2, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_rx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_tx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_inttx_buffer[2];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_buf[32];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_buf[USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_rtl8152 g_rtl8152_class;
@@ -949,9 +947,14 @@ static int usbh_rtl8152_read_regs(struct usbh_rtl8152 *rtl8152_class,
uint16_t size,
void *data)
{
struct usb_setup_packet *setup = rtl8152_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
if (!rtl8152_class || !rtl8152_class->hport) {
return -USB_ERR_INVAL;
}
setup = rtl8152_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = RTL8152_REQ_GET_REGS;
setup->wValue = value;
@@ -959,10 +962,10 @@ static int usbh_rtl8152_read_regs(struct usbh_rtl8152 *rtl8152_class,
setup->wLength = size;
ret = usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
if (ret < 0) {
if (ret < 8) {
return ret;
}
memcpy(data, g_rtl8152_buf, ret - 8);
memcpy(data, g_rtl8152_buf, MIN(ret - 8, size));
return ret;
}
@@ -973,7 +976,12 @@ static int usbh_rtl8152_write_regs(struct usbh_rtl8152 *rtl8152_class,
uint16_t size,
void *data)
{
struct usb_setup_packet *setup = rtl8152_class->hport->setup;
struct usb_setup_packet *setup;
if (!rtl8152_class || !rtl8152_class->hport) {
return -USB_ERR_INVAL;
}
setup = rtl8152_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = RTL8152_REQ_SET_REGS;
@@ -990,9 +998,10 @@ static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t si
{
uint16_t limit = 64;
int ret = 0;
uint8_t *buf = data;
/* both size and indix must be 4 bytes align */
if ((size & 3) || !size || (index & 3) || !data)
if ((size & 3) || !size || (index & 3) || !buf)
return -USB_ERR_INVAL;
if ((uint32_t)index + (uint32_t)size > 0xffff)
@@ -1000,20 +1009,20 @@ static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t si
while (size) {
if (size > limit) {
ret = usbh_rtl8152_read_regs(tp, index, type, limit, data);
ret = usbh_rtl8152_read_regs(tp, index, type, limit, buf);
if (ret < 0)
break;
index += limit;
data += limit;
buf += limit;
size -= limit;
} else {
ret = usbh_rtl8152_read_regs(tp, index, type, size, data);
ret = usbh_rtl8152_read_regs(tp, index, type, size, buf);
if (ret < 0)
break;
index += size;
data += size;
buf += size;
size = 0;
break;
}
@@ -1025,16 +1034,17 @@ static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t si
static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen,
uint16_t size, void *data, uint16_t type)
{
int ret;
int ret = -USB_ERR_INVAL;
uint16_t byteen_start, byteen_end, byen;
uint16_t limit = 512;
uint8_t *buf = data;
/* both size and indix must be 4 bytes align */
if ((size & 3) || !size || (index & 3) || !data)
return -USB_ERR_INVAL;
if ((size & 3) || !size || (index & 3) || !buf)
return ret;
if ((uint32_t)index + (uint32_t)size > 0xffff)
return -USB_ERR_INVAL;
return ret;
byteen_start = byteen & BYTE_EN_START_MASK;
byteen_end = byteen & BYTE_EN_END_MASK;
@@ -1043,12 +1053,12 @@ static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t b
/* Split the first DWORD if the byte_en is not 0xff */
if (byen != BYTE_EN_DWORD) {
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, data);
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, buf);
if (ret < 0)
goto error1;
index += 4;
data += 4;
buf += 4;
size -= 4;
}
@@ -1063,22 +1073,22 @@ static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t b
if (size > limit) {
ret = usbh_rtl8152_write_regs(tp, index,
type | BYTE_EN_DWORD,
limit, data);
limit, buf);
if (ret < 0)
goto error1;
index += limit;
data += limit;
buf += limit;
size -= limit;
} else {
ret = usbh_rtl8152_write_regs(tp, index,
type | BYTE_EN_DWORD,
size, data);
size, buf);
if (ret < 0)
goto error1;
index += size;
data += size;
buf += size;
size = 0;
break;
}
@@ -1086,7 +1096,7 @@ static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t b
/* Set the last DWORD */
if (byen != BYTE_EN_DWORD)
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, data);
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, buf);
}
error1:
@@ -1111,7 +1121,7 @@ static inline int usb_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_
static uint32_t ocp_read_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
{
uint32_t data;
uint32_t data = 0;
generic_ocp_read(tp, index, sizeof(data), &data, type);
@@ -1128,7 +1138,7 @@ static void ocp_write_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t ind
static uint16_t ocp_read_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
{
uint32_t data;
uint32_t tmp;
uint32_t tmp = 0;
uint16_t byen = BYTE_EN_WORD;
uint8_t shift = index & 2;
@@ -1168,7 +1178,7 @@ static void ocp_write_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t inde
static uint8_t ocp_read_byte(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
{
uint32_t data;
uint32_t tmp;
uint32_t tmp = 0;
uint8_t shift = index & 3;
index &= ~3;
@@ -1244,7 +1254,7 @@ static inline int r8152_mdio_read(struct usbh_rtl8152 *tp, uint32_t reg_addr)
static uint8_t usbh_rtl8152_get_version(struct usbh_rtl8152 *rtl8152_class)
{
uint8_t version;
uint32_t temp;
uint32_t temp = 0;
uint32_t ocp_data;
usbh_rtl8152_read_regs(rtl8152_class, PLA_TCR0, MCU_TYPE_PLA, 4, &temp);
@@ -1586,8 +1596,8 @@ static void r8153_teredo_off(struct usbh_rtl8152 *tp)
case RTL_VER_15:
default:
/* The bit 0 ~ 7 are relative with teredo settings. They are
* W1C (write 1 to clear), so set all 1 to disable it.
*/
* W1C (write 1 to clear), so set all 1 to disable it.
*/
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
break;
}
@@ -2034,13 +2044,13 @@ static int usbh_rtl8152_connect(struct usbh_hubport *hport, uint8_t intf)
rtl8152_class->rtl_ops.init(rtl8152_class);
rtl8152_class->rtl_ops.up(rtl8152_class);
if (rtl8152_class->rx_buf_sz > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SEGSZE) {
USB_LOG_ERR("rx_buf_sz is overflow, default is %d\r\n", CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SEGSZE);
if (rtl8152_class->rx_buf_sz > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
USB_LOG_ERR("rx_buf_sz is overflow, default is %d\r\n", (unsigned int)CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE);
return -USB_ERR_NOMEM;
}
memset(mac_buffer, 0, 12);
ret = usbh_get_string_desc(rtl8152_class->hport, 3, (uint8_t *)mac_buffer);
ret = usbh_get_string_desc(rtl8152_class->hport, 3, (uint8_t *)mac_buffer, 12);
if (ret < 0) {
return ret;
}
@@ -2083,7 +2093,7 @@ static int usbh_rtl8152_connect(struct usbh_hubport *hport, uint8_t intf)
}
}
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register RTL8152 Class:%s\r\n", hport->config.intf[intf].devname);
@@ -2111,6 +2121,7 @@ static int usbh_rtl8152_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister rtl8152 Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rtl8152_stop(rtl8152_class);
}
@@ -2121,16 +2132,19 @@ static int usbh_rtl8152_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
void usbh_rtl8152_rx_thread(void *argument)
void usbh_rtl8152_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_rtl8152_rx_length;
int ret;
err_t err;
uint16_t len;
uint16_t data_offset;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
uint32_t transfer_size = CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE;
#else
uint32_t transfer_size = (16 * 1024);
#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create rtl8152 rx thread\r\n");
// clang-format off
find_class:
@@ -2160,7 +2174,7 @@ find_class:
g_rtl8152_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, &g_rtl8152_rx_buffer[g_rtl8152_rx_length], USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize), USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, &g_rtl8152_rx_buffer[g_rtl8152_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rtl8152_class.bulkin_urb);
if (ret < 0) {
goto find_class;
@@ -2168,7 +2182,12 @@ find_class:
g_rtl8152_rx_length += g_rtl8152_class.bulkin_urb.actual_length;
if (g_rtl8152_class.bulkin_urb.actual_length != USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize)) {
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize).
* Short packet is zero, check if g_rtl8152_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
*/
if (g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize) ||
(g_rtl8152_class.bulkin_urb.actual_length < transfer_size)) {
data_offset = 0;
USB_LOG_DBG("rxlen:%d\r\n", g_rtl8152_rx_length);
@@ -2179,17 +2198,9 @@ find_class:
USB_LOG_DBG("data_offset:%d, eth len:%d\r\n", data_offset, len);
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
memcpy(p->payload, (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)], len);
uint8_t *buf = (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)];
usbh_rtl8152_eth_input(buf, len);
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
} else {
USB_LOG_ERR("No memory to alloc pbuf for rtl8152 rx\r\n");
}
data_offset += (len + sizeof(struct rx_desc));
g_rtl8152_rx_length -= (len + sizeof(struct rx_desc));
@@ -2199,6 +2210,15 @@ find_class:
}
}
} else {
#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
if (g_rtl8152_rx_length == CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
#else
if ((g_rtl8152_rx_length + (16 * 1024)) > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
#endif
USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE\r\n");
while (1) {
}
}
}
}
// clang-format off
@@ -2208,45 +2228,33 @@ delete:
// clang-format on
}
err_t usbh_rtl8152_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_rtl8152_get_eth_txbuf(void)
{
int ret;
struct pbuf *q;
uint8_t *buffer;
struct tx_desc *tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
return (g_rtl8152_tx_buffer + sizeof(struct tx_desc));
}
int usbh_rtl8152_eth_output(uint32_t buflen)
{
struct tx_desc *tx_desc;
if (g_rtl8152_class.connect_status == false) {
return ERR_BUF;
return -USB_ERR_NOTCONN;
}
tx_desc->opts1 = p->tot_len | TX_FS | TX_LS;
tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
tx_desc->opts1 = buflen | TX_FS | TX_LS;
tx_desc->opts2 = 0;
buffer = g_rtl8152_tx_buffer + sizeof(struct tx_desc);
USB_LOG_DBG("txlen:%d\r\n", buflen + sizeof(struct tx_desc));
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
USB_LOG_DBG("txlen:%d\r\n", p->tot_len + sizeof(struct tx_desc));
usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, p->tot_len + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, buflen + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
return usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
}
__WEAK void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
{
}
__WEAK void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
{
}
static const uint16_t rtl_id_table[][2] = {
{ 0x0BDA, 0x8152 },
{ 0, 0 },
};
static const struct usbh_class_driver rtl8152_class_driver = {
.driver_name = "rtl8152",
@@ -2255,11 +2263,10 @@ static const struct usbh_class_driver rtl8152_class_driver = {
};
CLASS_INFO_DEFINE const struct usbh_class_info rtl8152_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x0BDA,
.pid = 0x8152,
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = rtl_id_table,
.class_driver = &rtl8152_class_driver
};

View File

@@ -6,9 +6,6 @@
#ifndef USBH_RTL8152_H
#define USBH_RTL8152_H
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct usbh_rtl8152 {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -24,10 +21,6 @@ struct usbh_rtl8152 {
bool connect_status;
uint32_t speed[2];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
uint8_t version;
uint8_t eee_adv;
uint8_t eee_en;
@@ -50,6 +43,8 @@ struct usbh_rtl8152 {
void (*autosuspend_en)(struct usbh_rtl8152 *tp, bool enable);
void (*change_mtu)(struct usbh_rtl8152 *tp);
} rtl_ops;
void *user_data;
};
#ifdef __cplusplus
@@ -61,8 +56,10 @@ int usbh_rtl8152_get_connect_status(struct usbh_rtl8152 *rtl8152_class);
void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class);
void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class);
void usbh_rtl8152_rx_thread(void *argument);
err_t usbh_rtl8152_linkoutput(struct netif *netif, struct pbuf *p);
uint8_t *usbh_rtl8152_get_eth_txbuf(void);
int usbh_rtl8152_eth_output(uint32_t buflen);
void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_rtl8152_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#ifdef __cplusplus
}

View File

@@ -1,352 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_ch34x.h"
#define DEV_FORMAT "/dev/ttyUSB%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ch34x_buf[64];
#define CONFIG_USBHOST_MAX_CP210X_CLASS 1
static struct usbh_ch34x g_ch34x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_ch34x *usbh_ch34x_class_alloc(void)
{
int devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
memset(&g_ch34x_class[devno], 0, sizeof(struct usbh_ch34x));
g_ch34x_class[devno].minor = devno;
return &g_ch34x_class[devno];
}
}
return NULL;
}
static void usbh_ch34x_class_free(struct usbh_ch34x *ch34x_class)
{
int devno = ch34x_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
}
memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
}
static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
{
uint8_t a;
uint8_t b;
uint32_t c;
switch (baudrate) {
case 921600:
a = 0xf3;
b = 7;
break;
case 307200:
a = 0xd9;
b = 7;
break;
default:
if (baudrate > 6000000 / 255) {
b = 3;
c = 6000000;
} else if (baudrate > 750000 / 255) {
b = 2;
c = 750000;
} else if (baudrate > 93750 / 255) {
b = 1;
c = 93750;
} else {
b = 0;
c = 11719;
}
a = (uint8_t)(c / baudrate);
if (a == 0 || a == 0xFF) {
return -USB_ERR_INVAL;
}
if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
a++;
}
a = (uint8_t)(256 - a);
break;
}
*factor = a;
*divisor = b;
return 0;
}
static int usbh_ch34x_get_version(struct usbh_ch34x *ch34x_class)
{
struct usb_setup_packet *setup = ch34x_class->hport->setup;
int ret;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = CH34X_READ_VERSION;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 2;
ret = usbh_control_transfer(ch34x_class->hport, setup, g_ch34x_buf);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Ch34x chip version %02x:%02x\r\n", g_ch34x_buf[0], g_ch34x_buf[1]);
return ret;
}
static int usbh_ch34x_flow_ctrl(struct usbh_ch34x *ch34x_class)
{
struct usb_setup_packet *setup = ch34x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = CH34X_WRITE_REG;
setup->wValue = 0x2727;
setup->wIndex = 0;
setup->wLength = 0;
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
}
int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup = ch34x_class->hport->setup;
uint16_t reg_value = 0;
uint16_t value = 0;
uint8_t factor = 0;
uint8_t divisor = 0;
memcpy((uint8_t *)&ch34x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
/* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
switch (line_coding->bParityType) {
case 0:
break;
case 1:
reg_value |= CH341_L_PO;
break;
case 2:
reg_value |= CH341_L_PE;
break;
case 3:
reg_value |= CH341_L_PM;
break;
case 4:
reg_value |= CH341_L_PS;
break;
default:
return -USB_ERR_INVAL;
}
switch (line_coding->bDataBits) {
case 5:
reg_value |= CH341_L_D5;
break;
case 6:
reg_value |= CH341_L_D6;
break;
case 7:
reg_value |= CH341_L_D7;
break;
case 8:
reg_value |= CH341_L_D8;
break;
default:
return -USB_ERR_INVAL;
}
if (line_coding->bCharFormat == 2) {
reg_value |= CH341_L_SB;
}
reg_value |= 0xC0;
value |= 0x9c;
value |= reg_value << 8;
usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = CH34X_SERIAL_INIT;
setup->wValue = value;
setup->wIndex = (factor << 8) | 0x80 | divisor;
setup->wLength = 0;
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
}
int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
{
memcpy(line_coding, (uint8_t *)&ch34x_class->line_coding, sizeof(struct cdc_line_coding));
return 0;
}
int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts)
{
struct usb_setup_packet *setup = ch34x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = CH34X_MODEM_CTRL;
setup->wValue = 0x0f | (dtr << 5) | (rts << 6);
setup->wIndex = 0;
setup->wLength = 0;
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
}
static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_ch34x *ch34x_class = usbh_ch34x_class_alloc();
if (ch34x_class == NULL) {
USB_LOG_ERR("Fail to alloc ch34x_class\r\n");
return -USB_ERR_NOMEM;
}
ch34x_class->hport = hport;
ch34x_class->intf = intf;
hport->config.intf[intf].priv = ch34x_class;
usbh_ch34x_get_version(ch34x_class);
usbh_ch34x_flow_ctrl(ch34x_class);
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
continue;
} else {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(ch34x_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(ch34x_class->bulkout, ep_desc);
}
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ch34x_class->minor);
USB_LOG_INFO("Register CH34X Class:%s\r\n", hport->config.intf[intf].devname);
#if 0
USB_LOG_INFO("Test ch34x rx and tx and rx for 5 times, baudrate is 115200\r\n");
struct cdc_line_coding linecoding;
uint8_t count = 5;
linecoding.dwDTERate = 115200;
linecoding.bDataBits = 8;
linecoding.bParityType = 0;
linecoding.bCharFormat = 0;
usbh_ch34x_set_line_coding(ch34x_class, &linecoding);
usbh_ch34x_set_line_state(ch34x_class, true, false);
memset(g_ch34x_buf, 'a', sizeof(g_ch34x_buf));
ret = usbh_ch34x_bulk_out_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
USB_LOG_RAW("out ret:%d\r\n", ret);
while (count--) {
ret = usbh_ch34x_bulk_in_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
USB_LOG_RAW("in ret:%d\r\n", ret);
if (ret > 0) {
for (uint32_t i = 0; i < ret; i++) {
USB_LOG_RAW("%02x ", g_ch34x_buf[i]);
}
USB_LOG_RAW("\r\n");
}
}
#endif
usbh_ch34x_run(ch34x_class);
return ret;
}
static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_ch34x *ch34x_class = (struct usbh_ch34x *)hport->config.intf[intf].priv;
if (ch34x_class) {
if (ch34x_class->bulkin) {
usbh_kill_urb(&ch34x_class->bulkin_urb);
}
if (ch34x_class->bulkout) {
usbh_kill_urb(&ch34x_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister CH34X Class:%s\r\n", hport->config.intf[intf].devname);
usbh_ch34x_stop(ch34x_class);
}
usbh_ch34x_class_free(ch34x_class);
}
return ret;
}
int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &ch34x_class->bulkin_urb;
usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &ch34x_class->bulkout_urb;
usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
__WEAK void usbh_ch34x_run(struct usbh_ch34x *ch34x_class)
{
}
__WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class)
{
}
const struct usbh_class_driver ch34x_class_driver = {
.driver_name = "ch34x",
.connect = usbh_ch34x_connect,
.disconnect = usbh_ch34x_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0xff,
.protocol = 0xff,
.vid = 0x1A86,
.pid = 0x7523,
.class_driver = &ch34x_class_driver
};

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CH34X_H
#define USBH_CH34X_H
#include "usb_cdc.h"
/* Requests */
#define CH34X_READ_VERSION 0x5F
#define CH34X_WRITE_REG 0x9A
#define CH34X_READ_REG 0x95
#define CH34X_SERIAL_INIT 0xA1
#define CH34X_MODEM_CTRL 0xA4
// modem control bits
#define CH34X_BIT_RTS (1 << 6)
#define CH34X_BIT_DTR (1 << 5)
#define CH341_CTO_O 0x10
#define CH341_CTO_D 0x20
#define CH341_CTO_R 0x40
#define CH341_CTI_C 0x01
#define CH341_CTI_DS 0x02
#define CH341_CTRL_RI 0x04
#define CH341_CTI_DC 0x08
#define CH341_CTI_ST 0x0f
#define CH341_L_ER 0x80
#define CH341_L_ET 0x40
#define CH341_L_PS 0x38
#define CH341_L_PM 0x28
#define CH341_L_PE 0x18
#define CH341_L_PO 0x08
#define CH341_L_SB 0x04
#define CH341_L_D8 0x03
#define CH341_L_D7 0x02
#define CH341_L_D6 0x01
#define CH341_L_D5 0x00
struct usbh_ch34x {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct cdc_line_coding line_coding;
uint8_t intf;
uint8_t minor;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts);
int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_ch34x_run(struct usbh_ch34x *ch34x_class);
void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_CH34X_H */

View File

@@ -1,291 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_cp210x.h"
#define DEV_FORMAT "/dev/ttyUSB%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cp210x_buf[64];
#define CONFIG_USBHOST_MAX_CP210X_CLASS 4
static struct usbh_cp210x g_cp210x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_cp210x *usbh_cp210x_class_alloc(void)
{
int devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
memset(&g_cp210x_class[devno], 0, sizeof(struct usbh_cp210x));
g_cp210x_class[devno].minor = devno;
return &g_cp210x_class[devno];
}
}
return NULL;
}
static void usbh_cp210x_class_free(struct usbh_cp210x *cp210x_class)
{
int devno = cp210x_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
}
memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
}
static int usbh_cp210x_enable(struct usbh_cp210x *cp210x_class)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_IFC_ENABLE;
setup->wValue = 1;
setup->wIndex = cp210x_class->intf;
setup->wLength = 0;
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
}
static int usbh_cp210x_set_flow(struct usbh_cp210x *cp210x_class)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_FLOW;
setup->wValue = 0;
setup->wIndex = cp210x_class->intf;
setup->wLength = 16;
memset(g_cp210x_buf, 0, 16);
g_cp210x_buf[13] = 0x20;
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
}
static int usbh_cp210x_set_chars(struct usbh_cp210x *cp210x_class)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_CHARS;
setup->wValue = 0;
setup->wIndex = cp210x_class->intf;
setup->wLength = 6;
memset(g_cp210x_buf, 0, 6);
g_cp210x_buf[0] = 0x80;
g_cp210x_buf[4] = 0x88;
g_cp210x_buf[5] = 0x28;
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
}
static int usbh_cp210x_set_baudrate(struct usbh_cp210x *cp210x_class, uint32_t baudrate)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_BAUDRATE;
setup->wValue = 0;
setup->wIndex = cp210x_class->intf;
setup->wLength = 4;
memcpy(g_cp210x_buf, (uint8_t *)&baudrate, 4);
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
}
static int usbh_cp210x_set_data_format(struct usbh_cp210x *cp210x_class, uint8_t databits, uint8_t parity, uint8_t stopbits)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
uint16_t value;
value = ((databits & 0x0F) << 8) | ((parity & 0x0f) << 4) | ((stopbits & 0x03) << 0);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_LINE_CTL;
setup->wValue = value;
setup->wIndex = cp210x_class->intf;
setup->wLength = 0;
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
}
static int usbh_cp210x_set_mhs(struct usbh_cp210x *cp210x_class, uint8_t dtr, uint8_t rts, uint8_t dtr_mask, uint8_t rts_mask)
{
struct usb_setup_packet *setup = cp210x_class->hport->setup;
uint16_t value;
value = ((dtr & 0x01) << 0) | ((rts & 0x01) << 1) | ((dtr_mask & 0x01) << 8) | ((rts_mask & 0x01) << 9);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CP210X_SET_MHS;
setup->wValue = value;
setup->wIndex = cp210x_class->intf;
setup->wLength = 0;
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
}
int usbh_cp210x_set_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
{
memcpy((uint8_t *)&cp210x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
usbh_cp210x_set_baudrate(cp210x_class, line_coding->dwDTERate);
return usbh_cp210x_set_data_format(cp210x_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat);
}
int usbh_cp210x_get_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
{
memcpy(line_coding, (uint8_t *)&cp210x_class->line_coding, sizeof(struct cdc_line_coding));
return 0;
}
int usbh_cp210x_set_line_state(struct usbh_cp210x *cp210x_class, bool dtr, bool rts)
{
return usbh_cp210x_set_mhs(cp210x_class, dtr, rts, 1, 1);
}
static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_cp210x *cp210x_class = usbh_cp210x_class_alloc();
if (cp210x_class == NULL) {
USB_LOG_ERR("Fail to alloc cp210x_class\r\n");
return -USB_ERR_NOMEM;
}
cp210x_class->hport = hport;
cp210x_class->intf = intf;
hport->config.intf[intf].priv = cp210x_class;
usbh_cp210x_enable(cp210x_class);
usbh_cp210x_set_flow(cp210x_class);
usbh_cp210x_set_chars(cp210x_class);
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(cp210x_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(cp210x_class->bulkout, ep_desc);
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cp210x_class->minor);
USB_LOG_INFO("Register CP210X Class:%s\r\n", hport->config.intf[intf].devname);
#if 0
USB_LOG_INFO("Test cp2102 rx and tx and rx for 5 times, baudrate is 115200\r\n");
struct cdc_line_coding linecoding;
uint8_t count = 5;
linecoding.dwDTERate = 115200;
linecoding.bDataBits = 8;
linecoding.bParityType = 0;
linecoding.bCharFormat = 0;
usbh_cp210x_set_line_coding(cp210x_class, &linecoding);
usbh_cp210x_set_line_state(cp210x_class, true, false);
memset(g_cp210x_buf, 'a', sizeof(g_cp210x_buf));
ret = usbh_cp210x_bulk_out_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
USB_LOG_RAW("out ret:%d\r\n", ret);
while (count--) {
ret = usbh_cp210x_bulk_in_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
USB_LOG_RAW("in ret:%d\r\n", ret);
if (ret > 0) {
for (uint32_t i = 0; i < ret; i++) {
USB_LOG_RAW("%02x ", g_cp210x_buf[i]);
}
USB_LOG_RAW("\r\n");
}
}
#endif
usbh_cp210x_run(cp210x_class);
return ret;
}
static int usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_cp210x *cp210x_class = (struct usbh_cp210x *)hport->config.intf[intf].priv;
if (cp210x_class) {
if (cp210x_class->bulkin) {
usbh_kill_urb(&cp210x_class->bulkin_urb);
}
if (cp210x_class->bulkout) {
usbh_kill_urb(&cp210x_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister CP210X Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cp210x_stop(cp210x_class);
}
usbh_cp210x_class_free(cp210x_class);
}
return ret;
}
int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cp210x_class->bulkin_urb;
usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cp210x_class->bulkout_urb;
usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
__WEAK void usbh_cp210x_run(struct usbh_cp210x *cp210x_class)
{
}
__WEAK void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class)
{
}
const struct usbh_class_driver cp210x_class_driver = {
.driver_name = "cp210x",
.connect = usbh_cp210x_connect,
.disconnect = usbh_cp210x_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0xff,
.protocol = 0xff,
.vid = 0x10C4,
.pid = 0xEA60,
.class_driver = &cp210x_class_driver
};

View File

@@ -1,71 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CP210X_H
#define USBH_CP210X_H
#include "usb_cdc.h"
/* Requests */
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits
#define CP210X_GET_LINE_CTL 0x04
#define CP210X_SET_BREAK 0x05
#define CP210X_IMM_CHAR 0x06
#define CP210X_SET_MHS 0x07 // Set DTR, RTS
#define CP210X_GET_MDMSTS 0x08
#define CP210X_SET_XON 0x09
#define CP210X_SET_XOFF 0x0A
#define CP210X_SET_EVENTMASK 0x0B
#define CP210X_GET_EVENTMASK 0x0C
#define CP210X_SET_CHAR 0x0D
#define CP210X_GET_CHARS 0x0E
#define CP210X_GET_PROPS 0x0F
#define CP210X_GET_COMM_STATUS 0x10
#define CP210X_RESET 0x11
#define CP210X_PURGE 0x12
#define CP210X_SET_FLOW 0x13
#define CP210X_GET_FLOW 0x14
#define CP210X_EMBED_EVENTS 0x15
#define CP210X_GET_EVENTSTATE 0x16
#define CP210X_SET_CHARS 0x19
#define CP210X_GET_BAUDRATE 0x1D
#define CP210X_SET_BAUDRATE 0x1E // Set baudrate
#define CP210X_VENDOR_SPECIFIC 0xFF
struct usbh_cp210x {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct cdc_line_coding line_coding;
uint8_t intf;
uint8_t minor;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_cp210x_set_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
int usbh_cp210x_get_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
int usbh_cp210x_set_line_state(struct usbh_cp210x *ftdi_class, bool dtr, bool rts);
int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_cp210x_run(struct usbh_cp210x *cp210x_class);
void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_CP210X_H */

View File

@@ -1,368 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_ftdi.h"
#define DEV_FORMAT "/dev/ttyUSB%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ftdi_buf[64];
#define CONFIG_USBHOST_MAX_FTDI_CLASS 4
static struct usbh_ftdi g_ftdi_class[CONFIG_USBHOST_MAX_FTDI_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_ftdi *usbh_ftdi_class_alloc(void)
{
int devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_FTDI_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
memset(&g_ftdi_class[devno], 0, sizeof(struct usbh_ftdi));
g_ftdi_class[devno].minor = devno;
return &g_ftdi_class[devno];
}
}
return NULL;
}
static void usbh_ftdi_class_free(struct usbh_ftdi *ftdi_class)
{
int devno = ftdi_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
}
memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
}
static void usbh_ftdi_caculate_baudrate(uint32_t *itdf_divisor, uint32_t actual_baudrate)
{
#define FTDI_USB_CLK 48000000
int baudrate;
uint8_t frac[] = { 0, 8, 4, 2, 6, 10, 12, 14 };
if (actual_baudrate == 2000000) {
*itdf_divisor = 0x01;
} else if (actual_baudrate == 3000000) {
*itdf_divisor = 0x00;
} else {
baudrate = actual_baudrate;
if (baudrate > 100000 && baudrate < 12000000) {
baudrate = (baudrate / 100000) + 100000;
}
int divisor = FTDI_USB_CLK / baudrate;
int frac_bits = 0;
for (int i = 0; i < sizeof(frac) / sizeof(frac[0]); i++) {
if ((divisor & 0xF) == frac[i]) {
frac_bits = i;
break;
}
}
divisor >>= 4;
divisor &= 0x3FFF;
*itdf_divisor = (divisor << 14) | (frac_bits << 8);
}
}
int usbh_ftdi_reset(struct usbh_ftdi *ftdi_class)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_RESET_REQUEST;
setup->wValue = 0;
setup->wIndex = ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_set_modem(struct usbh_ftdi *ftdi_class, uint16_t value)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_SET_MODEM_CTRL_REQUEST;
setup->wValue = value;
setup->wIndex = ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_set_baudrate(struct usbh_ftdi *ftdi_class, uint32_t baudrate)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
uint32_t itdf_divisor;
uint16_t value;
uint8_t baudrate_high;
usbh_ftdi_caculate_baudrate(&itdf_divisor, baudrate);
value = itdf_divisor & 0xFFFF;
baudrate_high = (itdf_divisor >> 16) & 0xff;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_SET_BAUDRATE_REQUEST;
setup->wValue = value;
setup->wIndex = (baudrate_high << 8) | ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
{
/**
* D0-D7 databits BITS_7=7, BITS_8=8
* D8-D10 parity NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
* D11-D12 STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
* D14 BREAK_OFF=0, BREAK_ON=1
**/
uint16_t value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f);
struct usb_setup_packet *setup = ftdi_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_SET_DATA_REQUEST;
setup->wValue = value;
setup->wIndex = ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_set_latency_timer(struct usbh_ftdi *ftdi_class, uint16_t value)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_SET_LATENCY_TIMER_REQUEST;
setup->wValue = value;
setup->wIndex = ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_SET_FLOW_CTRL_REQUEST;
setup->wValue = value;
setup->wIndex = ftdi_class->intf;
setup->wLength = 0;
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
}
static int usbh_ftdi_read_modem_status(struct usbh_ftdi *ftdi_class)
{
struct usb_setup_packet *setup = ftdi_class->hport->setup;
int ret;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = SIO_POLL_MODEM_STATUS_REQUEST;
setup->wValue = 0x0000;
setup->wIndex = ftdi_class->intf;
setup->wLength = 2;
ret = usbh_control_transfer(ftdi_class->hport, setup, g_ftdi_buf);
if (ret < 0) {
return ret;
}
memcpy(ftdi_class->modem_status, g_ftdi_buf, 2);
return ret;
}
int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
{
memcpy((uint8_t *)&ftdi_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
usbh_ftdi_set_baudrate(ftdi_class, line_coding->dwDTERate);
return usbh_ftdi_set_data_format(ftdi_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
}
int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
{
memcpy(line_coding, (uint8_t *)&ftdi_class->line_coding, sizeof(struct cdc_line_coding));
return 0;
}
int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts)
{
int ret;
if (dtr) {
usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_HIGH);
} else {
usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_LOW);
}
if (rts) {
ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_HIGH);
} else {
ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_LOW);
}
return ret;
}
static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_ftdi *ftdi_class = usbh_ftdi_class_alloc();
if (ftdi_class == NULL) {
USB_LOG_ERR("Fail to alloc ftdi_class\r\n");
return -USB_ERR_NOMEM;
}
ftdi_class->hport = hport;
ftdi_class->intf = intf;
hport->config.intf[intf].priv = ftdi_class;
usbh_ftdi_reset(ftdi_class);
usbh_ftdi_set_flow_ctrl(ftdi_class, SIO_DISABLE_FLOW_CTRL);
usbh_ftdi_set_latency_timer(ftdi_class, 0x10);
usbh_ftdi_read_modem_status(ftdi_class);
USB_LOG_INFO("modem status:%02x:%02x\r\n", ftdi_class->modem_status[0], ftdi_class->modem_status[1]);
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(ftdi_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(ftdi_class->bulkout, ep_desc);
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ftdi_class->minor);
USB_LOG_INFO("Register FTDI Class:%s\r\n", hport->config.intf[intf].devname);
#if 0
USB_LOG_INFO("Test ftdi rx and tx and rx for 5 times, baudrate is 115200\r\n");
struct cdc_line_coding linecoding;
uint8_t count = 5;
linecoding.dwDTERate = 115200;
linecoding.bDataBits = 8;
linecoding.bParityType = 0;
linecoding.bCharFormat = 0;
usbh_ftdi_set_line_coding(ftdi_class, &linecoding);
usbh_ftdi_set_line_state(ftdi_class, true, false);
memset(g_ftdi_buf, 'a', sizeof(g_ftdi_buf));
ret = usbh_ftdi_bulk_out_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
USB_LOG_RAW("out ret:%d\r\n", ret);
while (count--) {
ret = usbh_ftdi_bulk_in_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
USB_LOG_RAW("in ret:%d\r\n", ret);
if (ret > 0) {
for (uint32_t i = 0; i < ret; i++) {
USB_LOG_RAW("%02x ", g_ftdi_buf[i]);
}
}
USB_LOG_RAW("\r\n");
}
#endif
usbh_ftdi_run(ftdi_class);
return ret;
}
static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_ftdi *ftdi_class = (struct usbh_ftdi *)hport->config.intf[intf].priv;
if (ftdi_class) {
if (ftdi_class->bulkin) {
usbh_kill_urb(&ftdi_class->bulkin_urb);
}
if (ftdi_class->bulkout) {
usbh_kill_urb(&ftdi_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister FTDI Class:%s\r\n", hport->config.intf[intf].devname);
usbh_ftdi_stop(ftdi_class);
}
usbh_ftdi_class_free(ftdi_class);
}
return ret;
}
int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &ftdi_class->bulkin_urb;
usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &ftdi_class->bulkout_urb;
usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
__WEAK void usbh_ftdi_run(struct usbh_ftdi *ftdi_class)
{
}
__WEAK void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class)
{
}
const struct usbh_class_driver ftdi_class_driver = {
.driver_name = "ftdi",
.connect = usbh_ftdi_connect,
.disconnect = usbh_ftdi_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info ftdi1_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0xff,
.protocol = 0xff,
.vid = 0x0403,
.pid = 0x6001,
.class_driver = &ftdi_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info ftdi2_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0xff,
.protocol = 0xff,
.vid = 0x0403,
.pid = 0x6010,
.class_driver = &ftdi_class_driver
};

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_FTDI_H
#define USBH_FTDI_H
#include "usb_cdc.h"
/* Requests */
#define SIO_RESET_REQUEST 0x00 /* Reset the port */
#define SIO_SET_MODEM_CTRL_REQUEST 0x01 /* Set the modem control register */
#define SIO_SET_FLOW_CTRL_REQUEST 0x02 /* Set flow control register */
#define SIO_SET_BAUDRATE_REQUEST 0x03 /* Set baud rate */
#define SIO_SET_DATA_REQUEST 0x04 /* Set the data characteristics of the port */
#define SIO_POLL_MODEM_STATUS_REQUEST 0x05
#define SIO_SET_EVENT_CHAR_REQUEST 0x06
#define SIO_SET_ERROR_CHAR_REQUEST 0x07
#define SIO_SET_LATENCY_TIMER_REQUEST 0x09
#define SIO_GET_LATENCY_TIMER_REQUEST 0x0A
#define SIO_SET_BITMODE_REQUEST 0x0B
#define SIO_READ_PINS_REQUEST 0x0C
#define SIO_READ_EEPROM_REQUEST 0x90
#define SIO_WRITE_EEPROM_REQUEST 0x91
#define SIO_ERASE_EEPROM_REQUEST 0x92
#define SIO_DISABLE_FLOW_CTRL 0x0
#define SIO_RTS_CTS_HS (0x1 << 8)
#define SIO_DTR_DSR_HS (0x2 << 8)
#define SIO_XON_XOFF_HS (0x4 << 8)
#define SIO_SET_DTR_MASK 0x1
#define SIO_SET_DTR_HIGH (1 | (SIO_SET_DTR_MASK << 8))
#define SIO_SET_DTR_LOW (0 | (SIO_SET_DTR_MASK << 8))
#define SIO_SET_RTS_MASK 0x2
#define SIO_SET_RTS_HIGH (2 | (SIO_SET_RTS_MASK << 8))
#define SIO_SET_RTS_LOW (0 | (SIO_SET_RTS_MASK << 8))
#define SIO_RTS_CTS_HS (0x1 << 8)
struct usbh_ftdi {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct cdc_line_coding line_coding;
uint8_t intf;
uint8_t minor;
uint8_t modem_status[2];
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts);
int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_ftdi_run(struct usbh_ftdi *ftdi_class);
void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_FTDI_H */

0
class/vendor/wifi/.gitkeep vendored Normal file
View File

229
class/vendor/xbox/usbh_xbox.c vendored Normal file
View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2024 Till Harbaum
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_xbox.h"
#define DEV_FORMAT "/dev/xbox%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_xbox_buf[128];
static struct usbh_xbox g_xbox_class[CONFIG_USBHOST_MAX_XBOX_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_xbox *usbh_xbox_class_alloc(void)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_XBOX_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_xbox_class[devno], 0, sizeof(struct usbh_xbox));
g_xbox_class[devno].minor = devno;
return &g_xbox_class[devno];
}
}
return NULL;
}
static void usbh_xbox_class_free(struct usbh_xbox *xbox_class)
{
uint8_t devno = xbox_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(xbox_class, 0, sizeof(struct usbh_xbox));
}
int usbh_xbox_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
struct usbh_xbox *xbox_class = usbh_xbox_class_alloc();
if (xbox_class == NULL) {
USB_LOG_ERR("Fail to alloc xbox_class\r\n");
return -USB_ERR_NOMEM;
}
xbox_class->hport = hport;
xbox_class->intf = intf;
hport->config.intf[intf].priv = xbox_class;
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(xbox_class->intin, ep_desc);
} else {
USBH_EP_INIT(xbox_class->intout, ep_desc);
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, xbox_class->minor);
USB_LOG_INFO("Register XBOX Class:%s\r\n", hport->config.intf[intf].devname);
usbh_xbox_run(xbox_class);
return 0;
}
int usbh_xbox_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_xbox *xbox_class = (struct usbh_xbox *)hport->config.intf[intf].priv;
if (xbox_class) {
if (xbox_class->intin) {
usbh_kill_urb(&xbox_class->intin_urb);
}
if (xbox_class->intout) {
usbh_kill_urb(&xbox_class->intout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister XBOX Class:%s\r\n", hport->config.intf[intf].devname);
usbh_xbox_stop(xbox_class);
}
usbh_xbox_class_free(xbox_class);
}
return ret;
}
__WEAK void usbh_xbox_run(struct usbh_xbox *xbox_class)
{
}
__WEAK void usbh_xbox_stop(struct usbh_xbox *xbox_class)
{
}
const struct usbh_class_driver xbox_class_driver = {
.driver_name = "xbox",
.connect = usbh_xbox_connect,
.disconnect = usbh_xbox_disconnect
};
static const uint16_t xbox_id_table[][2] = {
{ 0x0079, 0x18d4 }, // GPD Win 2 X-Box Controller
{ 0x03eb, 0xff01 }, // Wooting One (Legacy)
{ 0x03eb, 0xff02 }, // Wooting Two (Legacy)
{ 0x044f, 0xb326 }, // Thrustmaster Gamepad GP XID
{ 0x045e, 0x028e }, // Microsoft X-Box 360 pad
{ 0x045e, 0x028f }, // Microsoft X-Box 360 pad v2
{ 0x046d, 0xc21d }, // Logitech Gamepad F310
{ 0x046d, 0xc21e }, // Logitech Gamepad F510
{ 0x046d, 0xc21f }, // Logitech Gamepad F710
{ 0x046d, 0xc242 }, // Logitech Chillstream Controller
{ 0x046d, 0xcaa3 }, // Logitech DriveFx Racing Wheel
{ 0x056e, 0x2004 }, // Elecom JC-U3613M
{ 0x06a3, 0xf51a }, // Saitek P3600
{ 0x0738, 0x4716 }, // Mad Catz Wired Xbox 360 Controller
{ 0x0738, 0x4718 }, // Mad Catz Street Fighter IV FightStick SE
{ 0x0738, 0x4726 }, // Mad Catz Xbox 360 Controller
{ 0x0738, 0x4736 }, // Mad Catz MicroCon Gamepad
{ 0x0738, 0x4740 }, // Mad Catz Beat Pad
{ 0x0738, 0x9871 }, // Mad Catz Portable Drum
{ 0x0738, 0xb726 }, // Mad Catz Xbox controller - MW2
{ 0x0738, 0xbeef }, // Mad Catz JOYTECH NEO SE Advanced GamePad
{ 0x0738, 0xcb02 }, // Saitek Cyborg Rumble Pad - PC/Xbox 360
{ 0x0738, 0xcb03 }, // Saitek P3200 Rumble Pad - PC/Xbox 360
{ 0x0738, 0xcb29 }, // Saitek Aviator Stick AV8R02
{ 0x0738, 0xf738 }, // Super SFIV FightStick TE S
{ 0x07ff, 0xffff }, // Mad Catz GamePad
{ 0x0e6f, 0x0113 }, // Afterglow AX.1 Gamepad for Xbox 360
{ 0x0e6f, 0x011f }, // Rock Candy Gamepad Wired Controller
{ 0x0e6f, 0x0131 }, // PDP EA Sports Controller
{ 0x0e6f, 0x0133 }, // Xbox 360 Wired Controller
{ 0x0e6f, 0x0201 }, // Pelican PL-3601 'TSZ' Wired Xbox 360 Controller
{ 0x0e6f, 0x0213 }, // Afterglow Gamepad for Xbox 360
{ 0x0e6f, 0x021f }, // Rock Candy Gamepad for Xbox 360
{ 0x0e6f, 0x0301 }, // Logic3 Controller
{ 0x0e6f, 0x0401 }, // Logic3 Controller
{ 0x0e6f, 0x0413 }, // Afterglow AX.1 Gamepad for Xbox 360
{ 0x0e6f, 0x0501 }, // PDP Xbox 360 Controller
{ 0x0e6f, 0xf900 }, // PDP Afterglow AX.1
{ 0x0f0d, 0x000a }, // Hori Co. DOA4 FightStick
{ 0x0f0d, 0x000c }, // Hori PadEX Turbo
{ 0x1038, 0x1430 }, // SteelSeries Stratus Duo
{ 0x1038, 0x1431 }, // SteelSeries Stratus Duo
{ 0x11c9, 0x55f0 }, // Nacon GC-100XF
{ 0x1209, 0x2882 }, // Ardwiino Controller
{ 0x12ab, 0x0301 }, // PDP AFTERGLOW AX.1
{ 0x1430, 0x4748 }, // RedOctane Guitar Hero X-plorer
{ 0x1430, 0xf801 }, // RedOctane Controller
{ 0x146b, 0x0601 }, // BigBen Interactive XBOX 360 Controller
{ 0x1532, 0x0037 }, // Razer Sabertooth
{ 0x15e4, 0x3f00 }, // Power A Mini Pro Elite
{ 0x15e4, 0x3f0a }, // Xbox Airflo wired controller
{ 0x15e4, 0x3f10 }, // Batarang Xbox 360 controller
{ 0x162e, 0xbeef }, // Joytech Neo-Se Take2
{ 0x1689, 0xfd00 }, // Razer Onza Tournament Edition
{ 0x1689, 0xfd01 }, // Razer Onza Classic Edition
{ 0x1689, 0xfe00 }, // Razer Sabertooth
{ 0x1949, 0x041a }, // Amazon Game Controller
{ 0x1bad, 0x0002 }, // Harmonix Rock Band Guitar
{ 0x1bad, 0xf016 }, // Mad Catz Xbox 360 Controller
{ 0x1bad, 0xf021 }, // Mad Cats Ghost Recon FS GamePad
{ 0x1bad, 0xf023 }, // MLG Pro Circuit Controller (Xbox)
{ 0x1bad, 0xf025 }, // Mad Catz Call Of Duty
{ 0x1bad, 0xf027 }, // Mad Catz FPS Pro
{ 0x1bad, 0xf028 }, // Street Fighter IV FightPad
{ 0x1bad, 0xf030 }, // Mad Catz Xbox 360 MC2 MicroCon Racing Wheel
{ 0x1bad, 0xf036 }, // Mad Catz MicroCon GamePad Pro
{ 0x1bad, 0xf038 }, // Street Fighter IV FightStick TE
{ 0x1bad, 0xf501 }, // HoriPad EX2 Turbo
{ 0x1bad, 0xf506 }, // Hori Real Arcade Pro.EX Premium VLX
{ 0x1bad, 0xf900 }, // Harmonix Xbox 360 Controller
{ 0x1bad, 0xf901 }, // Gamestop Xbox 360 Controller
{ 0x1bad, 0xf903 }, // Tron Xbox 360 controller
{ 0x1bad, 0xf904 }, // PDP Versus Fighting Pad
{ 0x1bad, 0xfa01 }, // MadCatz GamePad
{ 0x1bad, 0xfd00 }, // Razer Onza TE
{ 0x1bad, 0xfd01 }, // Razer Onza
{ 0x20d6, 0x2001 }, // BDA Xbox Series X Wired Controller
{ 0x20d6, 0x281f }, // PowerA Wired Controller For Xbox 360
{ 0x24c6, 0x5300 }, // PowerA MINI PROEX Controller
{ 0x24c6, 0x5303 }, // Xbox Airflo wired controller
{ 0x24c6, 0x530a }, // Xbox 360 Pro EX Controller
{ 0x24c6, 0x531a }, // PowerA Pro Ex
{ 0x24c6, 0x5397 }, // FUS1ON Tournament Controller
{ 0x24c6, 0x5500 }, // Hori XBOX 360 EX 2 with Turbo
{ 0x24c6, 0x5501 }, // Hori Real Arcade Pro VX-SA
{ 0x24c6, 0x5506 }, // Hori SOULCALIBUR V Stick
{ 0x24c6, 0x550d }, // Hori GEM Xbox controller
{ 0x24c6, 0x5b00 }, // ThrustMaster Ferrari 458 Racing Wheel
{ 0x24c6, 0x5b02 }, // Thrustmaster, Inc. GPX Controller
{ 0x24c6, 0x5b03 }, // Thrustmaster Ferrari 458 Racing Wheel
{ 0x24c6, 0x5d04 }, // Razer Sabertooth
{ 0x24c6, 0xfafe }, // Rock Candy Gamepad for Xbox 360
{ 0x2563, 0x058d }, // OneXPlayer Gamepad
{ 0x2dc8, 0x3106 }, // 8BitDo Ultimate Wireless / Pro 2 Wired Controller
{ 0x2dc8, 0x3109 }, // 8BitDo Ultimate Wireless Bluetooth
{ 0x31e3, 0x1100 }, // Wooting One
{ 0x31e3, 0x1200 }, // Wooting Two
{ 0x31e3, 0x1210 }, // Wooting Lekker
{ 0x31e3, 0x1220 }, // Wooting Two HE
{ 0x31e3, 0x1230 }, // Wooting Two HE (ARM)
{ 0x31e3, 0x1300 }, // Wooting 60HE (AVR)
{ 0x31e3, 0x1310 }, // Wooting 60HE (ARM)
{ 0x3285, 0x0607 }, // Nacon GC-100
{ 0x413d, 0x2104 }, // Black Shark Green Ghost Gamepad
{ 0x0000, 0x0000 } // end of list
};
CLASS_INFO_DEFINE const struct usbh_class_info xbox_custom_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_VEND_SPECIFIC,
.bInterfaceSubClass = 0x5d,
.bInterfaceProtocol = 0x01,
.id_table = xbox_id_table,
.class_driver = &xbox_class_driver
};

31
class/vendor/xbox/usbh_xbox.h vendored Normal file
View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024, Till Harbaum
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_XBOX_H
#define USBH_XBOX_H
struct usbh_xbox {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
struct usb_endpoint_descriptor *intout; /* INTR OUT endpoint */
struct usbh_urb intin_urb; /* INTR IN urb */
struct usbh_urb intout_urb; /* INTR OUT urb */
uint8_t intf; /* interface number */
uint8_t minor;
};
#ifdef __cplusplus
extern "C" {
#endif
void usbh_xbox_run(struct usbh_xbox *xbox_class);
void usbh_xbox_stop(struct usbh_xbox *xbox_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_XBOX_H */

View File

@@ -806,14 +806,15 @@ struct video_still_probe_and_commit_controls {
struct video_cs_if_vc_header_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdVDC;
uint8_t bDescriptorSubType;
uint16_t bcdUVC;
uint16_t wTotalLength;
uint32_t dwClockFrequency;
uint8_t bInCollection;
uint8_t baInterfaceNr[];
} __PACKED;
#define VIDEO_SIZEOF_VC_HEADER_DESC(n) (11 + n)
#define VIDEO_SIZEOF_VC_HEADER_DESC(n) (12 + n)
struct video_cs_if_vc_input_terminal_descriptor {
uint8_t bLength;
@@ -860,6 +861,22 @@ struct video_cs_if_vc_output_terminal_descriptor {
#define VIDEO_SIZEOF_VC_OUTPUT_TERMINAL_DESC 9
struct video_cs_if_vc_extension_unit_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bUnitID;
uint8_t guidExtensionCode[16];
uint8_t bNumControls;
uint8_t bNrInPins;
// uint8_t baSourceID[];
uint8_t bControlSize;
// uint8_t bmControls[]
uint8_t iExtension;
} __PACKED;
#define VIDEO_SIZEOF_VC_EXTENSION_UNIT_DESC(p, n) (24 + p + n)
struct video_cs_ep_vc_ep_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
@@ -922,7 +939,7 @@ struct video_cs_if_vs_frame_uncompressed_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFormatIndex;
uint8_t bFrameIndex;
uint8_t bmCapabilities;
uint16_t wWidth;
uint16_t wHeight;
@@ -931,10 +948,10 @@ struct video_cs_if_vs_frame_uncompressed_descriptor {
uint32_t dwMaxVideoFrameBufferSize;
uint32_t dwDefaultFrameInterval;
uint8_t bFrameIntervalType;
uint32_t dwFrameInterval;
uint32_t dwFrameInterval[];
} __PACKED;
#define VIDEO_SIZEOF_VS_FRAME_UNCOMPRESSED_DESC 30
#define VIDEO_SIZEOF_VS_FRAME_UNCOMPRESSED_DESC(n) (26 + 4 * (n))
struct video_cs_if_vs_format_mjpeg_descriptor {
uint8_t bLength;
@@ -956,7 +973,7 @@ struct video_cs_if_vs_frame_mjpeg_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFormatIndex;
uint8_t bFrameIndex;
uint8_t bmCapabilities;
uint16_t wWidth;
uint16_t wHeight;
@@ -965,11 +982,48 @@ struct video_cs_if_vs_frame_mjpeg_descriptor {
uint32_t dwMaxVideoFrameBufferSize;
uint32_t dwDefaultFrameInterval;
uint8_t bFrameIntervalType;
uint32_t dwFrameInterval1;
uint32_t dwFrameInterval2;
uint32_t dwFrameInterval[];
} __PACKED;
#define VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(n) (26 + n)
#define VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(n) (26 + 4 * (n))
/* H264 Payload - 3.1.1. H264 Video Format Descriptor */
struct video_cs_if_vs_format_h26x_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFormatIndex;
uint8_t bNumFrameDescriptors;
uint8_t guidFormat[16];
uint8_t bBitsPerPixel;
uint8_t bDefaultFrameIndex;
uint8_t bAspectRatioX;
uint8_t bAspectRatioY;
uint8_t bmInterfaceFlags;
uint8_t bCopyProtect;
uint8_t bVariableSize;
} __PACKED;
#define VIDEO_SIZEOF_VS_FORMAT_H264_DESC 28
/* H264 Payload - 3.1.2. H264 Video Frame Descriptor */
struct video_cs_if_vs_frame_h26x_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFrameIndex;
uint8_t bmCapabilities;
uint16_t wWidth;
uint16_t wHeight;
uint32_t dwMinBitRate;
uint32_t dwMaxBitRate;
uint32_t dwDefaultFrameInterval;
uint8_t bFrameIntervalType;
uint32_t dwBytesPerLine;
uint32_t dwFrameInterval[];
} __PACKED;
#define VIDEO_SIZEOF_VS_FRAME_H264_DESC(n) (26 + 4 * (n))
struct video_cs_if_vs_colorformat_descriptor {
uint8_t bLength;
@@ -1041,98 +1095,185 @@ struct video_autoexposure_mode {
#define VIDEO_GUID_YUY2 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_GUID_NV12 0x4E, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_GUID_NV21 0x4E, 0x56, 0x32, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_GUID_M420 0x4D, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_GUID_I420 0x49, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_GUID_H264 0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
#define VIDEO_VC_TERMINAL_LEN (13 + 18 + 12 + 9)
/*Length of template descriptor: 81 bytes*/
#define VIDEO_VC_DESCRIPTOR_LEN (8 + 9 + VIDEO_VC_TERMINAL_LEN + 7 + 5)
#define VIDEO_VC_NOEP_DESCRIPTOR_LEN (8 + 9 + VIDEO_VC_TERMINAL_LEN)
// clang-format off
#define VIDEO_VC_DESCRIPTOR_INIT(bFirstInterface, bNumEndpoints, bcdUVC, wTotalLength, dwClockFrequency, stridx) \
/* Interface Association Descriptor */ \
0x08, \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \
bFirstInterface, \
0x02, \
USB_DEVICE_CLASS_VIDEO, \
VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \
0x00, \
0x00, \
/* VideoControl Interface Descriptor */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
0x00, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
bNumEndpoints, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \
USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \
VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \
VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \
stridx, /* iInterface:Index to string descriptor that contains the string <Your Product Name> */ \
/*Class-specific VideoControl Interface Descriptor */ \
0x0d, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \
WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \
WBVAL(wTotalLength), /* wTotalLength */ \
DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \
0x01, /* bInCollection : Number of streaming interfaces. */ \
(uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ \
/* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \
0x12, \
0x24, \
VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x01, /* bTerminalID */ \
WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \
0x00, /* bAssocTerminal */ \
0x00, /* iTerminal */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \
WBVAL(0x0000), /* wOcularFocalLength */ \
0x03, /* bControlSize */ \
0x00, 0x00, 0x00, /* bmControls */ \
0x0c, \
0x24, \
VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \
0x02, /* bUnitID */ \
0x01, /* bSourceID */ \
0x00, 0x00, /* wMaxMultiplier */ \
0x02, /* bControlSize */ \
0x00, 0x00, /* bmControls */ \
0x00, /* iProcessing */ \
0x00, /* bmVideoStandards */ \
0x09, \
0x24, \
VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x03, /* bTerminalID */ \
WBVAL(VIDEO_TT_STREAMING), \
0x00, /* bAssocTerminal */ \
0x02, /* bSourceID */ \
0x00 /* iTerminal */
#define VIDEO_VC_DESCRIPTOR_INIT(bFirstInterface, bEndpointAddress, bcdUVC, wTotalLength, dwClockFrequency, stridx) \
/* Interface Association Descriptor */ \
0x08, \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \
bFirstInterface, \
0x02, \
USB_DEVICE_CLASS_VIDEO, \
VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \
0x00, \
0x00, /* VideoControl Interface Descriptor */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
0x00, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x01, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \
USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \
VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \
VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \
stridx, /* iInterface:Index to string descriptor that contains the string <Your Product Name> */ /*Class-specific VideoControl Interface Descriptor */ \
0x0d, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \
WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \
WBVAL(wTotalLength), /* wTotalLength */ \
DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \
0x01, /* bInCollection : Number of streaming interfaces. */ \
(uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \
0x12, \
0x24, \
VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x01, /* bTerminalID */ \
WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \
0x00, /* bAssocTerminal */ \
0x00, /* iTerminal */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \
WBVAL(0x0000), /* wOcularFocalLength */ \
0x03, /* bControlSize */ \
0x00, 0x00, 0x00, /* bmControls */ \
0x0c, \
0x24, \
VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \
0x02, /* bUnitID */ \
0x01, /* bSourceID */ \
0x00, 0x00, /* wMaxMultiplier */ \
0x02, /* bControlSize */ \
0x00, 0x00, /* bmControls */ \
0x00, /* iProcessing */ \
0x00, /* bmVideoStandards */ \
0x09, \
0x24, \
VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x03, /* bTerminalID */ \
WBVAL(VIDEO_TT_STREAMING), \
0x00, /* bAssocTerminal */ \
0x02, /* bSourceID */ \
0x00, /* iTerminal */ \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
bEndpointAddress, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
0x10, 0x00, /* wMaxPacketSize */ \
0x08, /* bInterval */ \
/* Class-specific VC Interrupt Endpoint Descriptor */ \
0x05, 0x25, 0x03, 0x10, 0x00
#define VIDEO_VC_NOEP_DESCRIPTOR_INIT(bFirstInterface, bEndpointAddress, bcdUVC, wTotalLength, dwClockFrequency, stridx) \
/* Interface Association Descriptor */ \
0x08, \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \
bFirstInterface, \
0x02, \
USB_DEVICE_CLASS_VIDEO, \
VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \
0x00, \
0x00, /* VideoControl Interface Descriptor */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
0x00, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x00, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \
USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \
VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \
VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \
stridx, /* iInterface:Index to string descriptor that contains the string <Your Product Name> */ /*Class-specific VideoControl Interface Descriptor */ \
0x0d, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \
WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \
WBVAL(wTotalLength), /* wTotalLength */ \
DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \
0x01, /* bInCollection : Number of streaming interfaces. */ \
(uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \
0x12, \
0x24, \
VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x01, /* bTerminalID */ \
WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \
0x00, /* bAssocTerminal */ \
0x00, /* iTerminal */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \
WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \
WBVAL(0x0000), /* wOcularFocalLength */ \
0x03, /* bControlSize */ \
0x00, 0x00, 0x00, /* bmControls */ \
0x0c, \
0x24, \
VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \
0x02, /* bUnitID */ \
0x01, /* bSourceID */ \
0x00, 0x00, /* wMaxMultiplier */ \
0x02, /* bControlSize */ \
0x00, 0x00, /* bmControls */ \
0x00, /* iProcessing */ \
0x00, /* bmVideoStandards */ \
0x09, \
0x24, \
VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \
0x03, /* bTerminalID */ \
WBVAL(VIDEO_TT_STREAMING), \
0x00, /* bAssocTerminal */ \
0x02, /* bSourceID */ \
0x00 /* iTerminal */ \
#define VIDEO_VS_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints) \
/* Video Streaming (VS) Interface Descriptor */ \
0x09, /* bLength */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType : INTERFACE */ \
bInterfaceNumber, /* bInterfaceNumber: Index of this interface */ \
bAlternateSetting, /* bAlternateSetting: Index of this alternate setting */ \
bNumEndpoints, /* bNumEndpoints : 0 endpoints no bandwidth used*/ \
bNumEndpoints, /* bNumEndpoints : 0 endpoints, no bandwidth used*/ \
0x0e, /* bInterfaceClass : CC_VIDEO */ \
0x02, /* bInterfaceSubClass : SC_VIDEOSTREAMING */ \
0x00, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \
0x00 /* iInterface : unused */
#define VIDEO_VS_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \
/*Class-specific VideoStream Header Descriptor (Input) */ \
0x0d + PP_NARG(__VA_ARGS__), \
0x24, \
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE, \
bNumFormats, /* bNumFormats : One format descriptor follows. */ \
WBVAL(wTotalLength), \
bEndpointAddress, \
0x00, /* bmInfo : No dynamic format change supported. */ \
0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \
0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \
0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \
0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \
PP_NARG(__VA_ARGS__), /* bControlSize : Size of the bmaControls field */ \
__VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/
#define VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \
/*Class-specific VideoStream Header Descriptor (Input) */ \
0x0d + PP_NARG(__VA_ARGS__), \
0x24, \
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE, \
bNumFormats, /* bNumFormats : One format descriptor follows. */ \
WBVAL(wTotalLength), \
bEndpointAddress, \
0x00, /* bmInfo : No dynamic format change supported. */ \
0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \
0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \
0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \
0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \
0x01, /* bControlSize : Size of the bmaControls field */ \
__VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/
#define VIDEO_VS_OUTPUT_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \
/*Class-specific VideoStream Header Descriptor (Input) */ \
0x0d + PP_NARG(__VA_ARGS__), \
0x24, \
VIDEO_VS_OUTPUT_HEADER_DESCRIPTOR_SUBTYPE, \
bNumFormats, /* bNumFormats : One format descriptor follows. */ \
WBVAL(wTotalLength), \
bEndpointAddress, \
0x00, /* bmInfo : No dynamic format change supported. */ \
0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \
0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \
0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \
0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \
PP_NARG(__VA_ARGS__), /* bControlSize : Size of the bmaControls field */ \
__VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/
#define VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors, GUIDFormat) \
/*Payload Format(UNCOMPRESSED) Descriptor */ \
@@ -1142,7 +1283,7 @@ struct video_autoexposure_mode {
bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \
bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ \
GUIDFormat, /* GUID Format YUY2 {32595559-0000-0010-8000-00AA00389B71} */ \
0x0c, /* bBitsPerPixel : Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2*/ \
0x10, /* bBitsPerPixel : Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2*/ \
0x01, /* bDefaultFrameIndex : Default frame index is 1. */ \
0x00, /* bAspectRatioX : Non-interlaced stream not required. */ \
0x00, /* bAspectRatioY : Non-interlaced stream not required. */ \
@@ -1150,8 +1291,8 @@ struct video_autoexposure_mode {
0x00 /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */
#define VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \
dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, dwFrameInterval) \
0x1e, \
dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, bFrameIntervalType, ...) \
0x1a + PP_NARG(__VA_ARGS__), \
0x24, \
VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_SUBTYPE, \
bFrameIndex, \
@@ -1161,27 +1302,27 @@ struct video_autoexposure_mode {
DBVAL(dwMinBitRate), \
DBVAL(dwMaxBitRate), \
DBVAL(dwMaxVideoFrameBufferSize), \
DBVAL(dwDefaultFrameInterval), \
0x01, \
DBVAL(dwFrameInterval)
dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \
bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \
__VA_ARGS__
#define VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors) \
/*Payload Format(MJPEG) Descriptor */ \
0x0b, /* bLength */ \
0x0b, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
0x06, /* bDescriptorSubType : VS_FORMAT_MJPEG subtype */ \
bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \
bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ \
0x00, /* bmFlags : Uses fixed size samples.. */ \
0x01, /* bDefaultFrameIndex : Default frame index is 1. */ \
0x00, /* bAspectRatioX : Non-interlaced stream not required. */ \
0x00, /* bAspectRatioY : Non-interlaced stream not required. */ \
0x00, /* bAspectRatioX : Non-interlaced stream, not required. */ \
0x00, /* bAspectRatioY : Non-interlaced stream, not required. */ \
0x00, /* bmInterlaceFlags : Non-interlaced stream */ \
0x00 /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */
#define VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \
dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, bFrameIntervalType, ...) \
0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \
0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FRAME_MJPEG */ \
bFrameIndex, /* bFrameIndex : First (and only) frame descriptor */ \
@@ -1194,5 +1335,46 @@ struct video_autoexposure_mode {
dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \
bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \
__VA_ARGS__
#define VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors) \
/*Payload Format(H.264) Descriptor */ \
0x1c, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VS_FORMAT_FRAME_BASED_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FORMAT_FRAME_BASED subtype */\
bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \
bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ \
VIDEO_GUID_H264, \
0x00, /* bmFlags : Uses fixed size samples.. */ \
0x01, /* bDefaultFrameIndex : Default frame index is 1. */ \
0x00, /* bAspectRatioX : Non-interlaced stream, not required. */ \
0x00, /* bAspectRatioY : Non-interlaced stream, not required. */ \
0x00, /* bmInterlaceFlags : Non-interlaced stream */ \
0x00, /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */ \
0x00 /* Variable size: False */
#define VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \
dwDefaultFrameInterval, bFrameIntervalType, ...) \
0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VS_FRAME_FRAME_BASED_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FRAME_BASED */ \
bFrameIndex, /* bFrameIndex : First (and only) frame descriptor */ \
0x00, /* bmCapabilities : Still images using capture method 0 are supported at this frame setting.D1: Fixed frame-rate. */ \
WBVAL(wWidth), /* wWidth (2bytes): Width of frame is 128 pixels. */ \
WBVAL(wHeight), /* wHeight (2bytes): Height of frame is 64 pixels. */ \
DBVAL(dwMinBitRate), /* dwMinBitRate (4bytes): Min bit rate in bits/s */ \
DBVAL(dwMaxBitRate), /* dwMaxBitRate (4bytes): Max bit rate in bits/s */ \
dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \
bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \
DBVAL(0x00), /* dwBytesPerLine (4bytes) */ \
__VA_ARGS__
#define VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT() \
0x06, /* bLength */ \
0x24, /* bDescriptorType : CS_INTERFACE */ \
VIDEO_VS_COLORFORMAT_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_COLORFORMAT */ \
0x01, /* bColorPrimaries */ \
0x01, /* bTransferCharacteristics */ \
0x04 /* bMatrixCoefficients */
// clang-format on
#endif /*USB_VIDEO_H */

View File

@@ -18,12 +18,22 @@ struct usbd_video_priv {
uint8_t power_mode;
uint8_t error_code;
struct video_entity_info info[3];
uint8_t *ep_buf;
bool stream_finish;
uint8_t *stream_buf;
uint32_t stream_len;
uint32_t stream_offset;
uint8_t stream_frameid;
uint32_t stream_headerlen;
bool do_copy;
} g_usbd_video[CONFIG_USBDEV_MAX_BUS];
static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
uint8_t control_selector = (uint8_t)(setup->wValue >> 8);
(void)busid;
switch (control_selector) {
case VIDEO_VC_VIDEO_POWER_MODE_CONTROL:
switch (setup->bRequest) {
@@ -295,8 +305,7 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
case VIDEO_PU_BRIGHTNESS_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
uint16_t wBrightness = (uint16_t)(*data)[1] << 8 | (uint16_t)(*data)[0];
USB_LOG_INFO("Video set brightness:%d\r\n", wBrightness);
//uint16_t wBrightness = (uint16_t)(*data)[1] << 8 | (uint16_t)(*data)[0];
} break;
case VIDEO_REQUEST_GET_CUR: {
uint16_t wBrightness = 0x0080;
@@ -670,7 +679,7 @@ static int video_class_interface_request_handler(uint8_t busid, struct usb_setup
} else {
return usbd_video_control_unit_terminal_request_handler(busid, setup, data, len); /* Unit and Terminal Requests */
}
} else if (intf_num == 1) { /* Video Stream Inteface */
} else if (intf_num == 1) { /* Video Stream Inteface */
return usbd_video_stream_request_handler(busid, setup, data, len); /* Interface Stream Requests */
}
return -1;
@@ -699,7 +708,7 @@ static void video_notify_handler(uint8_t busid, uint8_t event, void *arg)
}
}
void usbd_video_probe_and_commit_controls_init(uint8_t busid, uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
static void usbd_video_probe_and_commit_controls_init(uint8_t busid, uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
{
g_usbd_video[busid].probe.hintUnion.bmHint = 0x01;
g_usbd_video[busid].probe.hintUnion1.bmHint = 0;
@@ -736,9 +745,13 @@ void usbd_video_probe_and_commit_controls_init(uint8_t busid, uint32_t dwFrameIn
g_usbd_video[busid].commit.bPreferedVersion = 0;
g_usbd_video[busid].commit.bMinVersion = 0;
g_usbd_video[busid].commit.bMaxVersion = 0;
g_usbd_video[busid].stream_frameid = 0;
g_usbd_video[busid].stream_headerlen = 12;
}
struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface *intf,
struct usbd_interface *usbd_video_init_intf(uint8_t busid,
struct usbd_interface *intf,
uint32_t dwFrameInterval,
uint32_t dwMaxVideoFrameSize,
uint32_t dwMaxPayloadTransferSize)
@@ -762,28 +775,101 @@ struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface
return intf;
}
uint32_t usbd_video_mjpeg_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len)
bool usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep)
{
uint32_t packets;
uint32_t last_packet_size;
uint32_t picture_pos = 0;
static uint8_t uvc_header[2] = { 0x02, 0x80 };
struct video_payload_header *header;
static uint32_t offset = 0;
static uint32_t len = 0;
packets = (input_len + (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
last_packet_size = input_len - ((packets - 1) * (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2));
for (size_t i = 0; i < packets; i++) {
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i] = uvc_header[0];
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1];
if (i == (packets - 1)) {
memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size);
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1);
} else {
memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
picture_pos += g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2;
}
if (g_usbd_video[busid].stream_finish) {
g_usbd_video[busid].stream_finish = false;
return true;
}
uvc_header[1] ^= 1;
*out_len = (input_len + 2 * packets);
return packets;
offset = g_usbd_video[busid].stream_offset;
len = MIN(g_usbd_video[busid].stream_len,
g_usbd_video[busid].probe.dwMaxPayloadTransferSize -
g_usbd_video[busid].stream_headerlen);
if (g_usbd_video[busid].do_copy) {
header = (struct video_payload_header *)&g_usbd_video[busid].ep_buf[0];
usb_memcpy(&g_usbd_video[busid].ep_buf[g_usbd_video[busid].stream_headerlen], &g_usbd_video[busid].stream_buf[offset], len);
} else {
header = (struct video_payload_header *)&g_usbd_video[busid].stream_buf[offset - g_usbd_video[busid].stream_headerlen];
}
memset(header, 0, g_usbd_video[busid].stream_headerlen);
header->bHeaderLength = g_usbd_video[busid].stream_headerlen;
header->headerInfoUnion.bmheaderInfo = 0;
header->headerInfoUnion.headerInfoBits.endOfHeader = 1;
header->headerInfoUnion.headerInfoBits.endOfFrame = 0;
header->headerInfoUnion.headerInfoBits.frameIdentifier = g_usbd_video[busid].stream_frameid;
g_usbd_video[busid].stream_offset += len;
g_usbd_video[busid].stream_len -= len;
if (g_usbd_video[busid].stream_len == 0) {
header->headerInfoUnion.headerInfoBits.endOfFrame = 1;
g_usbd_video[busid].stream_frameid ^= 1;
g_usbd_video[busid].stream_finish = true;
}
if (g_usbd_video[busid].do_copy) {
usbd_ep_start_write(busid, ep,
g_usbd_video[busid].ep_buf,
g_usbd_video[busid].stream_headerlen + len);
} else {
usbd_ep_start_write(busid, ep,
&g_usbd_video[busid].stream_buf[offset - g_usbd_video[busid].stream_headerlen],
g_usbd_video[busid].stream_headerlen + len);
}
return false;
}
int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buf, uint8_t *stream_buf, uint32_t stream_len, bool do_copy)
{
struct video_payload_header *header;
if ((usb_device_is_configured(busid) == 0) || (stream_len == 0)) {
return -1;
}
g_usbd_video[busid].ep_buf = ep_buf;
g_usbd_video[busid].stream_buf = stream_buf;
g_usbd_video[busid].stream_len = stream_len;
g_usbd_video[busid].stream_offset = 0;
g_usbd_video[busid].stream_finish = false;
g_usbd_video[busid].do_copy = do_copy;
uint32_t len = MIN(g_usbd_video[busid].stream_len,
g_usbd_video[busid].probe.dwMaxPayloadTransferSize -
g_usbd_video[busid].stream_headerlen);
header = (struct video_payload_header *)&ep_buf[0];
header->bHeaderLength = g_usbd_video[busid].stream_headerlen;
header->headerInfoUnion.bmheaderInfo = 0;
header->headerInfoUnion.headerInfoBits.endOfHeader = 1;
header->headerInfoUnion.headerInfoBits.endOfFrame = 0;
header->headerInfoUnion.headerInfoBits.frameIdentifier = g_usbd_video[busid].stream_frameid;
usb_memcpy(&ep_buf[g_usbd_video[busid].stream_headerlen], stream_buf, len);
g_usbd_video[busid].stream_offset += len;
g_usbd_video[busid].stream_len -= len;
usbd_ep_start_write(busid, ep, ep_buf, g_usbd_video[busid].stream_headerlen + len);
return 0;
}
__WEAK void usbd_video_open(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
}
__WEAK void usbd_video_close(uint8_t busid, uint8_t intf)
{
(void)busid;
(void)intf;
}

View File

@@ -20,7 +20,9 @@ struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface
void usbd_video_open(uint8_t busid, uint8_t intf);
void usbd_video_close(uint8_t busid, uint8_t intf);
uint32_t usbd_video_mjpeg_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len);
bool usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep);
int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buf, uint8_t *stream_buf, uint32_t stream_len, bool do_copy);
#ifdef __cplusplus
}

View File

@@ -25,7 +25,7 @@
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_video_buf[128];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_video_buf[USB_ALIGN_UP(128, CONFIG_USB_ALIGN_SIZE)];
static const char *format_type[] = { "uncompressed", "mjpeg" };
@@ -34,11 +34,11 @@ static uint32_t g_devinuse = 0;
static struct usbh_video *usbh_video_class_alloc(void)
{
int devno;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_VIDEO_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_video_class[devno], 0, sizeof(struct usbh_video));
g_video_class[devno].minor = devno;
return &g_video_class[devno];
@@ -49,20 +49,25 @@ static struct usbh_video *usbh_video_class_alloc(void)
static void usbh_video_class_free(struct usbh_video *video_class)
{
int devno = video_class->minor;
uint8_t devno = video_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(video_class, 0, sizeof(struct usbh_video));
}
int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
{
struct usb_setup_packet *setup = video_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
uint8_t retry;
if (!video_class || !video_class->hport) {
return -USB_ERR_INVAL;
}
setup = video_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = request;
setup->wValue = cs << 8;
@@ -91,9 +96,14 @@ int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf
int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
{
struct usb_setup_packet *setup = video_class->hport->setup;
struct usb_setup_packet *setup;
int ret;
if (!video_class || !video_class->hport) {
return -USB_ERR_INVAL;
}
setup = video_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = request;
setup->wValue = cs << 8;
@@ -112,12 +122,12 @@ int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class)
return usbh_video_get(video_class, VIDEO_REQUEST_GET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwFrameInterval)
{
video_class->probe.bFormatIndex = formatindex;
video_class->probe.bFrameIndex = frameindex;
video_class->probe.dwMaxPayloadTransferSize = 0;
video_class->probe.dwFrameInterval = 333333;
video_class->probe.dwFrameInterval = dwFrameInterval;
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
@@ -126,7 +136,6 @@ int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t f
memcpy(&video_class->commit, &video_class->probe, sizeof(struct video_probe_and_commit_controls));
video_class->commit.bFormatIndex = formatindex;
video_class->commit.bFrameIndex = frameindex;
video_class->commit.dwFrameInterval = 333333;
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
}
@@ -136,7 +145,7 @@ int usbh_video_open(struct usbh_video *video_class,
uint16_t wHeight,
uint8_t altsetting)
{
struct usb_setup_packet *setup = video_class->hport->setup;
struct usb_setup_packet *setup;
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
@@ -144,8 +153,14 @@ int usbh_video_open(struct usbh_video *video_class,
bool found = false;
uint8_t formatidx = 0;
uint8_t frameidx = 0;
uint32_t dwDefaultFrameInterval = 0;
uint8_t step;
if (!video_class || !video_class->hport) {
return -USB_ERR_INVAL;
}
setup = video_class->hport->setup;
if (video_class->is_opened) {
return 0;
}
@@ -157,6 +172,7 @@ int usbh_video_open(struct usbh_video *video_class,
if ((wWidth == video_class->format[i].frame[j].wWidth) &&
(wHeight == video_class->format[i].frame[j].wHeight)) {
frameidx = j + 1;
dwDefaultFrameInterval = video_class->format[i].frame[j].dwDefaultFrameInterval;
found = true;
break;
}
@@ -180,7 +196,7 @@ int usbh_video_open(struct usbh_video *video_class,
* Get MIN request (probe)
* Get CUR request (probe)
* Set CUR request (commit)
*
*
*/
step = 0;
ret = usbh_videostreaming_get_cur_probe(video_class);
@@ -189,7 +205,7 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 1;
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx, dwDefaultFrameInterval);
if (ret < 0) {
goto errout;
}
@@ -213,7 +229,7 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 5;
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx, dwDefaultFrameInterval);
if (ret < 0) {
goto errout;
}
@@ -231,26 +247,30 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 8;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
if (!video_class->is_bulk) {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
goto errout;
}
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
goto errout;
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
video_class->isoin_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoin, ep_desc);
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
video_class->isoin_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoin, ep_desc);
} else {
return -USB_ERR_NODEV;
}
} else {
video_class->isoout_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoout, ep_desc);
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[0].ep[0].ep_desc;
USBH_EP_INIT(video_class->bulkin, ep_desc);
}
USB_LOG_INFO("Open video and select formatidx:%u, frameidx:%u, altsetting:%u\r\n", formatidx, frameidx, altsetting);
@@ -265,74 +285,88 @@ errout:
int usbh_video_close(struct usbh_video *video_class)
{
struct usb_setup_packet *setup = video_class->hport->setup;
struct usb_setup_packet *setup;
int ret = 0;
if (!video_class || !video_class->hport) {
return -USB_ERR_INVAL;
}
setup = video_class->hport->setup;
USB_LOG_INFO("Close video device\r\n");
video_class->is_opened = false;
if (video_class->isoin) {
video_class->isoin = NULL;
if (video_class->is_bulk) {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_ENDPOINT;
setup->bRequest = USB_REQUEST_CLEAR_FEATURE;
setup->wValue = USB_FEATURE_ENDPOINT_HALT;
setup->wIndex = video_class->bulkin->bEndpointAddress;
setup->wLength = 0;
} else {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
}
if (video_class->isoout) {
video_class->isoout = NULL;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
return ret;
}
void usbh_video_list_info(struct usbh_video *video_class)
{
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
USB_LOG_INFO("============= Video device information ===================\r\n");
USB_LOG_INFO("bcdVDC:%04x\r\n", video_class->bcdVDC);
USB_LOG_INFO("Num of altsettings:%u\r\n", video_class->num_of_intf_altsettings);
USB_LOG_RAW("bcdVDC:%04x\r\n", video_class->bcdVDC);
USB_LOG_RAW("Num of altsettings:%u (%s mode)\r\n", video_class->num_of_intf_altsettings, video_class->num_of_intf_altsettings == 1 ? "bulk" : "iso");
for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
if (i == 0) {
USB_LOG_INFO("Ingore altsetting 0\r\n");
continue;
video_class->is_bulk = video_class->num_of_intf_altsettings == 1 ? true : false;
if (video_class->is_bulk) {
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[0].ep[0].ep_desc;
USB_LOG_RAW("Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize),
ep_desc->bInterval,
USB_GET_MULT(ep_desc->wMaxPacketSize));
} else {
for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
if (i == 0) {
USB_LOG_RAW("Ingore altsetting 0\r\n");
continue;
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
USB_LOG_RAW("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
i,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize),
ep_desc->bInterval,
USB_GET_MULT(ep_desc->wMaxPacketSize));
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
USB_LOG_INFO("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
i,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
mps,
ep_desc->bInterval,
mult);
}
USB_LOG_INFO("bNumFormats:%u\r\n", video_class->num_of_formats);
USB_LOG_RAW("bNumFormats:%u\r\n", video_class->num_of_formats);
for (uint8_t i = 0; i < video_class->num_of_formats; i++) {
USB_LOG_INFO(" FormatIndex:%u\r\n", i + 1);
USB_LOG_INFO(" FormatType:%s\r\n", format_type[video_class->format[i].format_type]);
USB_LOG_INFO(" bNumFrames:%u\r\n", video_class->format[i].num_of_frames);
USB_LOG_INFO(" Resolution:\r\n");
USB_LOG_RAW(" FormatIndex:%u\r\n", i + 1);
USB_LOG_RAW(" FormatType:%s\r\n", format_type[video_class->format[i].format_type]);
USB_LOG_RAW(" bNumFrames:%u\r\n", video_class->format[i].num_of_frames);
USB_LOG_RAW(" Resolution:\r\n");
for (uint8_t j = 0; j < video_class->format[i].num_of_frames; j++) {
USB_LOG_INFO(" FrameIndex:%u\r\n", j + 1);
USB_LOG_INFO(" wWidth: %d, wHeight: %d\r\n",
video_class->format[i].frame[j].wWidth,
video_class->format[i].frame[j].wHeight);
USB_LOG_RAW(" FrameIndex:%u\r\n", j + 1);
USB_LOG_RAW(" wWidth: %d, wHeight: %d, fps: %d\r\n",
video_class->format[i].frame[j].wWidth,
video_class->format[i].frame[j].wHeight,
(1000 / (video_class->format[i].frame[j].dwDefaultFrameInterval / 10000)));
}
}
@@ -418,12 +452,14 @@ static int usbh_video_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wWidth;
video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wHeight;
video_class->format[format_index - 1].frame[frame_index - 1].dwDefaultFrameInterval = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->dwDefaultFrameInterval;
break;
case VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE:
frame_index = p[DESC_bFrameIndex];
video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wWidth;
video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wHeight;
video_class->format[format_index - 1].frame[frame_index - 1].dwDefaultFrameInterval = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->dwDefaultFrameInterval;
break;
default:
break;
@@ -456,13 +492,8 @@ static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
struct usbh_video *video_class = (struct usbh_video *)hport->config.intf[intf].priv;
if (video_class) {
if (video_class->isoin) {
}
if (video_class->isoout) {
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Video Class:%s\r\n", hport->config.intf[intf].devname);
usbh_video_stop(video_class);
}
@@ -475,20 +506,26 @@ static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_video_streaming_connect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
static int usbh_video_streaming_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
(void)hport;
(void)intf;
return 0;
}
__WEAK void usbh_video_run(struct usbh_video *video_class)
{
(void)video_class;
}
__WEAK void usbh_video_stop(struct usbh_video *video_class)
{
(void)video_class;
}
const struct usbh_class_driver video_ctrl_class_driver = {
@@ -505,20 +542,18 @@ const struct usbh_class_driver video_streaming_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info video_ctrl_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_VIDEO,
.subclass = VIDEO_SC_VIDEOCONTROL,
.protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_VIDEO,
.bInterfaceSubClass = VIDEO_SC_VIDEOCONTROL,
.bInterfaceProtocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.id_table = NULL,
.class_driver = &video_ctrl_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info video_streaming_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_VIDEO,
.subclass = VIDEO_SC_VIDEOSTREAMING,
.protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_VIDEO,
.bInterfaceSubClass = VIDEO_SC_VIDEOSTREAMING,
.bInterfaceProtocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.id_table = NULL,
.class_driver = &video_streaming_class_driver
};

View File

@@ -14,6 +14,7 @@
struct usbh_video_resolution {
uint16_t wWidth;
uint16_t wHeight;
uint32_t dwDefaultFrameInterval;
};
struct usbh_video_format {
@@ -22,18 +23,25 @@ struct usbh_video_format {
uint8_t num_of_frames;
};
struct usbh_videoframe {
uint8_t *frame_buf;
uint32_t frame_bufsize;
uint32_t frame_format;
uint32_t frame_size;
};
struct usbh_videostreaming {
struct usbh_videoframe *frame;
uint32_t frame_format;
uint32_t bufoffset;
uint32_t buflen;
uint16_t width;
uint16_t heigth;
void (*video_one_frame_callback)(struct usbh_videostreaming *stream);
uint16_t height;
};
struct usbh_video {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *isoin; /* ISO IN endpoint */
struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
uint8_t ctrl_intf; /* interface number */
uint8_t data_intf; /* interface number */
@@ -41,13 +49,15 @@ struct usbh_video {
struct video_probe_and_commit_controls probe;
struct video_probe_and_commit_controls commit;
uint16_t isoin_mps;
uint16_t isoout_mps;
bool is_opened;
uint8_t current_format;
bool is_bulk;
uint16_t bcdVDC;
uint8_t num_of_intf_altsettings;
uint8_t num_of_formats;
struct usbh_video_format format[3];
void *user_data;
};
#ifdef __cplusplus

View File

@@ -17,26 +17,14 @@ static struct usbd_endpoint rndis_ep_data[3];
#define RNDIS_INQUIRY_PUT(src, len) (memcpy(infomation_buffer, src, len))
#define RNDIS_INQUIRY_PUT_LE32(value) (*(uint32_t *)infomation_buffer = (value))
#ifdef CONFIG_USB_HS
#define RNDIS_MAX_PACKET_SIZE 512
#else
#define RNDIS_MAX_PACKET_SIZE 64
#endif
#ifndef CONFIG_USB_HS
#define RNDIS_LINK_SPEED 12000000 /* Link baudrate (12Mbit/s for USB-FS) */
#else
#define RNDIS_LINK_SPEED 480000000 /* Link baudrate (480Mbit/s for USB-HS) */
#endif
/* Device data structure */
struct usbd_rndis_priv {
uint32_t drv_version;
uint32_t link_status;
uint32_t speed;
uint32_t net_filter;
usb_eth_stat_t eth_state;
rndis_state_t init_state;
bool set_rsp_get;
uint8_t mac[6];
} g_usbd_rndis;
@@ -45,14 +33,22 @@ struct usbd_rndis_priv {
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
#if CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE < 1580
#undef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rndis_encapsulated_resp_buffer[CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t NOTIFY_RESPONSE_AVAILABLE[8];
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[USB_ALIGN_UP(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[USB_ALIGN_UP(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE, CONFIG_USB_ALIGN_SIZE)];
#endif
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rndis_encapsulated_resp_buffer[USB_ALIGN_UP(CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t NOTIFY_RESPONSE_AVAILABLE[USB_ALIGN_UP(8, CONFIG_USB_ALIGN_SIZE)];
volatile uint8_t *g_rndis_rx_data_buffer;
volatile uint32_t g_rndis_rx_data_length;
volatile uint32_t g_rndis_rx_total_length;
volatile uint32_t g_rndis_tx_data_length;
/* RNDIS options list */
@@ -110,11 +106,17 @@ static void rndis_notify_rsp(void)
static int rndis_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
(void)busid;
switch (setup->bRequest) {
case CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
g_usbd_rndis.set_rsp_get = true;
rndis_encapsulated_cmd_handler(*data, setup->wLength);
break;
case CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
g_usbd_rndis.set_rsp_get = false;
*data = rndis_encapsulated_resp_buffer;
*len = ((rndis_generic_msg_t *)rndis_encapsulated_resp_buffer)->MessageLength;
break;
@@ -160,6 +162,8 @@ static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
rndis_initialize_msg_t *cmd = (rndis_initialize_msg_t *)data;
rndis_initialize_cmplt_t *resp;
(void)len;
resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
@@ -169,8 +173,8 @@ static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
resp->Status = RNDIS_STATUS_SUCCESS;
resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
resp->Medium = RNDIS_MEDIUM_802_3;
resp->MaxPacketsPerTransfer = 1;
resp->MaxTransferSize = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + sizeof(rndis_data_packet_t);
resp->MaxPacketsPerTransfer = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE / 1580;
resp->MaxTransferSize = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE;
resp->PacketAlignmentFactor = 0;
resp->AfListOffset = 0;
resp->AfListSize = 0;
@@ -185,6 +189,9 @@ static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_halt_msg_t *resp;
(void)data;
(void)len;
resp = ((rndis_halt_msg_t *)rndis_encapsulated_resp_buffer);
resp->MessageLength = 0;
@@ -200,6 +207,8 @@ static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
uint8_t *infomation_buffer;
uint32_t infomation_len = 0;
(void)len;
resp = ((rndis_query_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
resp->RequestId = cmd->RequestId;
@@ -225,7 +234,7 @@ static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
case OID_GEN_MAXIMUM_FRAME_SIZE:
case OID_GEN_TRANSMIT_BLOCK_SIZE:
case OID_GEN_RECEIVE_BLOCK_SIZE:
RNDIS_INQUIRY_PUT_LE32(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE);
RNDIS_INQUIRY_PUT_LE32(0x05DC); /* mtu 1500 */
infomation_len = 4;
break;
case OID_GEN_VENDOR_ID:
@@ -250,7 +259,12 @@ static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
infomation_len = 4;
break;
case OID_GEN_LINK_SPEED:
RNDIS_INQUIRY_PUT_LE32(RNDIS_LINK_SPEED / 100);
if (usbd_get_ep_mps(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr) > 64) {
RNDIS_INQUIRY_PUT_LE32(480000000 / 100);
} else {
RNDIS_INQUIRY_PUT_LE32(12000000 / 100);
}
infomation_len = 4;
break;
case OID_GEN_CURRENT_PACKET_FILTER:
@@ -258,11 +272,11 @@ static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
infomation_len = 4;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
RNDIS_INQUIRY_PUT_LE32(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE);
RNDIS_INQUIRY_PUT_LE32(0x0616); /* 1514 + 44 */
infomation_len = 4;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.link_status);
RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIA_STATE_CONNECTED);
infomation_len = 4;
break;
case OID_GEN_RNDIS_CONFIG_PARAMETER:
@@ -341,6 +355,8 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
rndis_set_cmplt_t *resp;
rndis_config_parameter_t *param;
(void)len;
resp = ((rndis_set_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_SET_CMPLT;
@@ -397,6 +413,9 @@ static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
// rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
rndis_reset_cmplt_t *resp;
(void)data;
(void)len;
resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
resp->MessageLength = sizeof(rndis_reset_cmplt_t);
@@ -415,6 +434,8 @@ static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
rndis_keepalive_msg_t *cmd = (rndis_keepalive_msg_t *)data;
rndis_keepalive_cmplt_t *resp;
(void)len;
resp = ((rndis_keepalive_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
@@ -428,15 +449,20 @@ static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
static void rndis_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
(void)busid;
(void)arg;
switch (event) {
case USBD_EVENT_RESET:
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
break;
case USBD_EVENT_CONFIGURED:
g_rndis_rx_data_length = 0;
g_rndis_tx_data_length = 0;
break;
case USBD_EVENT_CONFIGURED:
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
usbd_rndis_start_read(g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
#endif
break;
default:
@@ -448,10 +474,12 @@ void rndis_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
rndis_data_packet_t *hdr;
hdr = (rndis_data_packet_t *)g_rndis_rx_buffer;
g_rndis_rx_data_buffer = g_rndis_rx_buffer;
(void)busid;
(void)ep;
hdr = (rndis_data_packet_t *)g_rndis_rx_data_buffer;
if ((hdr->MessageType != REMOTE_NDIS_PACKET_MSG) || (nbytes < hdr->MessageLength)) {
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
usbd_rndis_start_read((uint8_t *)g_rndis_rx_data_buffer, g_rndis_rx_total_length);
return;
}
@@ -459,24 +487,59 @@ void rndis_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
g_rndis_rx_data_buffer += hdr->DataOffset + sizeof(rndis_generic_msg_t);
g_rndis_rx_data_length = hdr->DataLength;
usbd_rndis_data_recv_done();
usbd_rndis_data_recv_done(g_rndis_rx_data_length);
}
void rndis_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
if ((nbytes % RNDIS_MAX_PACKET_SIZE) == 0 && nbytes) {
(void)busid;
if ((nbytes % usbd_get_ep_mps(0, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(0, ep, NULL, 0);
} else {
usbd_rndis_data_send_done(g_rndis_tx_data_length);
g_rndis_tx_data_length = 0;
}
}
void rndis_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)busid;
(void)ep;
(void)nbytes;
//USB_LOG_DBG("len:%d\r\n", nbytes);
}
int usbd_rndis_start_write(uint8_t *buf, uint32_t len)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
if (g_rndis_tx_data_length > 0) {
return -USB_ERR_BUSY;
}
g_rndis_tx_data_length = len;
USB_LOG_DBG("txlen:%d\r\n", g_rndis_tx_data_length);
return usbd_ep_start_write(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr, buf, len);
}
int usbd_rndis_start_read(uint8_t *buf, uint32_t len)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
g_rndis_rx_data_buffer = buf;
g_rndis_rx_total_length = len;
g_rndis_rx_data_length = 0;
return usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, buf, len);
}
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
#include <lwip/pbuf.h>
@@ -489,15 +552,14 @@ struct pbuf *usbd_rndis_eth_rx(void)
}
p = pbuf_alloc(PBUF_RAW, g_rndis_rx_data_length, PBUF_POOL);
if (p == NULL) {
usbd_rndis_start_read(g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
return NULL;
}
memcpy(p->payload, (uint8_t *)g_rndis_rx_data_buffer, g_rndis_rx_data_length);
usb_memcpy(p->payload, (uint8_t *)g_rndis_rx_data_buffer, g_rndis_rx_data_length);
p->len = g_rndis_rx_data_length;
USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_data_length);
g_rndis_rx_data_length = 0;
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
usbd_rndis_start_read(g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
return p;
}
@@ -507,7 +569,7 @@ int usbd_rndis_eth_tx(struct pbuf *p)
uint8_t *buffer;
rndis_data_packet_t *hdr;
if (g_usbd_rndis.link_status == NDIS_MEDIA_STATE_DISCONNECTED) {
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
@@ -521,7 +583,7 @@ int usbd_rndis_eth_tx(struct pbuf *p)
buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
usb_memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
@@ -533,10 +595,7 @@ int usbd_rndis_eth_tx(struct pbuf *p)
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = p->tot_len;
g_rndis_tx_data_length = sizeof(rndis_data_packet_t) + p->tot_len;
USB_LOG_DBG("txlen:%d\r\n", g_rndis_tx_data_length);
return usbd_ep_start_write(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr, g_rndis_tx_buffer, g_rndis_tx_data_length);
return usbd_rndis_start_write(g_rndis_tx_buffer, sizeof(rndis_data_packet_t) + p->tot_len);
}
#endif
struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
@@ -548,7 +607,6 @@ struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
g_usbd_rndis.drv_version = 0x0001;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
g_usbd_rndis.speed = RNDIS_LINK_SPEED;
rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr = out_ep;
rndis_ep_data[RNDIS_OUT_EP_IDX].ep_cb = rndis_bulk_out;
@@ -568,3 +626,42 @@ struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
return intf;
}
int usbd_rndis_set_connect(bool connect)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
if(g_usbd_rndis.set_rsp_get)
return -USB_ERR_BUSY;
rndis_indicate_status_t *resp;
resp = ((rndis_indicate_status_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
resp->MessageLength = sizeof(rndis_indicate_status_t);
if(connect) {
resp->Status = RNDIS_STATUS_MEDIA_CONNECT;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
} else {
resp->Status = RNDIS_STATUS_MEDIA_DISCONNECT;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
}
resp->StatusBufferLength = 0;
resp->StatusBufferOffset = 0;
rndis_notify_rsp();
return 0;
}
__WEAK void usbd_rndis_data_recv_done(uint32_t len)
{
(void)len;
}
__WEAK void usbd_rndis_data_send_done(uint32_t len)
{
(void)len;
}

View File

@@ -18,7 +18,12 @@ struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
const uint8_t in_ep,
const uint8_t int_ep, uint8_t mac[6]);
void usbd_rndis_data_recv_done(void);
int usbd_rndis_set_connect(bool connect);
void usbd_rndis_data_recv_done(uint32_t len);
void usbd_rndis_data_send_done(uint32_t len);
int usbd_rndis_start_write(uint8_t *buf, uint32_t len);
int usbd_rndis_start_read(uint8_t *buf, uint32_t len);
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
struct pbuf *usbd_rndis_eth_rx(void);

View File

@@ -15,13 +15,13 @@
static struct usbh_bluetooth g_bluetooth_class;
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[USB_ALIGN_UP(CONFIG_USBHOST_BLUETOOTH_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[USB_ALIGN_UP(CONFIG_USBHOST_BLUETOOTH_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
#else
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_cmd_buf[1 + 256];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_evt_buf[1 + 256];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_cmd_buf[USB_ALIGN_UP(256, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_evt_buf[USB_ALIGN_UP(256, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[USB_ALIGN_UP(CONFIG_USBHOST_BLUETOOTH_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[USB_ALIGN_UP(CONFIG_USBHOST_BLUETOOTH_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
#endif
static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
@@ -96,7 +96,7 @@ static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
}
USB_LOG_INFO("Bluetooth select altsetting 0\r\n");
#endif
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bluetooth_run(bluetooth_class);
return ret;
@@ -134,6 +134,7 @@ static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf)
// }
#endif
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bluetooth_stop(bluetooth_class);
}
@@ -189,7 +190,7 @@ int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
return ret;
}
void usbh_bluetooth_hci_rx_thread(void *argument)
void usbh_bluetooth_hci_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
int ret;
uint32_t ep_mps;
@@ -224,7 +225,7 @@ void usbh_bluetooth_hci_rx_thread(void *argument)
}
}
// clang-format off
delete :
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
@@ -234,7 +235,12 @@ delete :
static int usbh_bluetooth_hci_cmd(uint8_t *buffer, uint32_t buflen)
{
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
struct usb_setup_packet *setup = bluetooth_class->hport->setup;
struct usb_setup_packet *setup;
if (!bluetooth_class || !bluetooth_class->hport) {
return -USB_ERR_INVAL;
}
setup = bluetooth_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = 0x00;
@@ -266,7 +272,7 @@ int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
return ret;
}
void usbh_bluetooth_hci_evt_rx_thread(void *argument)
void usbh_bluetooth_hci_evt_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
int ret;
uint32_t ep_mps;
@@ -309,13 +315,13 @@ void usbh_bluetooth_hci_evt_rx_thread(void *argument)
usb_osal_msleep(interval);
}
// clang-format off
delete :
delete :
USB_LOG_INFO("Delete hc event rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
void usbh_bluetooth_hci_acl_rx_thread(void *argument)
void usbh_bluetooth_hci_acl_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
int ret;
uint32_t ep_mps;
@@ -351,7 +357,7 @@ void usbh_bluetooth_hci_acl_rx_thread(void *argument)
}
}
// clang-format off
delete :
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
@@ -360,14 +366,18 @@ delete :
__WEAK void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len)
{
(void)data;
(void)len;
}
__WEAK void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class)
{
(void)bluetooth_class;
}
__WEAK void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class)
{
(void)bluetooth_class;
}
static const struct usbh_class_driver bluetooth_class_driver = {
@@ -377,23 +387,26 @@ static const struct usbh_class_driver bluetooth_class_driver = {
};
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
static const uint16_t bluetooth_id_table[][2] = {
{ 0x2fe3, 0x000c },
{ 0, 0 },
};
CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_h4_nrf_class_info = {
.match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x2fe3,
.pid = 0x000c,
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = bluetooth_id_table,
.class_driver = &bluetooth_class_driver
};
#else
CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_WIRELESS,
.subclass = 0x01,
.protocol = 0x01,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_WIRELESS,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01,
.id_table = NULL,
.class_driver = &bluetooth_class_driver
};
#endif

View File

@@ -29,6 +29,8 @@ struct usbh_bluetooth {
struct usbh_urb *isoout_urb; /* Bulk OUT urb */
uint8_t num_of_intf_altsettings;
#endif
void *user_data;
};
#ifdef __cplusplus
@@ -38,10 +40,10 @@ extern "C" {
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen);
void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len);
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
void usbh_bluetooth_hci_rx_thread(void *argument);
void usbh_bluetooth_hci_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#else
void usbh_bluetooth_hci_evt_rx_thread(void *argument);
void usbh_bluetooth_hci_acl_rx_thread(void *argument);
void usbh_bluetooth_hci_evt_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
void usbh_bluetooth_hci_acl_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#endif
void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class);

View File

@@ -13,23 +13,20 @@
#define DEV_FORMAT "/dev/rndis"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[512];
#define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
#define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
/* eth rx size must be a multiple of 512 or 64 */
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE];
// static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[16];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
// static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
static struct usbh_rndis g_rndis_class;
static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
{
(void)rndis_class;
// int ret;
// struct usbh_urb *urb = &rndis_class->intin_urb;
@@ -44,11 +41,16 @@ static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup = rndis_class->hport->setup;
struct usb_setup_packet *setup;
int ret = 0;
rndis_initialize_msg_t *cmd;
rndis_initialize_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_initialize_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_INITIALIZE_MSG;
@@ -66,7 +68,7 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_msg_t send error, ret: %d\r\n", ret);
USB_LOG_ERR("init send error, ret: %d\r\n", ret);
return ret;
}
@@ -78,24 +80,34 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
setup->wLength = sizeof(g_rndis_buf);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_cmplt_t recv error, ret: %d\r\n", ret);
USB_LOG_ERR("init recv error, ret: %d\r\n", ret);
return ret;
}
rndis_class->max_transfer_pkts = resp->MaxPacketsPerTransfer;
rndis_class->max_transfer_size = resp->MaxTransferSize;
USB_LOG_INFO("MaxPacketsPerTransfer: %u\r\n", (unsigned int)resp->MaxPacketsPerTransfer);
USB_LOG_INFO("MaxTransferSize: %u\r\n", (unsigned int)resp->MaxTransferSize);
return ret;
}
int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint32_t query_len, uint8_t *info, uint32_t *info_len)
{
struct usb_setup_packet *setup = rndis_class->hport->setup;
struct usb_setup_packet *setup;
int ret = 0;
rndis_query_msg_t *cmd;
rndis_query_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_query_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
@@ -126,7 +138,7 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
setup->wLength = sizeof(g_rndis_buf);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
@@ -142,11 +154,16 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
{
struct usb_setup_packet *setup = rndis_class->hport->setup;
struct usb_setup_packet *setup;
int ret = 0;
rndis_set_msg_t *cmd;
rndis_set_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_set_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_SET_MSG;
@@ -178,7 +195,7 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
setup->wLength = sizeof(g_rndis_buf);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
@@ -209,11 +226,16 @@ int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup = rndis_class->hport->setup;
struct usb_setup_packet *setup;
int ret = 0;
rndis_keepalive_msg_t *cmd;
rndis_keepalive_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_keepalive_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
@@ -240,7 +262,7 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
setup->wLength = sizeof(g_rndis_buf);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
@@ -256,8 +278,8 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint32_t *oid_support_list;
unsigned int oid = 0;
unsigned int oid_num = 0;
uint32_t oid = 0;
uint32_t oid_num = 0;
uint32_t data_len;
uint8_t tmp_buffer[512];
uint8_t data[32];
@@ -290,14 +312,13 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis init success\r\n");
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
if (ret < 0) {
return ret;
}
oid_num = (data_len / 4);
USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num :%d\r\n", oid_num);
USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num: %u\r\n", (unsigned int)oid_num);
oid_support_list = (uint32_t *)tmp_buffer;
@@ -358,25 +379,21 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
}
break;
default:
USB_LOG_WRN("Ignore rndis query iod:%08x\r\n", oid);
continue;
break;
}
USB_LOG_INFO("rndis query iod:%08x success\r\n", oid);
}
uint32_t packet_filter = 0x0f;
usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
ret = usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis set OID_GEN_CURRENT_PACKET_FILTER success\r\n");
uint8_t multicast_list[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
ret = usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
USB_LOG_INFO("rndis MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
rndis_class->mac[0],
@@ -386,13 +403,13 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
rndis_class->mac[4],
rndis_class->mac[5]);
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rndis_run(rndis_class);
return ret;
query_errorout:
USB_LOG_ERR("rndis query iod:%08x error\r\n", oid);
USB_LOG_ERR("rndis query iod:%08x error\r\n", (unsigned int)oid);
return ret;
}
@@ -416,6 +433,7 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
// }
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rndis_stop(rndis_class);
}
@@ -426,17 +444,20 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
void usbh_rndis_rx_thread(void *argument)
void usbh_rndis_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_rndis_rx_length;
uint32_t pmg_offset;
uint32_t payload_offset;
int ret;
err_t err;
struct pbuf *p, *q;
uint32_t pmg_offset;
rndis_data_packet_t *pmsg;
rndis_data_packet_t temp;
struct netif *netif = (struct netif *)argument;
#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
uint32_t transfer_size = CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE;
#else
uint32_t transfer_size = (16 * 1024);
#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create rndis rx thread\r\n");
// clang-format off
@@ -453,52 +474,65 @@ find_class:
usb_osal_msleep(100);
goto find_class;
}
usb_osal_msleep(128);
}
g_rndis_rx_length = 0;
while (1) {
g_rndis_rx_length = 0;
usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, g_rndis_rx_buffer, CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, &g_rndis_rx_buffer[g_rndis_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
if (ret < 0) {
goto find_class;
break;
}
g_rndis_rx_length = g_rndis_class.bulkin_urb.actual_length;
pmg_offset = 0;
while (g_rndis_rx_length > 0) {
USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_length);
g_rndis_rx_length += g_rndis_class.bulkin_urb.actual_length;
pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize).
* Short packet cannot be zero.
*/
if (g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize)) {
pmg_offset = 0;
/* Not word-aligned case */
if (pmg_offset & 0x3) {
memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
pmsg = &temp;
}
uint32_t total_len = g_rndis_rx_length;
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
if (p != NULL) {
payload_offset = 0;
for (q = p; q != NULL; q = q->next) {
void *src = (void *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset + payload_offset);
memcpy(q->payload, src, q->len);
payload_offset += q->len;
}
while (g_rndis_rx_length > 0) {
USB_LOG_DBG("rxlen:%u\r\n", (unsigned int)g_rndis_rx_length);
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
/* Not word-aligned case */
if (pmg_offset & 0x3) {
usb_memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
pmsg = &temp;
}
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
uint8_t *buf = (uint8_t *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
usbh_rndis_eth_input(buf, pmsg->DataLength);
pmg_offset += pmsg->MessageLength;
g_rndis_rx_length -= pmsg->MessageLength;
/* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
if (g_rndis_rx_length < 4) {
g_rndis_rx_length = 0;
}
} else {
USB_LOG_ERR("offset:%u,remain:%u,total:%u\r\n", (unsigned int)pmg_offset, (unsigned int)g_rndis_rx_length, (unsigned int)total_len);
g_rndis_rx_length = 0;
USB_LOG_ERR("No memory to alloc pbuf for rndis rx\r\n");
USB_LOG_ERR("Error rndis packet message\r\n");
}
}
} else {
#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
if (g_rndis_rx_length == CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
#else
if ((g_rndis_rx_length + (16 * 1024)) > CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
#endif
USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE\r\n");
while (1) {
}
} else {
g_rndis_rx_length = 0;
USB_LOG_ERR("Error rndis packet message\r\n");
}
}
}
@@ -510,53 +544,38 @@ delete:
// clang-format on
}
err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_rndis_get_eth_txbuf(void)
{
return (g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
}
int usbh_rndis_eth_output(uint32_t buflen)
{
int ret;
struct pbuf *q;
uint8_t *buffer;
rndis_data_packet_t *hdr;
uint32_t len;
if (g_rndis_class.connect_status == false) {
return ERR_BUF;
return -USB_ERR_NOTCONN;
}
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
hdr->MessageLength = sizeof(rndis_data_packet_t) + p->tot_len;
hdr->MessageLength = sizeof(rndis_data_packet_t) + buflen;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = p->tot_len;
buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
hdr->DataLength = buflen;
len = hdr->MessageLength;
/* if message length is the multiple of wMaxPacketSize, we should add a short packet to tell device transfer is over. */
if (!(hdr->MessageLength % g_rndis_class.bulkout->wMaxPacketSize)) {
hdr->MessageLength += 1;
if (!(len % g_rndis_class.bulkout->wMaxPacketSize)) {
len += 1;
}
USB_LOG_DBG("txlen:%d\r\n", hdr->MessageLength);
USB_LOG_DBG("txlen:%d\r\n", len);
usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, hdr->MessageLength, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
}
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
{
}
__WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
{
usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
return usbh_submit_urb(&g_rndis_class.bulkout_urb);
}
static const struct usbh_class_driver rndis_class_driver = {
@@ -567,10 +586,18 @@ static const struct usbh_class_driver rndis_class_driver = {
CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_WIRELESS,
.subclass = 0x01,
.protocol = 0x03,
.vid = 0x00,
.pid = 0x00,
.bInterfaceClass = USB_DEVICE_CLASS_WIRELESS,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x03,
.id_table = NULL,
.class_driver = &rndis_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info rndis_cdcacm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = 0xff,
.id_table = NULL,
.class_driver = &rndis_class_driver
};

View File

@@ -8,9 +8,6 @@
#include "usb_cdc.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct usbh_rndis {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -25,14 +22,15 @@ struct usbh_rndis {
uint8_t minor;
uint32_t request_id;
uint32_t tx_offset;
uint32_t max_transfer_pkts; /* max packets in one transfer */
uint32_t max_transfer_size; /* max size in one transfer */
uint32_t link_speed;
bool connect_status;
uint8_t mac[6];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
void *user_data;
};
#ifdef __cplusplus
@@ -45,8 +43,10 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class);
void usbh_rndis_run(struct usbh_rndis *rndis_class);
void usbh_rndis_stop(struct usbh_rndis *rndis_class);
err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p);
void usbh_rndis_rx_thread(void *argument);
uint8_t *usbh_rndis_get_eth_txbuf(void);
int usbh_rndis_eth_output(uint32_t buflen);
void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_rndis_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
#ifdef __cplusplus
}

View File

@@ -33,14 +33,21 @@ int usb_dc_deinit(uint8_t busid);
*/
int usbd_set_address(uint8_t busid, const uint8_t addr);
/**
* @brief Set remote wakeup feature
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_set_remote_wakeup(uint8_t busid);
/**
* @brief Get USB device speed
*
* @param[in] port port index
* @param[in] busid bus index
*
* @return port speed, USB_SPEED_LOW or USB_SPEED_FULL or USB_SPEED_HIGH
*/
uint8_t usbd_get_port_speed(uint8_t busid, const uint8_t port);
uint8_t usbd_get_port_speed(uint8_t busid);
/**
* @brief configure and enable endpoint.
@@ -129,7 +136,12 @@ int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, ui
*/
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len);
/* usb dcd irq callback */
/* usb dcd irq callback, called by user */
/**
* @brief Usb sof irq callback.
*/
void usbd_event_sof_handler(uint8_t busid);
/**
* @brief Usb connect irq callback.
@@ -187,6 +199,9 @@ void usbd_event_ep_out_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbyt
void usbd_execute_test_mode(uint8_t busid, uint8_t test_mode);
#endif
/* called by user */
void USBD_IRQHandler(uint8_t busid);
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More