1 /*
2  * Copyright (c) 2022, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_cdc_acm.h"
8 
9 const char *stop_name[] = { "1", "1.5", "2" };
10 const char *parity_name[] = { "N", "O", "E", "M", "S" };
11 
cdc_acm_class_interface_request_handler(uint8_t busid,struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)12 static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
13 {
14     USB_LOG_DBG("CDC Class request: "
15                 "bRequest 0x%02x\r\n",
16                 setup->bRequest);
17 
18     struct cdc_line_coding line_coding;
19     bool dtr, rts;
20     uint8_t intf_num = LO_BYTE(setup->wIndex);
21 
22     switch (setup->bRequest) {
23         case CDC_REQUEST_SET_LINE_CODING:
24 
25             /*******************************************************************************/
26             /* Line Coding Structure                                                       */
27             /*-----------------------------------------------------------------------------*/
28             /* Offset | Field       | Size | Value  | Description                          */
29             /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
30             /* 4      | bCharFormat |   1  | Number | Stop bits                            */
31             /*                                        0 - 1 Stop bit                       */
32             /*                                        1 - 1.5 Stop bits                    */
33             /*                                        2 - 2 Stop bits                      */
34             /* 5      | bParityType |  1   | Number | Parity                               */
35             /*                                        0 - None                             */
36             /*                                        1 - Odd                              */
37             /*                                        2 - Even                             */
38             /*                                        3 - Mark                             */
39             /*                                        4 - Space                            */
40             /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
41             /*******************************************************************************/
42             memcpy(&line_coding, *data, setup->wLength);
43             USB_LOG_DBG("Set intf:%d linecoding <%d %d %s %s>\r\n",
44                         intf_num,
45                         (unsigned int)line_coding.dwDTERate,
46                         line_coding.bDataBits,
47                         parity_name[line_coding.bParityType],
48                         stop_name[line_coding.bCharFormat]);
49 
50             usbd_cdc_acm_set_line_coding(busid, intf_num, &line_coding);
51             break;
52 
53         case CDC_REQUEST_SET_CONTROL_LINE_STATE:
54             dtr = (setup->wValue & 0x0001);
55             rts = (setup->wValue & 0x0002);
56             USB_LOG_DBG("Set intf:%d DTR 0x%x,RTS 0x%x\r\n",
57                         intf_num,
58                         dtr,
59                         rts);
60             usbd_cdc_acm_set_dtr(busid, intf_num, dtr);
61             usbd_cdc_acm_set_rts(busid, intf_num, rts);
62             break;
63 
64         case CDC_REQUEST_GET_LINE_CODING:
65             usbd_cdc_acm_get_line_coding(busid, intf_num, &line_coding);
66             memcpy(*data, &line_coding, 7);
67             *len = 7;
68             USB_LOG_DBG("Get intf:%d linecoding %d %d %d %d\r\n",
69                         intf_num,
70                         (unsigned int)line_coding.dwDTERate,
71                         line_coding.bCharFormat,
72                         line_coding.bParityType,
73                         line_coding.bDataBits);
74             break;
75         case CDC_REQUEST_SEND_BREAK:
76             usbd_cdc_acm_send_break(busid, intf_num);
77             break;
78         default:
79             USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
80             return -1;
81     }
82 
83     return 0;
84 }
85 
usbd_cdc_acm_init_intf(uint8_t busid,struct usbd_interface * intf)86 struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf)
87 {
88     (void)busid;
89 
90     intf->class_interface_handler = cdc_acm_class_interface_request_handler;
91     intf->class_endpoint_handler = NULL;
92     intf->vendor_handler = NULL;
93     intf->notify_handler = NULL;
94 
95     return intf;
96 }
97 
usbd_cdc_acm_set_line_coding(uint8_t busid,uint8_t intf,struct cdc_line_coding * line_coding)98 __WEAK void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
99 {
100     (void)busid;
101     (void)intf;
102     (void)line_coding;
103 }
104 
usbd_cdc_acm_get_line_coding(uint8_t busid,uint8_t intf,struct cdc_line_coding * line_coding)105 __WEAK void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
106 {
107     (void)busid;
108     (void)intf;
109 
110     line_coding->dwDTERate = 2000000;
111     line_coding->bDataBits = 8;
112     line_coding->bParityType = 0;
113     line_coding->bCharFormat = 0;
114 }
115 
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)116 __WEAK void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
117 {
118     (void)busid;
119     (void)intf;
120     (void)dtr;
121 }
122 
usbd_cdc_acm_set_rts(uint8_t busid,uint8_t intf,bool rts)123 __WEAK void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts)
124 {
125     (void)busid;
126     (void)intf;
127     (void)rts;
128 }
129 
usbd_cdc_acm_send_break(uint8_t busid,uint8_t intf)130 __WEAK void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf)
131 {
132     (void)busid;
133     (void)intf;
134 }
135