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