1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017-11-16 ZYH first version
9 */
10 #include <rthw.h>
11 #include <rtthread.h>
12 #include <rtservice.h>
13 #include <rtdevice.h>
14 #include <drivers/usb_device.h>
15 #include "winusb.h"
16 struct winusb_device
17 {
18 struct rt_device parent;
19 void (*cmd_handler)(rt_uint8_t *buffer,rt_size_t size);
20 rt_uint8_t cmd_buff[256];
21 uep_t ep_out;
22 uep_t ep_in;
23 };
24
25 typedef struct winusb_device * winusb_device_t;
26
27 ALIGN(4)
28 static struct udevice_descriptor dev_desc =
29 {
30 USB_DESC_LENGTH_DEVICE, //bLength;
31 USB_DESC_TYPE_DEVICE, //type;
32 USB_BCD_VERSION, //bcdUSB;
33 0x00, //bDeviceClass;
34 0x00, //bDeviceSubClass;
35 0x00, //bDeviceProtocol;
36 0x40, //bMaxPacketSize0;
37 _VENDOR_ID, //idVendor;
38 _PRODUCT_ID, //idProduct;
39 USB_BCD_DEVICE, //bcdDevice;
40 USB_STRING_MANU_INDEX, //iManufacturer;
41 USB_STRING_PRODUCT_INDEX, //iProduct;
42 USB_STRING_SERIAL_INDEX, //iSerialNumber;
43 USB_DYNAMIC, //bNumConfigurations;
44 };
45
46 //FS and HS needed
47 ALIGN(4)
48 static struct usb_qualifier_descriptor dev_qualifier =
49 {
50 sizeof(dev_qualifier), //bLength
51 USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
52 0x0200, //bcdUSB
53 0xFF, //bDeviceClass
54 0x00, //bDeviceSubClass
55 0x00, //bDeviceProtocol
56 64, //bMaxPacketSize0
57 0x01, //bNumConfigurations
58 0,
59 };
60
61 ALIGN(4)
62 struct winusb_descriptor _winusb_desc =
63 {
64 #ifdef RT_USB_DEVICE_COMPOSITE
65 /* Interface Association Descriptor */
66 {
67 USB_DESC_LENGTH_IAD,
68 USB_DESC_TYPE_IAD,
69 USB_DYNAMIC,
70 0x01,
71 0xFF,
72 0x00,
73 0x00,
74 0x00,
75 },
76 #endif
77 /*interface descriptor*/
78 {
79 USB_DESC_LENGTH_INTERFACE, //bLength;
80 USB_DESC_TYPE_INTERFACE, //type;
81 USB_DYNAMIC, //bInterfaceNumber;
82 0x00, //bAlternateSetting;
83 0x02, //bNumEndpoints
84 0xFF, //bInterfaceClass;
85 0x00, //bInterfaceSubClass;
86 0x00, //bInterfaceProtocol;
87 0x00, //iInterface;
88 },
89 /*endpoint descriptor*/
90 {
91 USB_DESC_LENGTH_ENDPOINT,
92 USB_DESC_TYPE_ENDPOINT,
93 USB_DYNAMIC | USB_DIR_OUT,
94 USB_EP_ATTR_BULK,
95 USB_DYNAMIC,
96 0x00,
97 },
98 /*endpoint descriptor*/
99 {
100 USB_DESC_LENGTH_ENDPOINT,
101 USB_DESC_TYPE_ENDPOINT,
102 USB_DYNAMIC | USB_DIR_IN,
103 USB_EP_ATTR_BULK,
104 USB_DYNAMIC,
105 0x00,
106 },
107 };
108
109 ALIGN(4)
110 const static char* _ustring[] =
111 {
112 "Language",
113 "RT-Thread Team.",
114 "RTT Win USB",
115 "32021919830108",
116 "Configuration",
117 "Interface",
118 USB_STRING_OS//must be
119 };
120
121 ALIGN(4)
122 struct usb_os_proerty winusb_proerty[] =
123 {
124 USB_OS_PROERTY_DESC(USB_OS_PROERTY_TYPE_REG_SZ,"DeviceInterfaceGUID",RT_WINUSB_GUID),
125 };
126
127 ALIGN(4)
128 struct usb_os_function_comp_id_descriptor winusb_func_comp_id_desc =
129 {
130 .bFirstInterfaceNumber = USB_DYNAMIC,
131 .reserved1 = 0x01,
132 .compatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00},
133 .subCompatibleID = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
134 .reserved2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
135 };
136
_ep_out_handler(ufunction_t func,rt_size_t size)137 static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
138 {
139 winusb_device_t winusb_device = (winusb_device_t)func->user_data;
140 if(winusb_device->parent.rx_indicate != RT_NULL)
141 {
142 winusb_device->parent.rx_indicate(&winusb_device->parent, size);
143 }
144 return RT_EOK;
145 }
146
_ep_in_handler(ufunction_t func,rt_size_t size)147 static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
148 {
149 winusb_device_t winusb_device = (winusb_device_t)func->user_data;
150 if(winusb_device->parent.tx_complete != RT_NULL)
151 {
152 winusb_device->parent.tx_complete(&winusb_device->parent, winusb_device->ep_in->buffer);
153 }
154 return RT_EOK;
155 }
156 static ufunction_t cmd_func = RT_NULL;
_ep0_cmd_handler(udevice_t device,rt_size_t size)157 static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
158 {
159 winusb_device_t winusb_device;
160
161 if(cmd_func != RT_NULL)
162 {
163 winusb_device = (winusb_device_t)cmd_func->user_data;
164 cmd_func = RT_NULL;
165 if(winusb_device->cmd_handler != RT_NULL)
166 {
167 winusb_device->cmd_handler(winusb_device->cmd_buff,size);
168 }
169 }
170 dcd_ep0_send_status(device->dcd);
171 return RT_EOK;
172 }
_ep0_cmd_read(ufunction_t func,ureq_t setup)173 static rt_err_t _ep0_cmd_read(ufunction_t func, ureq_t setup)
174 {
175 winusb_device_t winusb_device = (winusb_device_t)func->user_data;
176 cmd_func = func;
177 rt_usbd_ep0_read(func->device,winusb_device->cmd_buff,setup->wLength,_ep0_cmd_handler);
178 return RT_EOK;
179 }
_interface_handler(ufunction_t func,ureq_t setup)180 static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
181 {
182 switch(setup->bRequest)
183 {
184 case 'A':
185 switch(setup->wIndex)
186 {
187 case 0x05:
188 usbd_os_proerty_descriptor_send(func,setup,winusb_proerty,sizeof(winusb_proerty)/sizeof(winusb_proerty[0]));
189 break;
190 }
191 break;
192 case 0x0A://customer
193 _ep0_cmd_read(func, setup);
194 break;
195 }
196
197 return RT_EOK;
198 }
_function_enable(ufunction_t func)199 static rt_err_t _function_enable(ufunction_t func)
200 {
201 RT_ASSERT(func != RT_NULL);
202 return RT_EOK;
203 }
_function_disable(ufunction_t func)204 static rt_err_t _function_disable(ufunction_t func)
205 {
206 RT_ASSERT(func != RT_NULL);
207 return RT_EOK;
208 }
209
210 static struct ufunction_ops ops =
211 {
212 _function_enable,
213 _function_disable,
214 RT_NULL,
215 };
216
_winusb_descriptor_config(winusb_desc_t winusb,rt_uint8_t cintf_nr,rt_uint8_t device_is_hs)217 static rt_err_t _winusb_descriptor_config(winusb_desc_t winusb, rt_uint8_t cintf_nr, rt_uint8_t device_is_hs)
218 {
219 #ifdef RT_USB_DEVICE_COMPOSITE
220 winusb->iad_desc.bFirstInterface = cintf_nr;
221 #endif
222 winusb->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
223 winusb->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
224 winusb_func_comp_id_desc.bFirstInterfaceNumber = cintf_nr;
225 return RT_EOK;
226 }
227
win_usb_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)228 static rt_size_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
229 {
230 if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
231 {
232 return 0;
233 }
234 winusb_device_t winusb_device = (winusb_device_t)dev;
235 winusb_device->ep_out->buffer = buffer;
236 winusb_device->ep_out->request.buffer = buffer;
237 winusb_device->ep_out->request.size = size;
238 winusb_device->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
239 rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_out,&winusb_device->ep_out->request);
240 return size;
241 }
win_usb_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)242 static rt_size_t win_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
243 {
244 if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
245 {
246 return 0;
247 }
248 winusb_device_t winusb_device = (winusb_device_t)dev;
249 winusb_device->ep_in->buffer = (void *)buffer;
250 winusb_device->ep_in->request.buffer = winusb_device->ep_in->buffer;
251 winusb_device->ep_in->request.size = size;
252 winusb_device->ep_in->request.req_type = UIO_REQUEST_WRITE;
253 rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_in,&winusb_device->ep_in->request);
254 return size;
255 }
win_usb_control(rt_device_t dev,int cmd,void * args)256 static rt_err_t win_usb_control(rt_device_t dev, int cmd, void *args)
257 {
258 winusb_device_t winusb_device = (winusb_device_t)dev;
259 if(RT_DEVICE_CTRL_CONFIG == cmd)
260 {
261 winusb_device->cmd_handler = (void(*)(rt_uint8_t*,rt_size_t))args;
262 }
263 return RT_EOK;
264 }
265
266 #ifdef RT_USING_DEVICE_OPS
267 const static struct rt_device_ops winusb_device_ops =
268 {
269 RT_NULL,
270 RT_NULL,
271 RT_NULL,
272 win_usb_read,
273 win_usb_write,
274 win_usb_control,
275 };
276 #endif
277
rt_usb_winusb_init(ufunction_t func)278 static rt_err_t rt_usb_winusb_init(ufunction_t func)
279 {
280 winusb_device_t winusb_device = (winusb_device_t)func->user_data;
281 winusb_device->parent.type = RT_Device_Class_Miscellaneous;
282
283 #ifdef RT_USING_DEVICE_OPS
284 winusb_device->parent.ops = &winusb_device_ops;
285 #else
286 winusb_device->parent.init = RT_NULL;
287 winusb_device->parent.open = RT_NULL;
288 winusb_device->parent.close = RT_NULL;
289 winusb_device->parent.read = win_usb_read;
290 winusb_device->parent.write = win_usb_write;
291 winusb_device->parent.control = win_usb_control;
292 #endif
293
294 winusb_device->parent.user_data = func;
295
296
297 return rt_device_register(&winusb_device->parent, "winusb", RT_DEVICE_FLAG_RDWR);
298 }
299
rt_usbd_function_winusb_create(udevice_t device)300 ufunction_t rt_usbd_function_winusb_create(udevice_t device)
301 {
302 ufunction_t func;
303 winusb_device_t winusb_device;
304
305 uintf_t winusb_intf;
306 ualtsetting_t winusb_setting;
307 winusb_desc_t winusb_desc;
308
309 /* parameter check */
310 RT_ASSERT(device != RT_NULL);
311
312 /* set usb device string description */
313 rt_usbd_device_set_string(device, _ustring);
314
315 /* create a cdc function */
316 func = rt_usbd_function_new(device, &dev_desc, &ops);
317 rt_usbd_device_set_qualifier(device, &dev_qualifier);
318
319 /* allocate memory for cdc vcom data */
320 winusb_device = (winusb_device_t)rt_malloc(sizeof(struct winusb_device));
321 rt_memset((void *)winusb_device, 0, sizeof(struct winusb_device));
322 func->user_data = (void*)winusb_device;
323 /* create an interface object */
324 winusb_intf = rt_usbd_interface_new(device, _interface_handler);
325
326 /* create an alternate setting object */
327 winusb_setting = rt_usbd_altsetting_new(sizeof(struct winusb_descriptor));
328
329 /* config desc in alternate setting */
330 rt_usbd_altsetting_config_descriptor(winusb_setting, &_winusb_desc, (rt_off_t)&((winusb_desc_t)0)->intf_desc);
331
332 /* configure the hid interface descriptor */
333 _winusb_descriptor_config(winusb_setting->desc, winusb_intf->intf_num, device->dcd->device_is_hs);
334
335 /* create endpoint */
336 winusb_desc = (winusb_desc_t)winusb_setting->desc;
337 winusb_device->ep_out = rt_usbd_endpoint_new(&winusb_desc->ep_out_desc, _ep_out_handler);
338 winusb_device->ep_in = rt_usbd_endpoint_new(&winusb_desc->ep_in_desc, _ep_in_handler);
339
340 /* add the int out and int in endpoint to the alternate setting */
341 rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_out);
342 rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_in);
343
344 /* add the alternate setting to the interface, then set default setting */
345 rt_usbd_interface_add_altsetting(winusb_intf, winusb_setting);
346 rt_usbd_set_altsetting(winusb_intf, 0);
347
348 /* add the interface to the mass storage function */
349 rt_usbd_function_add_interface(func, winusb_intf);
350
351 rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(device->os_comp_id_desc, &winusb_func_comp_id_desc);
352 /* initilize winusb */
353 rt_usb_winusb_init(func);
354 return func;
355 }
356
357 struct udclass winusb_class =
358 {
359 .rt_usbd_function_create = rt_usbd_function_winusb_create
360 };
361
rt_usbd_winusb_class_register(void)362 int rt_usbd_winusb_class_register(void)
363 {
364 rt_usbd_class_register(&winusb_class);
365 return 0;
366 }
367 INIT_PREV_EXPORT(rt_usbd_winusb_class_register);
368