xref: /nrf52832-nimble/rt-thread/components/drivers/usb/usbdevice/class/winusb.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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 
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 
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;
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 }
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 }
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 }
199 static rt_err_t _function_enable(ufunction_t func)
200 {
201     RT_ASSERT(func != RT_NULL);
202     return RT_EOK;
203 }
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 
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 
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 }
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 }
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 
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 
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 
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