• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbh_core.h"
7 #include "usbh_hid.h"
8 
9 #define DEV_FORMAT "/dev/input%d"
10 
11 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[128];
12 
13 static struct usbh_hid g_hid_class[CONFIG_USBHOST_MAX_HID_CLASS];
14 static uint32_t g_devinuse = 0;
15 
usbh_hid_class_alloc(void)16 static struct usbh_hid *usbh_hid_class_alloc(void)
17 {
18     int devno;
19 
20     for (devno = 0; devno < CONFIG_USBHOST_MAX_HID_CLASS; devno++) {
21         if ((g_devinuse & (1 << devno)) == 0) {
22             g_devinuse |= (1 << devno);
23             memset(&g_hid_class[devno], 0, sizeof(struct usbh_hid));
24             g_hid_class[devno].minor = devno;
25             return &g_hid_class[devno];
26         }
27     }
28     return NULL;
29 }
30 
usbh_hid_class_free(struct usbh_hid * hid_class)31 static void usbh_hid_class_free(struct usbh_hid *hid_class)
32 {
33     int devno = hid_class->minor;
34 
35     if (devno >= 0 && devno < 32) {
36         g_devinuse &= ~(1 << devno);
37     }
38     memset(hid_class, 0, sizeof(struct usbh_hid));
39 }
40 
usbh_hid_get_report_descriptor(struct usbh_hid * hid_class,uint8_t * buffer)41 static int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer)
42 {
43     struct usb_setup_packet *setup = hid_class->hport->setup;
44     int ret;
45 
46     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
47     setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
48     setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
49     setup->wIndex = hid_class->intf;
50     setup->wLength = 128;
51 
52     ret = usbh_control_transfer(hid_class->hport->ep0, setup, g_hid_buf);
53     if (ret < 0) {
54         return ret;
55     }
56     memcpy(buffer, g_hid_buf, ret - 8);
57     return ret;
58 }
59 
usbh_hid_set_idle(struct usbh_hid * hid_class,uint8_t report_id,uint8_t duration)60 int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration)
61 {
62     struct usb_setup_packet *setup = hid_class->hport->setup;
63 
64     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
65     setup->bRequest = HID_REQUEST_SET_IDLE;
66     setup->wValue = (duration << 8) | report_id;
67     setup->wIndex = hid_class->intf;
68     setup->wLength = 0;
69 
70     return usbh_control_transfer(hid_class->hport->ep0, setup, NULL);
71 }
72 
usbh_hid_get_idle(struct usbh_hid * hid_class,uint8_t * buffer)73 int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
74 {
75     struct usb_setup_packet *setup = hid_class->hport->setup;
76     int ret;
77 
78     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
79     setup->bRequest = HID_REQUEST_GET_IDLE;
80     setup->wValue = 0;
81     setup->wIndex = hid_class->intf;
82     setup->wLength = 1;
83 
84     ret = usbh_control_transfer(hid_class->hport->ep0, setup, g_hid_buf);
85     if (ret < 0) {
86         return ret;
87     }
88     memcpy(buffer, g_hid_buf, 1);
89     return ret;
90 }
91 
usbh_hid_set_protocol(struct usbh_hid * hid_class,uint8_t protocol)92 int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
93 {
94     struct usb_setup_packet *setup = hid_class->hport->setup;
95 
96     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
97     setup->bRequest = HID_REQUEST_SET_PROTOCOL;
98     setup->wValue = protocol;
99     setup->wIndex = 0;
100     setup->wLength = 0;
101 
102     return usbh_control_transfer(hid_class->hport->ep0, setup, NULL);
103 }
104 
usbh_hid_connect(struct usbh_hubport * hport,uint8_t intf)105 int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
106 {
107     struct usb_endpoint_descriptor *ep_desc;
108     int ret;
109 
110     struct usbh_hid *hid_class = usbh_hid_class_alloc();
111     if (hid_class == NULL) {
112         USB_LOG_ERR("Fail to alloc hid_class\r\n");
113         return -ENOMEM;
114     }
115 
116     hid_class->hport = hport;
117     hid_class->intf = intf;
118 
119     hport->config.intf[intf].priv = hid_class;
120 
121     // /* 0x0 = boot protocol, 0x1 = report protocol */
122     // ret = usbh_hid_set_protocol(hid_class, 0x1);
123     // if (ret < 0) {
124     //     return ret;
125     // }
126 
127     ret = usbh_hid_set_idle(hid_class, 0, 0);
128     if (ret < 0) {
129         USB_LOG_WRN("Do not support set idle\r\n");
130     }
131 
132     ret = usbh_hid_get_report_descriptor(hid_class, hid_class->report_desc);
133     if (ret < 0) {
134         return ret;
135     }
136 
137     for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
138         ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
139         if (ep_desc->bEndpointAddress & 0x80) {
140             usbh_hport_activate_epx(&hid_class->intin, hport, ep_desc);
141         } else {
142             usbh_hport_activate_epx(&hid_class->intout, hport, ep_desc);
143         }
144     }
145 
146     snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hid_class->minor);
147 
148     USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
149 
150     usbh_hid_run(hid_class);
151     return ret;
152 }
153 
usbh_hid_disconnect(struct usbh_hubport * hport,uint8_t intf)154 int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
155 {
156     int ret = 0;
157 
158     struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
159 
160     if (hid_class) {
161         if (hid_class->intin) {
162             usbh_pipe_free(hid_class->intin);
163         }
164 
165         if (hid_class->intout) {
166             usbh_pipe_free(hid_class->intout);
167         }
168 
169         if (hport->config.intf[intf].devname[0] != '\0') {
170             USB_LOG_INFO("Unregister HID Class:%s\r\n", hport->config.intf[intf].devname);
171             usbh_hid_stop(hid_class);
172         }
173 
174         usbh_hid_class_free(hid_class);
175     }
176 
177     return ret;
178 }
179 
usbh_hid_run(struct usbh_hid * hid_class)180 __WEAK void usbh_hid_run(struct usbh_hid *hid_class)
181 {
182 }
183 
usbh_hid_stop(struct usbh_hid * hid_class)184 __WEAK void usbh_hid_stop(struct usbh_hid *hid_class)
185 {
186 }
187 
188 const struct usbh_class_driver hid_class_driver = {
189     .driver_name = "hid",
190     .connect = usbh_hid_connect,
191     .disconnect = usbh_hid_disconnect
192 };
193 
194 CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
195     .match_flags = USB_CLASS_MATCH_INTF_CLASS,
196     .class = USB_DEVICE_CLASS_HID,
197     .subclass = 0x00,
198     .protocol = 0x00,
199     .vid = 0x00,
200     .pid = 0x00,
201     .class_driver = &hid_class_driver
202 };
203