440 Commits

Author SHA1 Message Date
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
sakumisu
a6d539792f release v1.2.0 2024-03-29 15:31:29 +08:00
sakumisu
7b5d8f29d4 update hid inout for hs 2024-03-29 15:31:29 +08:00
sakumisu
e7616399b7 add hpm5000 macro 2024-03-29 15:31:29 +08:00
sakumisu
a21947ff22 fix timer start in isr 2024-03-29 08:11:56 +08:00
sakumisu
078e21066c mark errorcode with USB_ERR_SHUTDOWN when kill urb 2024-03-28 21:00:18 +08:00
sakumisu
2335e08ef2 update scons 2024-03-28 20:45:35 +08:00
sakumisu
64f8a86569 update readme 2024-03-28 20:45:26 +08:00
sakumisu
4164e687f0 comment test mode api 2024-03-28 20:42:53 +08:00
sakumisu
4da3550582 fix msc buf overflow because of SCSICMD_INQUIRY_SIZEOF 2024-03-28 20:42:31 +08:00
sakumisu
22121bc54d fix warning in 64bit 2024-03-27 21:23:14 +08:00
sakumisu
68708c0f3a fix aic irq param num and add usbh_init api 2024-03-27 20:43:18 +08:00
sakumisu
5cd50410e6 update readme 2024-03-27 19:35:37 +08:00
sakumisu
74bb03b8b4 remove qtd alloc & free, use static pool instead 2024-03-26 20:41:17 +08:00
sakumisu
bc6ed589b0 update aic glue 2024-03-25 21:01:56 +08:00
sakumisu
f99e4ce113 use only one qh for intr, following with linux driver 2024-03-25 19:53:22 +08:00
sakumisu
d6d1b67761 update rst 2024-03-24 14:46:56 +08:00
sakumisu
3c16d7c61c update ehci glue 2024-03-24 14:24:10 +08:00
Zhihong Chen
0d647cf9c0 rndis: fix MessageLength check
- when MessageLength is MPS, PC rndis host will send (MPS + 1) bytes

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-23 22:19:15 +08:00
sakumisu
eef3e116b8 update cmake 2024-03-23 19:54:53 +08:00
sakumisu
bfa4490e6c remove init data 2024-03-23 18:09:08 +08:00
sakumisu
2bfb7255cd reset flag in USBD_EVENT_CONFIGURED 2024-03-23 18:08:54 +08:00
sakumisu
f28b1c61ba update cmake file, submodule change ssh to https 2024-03-22 20:39:07 +08:00
sakumisu
f4a0ba9839 dwc2:get next toggle from HCTSIZ 2024-03-22 19:31:47 +08:00
sakumisu
26e2436847 dwc2:add fifo macros for users to config 2024-03-21 23:07:07 +08:00
sakumisu
6cb442503d add usb_hc_low_level_deinit api 2024-03-21 21:04:10 +08:00
sakumisu
9dbc441082 update esp glue 2024-03-21 20:31:35 +08:00
sakumisu
44c408959b dwc2:add HCCHAR register init api, only enable chan halt irq, buffer dma mode just need this 2024-03-21 19:11:56 +08:00
sakumisu
aa1a30d581 dwc2:add register for desc dma mode 2024-03-20 21:54:43 +08:00
sakumisu
235139ad77 dwc2:simplify chan irq code 2024-03-20 21:53:49 +08:00
sakumisu
b2af686e67 dwc2:change dma incr to 16, flush fifo after fifo config 2024-03-20 21:53:22 +08:00
sakumisu
15b97f3348 ehci:fix missing bus param 2024-03-20 21:52:04 +08:00
Zhihong Chen
9145add9af core: host: add "." to section usbh_class_info for IAR
- add "." to section usbh_class_info for IAR

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-18 19:20:30 +08:00
sakumisu
ce241024b1 add rtl8152 host driver 2024-03-18 19:16:12 +08:00
sakumisu
1d38fde61a update url 2024-03-17 22:59:33 +08:00
sakumisu
b628c737ec add esp dwc2 glue 2024-03-17 22:48:35 +08:00
sakumisu
e40c72f3a8 add host cdc speed test 2024-03-15 22:59:53 +08:00
sakumisu
b4c455e5e6 must enable RT_USING_TIMER_SOFT when use timer 2024-03-14 19:37:15 +08:00
sakumisu
2660af5d87 add timer to control interrupt transfer 2024-03-14 19:31:52 +08:00
Zhihong Chen
869b5809f3 core: usbh_core: fix ep0_request_buffer index lose
- fix ep0_request_buffer index lose

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-13 19:25:07 +08:00
Zhihong Chen
4c062d4442 port: HPMicro: update usb_dc_hpm.c
- support usbd_execute_test_mode() API
- interrupt should be check dtd active status
- update usbd_ep_open() time sequence
- change irq return to break

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-13 19:25:07 +08:00
Zhihong Chen
bba4b46fa4 update usb test mode
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-13 19:25:07 +08:00
sakumisu
2e862f3864 set config with configvalue 2024-03-12 22:45:12 +08:00
sakumisu
6369ead152 optimise find class driver api 2024-03-12 22:41:01 +08:00
sakumisu
969c0342f0 fix cdc ncm build 2024-03-12 22:37:43 +08:00
sakumisu
5bd8ea8925 add winusbv2 template 2024-03-12 22:31:54 +08:00
sakumisu
7910666998 fix warning 2024-03-11 20:35:03 +08:00
sakumisu
39693f4702 support cdc ncm host 2024-03-10 19:53:33 +08:00
sakumisu
f489619c20 update svg 2024-03-08 17:30:21 +08:00
sakumisu
215534982a fix bt hci recv when CONFIG_BT_RECV_IS_RX_THREAD is disabled 2024-03-07 20:35:00 +08:00
sakumisu
6af1c143d3 remove unused macro 2024-03-06 21:49:57 +08:00
Zhihong Chen
9e9772fde7 HPMicro: port: fix usbd_ep_close() not reset ep_enable flag
- fix usbd_ep_close() not reset ep_enable flag

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-03-04 22:00:21 +08:00
sakumisu
b545830f70 update rtthread rst 2024-03-03 14:55:55 +08:00
sakumisu
850e96577c fix missing bus in sunxi 2024-03-02 13:14:58 +08:00
sakumisu
384b11eb88 release v1.1.0 2024-02-25 21:07:13 +08:00
sakumisu
cfbe5615c4 disable device shell cmd 2024-02-25 21:06:03 +08:00
sakumisu
cbefa69715 disable net class 2024-02-24 16:41:37 +08:00
sakumisu
9e0cc8347c align for some buffers 2024-02-24 16:38:57 +08:00
sakumisu
8c72947794 fix bl glue 2024-02-24 16:34:43 +08:00
sakumisu
d5b4cdd4bd update img 2024-02-24 15:01:28 +08:00
sakumisu
3508879e1d fix asix output zlp 2024-02-24 14:57:01 +08:00
sakumisu
5c36affc3c classify vendor class 2024-02-24 13:35:41 +08:00
sakumisu
762c3cbb2f add get_connect_status api for rndis/cdc_ecm/asix 2024-02-24 10:49:11 +08:00
Zhihong Chen
b4e952b371 port: HPMicro: call suspend/connect/disconnect event
- call suspend/connect/disconnect event

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-23 16:55:58 +08:00
Zhihong Chen
756987050f class: msc: stage change should be before usbd_ep_start_write()
- stage change should be before usbd_ep_start_write()

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-23 10:42:53 +08:00
sakumisu
64773ab5e8 remove duplicate class info 2024-02-22 22:32:27 +08:00
Zhihong Chen
743669861e port: HPMicro: fix transfer_len not reset
- fix transfer_len not reset

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-20 22:10:56 +08:00
Zhihong Chen
0e3e9477cc port: HPMicro: decoupling the relationship between busid and usbid
- decoupling the relationship between busid and usbid

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-20 14:28:10 +08:00
sakumisu
56c90ab6f9 update rst 2024-02-19 20:31:19 +08:00
sakumisu
9c247f6e6b update asix phy config 2024-02-19 20:22:07 +08:00
Zhihong Chen
556fd6af63 HPMicro: port: fix _dcd_data align to 2048
- fix _dcd_data align to 2048

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-19 20:19:48 +08:00
Zhihong Chen
4803a6826b update endpoint number usage and fix busid check
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-19 20:19:48 +08:00
sakumisu
e0551b3e7b config busid and regbase in usbh_initialize and usbd_initialize 2024-02-18 21:15:04 +08:00
sakumisu
31fa2b99c5 enable asix host driver 2024-02-15 22:54:14 +08:00
sakumisu
4313a2666e check if device is on extern hub 2024-02-09 12:35:44 +08:00
sakumisu
466d241c31 update doc 2024-02-09 12:21:40 +08:00
sakumisu
49116c6fbc format code 2024-02-09 12:08:08 +08:00
sakumisu
e7a57289ce update license year 2024-02-09 12:07:29 +08:00
sakumisu
e34ecc6cbb add volatile for HcEpType & ChannelEna 2024-02-07 21:37:17 +08:00
sakumisu
d1c7fa8c19 support multi port api for device 2024-02-06 19:52:22 +08:00
Zhihong Chen
920b02cb7c class: msc device: support multi lun
- support multi lun

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-06 18:31:47 +08:00
Zhihong Chen
3f89d1b003 usbd: change endpoint number from 8 to 16
- Because the maximum number of endpoints specified in the USB protocol is 16, and some vendors support 16 endpoints

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-02-06 18:31:47 +08:00
sakumisu
5897edffed make serial driver standard for cdc acm, ftdi, cp210x, ch34x 2024-02-03 22:20:58 +08:00
sakumisu
a01c08ddaa use cdc_linecoding and line state for ftdi 2024-02-02 23:37:46 +08:00
sakumisu
dcad369d06 add ftdi host 2024-02-02 22:53:54 +08:00
sakumisu
8232f64775 add nrf usbhci firmware 2024-02-01 20:49:31 +08:00
sakumisu
6fb3f31cbe add usbhci_h4 log and update bluetooth submodule 2024-01-31 20:52:01 +08:00
sakumisu
eeb304ae08 update log tag 2024-01-30 23:04:35 +08:00
sakumisu
fc80972284 add nimble submodule 2024-01-29 21:16:05 +08:00
sakumisu
feb69dcd95 add zephyr bluetooth submodule 2024-01-29 21:14:35 +08:00
sakumisu
cdfb7c3fb2 support hci usb h4 for usb bluetooth 2024-01-25 22:06:39 +08:00
sakumisu
24511c4d4b fix actual len position 2024-01-23 22:05:10 +08:00
sakumisu
c7cf09f6c3 update nimble porting with freertos 2024-01-22 19:49:23 +08:00
sakumisu
6b0a0135ac remove ununsed macro 2024-01-23 07:39:41 +08:00
sakumisu
04a300d803 remove ununsed header 2024-01-19 23:08:04 +08:00
sakumisu
0f5e05052f add usbd init and deinit event macro 2024-01-16 22:50:48 +08:00
sakumisu
b773cecd2e add ecm device write and read api 2024-01-14 18:49:41 +08:00
Zhihong Chen
c4a65146e8 port: hpmicro: fix usb_dc_deinit()
- fix usb_dc_deinit()

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-01-14 17:00:40 +08:00
Zhihong Chen
6bc6b06076 usbh_core: add iar risc-v support
- add iar risc-v support

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2024-01-14 17:00:40 +08:00
sakumisu
125aad65d6 dwc2 use fifo not dma as default because users may have problems in cache 2024-01-13 00:22:03 +08:00
sakumisu
07ced6d023 fix cdc ecm zlp check 2024-01-09 21:20:38 +08:00
sakumisu
45cca3930b update bluetooth rx callback, add zephyr bluetooth stack porting 2024-01-09 21:18:59 +08:00
sakumisu
eff338f8a7 add ehci hccr offset macro 2024-01-09 20:59:04 +08:00
sakumisu
1158fc3d8c support multi USB IP for host 2024-01-08 22:47:28 +08:00
sakumisu
d517f2594e fix macro name 2024-01-06 17:47:22 +08:00
sakumisu
b37f494304 support usb ble host 2024-01-06 12:53:22 +08:00
sakumisu
5fe66b4f0d dwc2: ctrl and bulk no need nak irq, when intr calls nak, retry by user 2024-01-06 01:09:55 +08:00
sakumisu
249e650c37 rename CONFIG_USBDEV_MSC_BLOCK_SIZE to CONFIG_USBDEV_MSC_MAX_BUFSIZE 2024-01-06 01:07:39 +08:00
sakumisu
cbfac7ec0c dwc2 low level deinit after usb register reset 2024-01-06 01:07:39 +08:00
419 changed files with 78145 additions and 14220 deletions

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

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

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[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

View File

@@ -1,57 +1,155 @@
add_library(cherryusb STATIC)
cmake_minimum_required(VERSION 3.15)
target_include_directories(cherryusb PUBLIC
common
core
osal
class/cdc
class/hid
class/msc
class/audio
class/video
class/hub
class/wireless
if(BL_SDK_BASE)
set(CONFIG_CHERRYUSB_DEVICE 1)
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_DCD "bl")
set(CONFIG_CHERRYUSB_HOST 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_OSAL "freertos")
set(CONFIG_CHERRYUSB_HOST_HCD "ehci_bouffalo")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
sdk_generate_library(cherryusb)
sdk_add_include_directories(${cherryusb_incs})
sdk_library_add_sources(${cherryusb_srcs})
sdk_library_add_sources(platform/none/usbh_lwip.c)
elseif(HPM_SDK_BASE)
set(CONFIG_CHERRYUSB_HOST 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_BL616 1)
set(CONFIG_CHERRYUSB_OSAL "freertos")
set(CONFIG_CHERRYUSB_HOST_HCD "ehci_hpm")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
sdk_inc(${cherryusb_incs})
sdk_src(${cherryusb_srcs})
sdk_src(platform/none/usbh_lwip.c)
elseif(ESP_PLATFORM)
set(CONFIG_CHERRYUSB_DEVICE_DCD "dwc2_esp")
set(CONFIG_CHERRYUSB_HOST_HCD "dwc2_esp")
set(CONFIG_CHERRYUSB_OSAL "idf")
include(${CMAKE_CURRENT_LIST_DIR}/cherryusb.cmake)
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 OR CONFIG_CHERRYUSB_HOST_BL616)
list(APPEND cherryusb_srcs platform/none/usbh_lwip.c)
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)
idf_component_register(SRCS ${cherryusb_srcs}
INCLUDE_DIRS ${cherryusb_incs} ${freertos_include}
PRIV_REQUIRES usb
LDFRAGMENTS ${ldfragments}
)
if(CONFIG_CHERRYUSB_DEVICE)
target_sources(cherryusb PRIVATE core/usbd_core.c)
if(CONFIG_CHERRYUSB_DEVICE_CDC)
target_sources(cherryusb PRIVATE class/cdc/usbd_cdc.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_HID)
target_sources(cherryusb PRIVATE class/hid/usbd_hid.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_MSC)
target_sources(cherryusb PRIVATE class/msc/usbd_msc.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_AUDIO)
target_sources(cherryusb PRIVATE class/audio/usbd_audio.c)
endif()
if(CONFIG_CHERRYUSB_DEVICE_VIDEO)
target_sources(cherryusb PRIVATE class/video/usbd_video.c)
endif()
endif()
if(CONFIG_CHERRYUSB_HOST)
target_sources(cherryusb PRIVATE
core/usbh_core.c
class/hub/usbh_hub.c
class/cdc/usbh_cdc_acm.c
class/hid/usbh_hid.c
class/msc/usbh_msc.c
class/audio/usbh_audio.c
class/video/usbh_video.c
class/wireless/usbh_rndis.c
)
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_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()
endif()
if(DEFINED CONFIG_CHERRYUSB_OSAL)
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
target_sources(cherryusb PRIVATE osal/usb_osal_freertos.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "rtthread")
target_sources(cherryusb PRIVATE osal/usb_osal_rtthread.c)
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "yoc")
target_sources(cherryusb PRIVATE osal/usb_osal_yoc.c)
endif()
if(CONFIG_CHERRYUSB)
set_source_files_properties("class/audio/usbd_audio.c"
PROPERTIES COMPILE_FLAGS
-Wno-maybe-uninitialized)
endif()
endif()

3
CherryUSB.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 38 KiB

346
Kconfig Normal file
View File

@@ -0,0 +1,346 @@
# 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
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
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
bool "fsdev"
config CHERRYUSB_DEVICE_DWC2_ST
bool "dwc2_st"
config CHERRYUSB_DEVICE_DWC2_ESP
bool "dwc2_esp"
config CHERRYUSB_DEVICE_DWC2_AT
bool "dwc2_at"
config CHERRYUSB_DEVICE_DWC2_GD
bool "dwc2_gd"
config CHERRYUSB_DEVICE_DWC2_HC
bool "dwc2_hc"
config CHERRYUSB_DEVICE_DWC2_KENDRYTE
bool "dwc2_kendryte"
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_CUSTOM
bool "musb_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_CHIPIDEA_MCX
bool "chipidea_mcx"
config CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM
bool "chipidea_custom"
config CHERRYUSB_DEVICE_BL
bool "bouffalo"
config CHERRYUSB_DEVICE_HPM
bool "hpm"
config CHERRYUSB_DEVICE_AIC
bool "aic"
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"
default n
config CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
config CHERRYUSB_DEVICE_ADB
bool
prompt "Enable usb adb device"
default n
choice
prompt "Select usb device template"
default CHERRYUSB_DEVICE_TEMPLATE_NONE
config CHERRYUSB_DEVICE_TEMPLATE_NONE
bool "none (Implement it yourself)"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
bool "cdc_acm"
config CHERRYUSB_DEVICE_TEMPLATE_MSC
bool "msc"
config CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
bool "hid_keyboard"
config CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
bool "hid_mouse"
config CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
bool "hid_custom"
config CHERRYUSB_DEVICE_TEMPLATE_VIDEO
bool "video"
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
bool "audio_v1_mic_speaker_multichan"
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
bool "audio_v2_mic_speaker_multichan"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
bool "cdc_rndis"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
bool "cdc_ecm"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
bool "cdc_ncm"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
bool "cdc_acm_msc"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
bool "cdc_acm_msc_hid"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
bool "winusbv1"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
bool "winusbv2_cdc"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
bool "winusbv2_hid"
endchoice
endif
menuconfig CHERRYUSB_HOST
bool "Enable usb host mode"
default n
if CHERRYUSB_HOST
choice
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_HC
bool "dwc2_hc"
config CHERRYUSB_HOST_DWC2_KENDRYTE
bool "dwc2_kendryte"
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_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"
endchoice
config CHERRYUSB_HOST_CDC_ACM
bool
prompt "Enable usb cdc acm driver"
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"
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"
default n
config CHERRYUSB_HOST_CH34X
bool
prompt "Enable usb ch34x driver"
default n
config CHERRYUSB_HOST_CP210X
bool
prompt "Enable usb cp210x driver"
default n
config CHERRYUSB_HOST_PL2303
bool
prompt "Enable usb pl2303 driver"
default n
config CHERRYUSB_HOST_AOA
bool
prompt "Enable usb aoa driver"
default n
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 CHERRYUSB_HOST_TEMPLATE
bool
prompt "Use usb host template"
default n
if CHERRYUSB_HOST_TEMPLATE
config TEST_USBH_CDC_ACM
int
prompt "demo for test cdc acm"
default 0
depends on CHERRYUSB_HOST_CDC_ACM
config TEST_USBH_HID
int
prompt "demo for test hid"
default 0
depends on CHERRYUSB_HOST_HID
config TEST_USBH_MSC
int
prompt "demo for test msc"
default 0
depends on CHERRYUSB_HOST_MSC
endif
endif
endif

154
README.md
View File

@@ -1,10 +1,20 @@
# CherryUSB
<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>
[中文版](./README_zh.md)
<p align="center">
<a href="./README_zh.md">中文</a>
|
<a href="./README.md">English</a>
</p>
CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP.
![CherryUSB](./docs/assets/CherryUSB.svg)
![CherryUSB](CherryUSB.svg)
## Why choose
@@ -17,12 +27,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 +42,18 @@ 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
```
.
├── 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 |
@@ -78,20 +75,23 @@ CherryUSB Device Stack has the following functions
- Support Device Firmware Upgrade CLASS (DFU)
- Support USB MIDI CLASS (MIDI)
- Support Remote NDIS (RNDIS)
- Support WINUSB1.0、WINUSB2.0(with BOS)
- 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):
| 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 | ~4400 | 512(default) + 320 | 0 | 0 |
|usbd_cdc_acm.c | ~400 | 0 | 0 | 0 |
|usbd_msc.c | ~3800 | 128 + 512(default) | 16 | 0 |
|usbd_hid.c | ~360 | 0 | 0 | 0 |
|usbd_audio.c | ~1500 | 0 | 0 | 0 |
|usbd_video.c | ~2600 | 0 | 84 | 0 |
|usbd_rndis.c | ~2100 | 2 * 1580(default)+156+8 | 76 | 0 |
## Host Stack Overview
@@ -99,18 +99,22 @@ The CherryUSB Host Stack has a standard enumeration implementation for devices m
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
- 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)
- Support Human Interface Device (HID)
- Support 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)
- Support Remote NDIS (RNDIS)
- Support Vendor class
- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
- Support Vendor class (serial, net, wifi)
- 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.
@@ -118,15 +122,17 @@ CherryUSB Host Stack resource usage (GCC 10.2 with -O2):
| 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_core.c | ~9000 | 512 + 8 * (1+x) *n | 28 | raw_config_desc |
|usbh_hub.c | ~6000 | 32 + 4 * (1+x) | 12 + sizeof(struct usbh_hub) * (1+x) | 0 |
|usbh_cdc_acm.c | ~900 | 7 | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2700 | 64 | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~1400 | 256 | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~3800 | 128 | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~4100 | 128 | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~4200 | 512 + 2 * 2048(default)| sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~2200 | 2 * 1514 + 16 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_cdc_ncm.c | ~3300 | 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 |
Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affected by the following macros
@@ -148,6 +154,24 @@ x is affected by the following macros
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
```
## USB IP Support
Only standard and commercial USB IP are listed.
| IP | device | host | Support status |
|:----------------:|:----------:|:--------:|:--------------:|
| OHCI(intel) | none | OHCI | √ |
| EHCI(intel) | none | EHCI | √ |
| XHCI(intel) | none | XHCI | √ |
| 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/)
@@ -165,17 +189,39 @@ USB basic concepts and how the CherryUSB Device stack is implemented, see [Cherr
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Support status |
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|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 |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2 | Long-term |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
|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 |
|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 | HPM6000/HPM5000 | 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)|>=1.4.0 | Long-term |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/canmv_k230)|v1.2.0 | Long-term |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
## 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
QQ group: 642693751
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" />

View File

@@ -1,10 +1,20 @@
# CherryUSB
<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>
[English](./README.md)
<p align="center">
<a href="./README_zh.md">中文</a>
|
<a href="./README.md">English</a>
</p>
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
![CherryUSB](./docs/assets/CherryUSB.svg)
![CherryUSB](CherryUSB.svg)
## 为什么选择
@@ -22,7 +32,7 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带
为了方便用户使用 USB 接口,考虑到用户学习过 uart 和 dma因此设计的数据收发类接口具备以下优点
- 等价于使用 uart tx dma/uart rx dma
- 收发长度没有限制,用户不需要关心 USB 分包过程porting 驱动做分包过程
- 收发长度没有限制,用户不需要关心 USB 分包过程(分包过程在 porting 中处理
### 易于发挥 USB 性能
@@ -32,30 +42,19 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带
- Memory zero copy
- IP 如果带 DMA 则使用 DMA 模式DMA 带硬件分包功能)
- 长度无限制,方便对接硬件 DMA 并且发挥 DMA 的优势
- 分包功能在中断中处理
- 分包过程在中断中执行
## 目录结构
```
.
├── 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 | 工具链接 |
@@ -76,20 +75,23 @@ CherryUSB Device 协议栈当前实现以下功能:
- 支持 Device Firmware Upgrade CLASS (DFU)
- 支持 USB MIDI CLASS (MIDI)
- 支持 Remote NDIS (RNDIS)
- 支持 WINUSB1.0、WINUSB2.0(带 BOS )
- 支持 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 | ~4400 | 512(default) + 320 | 0 | 0 |
|usbd_cdc_acm.c | ~400 | 0 | 0 | 0 |
|usbd_msc.c | ~3800 | 128 + 512(default) | 16 | 0 |
|usbd_hid.c | ~360 | 0 | 0 | 0 |
|usbd_audio.c | ~1500 | 0 | 0 | 0 |
|usbd_video.c | ~2600 | 0 | 84 | 0 |
|usbd_rndis.c | ~2100 | 2 * 1580(default)+156+8 | 76 | 0 |
## Host 协议栈简介
@@ -97,18 +99,22 @@ CherryUSB Host 协议栈对挂载在 roothub、外部 hub 上的设备规范了
CherryUSB Host 协议栈当前实现以下功能:
- 支持 low speed, full speed, high speed 和 super speed 设备
- 自动加载支持的Class 驱动
- 支持阻塞式传输和异步传输
- 支持复合设备
- 支持多级 HUB,最高可拓展到 7 级
- 支持多级 HUB,最高可拓展到 7 级(目前测试 1拖 10 没有问题,当前仅支持 dwc2 和 ehci)
- 支持 Communication Device Class (CDC_ACM, CDC_ECM)
- 支持 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)
- 支持 Vendor 类 class
- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
- 支持 Vendor 类 class (serial, net, wifi)
- 支持 USB modeswitch
- 支持 Android Open Accessory
- 支持相同 USB IP 的多主机
同时CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
@@ -116,15 +122,17 @@ CherryUSB Host 协议栈资源占用说明GCC 10.2 with -O2
| 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_core.c | ~9000 | 512 + 8 * (1+x) *n | 28 | raw_config_desc |
|usbh_hub.c | ~6000 | 32 + 4 * (1+x) | 12 + sizeof(struct usbh_hub) * (1+x) | 0 |
|usbh_cdc_acm.c | ~900 | 7 | 4 + sizeof(struct usbh_cdc_acm) * x | 0 |
|usbh_msc.c | ~2700 | 64 | 4 + sizeof(struct usbh_msc) * x | 0 |
|usbh_hid.c | ~1400 | 256 | 4 + sizeof(struct usbh_hid) * x | 0 |
|usbh_video.c | ~3800 | 128 | 4 + sizeof(struct usbh_video) * x | 0 |
|usbh_audio.c | ~4100 | 128 | 4 + sizeof(struct usbh_audio) * x | 0 |
|usbh_rndis.c | ~4200 | 512 + 2 * 2048(default)| sizeof(struct usbh_rndis) * 1 | 0 |
|usbh_cdc_ecm.c | ~2200 | 2 * 1514 + 16 | sizeof(struct usbh_cdc_ecm) * 1 | 0 |
|usbh_cdc_ncm.c | ~3300 | 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 |
其中,`sizeof(struct usbh_hub)``sizeof(struct usbh_hubport)` 受以下宏影响:
@@ -146,13 +154,32 @@ x 受以下宏影响:
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
```
## USB IP 支持情况
仅列举标准 USB IP 和商业性 USB IP
| IP | device | host | Support status |
|:----------------:|:----------:|:--------:|:--------------:|
| OHCI(intel) | none | OHCI | √ |
| EHCI(intel) | none | EHCI | √ |
| XHCI(intel) | none | XHCI | √ |
| 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 文档教程](https://cherryusb.readthedocs.io/)
CherryUSB 快速入门、USB 基本概念API 手册Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
## 视频教程
USB 基本知识点与 CherryUSB Device 协议栈是如何编写的,参考 [CherryUSB Device 协议栈教程](https://www.bilibili.com/video/BV1Ef4y1t73d).
- USB 基本知识点与 CherryUSB Device 协议栈是如何编写的使用v0.4.1 版本),参考 https://www.bilibili.com/video/BV1Ef4y1t73d.
- CherryUSB 腾讯会议使用v1.1.0 版本),参考 https://www.bilibili.com/video/BV16x421y7mM.
## 图形化界面配置工具
@@ -163,17 +190,40 @@ USB 基本知识点与 CherryUSB Device 协议栈是如何编写的,参考 [Ch
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Support status |
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|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 |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2 | Long-term |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
|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 |
|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 | HPM6000/HPM5000 | 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)|>=1.4.0 | Long-term |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/canmv_k230)|v1.2.0 | Long-term |
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
## Contact
## 软件包支持
QQ 群:642693751
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" />

View File

@@ -10,8 +10,13 @@ path += [cwd + '/class/audio']
path += [cwd + '/class/video']
path += [cwd + '/class/wireless']
path += [cwd + '/class/dfu']
path += [cwd + '/class/midi']
path += [cwd + '/class/vendor/net']
path += [cwd + '/class/vendor/serial']
src = []
LIBS = []
LIBPATH = []
CPPDEFINES = []
# USB DEVICE
@@ -23,8 +28,71 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
CPPDEFINES+=['CONFIG_USB_HS']
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC']):
src += Glob('class/cdc/usbd_cdc.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_FSDEV']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_ST']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_st.c')
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_AT']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_at.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_HC']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
src += Glob('port/dwc2/usb_glue_hc.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_CUSTOM']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
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')
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_CUSTOM']):
src += Glob('port/musb/usb_dc_musb.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_CHIPIDEA_MCX']):
src += Glob('port/chipidea/usb_dc_chipidea.c')
src += Glob('port/chipidea/usb_glue_mcx.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')
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/xhci/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_CDC_ACM']):
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']):
@@ -33,112 +101,177 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('class/audio/usbd_audio.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_VIDEO']):
src += Glob('class/video/usbd_video.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_RNDIS']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_RNDIS']):
src += Glob('class/wireless/usbd_rndis.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_ECM']):
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']):
src += Glob('class/dfu/usbd_dfu.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_TEMPLATE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM']):
src += Glob('demo/cdc_acm_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_HID_MOUSE_TEMPLATE']):
src += Glob('demo/hid_mouse_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_HID_KEYBOARD_TEMPLATE']):
src += Glob('demo/hid_keyboard_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_TEMPLATE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC']):
src += Glob('demo/msc_ram_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_STORAGE_TEMPLATE']):
src += Glob('demo/msc_storage_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V1_TEMPLATE']):
src += Glob('demo/audio_v1_mic_speaker_multichan_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V2_TEMPLATE']):
src += Glob('demo/audio_v2_mic_speaker_multichan_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_VIDEO_TEMPLATE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE']):
src += Glob('demo/hid_mouse_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD']):
src += Glob('demo/hid_keyboard_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM']):
src += Glob('demo/hid_custom_inout_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_VIDEO']):
src += Glob('demo/video_static_mjpeg_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_RNDIS_TEMPLATE']):
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER']):
src += Glob('demo/audio_v1_mic_speaker_multichan_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER']):
src += Glob('demo/audio_v2_mic_speaker_multichan_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS']):
src += Glob('demo/cdc_rndis_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_FSDEV']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2']):
src += Glob('port/dwc2/usb_dc_dwc2.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_STM32']):
src += Glob('port/dwc2/usb_glue_st.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB']):
src += Glob('port/musb/usb_dc_musb.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_MUSB_SUNXI']):
CPPDEFINES += ['CONFIG_USB_MUSB_SUNXI']
if GetDepend(['PKG_CHERRYUSB_DEVICE_HPM']):
src += Glob('port/hpm/usb_dc_hpm.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CH32_CH32V307']):
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')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM']):
src += Glob('demo/cdc_ecm_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM']):
src += Glob('demo/cdc_ncm_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC']):
src += Glob('demo/cdc_acm_msc_template.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID']):
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_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')
# USB HOST
if GetDepend(['PKG_CHERRYUSB_HOST']):
path += [cwd + '/osal']
path += [cwd + '/class/hub']
src += Glob('core/usbh_core.c')
src += Glob('class/hub/usbh_hub.c')
src += Glob('osal/usb_osal_rtthread.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CDC']):
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_BL']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_bouffalo.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/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')
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/ehci/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_MA35D0']):
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/ehci/usb_glue_ma35d0.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_CUSTOM']):
src += Glob('port/ehci/usb_hc_ehci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_ST']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
src += Glob('port/dwc2/usb_glue_st.c')
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_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')
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_CUSTOM']):
src += Glob('port/musb/usb_hc_musb.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/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_CDC_ACM']):
src += Glob('class/cdc/usbh_cdc_acm.c')
if GetDepend(['PKG_CHERRYUSB_HOST_HID']):
src += Glob('class/hid/usbh_hid.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
src += Glob('class/msc/usbh_msc.c')
if GetDepend(['PKG_CHERRYUSB_HOST_RNDIS']):
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_RNDIS']):
src += Glob('class/wireless/usbh_rndis.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ECM']):
src += Glob('class/cdc/usbh_cdc_ecm.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2']):
src += Glob('port/dwc2/usb_hc_dwc2.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_STM32']):
src += Glob('port/dwc2/usb_glue_st.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB']):
src += Glob('port/musb/usb_hc_musb.c')
if GetDepend(['PKG_CHERRYUSB_HOST_MUSB_SUNXI']):
CPPDEFINES += ['CONFIG_USB_MUSB_SUNXI']
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI']):
src += Glob('port/ehci/usb_hc_ehci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']):
src += Glob('port/ehci/usb_glue_hpm.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_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')
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_NCM']):
src += Glob('class/cdc/usbh_cdc_ncm.c')
if GetDepend(['PKG_CHERRYUSB_HOST_VIDEO']):
src += Glob('class/video/usbh_video.c')
if GetDepend(['PKG_CHERRYUSB_HOST_AUDIO']):
src += Glob('class/audio/usbh_audio.c')
if GetDepend(['PKG_CHERRYUSB_HOST_BLUETOOTH']):
src += Glob('class/wireless/usbh_bluetooth.c')
if GetDepend(['PKG_CHERRYUSB_HOST_ASIX']):
src += Glob('class/vendor/net/usbh_asix.c')
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')
if GetDepend(['PKG_CHERRYUSB_HOST_CH34X']):
src += Glob('class/vendor/serial/usbh_ch34x.c')
if GetDepend(['PKG_CHERRYUSB_HOST_CP210X']):
src += Glob('class/vendor/serial/usbh_cp210x.c')
if GetDepend(['PKG_CHERRYUSB_HOST_PL2303']):
src += Glob('class/vendor/serial/usbh_pl2303.c')
if GetDepend(['PKG_CHERRYUSB_HOST_TEMPLATE']):
src += Glob('demo/usb_host.c')
if GetDepend('RT_USING_DFS'):
src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
src += Glob('third_party/rt-thread-5.0/msh_cmd.c')
if GetDepend('RT_USING_DFS') and GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
src += Glob('platform/rtthread/usbh_dfs.c')
group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
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 = 0
PATCHLEVEL = 99
VERSION_MINOR = 4
PATCHLEVEL = 2
VERSION_TWEAK = 0
EXTRAVERSION = 0

306
cherryusb.cmake Normal file
View File

@@ -0,0 +1,306 @@
#
# Copyright (c) 2024, sakumisu
#
# SPDX-License-Identifier: Apache-2.0
#
# 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_HOST 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_OSAL "freertos")
# set(CONFIG_CHERRYUSB_HOST_HCD "ehci_xxx")
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/adb
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
${CMAKE_CURRENT_LIST_DIR}/class/aoa
)
if(CONFIG_CHERRYUSB_DEVICE)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbd_core.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)
endif()
if(CONFIG_CHERRYUSB_DEVICE_MSC)
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)
endif()
if(CONFIG_CHERRYUSB_DEVICE_VIDEO)
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)
endif()
if(CONFIG_CHERRYUSB_DEVICE_CDC_NCM)
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)
endif()
if(CONFIG_CHERRYUSB_DEVICE_DFU)
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(DEFINED CONFIG_CHERRYUSB_DEVICE_DCD)
if("${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 "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")
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_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 "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_DCD}" STREQUAL "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_DCD}" STREQUAL "musb_es")
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_es.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "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_DCD}" STREQUAL "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_DCD}" STREQUAL "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/chipidea/usb_glue_mcx.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "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)
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 "bl")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/bouffalolab/usb_dc_bl.c)
elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "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)
endif()
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
)
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/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_RNDIS)
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)
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
)
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)
endif()
if(CONFIG_CHERRYUSB_HOST_RTL8152)
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/vendor/serial/usbh_ch34x.c)
endif()
if(CONFIG_CHERRYUSB_HOST_CP210X)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_cp210x.c)
endif()
if(CONFIG_CHERRYUSB_HOST_FTDI)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ftdi.c)
endif()
if(CONFIG_CHERRYUSB_HOST_PL2303)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_pl2303.c)
endif()
if(CONFIG_CHERRYUSB_HOST_BL616)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi/usbh_bl616.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)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
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)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
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)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "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/ehci/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_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 "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_HCD}" STREQUAL "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_HCD}" STREQUAL "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_HCD}" STREQUAL "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_HCD}" STREQUAL "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)
endif()
endif()
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)
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)
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)
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,16 +6,10 @@
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
#define CHERRYUSB_VERSION 0x010000
#define CHERRYUSB_VERSION_STR "v1.0.0"
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#define usb_malloc(size) malloc(size)
#define usb_free(ptr) free(ptr)
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#endif
@@ -33,20 +27,31 @@
/* ================= USB Device Stack Configuration ================ */
/* Ep0 max transfer buffer, specially for receiving data from ep0 out */
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 256
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* 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
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
#ifndef CONFIG_USBDEV_MSC_BLOCK_SIZE
#define CONFIG_USBDEV_MSC_BLOCK_SIZE 512
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
@@ -61,6 +66,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
@@ -75,8 +84,9 @@
#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
@@ -116,10 +126,14 @@
//#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
@@ -129,26 +143,137 @@
#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
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
#endif
/* ================ USB Device Port Configuration ================*/
#define USBD_IRQHandler USBD_IRQHandler
#define USBD_BASE (0)
#define CONFIG_USBDEV_EP_NUM 4
#ifndef CONFIG_USBDEV_MAX_BUS
#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
#endif
#ifndef CONFIG_USBDEV_EP_NUM
#define CONFIG_USBDEV_EP_NUM 8
#endif
/* 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. */
// #define CONFIG_USB_HS
/* ---------------- FSDEV Configuration ---------------- */
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
/* ---------------- DWC2 Configuration ---------------- */
/* (5 * number of control endpoints + 8) + ((largest USB packet used / 4) + 1 for
* status information) + (2 * number of OUT endpoints) + 1 for Global NAK
*/
// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
/* IN Endpoints Max packet Size / 4 */
// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (1024 / 4)
// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_DMA_ENABLE
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Host Port Configuration ==================*/
#ifndef CONFIG_USBHOST_MAX_BUS
#define CONFIG_USBHOST_MAX_BUS 1
#endif
// #define USBH_IRQHandler USBH_IRQHandler
// #define USBH_BASE (0)
// #define CONFIG_USBHOST_PIPE_NUM 10
#ifndef CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USBHOST_PIPE_NUM 10
#endif
/* ================ EHCI Configuration ================ */
/* ---------------- EHCI Configuration ---------------- */
#define CONFIG_USB_EHCI_HCCR_BASE (0x20072000)
#define CONFIG_USB_EHCI_HCOR_BASE (0x20072000 + 0x10)
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
// #define CONFIG_USB_EHCI_INFO_ENABLE
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USB_EHCI_QTD_NUM 3
#define CONFIG_USB_EHCI_ITD_NUM 20
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
// #define CONFIG_USB_EHCI_CONFIGFLAG
// #define CONFIG_USB_EHCI_PORT_POWER
// #define CONFIG_USB_EHCI_ISO
// #define CONFIG_USB_EHCI_WITH_OHCI
/* ---------------- OHCI Configuration ---------------- */
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
/* ---------------- XHCI Configuration ---------------- */
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- DWC2 Configuration ---------------- */
/* largest non-periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
/* largest periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
/*
* (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
* 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
*/
// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE))
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
#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 {
struct adb_msg msg;
uint8_t payload[MAX_PAYLOAD];
};
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", 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 */

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

@@ -0,0 +1,289 @@
/*
* 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[128];
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;
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_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;
int ret = 0;
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

@@ -132,11 +132,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
@@ -648,6 +648,18 @@ struct audio_cs_if_ac_feature_unit_descriptor {
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
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(n) (6 + n)
struct audio_cs_if_as_general_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
@@ -812,6 +824,60 @@ struct audio_cs_ep_ep_general_descriptor {
#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
#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_INIT_LEN(n) (0x09 + 0x07 + 0x08 + 3 * n + 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(bInterfaceNumber, bNumEndpoints) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
@@ -1096,6 +1162,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,12 +1268,13 @@ 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_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_INIT_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_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))

View File

@@ -17,9 +17,9 @@ struct usbd_audio_priv {
struct audio_entity_info *table;
uint8_t num;
uint16_t uac_version;
} g_usbd_audio;
} g_usbd_audio[CONFIG_USBDEV_MAX_BUS];
static int audio_class_endpoint_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
uint8_t control_selector;
uint32_t sampling_freq = 0;
@@ -34,13 +34,13 @@ static int audio_class_endpoint_request_handler(struct usb_setup_packet *setup,
case AUDIO_REQUEST_SET_CUR:
memcpy((uint8_t *)&sampling_freq, *data, *len);
USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
usbd_audio_set_sampling_freq(ep, sampling_freq);
usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
break;
case AUDIO_REQUEST_GET_CUR:
case AUDIO_REQUEST_GET_MIN:
case AUDIO_REQUEST_GET_MAX:
case AUDIO_REQUEST_GET_RES:
sampling_freq = usbd_audio_get_sampling_freq(ep);
sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
memcpy(*data, &sampling_freq, 3);
USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
*len = 3;
@@ -55,14 +55,14 @@ static int audio_class_endpoint_request_handler(struct usb_setup_packet *setup,
return 0;
}
static int audio_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("Audio Class request: "
"bRequest 0x%02x\r\n",
setup->bRequest);
uint8_t entity_id;
uint8_t ep;
uint8_t ep = 0;
uint8_t subtype = 0x01;
uint8_t control_selector;
uint8_t ch;
@@ -79,10 +79,10 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
ARG_UNUSED(mute_string);
for (uint8_t i = 0; i < g_usbd_audio.num; i++) {
if (g_usbd_audio.table[i].bEntityId == entity_id) {
subtype = g_usbd_audio.table[i].bDescriptorSubtype;
ep = g_usbd_audio.table[i].ep;
for (uint8_t i = 0; i < g_usbd_audio[busid].num; i++) {
if (g_usbd_audio[busid].table[i].bEntityId == entity_id) {
subtype = g_usbd_audio[busid].table[i].bDescriptorSubtype;
ep = g_usbd_audio[busid].table[i].ep;
break;
}
}
@@ -98,14 +98,14 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
case AUDIO_CONTROL_FEATURE_UNIT:
switch (control_selector) {
case AUDIO_FU_CONTROL_MUTE:
if (g_usbd_audio.uac_version < 0x0200) {
if (g_usbd_audio[busid].uac_version < 0x0200) {
switch (setup->bRequest) {
case AUDIO_REQUEST_SET_CUR:
mute = (*data)[0];
usbd_audio_set_mute(ep, ch, mute);
usbd_audio_set_mute(busid, ep, ch, mute);
break;
case AUDIO_REQUEST_GET_CUR:
(*data)[0] = usbd_audio_get_mute(ep, ch);
(*data)[0] = usbd_audio_get_mute(busid, ep, ch);
*len = 1;
break;
default:
@@ -116,11 +116,11 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
switch (setup->bRequest) {
case AUDIO_REQUEST_CUR:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
(*data)[0] = usbd_audio_get_mute(ep, ch);
(*data)[0] = usbd_audio_get_mute(busid, ep, ch);
*len = 1;
} else {
mute = (*data)[0];
usbd_audio_set_mute(ep, ch, mute);
usbd_audio_set_mute(busid, ep, ch, mute);
}
break;
default:
@@ -130,33 +130,32 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
}
break;
case AUDIO_FU_CONTROL_VOLUME:
if (g_usbd_audio.uac_version < 0x0200) {
if (g_usbd_audio[busid].uac_version < 0x0200) {
switch (setup->bRequest) {
case AUDIO_REQUEST_SET_CUR:
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);
usbd_audio_set_volume(ep, ch, volume_db);
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(ep, ch);
volume_db -= 128;
volume_db = usbd_audio_get_volume(busid, ep, ch);
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(struct usb_setup_packet *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;
@@ -177,23 +176,32 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
switch (setup->bRequest) {
case AUDIO_REQUEST_CUR:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
volume_db = usbd_audio_get_volume(ep, ch);
volume = volume_db;
volume_db = usbd_audio_get_volume(busid, ep, ch);
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);
usbd_audio_set_volume(ep, ch, volume_db);
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 {
}
@@ -216,14 +224,14 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
switch (setup->bRequest) {
case AUDIO_REQUEST_CUR:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
sampling_freq = usbd_audio_get_sampling_freq(ep);
sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
memcpy(*data, &sampling_freq, 4);
USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
*len = 4;
} else {
memcpy(&sampling_freq, *data, setup->wLength);
USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
usbd_audio_set_sampling_freq(ep, sampling_freq);
usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
}
break;
case AUDIO_REQUEST_RANGE:
@@ -231,7 +239,7 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
uint8_t *sampling_freq_table = NULL;
uint16_t num;
usbd_audio_get_sampling_freq_table(ep, &sampling_freq_table);
usbd_audio_get_sampling_freq_table(busid, ep, &sampling_freq_table);
num = (uint16_t)((uint16_t)(sampling_freq_table[1] << 8) | ((uint16_t)sampling_freq_table[0]));
memcpy(*data, sampling_freq_table, (12 * num + 2));
*len = (12 * num + 2);
@@ -264,7 +272,7 @@ static int audio_class_interface_request_handler(struct usb_setup_packet *setup,
return 0;
}
static void audio_notify_handler(uint8_t event, void *arg)
static void audio_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:
@@ -274,9 +282,9 @@ static void audio_notify_handler(uint8_t event, void *arg)
case USBD_EVENT_SET_INTERFACE: {
struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
if (intf->bAlternateSetting) {
usbd_audio_open(intf->bInterfaceNumber);
usbd_audio_open(busid, intf->bInterfaceNumber);
} else {
usbd_audio_close(intf->bInterfaceNumber);
usbd_audio_close(busid, intf->bInterfaceNumber);
}
}
@@ -287,7 +295,8 @@ static void audio_notify_handler(uint8_t event, void *arg)
}
}
struct usbd_interface *usbd_audio_init_intf(struct usbd_interface *intf,
struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
struct usbd_interface *intf,
uint16_t uac_version,
struct audio_entity_info *table,
uint8_t num)
@@ -304,40 +313,65 @@ struct usbd_interface *usbd_audio_init_intf(struct usbd_interface *intf,
intf->notify_handler = audio_notify_handler;
}
g_usbd_audio.uac_version = uac_version;
g_usbd_audio.table = table;
g_usbd_audio.num = num;
g_usbd_audio[busid].uac_version = uac_version;
g_usbd_audio[busid].table = table;
g_usbd_audio[busid].num = num;
return intf;
}
__WEAK void usbd_audio_set_volume(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 ep, uint8_t ch)
__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 ep, uint8_t ch, bool mute)
__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 ep, uint8_t ch)
__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 ep, uint32_t sampling_freq)
__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 ep)
__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 ep, uint8_t **sampling_freq_table)
__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;
}

View File

@@ -19,22 +19,22 @@ struct audio_entity_info {
};
/* Init audio interface driver */
struct usbd_interface *usbd_audio_init_intf(struct usbd_interface *intf,
struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface *intf,
uint16_t uac_version,
struct audio_entity_info *table,
uint8_t num);
void usbd_audio_open(uint8_t intf);
void usbd_audio_close(uint8_t intf);
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 ep, uint8_t ch, int volume);
int usbd_audio_get_volume(uint8_t ep, uint8_t ch);
void usbd_audio_set_mute(uint8_t ep, uint8_t ch, bool mute);
bool usbd_audio_get_mute(uint8_t ep, uint8_t ch);
void usbd_audio_set_sampling_freq(uint8_t ep, uint32_t sampling_freq);
uint32_t usbd_audio_get_sampling_freq(uint8_t ep);
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);
void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq);
uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep);
void usbd_audio_get_sampling_freq_table(uint8_t ep, uint8_t **sampling_freq_table);
void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table);
#ifdef __cplusplus
}

View File

@@ -6,6 +6,10 @@
#include "usbh_core.h"
#include "usbh_audio.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_audio"
#include "usb_log.h"
#define DEV_FORMAT "/dev/audio%d"
/* general descriptor field offsets */
@@ -17,10 +21,6 @@
#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];
static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
@@ -28,11 +28,11 @@ 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];
@@ -43,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;
@@ -61,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:
@@ -96,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;
@@ -118,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;
}
}
@@ -141,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;
@@ -155,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:%d dB range: %d dB ~ %d dB\r\n", 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);
}
}
}
@@ -263,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) {
@@ -280,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;
@@ -307,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;
@@ -383,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;
}
}
@@ -432,20 +606,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 = {
@@ -462,20 +642,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

@@ -117,6 +117,7 @@
#define CDC_FUNC_DESC_COMMAND_SET_DETAIL 0x17
#define CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL 0x18
#define CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER 0x19
#define CDC_FUNC_DESC_NCM 0x1A
/* CDC class-specific request codes */
/* (usbcdc11.pdf, 6.2, Table 46) */
@@ -156,6 +157,17 @@
#define CDC_REQUEST_GET_ATM_DEVICE_STATISTICS 0x51
#define CDC_REQUEST_SET_ATM_DEFAULT_VC 0x52
#define CDC_REQUEST_GET_ATM_VC_STATISTICS 0x53
#define CDC_REQUEST_GET_NTB_PARAMETERS 0x80
#define CDC_REQUEST_GET_NET_ADDRESS 0x81
#define CDC_REQUEST_SET_NET_ADDRESS 0x82
#define CDC_REQUEST_GET_NTB_FORMAT 0x83
#define CDC_REQUEST_SET_NTB_FORMAT 0x84
#define CDC_REQUEST_GET_NTB_INPUT_SIZE 0x85
#define CDC_REQUEST_SET_NTB_INPUT_SIZE 0x86
#define CDC_REQUEST_GET_MAX_DATAGRAM_SIZE 0x87
#define CDC_REQUEST_SET_MAX_DATAGRAM_SIZE 0x88
#define CDC_REQUEST_GET_CRC_MODE 0x89
#define CDC_REQUEST_SET_CRC_MODE 0x90
/* Communication feature selector codes */
/* (usbcdc11.pdf, 6.2.2..6.2.4, Table 47) */
@@ -263,6 +275,10 @@
#define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE 0x01
#define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE 0x2A
#define CDC_NCM_NTH16_SIGNATURE 0x484D434E
#define CDC_NCM_NDP16_SIGNATURE_NCM0 0x304D434E
#define CDC_NCM_NDP16_SIGNATURE_NCM1 0x314D434E
/*------------------------------------------------------------------------------
* Structures based on usbcdc11.pdf (www.usb.org)
*----------------------------------------------------------------------------*/
@@ -339,7 +355,7 @@ struct cdc_acm_notification {
} __PACKED;
/** Ethernet Networking Functional Descriptor */
struct cdc_ecm_descriptor {
struct cdc_eth_descriptor {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
@@ -350,7 +366,7 @@ struct cdc_ecm_descriptor {
uint8_t bNumberPowerFilters;
} __PACKED;
struct cdc_ecm_notification {
struct cdc_eth_notification {
uint8_t bmRequestType;
uint8_t bNotificationType;
uint16_t wValue;
@@ -359,6 +375,41 @@ struct cdc_ecm_notification {
uint8_t data[8];
} __PACKED;
struct cdc_ncm_ntb_parameters {
uint16_t wLength;
uint16_t bmNtbFormatsSupported;
uint32_t dwNtbInMaxSize;
uint16_t wNdbInDivisor;
uint16_t wNdbInPayloadRemainder;
uint16_t wNdbInAlignment;
uint16_t wReserved;
uint32_t dwNtbOutMaxSize;
uint16_t wNdbOutDivisor;
uint16_t wNdbOutPayloadRemainder;
uint16_t wNdbOutAlignment;
uint16_t wNtbOutMaxDatagrams;
};
struct cdc_ncm_nth16 {
uint32_t dwSignature;
uint16_t wHeaderLength;
uint16_t wSequence;
uint16_t wBlockLength;
uint16_t wNdpIndex;
};
struct cdc_ncm_ndp16_datagram {
uint16_t wDatagramIndex;
uint16_t wDatagramLength;
};
struct cdc_ncm_ndp16 {
uint32_t dwSignature;
uint16_t wLength;
uint16_t wNextNdpIndex;
struct cdc_ncm_ndp16_datagram datagram[];
};
/*Length of template descriptor: 66 bytes*/
#define CDC_ACM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7)
// clang-format off
@@ -370,7 +421,7 @@ struct cdc_ecm_notification {
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 */ \
@@ -379,7 +430,7 @@ struct cdc_ecm_notification {
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 */ \
@@ -438,8 +489,8 @@ struct cdc_ecm_notification {
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 */ \
@@ -447,8 +498,8 @@ struct cdc_ecm_notification {
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 */ \
@@ -473,7 +524,7 @@ struct cdc_ecm_notification {
int_ep, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
0x08, 0x00, /* wMaxPacketSize */ \
0x10, /* bInterval */ \
0x05, /* bInterval */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
@@ -499,7 +550,7 @@ struct cdc_ecm_notification {
#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF)
/*Length of template descriptor: 66 bytes*/
/*Length of template descriptor: 71 bytes*/
#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, \
@@ -537,9 +588,84 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
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(wMaxSegmentSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
int_ep, /* bEndpointAddress */ \
0x03, /* bmAttributes */ \
0x10, 0x00, /* wMaxPacketSize */ \
0x05, /* bInterval */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x02, /* bNumEndpoints */ \
CDC_DATA_INTERFACE_CLASS, /* bInterfaceClass */ \
0x00, /* bInterfaceSubClass */ \
0x00, /* bInterfaceProtocol */ \
0x00, /* 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 */
// clang-format on
/*Length of template descriptor: 77 bytes*/
#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) \
/* Interface Associate */ \
0x08, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
bFirstInterface, /* bFirstInterface */ \
0x02, /* bInterfaceCount */ \
USB_DEVICE_CLASS_CDC, /* bFunctionClass */ \
CDC_NETWORK_CONTROL_MODEL, /* bFunctionSubClass */ \
CDC_COMMON_PROTOCOL_NONE, /* bFunctionProtocol */ \
0x00, /* iFunction */ \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
bFirstInterface, /* bInterfaceNumber */ \
0x00, /* bAlternateSetting */ \
0x01, /* bNumEndpoints */ \
USB_DEVICE_CLASS_CDC, /* bInterfaceClass */ \
CDC_NETWORK_CONTROL_MODEL, /* bInterfaceSubClass */ \
CDC_COMMON_PROTOCOL_NONE, /* bInterfaceProtocol */ \
str_idx, /* iInterface */ \
0x05, /* bLength */ \
CDC_CS_INTERFACE, /* bDescriptorType */ \
CDC_FUNC_DESC_HEADER, /* bDescriptorSubtype */ \
WBVAL(CDC_V1_10), /* bcdCDC */ \
0x05, /* bLength */ \
CDC_CS_INTERFACE, /* bDescriptorType */ \
CDC_FUNC_DESC_UNION, /* bDescriptorSubtype */ \
bFirstInterface, /* bMasterInterface */ \
(uint8_t)(bFirstInterface + 1), /* bSlaveInterface0 */ \
/* CDC ETH Functional Descriptor */ \
0x0D, /* bFunctionLength */\
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 */\
0x06, \
CDC_CS_INTERFACE, \
CDC_FUNC_DESC_NCM, \
0x00, 0x01, \
0x23, \
0x07, /* bLength */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
int_ep, /* bEndpointAddress */ \

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(struct usbd_interface *intf);
/* Setup request command callback api */
void usbd_cdc_acm_set_line_coding(uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_get_line_coding(uint8_t intf, struct cdc_line_coding *line_coding);
void usbd_cdc_acm_set_dtr(uint8_t intf, bool dtr);
void usbd_cdc_acm_set_rts(uint8_t intf, bool rts);
void usbd_cdc_acm_send_break(uint8_t intf);
#ifdef __cplusplus
}
#endif
#endif /* USBD_CDC_H */
#endif

View File

@@ -4,12 +4,12 @@
* 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" };
static int cdc_acm_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("CDC Class request: "
"bRequest 0x%02x\r\n",
@@ -47,7 +47,7 @@ static int cdc_acm_class_interface_request_handler(struct usb_setup_packet *setu
parity_name[line_coding.bParityType],
stop_name[line_coding.bCharFormat]);
usbd_cdc_acm_set_line_coding(intf_num, &line_coding);
usbd_cdc_acm_set_line_coding(busid, intf_num, &line_coding);
break;
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
@@ -57,12 +57,12 @@ static int cdc_acm_class_interface_request_handler(struct usb_setup_packet *setu
intf_num,
dtr,
rts);
usbd_cdc_acm_set_dtr(intf_num, dtr);
usbd_cdc_acm_set_rts(intf_num, rts);
usbd_cdc_acm_set_dtr(busid, intf_num, dtr);
usbd_cdc_acm_set_rts(busid, intf_num, rts);
break;
case CDC_REQUEST_GET_LINE_CODING:
usbd_cdc_acm_get_line_coding(intf_num, &line_coding);
usbd_cdc_acm_get_line_coding(busid, intf_num, &line_coding);
memcpy(*data, &line_coding, 7);
*len = 7;
USB_LOG_DBG("Get intf:%d linecoding %d %d %d %d\r\n",
@@ -73,7 +73,7 @@ static int cdc_acm_class_interface_request_handler(struct usb_setup_packet *setu
line_coding.bDataBits);
break;
case CDC_REQUEST_SEND_BREAK:
usbd_cdc_acm_send_break(intf_num);
usbd_cdc_acm_send_break(busid, intf_num);
break;
default:
USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
@@ -83,8 +83,10 @@ static int cdc_acm_class_interface_request_handler(struct usb_setup_packet *setu
return 0;
}
struct usbd_interface *usbd_cdc_acm_init_intf(struct usbd_interface *intf)
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;
@@ -93,26 +95,40 @@ struct usbd_interface *usbd_cdc_acm_init_intf(struct usbd_interface *intf)
return intf;
}
__WEAK void usbd_cdc_acm_set_line_coding(uint8_t intf, struct cdc_line_coding *line_coding)
__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 intf, struct cdc_line_coding *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;
line_coding->bCharFormat = 0;
}
__WEAK void usbd_cdc_acm_set_dtr(uint8_t intf, bool dtr)
__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 intf, bool rts)
__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 intf)
__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
#endif
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
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];
#endif
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;
@@ -35,7 +33,7 @@ static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
{
struct cdc_ecm_notification *notify = (struct cdc_ecm_notification *)g_cdc_ecm_notify_buf;
struct cdc_eth_notification *notify = (struct cdc_eth_notification *)g_cdc_ecm_notify_buf;
uint8_t bytes2send = 0;
notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
@@ -74,32 +72,38 @@ void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed
break;
}
if (bytes2send) {
usbd_ep_start_write(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);
}
}
}
static int cdc_ecm_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("CDC ECM Class request: "
"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);
@@ -109,17 +113,21 @@ static int cdc_ecm_class_interface_request_handler(struct usb_setup_packet *setu
return 0;
}
void cdc_ecm_notify_handler(uint8_t event, void *arg)
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(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:
@@ -127,56 +135,85 @@ void cdc_ecm_notify_handler(uint8_t event, void *arg)
}
}
void cdc_ecm_bulk_out(uint8_t ep, uint32_t nbytes)
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();
} else {
usbd_ep_start_read(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 ep, uint32_t nbytes)
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(ep, NULL, 0);
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 ep, uint32_t nbytes)
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_NODEV;
}
if (g_cdc_ecm_tx_data_length > 0) {
return -USB_ERR_BUSY;
}
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, len);
}
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
{
if (!usb_device_is_configured(0)) {
return -USB_ERR_NODEV;
}
g_cdc_ecm_rx_data_length = 0;
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
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(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);
g_cdc_ecm_rx_data_length = 0;
g_cdc_ecm_rx_data_buffer = NULL;
usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, CDC_ECM_MAX_PACKET_SIZE);
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
return p;
}
@@ -195,14 +232,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;
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
return usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, 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
@@ -220,18 +254,31 @@ struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const
cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep;
cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in;
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
return intf;
}
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
void usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2])
{
memcpy(g_connect_speed_table, speed, 8);
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);
}
}
__WEAK void usbd_cdc_ecm_data_recv_done(void)
__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,19 +12,19 @@
extern "C" {
#endif
/* Ethernet Maximum Segment size, typically 1514 bytes */
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
/* 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]);
void usbd_cdc_ecm_data_recv_done(void);
void usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2]);
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);
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len);
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
#include <lwip/pbuf.h>
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct pbuf *usbd_cdc_ecm_eth_rx(void);
int usbd_cdc_ecm_eth_tx(struct pbuf *p);
#endif

View File

@@ -6,20 +6,24 @@
#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 struct cdc_line_coding g_cdc_line_coding;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_acm_buf[CONFIG_USBHOST_MAX_CDC_ACM_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
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;
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CDC_ACM_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << 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];
@@ -30,68 +34,80 @@ static struct usbh_cdc_acm *usbh_cdc_acm_class_alloc(void)
static void usbh_cdc_acm_class_free(struct usbh_cdc_acm *cdc_acm_class)
{
int devno = cdc_acm_class->minor;
uint8_t devno = cdc_acm_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
if (devno < 32) {
g_devinuse &= ~(1U << 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;
struct usb_setup_packet *setup;
if (!cdc_acm_class || !cdc_acm_class->hport) {
return -USB_ERR_INVAL;
}
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->ctrl_intf;
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 7;
memcpy((uint8_t *)&g_cdc_line_coding, line_coding, sizeof(struct cdc_line_coding));
memcpy(g_cdc_acm_buf[cdc_acm_class->minor], line_coding, sizeof(struct cdc_line_coding));
return usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding);
return usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf[cdc_acm_class->minor]);
}
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;
struct usb_setup_packet *setup;
int ret;
if (!cdc_acm_class || !cdc_acm_class->hport) {
return -USB_ERR_INVAL;
}
setup = cdc_acm_class->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 = cdc_acm_class->ctrl_intf;
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 7;
ret = usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding);
ret = usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf[cdc_acm_class->minor]);
if (ret < 0) {
return ret;
}
memcpy(line_coding, (uint8_t *)&g_cdc_line_coding, sizeof(struct cdc_line_coding));
memcpy(line_coding, g_cdc_acm_buf[cdc_acm_class->minor], 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;
struct usb_setup_packet *setup;
if (!cdc_acm_class || !cdc_acm_class->hport) {
return -USB_ERR_INVAL;
}
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->ctrl_intf;
setup->wIndex = cdc_acm_class->intf;
setup->wLength = 0;
cdc_acm_class->dtr = dtr;
cdc_acm_class->rts = rts;
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;
int ret = 0;
struct usbh_cdc_acm *cdc_acm_class = usbh_cdc_acm_class_alloc();
if (cdc_acm_class == NULL) {
@@ -100,28 +116,11 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
}
cdc_acm_class->hport = hport;
cdc_acm_class->ctrl_intf = intf;
cdc_acm_class->data_intf = intf + 1;
cdc_acm_class->intf = intf;
hport->config.intf[intf].priv = cdc_acm_class;
hport->config.intf[intf + 1].priv = NULL;
cdc_acm_class->linecoding.dwDTERate = 115200;
cdc_acm_class->linecoding.bDataBits = 8;
cdc_acm_class->linecoding.bParityType = 0;
cdc_acm_class->linecoding.bCharFormat = 0;
ret = usbh_cdc_acm_set_line_coding(cdc_acm_class, &cdc_acm_class->linecoding);
if (ret < 0) {
USB_LOG_ERR("Fail to set linecoding\r\n");
return ret;
}
ret = usbh_cdc_acm_set_line_state(cdc_acm_class, true, true);
if (ret < 0) {
USB_LOG_ERR("Fail to set line state\r\n");
return ret;
}
#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);
@@ -140,6 +139,34 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
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;
}
@@ -204,20 +231,26 @@ int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *
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;
}
__WEAK void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
(void)cdc_acm_class;
}
__WEAK void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
{
(void)cdc_acm_class;
}
const struct usbh_class_driver cdc_acm_class_driver = {
@@ -233,21 +266,19 @@ const struct usbh_class_driver cdc_data_class_driver = {
};
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,
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.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,
.bInterfaceClass = USB_DEVICE_CLASS_CDC_DATA,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = NULL,
.class_driver = &cdc_data_class_driver
};

View File

@@ -12,17 +12,21 @@ struct usbh_cdc_acm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint (optional) */
#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 ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
bool dtr;
bool rts;
uint8_t intf;
uint8_t minor;
void *user_data;
};
#ifdef __cplusplus

View File

@@ -1,11 +1,15 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_cdc_ecm.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_cdc_ecm"
#include "usb_log.h"
#define DEV_FORMAT "/dev/cdc_ether"
/* general descriptor field offsets */
@@ -17,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_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
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;
@@ -39,7 +48,7 @@ static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class
return usbh_control_transfer(cdc_ecm_class->hport, setup, NULL);
}
int usbh_cdc_ecm_get_notification(struct usbh_cdc_ecm *cdc_ecm_class)
int usbh_cdc_ecm_get_connect_status(struct usbh_cdc_ecm *cdc_ecm_class)
{
int ret;
@@ -91,7 +100,7 @@ static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
break;
case CDC_CS_INTERFACE:
if ((cur_iface == cdc_ecm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
struct cdc_ecm_descriptor *desc = (struct cdc_ecm_descriptor *)p;
struct cdc_eth_descriptor *desc = (struct cdc_eth_descriptor *)p;
mac_str_idx = desc->iMACAddress;
cdc_ecm_class->max_segment_size = desc->wMaxSegmentSize;
goto get_mac;
@@ -135,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);
}
@@ -172,7 +181,7 @@ get_mac:
}
}
/* bit0 Promiscuous
/* bit0 Promiscuous
* bit1 ALL Multicast
* bit2 Directed
* bit3 Broadcast
@@ -184,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);
@@ -226,10 +235,8 @@ void usbh_cdc_ecm_rx_thread(void *argument)
{
uint32_t g_cdc_ecm_rx_length;
int ret;
err_t err;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
(void)argument;
USB_LOG_INFO("Create cdc ecm rx thread\r\n");
// clang-format off
find_class:
@@ -240,40 +247,38 @@ find_class:
}
while (g_cdc_ecm_class.connect_status == false) {
ret = usbh_cdc_ecm_get_notification(&g_cdc_ecm_class);
ret = usbh_cdc_ecm_get_connect_status(&g_cdc_ecm_class);
if (ret < 0) {
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_rx_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 {
/* There's no way to run here. */
}
}
// clang-format off
@@ -283,38 +288,31 @@ 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;
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);
}
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
{
(void)cdc_ecm_class;
}
__WEAK void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
{
(void)cdc_ecm_class;
}
const struct usbh_class_driver cdc_ecm_class_driver = {
@@ -325,10 +323,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

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -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,29 +20,31 @@ 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
extern "C" {
#endif
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);
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(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* USBH_CDC_ACM_H */
#endif /* USBH_CDC_ECM_H */

411
class/cdc/usbh_cdc_ncm.c Normal file
View File

@@ -0,0 +1,411 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_cdc_ncm.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_cdc_ncm"
#include "usb_log.h"
#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 */
/* interface descriptor field offsets */
#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[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[16];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_buf[32];
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;
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;
setup->wIndex = cdc_ncm_class->ctrl_intf;
setup->wLength = 28;
ret = usbh_control_transfer(cdc_ncm_class->hport, setup, g_cdc_ncm_buf);
if (ret < 8) {
return ret;
}
memcpy((uint8_t *)param, g_cdc_ncm_buf, ret - 8);
return 0;
}
static void print_ntb_parameters(struct cdc_ncm_ntb_parameters *param)
{
USB_LOG_RAW("CDC NCM ntb parameters:\r\n");
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("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("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);
USB_LOG_RAW("wNtbOutMaxDatagrams: 0x%02x \r\n", param->wNtbOutMaxDatagrams);
}
int usbh_cdc_ncm_get_connect_status(struct usbh_cdc_ncm *cdc_ncm_class)
{
int ret;
usbh_int_urb_fill(&cdc_ncm_class->intin_urb, cdc_ncm_class->hport, cdc_ncm_class->intin, g_cdc_ncm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&cdc_ncm_class->intin_urb);
if (ret < 0) {
return ret;
}
if (g_cdc_ncm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
if (g_cdc_ncm_inttx_buffer[2] == CDC_ECM_NET_CONNECTED) {
cdc_ncm_class->connect_status = true;
} else {
cdc_ncm_class->connect_status = false;
}
} else if (g_cdc_ncm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
memcpy(cdc_ncm_class->speed, &g_cdc_ncm_inttx_buffer[8], 8);
}
return 0;
}
static int usbh_cdc_ncm_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint8_t altsetting = 0;
char mac_buffer[12];
uint8_t *p;
uint8_t cur_iface = 0xff;
uint8_t mac_str_idx = 0xff;
struct usbh_cdc_ncm *cdc_ncm_class = &g_cdc_ncm_class;
memset(cdc_ncm_class, 0, sizeof(struct usbh_cdc_ncm));
cdc_ncm_class->hport = hport;
cdc_ncm_class->ctrl_intf = intf;
cdc_ncm_class->data_intf = intf + 1;
hport->config.intf[intf].priv = cdc_ncm_class;
hport->config.intf[intf + 1].priv = NULL;
p = hport->raw_config_desc;
while (p[DESC_bLength]) {
switch (p[DESC_bDescriptorType]) {
case USB_DESCRIPTOR_TYPE_INTERFACE:
cur_iface = p[INTF_DESC_bInterfaceNumber];
//cur_alt_setting = p[INTF_DESC_bAlternateSetting];
break;
case CDC_CS_INTERFACE:
if ((cur_iface == cdc_ncm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
struct cdc_eth_descriptor *desc = (struct cdc_eth_descriptor *)p;
mac_str_idx = desc->iMACAddress;
cdc_ncm_class->max_segment_size = desc->wMaxSegmentSize;
goto get_mac;
}
break;
default:
break;
}
/* skip to next descriptor */
p += p[DESC_bLength];
}
get_mac:
if (mac_str_idx == 0xff) {
USB_LOG_ERR("Do not find cdc ncm mac string\r\n");
return -1;
}
memset(mac_buffer, 0, 12);
ret = usbh_get_string_desc(cdc_ncm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
if (ret < 0) {
return ret;
}
for (int i = 0, j = 0; i < 12; i += 2, j++) {
char byte_str[3];
byte_str[0] = mac_buffer[i];
byte_str[1] = mac_buffer[i + 1];
byte_str[2] = '\0';
uint32_t byte = strtoul(byte_str, NULL, 16);
cdc_ncm_class->mac[j] = (unsigned char)byte;
}
USB_LOG_INFO("CDC NCM MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
cdc_ncm_class->mac[0],
cdc_ncm_class->mac[1],
cdc_ncm_class->mac[2],
cdc_ncm_class->mac[3],
cdc_ncm_class->mac[4],
cdc_ncm_class->mac[5]);
if (cdc_ncm_class->max_segment_size > CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE) {
USB_LOG_ERR("CDC NCM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE, cdc_ncm_class->max_segment_size);
} else {
USB_LOG_INFO("CDC NCM Max Segment Size:%u\r\n", cdc_ncm_class->max_segment_size);
}
usbh_cdc_ncm_get_ntb_parameters(cdc_ncm_class, &cdc_ncm_class->ntb_param);
print_ntb_parameters(&cdc_ncm_class->ntb_param);
/* enable int ep */
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
USBH_EP_INIT(cdc_ncm_class->intin, ep_desc);
if (hport->config.intf[intf + 1].altsetting_num > 1) {
altsetting = hport->config.intf[intf + 1].altsetting_num - 1;
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[altsetting].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[altsetting].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(cdc_ncm_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(cdc_ncm_class->bulkout, ep_desc);
}
}
USB_LOG_INFO("Select cdc ncm altsetting: %d\r\n", altsetting);
usbh_set_interface(cdc_ncm_class->hport, cdc_ncm_class->data_intf, altsetting);
} else {
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_ncm_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(cdc_ncm_class->bulkout, ep_desc);
}
}
}
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);
usbh_cdc_ncm_run(cdc_ncm_class);
return ret;
}
static int usbh_cdc_ncm_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_cdc_ncm *cdc_ncm_class = (struct usbh_cdc_ncm *)hport->config.intf[intf].priv;
if (cdc_ncm_class) {
if (cdc_ncm_class->bulkin) {
usbh_kill_urb(&cdc_ncm_class->bulkin_urb);
}
if (cdc_ncm_class->bulkout) {
usbh_kill_urb(&cdc_ncm_class->bulkout_urb);
}
if (cdc_ncm_class->intin) {
usbh_kill_urb(&cdc_ncm_class->intin_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister CDC NCM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_ncm_stop(cdc_ncm_class);
}
memset(cdc_ncm_class, 0, sizeof(struct usbh_cdc_ncm));
}
return ret;
}
void usbh_cdc_ncm_rx_thread(void *argument)
{
uint32_t g_cdc_ncm_rx_length;
int ret;
#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)argument;
USB_LOG_INFO("Create cdc ncm rx thread\r\n");
// clang-format off
find_class:
// clang-format on
g_cdc_ncm_class.connect_status = false;
if (usbh_find_class_instance("/dev/cdc_ncm") == NULL) {
goto delete;
}
while (g_cdc_ncm_class.connect_status == false) {
ret = usbh_cdc_ncm_get_connect_status(&g_cdc_ncm_class);
if (ret < 0) {
usb_osal_msleep(100);
goto 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], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ncm_class.bulkin_urb);
if (ret < 0) {
goto find_class;
}
g_cdc_ncm_rx_length += g_cdc_ncm_class.bulkin_urb.actual_length;
/* 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];
if ((nth16->dwSignature != CDC_NCM_NTH16_SIGNATURE) ||
(nth16->wHeaderLength != 12) ||
(nth16->wBlockLength != g_cdc_ncm_rx_length)) {
USB_LOG_ERR("invalid rx nth16\r\n");
g_cdc_ncm_rx_length = 0;
continue;
}
struct cdc_ncm_ndp16 *ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_buffer[nth16->wNdpIndex];
if ((ndp16->dwSignature != CDC_NCM_NDP16_SIGNATURE_NCM0) && (ndp16->dwSignature != CDC_NCM_NDP16_SIGNATURE_NCM1)) {
USB_LOG_ERR("invalid rx ndp16\r\n");
g_cdc_ncm_rx_length = 0;
continue;
}
uint16_t datagram_num = (ndp16->wLength - 8) / 4;
USB_LOG_DBG("datagram num:%02x\r\n", datagram_num);
for (uint16_t i = 0; i < datagram_num; i++) {
struct cdc_ncm_ndp16_datagram *ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_rx_buffer[nth16->wNdpIndex + 8 + 4 * i];
if (ndp16_datagram->wDatagramIndex && ndp16_datagram->wDatagramLength) {
USB_LOG_DBG("ndp16_datagram index:%02x, length:%02x\r\n", ndp16_datagram->wDatagramIndex, ndp16_datagram->wDatagramLength);
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
delete:
USB_LOG_INFO("Delete cdc ncm rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
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)
{
struct cdc_ncm_ndp16_datagram *ndp16_datagram;
if (g_cdc_ncm_class.connect_status == false) {
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(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];
ndp16->dwSignature = CDC_NCM_NDP16_SIGNATURE_NCM0;
ndp16->wLength = 16;
ndp16->wNextNdpIndex = 0;
ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 0];
ndp16_datagram->wDatagramIndex = 16;
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;
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);
return usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
}
__WEAK void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
{
(void)cdc_ncm_class;
}
__WEAK void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
{
(void)cdc_ncm_class;
}
const struct usbh_class_driver cdc_ncm_class_driver = {
.driver_name = "cdc_ncm",
.connect = usbh_cdc_ncm_connect,
.disconnect = usbh_cdc_ncm_disconnect
};
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,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_NETWORK_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
.id_table = NULL,
.class_driver = &cdc_ncm_class_driver
};

54
class/cdc/usbh_cdc_ncm.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_CDC_NCM_H
#define USBH_CDC_NCM_H
#include "usb_cdc.h"
struct usbh_cdc_ncm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* Interrupt IN endpoint */
struct usbh_urb bulkout_urb; /* Bulk out endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN endpoint */
struct usbh_urb intin_urb; /* Interrupt IN endpoint */
uint8_t ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
uint8_t minor;
struct cdc_ncm_ntb_parameters ntb_param;
uint16_t bulkin_sequence;
uint16_t bulkout_sequence;
uint8_t mac[6];
bool connect_status;
uint16_t max_segment_size;
uint32_t speed[2];
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
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);
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(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* USBH_CDC_NCM_H */

View File

@@ -428,7 +428,7 @@ void dfu_request_abort(void)
}
}
static int dfu_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("DFU Class request: "
"bRequest 0x%02x\r\n",
@@ -464,7 +464,7 @@ static int dfu_class_interface_request_handler(struct usb_setup_packet *setup, u
return 0;
}
static void dfu_notify_handler(uint8_t event, void *arg)
static void dfu_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:

View File

@@ -558,26 +558,24 @@ struct usb_hid_kbd_report
};
/* 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 */
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
};
/* Joystick input report (1 bytes) (HID D.1) */
struct usb_hid_js_report
{
uint8_t xpos; /* X position */
uint8_t ypos; /* X position */
int8_t xpos; /* X position */
int8_t ypos; /* X position */
uint8_t buttons; /* See USBHID_JSIN_* definitions */
uint8_t throttle; /* Throttle */
};

View File

@@ -6,7 +6,7 @@
#include "usbd_core.h"
#include "usbd_hid.h"
static int hid_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("HID Class request: "
"bRequest 0x%02x\r\n",
@@ -17,27 +17,27 @@ static int hid_class_interface_request_handler(struct usb_setup_packet *setup, u
switch (setup->bRequest) {
case HID_REQUEST_GET_REPORT:
/* report id ,report type */
usbd_hid_get_report(intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), data, len);
usbd_hid_get_report(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), data, len);
break;
case HID_REQUEST_GET_IDLE:
(*data)[0] = usbd_hid_get_idle(intf_num, LO_BYTE(setup->wValue));
(*data)[0] = usbd_hid_get_idle(busid, intf_num, LO_BYTE(setup->wValue));
*len = 1;
break;
case HID_REQUEST_GET_PROTOCOL:
(*data)[0] = usbd_hid_get_protocol(intf_num);
(*data)[0] = usbd_hid_get_protocol(busid, intf_num);
*len = 1;
break;
case HID_REQUEST_SET_REPORT:
/* report id ,report type, report, report len */
usbd_hid_set_report(intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), *data, *len);
usbd_hid_set_report(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), *data, *len);
break;
case HID_REQUEST_SET_IDLE:
/* report id, duration */
usbd_hid_set_idle(intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue));
usbd_hid_set_idle(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue));
break;
case HID_REQUEST_SET_PROTOCOL:
/* protocol */
usbd_hid_set_protocol(intf_num, LO_BYTE(setup->wValue));
usbd_hid_set_protocol(busid, intf_num, LO_BYTE(setup->wValue));
break;
default:
@@ -48,8 +48,10 @@ static int hid_class_interface_request_handler(struct usb_setup_packet *setup, u
return 0;
}
struct usbd_interface *usbd_hid_init_intf(struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len)
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(struct usbd_interface *intf, const uin
return intf;
}
__WEAK void usbd_hid_get_report(uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len)
/*
* 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 intf, uint8_t report_id)
__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 intf)
__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 intf, uint8_t report_id, uint8_t report_type, uint8_t *report, uint32_t report_len)
__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 intf, uint8_t report_id, uint8_t duration)
__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 intf, uint8_t protocol)
__WEAK void usbd_hid_set_protocol(uint8_t busid, uint8_t intf, uint8_t protocol)
{
(void)busid;
(void)intf;
(void)protocol;
}

View File

@@ -13,19 +13,19 @@ extern "C" {
#endif
/* Init hid interface driver */
struct usbd_interface *usbd_hid_init_intf(struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
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 intf_num, const uint8_t *desc);
void usbd_hid_report_descriptor_register(uint8_t intf_num, const uint8_t *desc, uint32_t desc_len);
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 intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len);
uint8_t usbd_hid_get_idle(uint8_t intf, uint8_t report_id);
uint8_t usbd_hid_get_protocol(uint8_t intf);
void usbd_hid_set_report(uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t *report, uint32_t report_len);
void usbd_hid_set_idle(uint8_t intf, uint8_t report_id, uint8_t duration);
void usbd_hid_set_protocol(uint8_t intf, uint8_t protocol);
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);
uint8_t usbd_hid_get_protocol(uint8_t busid, uint8_t intf);
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 usbd_hid_set_idle(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t duration);
void usbd_hid_set_protocol(uint8_t busid, uint8_t intf, uint8_t protocol);
#ifdef __cplusplus
}

View File

@@ -6,20 +6,32 @@
#include "usbh_core.h"
#include "usbh_hid.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_hid"
#include "usb_log.h"
#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(64, 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];
@@ -30,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;
@@ -72,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], ret - 8);
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;
@@ -102,10 +128,55 @@ 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_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;
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_REPORT;
setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
setup->wIndex = 0;
setup->wLength = buflen;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
if (ret < 8) {
return ret;
}
memcpy(buffer, g_hid_buf[hid_class->minor], ret - 8);
return ret;
}
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) {
@@ -118,6 +189,42 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
hport->config.intf[intf].priv = hid_class;
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);
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];
}
if (found == false) {
USB_LOG_ERR("HID interface not found\r\n");
return -USB_ERR_INVAL;
}
found:
// /* 0x0 = boot protocol, 0x1 = report protocol */
// ret = usbh_hid_set_protocol(hid_class, 0x1);
// if (ret < 0) {
@@ -129,7 +236,8 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_WRN("Do not support set idle\r\n");
}
ret = usbh_hid_get_report_descriptor(hid_class, hid_class->report_desc);
/* We read report desc but do nothing (because of too much memory usage for parsing report desc, parsed by users) */
ret = usbh_hid_get_report_descriptor(hid_class, g_hid_buf[hid_class->minor], MIN(sizeof(g_hid_buf[hid_class->minor]), hid_class->report_size));
if (ret < 0) {
return ret;
}
@@ -179,10 +287,12 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
__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 = {
@@ -193,10 +303,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

@@ -15,17 +15,24 @@ 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_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);
void usbh_hid_run(struct usbh_hid *hid_class);
void usbh_hid_stop(struct usbh_hid *hid_class);

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

@@ -6,48 +6,38 @@
#include "usbh_core.h"
#include "usbh_hub.h"
#define DEV_FORMAT "/dev/hub%d"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_hub"
#include "usb_log.h"
#define DEV_FORMAT "/dev/hub%d"
#define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 100
#define DELAY_TIME_AFTER_RESET 200
#define EXTHUB_FIRST_INDEX 2
#define EXTHUB_FIRST_INDEX 2
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[32];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USB_ALIGN_SIZE];
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)];
usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
usb_osal_thread_t hub_thread;
usb_osal_mq_t hub_mq;
struct usbh_hub roothub;
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];
@@ -58,25 +48,13 @@ 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
static void usbh_hub_register(struct usbh_hub *hub)
{
usb_slist_add_tail(&hub_class_head, &hub->list);
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static void usbh_hub_unregister(struct usbh_hub *hub)
{
usb_slist_remove(&hub_class_head, &hub->list);
}
static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
{
@@ -87,28 +65,20 @@ 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;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
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;
@@ -116,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)
{
@@ -144,11 +114,11 @@ static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct h
setup->wIndex = port;
setup->wLength = 4;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
if (ret < 0) {
return ret;
}
memcpy(port_status, g_hub_buf, 4);
memcpy(port_status, g_hub_buf[hub->bus->busid], 4);
return ret;
}
@@ -200,6 +170,8 @@ static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
#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;
@@ -219,6 +191,29 @@ static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length
}
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_RAW("SuperSpeed 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);
}
return 0;
}
#endif
static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
@@ -233,7 +228,7 @@ static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hu
setup->wValue = 0;
setup->wIndex = port;
setup->wLength = 4;
return usbh_roothub_control(&roothub_setup, (uint8_t *)port_status);
return usbh_roothub_control(hub->bus, &roothub_setup, (uint8_t *)port_status);
} else {
return _usbh_hub_get_portstatus(hub, port, port_status);
}
@@ -251,7 +246,7 @@ 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(setup, NULL);
return usbh_roothub_control(hub->bus, setup, NULL);
} else {
return _usbh_hub_set_feature(hub, port, feature);
}
@@ -269,7 +264,7 @@ int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
setup->wValue = feature;
setup->wIndex = port;
setup->wLength = 0;
return usbh_roothub_control(setup, NULL);
return usbh_roothub_control(hub->bus, setup, NULL);
} else {
return _usbh_hub_clear_feature(hub, port, feature);
}
@@ -287,33 +282,12 @@ static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
setup->wValue = depth;
setup->wIndex = 0;
setup->wLength = 0;
return usbh_roothub_control(setup, NULL);
return usbh_roothub_control(hub->bus, setup, NULL);
} else {
return _usbh_hub_set_depth(hub, depth);
}
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_osal_mq_send(hub_mq, (uintptr_t)hub);
}
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)
{
@@ -321,9 +295,22 @@ static void hub_int_complete_callback(void *arg, int nbytes)
if (nbytes > 0) {
usbh_hub_thread_wakeup(hub);
} else if (nbytes == -USB_ERR_NAK) {
/* Restart timer to submit urb again */
USB_LOG_DBG("Restart timer\r\n");
usb_osal_timer_start(hub->int_timer);
} else {
}
}
static void hub_int_timeout(void *arg)
{
struct usbh_hub *hub = (struct usbh_hub *)arg;
usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
usbh_submit_urb(&hub->intin_urb);
}
static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
@@ -338,19 +325,64 @@ 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);
}
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;
@@ -360,28 +392,16 @@ 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);
if (ret < 0) {
@@ -391,12 +411,17 @@ 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);
usbh_hub_register(hub);
USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
hub->int_buffer = g_hub_intbuf[hub->index - 1];
usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
usbh_submit_urb(&hub->intin_urb);
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);
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,7 +437,11 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_kill_urb(&hub->intin_urb);
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
if (hub->int_timer) {
usb_osal_timer_delete(hub->int_timer);
}
for (uint8_t port = 0; port < hub->nports; port++) {
child = &hub->child[port];
usbh_hubport_release(child);
child->parent = NULL;
@@ -420,7 +449,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);
usbh_hub_unregister(hub);
}
usbh_hub_class_free(hub);
@@ -429,38 +457,28 @@ 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;
if (!hub->connected) {
return;
}
portchange_index = hub->int_buffer[0];
hub->int_buffer[0] = 0;
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)))) {
@@ -566,29 +584,24 @@ static void usbh_hub_events(struct usbh_hub *hub)
}
}
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 */
@@ -596,15 +609,20 @@ 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;
child->bus = hub->bus;
child->mutex = usb_osal_mutex_create();
USB_LOG_INFO("New %s device on Hub %u, Port %u connected\r\n", speed_table[speed], hub->index, port + 1);
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 */
@@ -619,14 +637,14 @@ 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 Hub %u, Port %u disconnected\r\n", hub->index, port + 1);
USB_LOG_INFO("Device on Bus %u, Hub %u, Port %u disconnected\r\n", hub->bus->busid, hub->index, port + 1);
}
}
}
/* Start next hub int transfer */
if (!hub->is_roothub && hub->connected) {
usbh_submit_urb(&hub->intin_urb);
usb_osal_timer_start(hub->int_timer);
}
}
@@ -635,9 +653,11 @@ static void usbh_hub_thread(void *argument)
struct usbh_hub *hub;
int ret = 0;
usb_hc_init();
struct usbh_bus *bus = (struct usbh_bus *)argument;
usb_hc_init(bus);
while (1) {
ret = usb_osal_mq_recv(hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
continue;
}
@@ -645,69 +665,62 @@ static void usbh_hub_thread(void *argument)
}
}
static void usbh_roothub_register(void)
void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_slist_init(&hub_class_head);
memset(&roothub, 0, sizeof(struct usbh_hub));
roothub.connected = true;
roothub.index = 1;
roothub.is_roothub = true;
roothub.parent = NULL;
roothub.hub_addr = 1;
roothub.hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
usbh_hub_register(&roothub);
usb_osal_mq_send(hub->bus->hub_mq, (uintptr_t)hub);
}
void usbh_roothub_thread_wakeup(uint8_t port)
int usbh_hub_initialize(struct usbh_bus *bus)
{
roothub.int_buffer = g_hub_intbuf[roothub.index - 1];
roothub.int_buffer[0] |= (1 << port);
usbh_hub_thread_wakeup(&roothub);
}
char thread_name[32] = { 0 };
struct usbh_hub *hub;
int usbh_hub_initialize(void)
{
usbh_roothub_register();
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;
hub_mq = usb_osal_mq_create(7);
if (hub_mq == NULL) {
bus->hub_mq = usb_osal_mq_create(7);
if (bus->hub_mq == NULL) {
USB_LOG_ERR("Failed to create hub mq\r\n");
return -1;
}
hub_thread = usb_osal_thread_create("usbh_hub", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, NULL);
if (hub_thread == NULL) {
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) {
USB_LOG_ERR("Failed to create hub thread\r\n");
return -1;
}
return 0;
}
int usbh_hub_deinitialize(void)
int usbh_hub_deinitialize(struct usbh_bus *bus)
{
usb_slist_t *i;
struct usbh_hubport *hport;
struct usbh_hub *hub;
size_t flags;
flags = usb_osal_enter_critical_section();
usb_slist_for_each(i, &hub_class_head)
{
struct usbh_hub *hub = usb_slist_entry(i, struct usbh_hub, list);
hub = &bus->hcd.roothub;
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
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();
usb_hc_deinit(bus);
usb_osal_leave_critical_section(flags);
usb_osal_mq_delete(hub_mq);
usb_osal_thread_delete(hub_thread);
usb_osal_mq_delete(bus->hub_mq);
usb_osal_thread_delete(bus->hub_thread);
return 0;
}
@@ -721,11 +734,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

@@ -8,12 +8,7 @@
#include "usb_hub.h"
#define USBH_HUB_MAX_PORTS 4
/* Maximum size of an interrupt IN transfer */
#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
extern usb_slist_t hub_class_head;
extern struct usbh_hub roothub;
struct usbh_hub;
#ifdef __cplusplus
extern "C" {
@@ -22,10 +17,10 @@ extern "C" {
int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature);
int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature);
void usbh_roothub_thread_wakeup(uint8_t port);
void usbh_hub_thread_wakeup(struct usbh_hub *hub);
int usbh_hub_initialize(void);
int usbh_hub_deinitialize(void);
int usbh_hub_initialize(struct usbh_bus *bus);
int usbh_hub_deinitialize(struct usbh_bus *bus);
#ifdef __cplusplus
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, zhihong chen
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,16 +14,18 @@ extern "C" {
#endif
/* Init msc interface driver */
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf,
struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep);
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length);
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length);
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size);
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
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(bool readonly);
bool usbd_msc_set_popup(void);
void usbd_msc_set_readonly(uint8_t busid, bool readonly);
bool usbd_msc_get_popup(uint8_t busid);
void usbd_msc_polling(uint8_t busid);
#ifdef __cplusplus
}

View File

@@ -7,9 +7,15 @@
#include "usbh_msc.h"
#include "usb_scsi.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_msc"
#include "usb_log.h"
#define DEV_FORMAT "/dev/sd%c"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_buf[32];
#define MSC_INQUIRY_TIMEOUT 500
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;
@@ -17,11 +23,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];
@@ -32,17 +38,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;
@@ -76,6 +87,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);
@@ -109,14 +122,14 @@ 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");
goto __err_exit;
@@ -124,16 +137,16 @@ static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, s
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) {
@@ -144,7 +157,7 @@ static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, s
/* 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");
goto __err_exit;
@@ -171,14 +184,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_buf[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_buf[msc_class->sdchar - 'a'], NULL, MSC_INQUIRY_TIMEOUT);
}
static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
@@ -186,7 +199,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_buf[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -196,7 +209,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_buf[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], MSC_INQUIRY_TIMEOUT);
}
static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
@@ -204,7 +217,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_buf[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -214,7 +227,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_buf[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], MSC_INQUIRY_TIMEOUT);
}
static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
@@ -222,7 +235,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_buf[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -231,7 +244,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_buf[msc_class->sdchar - 'a'], g_msc_buf[msc_class->sdchar - 'a'], MSC_INQUIRY_TIMEOUT);
}
static inline void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
@@ -239,11 +252,11 @@ 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_buf[msc_class->sdchar - 'a'];
memcpy(g_msc_buf, message, 31);
memcpy(g_msc_buf[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_buf[msc_class->sdchar - 'a'], NULL, MSC_INQUIRY_TIMEOUT);
}
static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
@@ -263,12 +276,17 @@ 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;
} 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;
@@ -359,13 +377,12 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
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_buf[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -376,7 +393,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_buf[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)
@@ -384,7 +401,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_buf[msc_class->sdchar - 'a'];
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
@@ -396,7 +413,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_buf[msc_class->sdchar - 'a'], (uint8_t *)buffer, CONFIG_USBHOST_MSC_TIMEOUT);
}
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
@@ -410,10 +427,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 = {
@@ -424,10 +443,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 {

View File

@@ -1,7 +1,7 @@
#include "usbd_core.h"
#include "usbd_xxx.h"
static int xxx_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int xxx_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_WRN("XXX Class request: "
"bRequest 0x%02x\r\n",
@@ -16,7 +16,7 @@ static int xxx_class_interface_request_handler(struct usb_setup_packet *setup, u
return 0;
}
static void xxx_notify_handler(uint8_t event, void *arg)
static void xxx_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:
@@ -28,7 +28,7 @@ static void xxx_notify_handler(uint8_t event, void *arg)
}
}
struct usbd_interface *usbd_xxx_init_intf(struct usbd_interface *intf)
struct usbd_interface *usbd_xxx_init_intf(uint8_t busid, struct usbd_interface *intf)
{
intf->class_interface_handler = xxx_class_interface_request_handler;
intf->class_endpoint_handler = NULL;

View File

@@ -7,7 +7,7 @@
extern "C" {
#endif
struct usbd_interface *usbd_xxx_init_intf(struct usbd_interface *intf);
struct usbd_interface *usbd_xxx_init_intf(uint8_t busid, struct usbd_interface *intf);
#ifdef __cplusplus
}

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);

825
class/vendor/net/usbh_asix.c vendored Normal file
View File

@@ -0,0 +1,825 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_asix.h"
#include "usb_cdc.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "asix"
#include "usb_log.h"
#define DEV_FORMAT "/dev/asix"
static struct usbh_asix g_asix_class;
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_rx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_tx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE];
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];
#define ETH_ALEN 6
#define PHY_MODE_MARVELL 0x0000
#define MII_MARVELL_LED_CTRL 0x0018
#define MII_MARVELL_STATUS 0x001b
#define MII_MARVELL_CTRL 0x0014
#define MARVELL_LED_MANUAL 0x0019
#define MARVELL_STATUS_HWCFG 0x0004
#define MARVELL_CTRL_TXDELAY 0x0002
#define MARVELL_CTRL_RXDELAY 0x0080
#define PHY_MODE_RTL8211CL 0x000C
#define AX88772A_PHY14H 0x14
#define AX88772A_PHY14H_DEFAULT 0x442C
#define AX88772A_PHY15H 0x15
#define AX88772A_PHY15H_DEFAULT 0x03C8
#define AX88772A_PHY16H 0x16
#define AX88772A_PHY16H_DEFAULT 0x4044
#define SPEED_100 0
#define SPEED_10 1
static int usbh_asix_read_cmd(struct usbh_asix *asix_class,
uint8_t cmd,
uint16_t value,
uint16_t index,
void *data,
uint16_t size)
{
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;
setup->wIndex = index;
setup->wLength = size;
ret = usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
if (ret < 8) {
return ret;
}
memcpy(data, g_asix_buf, ret - 8);
return ret;
}
static int usbh_asix_write_cmd(struct usbh_asix *asix_class,
uint8_t cmd,
uint16_t value,
uint16_t index,
void *data,
uint16_t size)
{
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;
setup->wValue = value;
setup->wIndex = index;
setup->wLength = size;
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)
{
uint8_t smsr;
uint16_t res = (uint16_t)val;
int ret;
for (uint8_t i = 0; i < 10; i++) {
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_SW_MII, 0, 0, NULL, 0);
if (ret < 0) {
return ret;
}
usb_osal_msleep(1);
ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &smsr, 1);
if (ret < 0) {
return ret;
}
if (smsr & AX_HOST_EN) {
break;
}
}
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MII_REG, phy_id, loc, &res, 2);
if (ret < 0) {
return ret;
}
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_HW_MII, 0, 0, NULL, 0);
if (ret < 0) {
return ret;
}
return 0;
}
static int usbh_asix_mdio_read(struct usbh_asix *asix_class, int phy_id, int loc)
{
uint8_t smsr;
uint16_t res;
int ret;
for (uint8_t i = 0; i < 10; i++) {
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_SW_MII, 0, 0, NULL, 0);
if (ret < 0) {
return ret;
}
usb_osal_msleep(1);
ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &smsr, 1);
if (ret < 0) {
return ret;
}
if (smsr & AX_HOST_EN) {
break;
}
}
ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_MII_REG, phy_id, loc, &res, 2);
if (ret < 0) {
return ret;
}
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_HW_MII, 0, 0, NULL, 0);
if (ret < 0) {
return ret;
}
return res;
}
static int usbh_asix_read_phy_addr(struct usbh_asix *asix_class, bool internal)
{
int ret, offset;
uint8_t buf[2];
ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_PHY_ID, 0, 0, buf, 2);
if (ret < 0) {
return ret;
}
offset = (internal ? 1 : 0);
ret = buf[offset];
USB_LOG_INFO("%s PHY address 0x%x\r\n", internal ? "internal" : "external", ret);
return ret;
}
static int usbh_asix_sw_reset(struct usbh_asix *asix_class, uint8_t flags)
{
int ret;
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_RESET, flags, 0, NULL, 0);
if (ret < 0)
USB_LOG_ERR("Failed to send software reset: %d\r\n", ret);
return ret;
}
static uint16_t usbh_asix_read_rx_ctl(struct usbh_asix *asix_class)
{
uint16_t v;
int ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_RX_CTL, 0, 0, &v, 2);
if (ret < 0) {
return ret;
}
return v;
}
static int usbh_asix_write_rx_ctl(struct usbh_asix *asix_class, uint16_t mode)
{
int ret;
USB_LOG_DBG("asix_write_rx_ctl() - mode = 0x%04x\r\n", mode);
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_RX_CTL, mode, 0, NULL, 0);
if (ret < 0)
USB_LOG_ERR("Failed to write RX_CTL mode to 0x%04x: %02x\r\n",
mode, ret);
return ret;
}
static uint16_t usbh_asix_read_medium_status(struct usbh_asix *asix_class)
{
uint16_t v;
int ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_MEDIUM_STATUS, 0, 0, &v, 2);
if (ret < 0) {
USB_LOG_ERR("Error reading Medium Status register: %02x\r\n",
ret);
return ret; /* TODO: callers not checking for error ret */
}
return v;
}
static int usbh_asix_write_medium_mode(struct usbh_asix *asix_class, uint16_t mode)
{
int ret;
USB_LOG_DBG("asix_write_medium_mode() - mode = 0x%04x\r\n", mode);
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, NULL, 0);
if (ret < 0)
USB_LOG_ERR("Failed to write Medium Mode mode to 0x%04x: %02x\r\n",
mode, ret);
return ret;
}
static int usbh_asix_write_gpio(struct usbh_asix *asix_class, uint16_t value, int sleep)
{
int ret;
USB_LOG_DBG("asix_write_gpio() - value = 0x%04x\r\n", value);
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_GPIOS, value, 0, NULL, 0);
if (ret < 0)
USB_LOG_ERR("Failed to write GPIO value 0x%04x: %d\r\n",
value, ret);
if (sleep)
usb_osal_msleep(sleep);
return ret;
}
/*
* AX88772 & AX88178 have a 16-bit RX_CTL value
*/
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);
usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, NULL, 0);
}
static int usbh_ax88772_hw_reset(struct usbh_asix *asix_class)
{
uint16_t rx_ctl;
int ret;
ret = usbh_asix_write_gpio(asix_class, AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5);
if (ret < 0)
goto out;
ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_PHY_SELECT, asix_class->embd_phy,
0, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Select PHY #1 failed: %d\r\n", ret);
goto out;
}
if (asix_class->embd_phy) {
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD);
if (ret < 0)
goto out;
usb_osal_msleep(10);
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_CLEAR);
if (ret < 0)
goto out;
usb_osal_msleep(60);
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL | AX_SWRESET_PRL);
if (ret < 0)
goto out;
} else {
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD | AX_SWRESET_PRL);
if (ret < 0)
goto out;
}
usb_osal_msleep(150);
ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
if (ret < 0)
goto out;
ret = usbh_asix_write_medium_mode(asix_class, AX88772_MEDIUM_DEFAULT);
if (ret < 0)
goto out;
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Write IPG,IPG1,IPG2 failed: %d\r\n", ret);
goto out;
}
/* Rewrite MAC address */
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_NODE_ID, 0, 0, asix_class->mac, ETH_ALEN);
if (ret < 0)
goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
if (ret < 0)
goto out;
rx_ctl = usbh_asix_read_rx_ctl(asix_class);
USB_LOG_INFO("RX_CTL is 0x%04x after all initializations\r\n",
rx_ctl);
rx_ctl = usbh_asix_read_medium_status(asix_class);
USB_LOG_INFO("Medium Status is 0x%04x after all initializations\r\n",
rx_ctl);
return 0;
out:
return ret;
}
static int usbh_ax88772a_hw_reset(struct usbh_asix *asix_class)
{
uint16_t rx_ctl, phy14h, phy15h, phy16h;
int ret;
ret = usbh_asix_write_gpio(asix_class, AX_GPIO_RSE, 5);
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, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Select PHY #1 failed: %d\r\n", ret);
goto out;
}
usb_osal_msleep(10);
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD | AX_SWRESET_IPRL);
if (ret < 0)
goto out;
usb_osal_msleep(10);
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL);
if (ret < 0)
goto out;
usb_osal_msleep(160);
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_CLEAR);
if (ret < 0)
goto out;
ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL);
if (ret < 0)
goto out;
usb_osal_msleep(200);
if (asix_class->chipcode == AX_AX88772B_CHIPCODE) {
ret = usbh_asix_write_cmd(asix_class, AX_QCTCTRL, 0x8000, 0x8001, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Write BQ setting failed: %d\r\n", ret);
goto out;
}
} else if (asix_class->chipcode == AX_AX88772A_CHIPCODE) {
/* Check if the PHY registers have default settings */
phy14h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
AX88772A_PHY14H);
phy15h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
AX88772A_PHY15H);
phy16h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
AX88772A_PHY16H);
USB_LOG_DBG("772a_hw_reset: MR20=0x%x MR21=0x%x MR22=0x%x\r\n",
phy14h, phy15h, phy16h);
/* Restore PHY registers default setting if not */
if (phy14h != AX88772A_PHY14H_DEFAULT)
usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
AX88772A_PHY14H,
AX88772A_PHY14H_DEFAULT);
if (phy15h != AX88772A_PHY15H_DEFAULT)
usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
AX88772A_PHY15H,
AX88772A_PHY15H_DEFAULT);
if (phy16h != AX88772A_PHY16H_DEFAULT)
usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
AX88772A_PHY16H,
AX88772A_PHY16H_DEFAULT);
}
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, NULL, 0);
if (ret < 0) {
USB_LOG_ERR("Write IPG,IPG1,IPG2 failed: %d\r\n", ret);
goto out;
}
/* Rewrite MAC address */
ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_NODE_ID, 0, 0, asix_class->mac, ETH_ALEN);
if (ret < 0)
goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
if (ret < 0)
goto out;
ret = usbh_asix_write_medium_mode(asix_class, AX88772_MEDIUM_DEFAULT);
if (ret < 0)
return ret;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
if (ret < 0)
goto out;
rx_ctl = usbh_asix_read_rx_ctl(asix_class);
USB_LOG_INFO("RX_CTL is 0x%04x after all initializations\r\n", rx_ctl);
rx_ctl = usbh_asix_read_medium_status(asix_class);
USB_LOG_INFO("Medium Status is 0x%04x after all initializations\r\n", rx_ctl);
return 0;
out:
return ret;
}
static void usbh_ax88772_mac_link_down(struct usbh_asix *asix_class)
{
usbh_asix_write_medium_mode(asix_class, 0);
}
static void usbh_ax88772_mac_link_up(struct usbh_asix *asix_class, int speed, int duplex, bool tx_pause, bool rx_pause)
{
uint16_t m = AX_MEDIUM_AC | AX_MEDIUM_RE;
m |= duplex ? AX_MEDIUM_FD : 0;
switch (speed) {
case SPEED_100:
m |= AX_MEDIUM_PS;
break;
case SPEED_10:
break;
default:
return;
}
if (tx_pause)
m |= AX_MEDIUM_TFC;
if (rx_pause)
m |= AX_MEDIUM_RFC;
usbh_asix_write_medium_mode(asix_class, m);
}
static int usbh_asix_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
struct usbh_asix *asix_class = &g_asix_class;
memset(asix_class, 0, sizeof(struct usbh_asix));
asix_class->hport = hport;
asix_class->intf = intf;
hport->config.intf[intf].priv = asix_class;
if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x772b)) {
asix_class->name = "ASIX AX88772B";
} else if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x7720)) {
asix_class->name = "ASIX AX88772";
} else if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x1780)) {
asix_class->name = "ASIX AX88178";
}
for (uint8_t i = 0; i < (ETH_ALEN >> 1); i++) {
ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_EEPROM,
0x04 + i, 0, &asix_class->mac[i * 2], 2);
if (ret < 0) {
return ret;
}
}
USB_LOG_INFO("asix MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
asix_class->mac[0],
asix_class->mac[1],
asix_class->mac[2],
asix_class->mac[3],
asix_class->mac[4],
asix_class->mac[5]);
ret = usbh_asix_read_phy_addr(asix_class, true);
if (ret < 0) {
USB_LOG_ERR("Failed to read phy addr: %d\r\n", ret);
return ret;
}
asix_class->phy_addr = ret;
asix_class->embd_phy = ((ret & 0x1f) == AX_EMBD_PHY_ADDR);
ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &asix_class->chipcode, 1);
if (ret < 0) {
USB_LOG_ERR("Failed to read STATMNGSTS_REG: %d\r\n", ret);
return ret;
}
asix_class->chipcode &= AX_CHIPCODE_MASK;
USB_LOG_INFO("asix chipcode 0x%x\r\n", asix_class->chipcode);
if (asix_class->chipcode == AX_AX88772_CHIPCODE) {
usbh_ax88772_hw_reset(asix_class);
} else {
usbh_ax88772a_hw_reset(asix_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) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(asix_class->intin, ep_desc);
} else {
return -USB_ERR_NOTSUPP;
}
} else {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(asix_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(asix_class->bulkout, ep_desc);
}
}
}
if (asix_class->chipcode == AX_AX88772B_CHIPCODE) {
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x8200);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3900);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3100);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 4);
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 4, 0x01e1);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 1);
usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3300);
usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
}
USB_LOG_INFO("Init %s done\r\n", asix_class->name);
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);
return ret;
}
static int usbh_asix_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_asix *asix_class = (struct usbh_asix *)hport->config.intf[intf].priv;
if (asix_class) {
if (asix_class->bulkin) {
usbh_kill_urb(&asix_class->bulkin_urb);
}
if (asix_class->bulkout) {
usbh_kill_urb(&asix_class->bulkout_urb);
}
if (asix_class->intin) {
usbh_kill_urb(&asix_class->intin_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister ASIX Class:%s\r\n", hport->config.intf[intf].devname);
usbh_asix_stop(asix_class);
}
memset(asix_class, 0, sizeof(struct usbh_asix));
}
return ret;
}
int usbh_asix_get_connect_status(struct usbh_asix *asix_class)
{
int ret;
usbh_int_urb_fill(&asix_class->intin_urb, asix_class->hport, asix_class->intin, g_asix_inttx_buffer, 8, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&asix_class->intin_urb);
if (ret < 0) {
return ret;
}
if (g_asix_inttx_buffer[1] == 0x00) {
if (g_asix_inttx_buffer[2] & 0x01) {
asix_class->connect_status = true;
usbh_ax88772_mac_link_up(asix_class, SPEED_100, 1, 1, 1);
usbh_asix_set_multicast(asix_class);
} else {
asix_class->connect_status = false;
usbh_ax88772_mac_link_down(asix_class);
}
}
return 0;
}
void usbh_asix_rx_thread(void *argument)
{
uint32_t g_asix_rx_length;
int ret;
uint16_t len;
uint16_t len_crc;
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)argument;
USB_LOG_INFO("Create asix rx thread\r\n");
// clang-format off
find_class:
// clang-format on
g_asix_class.connect_status = false;
if (usbh_find_class_instance("/dev/asix") == NULL) {
goto delete;
}
while (g_asix_class.connect_status == false) {
ret = usbh_asix_get_connect_status(&g_asix_class);
if (ret < 0) {
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], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_asix_class.bulkin_urb);
if (ret < 0) {
goto find_class;
}
g_asix_rx_length += g_asix_class.bulkin_urb.actual_length;
/* 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);
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);
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 {
#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
delete:
USB_LOG_INFO("Delete asix rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
uint8_t *usbh_asix_get_eth_txbuf(void)
{
return &g_asix_tx_buffer[4];
}
int usbh_asix_eth_output(uint32_t buflen)
{
uint16_t actual_len;
if (g_asix_class.connect_status == false) {
return -USB_ERR_NOTCONN;
}
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 (!(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", 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);
return usbh_submit_urb(&g_asix_class.bulkout_urb);
}
__WEAK void usbh_asix_run(struct usbh_asix *asix_class)
{
(void)asix_class;
}
__WEAK void usbh_asix_stop(struct usbh_asix *asix_class)
{
(void)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",
.connect = usbh_asix_connect,
.disconnect = usbh_asix_disconnect
};
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
};

177
class/vendor/net/usbh_asix.h vendored Normal file
View File

@@ -0,0 +1,177 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_ASIX_H
#define USBH_ASIX_H
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
#define AX_CMD_READ_MII_REG 0x07
#define AX_CMD_WRITE_MII_REG 0x08
#define AX_CMD_STATMNGSTS_REG 0x09
#define AX_CMD_SET_HW_MII 0x0a
#define AX_CMD_READ_EEPROM 0x0b
#define AX_CMD_WRITE_EEPROM 0x0c
#define AX_CMD_WRITE_ENABLE 0x0d
#define AX_CMD_WRITE_DISABLE 0x0e
#define AX_CMD_READ_RX_CTL 0x0f
#define AX_CMD_WRITE_RX_CTL 0x10
#define AX_CMD_READ_IPG012 0x11
#define AX_CMD_WRITE_IPG0 0x12
#define AX_CMD_WRITE_IPG1 0x13
#define AX_CMD_READ_NODE_ID 0x13
#define AX_CMD_WRITE_NODE_ID 0x14
#define AX_CMD_WRITE_IPG2 0x14
#define AX_CMD_WRITE_MULTI_FILTER 0x16
#define AX88172_CMD_READ_NODE_ID 0x17
#define AX_CMD_READ_PHY_ID 0x19
#define AX_CMD_READ_MEDIUM_STATUS 0x1a
#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
#define AX_CMD_READ_MONITOR_MODE 0x1c
#define AX_CMD_WRITE_MONITOR_MODE 0x1d
#define AX_CMD_READ_GPIOS 0x1e
#define AX_CMD_WRITE_GPIOS 0x1f
#define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22
#define AX_QCTCTRL 0x2A
#define AX_CHIPCODE_MASK 0x70
#define AX_AX88772_CHIPCODE 0x00
#define AX_AX88772A_CHIPCODE 0x10
#define AX_AX88772B_CHIPCODE 0x20
#define AX_HOST_EN 0x01
#define AX_PHYSEL_PSEL 0x01
#define AX_PHYSEL_SSMII 0
#define AX_PHYSEL_SSEN 0x10
#define AX_PHY_SELECT_MASK (BIT(3) | BIT(2))
#define AX_PHY_SELECT_INTERNAL 0
#define AX_PHY_SELECT_EXTERNAL BIT(2)
#define AX_MONITOR_MODE 0x01
#define AX_MONITOR_LINK 0x02
#define AX_MONITOR_MAGIC 0x04
#define AX_MONITOR_HSFS 0x10
/* AX88172 Medium Status Register values */
#define AX88172_MEDIUM_FD 0x02
#define AX88172_MEDIUM_TX 0x04
#define AX88172_MEDIUM_FC 0x10
#define AX88172_MEDIUM_DEFAULT \
(AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC)
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64
#define AX_SWRESET_CLEAR 0x00
#define AX_SWRESET_RR 0x01
#define AX_SWRESET_RT 0x02
#define AX_SWRESET_PRTE 0x04
#define AX_SWRESET_PRL 0x08
#define AX_SWRESET_BZ 0x10
#define AX_SWRESET_IPRL 0x20
#define AX_SWRESET_IPPD 0x40
#define AX88772_IPG0_DEFAULT 0x15
#define AX88772_IPG1_DEFAULT 0x0c
#define AX88772_IPG2_DEFAULT 0x12
/* AX88772 & AX88178 Medium Mode Register */
#define AX_MEDIUM_PF 0x0080
#define AX_MEDIUM_JFE 0x0040
#define AX_MEDIUM_TFC 0x0020
#define AX_MEDIUM_RFC 0x0010
#define AX_MEDIUM_ENCK 0x0008
#define AX_MEDIUM_AC 0x0004
#define AX_MEDIUM_FD 0x0002
#define AX_MEDIUM_GM 0x0001
#define AX_MEDIUM_SM 0x1000
#define AX_MEDIUM_SBP 0x0800
#define AX_MEDIUM_PS 0x0200
#define AX_MEDIUM_RE 0x0100
#define AX88178_MEDIUM_DEFAULT \
(AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
AX_MEDIUM_RE)
#define AX88772_MEDIUM_DEFAULT \
(AX_MEDIUM_FD | AX_MEDIUM_PS | \
AX_MEDIUM_AC | AX_MEDIUM_RE)
/* AX88772 & AX88178 RX_CTL values */
#define AX_RX_CTL_SO 0x0080
#define AX_RX_CTL_AP 0x0020
#define AX_RX_CTL_AM 0x0010
#define AX_RX_CTL_AB 0x0008
#define AX_RX_CTL_SEP 0x0004
#define AX_RX_CTL_AMALL 0x0002
#define AX_RX_CTL_PRO 0x0001
#define AX_RX_CTL_MFB_2048 0x0000
#define AX_RX_CTL_MFB_4096 0x0100
#define AX_RX_CTL_MFB_8192 0x0200
#define AX_RX_CTL_MFB_16384 0x0300
#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB)
/* GPIO 0 .. 2 toggles */
#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
#define AX_GPIO_RESERVED 0x40 /* Reserved */
#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
#define AX_EEPROM_MAGIC 0xdeadbeef
#define AX_EEPROM_LEN 0x200
#define AX_EMBD_PHY_ADDR 0x10
struct usbh_asix {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct usbh_urb intin_urb;
uint8_t intf;
char *name;
uint8_t phy_addr;
uint8_t embd_phy;
uint8_t chipcode;
uint16_t mac_capabilities;
bool connect_status;
uint8_t mac[6];
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
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);
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(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* USBH_ASIX_H */

2280
class/vendor/net/usbh_rtl8152.c vendored Normal file

File diff suppressed because it is too large Load Diff

68
class/vendor/net/usbh_rtl8152.h vendored Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_RTL8152_H
#define USBH_RTL8152_H
struct usbh_rtl8152 {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct usbh_urb intin_urb;
uint8_t intf;
uint8_t mac[6];
bool connect_status;
uint32_t speed[2];
uint8_t version;
uint8_t eee_adv;
uint8_t eee_en;
uint8_t supports_gmii;
uint16_t min_mtu;
uint16_t max_mtu;
uint16_t ocp_base;
uint32_t saved_wolopts;
uint32_t rx_buf_sz;
struct rtl_ops {
void (*init)(struct usbh_rtl8152 *tp);
int (*enable)(struct usbh_rtl8152 *tp);
void (*disable)(struct usbh_rtl8152 *tp);
void (*up)(struct usbh_rtl8152 *tp);
void (*down)(struct usbh_rtl8152 *tp);
void (*unload)(struct usbh_rtl8152 *tp);
bool (*in_nway)(struct usbh_rtl8152 *tp);
void (*hw_phy_cfg)(struct usbh_rtl8152 *tp);
void (*autosuspend_en)(struct usbh_rtl8152 *tp, bool enable);
void (*change_mtu)(struct usbh_rtl8152 *tp);
} rtl_ops;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
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);
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(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* USBH_RTL8152_H */

378
class/vendor/serial/usbh_ch34x.c vendored Normal file
View File

@@ -0,0 +1,378 @@
/*
* 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)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << 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)
{
uint8_t devno = ch34x_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << 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;
int ret;
if (!ch34x_class || !ch34x_class->hport) {
return -USB_ERR_INVAL;
}
setup = ch34x_class->hport->setup;
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;
if (!ch34x_class || !ch34x_class->hport) {
return -USB_ERR_INVAL;
}
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;
uint16_t reg_value = 0;
uint16_t value = 0;
uint8_t factor = 0;
uint8_t divisor = 0;
if (!ch34x_class || !ch34x_class->hport) {
return -USB_ERR_INVAL;
}
setup = ch34x_class->hport->setup;
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;
if (!ch34x_class || !ch34x_class->hport) {
return -USB_ERR_INVAL;
}
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)
{
(void)ch34x_class;
}
__WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class)
{
(void)ch34x_class;
}
static const uint16_t ch34x_id_table[][2] = {
{ 0x1A86, 0x7523 },
{ 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
};

76
class/vendor/serial/usbh_ch34x.h vendored Normal file
View File

@@ -0,0 +1,76 @@
/*
* 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;
void *user_data;
};
#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 */

327
class/vendor/serial/usbh_cp210x.c vendored Normal file
View File

@@ -0,0 +1,327 @@
/*
* 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 1
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)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << 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)
{
uint8_t devno = cp210x_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
}
static int usbh_cp210x_enable(struct usbh_cp210x *cp210x_class)
{
struct usb_setup_packet *setup;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
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;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
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;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
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;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
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;
uint16_t value;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
setup = cp210x_class->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 = 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;
uint16_t value;
if (!cp210x_class || !cp210x_class->hport) {
return -USB_ERR_INVAL;
}
setup = cp210x_class->hport->setup;
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)
{
(void)cp210x_class;
}
__WEAK void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class)
{
(void)cp210x_class;
}
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
};

73
class/vendor/serial/usbh_cp210x.h vendored Normal file
View File

@@ -0,0 +1,73 @@
/*
* 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;
void *user_data;
};
#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 */

400
class/vendor/serial/usbh_ftdi.c vendored Normal file
View File

@@ -0,0 +1,400 @@
/*
* 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 1
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)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_FTDI_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << 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)
{
uint8_t devno = ftdi_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << 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 (uint8_t 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;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
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;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
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;
uint32_t itdf_divisor;
uint16_t value;
uint8_t baudrate_high;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
setup = ftdi_class->hport->setup;
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
**/
struct usb_setup_packet *setup;
uint16_t value;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
setup = ftdi_class->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 = 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;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
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;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
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;
int ret;
if (!ftdi_class || !ftdi_class->hport) {
return -USB_ERR_INVAL;
}
setup = ftdi_class->hport->setup;
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)
{
(void)ftdi_class;
}
__WEAK void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class)
{
(void)ftdi_class;
}
static const uint16_t ftdi_id_table[][2] = {
{ 0x0403, 0x6001 },
{ 0x0403, 0x6010 },
{ 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
};

76
class/vendor/serial/usbh_ftdi.h vendored Normal file
View File

@@ -0,0 +1,76 @@
/*
* 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];
void *user_data;
};
#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 */

448
class/vendor/serial/usbh_pl2303.c vendored Normal file
View File

@@ -0,0 +1,448 @@
/*
* Copyright (c) 2024, sakumisu
* Copyright (c) 2024, Derek Konigsberg
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_pl2303.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_pl2303"
#include "usb_log.h"
#define DEV_FORMAT "/dev/ttyUSB%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_pl2303_buf[64];
#define CONFIG_USBHOST_MAX_PL2303_CLASS 1
#define UT_WRITE_VENDOR_DEVICE (USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
#define UT_READ_VENDOR_DEVICE (USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
static struct usbh_pl2303 g_pl2303_class[CONFIG_USBHOST_MAX_PL2303_CLASS];
static uint32_t g_devinuse = 0;
static struct usbh_pl2303 *usbh_pl2303_class_alloc(void)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_PL2303_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_pl2303_class[devno], 0, sizeof(struct usbh_pl2303));
g_pl2303_class[devno].minor = devno;
return &g_pl2303_class[devno];
}
}
return NULL;
}
static void usbh_pl2303_class_free(struct usbh_pl2303 *pl2303_class)
{
uint8_t devno = pl2303_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(pl2303_class, 0, sizeof(struct usbh_pl2303));
}
static int usbh_pl2303_get_chiptype(struct usbh_pl2303 *pl2303_class)
{
int ret = 0;
switch (pl2303_class->hport->device_desc.bcdDevice) {
case 0x0300:
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
/* or TA, that is HX with external crystal */
break;
case 0x0400:
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
/* or EA, that is HXD with ESD protection */
/* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
break;
case 0x0500:
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
/* in fact it's TB, that is HXD with external crystal */
break;
default:
/* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
/* Determine the chip type. This algorithm is taken from Linux. */
if (pl2303_class->hport->device_desc.bDeviceClass == 0x02) {
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
} else if (pl2303_class->hport->device_desc.bMaxPacketSize0 == 0x40) {
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
} else {
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
}
break;
}
/*
* The new chip revision PL2303HXN is only compatible with the new
* PLCOM_SET_REQUEST_PL2303HXN command. Issuing the old command
* PLCOM_SET_REQUEST to the new chip raises an error. Thus, PL2303HX
* and PL2303HXN can be distinguished by issuing an old-style request
* (on a status register) to the new chip and checking the error.
*/
if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX) {
struct usb_setup_packet *setup = pl2303_class->hport->setup;
setup->bmRequestType = UT_READ_VENDOR_DEVICE;
setup->bRequest = PL2303_SET_REQUEST;
setup->wValue = PL2303_STATUS_REG_PL2303HX;
setup->wIndex = 0;
setup->wLength = 1;
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
if (ret == -USB_ERR_STALL) {
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXN;
ret = 0;
} else if (ret < 0) {
USB_LOG_WRN("Error checking chip type: %d\r\n", ret);
return ret;
}
}
switch (pl2303_class->chiptype) {
case USBH_PL2303_TYPE_PL2303:
USB_LOG_INFO("chiptype = 2303\r\n");
break;
case USBH_PL2303_TYPE_PL2303HX:
USB_LOG_INFO("chiptype = 2303HX/TA\r\n");
break;
case USBH_PL2303_TYPE_PL2303HXN:
USB_LOG_INFO("chiptype = 2303HXN\r\n");
break;
case USBH_PL2303_TYPE_PL2303HXD:
USB_LOG_INFO("chiptype = 2303HXD/TB/RA/EA\r\n");
break;
default:
USB_LOG_INFO("chiptype = [%d]\r\n", pl2303_class->chiptype);
break;
}
return ret;
}
static int usbh_pl2303_do(struct usbh_pl2303 *pl2303_class,
uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
uint16_t length)
{
struct usb_setup_packet *setup;
if (!pl2303_class || !pl2303_class->hport) {
return -USB_ERR_INVAL;
}
setup = pl2303_class->hport->setup;
setup->bmRequestType = req_type;
setup->bRequest = request;
setup->wValue = value;
setup->wIndex = index;
setup->wLength = length;
return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
}
int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
if (!pl2303_class || !pl2303_class->hport) {
return -USB_ERR_INVAL;
}
setup = pl2303_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 = pl2303_class->intf;
setup->wLength = 7;
memcpy(g_pl2303_buf, line_coding, sizeof(struct cdc_line_coding));
return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
}
int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
{
struct usb_setup_packet *setup;
int ret;
if (!pl2303_class || !pl2303_class->hport) {
return -USB_ERR_INVAL;
}
setup = pl2303_class->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 = pl2303_class->intf;
setup->wLength = 7;
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
if (ret < 0) {
return ret;
}
memcpy(line_coding, g_pl2303_buf, sizeof(struct cdc_line_coding));
return ret;
}
int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts)
{
struct usb_setup_packet *setup;
if (!pl2303_class || !pl2303_class->hport) {
return -USB_ERR_INVAL;
}
setup = pl2303_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 = pl2303_class->intf;
setup->wLength = 0;
return usbh_control_transfer(pl2303_class->hport, setup, NULL);
}
static int usbh_pl2303_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_pl2303 *pl2303_class = usbh_pl2303_class_alloc();
if (pl2303_class == NULL) {
USB_LOG_ERR("Fail to alloc pl2303_class\r\n");
return -USB_ERR_NOMEM;
}
pl2303_class->hport = hport;
pl2303_class->intf = intf;
hport->config.intf[intf].priv = pl2303_class;
do {
ret = usbh_pl2303_get_chiptype(pl2303_class);
if (ret < 0) {
break;
}
/* Startup reset sequence, if necessary for the chip type */
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
struct usb_setup_packet *setup = pl2303_class->hport->setup;
setup->bmRequestType = UT_WRITE_VENDOR_DEVICE;
setup->bRequest = PL2303_SET_REQUEST;
setup->wValue = 0;
setup->wIndex = pl2303_class->intf;
setup->wLength = 0;
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
if (ret < 0) {
USB_LOG_WRN("Initialization reset failed: %d\r\n", ret);
break;
}
}
if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303) {
/* HX variants seem to lock up after a clear stall request. */
/*
* The FreeBSD code sets the stall flags on the in and out pipes
* here. Have no idea exactly how to do this, or if it is necessary.
* May just leave this code unwritten until test hardware is available.
*/
} else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX || pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXD) {
/* Reset upstream data pipes */
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 8, 0, 0);
if (ret < 0) {
USB_LOG_WRN("Could not reset upstream data pipes (8,0): %d\r\n", ret);
break;
}
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 9, 0, 0);
if (ret < 0) {
USB_LOG_WRN("Could not reset upstream data pipes (9,0): %d\r\n", ret);
break;
}
} else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXN) {
/* Reset upstream data pipes */
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST_PL2303HXN, 0x07, 0x03, 0);
if (ret < 0) {
USB_LOG_WRN("Could not reset upstream data pipes (7,3): %d\r\n", ret);
break;
}
}
/* Final device initialization, if necessary for the chip type */
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
if (usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 0, 0) < 0 ||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 1, 0) < 0 ||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0, 1, 0) < 0 ||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 1, 0, 0) < 0) {
USB_LOG_WRN("Could not complete init sequence\r\n");
ret = -USB_ERR_INVAL;
break;
}
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303) {
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x44, 0);
} else {
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x24, 0);
}
if (ret < 0) {
USB_LOG_WRN("Could not complete final init request: %d\r\n", ret);
break;
}
}
} while (0);
if (ret < 0) {
USB_LOG_ERR("Failed to initialize PL2303 device: %d\r\n", ret);
return ret;
}
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(pl2303_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(pl2303_class->bulkout, ep_desc);
}
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, pl2303_class->minor);
USB_LOG_INFO("Register PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
#if 0
USB_LOG_INFO("Test pl2303 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_pl2303_set_line_coding(pl2303_class, &linecoding);
usbh_pl2303_set_line_state(pl2303_class, true, false);
memset(g_pl2303_buf, 'a', sizeof(g_pl2303_buf));
ret = usbh_pl2303_bulk_out_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_buf), 0xfffffff);
USB_LOG_RAW("out ret:%d\r\n", ret);
while (count--) {
ret = usbh_pl2303_bulk_in_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_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_pl2303_buf[i]);
}
}
USB_LOG_RAW("\r\n");
}
#endif
usbh_pl2303_run(pl2303_class);
return ret;
}
static int usbh_pl2303_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_pl2303 *pl2303_class = (struct usbh_pl2303 *)hport->config.intf[intf].priv;
if (pl2303_class) {
if (pl2303_class->bulkin) {
usbh_kill_urb(&pl2303_class->bulkin_urb);
}
if (pl2303_class->bulkout) {
usbh_kill_urb(&pl2303_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
usbh_pl2303_stop(pl2303_class);
}
usbh_pl2303_class_free(pl2303_class);
}
return ret;
}
int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &pl2303_class->bulkin_urb;
usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &pl2303_class->bulkout_urb;
usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
__WEAK void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class)
{
(void)pl2303_class;
}
__WEAK void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class)
{
(void)pl2303_class;
}
static const uint16_t pl2303_id_table[][2] = {
{ 0x067B, 0x2303 }, // PL2303 Serial (ATEN/IOGEAR UC232A)
{ 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
};

62
class/vendor/serial/usbh_pl2303.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_PL2303_H
#define USBH_PL2303_H
#include "usb_cdc.h"
#define PL2303_SET_REQUEST 0x01
#define PL2303_SET_REQUEST_PL2303HXN 0x80
#define PL2303_SET_CRTSCTS 0x41
#define PL2303_SET_CRTSCTS_PL2303X 0x61
#define PL2303_SET_CRTSCTS_PL2303HXN 0xFA
#define PL2303_CLEAR_CRTSCTS_PL2303HXN 0xFF
#define PL2303_CRTSCTS_REG_PL2303HXN 0x0A
#define PL2303_STATUS_REG_PL2303HX 0x8080
/* Different PL2303 IC types */
#define USBH_PL2303_TYPE_UNKNOWN 0
#define USBH_PL2303_TYPE_PL2303 1
#define USBH_PL2303_TYPE_PL2303HX 2
#define USBH_PL2303_TYPE_PL2303HXD 3
#define USBH_PL2303_TYPE_PL2303HXN 4
struct usbh_pl2303 {
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 linecoding;
uint8_t intf;
uint8_t minor;
uint8_t chiptype;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts);
int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class);
void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_PL2303_H */

6
class/vendor/wifi/README.md vendored Normal file
View File

@@ -0,0 +1,6 @@
# BL616 USB WIFI
Usbwifi firmware please contact bouffalolab. You can purchase a module in the following ways:
- https://iot.mi.com/moduleBrowser.html
- https://docs.ai-thinker.com/ai_m61

512
class/vendor/wifi/usbh_bl616.c vendored Normal file
View File

@@ -0,0 +1,512 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_bl616.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_bl616"
#include "usb_log.h"
#define DEV_FORMAT "/dev/wifi/bl616"
#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define ARR_ELE_6(e) (e)[0], (e)[1], (e)[2], (e)[3], (e)[4], (e)[5]
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_tx_buffer[2048 + 512];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_rx_buffer[2048 + 512];
static struct usbh_bl616 g_bl616_class;
static const char *auth_to_str(uint8_t auth)
{
const char *table[RNM_WIFI_AUTH_MAX] = {
[RNM_WIFI_AUTH_UNKNOWN] = "UNKNOWN",
[RNM_WIFI_AUTH_OPEN] = "OPEN",
[RNM_WIFI_AUTH_WEP] = "WEP",
[RNM_WIFI_AUTH_WPA_PSK] = "WPA-PSK",
[RNM_WIFI_AUTH_WPA2_PSK] = "WPA2-PSK",
[RNM_WIFI_AUTH_WPA_WPA2_PSK] = "WPA2-PSK/WPA-PSK",
[RNM_WIFI_AUTH_WPA_ENTERPRISE] = "WPA-ENT",
[RNM_WIFI_AUTH_WPA3_SAE] = "WPA3-SAE",
[RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE] = "WPA2-PSK/WPA3-SAE",
};
if (auth < RNM_WIFI_AUTH_MAX)
return table[auth];
else
return table[RNM_WIFI_AUTH_UNKNOWN];
}
static const char *cipher_to_str(uint8_t cipher)
{
const char *table[RNM_WIFI_CIPHER_MAX] = {
[RNM_WIFI_CIPHER_UNKNOWN] = "UNKNOWN",
[RNM_WIFI_CIPHER_NONE] = "NONE",
[RNM_WIFI_CIPHER_WEP] = "WEP",
[RNM_WIFI_CIPHER_AES] = "AES",
[RNM_WIFI_CIPHER_TKIP] = "TKIP",
[RNM_WIFI_CIPHER_TKIP_AES] = "TKIP/AES",
};
if (cipher < RNM_WIFI_CIPHER_MAX)
return table[cipher];
else
return table[RNM_WIFI_CIPHER_UNKNOWN];
}
static int parse_get_mac_rsp_msg(struct usbh_bl616 *bl616_class, void *buf, int buf_len)
{
usb_data_t *usb_hdr = buf;
rnm_mac_addr_ind_msg_t *rsp = buf + sizeof(usb_data_t);
if (buf_len != sizeof(usb_data_t) + sizeof(rnm_mac_addr_ind_msg_t)) {
return -1;
}
if (usb_hdr->type != USBWIFI_DATA_TYPE_CMD || usb_hdr->length != sizeof(rnm_mac_addr_ind_msg_t)) {
return -1;
}
if (rsp->hdr.cmd != BFLB_CMD_GET_MAC_ADDR || !(rsp->hdr.flags & RNM_MSG_FLAG_ACK)) {
return -1;
}
memcpy(bl616_class->sta_mac, rsp->sta_mac, 6);
memcpy(bl616_class->ap_mac, rsp->ap_mac, 6);
return 0;
}
static int usbh_bl616_bulk_in_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &bl616_class->bulkin_urb;
usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
static int usbh_bl616_bulk_out_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &bl616_class->bulkout_urb;
usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
static int usbh_bl616_get_wifi_mac(struct usbh_bl616 *bl616_class)
{
int ret;
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *rnm_msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(rnm_msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
rnm_msg->cmd = BFLB_CMD_GET_MAC_ADDR;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
ret = usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
if (ret < 0) {
return ret;
}
ret = usbh_bl616_bulk_in_transfer(bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), 500);
if (ret < 0) {
return ret;
}
ret = parse_get_mac_rsp_msg(bl616_class, g_bl616_rx_buffer, ret);
return ret;
}
static int usbh_bl616_wifi_open(struct usbh_bl616 *bl616_class)
{
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->cmd = BFLB_CMD_HELLO;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
}
static int usbh_bl616_wifi_close(struct usbh_bl616 *bl616_class)
{
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->cmd = BFLB_CMD_UNLOAD_DRV;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
}
int usbh_bl616_wifi_sta_connect(const char *ssid,
const int ssid_len,
const char *password,
const int pwd_len)
{
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_sta_connect_msg_t *msg = (rnm_sta_connect_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_sta_connect_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_sta_connect_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->hdr.cmd = BFLB_CMD_STA_CONNECT;
msg->hdr.msg_id = 0x0001;
msg->hdr.session_id = 0x0002;
msg->ssid_len = ssid_len;
memcpy(msg->ssid, ssid, ssid_len);
if (password) {
memcpy(msg->password, password, pwd_len);
}
msg_len = sizeof(usb_data_t) + sizeof(rnm_sta_connect_msg_t);
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
}
int usbh_bl616_wifi_sta_disconnect(void)
{
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->cmd = BFLB_CMD_STA_DISCONNECT;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
}
int usbh_bl616_get_wifi_scan_result(void)
{
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->cmd = BFLB_CMD_SCAN_RESULTS;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
}
int usbh_bl616_wifi_scan(void)
{
int ret;
uint32_t msg_len;
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
memset(usb_hdr, 0, sizeof(usb_data_t));
memset(msg, 0, sizeof(rnm_base_msg_t));
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
usb_hdr->length = sizeof(rnm_base_msg_t);
usb_hdr->payload_offset = sizeof(usb_data_t);
msg->cmd = BFLB_CMD_SCAN;
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
ret = usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
if (ret < 0) {
return ret;
}
usb_osal_msleep(500);
return usbh_bl616_get_wifi_scan_result();
}
static int usbh_bl616_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_bl616 *bl616_class = &g_bl616_class;
memset(bl616_class, 0, sizeof(struct usbh_bl616));
bl616_class->hport = hport;
bl616_class->intf = intf;
hport->config.intf[intf].priv = bl616_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(bl616_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(bl616_class->bulkout, ep_desc);
}
}
usbh_bl616_get_wifi_mac(bl616_class);
usbh_bl616_wifi_close(bl616_class);
usbh_bl616_wifi_open(bl616_class);
USB_LOG_INFO("BL616 WIFI STA MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
bl616_class->sta_mac[0],
bl616_class->sta_mac[1],
bl616_class->sta_mac[2],
bl616_class->sta_mac[3],
bl616_class->sta_mac[4],
bl616_class->sta_mac[5]);
USB_LOG_INFO("BL616 WIFI AP MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
bl616_class->ap_mac[0],
bl616_class->ap_mac[1],
bl616_class->ap_mac[2],
bl616_class->ap_mac[3],
bl616_class->ap_mac[4],
bl616_class->ap_mac[5]);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bl616_run(bl616_class);
return ret;
}
static int usbh_bl616_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_bl616 *bl616_class = (struct usbh_bl616 *)hport->config.intf[intf].priv;
if (bl616_class) {
if (bl616_class->bulkin) {
usbh_kill_urb(&bl616_class->bulkin_urb);
}
if (bl616_class->bulkout) {
usbh_kill_urb(&bl616_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bl616_stop(bl616_class);
}
memset(bl616_class, 0, sizeof(struct usbh_bl616));
}
return ret;
}
void usbh_bl616_rx_thread(void *argument)
{
int ret;
usb_data_t *usb_hdr;
rnm_base_msg_t *msg;
rnm_sta_ip_update_ind_msg_t *ipmsg;
rnm_scan_ind_msg_t *scanmsg;
uint8_t *data;
(void)argument;
USB_LOG_INFO("Create bl616 wifi rx thread\r\n");
while (1) {
ret = usbh_bl616_bulk_in_transfer(&g_bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
break;
}
usb_hdr = (usb_data_t *)g_bl616_rx_buffer;
if (usb_hdr->type == USBWIFI_DATA_TYPE_CMD) {
msg = (rnm_base_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
switch (msg->cmd) {
case BFLB_CMD_STA_CONNECTED_IND:
USB_LOG_INFO("AP connected\n");
g_bl616_class.connect_status = true;
usbh_bl616_sta_connect_callback();
break;
case BFLB_CMD_STA_DISCONNECTED_IND:
if (g_bl616_class.connect_status == true) {
g_bl616_class.connect_status = false;
USB_LOG_INFO("AP disconnected\n");
usbh_bl616_sta_disconnect_callback();
}
break;
case BFLB_CMD_STA_IP_UPDATE_IND:
ipmsg = (rnm_sta_ip_update_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
USB_LOG_INFO("WIFI IP update\r\n");
USB_LOG_INFO("WIFI IPv4 Address : %d:%d:%d:%d\r\n",
ipmsg->ip4_addr[0],
ipmsg->ip4_addr[1],
ipmsg->ip4_addr[2],
ipmsg->ip4_addr[3]);
USB_LOG_INFO("WIFI IPv4 Mask : %d:%d:%d:%d\r\n",
ipmsg->ip4_mask[0],
ipmsg->ip4_mask[1],
ipmsg->ip4_mask[2],
ipmsg->ip4_mask[3]);
USB_LOG_INFO("WIFI IPv4 Gateway : %d:%d:%d:%d\r\n\r\n",
ipmsg->ip4_gw[0],
ipmsg->ip4_gw[1],
ipmsg->ip4_gw[2],
ipmsg->ip4_gw[3]);
g_bl616_class.mode = BL_MODE_STA;
usbh_bl616_sta_update_ip(ipmsg->ip4_addr, ipmsg->ip4_mask, ipmsg->ip4_gw);
break;
case BFLB_CMD_SCAN_RESULTS:
scanmsg = (rnm_scan_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
USB_LOG_INFO("WIFI scan result:\r\n");
for (uint32_t i = 0; i < scanmsg->num; ++i) {
struct bf1b_wifi_scan_record *r = &scanmsg->records[i];
USB_LOG_INFO("BSSID " MAC_FMT ", channel %u, rssi %d, auth %s, cipher %s, SSID %s\r\n",
ARR_ELE_6(r->bssid), r->channel, r->rssi,
auth_to_str(r->auth_mode), cipher_to_str(r->cipher), r->ssid);
}
break;
default:
break;
}
} else if (usb_hdr->type == USBWIFI_DATA_TYPE_PKT) {
data = (uint8_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
usbh_bl616_eth_input(data, usb_hdr->length);
} else {
}
}
USB_LOG_INFO("Delete bl616 wifi rx thread\r\n");
usb_osal_thread_delete(NULL);
}
uint8_t *usbh_bl616_get_eth_txbuf(void)
{
return (g_bl616_tx_buffer + sizeof(usb_data_t));
}
int usbh_bl616_eth_output(uint32_t buflen)
{
usb_data_t *usb_hdr;
uint32_t txlen;
if (g_bl616_class.connect_status == false) {
return -USB_ERR_NOTCONN;
}
usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
memset(usb_hdr, 0, sizeof(usb_data_t));
usb_hdr->type = USBWIFI_DATA_TYPE_PKT;
usb_hdr->length = buflen;
usb_hdr->payload_offset = sizeof(usb_data_t);
txlen = buflen + sizeof(usb_data_t);
if (!(txlen % USB_GET_MAXPACKETSIZE(g_bl616_class.bulkout->wMaxPacketSize))) {
txlen += 1;
}
USB_LOG_DBG("txlen:%d\r\n", txlen);
usbh_bulk_urb_fill(&g_bl616_class.bulkout_urb, g_bl616_class.hport, g_bl616_class.bulkout, g_bl616_tx_buffer, txlen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
return usbh_submit_urb(&g_bl616_class.bulkout_urb);
}
int wifi_sta_connect(int argc, char **argv)
{
if (argc < 3) {
USB_LOG_ERR("Usage: %s <ssid> <password>\r\n", argv[0]);
return -1;
}
usbh_bl616_wifi_sta_connect(argv[1], strlen(argv[1]), argv[2], strlen(argv[2]));
return 0;
}
int wifi_scan(int argc, char **argv)
{
(void)argc;
(void)argv;
usbh_bl616_wifi_scan();
return 0;
}
__WEAK void usbh_bl616_run(struct usbh_bl616 *bl616_class)
{
(void)bl616_class;
}
__WEAK void usbh_bl616_stop(struct usbh_bl616 *bl616_class)
{
(void)bl616_class;
}
static const uint16_t bl616_id_table[][2] = {
{ 0x349b, 0x616f },
{ 0, 0 },
};
static const struct usbh_class_driver bl616_class_driver = {
.driver_name = "bl616_wifi",
.connect = usbh_bl616_connect,
.disconnect = usbh_bl616_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info bl616_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.id_table = bl616_id_table,
.class_driver = &bl616_class_driver
};

220
class/vendor/wifi/usbh_bl616.h vendored Normal file
View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_BL616_H
#define USBH_BL616_H
#define USBWIFI_DATA_TYPE_CMD 0xA55A
#define USBWIFI_DATA_TYPE_PKT 0x6996
#define USB_DATA_FLAG_AP_PKT (1u << 0)
typedef enum {
BFLB_CMD_REBOOT = 0,
BFLB_CMD_RESET,
BFLB_CMD_HELLO,
BFLB_CMD_PING,
BFLB_CMD_GET_MAC_ADDR,
// Scan
BFLB_CMD_SCAN,
BFLB_CMD_SCAN_RESULTS,
// STA
BFLB_CMD_STA_CONNECT,
BFLB_CMD_STA_DISCONNECT,
BFLB_CMD_STA_CONNECTED_IND,
BFLB_CMD_STA_DISCONNECTED_IND,
BFLB_CMD_STA_IP_UPDATE_IND,
BFLB_CMD_STA_SET_AUTO_RECONNECT,
BFLB_CMD_STA_GET_LINK_STATUS,
// AP
BFLB_CMD_AP_START,
BFLB_CMD_AP_STOP,
BFLB_CMD_AP_STARTED_IND,
BFLB_CMD_AP_STOPPED_IND,
BFLB_CMD_AP_GET_STA_LIST,
// Monitor
BFLB_CMD_MONITOR_START,
BFLB_CMD_MONITOR_STOP,
BFLB_CMD_MONITOR_SET_CHANNEL,
BFLB_CMD_MONITOR_GET_CHANNEL,
BFLB_CMD_SET_LPM_MODE,
// OTA
BFLB_CMD_GET_DEV_VERSION,
BFLB_CMD_OTA,
BFLB_CMD_EXT,
BFLB_CMD_USER_EXT,
BFLB_CMD_UNLOAD_DRV,
BFLB_CMD_MAX,
} bflb_cmd_t;
typedef enum {
STATUS_OK,
STATUS_NOMEM = 128,
STATUS_INVALID_INPUT,
STATUS_INVALID_MODE,
STATUS_ERR_UNSPECIFIED,
STATUS_NOT_IMPLEMENTED,
} cmd_status_t;
typedef enum {
RNM_WIFI_AUTH_UNKNOWN = 0,
RNM_WIFI_AUTH_OPEN,
RNM_WIFI_AUTH_WEP,
RNM_WIFI_AUTH_WPA_PSK,
RNM_WIFI_AUTH_WPA2_PSK,
RNM_WIFI_AUTH_WPA_WPA2_PSK,
RNM_WIFI_AUTH_WPA_ENTERPRISE,
RNM_WIFI_AUTH_WPA3_SAE,
RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE,
RNM_WIFI_AUTH_MAX,
} rnm_wifi_auth_mode_t;
typedef enum {
RNM_WIFI_CIPHER_UNKNOWN = 0,
RNM_WIFI_CIPHER_NONE,
RNM_WIFI_CIPHER_WEP,
RNM_WIFI_CIPHER_AES,
RNM_WIFI_CIPHER_TKIP,
RNM_WIFI_CIPHER_TKIP_AES,
RNM_WIFI_CIPHER_MAX,
} rnm_wifi_cipher_t;
/* common header */
typedef struct {
uint16_t cmd;
// flag ACK is used by server to indicate a response to client
#define RNM_MSG_FLAG_ACK (1 << 0)
// flag TRANSPARENT is never transfered to peer but used locally
#define RNM_MSG_FLAG_TRANSPARENT (1 << 1)
// flag ASYNC is used by server to notify client events such as STA_CONNECTED
#define RNM_MSG_FLAG_ASYNC (1 << 2)
uint16_t flags;
uint16_t status;
uint16_t msg_id;
uint16_t session_id;
uint16_t msg_id_replying;
} rnm_base_msg_t;
typedef struct {
rnm_base_msg_t hdr;
} rnm_ack_msg_t;
typedef struct {
rnm_base_msg_t hdr;
uint8_t sta_mac[6];
uint8_t ap_mac[6];
} rnm_mac_addr_ind_msg_t;
typedef struct {
rnm_base_msg_t hdr;
uint16_t ssid_len;
uint8_t ssid[32];
uint8_t password[64];
} rnm_sta_connect_msg_t;
typedef struct {
rnm_base_msg_t hdr;
uint8_t ip4_addr[4];
uint8_t ip4_mask[4];
uint8_t ip4_gw[4];
uint8_t ip4_dns1[4];
uint8_t ip4_dns2[4];
uint8_t gw_mac[6];
} rnm_sta_ip_update_ind_msg_t;
struct bf1b_wifi_scan_record {
uint8_t bssid[6];
// TODO use compressed SSID encoding to save room
uint8_t ssid[32 + 1];
uint16_t channel;
int8_t rssi;
uint8_t auth_mode;
uint8_t cipher;
} __PACKED;
typedef struct {
rnm_base_msg_t hdr;
uint16_t num;
struct bf1b_wifi_scan_record records[];
} rnm_scan_ind_msg_t;
typedef enum {
BL_MODE_NONE,
BL_MODE_STA, // card is STA
BL_MODE_AP, // card is AP
BL_MODE_STA_AP, // card is STA&AP
BL_MODE_SNIFFER, // card is sniffer
BL_MODE_MAX,
} bl_wifi_mode_t;
typedef struct {
uint16_t type;
uint16_t length;
uint16_t flags;
uint16_t payload_offset;
uint32_t rsvd[8];
uint8_t payload[];
} __attribute__((aligned(4))) usb_data_t;
struct usbh_bl616 {
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 sta_mac[6];
uint8_t ap_mac[6];
uint8_t mode;
bool connect_status;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_bl616_wifi_sta_connect(const char *ssid,
const int ssid_len,
const char *password,
const int pwd_len);
int usbh_bl616_wifi_sta_disconnect(void);
int usbh_bl616_wifi_scan(void);
void usbh_bl616_sta_connect_callback(void);
void usbh_bl616_sta_disconnect_callback(void);
void usbh_bl616_sta_update_ip(uint8_t ip4_addr[4], uint8_t ip4_mask[4], uint8_t ip4_gw[4]);
uint8_t *usbh_bl616_get_eth_txbuf(void);
int usbh_bl616_eth_output(uint32_t buflen);
void usbh_bl616_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_bl616_rx_thread(void *argument);
void usbh_bl616_run(struct usbh_bl616 *bl616_class);
void usbh_bl616_stop(struct usbh_bl616 *bl616_class);
int wifi_sta_connect(int argc, char **argv);
int wifi_scan(int argc, char **argv);
#ifdef __cplusplus
}
#endif
#endif /* USBH_BL616_H */

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

@@ -0,0 +1,228 @@
/*
* 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_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,74 +1095,145 @@ 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 */ \
@@ -1118,21 +1243,37 @@ struct video_autoexposure_mode {
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,13 +1302,13 @@ 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 */ \
@@ -1181,7 +1322,7 @@ struct video_autoexposure_mode {
#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,28 @@ struct usbd_video_priv {
uint8_t power_mode;
uint8_t error_code;
struct video_entity_info info[3];
} g_usbd_video;
uint8_t *ep_buf0;
uint8_t *ep_buf1;
bool ep_buf0_ready;
bool ep_buf1_ready;
uint32_t ep_buf0_len;
uint32_t ep_buf1_len;
uint8_t ep_buf_idx;
bool stream_finish;
uint32_t max_packets;
uint8_t *stream_buf;
uint32_t stream_len;
uint32_t stream_offset;
uint8_t stream_frameid;
uint32_t stream_headerlen;
} g_usbd_video[CONFIG_USBDEV_MAX_BUS];
static int usbd_video_control_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
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) {
@@ -60,13 +76,13 @@ static int usbd_video_control_request_handler(struct usb_setup_packet *setup, ui
return 0;
}
static int usbd_video_control_unit_terminal_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
uint8_t entity_id = (uint8_t)(setup->wIndex >> 8);
uint8_t control_selector = (uint8_t)(setup->wValue >> 8);
for (uint8_t i = 0; i < 3; i++) {
struct video_entity_info *entity_info = &g_usbd_video.info[i];
struct video_entity_info *entity_info = &g_usbd_video[busid].info[i];
if (entity_info->bEntityId == entity_id) {
switch (entity_info->bDescriptorSubtype) {
case VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE:
@@ -295,8 +311,7 @@ static int usbd_video_control_unit_terminal_request_handler(struct usb_setup_pac
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;
@@ -546,7 +561,7 @@ static int usbd_video_control_unit_terminal_request_handler(struct usb_setup_pac
}
break;
default:
g_usbd_video.error_code = 0x06;
g_usbd_video[busid].error_code = 0x06;
USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
return -1;
}
@@ -564,7 +579,7 @@ static int usbd_video_control_unit_terminal_request_handler(struct usb_setup_pac
return 0;
}
static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int usbd_video_stream_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);
@@ -572,10 +587,10 @@ static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uin
case VIDEO_VS_PROBE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR:
//memcpy((uint8_t *)&g_usbd_video.probe, *data, setup->wLength);
//memcpy((uint8_t *)&g_usbd_video[busid].probe, *data, setup->wLength);
break;
case VIDEO_REQUEST_GET_CUR:
memcpy(*data, (uint8_t *)&g_usbd_video.probe, setup->wLength);
memcpy(*data, (uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
*len = sizeof(struct video_probe_and_commit_controls);
break;
@@ -583,7 +598,7 @@ static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uin
case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_RES:
case VIDEO_REQUEST_GET_DEF:
memcpy(*data, (uint8_t *)&g_usbd_video.probe, setup->wLength);
memcpy(*data, (uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
*len = sizeof(struct video_probe_and_commit_controls);
break;
case VIDEO_REQUEST_GET_LEN:
@@ -604,17 +619,17 @@ static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uin
case VIDEO_VS_COMMIT_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR:
//memcpy((uint8_t *)&g_usbd_video.commit, *data, setup->wLength);
//memcpy((uint8_t *)&g_usbd_video[busid].commit, *data, setup->wLength);
break;
case VIDEO_REQUEST_GET_CUR:
memcpy(*data, (uint8_t *)&g_usbd_video.commit, setup->wLength);
memcpy(*data, (uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
*len = sizeof(struct video_probe_and_commit_controls);
break;
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_RES:
case VIDEO_REQUEST_GET_DEF:
memcpy(*data, (uint8_t *)&g_usbd_video.commit, setup->wLength);
memcpy(*data, (uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
*len = sizeof(struct video_probe_and_commit_controls);
break;
@@ -636,7 +651,7 @@ static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uin
case VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR:
(*data)[0] = g_usbd_video.error_code;
(*data)[0] = g_usbd_video[busid].error_code;
*len = 1;
break;
case VIDEO_REQUEST_GET_INFO:
@@ -655,7 +670,7 @@ static int usbd_video_stream_request_handler(struct usb_setup_packet *setup, uin
return 0;
}
static int video_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
static int video_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("Video Class request: "
"bRequest 0x%02x\r\n",
@@ -666,30 +681,30 @@ static int video_class_interface_request_handler(struct usb_setup_packet *setup,
if (intf_num == 0) { /* Video Control Interface */
if (entity_id == 0) {
return usbd_video_control_request_handler(setup, data, len); /* Interface Control Requests */
return usbd_video_control_request_handler(busid, setup, data, len); /* Interface Control Requests */
} else {
return usbd_video_control_unit_terminal_request_handler(setup, data, len); /* Unit and Terminal Requests */
return usbd_video_control_unit_terminal_request_handler(busid, setup, data, len); /* Unit and Terminal Requests */
}
} else if (intf_num == 1) { /* Video Stream Inteface */
return usbd_video_stream_request_handler(setup, data, len); /* Interface Stream Requests */
} else if (intf_num == 1) { /* Video Stream Inteface */
return usbd_video_stream_request_handler(busid, setup, data, len); /* Interface Stream Requests */
}
return -1;
}
static void video_notify_handler(uint8_t event, void *arg)
static void video_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:
g_usbd_video.error_code = 0;
g_usbd_video.power_mode = 0;
g_usbd_video[busid].error_code = 0;
g_usbd_video[busid].power_mode = 0;
break;
case USBD_EVENT_SET_INTERFACE: {
struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
if (intf->bAlternateSetting == 1) {
usbd_video_open(intf->bInterfaceNumber);
usbd_video_open(busid, intf->bInterfaceNumber);
} else {
usbd_video_close(intf->bInterfaceNumber);
usbd_video_close(busid, intf->bInterfaceNumber);
}
}
@@ -699,46 +714,84 @@ static void video_notify_handler(uint8_t event, void *arg)
}
}
void usbd_video_probe_and_commit_controls_init(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.probe.hintUnion.bmHint = 0x01;
g_usbd_video.probe.hintUnion1.bmHint = 0;
g_usbd_video.probe.bFormatIndex = 1;
g_usbd_video.probe.bFrameIndex = 1;
g_usbd_video.probe.dwFrameInterval = dwFrameInterval;
g_usbd_video.probe.wKeyFrameRate = 0;
g_usbd_video.probe.wPFrameRate = 0;
g_usbd_video.probe.wCompQuality = 0;
g_usbd_video.probe.wCompWindowSize = 0;
g_usbd_video.probe.wDelay = 0;
g_usbd_video.probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video.probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video.probe.dwClockFrequency = 0;
g_usbd_video.probe.bmFramingInfo = 0;
g_usbd_video.probe.bPreferedVersion = 0;
g_usbd_video.probe.bMinVersion = 0;
g_usbd_video.probe.bMaxVersion = 0;
g_usbd_video[busid].probe.hintUnion.bmHint = 0x01;
g_usbd_video[busid].probe.hintUnion1.bmHint = 0;
g_usbd_video[busid].probe.bFormatIndex = 1;
g_usbd_video[busid].probe.bFrameIndex = 1;
g_usbd_video[busid].probe.dwFrameInterval = dwFrameInterval;
g_usbd_video[busid].probe.wKeyFrameRate = 0;
g_usbd_video[busid].probe.wPFrameRate = 0;
g_usbd_video[busid].probe.wCompQuality = 0;
g_usbd_video[busid].probe.wCompWindowSize = 0;
g_usbd_video[busid].probe.wDelay = 0;
g_usbd_video[busid].probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video[busid].probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video[busid].probe.dwClockFrequency = 0;
g_usbd_video[busid].probe.bmFramingInfo = 0;
g_usbd_video[busid].probe.bPreferedVersion = 0;
g_usbd_video[busid].probe.bMinVersion = 0;
g_usbd_video[busid].probe.bMaxVersion = 0;
g_usbd_video.commit.hintUnion.bmHint = 0x01;
g_usbd_video.commit.hintUnion1.bmHint = 0;
g_usbd_video.commit.bFormatIndex = 1;
g_usbd_video.commit.bFrameIndex = 1;
g_usbd_video.commit.dwFrameInterval = dwFrameInterval;
g_usbd_video.commit.wKeyFrameRate = 0;
g_usbd_video.commit.wPFrameRate = 0;
g_usbd_video.commit.wCompQuality = 0;
g_usbd_video.commit.wCompWindowSize = 0;
g_usbd_video.commit.wDelay = 0;
g_usbd_video.commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video.commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video.commit.dwClockFrequency = 0;
g_usbd_video.commit.bmFramingInfo = 0;
g_usbd_video.commit.bPreferedVersion = 0;
g_usbd_video.commit.bMinVersion = 0;
g_usbd_video.commit.bMaxVersion = 0;
g_usbd_video[busid].commit.hintUnion.bmHint = 0x01;
g_usbd_video[busid].commit.hintUnion1.bmHint = 0;
g_usbd_video[busid].commit.bFormatIndex = 1;
g_usbd_video[busid].commit.bFrameIndex = 1;
g_usbd_video[busid].commit.dwFrameInterval = dwFrameInterval;
g_usbd_video[busid].commit.wKeyFrameRate = 0;
g_usbd_video[busid].commit.wPFrameRate = 0;
g_usbd_video[busid].commit.wCompQuality = 0;
g_usbd_video[busid].commit.wCompWindowSize = 0;
g_usbd_video[busid].commit.wDelay = 0;
g_usbd_video[busid].commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video[busid].commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video[busid].commit.dwClockFrequency = 0;
g_usbd_video[busid].commit.bmFramingInfo = 0;
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 = 2;
}
struct usbd_interface *usbd_video_init_intf(struct usbd_interface *intf,
static uint32_t usbd_video_prepare_ep_buf_data(uint8_t busid, uint32_t remain, uint8_t *ep_buf)
{
struct video_payload_header *header;
uint32_t len;
uint32_t offset;
len = MIN(remain, (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - g_usbd_video[busid].stream_headerlen) * g_usbd_video[busid].max_packets);
offset = 0;
while (len > 0) {
header = (struct video_payload_header *)&ep_buf[offset];
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;
uint32_t len2 = MIN(len, g_usbd_video[busid].probe.dwMaxPayloadTransferSize - g_usbd_video[busid].stream_headerlen);
usb_memcpy(&ep_buf[offset + g_usbd_video[busid].stream_headerlen],
&g_usbd_video[busid].stream_buf[g_usbd_video[busid].stream_offset],
len2);
g_usbd_video[busid].stream_offset += len2;
len -= len2;
offset += (len2 + g_usbd_video[busid].stream_headerlen);
if (g_usbd_video[busid].stream_offset == g_usbd_video[busid].stream_len) {
header->headerInfoUnion.headerInfoBits.endOfFrame = 1;
}
}
return offset;
}
struct usbd_interface *usbd_video_init_intf(uint8_t busid,
struct usbd_interface *intf,
uint32_t dwFrameInterval,
uint32_t dwMaxVideoFrameSize,
uint32_t dwMaxPayloadTransferSize)
@@ -748,42 +801,84 @@ struct usbd_interface *usbd_video_init_intf(struct usbd_interface *intf,
intf->vendor_handler = NULL;
intf->notify_handler = video_notify_handler;
g_usbd_video.info[0].bDescriptorSubtype = VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video.info[0].bEntityId = 0x01;
g_usbd_video.info[0].wTerminalType = VIDEO_ITT_CAMERA;
g_usbd_video.info[1].bDescriptorSubtype = VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video.info[1].bEntityId = 0x03;
g_usbd_video.info[1].wTerminalType = 0x00;
g_usbd_video.info[2].bDescriptorSubtype = VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE;
g_usbd_video.info[2].bEntityId = 0x02;
g_usbd_video.info[2].wTerminalType = 0x00;
g_usbd_video[busid].info[0].bDescriptorSubtype = VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[0].bEntityId = 0x01;
g_usbd_video[busid].info[0].wTerminalType = VIDEO_ITT_CAMERA;
g_usbd_video[busid].info[1].bDescriptorSubtype = VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[1].bEntityId = 0x03;
g_usbd_video[busid].info[1].wTerminalType = 0x00;
g_usbd_video[busid].info[2].bDescriptorSubtype = VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[2].bEntityId = 0x02;
g_usbd_video[busid].info[2].wTerminalType = 0x00;
usbd_video_probe_and_commit_controls_init(dwFrameInterval, dwMaxVideoFrameSize, dwMaxPayloadTransferSize);
usbd_video_probe_and_commit_controls_init(busid, dwFrameInterval, dwMaxVideoFrameSize, dwMaxPayloadTransferSize);
return intf;
}
uint32_t usbd_video_mjpeg_payload_fill(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 };
uint32_t remain;
packets = (input_len + (g_usbd_video.probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video.probe.dwMaxPayloadTransferSize - 2);
last_packet_size = input_len - ((packets - 1) * (g_usbd_video.probe.dwMaxPayloadTransferSize - 2));
for (size_t i = 0; i < packets; i++) {
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i] = uvc_header[0];
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1];
if (i == (packets - 1)) {
memcpy(&output[2 + g_usbd_video.probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size);
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1);
} else {
memcpy(&output[2 + g_usbd_video.probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video.probe.dwMaxPayloadTransferSize - 2);
picture_pos += g_usbd_video.probe.dwMaxPayloadTransferSize - 2;
if (g_usbd_video[busid].ep_buf1_ready && (g_usbd_video[busid].ep_buf_idx == 0)) { /* callback: buf1 ready and buf0 was sent */
g_usbd_video[busid].ep_buf0_ready = false;
g_usbd_video[busid].ep_buf_idx = 1;
usbd_ep_start_write(busid, ep, g_usbd_video[busid].ep_buf1, g_usbd_video[busid].ep_buf1_len);
} else if (g_usbd_video[busid].ep_buf0_ready && (g_usbd_video[busid].ep_buf_idx == 1)) { /* callback: buf0 ready and buf1 was sent */
g_usbd_video[busid].ep_buf1_ready = false;
g_usbd_video[busid].ep_buf_idx = 0;
usbd_ep_start_write(busid, ep, g_usbd_video[busid].ep_buf0, g_usbd_video[busid].ep_buf0_len);
} else {
if (g_usbd_video[busid].stream_finish) {
return true;
}
}
uvc_header[1] ^= 1;
*out_len = (input_len + 2 * packets);
return packets;
}
if (!g_usbd_video[busid].ep_buf0_ready) {
remain = g_usbd_video[busid].stream_len - g_usbd_video[busid].stream_offset;
if (remain == 0) {
g_usbd_video[busid].stream_frameid ^= 1;
g_usbd_video[busid].stream_finish = true;
} else {
g_usbd_video[busid].ep_buf0_len = usbd_video_prepare_ep_buf_data(busid, remain, g_usbd_video[busid].ep_buf0);
g_usbd_video[busid].ep_buf0_ready = true;
if (!g_usbd_video[busid].ep_buf1_ready) {
g_usbd_video[busid].ep_buf_idx = 0;
usbd_ep_start_write(busid, ep, g_usbd_video[busid].ep_buf0, g_usbd_video[busid].ep_buf0_len);
}
}
}
if (!g_usbd_video[busid].ep_buf1_ready) {
remain = g_usbd_video[busid].stream_len - g_usbd_video[busid].stream_offset;
if (remain == 0) {
g_usbd_video[busid].stream_frameid ^= 1;
g_usbd_video[busid].stream_finish = true;
} else {
g_usbd_video[busid].ep_buf1_len = usbd_video_prepare_ep_buf_data(busid, remain, g_usbd_video[busid].ep_buf1);
g_usbd_video[busid].ep_buf1_ready = true;
}
}
return false;
}
int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buf0, uint8_t *ep_buf1, uint32_t ep_bufsize, uint8_t *stream_buf, uint32_t stream_len)
{
if ((usb_device_is_configured(busid) == 0) || (stream_len == 0)) {
return -1;
}
g_usbd_video[busid].ep_buf0 = ep_buf0;
g_usbd_video[busid].ep_buf1 = ep_buf1;
g_usbd_video[busid].ep_buf0_ready = false;
g_usbd_video[busid].ep_buf1_ready = false;
g_usbd_video[busid].ep_buf_idx = 0;
g_usbd_video[busid].stream_finish = false;
g_usbd_video[busid].max_packets = ep_bufsize / g_usbd_video[busid].probe.dwMaxPayloadTransferSize;
g_usbd_video[busid].stream_buf = stream_buf;
g_usbd_video[busid].stream_len = stream_len;
g_usbd_video[busid].stream_offset = 0;
usbd_video_stream_split_transfer(busid, ep);
return 0;
}

View File

@@ -13,14 +13,16 @@ extern "C" {
#endif
/* Init video interface driver */
struct usbd_interface *usbd_video_init_intf(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);
void usbd_video_open(uint8_t intf);
void usbd_video_close(uint8_t intf);
uint32_t usbd_video_mjpeg_payload_fill(uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len);
void usbd_video_open(uint8_t busid, uint8_t intf);
void usbd_video_close(uint8_t busid, uint8_t intf);
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_buf0, uint8_t *ep_buf1, uint32_t ep_bufsize, uint8_t *stream_buf, uint32_t stream_len);
#ifdef __cplusplus
}

View File

@@ -6,6 +6,10 @@
#include "usbh_core.h"
#include "usbh_video.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_video"
#include "usb_log.h"
#define DEV_FORMAT "/dev/video%d"
/* general descriptor field offsets */
@@ -30,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];
@@ -45,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;
@@ -87,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;
@@ -132,7 +146,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;
@@ -142,6 +156,11 @@ int usbh_video_open(struct usbh_video *video_class,
uint8_t frameidx = 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;
}
@@ -176,7 +195,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);
@@ -261,9 +280,14 @@ 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;
@@ -296,12 +320,12 @@ void usbh_video_list_info(struct usbh_video *video_class)
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\r\n", video_class->num_of_intf_altsettings);
for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
if (i == 0) {
USB_LOG_INFO("Ingore altsetting 0\r\n");
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;
@@ -309,7 +333,7 @@ void usbh_video_list_info(struct usbh_video *video_class)
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",
USB_LOG_RAW("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
i,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
@@ -318,15 +342,15 @@ void usbh_video_list_info(struct usbh_video *video_class)
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",
USB_LOG_RAW(" FrameIndex:%u\r\n", j + 1);
USB_LOG_RAW(" wWidth: %d, wHeight: %d\r\n",
video_class->format[i].frame[j].wWidth,
video_class->format[i].frame[j].wHeight);
}
@@ -471,20 +495,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 = {
@@ -501,20 +531,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

@@ -22,12 +22,19 @@ 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 {
@@ -48,6 +55,8 @@ struct usbh_video {
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,23 +17,10 @@ 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;
@@ -45,8 +32,13 @@ 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
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
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];
@@ -105,11 +97,13 @@ static void rndis_notify_rsp(void)
{
memset(NOTIFY_RESPONSE_AVAILABLE, 0, 8);
NOTIFY_RESPONSE_AVAILABLE[0] = 0x01;
usbd_ep_start_write(rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr, NOTIFY_RESPONSE_AVAILABLE, 8);
usbd_ep_start_write(0, rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr, NOTIFY_RESPONSE_AVAILABLE, 8);
}
static int rndis_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
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:
rndis_encapsulated_cmd_handler(*data, setup->wLength);
@@ -160,6 +154,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 +165,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 +181,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 +199,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 +226,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 +251,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,7 +264,7 @@ 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:
@@ -341,6 +347,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 +405,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 +426,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;
@@ -426,8 +439,11 @@ static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
return 0;
}
static void rndis_notify_handler(uint8_t event, void *arg)
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;
@@ -436,7 +452,7 @@ static void rndis_notify_handler(uint8_t event, void *arg)
g_rndis_rx_data_length = 0;
g_rndis_tx_data_length = 0;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
usbd_ep_start_read(rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
break;
default:
@@ -444,14 +460,17 @@ static void rndis_notify_handler(uint8_t event, void *arg)
}
}
void rndis_bulk_out(uint8_t ep, uint32_t nbytes)
void rndis_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
rndis_data_packet_t *hdr;
(void)busid;
(void)ep;
hdr = (rndis_data_packet_t *)g_rndis_rx_buffer;
g_rndis_rx_data_buffer = g_rndis_rx_buffer;
if ((hdr->MessageType != NDIS_PACKET_TYPE_DIRECTED) || (nbytes != hdr->MessageLength)) {
usbd_ep_start_read(rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_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));
return;
}
@@ -459,21 +478,28 @@ void rndis_bulk_out(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 ep, uint32_t nbytes)
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(ep, NULL, 0);
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 ep, uint32_t nbytes)
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);
}
@@ -491,12 +517,12 @@ struct pbuf *usbd_rndis_eth_rx(void)
if (p == NULL) {
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(rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
return p;
}
@@ -508,7 +534,7 @@ int usbd_rndis_eth_tx(struct pbuf *p)
rndis_data_packet_t *hdr;
if (g_usbd_rndis.link_status == NDIS_MEDIA_STATE_DISCONNECTED) {
return 0;
return -USB_ERR_NOTCONN;
}
if (g_rndis_tx_data_length > 0) {
@@ -521,7 +547,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;
}
@@ -536,7 +562,7 @@ int usbd_rndis_eth_tx(struct pbuf *p)
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(rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr, g_rndis_tx_buffer, 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);
}
#endif
struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
@@ -548,7 +574,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;
@@ -557,9 +582,9 @@ struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr = int_ep;
rndis_ep_data[RNDIS_INT_EP_IDX].ep_cb = rndis_int_in;
usbd_add_endpoint(&rndis_ep_data[RNDIS_OUT_EP_IDX]);
usbd_add_endpoint(&rndis_ep_data[RNDIS_IN_EP_IDX]);
usbd_add_endpoint(&rndis_ep_data[RNDIS_INT_EP_IDX]);
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_OUT_EP_IDX]);
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_IN_EP_IDX]);
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_INT_EP_IDX]);
intf->class_interface_handler = rndis_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
@@ -568,3 +593,13 @@ struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
return intf;
}
__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,8 @@ 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);
void usbd_rndis_data_recv_done(uint32_t len);
void usbd_rndis_data_send_done(uint32_t len);
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
struct pbuf *usbd_rndis_eth_rx(void);

View File

@@ -0,0 +1,411 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_bluetooth.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_bluetooth"
#include "usb_log.h"
#define DEV_FORMAT "/dev/bluetooth"
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];
#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];
#endif
static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
uint8_t mult;
uint16_t mps;
#endif
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (intf != 0) {
return 0;
}
#endif
memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
bluetooth_class->hport = hport;
bluetooth_class->intf = intf;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
bluetooth_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
#endif
hport->config.intf[intf].priv = bluetooth_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;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(bluetooth_class->intin, ep_desc);
} else {
return -USB_ERR_NOTSUPP;
}
} else {
#endif
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(bluetooth_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(bluetooth_class->bulkout, ep_desc);
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
}
#endif
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
USB_LOG_INFO("Num of altsettings:%u\r\n", bluetooth_class->num_of_intf_altsettings);
for (uint8_t i = 0; i < bluetooth_class->num_of_intf_altsettings; i++) {
USB_LOG_INFO("Altsetting:%u\r\n", i);
for (uint8_t j = 0; j < hport->config.intf[intf + 1].altsetting[i].intf_desc.bNumEndpoints; j++) {
ep_desc = &bluetooth_class->hport->config.intf[intf + 1].altsetting[i].ep[j].ep_desc;
mult = USB_GET_MULT(ep_desc->wMaxPacketSize);
mps = USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize);
USB_LOG_INFO("\tEp=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
mps,
ep_desc->bInterval,
mult);
}
}
ret = usbh_set_interface(hport, intf, 0);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Bluetooth select altsetting 0\r\n");
#endif
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;
}
static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_bluetooth *bluetooth_class = (struct usbh_bluetooth *)hport->config.intf[intf].priv;
if (hport->config.config_desc.bNumInterfaces == (intf + 1)) {
return 0;
}
if (bluetooth_class) {
if (bluetooth_class->bulkin) {
usbh_kill_urb(&bluetooth_class->bulkin_urb);
}
if (bluetooth_class->bulkout) {
usbh_kill_urb(&bluetooth_class->bulkout_urb);
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (bluetooth_class->intin) {
usbh_kill_urb(&bluetooth_class->intin_urb);
}
// if (bluetooth_class->isoin) {
// usbh_kill_urb(&bluetooth_class->isoin_urb);
// }
// if (bluetooth_class->isoin) {
// usbh_kill_urb(&bluetooth_class->isoinin_urb);
// }
#endif
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bluetooth_stop(bluetooth_class);
}
memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
}
return ret;
}
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_LOG
static void usbh_bluetooth_hci_dump(uint8_t *data, uint32_t len)
{
uint32_t i = 0;
for (i = 0; i < len; i++) {
if (i % 16 == 0) {
USB_LOG_RAW("\r\n");
}
USB_LOG_RAW("%02x ", data[i]);
}
USB_LOG_RAW("\r\n");
}
#else
#define usbh_bluetooth_hci_dump(data, len)
#endif
static int usbh_bluetooth_hci_bulk_out(uint8_t *buffer, uint32_t buflen)
{
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
struct usbh_urb *urb = &bluetooth_class->bulkout_urb;
int ret;
usbh_bulk_urb_fill(urb, bluetooth_class->hport, bluetooth_class->bulkout, buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
{
int ret;
g_bluetooth_tx_buf[0] = hci_type;
memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
ret = usbh_bluetooth_hci_bulk_out(g_bluetooth_tx_buf, buflen + 1);
return ret;
}
void usbh_bluetooth_hci_rx_thread(void *argument)
{
int ret;
uint32_t ep_mps;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
USB_LOG_INFO("Create hc rx thread\r\n");
while (1) {
usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
continue;
}
}
actual_len += g_bluetooth_class.bulkin_urb.actual_length;
if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len);
usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len);
actual_len = 0;
} else {
/* read continue util read short packet */
}
}
// clang-format off
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
#else
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;
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;
setup->wValue = 0;
setup->wIndex = bluetooth_class->intf;
setup->wLength = buflen;
return usbh_control_transfer(bluetooth_class->hport, setup, buffer);
}
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
{
int ret;
if (hci_type == USB_BLUETOOTH_HCI_CMD) {
g_bluetooth_cmd_buf[0] = USB_BLUETOOTH_HCI_CMD;
memcpy(&g_bluetooth_cmd_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_cmd_buf, buflen + 1);
ret = usbh_bluetooth_hci_cmd(&g_bluetooth_cmd_buf[1], buflen);
} else if (hci_type == USB_BLUETOOTH_HCI_ACL) {
g_bluetooth_tx_buf[0] = USB_BLUETOOTH_HCI_ACL;
memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
ret = usbh_bluetooth_hci_bulk_out(&g_bluetooth_tx_buf[1], buflen);
} else {
ret = -1;
}
return ret;
}
void usbh_bluetooth_hci_evt_rx_thread(void *argument)
{
int ret;
uint32_t ep_mps;
uint32_t interval;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.intin->wMaxPacketSize);
interval = g_bluetooth_class.intin->bInterval;
USB_LOG_INFO("Create hc event rx thread\r\n");
while (1) {
usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, &g_bluetooth_evt_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.intin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else if (ret == -USB_ERR_NAK) {
usb_osal_msleep(interval);
continue;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
usb_osal_msleep(interval);
continue;
}
}
actual_len += g_bluetooth_class.intin_urb.actual_length;
if (g_bluetooth_class.intin_urb.actual_length != ep_mps) {
g_bluetooth_evt_buf[0] = USB_BLUETOOTH_HCI_EVT;
usbh_bluetooth_hci_dump(g_bluetooth_evt_buf, actual_len + 1);
usbh_bluetooth_hci_read_callback(g_bluetooth_evt_buf, actual_len + 1);
actual_len = 0;
} else {
/* read continue util read short packet */
}
usb_osal_msleep(interval);
}
// clang-format off
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)
{
int ret;
uint32_t ep_mps;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
USB_LOG_INFO("Create hc acl rx thread\r\n");
while (1) {
usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
continue;
}
}
actual_len += g_bluetooth_class.bulkin_urb.actual_length;
if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
g_bluetooth_rx_buf[0] = USB_BLUETOOTH_HCI_ACL;
usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len + 1);
usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len + 1);
actual_len = 0;
} else {
/* read continue util read short packet */
}
}
// clang-format off
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
#endif
__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 = {
.driver_name = "bluetooth",
.connect = usbh_bluetooth_connect,
.disconnect = usbh_bluetooth_disconnect
};
#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_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,
.bInterfaceClass = USB_DEVICE_CLASS_WIRELESS,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01,
.id_table = NULL,
.class_driver = &bluetooth_class_driver
};
#endif

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_BLUETOOTH_H
#define USBH_BLUETOOTH_H
#define USB_BLUETOOTH_HCI_NONE 0x00
#define USB_BLUETOOTH_HCI_CMD 0x01
#define USB_BLUETOOTH_HCI_ACL 0x02
#define USB_BLUETOOTH_HCI_SCO 0x03
#define USB_BLUETOOTH_HCI_EVT 0x04
#define USB_BLUETOOTH_HCI_ISO 0x05
struct usbh_bluetooth {
struct usbh_hubport *hport;
uint8_t intf;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
struct usb_endpoint_descriptor *intin; /* INTR endpoint */
struct usb_endpoint_descriptor *isoin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *isoout; /* Bulk OUT endpoint */
struct usbh_urb intin_urb; /* INTR IN urb */
struct usbh_urb *isoin_urb; /* Bulk IN urb */
struct usbh_urb *isoout_urb; /* Bulk OUT urb */
uint8_t num_of_intf_altsettings;
#endif
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
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);
#else
void usbh_bluetooth_hci_evt_rx_thread(void *argument);
void usbh_bluetooth_hci_acl_rx_thread(void *argument);
#endif
void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class);
void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_BLUETOOTH_H */

View File

@@ -7,17 +7,17 @@
#include "usbh_rndis.h"
#include "rndis_protocol.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_rndis"
#include "usb_log.h"
#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];
@@ -26,6 +26,7 @@ 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;
@@ -40,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;
@@ -74,7 +80,7 @@ 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) {
@@ -82,16 +88,26 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
return ret;
}
rndis_class->max_transfer_pkts = resp->MaxPacketsPerTransfer;
rndis_class->max_transfer_size = resp->MaxTransferSize;
USB_LOG_INFO("MaxPacketsPerTransfer:%d\r\n", resp->MaxPacketsPerTransfer);
USB_LOG_INFO("MaxTransferSize:%d\r\n", 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;
@@ -122,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) {
@@ -138,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;
@@ -174,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) {
@@ -185,7 +206,7 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
return ret;
}
static int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
{
int ret;
uint8_t data[32];
@@ -196,20 +217,25 @@ static int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
return ret;
}
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->link_status = true;
rndis_class->connect_status = true;
} else {
rndis_class->link_status = false;
rndis_class->connect_status = false;
}
return 0;
}
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;
@@ -236,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) {
@@ -326,9 +352,9 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
goto query_errorout;
}
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->link_status = true;
rndis_class->connect_status = true;
} else {
rndis_class->link_status = false;
rndis_class->connect_status = false;
}
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
@@ -361,14 +387,14 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
}
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;
}
@@ -382,7 +408,7 @@ 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);
@@ -425,76 +451,92 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
void usbh_rndis_rx_thread(void *argument)
{
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)argument;
USB_LOG_INFO("Create rndis rx thread\r\n");
// clang-format off
find_class:
// clang-format on
g_rndis_class.link_status = false;
g_rndis_class.connect_status = false;
if (usbh_find_class_instance("/dev/rndis") == NULL) {
goto delete;
}
while (g_rndis_class.link_status == false) {
while (g_rndis_class.connect_status == false) {
ret = usbh_rndis_get_connect_status(&g_rndis_class);
if (ret < 0) {
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;
}
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:%d\r\n", 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:%d,remain:%d,total:%d\r\n", pmg_offset, g_rndis_rx_length, 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");
}
}
}
@@ -506,53 +548,48 @@ delete:
// clang-format on
}
err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
uint8_t *usbh_rndis_get_eth_txbuf(void)
{
int ret;
struct pbuf *q;
uint8_t *buffer;
rndis_data_packet_t *hdr;
return (g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
}
if (g_rndis_class.link_status == false) {
return ERR_BUF;
int usbh_rndis_eth_output(uint32_t buflen)
{
rndis_data_packet_t *hdr;
uint32_t len;
if (g_rndis_class.connect_status == false) {
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;
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);
}
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
{
(void)rndis_class;
}
__WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
{
(void)rndis_class;
}
static const struct usbh_class_driver rndis_class_driver = {
@@ -563,10 +600,9 @@ 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
};

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,26 +22,30 @@ 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 link_status;
bool connect_status;
uint8_t mac[6];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class);
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);
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(void *argument);
#ifdef __cplusplus

View File

@@ -16,13 +16,13 @@ extern "C" {
* @brief init device controller registers.
* @return On success will return 0, and others indicate fail.
*/
int usb_dc_init(void);
int usb_dc_init(uint8_t busid);
/**
* @brief deinit device controller registers.
* @return On success will return 0, and others indicate fail.
*/
int usb_dc_deinit(void);
int usb_dc_deinit(uint8_t busid);
/**
* @brief Set USB device address
@@ -31,16 +31,23 @@ int usb_dc_deinit(void);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_set_address(const uint8_t addr);
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(const uint8_t port);
uint8_t usbd_get_port_speed(uint8_t busid);
/**
* @brief configure and enable endpoint.
@@ -49,7 +56,7 @@ uint8_t usbd_get_port_speed(const uint8_t port);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_ep_open(const struct usb_endpoint_descriptor *ep);
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep);
/**
* @brief Disable the selected endpoint
@@ -58,7 +65,7 @@ int usbd_ep_open(const struct usb_endpoint_descriptor *ep);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_ep_close(const uint8_t ep);
int usbd_ep_close(uint8_t busid, const uint8_t ep);
/**
* @brief Set stall condition for the selected endpoint
@@ -68,7 +75,7 @@ int usbd_ep_close(const uint8_t ep);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_ep_set_stall(const uint8_t ep);
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep);
/**
* @brief Clear stall condition for the selected endpoint
@@ -78,7 +85,7 @@ int usbd_ep_set_stall(const uint8_t ep);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_ep_clear_stall(const uint8_t ep);
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep);
/**
* @brief Check if the selected endpoint is stalled
@@ -89,7 +96,7 @@ int usbd_ep_clear_stall(const uint8_t ep);
*
* @return On success will return 0, and others indicate fail.
*/
int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled);
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled);
/**
* @brief Setup in ep transfer setting and start transfer.
@@ -108,7 +115,7 @@ int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled);
* be zero for a zero length status packet.
* @return 0 on success, negative errno code on fail.
*/
int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len);
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len);
/**
* @brief Setup out ep transfer setting and start transfer.
@@ -127,40 +134,40 @@ int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len
*
* @return 0 on success, negative errno code on fail.
*/
int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len);
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len);
/* usb dcd irq callback */
/**
* @brief Usb connect irq callback.
*/
void usbd_event_connect_handler(void);
void usbd_event_connect_handler(uint8_t busid);
/**
* @brief Usb disconnect irq callback.
*/
void usbd_event_disconnect_handler(void);
void usbd_event_disconnect_handler(uint8_t busid);
/**
* @brief Usb resume irq callback.
*/
void usbd_event_resume_handler(void);
void usbd_event_resume_handler(uint8_t busid);
/**
* @brief Usb suspend irq callback.
*/
void usbd_event_suspend_handler(void);
void usbd_event_suspend_handler(uint8_t busid);
/**
* @brief Usb reset irq callback.
*/
void usbd_event_reset_handler(void);
void usbd_event_reset_handler(uint8_t busid);
/**
* @brief Usb setup packet recv irq callback.
* @param[in] psetup setup packet.
*/
void usbd_event_ep0_setup_complete_handler(uint8_t *psetup);
void usbd_event_ep0_setup_complete_handler(uint8_t busid, uint8_t *psetup);
/**
* @brief In ep transfer complete irq callback.
@@ -168,7 +175,7 @@ void usbd_event_ep0_setup_complete_handler(uint8_t *psetup);
* listed in the device configuration table
* @param[in] nbytes How many nbytes have transferred.
*/
void usbd_event_ep_in_complete_handler(uint8_t ep, uint32_t nbytes);
void usbd_event_ep_in_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbytes);
/**
* @brief Out ep transfer complete irq callback.
@@ -176,7 +183,16 @@ void usbd_event_ep_in_complete_handler(uint8_t ep, uint32_t nbytes);
* listed in the device configuration table
* @param[in] nbytes How many nbytes have transferred.
*/
void usbd_event_ep_out_complete_handler(uint8_t ep, uint32_t nbytes);
void usbd_event_ep_out_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbytes);
#ifdef CONFIG_USBDEV_TEST_MODE
/**
* @brief Usb execute test mode
* @param[in] busid device busid
* @param[in] test_mode usb test mode
*/
void usbd_execute_test_mode(uint8_t busid, uint8_t test_mode);
#endif
#ifdef __cplusplus
}

View File

@@ -34,6 +34,10 @@
/**< maximum packet size (MPS) for EP 0 */
#define USB_CTRL_EP_MPS 64
/**< maximum packet size (MPS) for bulk EP */
#define USB_BULK_EP_MPS_HS 512
#define USB_BULK_EP_MPS_FS 64
/* USB PID Types */
#define USB_PID_OUT (0x01) /* Tokens */
#define USB_PID_IN (0x09)
@@ -538,7 +542,7 @@ struct usb_msosv2_subset_function_descriptor {
} __PACKED;
struct usb_msosv2_descriptor {
uint8_t *compat_id;
const uint8_t *compat_id;
uint16_t compat_id_len;
uint8_t vendor_code;
};
@@ -610,14 +614,14 @@ struct usb_webusb_url_descriptor {
char URL[];
} __PACKED;
struct usb_webusb_url_ex_descriptor {
struct usb_webusb_descriptor {
uint8_t vendor_code;
uint8_t *string;
const uint8_t *string;
uint32_t string_len;
} __PACKED;
struct usb_bos_descriptor {
uint8_t *string;
const uint8_t *string;
uint32_t string_len;
};
@@ -660,6 +664,27 @@ struct usb_desc_header {
bmAttributes, /* bmAttributes */ \
USB_CONFIG_POWER_MA(bMaxPower) /* bMaxPower */
#define USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bNumConfigurations) \
0x0A, /* bLength */ \
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, /* bDescriptorType */ \
WBVAL(bcdUSB), /* bcdUSB */ \
bDeviceClass, /* bDeviceClass */ \
bDeviceSubClass, /* bDeviceSubClass */ \
bDeviceProtocol, /* bDeviceProtocol */ \
0x40, /* bMaxPacketSize */ \
bNumConfigurations, /* bNumConfigurations */ \
0x00 /* bReserved */
#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_OTHER_SPEED, /* bDescriptorType */ \
WBVAL(wTotalLength), /* wTotalLength */ \
bNumInterfaces, /* bNumInterfaces */ \
bConfigurationValue, /* bConfigurationValue */ \
0x00, /* iConfiguration */ \
bmAttributes, /* bmAttributes */ \
USB_CONFIG_POWER_MA(bMaxPower) /* bMaxPower */
#define USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints, \
bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface) \
0x09, /* bLength */ \

View File

@@ -14,6 +14,8 @@ extern "C" {
typedef void (*usbh_complete_callback_t)(void *arg, int nbytes);
struct usbh_bus;
/**
* @brief USB Iso Configuration.
*
@@ -32,10 +34,12 @@ struct usbh_iso_frame_packet {
* Structure containing the USB Urb configuration.
*/
struct usbh_urb {
usb_slist_t list;
void *hcpriv;
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *ep;
uint8_t data_toggle;
uint8_t interval;
struct usb_setup_packet *setup;
uint8_t *transfer_buffer;
uint32_t transfer_buffer_length;
@@ -59,21 +63,21 @@ struct usbh_urb {
*
* @return On success will return 0, and others indicate fail.
*/
int usb_hc_init(void);
int usb_hc_init(struct usbh_bus *bus);
/**
* @brief usb host controller hardware deinit.
*
* @return On success will return 0, and others indicate fail.
*/
int usb_hc_deinit(void);
int usb_hc_deinit(struct usbh_bus *bus);
/**
* @brief Get frame number.
*
* @return frame number.
*/
uint16_t usbh_get_frame_number(void);
uint16_t usbh_get_frame_number(struct usbh_bus *bus);
/**
* @brief control roothub.
*
@@ -81,7 +85,7 @@ uint16_t usbh_get_frame_number(void);
* @param buf buf for reading response or write data.
* @return On success will return 0, and others indicate fail.
*/
int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf);
int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
/**
* @brief Submit a usb transfer request to an endpoint.

View File

@@ -82,4 +82,33 @@ void usb_assert(const char *filename, int linenum);
usb_assert(__FILE__, __LINE__); \
} while (0)
#define ___is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
static inline void usb_hexdump(const void *ptr, uint32_t buflen)
{
unsigned char *buf = (unsigned char *)ptr;
uint32_t i, j;
(void)buf;
for (i = 0; i < buflen; i += 16) {
CONFIG_USB_PRINTF("%08X:", i);
for (j = 0; j < 16; j++)
if (i + j < buflen) {
if ((j % 8) == 0) {
CONFIG_USB_PRINTF(" ");
}
CONFIG_USB_PRINTF("%02X ", buf[i + j]);
} else
CONFIG_USB_PRINTF(" ");
CONFIG_USB_PRINTF(" ");
for (j = 0; j < 16; j++)
if (i + j < buflen)
CONFIG_USB_PRINTF("%c", ___is_print(buf[i + j]) ? buf[i + j] : '.');
CONFIG_USB_PRINTF("\n");
}
}
#endif /* USB_LOG_H */

91
common/usb_memcpy.h Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USB_MEMCPY_H
#define USB_MEMCPY_H
#include <stdint.h>
#include <stddef.h>
#define ALIGN_UP_DWORD(x) ((uint32_t)(uintptr_t)(x) & (sizeof(uint32_t) - 1))
static inline void dword2array(char *addr, uint32_t w)
{
addr[0] = w;
addr[1] = w >> 8;
addr[2] = w >> 16;
addr[3] = w >> 24;
}
static inline void *usb_memcpy(void *s1, const void *s2, size_t n)
{
char *b1 = (char *)s1;
const char *b2 = (const char *)s2;
uint32_t *w1;
const uint32_t *w2;
if (ALIGN_UP_DWORD(b1) == ALIGN_UP_DWORD(b2)) {
while (ALIGN_UP_DWORD(b1) != 0 && n > 0) {
*b1++ = *b2++;
--n;
}
w1 = (uint32_t *)b1;
w2 = (const uint32_t *)b2;
while (n >= 4 * sizeof(uint32_t)) {
*w1++ = *w2++;
*w1++ = *w2++;
*w1++ = *w2++;
*w1++ = *w2++;
n -= 4 * sizeof(uint32_t);
}
while (n >= sizeof(uint32_t)) {
*w1++ = *w2++;
n -= sizeof(uint32_t);
}
b1 = (char *)w1;
b2 = (const char *)w2;
while (n--) {
*b1++ = *b2++;
}
} else {
while (n > 0 && ALIGN_UP_DWORD(b2) != 0) {
*b1++ = *b2++;
--n;
}
w2 = (const uint32_t *)b2;
while (n >= 4 * sizeof(uint32_t)) {
dword2array(b1, *w2++);
b1 += sizeof(uint32_t);
dword2array(b1, *w2++);
b1 += sizeof(uint32_t);
dword2array(b1, *w2++);
b1 += sizeof(uint32_t);
dword2array(b1, *w2++);
b1 += sizeof(uint32_t);
n -= 4 * sizeof(uint32_t);
}
while (n >= sizeof(uint32_t)) {
dword2array(b1, *w2++);
b1 += sizeof(uint32_t);
n -= sizeof(uint32_t);
}
b2 = (const char *)w2;
while (n--) {
*b1++ = *b2++;
}
}
return s1;
}
#endif

View File

@@ -8,6 +8,7 @@
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#define USB_OSAL_WAITING_FOREVER (0xFFFFFFFFU)
@@ -16,6 +17,14 @@ typedef void *usb_osal_sem_t;
typedef void *usb_osal_mutex_t;
typedef void *usb_osal_mq_t;
typedef void (*usb_thread_entry_t)(void *argument);
typedef void (*usb_timer_handler_t)(void *argument);
struct usb_osal_timer {
usb_timer_handler_t handler;
void *argument;
bool is_period;
uint32_t ticks;
void *timer;
};
/*
* Task with smaller priority value indicates higher task priority
@@ -39,9 +48,17 @@ void usb_osal_mq_delete(usb_osal_mq_t mq);
int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr);
int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout);
struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_ms, usb_timer_handler_t handler, void *argument, bool is_period);
void usb_osal_timer_delete(struct usb_osal_timer *timer);
void usb_osal_timer_start(struct usb_osal_timer *timer);
void usb_osal_timer_stop(struct usb_osal_timer *timer);
size_t usb_osal_enter_critical_section(void);
void usb_osal_leave_critical_section(size_t flag);
void usb_osal_msleep(uint32_t delay);
void *usb_osal_malloc(size_t size);
void usb_osal_free(void *ptr);
#endif /* USB_OSAL_H */

View File

@@ -46,7 +46,7 @@
#endif
#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
#ifndef __USED
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __USED __attribute__((used))
#else
#define __USED __root
@@ -54,7 +54,7 @@
#endif
#ifndef __WEAK
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __WEAK __attribute__((weak))
#else
#define __WEAK _Pragma("__weak")
@@ -62,7 +62,7 @@
#endif
#ifndef __PACKED
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
@@ -71,7 +71,7 @@
#endif
#ifndef __PACKED_STRUCT
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
@@ -80,7 +80,7 @@
#endif
#ifndef __PACKED_UNION
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
@@ -89,7 +89,7 @@
#endif
#ifndef __ALIGNED
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __ALIGNED(x) __attribute__((aligned(x)))
#elif (__VER__ >= 7080000)
/* Needs IAR language extensions */
@@ -205,4 +205,6 @@
#define USB_MEM_ALIGNX __attribute__((aligned(CONFIG_USB_ALIGN_SIZE)))
#define USB_ALIGN_UP(size, align) (((size) + (align)-1) & ~((align)-1))
#endif /* USB_UTIL_H */

21
common/usb_version.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USB_VERSION_H
#define USB_VERSION_H
#ifdef CHERRYUSB_VERSION
#warning "Please do not define CHERRYUSB_VERSION in usb_config.h"
#undef CHERRYUSB_VERSION
#endif
#ifdef CHERRYUSB_VERSION_STR
#warning "Please do not define CHERRYUSB_VERSION_STR in usb_config.h"
#undef CHERRYUSB_VERSION_STR
#endif
#define CHERRYUSB_VERSION 0x010402
#define CHERRYUSB_VERSION_STR "v1.4.2"
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,8 @@ extern "C" {
#include "usb_list.h"
#include "usb_log.h"
#include "usb_dc.h"
#include "usb_memcpy.h"
#include "usb_version.h"
enum usbd_event_type {
/* USB DCD IRQ */
@@ -38,12 +40,14 @@ enum usbd_event_type {
USBD_EVENT_SET_INTERFACE, /** USB interface selected */
USBD_EVENT_SET_REMOTE_WAKEUP, /** USB set remote wakeup */
USBD_EVENT_CLR_REMOTE_WAKEUP, /** USB clear remote wakeup */
USBD_EVENT_INIT, /** USB init done when call usbd_initialize */
USBD_EVENT_DEINIT, /** USB deinit done when call usbd_deinitialize */
USBD_EVENT_UNKNOWN
};
typedef int (*usbd_request_handler)(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len);
typedef void (*usbd_endpoint_callback)(uint8_t ep, uint32_t nbytes);
typedef void (*usbd_notify_handler)(uint8_t event, void *arg);
typedef int (*usbd_request_handler)(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len);
typedef void (*usbd_endpoint_callback)(uint8_t busid, uint8_t ep, uint32_t nbytes);
typedef void (*usbd_notify_handler)(uint8_t busid, uint8_t event, void *arg);
struct usbd_endpoint {
uint8_t ep_addr;
@@ -65,30 +69,45 @@ struct usb_descriptor {
const uint8_t *(*config_descriptor_callback)(uint8_t speed);
const uint8_t *(*device_quality_descriptor_callback)(uint8_t speed);
const uint8_t *(*other_speed_descriptor_callback)(uint8_t speed);
const uint8_t *(*string_descriptor_callback)(uint8_t speed, uint8_t index);
const char *(*string_descriptor_callback)(uint8_t speed, uint8_t index);
const struct usb_msosv1_descriptor *msosv1_descriptor;
const struct usb_msosv2_descriptor *msosv2_descriptor;
const struct usb_webusb_url_ex_descriptor *webusb_url_descriptor;
const struct usb_webusb_descriptor *webusb_url_descriptor;
const struct usb_bos_descriptor *bos_descriptor;
};
#ifdef CONFIG_USBDEV_ADVANCE_DESC
void usbd_desc_register(const struct usb_descriptor *desc);
#else
void usbd_desc_register(const uint8_t *desc);
void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc);
void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc);
void usbd_bos_desc_register(struct usb_bos_descriptor *desc);
struct usbd_bus {
uint8_t busid;
uintptr_t reg_base;
};
extern struct usbd_bus g_usbdev_bus[];
#ifdef USBD_IRQHandler
#error USBD_IRQHandler is obsolete, please call USBD_IRQHandler(xxx) in your irq
#endif
void usbd_add_interface(struct usbd_interface *intf);
void usbd_add_endpoint(struct usbd_endpoint *ep);
#ifdef CONFIG_USBDEV_ADVANCE_DESC
void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc);
#else
void usbd_desc_register(uint8_t busid, const uint8_t *desc);
void usbd_msosv1_desc_register(uint8_t busid, struct usb_msosv1_descriptor *desc);
void usbd_msosv2_desc_register(uint8_t busid, struct usb_msosv2_descriptor *desc);
void usbd_bos_desc_register(uint8_t busid, struct usb_bos_descriptor *desc);
void usbd_webusb_desc_register(uint8_t busid, struct usb_webusb_descriptor *desc);
#endif
bool usb_device_is_configured(void);
int usbd_initialize(void);
int usbd_deinitialize(void);
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf);
void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep);
void usbd_event_handler(uint8_t event);
uint16_t usbd_get_ep_mps(uint8_t busid, uint8_t ep);
uint8_t usbd_get_ep_mult(uint8_t busid, uint8_t ep);
bool usb_device_is_configured(uint8_t busid);
bool usb_device_is_suspend(uint8_t busid);
int usbd_send_remote_wakeup(uint8_t busid);
int usbd_initialize(uint8_t busid, uintptr_t reg_base, void (*event_handler)(uint8_t busid, uint8_t event));
int usbd_deinitialize(uint8_t busid);
#ifdef __cplusplus
}

View File

@@ -5,36 +5,28 @@
*/
#include "usbh_core.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_core"
#include "usb_log.h"
struct usbh_class_info *usbh_class_info_table_begin = NULL;
struct usbh_class_info *usbh_class_info_table_end = NULL;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t ep0_request_buffer[CONFIG_USBHOST_REQUEST_BUFFER_LEN];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct usb_setup_packet g_setup[CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USBHOST_MAX_EHPORTS];
usb_slist_t g_bus_head = USB_SLIST_OBJECT_INIT(g_bus_head);
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t ep0_request_buffer[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(CONFIG_USBHOST_REQUEST_BUFFER_LEN, CONFIG_USB_ALIGN_SIZE)];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct usb_setup_packet g_setup_buffer[CONFIG_USBHOST_MAX_BUS][CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USBHOST_MAX_EHPORTS];
struct usbh_bus g_usbhost_bus[CONFIG_USBHOST_MAX_BUS];
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define USB_DEV_ADDR_MAX 0x7f
#define USB_DEV_ADDR_MARK_OFFSET 5
#define USB_DEV_ADDR_MARK_MASK 0x1f
struct usbh_devaddr_map {
/**
* alloctab[0]:addr from 0~31
* alloctab[1]:addr from 32~63
* alloctab[2]:addr from 64~95
* alloctab[3]:addr from 96~127
*
*/
uint8_t next; /* Next device address */
uint32_t alloctab[4]; /* Bit allocation table */
};
struct usbh_bus {
struct usbh_devaddr_map devgen;
} g_usbh_bus;
static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen)
{
uint8_t startaddr = devgen->next;
@@ -87,37 +79,43 @@ static int __usbh_free_devaddr(struct usbh_devaddr_map *devgen, uint8_t devaddr)
return 0;
}
static int usbh_free_devaddr(struct usbh_hubport *hport)
{
if (hport->dev_addr > 0) {
__usbh_free_devaddr(&hport->bus->devgen, hport->dev_addr);
}
return 0;
}
static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subclass, uint8_t protocol,
uint16_t vid, uint16_t pid)
{
struct usbh_class_info *index = NULL;
for (index = usbh_class_info_table_begin; index < usbh_class_info_table_end; index++) {
if ((index->match_flags & (USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL)) ==
(USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL)) {
if (index->vid == vid && index->pid == pid &&
index->class == class && index->subclass == subclass && index->protocol == protocol) {
return index->class_driver;
if ((index->match_flags & USB_CLASS_MATCH_INTF_CLASS) && !(index->bInterfaceClass == class)) {
continue;
}
if ((index->match_flags & USB_CLASS_MATCH_INTF_SUBCLASS) && !(index->bInterfaceSubClass == subclass)) {
continue;
}
if ((index->match_flags & USB_CLASS_MATCH_INTF_PROTOCOL) && !(index->bInterfaceProtocol == protocol)) {
continue;
}
if (index->match_flags & USB_CLASS_MATCH_VID_PID && index->id_table) {
/* scan id table */
uint32_t i;
for (i = 0; index->id_table[i][0]; i++) {
if (index->id_table[i][0] == vid && index->id_table[i][1] == pid) {
break;
}
}
} else if ((index->match_flags & (USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL)) ==
(USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL)) {
if (index->class == class && index->subclass == subclass && index->protocol == protocol) {
return index->class_driver;
}
} else if ((index->match_flags & (USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS)) ==
(USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS)) {
if (index->vid == vid && index->pid == pid && index->class == class) {
return index->class_driver;
}
} else if ((index->match_flags & (USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS)) == (USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS)) {
if (index->class == class && index->subclass == subclass) {
return index->class_driver;
}
} else if ((index->match_flags & (USB_CLASS_MATCH_INTF_CLASS)) == USB_CLASS_MATCH_INTF_CLASS) {
if (index->class == class) {
return index->class_driver;
/* do not match, continue next */
if (!index->id_table[i][0]) {
continue;
}
}
return index->class_driver;
}
return NULL;
}
@@ -227,15 +225,18 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config
cur_ep = 0;
if (cur_iface > (CONFIG_USBHOST_MAX_INTERFACES - 1)) {
USB_LOG_ERR("Interface num overflow\r\n");
return -USB_ERR_NOMEM;
while (1) {
}
}
if (cur_alt_setting > (CONFIG_USBHOST_MAX_INTF_ALTSETTINGS - 1)) {
USB_LOG_ERR("Interface altsetting num overflow\r\n");
return -USB_ERR_NOMEM;
while (1) {
}
}
if (cur_ep_num > CONFIG_USBHOST_MAX_ENDPOINTS) {
USB_LOG_ERR("Endpoint num overflow\r\n");
return -USB_ERR_NOMEM;
while (1) {
}
}
#if 0
USB_LOG_DBG("Interface Descriptor:\r\n");
@@ -339,66 +340,6 @@ static int usbh_get_default_mps(int speed)
}
}
int usbh_free_devaddr(struct usbh_hubport *hport)
{
#ifndef CONFIG_USBHOST_XHCI
if (hport->dev_addr > 0) {
__usbh_free_devaddr(&g_usbh_bus.devgen, hport->dev_addr);
}
#endif
hport->dev_addr = 0;
return 0;
}
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output)
{
struct usb_setup_packet *setup = hport->setup;
int ret;
uint8_t *src;
uint8_t *dst;
uint16_t len;
uint16_t i = 2;
uint16_t j = 0;
/* Get Manufacturer string */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | index);
setup->wIndex = 0x0409;
setup->wLength = 255;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
return ret;
}
src = ep0_request_buffer;
dst = output;
len = src[0];
while (i < len) {
dst[j] = src[i];
i += 2;
j++;
}
return 0;
}
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting)
{
struct usb_setup_packet *setup = hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = intf;
setup->wLength = 0;
return usbh_control_transfer(hport, setup, NULL);
}
int usbh_enumerate(struct usbh_hubport *hport)
{
struct usb_interface_descriptor *intf_desc;
@@ -407,9 +348,11 @@ int usbh_enumerate(struct usbh_hubport *hport)
struct usb_endpoint_descriptor *ep;
int dev_addr;
uint16_t ep_mps;
uint8_t config_value;
uint8_t config_index;
int ret;
hport->setup = &g_setup[hport->parent->index - 1][hport->port - 1];
hport->setup = &g_setup_buffer[hport->bus->busid][hport->parent->index - 1][hport->port - 1];
setup = hport->setup;
ep = &hport->ep0;
@@ -431,16 +374,16 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = 8;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0) {
USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
goto errout;
}
parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer, 8);
parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid], 8);
/* Extract the correct max packetsize from the device descriptor */
dev_desc = (struct usb_device_descriptor *)ep0_request_buffer;
dev_desc = (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid];
if (dev_desc->bcdUSB >= USB_3_0) {
ep_mps = 1 << dev_desc->bMaxPacketSize0;
} else {
@@ -454,23 +397,12 @@ int usbh_enumerate(struct usbh_hubport *hport)
/* Reconfigure EP0 with the correct maximum packet size */
ep->wMaxPacketSize = ep_mps;
#ifdef CONFIG_USBHOST_XHCI
extern int usbh_get_xhci_devaddr(usbh_pipe_t * pipe);
/* Assign a function address to the device connected to this port */
dev_addr = usbh_get_xhci_devaddr(hport->ep0);
dev_addr = usbh_allocate_devaddr(&hport->bus->devgen);
if (dev_addr < 0) {
USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret);
goto errout;
}
#else
/* Assign a function address to the device connected to this port */
dev_addr = usbh_allocate_devaddr(&g_usbh_bus.devgen);
if (dev_addr < 0) {
USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret);
goto errout;
}
#endif
/* Set the USB device address */
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
@@ -498,61 +430,76 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_DEVICE_DESC;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0) {
USB_LOG_ERR("Failed to get full device descriptor,errorcode:%d\r\n", ret);
goto errout;
}
parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer, USB_SIZEOF_DEVICE_DESC);
parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid], USB_SIZEOF_DEVICE_DESC);
USB_LOG_INFO("New device found,idVendor:%04x,idProduct:%04x,bcdDevice:%04x\r\n",
((struct usb_device_descriptor *)ep0_request_buffer)->idVendor,
((struct usb_device_descriptor *)ep0_request_buffer)->idProduct,
((struct usb_device_descriptor *)ep0_request_buffer)->bcdDevice);
((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->idVendor,
((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->idProduct,
((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->bcdDevice);
USB_LOG_INFO("The device has %d bNumConfigurations\r\n", ((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->bNumConfigurations);
config_index = 0;
USB_LOG_DBG("The device selects config %d\r\n", config_index);
/* Read the first 9 bytes of the config descriptor */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | config_index);
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_CONFIG_DESC;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0) {
USB_LOG_ERR("Failed to get config descriptor,errorcode:%d\r\n", ret);
goto errout;
}
parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_request_buffer, USB_SIZEOF_CONFIG_DESC);
parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_request_buffer[hport->bus->busid], USB_SIZEOF_CONFIG_DESC);
/* Read the full size of the configuration data */
uint16_t wTotalLength = ((struct usb_configuration_descriptor *)ep0_request_buffer)->wTotalLength;
uint16_t wTotalLength = ((struct usb_configuration_descriptor *)ep0_request_buffer[hport->bus->busid])->wTotalLength;
if (wTotalLength > CONFIG_USBHOST_REQUEST_BUFFER_LEN) {
ret = -USB_ERR_NOMEM;
USB_LOG_ERR("wTotalLength %d is overflow, default is %d\r\n", wTotalLength, CONFIG_USBHOST_REQUEST_BUFFER_LEN);
goto errout;
}
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | 0);
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | config_index);
setup->wIndex = 0;
setup->wLength = wTotalLength;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0) {
USB_LOG_ERR("Failed to get full config descriptor,errorcode:%d\r\n", ret);
goto errout;
}
ret = parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_request_buffer, wTotalLength);
ret = parse_config_descriptor(hport, (struct usb_configuration_descriptor *)ep0_request_buffer[hport->bus->busid], wTotalLength);
if (ret < 0) {
USB_LOG_ERR("Parse config fail\r\n");
goto errout;
}
USB_LOG_INFO("The device has %d interfaces\r\n", ((struct usb_configuration_descriptor *)ep0_request_buffer)->bNumInterfaces);
hport->raw_config_desc = usb_malloc(wTotalLength);
USB_LOG_INFO("The device has %d interfaces\r\n", ((struct usb_configuration_descriptor *)ep0_request_buffer[hport->bus->busid])->bNumInterfaces);
hport->raw_config_desc = usb_osal_malloc(wTotalLength + 1);
if (hport->raw_config_desc == NULL) {
ret = -USB_ERR_NOMEM;
USB_LOG_ERR("No memory to alloc for raw_config_desc\r\n");
goto errout;
}
memcpy(hport->raw_config_desc, ep0_request_buffer, wTotalLength);
config_value = ((struct usb_configuration_descriptor *)ep0_request_buffer[hport->bus->busid])->bConfigurationValue;
memcpy(hport->raw_config_desc, ep0_request_buffer[hport->bus->busid], wTotalLength);
hport->raw_config_desc[wTotalLength] = '\0';
#ifdef CONFIG_USBHOST_GET_STRING_DESC
uint8_t string_buffer[128];
@@ -589,7 +536,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
/* Select device configuration 1 */
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_SET_CONFIGURATION;
setup->wValue = 1;
setup->wValue = config_value;
setup->wIndex = 0;
setup->wLength = 0;
@@ -606,8 +553,8 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0x0004;
setup->wLength = 16;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0 && (ret != -EPERM)) {
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0 && (ret != -USB_ERR_STALL)) {
USB_LOG_ERR("Failed to get msosv1 compat id,errorcode:%d\r\n", ret);
goto errout;
}
@@ -634,15 +581,56 @@ int usbh_enumerate(struct usbh_hubport *hport)
errout:
if (hport->raw_config_desc) {
usb_free(hport->raw_config_desc);
usb_osal_free(hport->raw_config_desc);
hport->raw_config_desc = NULL;
}
return ret;
}
int usbh_initialize(void)
void usbh_hubport_release(struct usbh_hubport *hport)
{
memset(&g_usbh_bus, 0, sizeof(struct usbh_bus));
if (hport->connected) {
hport->connected = false;
usbh_free_devaddr(hport);
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
if (hport->config.intf[i].class_driver && hport->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(hport, i);
}
}
hport->config.config_desc.bNumInterfaces = 0;
usbh_kill_urb(&hport->ep0_urb);
if (hport->mutex) {
usb_osal_mutex_delete(hport->mutex);
}
}
}
static void usbh_bus_init(struct usbh_bus *bus, uint8_t busid, uintptr_t reg_base)
{
memset(bus, 0, sizeof(struct usbh_bus));
bus->busid = busid;
bus->hcd.hcd_id = busid;
bus->hcd.reg_base = reg_base;
/* devaddr 1 is for roothub */
bus->devgen.next = 2;
usb_slist_add_tail(&g_bus_head, &bus->list);
}
int usbh_initialize(uint8_t busid, uintptr_t reg_base)
{
struct usbh_bus *bus;
if (busid >= CONFIG_USBHOST_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
bus = &g_usbhost_bus[busid];
usbh_bus_init(bus, busid, reg_base);
#ifdef __ARMCC_VERSION /* ARM C Compiler */
extern const int usbh_class_info$$Base;
@@ -654,21 +642,31 @@ int usbh_initialize(void)
extern uint32_t __usbh_class_info_end__;
usbh_class_info_table_begin = (struct usbh_class_info *)&__usbh_class_info_start__;
usbh_class_info_table_end = (struct usbh_class_info *)&__usbh_class_info_end__;
#elif defined(__ICCARM__) || defined(__ICCRX__)
usbh_class_info_table_begin = (struct usbh_class_info *)__section_begin("usbh_class_info");
usbh_class_info_table_end = (struct usbh_class_info *)__section_end("usbh_class_info");
#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
usbh_class_info_table_begin = (struct usbh_class_info *)__section_begin(".usbh_class_info");
usbh_class_info_table_end = (struct usbh_class_info *)__section_end(".usbh_class_info");
#endif
/* devaddr 1 is for roothub */
g_usbh_bus.devgen.next = 2;
usbh_hub_initialize();
usbh_hub_initialize(bus);
return 0;
}
int usbh_deinitialize(void)
int usbh_deinitialize(uint8_t busid)
{
return usbh_hub_deinitialize();
struct usbh_bus *bus;
if (busid >= CONFIG_USBHOST_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
bus = &g_usbhost_bus[busid];
usbh_hub_deinitialize(bus);
usb_slist_remove(&g_bus_head, &bus->list);
return 0;
}
int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *setup, uint8_t *buffer)
@@ -680,7 +678,6 @@ int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *s
usb_osal_mutex_take(hport->mutex);
memset(urb, 0, sizeof(struct usbh_urb));
usbh_control_urb_fill(urb, hport, setup, buffer, setup->wLength, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
@@ -691,20 +688,78 @@ int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *s
return ret;
}
void *usbh_find_class_instance(const char *devname)
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output)
{
struct usb_setup_packet *setup = hport->setup;
int ret;
uint8_t *src;
uint8_t *dst;
uint16_t len;
uint16_t i = 2;
uint16_t j = 0;
/* Get Manufacturer string */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | index);
setup->wIndex = 0x0409;
setup->wLength = 255;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
if (ret < 0) {
return ret;
}
src = ep0_request_buffer[hport->bus->busid];
dst = output;
len = src[0];
while (i < len) {
dst[j] = src[i];
i += 2;
j++;
}
return 0;
}
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting)
{
struct usb_setup_packet *setup = hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = intf;
setup->wLength = 0;
return usbh_control_transfer(hport, setup, NULL);
}
static void *usbh_list_all_interface_name(struct usbh_hub *hub, const char *devname)
{
struct usbh_hubport *hport;
usb_slist_t *hub_list;
struct usbh_hub *hub_next;
void *priv;
usb_slist_for_each(hub_list, &hub_class_head)
{
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];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
if ((strncmp(hport->config.intf[itf].devname, devname, CONFIG_USBHOST_DEV_NAMELEN) == 0) && hport->config.intf[itf].priv)
return hport->config.intf[itf].priv;
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
priv = usbh_list_all_interface_name(hub_next, devname);
if (priv) {
return priv;
}
}
}
}
}
}
@@ -712,10 +767,151 @@ void *usbh_find_class_instance(const char *devname)
return NULL;
}
static void usbh_list_all_interface_driver(struct usbh_hub *hub)
{
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
for (uint8_t j = 0; j < hub->index; j++) {
USB_LOG_RAW("\t");
}
USB_LOG_RAW("|__Port %u, dev addr:0x%02x, If %u, ClassDriver=%s, %s\r\n",
hport->port,
hport->dev_addr,
itf,
hport->config.intf[itf].class_driver->driver_name,
speed_table[hport->speed]);
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
usbh_list_all_interface_driver(hub_next);
}
}
}
}
}
}
}
static void usbh_list_all_interface_desc(struct usbh_bus *bus, struct usbh_hub *hub)
{
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
USB_LOG_RAW("\r\nBus %u, Hub %u, Port %u, dev addr:0x%02x, VID:PID 0x%04x:0x%04x\r\n",
bus->busid,
hub->index,
hport->port,
hport->dev_addr,
hport->device_desc.idVendor,
hport->device_desc.idProduct);
usbh_print_hubport_info(hport);
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
usbh_list_all_interface_desc(bus, hub_next);
}
}
}
}
}
}
}
static struct usbh_hubport *usbh_list_all_hubport(struct usbh_hub *hub, uint8_t hub_index, uint8_t hub_port)
{
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
if (hub->index == hub_index) {
hport = &hub->child[hub_port - 1];
return hport;
} else {
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
hport = usbh_list_all_hubport(hub_next, hub_index, hub_port);
if (hport) {
return hport;
}
}
}
}
}
}
}
}
return NULL;
}
void *usbh_find_class_instance(const char *devname)
{
usb_slist_t *bus_list;
struct usbh_hub *hub;
struct usbh_bus *bus;
void *priv;
size_t flags;
flags = usb_osal_enter_critical_section();
usb_slist_for_each(bus_list, &g_bus_head)
{
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
hub = &bus->hcd.roothub;
priv = usbh_list_all_interface_name(hub, devname);
if (priv) {
usb_osal_leave_critical_section(flags);
return priv;
}
}
usb_osal_leave_critical_section(flags);
return NULL;
}
struct usbh_hubport *usbh_find_hubport(uint8_t busid, uint8_t hub_index, uint8_t hub_port)
{
struct usbh_hub *hub;
struct usbh_bus *bus;
struct usbh_hubport *hport;
size_t flags;
flags = usb_osal_enter_critical_section();
bus = &g_usbhost_bus[busid];
hub = &bus->hcd.roothub;
hport = usbh_list_all_hubport(hub, hub_index, hub_port);
usb_osal_leave_critical_section(flags);
return hport;
}
int lsusb(int argc, char **argv)
{
usb_slist_t *i;
struct usbh_hubport *hport;
usb_slist_t *bus_list;
struct usbh_hub *hub;
struct usbh_bus *bus;
size_t flags;
if (argc < 2) {
USB_LOG_RAW("Usage: lsusb [options]...\r\n");
@@ -738,56 +934,36 @@ int lsusb(int argc, char **argv)
return 0;
}
flags = usb_osal_enter_critical_section();
if (strcmp(argv[1], "-V") == 0) {
USB_LOG_RAW("CherryUSB Version %s\r\n", CHERRYUSB_VERSION_STR);
}
if (strcmp(argv[1], "-t") == 0) {
usb_slist_for_each(i, &hub_class_head)
usb_slist_for_each(bus_list, &g_bus_head)
{
struct usbh_hub *hub = usb_slist_entry(i, struct usbh_hub, list);
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
hub = &bus->hcd.roothub;
if (hub->is_roothub) {
USB_LOG_RAW("/: Hub %02u, ports=%u, is roothub\r\n", hub->index, hub->hub_desc.bNbrPorts);
} else {
USB_LOG_RAW("/: Hub %02u, ports=%u, mounted on Hub %02u:Port %u\r\n",
hub->index,
hub->hub_desc.bNbrPorts,
hub->parent->parent->index,
hub->parent->port);
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
if (hport->config.intf[i].class_driver->driver_name) {
USB_LOG_RAW(" |__Port %u,Port addr:0x%02x,If %u,ClassDriver=%s\r\n",
hport->port,
hport->dev_addr,
i,
hport->config.intf[i].class_driver->driver_name);
}
}
}
}
USB_LOG_RAW("/: Bus %u, Hub %u, ports=%u, is roothub\r\n",
bus->busid,
hub->index,
hub->nports);
usbh_list_all_interface_driver(hub);
}
}
if (strcmp(argv[1], "-v") == 0) {
usb_slist_for_each(i, &hub_class_head)
usb_slist_for_each(bus_list, &g_bus_head)
{
struct usbh_hub *hub = usb_slist_entry(i, struct usbh_hub, list);
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hport = &hub->child[port];
if (hport->connected) {
USB_LOG_RAW("Hub %02u,Port %u,Port addr:0x%02x,VID:PID 0x%04x:0x%04x\r\n",
hub->index,
hport->port,
hport->dev_addr,
hport->device_desc.idVendor,
hport->device_desc.idProduct);
usbh_print_hubport_info(hport);
}
}
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
hub = &bus->hcd.roothub;
usbh_list_all_interface_desc(bus, hub);
}
}
usb_osal_leave_critical_section(flags);
return 0;
}

View File

@@ -20,6 +20,8 @@
#include "usb_hc.h"
#include "usb_osal.h"
#include "usbh_hub.h"
#include "usb_memcpy.h"
#include "usb_version.h"
#ifdef __cplusplus
extern "C" {
@@ -30,37 +32,39 @@ extern "C" {
#define USB_CLASS_MATCH_INTF_CLASS 0x0004
#define USB_CLASS_MATCH_INTF_SUBCLASS 0x0008
#define USB_CLASS_MATCH_INTF_PROTOCOL 0x0010
#define USB_CLASS_MATCH_VID_PID (USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT)
#define CLASS_CONNECT(hport, i) ((hport)->config.intf[i].class_driver->connect(hport, i))
#define CLASS_DISCONNECT(hport, i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
#define CLASS_CONNECT(hport, i) ((hport)->config.intf[i].class_driver->connect(hport, i))
#define CLASS_DISCONNECT(hport, i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
#ifdef __ARMCC_VERSION /* ARM C Compiler */
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
#elif defined(__GNUC__)
#define CLASS_INFO_DEFINE __attribute__((section(".usbh_class_info"))) __USED __ALIGNED(1)
#elif defined(__ICCARM__) || defined(__ICCRX__)
#pragma section = "usbh_class_info"
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
#pragma section = ".usbh_class_info"
#define CLASS_INFO_DEFINE __attribute__((section(".usbh_class_info"))) __USED __ALIGNED(1)
#endif
#define USBH_GET_URB_INTERVAL(interval, speed) (speed < USB_SPEED_HIGH ? interval : (1 << (interval - 1)))
#define USBH_EP_INIT(ep, ep_desc) \
do { \
ep = ep_desc; \
USB_LOG_INFO("Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n", \
ep_desc->bEndpointAddress, \
USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes), \
ep_desc->bmAttributes, \
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize), \
ep_desc->bInterval, \
USB_GET_MULT(ep_desc->bmAttributes)); \
USB_GET_MULT(ep_desc->wMaxPacketSize)); \
} while (0)
struct usbh_class_info {
uint8_t match_flags; /* Used for product specific matches; range is inclusive */
uint8_t class; /* Base device class code */
uint8_t subclass; /* Sub-class, depends on base class. Eg. */
uint8_t protocol; /* Protocol, depends on base class. Eg. */
uint16_t vid; /* Vendor ID (for vendor/product specific devices) */
uint16_t pid; /* Product ID (for vendor/product specific devices) */
uint8_t match_flags; /* Used for product specific matches; range is inclusive */
uint8_t bInterfaceClass; /* Base device class code */
uint8_t bInterfaceSubClass; /* Sub-class, depends on base class. Eg. */
uint8_t bInterfaceProtocol; /* Protocol, depends on base class. Eg. */
const uint16_t (*id_table)[2]; /* List of Vendor/Product ID pairs */
const struct usbh_class_driver *class_driver;
};
@@ -98,6 +102,9 @@ struct usbh_hubport {
uint8_t port; /* Hub port index */
uint8_t dev_addr; /* device address */
uint8_t speed; /* device speed */
uint8_t depth; /* distance from root hub */
uint8_t route; /* route string */
uint8_t slot_id; /* slot id */
struct usb_device_descriptor device_desc;
struct usbh_configuration config;
const char *iManufacturer;
@@ -106,26 +113,60 @@ struct usbh_hubport {
uint8_t *raw_config_desc;
struct usb_setup_packet *setup;
struct usbh_hub *parent;
#ifdef CONFIG_USBHOST_XHCI
uint32_t protocol; /* port protocol, for xhci, some ports are USB2.0, others are USB3.0 */
#endif
struct usbh_hub *self; /* if this hubport is a hub */
struct usbh_bus *bus;
struct usb_endpoint_descriptor ep0;
struct usbh_urb ep0_urb;
usb_osal_mutex_t mutex;
};
struct usbh_hub {
usb_slist_t list;
bool connected;
bool is_roothub;
uint8_t index;
uint8_t hub_addr;
struct usb_hub_descriptor hub_desc;
uint8_t speed;
uint8_t nports;
uint8_t powerdelay;
uint8_t tt_think;
bool ismtt;
struct usb_hub_descriptor hub_desc; /* USB 2.0 only */
struct usb_hub_ss_descriptor hub_ss_desc; /* USB 3.0 only */
struct usbh_hubport child[CONFIG_USBHOST_MAX_EHPORTS];
struct usbh_hubport *parent;
struct usbh_bus *bus;
struct usb_endpoint_descriptor *intin;
struct usbh_urb intin_urb;
uint8_t *int_buffer;
struct usb_osal_timer *int_timer;
};
struct usbh_devaddr_map {
/**
* alloctab[0]:addr from 0~31
* alloctab[1]:addr from 32~63
* alloctab[2]:addr from 64~95
* alloctab[3]:addr from 96~127
*
*/
uint8_t next; /* Next device address */
uint32_t alloctab[4]; /* Bit allocation table */
};
struct usbh_hcd {
uintptr_t reg_base;
uint8_t hcd_id;
uint8_t roothub_intbuf[2]; /* at most 15 roothub ports */
struct usbh_hub roothub;
};
struct usbh_bus {
usb_slist_t list;
uint8_t busid;
struct usbh_hcd hcd;
struct usbh_devaddr_map devgen;
usb_osal_thread_t hub_thread;
usb_osal_mq_t hub_mq;
};
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
@@ -183,8 +224,14 @@ static inline void usbh_int_urb_fill(struct usbh_urb *urb,
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
urb->interval = USBH_GET_URB_INTERVAL(ep->bInterval, hport->speed);
}
extern struct usbh_bus g_usbhost_bus[];
#ifdef USBH_IRQHandler
#error USBH_IRQHandler is obsolete, please call USBH_IRQHandler(xxx) in your irq
#endif
/**
* @brief Submit an control transfer to an endpoint.
* This is a blocking method; this method will not return until the transfer has completed.
@@ -199,11 +246,11 @@ int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *s
/**
* @brief Retrieves a USB string descriptor from a specific hub port.
*
*
* This function is responsible for retrieving the USB string descriptor
* with the specified index from the USB device connected to the given hub port.
* The retrieved descriptor is stored in the output buffer provided.
*
*
* @param hport Pointer to the USB hub port structure.
* @param index Index of the string descriptor to retrieve.
* @param output Pointer to the buffer where the retrieved descriptor will be stored.
@@ -213,11 +260,11 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
/**
* @brief Sets the alternate setting for a USB interface on a specific hub port.
*
*
* This function is responsible for setting the alternate setting of the
* specified USB interface on the USB device connected to the given hub port.
* The interface and alternate setting are identified by the respective parameters.
*
*
* @param hport Pointer to the USB hub port structure.
* @param intf Interface number to set the alternate setting for.
* @param altsetting Alternate setting value to set for the interface.
@@ -225,9 +272,10 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
*/
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting);
int usbh_initialize(void);
int usbh_deinitialize(void);
int usbh_initialize(uint8_t busid, uintptr_t reg_base);
int usbh_deinitialize(uint8_t busid);
void *usbh_find_class_instance(const char *devname);
struct usbh_hubport *usbh_find_hubport(uint8_t busid, uint8_t hub_index, uint8_t hub_port);
int lsusb(int argc, char **argv);

BIN
demo/CherryUSB.h264 Normal file

Binary file not shown.

BIN
demo/CherryUSB.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

BIN
demo/adb/cherryadb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

330
demo/adb/cherrysh_port.c Normal file
View File

@@ -0,0 +1,330 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
#include "csh.h"
#include "usbd_core.h"
#include "usbd_adb.h"
#include "chry_ringbuffer.h"
static chry_ringbuffer_t shell_rb;
static uint8_t mempool[1024];
#ifndef task_repl_PRIORITY
#define task_repl_PRIORITY (configMAX_PRIORITIES - 4U)
#endif
#ifndef task_exec_PRIORITY
#define task_exec_PRIORITY (configMAX_PRIORITIES - 5U)
#endif
static chry_shell_t csh;
static volatile bool login = false;
static StaticTask_t task_buffer_repl;
static StaticTask_t task_buffer_exec;
static StackType_t task_stack_repl[1024];
static StackType_t task_stack_exec[1024];
static TaskHandle_t task_hdl_repl = NULL;
static TaskHandle_t task_hdl_exec = NULL;
static EventGroupHandle_t event_hdl;
static StaticEventGroup_t event_grp;
void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len)
{
chry_ringbuffer_write(&shell_rb, data, len);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR(event_hdl, 0x10, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void usbd_adb_notify_write_done(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR(event_hdl, 0x20, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size)
{
(void)rl;
if (!usb_device_is_configured(0)) {
return size;
}
if (usbd_adb_can_write() && size) {
usbd_abd_write(ADB_SHELL_LOALID, data, size);
xEventGroupWaitBits(event_hdl, 0x20, pdTRUE, pdFALSE, portMAX_DELAY);
}
return size;
}
static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size)
{
(void)rl;
return chry_ringbuffer_read(&shell_rb, data, size);
}
static void wait_char(void)
{
EventBits_t event;
wait:
/* In order to lock the log from being disrupted , wait for REPL task execution to complete */
event = xEventGroupWaitBits(event_hdl, (0x10 | 0x01 | 0x04), pdTRUE, pdFALSE, portMAX_DELAY);
if ((event & 0x10) == 0) {
if (event & 0x01) {
chry_readline_erase_line(&csh.rl);
xEventGroupSetBits(event_hdl, 0x02);
}
if (event & 0x04) {
chry_readline_edit_refresh(&csh.rl);
xEventGroupSetBits(event_hdl, 0x08);
}
goto wait;
}
}
static void task_repl(void *param)
{
(void)param;
int ret;
volatile uint8_t *pexec = (void *)&csh.exec;
for (;;) {
restart:
if (login) {
goto repl;
} else {
}
ret = csh_login(&csh);
if (ret == 0) {
login = true;
} else if (ret == 1) {
/*!< no enough char */
wait_char();
continue;
} else {
continue;
}
repl:
ret = chry_shell_task_repl(&csh);
if (ret == -1) {
/*!< error */
goto restart;
} else if (ret == 1) {
/*!< no enough char */
wait_char();
} else {
/*!< restart */
}
/*!< check flag */
if (*pexec == CSH_STATUS_EXEC_DONE) {
*pexec = CSH_STATUS_EXEC_IDLE;
chry_readline_auto_refresh(&csh.rl, true);
chry_readline_ignore(&csh.rl, false);
chry_readline_edit_refresh(&csh.rl);
}
if (login == false) {
chry_readline_erase_line(&csh.rl);
csh.rl.noblock = false;
}
}
}
static void task_exec(void *param)
{
(void)param;
/*!< execute shell command */
chry_shell_task_exec(&csh);
/*!< notify REPL task execute done */
xEventGroupSetBits(event_hdl, 0x10);
/*!< wait for REPL task delete */
vTaskSuspend(NULL);
}
int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv)
{
volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec;
(void)csh;
(void)argc;
(void)argv;
if (*p_task_hdl_exec != NULL) {
vTaskDelete(*p_task_hdl_exec);
}
*p_task_hdl_exec = xTaskCreateStatic(task_exec, "task_exec", 1024U, NULL, task_exec_PRIORITY, task_stack_exec, &task_buffer_exec);
return 0;
}
void chry_shell_port_default_handler(chry_shell_t *csh, int sig)
{
volatile uint8_t *pexec = (void *)&csh->exec;
volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec;
switch (sig) {
case CSH_SIGINT:
case CSH_SIGQUIT:
case CSH_SIGKILL:
case CSH_SIGTERM:
break;
default:
return;
}
/*!< force delete task */
if (*p_task_hdl_exec != NULL) {
vTaskDelete(task_hdl_exec);
*p_task_hdl_exec = NULL;
}
switch (sig) {
case CSH_SIGINT:
csh->rl.sput(&csh->rl, "^SIGINT" CONFIG_CSH_NEWLINE, sizeof("^SIGINT" CONFIG_CSH_NEWLINE) - 1);
break;
case CSH_SIGQUIT:
csh->rl.sput(&csh->rl, "^SIGQUIT" CONFIG_CSH_NEWLINE, sizeof("^SIGQUIT" CONFIG_CSH_NEWLINE) - 1);
break;
case CSH_SIGKILL:
csh->rl.sput(&csh->rl, "^SIGKILL" CONFIG_CSH_NEWLINE, sizeof("^SIGKILL" CONFIG_CSH_NEWLINE) - 1);
break;
case CSH_SIGTERM:
csh->rl.sput(&csh->rl, "^SIGTERM" CONFIG_CSH_NEWLINE, sizeof("^SIGTERM" CONFIG_CSH_NEWLINE) - 1);
break;
default:
return;
}
*pexec = CSH_STATUS_EXEC_IDLE;
chry_readline_auto_refresh(&csh->rl, true);
chry_readline_ignore(&csh->rl, false);
chry_readline_edit_refresh(&csh->rl);
}
int shell_init(bool need_login)
{
chry_shell_init_t csh_init;
if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) {
return -1;
}
if (need_login) {
login = false;
} else {
login = true;
}
/*!< I/O callback */
csh_init.sput = csh_sput_cb;
csh_init.sget = csh_sget_cb;
#if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB
extern const int __fsymtab_start;
extern const int __fsymtab_end;
extern const int __vsymtab_start;
extern const int __vsymtab_end;
/*!< get table from ld symbol */
csh_init.command_table_beg = &__fsymtab_start;
csh_init.command_table_end = &__fsymtab_end;
csh_init.variable_table_beg = &__vsymtab_start;
csh_init.variable_table_end = &__vsymtab_end;
#endif
#if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
static char csh_prompt_buffer[128];
/*!< set prompt buffer */
csh_init.prompt_buffer = csh_prompt_buffer;
csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer);
#endif
#if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY
static char csh_history_buffer[128];
/*!< set history buffer */
csh_init.history_buffer = csh_history_buffer;
csh_init.history_buffer_size = sizeof(csh_history_buffer);
#endif
#if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC
static char csh_line_buffer[128];
/*!< set linebuffer */
csh_init.line_buffer = csh_line_buffer;
csh_init.line_buffer_size = sizeof(csh_line_buffer);
#endif
csh_init.uid = 0;
csh_init.user[0] = "cherry";
/*!< The port hash function is required,
and the strcmp attribute is used weakly by default,
int chry_shell_port_hash_strcmp(const char *hash, const char *str); */
csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */
csh_init.host = "cherryadb";
csh_init.user_data = NULL;
int ret = chry_shell_init(&csh, &csh_init);
if (ret) {
return -1;
}
task_hdl_exec = NULL;
event_hdl = xEventGroupCreateStatic(&event_grp);
task_hdl_repl = xTaskCreateStatic(task_repl, "task_repl", 1024U, NULL, task_repl_PRIORITY, task_stack_repl, &task_buffer_repl);
return 0;
}
void shell_lock(void)
{
xEventGroupSetBits(event_hdl, 0x01);
xEventGroupWaitBits(event_hdl, 0x02, pdTRUE, pdTRUE, portMAX_DELAY);
}
void shell_unlock(void)
{
xEventGroupSetBits(event_hdl, 0x04);
xEventGroupWaitBits(event_hdl, 0x08, pdTRUE, pdTRUE, portMAX_DELAY);
}
static int csh_exit(int argc, char **argv)
{
(void)argc;
(void)argv;
usbd_adb_close(ADB_SHELL_LOALID);
return 0;
}
CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, );
#define __ENV_PATH "/sbin:/bin"
const char ENV_PATH[] = __ENV_PATH;
CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH));
#define __ENV_ZERO ""
const char ENV_ZERO[] = __ENV_ZERO;
CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO));

View File

@@ -0,0 +1,228 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_adb.h"
/*!< endpoint address */
#define WINUSB_IN_EP 0x81
#define WINUSB_OUT_EP 0x02
#define USBD_VID 0xFFFF
#define USBD_PID 0xFFFF
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7)
#ifdef CONFIG_USB_HS
#define WINUSB_MAX_MPS 512
#else
#define WINUSB_MAX_MPS 64
#endif
#define WCID_VENDOR_CODE 0x17
#define ADB_INTF_NUM 0
__ALIGN_BEGIN const uint8_t WCID_StringDescriptor_MSOS[18] __ALIGN_END = {
///////////////////////////////////////
/// MS OS string descriptor
///////////////////////////////////////
0x12, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
/* MSFT100 */
'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, /* wcChar_7 */
'1', 0x00, '0', 0x00, '0', 0x00, /* wcChar_7 */
WCID_VENDOR_CODE, /* bVendorCode */
0x00, /* bReserved */
};
__ALIGN_BEGIN const uint8_t WINUSB_WCIDDescriptor[40] __ALIGN_END = {
///////////////////////////////////////
/// WCID descriptor
///////////////////////////////////////
0x28, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x04, 0x00, /* wIndex */
0x01, /* bCount */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_7 */
///////////////////////////////////////
/// WCID function descriptor
///////////////////////////////////////
ADB_INTF_NUM, /* bFirstInterfaceNumber */
0x01, /* bReserved */
/* Compatible ID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, /* cCID_8: WINUSB */
/* */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cSubCID_8 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_6 */
};
__ALIGN_BEGIN const uint8_t WINUSB_IF0_WCIDProperties[142] __ALIGN_END = {
///////////////////////////////////////
/// WCID property descriptor
///////////////////////////////////////
0x8e, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x05, 0x00, /* wIndex */
0x01, 0x00, /* wCount */
///////////////////////////////////////
/// registry propter descriptor
///////////////////////////////////////
0x84, 0x00, 0x00, 0x00, /* dwSize */
0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType */
0x28, 0x00, /* wPropertyNameLength */
/* DeviceInterfaceGUID */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, /* wcName_20 */
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, /* wcName_20 */
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, /* wcName_20 */
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, /* wcName_20 */
'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, /* wcName_20 */
0x4e, 0x00, 0x00, 0x00, /* dwPropertyDataLength */
/* {1D4B2365-4749-48EA-B38A-7C6FDDDD7E26} */
'{', 0x00, '1', 0x00, 'D', 0x00, '4', 0x00, /* wcData_39 */
'B', 0x00, '2', 0x00, '3', 0x00, '6', 0x00, /* wcData_39 */
'5', 0x00, '-', 0x00, '4', 0x00, '7', 0x00, /* wcData_39 */
'4', 0x00, '9', 0x00, '-', 0x00, '4', 0x00, /* wcData_39 */
'8', 0x00, 'E', 0x00, 'A', 0x00, '-', 0x00, /* wcData_39 */
'B', 0x00, '3', 0x00, '8', 0x00, 'A', 0x00, /* wcData_39 */
'-', 0x00, '7', 0x00, 'C', 0x00, '6', 0x00, /* wcData_39 */
'F', 0x00, 'D', 0x00, 'D', 0x00, 'D', 0x00, /* wcData_39 */
'D', 0x00, '7', 0x00, 'E', 0x00, '2', 0x00, /* wcData_39 */
'6', 0x00, '}', 0x00, 0x00, 0x00, /* wcData_39 */
};
const uint8_t *WINUSB_IFx_WCIDProperties[] = {
WINUSB_IF0_WCIDProperties,
};
struct usb_msosv1_descriptor msosv1_desc = {
.string = WCID_StringDescriptor_MSOS,
.vendor_code = WCID_VENDOR_CODE,
.compat_id = WINUSB_WCIDDescriptor,
.comp_id_property = WINUSB_IFx_WCIDProperties,
};
/*!< global descriptor */
static const uint8_t adb_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01),
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, WINUSB_MAX_MPS),
///////////////////////////////////////
/// string0 descriptor
///////////////////////////////////////
USB_LANGID_INIT(USBD_LANGID_STRING),
///////////////////////////////////////
/// string1 descriptor
///////////////////////////////////////
0x14, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
///////////////////////////////////////
/// string2 descriptor
///////////////////////////////////////
0x14, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'A', 0x00, /* wcChar6 */
'D', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
///////////////////////////////////////
/// string3 descriptor
///////////////////////////////////////
0x1C, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'A', 0x00, /* wcChar6 */
'D', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
'2', 0x00, /* wcChar9 */
'0', 0x00, /* wcChar10 */
'2', 0x00, /* wcChar11 */
'4', 0x00, /* wcChar12 */
#ifdef CONFIG_USB_HS
///////////////////////////////////////
/// device qualifier descriptor
///////////////////////////////////////
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x02,
0x02,
0x01,
0x40,
0x00,
0x00,
#endif
0x00
};
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
static struct usbd_interface intf0;
extern int shell_init(bool need_login);
void cherryadb_init(uint8_t busid, uint32_t reg_base)
{
/* default password is : 12345678 */
/* shell_init() must be called in-task */
if (0 != shell_init(false)) {
/* shell failed to be initialized */
printf("Failed to initialize shell\r\n");
for (;;) {
;
}
}
usbd_desc_register(busid, adb_descriptor);
usbd_add_interface(busid, usbd_adb_init_intf(busid, &intf0, WINUSB_IN_EP, WINUSB_OUT_EP));
usbd_initialize(busid, reg_base, usbd_event_handler);
}

View File

@@ -1,3 +1,8 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_audio.h"
@@ -139,7 +144,7 @@ const uint8_t audio_v1_descriptor[] = {
0x00,
0x00,
0x40,
0x01,
0x00,
0x00,
#endif
0x00
@@ -148,7 +153,7 @@ const uint8_t audio_v1_descriptor[] = {
volatile bool tx_flag = 0;
volatile bool ep_tx_busy_flag = false;
void usbd_event_handler(uint8_t event)
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
@@ -173,19 +178,21 @@ void usbd_event_handler(uint8_t event)
}
}
void usbd_audio_open(uint8_t intf)
void usbd_audio_open(uint8_t busid, uint8_t intf)
{
tx_flag = 1;
ep_tx_busy_flag = false;
USB_LOG_RAW("OPEN\r\n");
}
void usbd_audio_close(uint8_t intf)
void usbd_audio_close(uint8_t busid, uint8_t intf)
{
USB_LOG_RAW("CLOSE\r\n");
ep_tx_busy_flag = false;
tx_flag = 0;
}
void usbd_audio_iso_callback(uint8_t ep, uint32_t nbytes)
void usbd_audio_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
ep_tx_busy_flag = false;
@@ -205,25 +212,25 @@ struct audio_entity_info audio_entity_table[] = {
.ep = AUDIO_IN_EP },
};
void audio_v1_init(void)
void audio_v1_init(uint8_t busid, uintptr_t reg_base)
{
usbd_desc_register(audio_v1_descriptor);
usbd_add_interface(usbd_audio_init_intf(&intf0, 0x0100, audio_entity_table, 1));
usbd_add_interface(usbd_audio_init_intf(&intf1, 0x0100, audio_entity_table, 1));
usbd_add_endpoint(&audio_in_ep);
usbd_desc_register(busid, audio_v1_descriptor);
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0100, audio_entity_table, 1));
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0100, audio_entity_table, 1));
usbd_add_endpoint(busid, &audio_in_ep);
usbd_initialize();
usbd_initialize(busid, reg_base, usbd_event_handler);
}
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[AUDIO_IN_PACKET];
void audio_test()
void audio_test(uint8_t busid)
{
while (1) {
if (tx_flag) {
memset(write_buffer, 'a', AUDIO_IN_PACKET);
ep_tx_busy_flag = true;
usbd_ep_start_write(AUDIO_IN_EP, write_buffer, AUDIO_IN_PACKET);
usbd_ep_start_write(busid, AUDIO_IN_EP, write_buffer, AUDIO_IN_PACKET);
while (ep_tx_busy_flag) {
if (tx_flag == false) {
break;

View File

@@ -1,3 +1,8 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_audio.h"
@@ -134,7 +139,7 @@ const uint8_t audio_v1_descriptor[] = {
0x00,
0x00,
0x40,
0x01,
0x00,
0x00,
#endif
0x00
@@ -147,7 +152,7 @@ volatile bool tx_flag = 0;
volatile bool rx_flag = 0;
volatile bool ep_tx_busy_flag = false;
void usbd_event_handler(uint8_t event)
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
@@ -172,37 +177,39 @@ void usbd_event_handler(uint8_t event)
}
}
void usbd_audio_open(uint8_t intf)
void usbd_audio_open(uint8_t busid, uint8_t intf)
{
if (intf == 1) {
rx_flag = 1;
/* setup first out ep read transfer */
usbd_ep_start_read(AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
usbd_ep_start_read(busid, AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
printf("OPEN1\r\n");
} else {
tx_flag = 1;
ep_tx_busy_flag = false;
printf("OPEN2\r\n");
}
}
void usbd_audio_close(uint8_t intf)
void usbd_audio_close(uint8_t busid, uint8_t intf)
{
if (intf == 1) {
rx_flag = 1;
rx_flag = 0;
printf("CLOSE1\r\n");
} else {
tx_flag = 0;
ep_tx_busy_flag = false;
printf("CLOSE2\r\n");
}
}
void usbd_audio_out_callback(uint8_t ep, uint32_t nbytes)
void usbd_audio_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", nbytes);
usbd_ep_start_read(AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
usbd_ep_start_read(busid, AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
}
void usbd_audio_in_callback(uint8_t ep, uint32_t nbytes)
void usbd_audio_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
ep_tx_busy_flag = false;
@@ -231,24 +238,24 @@ struct audio_entity_info audio_entity_table[] = {
.ep = AUDIO_OUT_EP },
};
void audio_v1_init(void)
void audio_v1_init(uint8_t busid, uintptr_t reg_base)
{
usbd_desc_register(audio_v1_descriptor);
usbd_add_interface(usbd_audio_init_intf(&intf0, 0x0100, audio_entity_table, 2));
usbd_add_interface(usbd_audio_init_intf(&intf1, 0x0100, audio_entity_table, 2));
usbd_add_interface(usbd_audio_init_intf(&intf2, 0x0100, audio_entity_table, 2));
usbd_add_endpoint(&audio_in_ep);
usbd_add_endpoint(&audio_out_ep);
usbd_desc_register(busid, audio_v1_descriptor);
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0100, audio_entity_table, 2));
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0100, audio_entity_table, 2));
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf2, 0x0100, audio_entity_table, 2));
usbd_add_endpoint(busid, &audio_in_ep);
usbd_add_endpoint(busid, &audio_out_ep);
usbd_initialize();
usbd_initialize(busid, reg_base, usbd_event_handler);
}
void audio_v1_test(void)
void audio_v1_test(uint8_t busid)
{
if (tx_flag) {
memset(write_buffer, 'a', AUDIO_IN_PACKET);
ep_tx_busy_flag = true;
usbd_ep_start_write(AUDIO_IN_EP, write_buffer, AUDIO_IN_PACKET);
usbd_ep_start_write(busid, AUDIO_IN_EP, write_buffer, AUDIO_IN_PACKET);
while (ep_tx_busy_flag) {
if (tx_flag == false) {
break;

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