]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/usb/gadget/f_thor.c
Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[karo-tx-uboot.git] / drivers / usb / gadget / f_thor.c
1 /*
2  * f_thor.c -- USB TIZEN THOR Downloader gadget function
3  *
4  * Copyright (C) 2013 Samsung Electronics
5  * Lukasz Majewski <l.majewski@samsung.com>
6  *
7  * Based on code from:
8  * git://review.tizen.org/kernel/u-boot
9  *
10  * Developed by:
11  * Copyright (C) 2009 Samsung Electronics
12  * Minkyu Kang <mk7.kang@samsung.com>
13  * Sanghee Kim <sh0130.kim@samsung.com>
14  *
15  * SPDX-License-Identifier:     GPL-2.0+
16  */
17
18 #include <errno.h>
19 #include <common.h>
20 #include <malloc.h>
21 #include <version.h>
22 #include <linux/usb/ch9.h>
23 #include <linux/usb/gadget.h>
24 #include <linux/usb/composite.h>
25 #include <linux/usb/cdc.h>
26 #include <g_dnl.h>
27 #include <dfu.h>
28
29 #include "f_thor.h"
30
31 static void thor_tx_data(unsigned char *data, int len);
32 static void thor_set_dma(void *addr, int len);
33 static int thor_rx_data(void);
34
35 static struct f_thor *thor_func;
36 static inline struct f_thor *func_to_thor(struct usb_function *f)
37 {
38         return container_of(f, struct f_thor, usb_function);
39 }
40
41 DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_tx_data_buf,
42                           sizeof(struct rsp_box));
43 DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_rx_data_buf,
44                           sizeof(struct rqt_box));
45
46 /* ********************************************************** */
47 /*         THOR protocol - transmission handling              */
48 /* ********************************************************** */
49 DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE);
50 static unsigned long long int thor_file_size;
51 static int alt_setting_num;
52
53 static void send_rsp(const struct rsp_box *rsp)
54 {
55         memcpy(thor_tx_data_buf, rsp, sizeof(struct rsp_box));
56         thor_tx_data(thor_tx_data_buf, sizeof(struct rsp_box));
57
58         debug("-RSP: %d, %d\n", rsp->rsp, rsp->rsp_data);
59 }
60
61 static void send_data_rsp(s32 ack, s32 count)
62 {
63         ALLOC_CACHE_ALIGN_BUFFER(struct data_rsp_box, rsp,
64                                  sizeof(struct data_rsp_box));
65
66         rsp->ack = ack;
67         rsp->count = count;
68
69         memcpy(thor_tx_data_buf, rsp, sizeof(struct data_rsp_box));
70         thor_tx_data(thor_tx_data_buf, sizeof(struct data_rsp_box));
71
72         debug("-DATA RSP: %d, %d\n", ack, count);
73 }
74
75 static int process_rqt_info(const struct rqt_box *rqt)
76 {
77         ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
78         memset(rsp, 0, sizeof(struct rsp_box));
79
80         rsp->rsp = rqt->rqt;
81         rsp->rsp_data = rqt->rqt_data;
82
83         switch (rqt->rqt_data) {
84         case RQT_INFO_VER_PROTOCOL:
85                 rsp->int_data[0] = VER_PROTOCOL_MAJOR;
86                 rsp->int_data[1] = VER_PROTOCOL_MINOR;
87                 break;
88         case RQT_INIT_VER_HW:
89                 snprintf(rsp->str_data[0], sizeof(rsp->str_data[0]),
90                          "%x", checkboard());
91                 break;
92         case RQT_INIT_VER_BOOT:
93                 sprintf(rsp->str_data[0], "%s", U_BOOT_VERSION);
94                 break;
95         case RQT_INIT_VER_KERNEL:
96                 sprintf(rsp->str_data[0], "%s", "k unknown");
97                 break;
98         case RQT_INIT_VER_PLATFORM:
99                 sprintf(rsp->str_data[0], "%s", "p unknown");
100                 break;
101         case RQT_INIT_VER_CSC:
102                 sprintf(rsp->str_data[0], "%s", "c unknown");
103                 break;
104         default:
105                 return -EINVAL;
106         }
107
108         send_rsp(rsp);
109         return true;
110 }
111
112 static int process_rqt_cmd(const struct rqt_box *rqt)
113 {
114         ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
115         memset(rsp, 0, sizeof(struct rsp_box));
116
117         rsp->rsp = rqt->rqt;
118         rsp->rsp_data = rqt->rqt_data;
119
120         switch (rqt->rqt_data) {
121         case RQT_CMD_REBOOT:
122                 debug("TARGET RESET\n");
123                 send_rsp(rsp);
124                 g_dnl_unregister();
125                 dfu_free_entities();
126                 run_command("reset", 0);
127                 break;
128         case RQT_CMD_POWEROFF:
129         case RQT_CMD_EFSCLEAR:
130                 send_rsp(rsp);
131         default:
132                 printf("Command not supported -> cmd: %d\n", rqt->rqt_data);
133                 return -EINVAL;
134         }
135
136         return true;
137 }
138
139 static long long int download_head(unsigned long long total,
140                                    unsigned int packet_size,
141                                    long long int *left,
142                                    int *cnt)
143 {
144         long long int rcv_cnt = 0, left_to_rcv, ret_rcv;
145         void *transfer_buffer = dfu_get_buf();
146         void *buf = transfer_buffer;
147         int usb_pkt_cnt = 0, ret;
148
149         /*
150          * Files smaller than THOR_STORE_UNIT_SIZE (now 32 MiB) are stored on
151          * the medium.
152          * The packet response is sent on the purpose after successful data
153          * chunk write. There is a room for improvement when asynchronous write
154          * is performed.
155          */
156         while (total - rcv_cnt >= packet_size) {
157                 thor_set_dma(buf, packet_size);
158                 buf += packet_size;
159                 ret_rcv = thor_rx_data();
160                 if (ret_rcv < 0)
161                         return ret_rcv;
162                 rcv_cnt += ret_rcv;
163                 debug("%d: RCV data count: %llu cnt: %d\n", usb_pkt_cnt,
164                       rcv_cnt, *cnt);
165
166                 if ((rcv_cnt % THOR_STORE_UNIT_SIZE) == 0) {
167                         ret = dfu_write(dfu_get_entity(alt_setting_num),
168                                         transfer_buffer, THOR_STORE_UNIT_SIZE,
169                                         (*cnt)++);
170                         if (ret) {
171                                 error("DFU write failed [%d] cnt: %d",
172                                       ret, *cnt);
173                                 return ret;
174                         }
175                         buf = transfer_buffer;
176                 }
177                 send_data_rsp(0, ++usb_pkt_cnt);
178         }
179
180         /* Calculate the amount of data to arrive from PC (in bytes) */
181         left_to_rcv = total - rcv_cnt;
182
183         /*
184          * Calculate number of data already received. but not yet stored
185          * on the medium (they are smaller than THOR_STORE_UNIT_SIZE)
186          */
187         *left = left_to_rcv + buf - transfer_buffer;
188         debug("%s: left: %llu left_to_rcv: %llu buf: 0x%p\n", __func__,
189               *left, left_to_rcv, buf);
190
191         if (left_to_rcv) {
192                 thor_set_dma(buf, packet_size);
193                 ret_rcv = thor_rx_data();
194                 if (ret_rcv < 0)
195                         return ret_rcv;
196                 rcv_cnt += ret_rcv;
197                 send_data_rsp(0, ++usb_pkt_cnt);
198         }
199
200         debug("%s: %llu total: %llu cnt: %d\n", __func__, rcv_cnt, total, *cnt);
201
202         return rcv_cnt;
203 }
204
205 static int download_tail(long long int left, int cnt)
206 {
207         struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num);
208         void *transfer_buffer = dfu_get_buf();
209         int ret;
210
211         debug("%s: left: %llu cnt: %d\n", __func__, left, cnt);
212
213         if (left) {
214                 ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++);
215                 if (ret) {
216                         error("DFU write failed [%d]: left: %llu", ret, left);
217                         return ret;
218                 }
219         }
220
221         /*
222          * To store last "packet" or write file from buffer to filesystem
223          * DFU storage backend requires dfu_flush
224          *
225          * This also frees memory malloc'ed by dfu_get_buf(), so no explicit
226          * need fo call dfu_free_buf() is needed.
227          */
228         ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt);
229         if (ret)
230                 error("DFU flush failed!");
231
232         return ret;
233 }
234
235 static long long int process_rqt_download(const struct rqt_box *rqt)
236 {
237         ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
238         static long long int left, ret_head;
239         int file_type, ret = 0;
240         static int cnt;
241
242         memset(rsp, 0, sizeof(struct rsp_box));
243         rsp->rsp = rqt->rqt;
244         rsp->rsp_data = rqt->rqt_data;
245
246         switch (rqt->rqt_data) {
247         case RQT_DL_INIT:
248                 thor_file_size = rqt->int_data[0];
249                 debug("INIT: total %d bytes\n", rqt->int_data[0]);
250                 break;
251         case RQT_DL_FILE_INFO:
252                 file_type = rqt->int_data[0];
253                 if (file_type == FILE_TYPE_PIT) {
254                         puts("PIT table file - not supported\n");
255                         rsp->ack = -ENOTSUPP;
256                         ret = rsp->ack;
257                         break;
258                 }
259
260                 thor_file_size = rqt->int_data[1];
261                 memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE);
262
263                 debug("INFO: name(%s, %d), size(%llu), type(%d)\n",
264                       f_name, 0, thor_file_size, file_type);
265
266                 rsp->int_data[0] = THOR_PACKET_SIZE;
267
268                 alt_setting_num = dfu_get_alt(f_name);
269                 if (alt_setting_num < 0) {
270                         error("Alt setting [%d] to write not found!",
271                               alt_setting_num);
272                         rsp->ack = -ENODEV;
273                         ret = rsp->ack;
274                 }
275                 break;
276         case RQT_DL_FILE_START:
277                 send_rsp(rsp);
278                 ret_head = download_head(thor_file_size, THOR_PACKET_SIZE,
279                                          &left, &cnt);
280                 if (ret_head < 0) {
281                         left = 0;
282                         cnt = 0;
283                 }
284                 return ret_head;
285         case RQT_DL_FILE_END:
286                 debug("DL FILE_END\n");
287                 rsp->ack = download_tail(left, cnt);
288                 ret = rsp->ack;
289                 left = 0;
290                 cnt = 0;
291                 break;
292         case RQT_DL_EXIT:
293                 debug("DL EXIT\n");
294                 break;
295         default:
296                 error("Operation not supported: %d", rqt->rqt_data);
297                 ret = -ENOTSUPP;
298         }
299
300         send_rsp(rsp);
301         return ret;
302 }
303
304 static int process_data(void)
305 {
306         ALLOC_CACHE_ALIGN_BUFFER(struct rqt_box, rqt, sizeof(struct rqt_box));
307         int ret = -EINVAL;
308
309         memcpy(rqt, thor_rx_data_buf, sizeof(struct rqt_box));
310
311         debug("+RQT: %d, %d\n", rqt->rqt, rqt->rqt_data);
312
313         switch (rqt->rqt) {
314         case RQT_INFO:
315                 ret = process_rqt_info(rqt);
316                 break;
317         case RQT_CMD:
318                 ret = process_rqt_cmd(rqt);
319                 break;
320         case RQT_DL:
321                 ret = (int) process_rqt_download(rqt);
322                 break;
323         case RQT_UL:
324                 puts("RQT: UPLOAD not supported!\n");
325                 break;
326         default:
327                 error("unknown request (%d)", rqt->rqt);
328         }
329
330         return ret;
331 }
332
333 /* ********************************************************** */
334 /*         THOR USB Function                                  */
335 /* ********************************************************** */
336
337 static inline struct usb_endpoint_descriptor *
338 ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
339         struct usb_endpoint_descriptor *fs)
340 {
341         if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
342                 return hs;
343         return fs;
344 }
345
346 static struct usb_interface_descriptor thor_downloader_intf_data = {
347         .bLength =              sizeof(thor_downloader_intf_data),
348         .bDescriptorType =      USB_DT_INTERFACE,
349
350         .bNumEndpoints =        2,
351         .bInterfaceClass =      USB_CLASS_CDC_DATA,
352 };
353
354 static struct usb_endpoint_descriptor fs_in_desc = {
355         .bLength =              USB_DT_ENDPOINT_SIZE,
356         .bDescriptorType =      USB_DT_ENDPOINT,
357
358         .bEndpointAddress =     USB_DIR_IN,
359         .bmAttributes = USB_ENDPOINT_XFER_BULK,
360 };
361
362 static struct usb_endpoint_descriptor fs_out_desc = {
363         .bLength =              USB_DT_ENDPOINT_SIZE,
364         .bDescriptorType =      USB_DT_ENDPOINT,
365
366         .bEndpointAddress =     USB_DIR_OUT,
367         .bmAttributes = USB_ENDPOINT_XFER_BULK,
368 };
369
370 /* CDC configuration */
371 static struct usb_interface_descriptor thor_downloader_intf_int = {
372         .bLength =              sizeof(thor_downloader_intf_int),
373         .bDescriptorType =      USB_DT_INTERFACE,
374
375         .bNumEndpoints =        1,
376         .bInterfaceClass =      USB_CLASS_COMM,
377          /* 0x02 Abstract Line Control Model */
378         .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
379         /* 0x01 Common AT commands */
380         .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
381 };
382
383 static struct usb_cdc_header_desc thor_downloader_cdc_header = {
384         .bLength         =    sizeof(thor_downloader_cdc_header),
385         .bDescriptorType =    0x24, /* CS_INTERFACE */
386         .bDescriptorSubType = 0x00,
387         .bcdCDC =             0x0110,
388 };
389
390 static struct usb_cdc_call_mgmt_descriptor thor_downloader_cdc_call = {
391         .bLength         =    sizeof(thor_downloader_cdc_call),
392         .bDescriptorType =    0x24, /* CS_INTERFACE */
393         .bDescriptorSubType = 0x01,
394         .bmCapabilities =     0x00,
395         .bDataInterface =     0x01,
396 };
397
398 static struct usb_cdc_acm_descriptor thor_downloader_cdc_abstract = {
399         .bLength         =    sizeof(thor_downloader_cdc_abstract),
400         .bDescriptorType =    0x24, /* CS_INTERFACE */
401         .bDescriptorSubType = 0x02,
402         .bmCapabilities =     0x00,
403 };
404
405 static struct usb_cdc_union_desc thor_downloader_cdc_union = {
406         .bLength         =     sizeof(thor_downloader_cdc_union),
407         .bDescriptorType =     0x24, /* CS_INTERFACE */
408         .bDescriptorSubType =  USB_CDC_UNION_TYPE,
409 };
410
411 static struct usb_endpoint_descriptor fs_int_desc = {
412         .bLength = USB_DT_ENDPOINT_SIZE,
413         .bDescriptorType = USB_DT_ENDPOINT,
414
415         .bEndpointAddress = 3 | USB_DIR_IN,
416         .bmAttributes = USB_ENDPOINT_XFER_INT,
417         .wMaxPacketSize = __constant_cpu_to_le16(16),
418
419         .bInterval = 0x9,
420 };
421
422 static struct usb_interface_assoc_descriptor
423 thor_iad_descriptor = {
424         .bLength =              sizeof(thor_iad_descriptor),
425         .bDescriptorType =      USB_DT_INTERFACE_ASSOCIATION,
426
427         .bFirstInterface =      0,
428         .bInterfaceCount =      2,      /* control + data */
429         .bFunctionClass =       USB_CLASS_COMM,
430         .bFunctionSubClass =    USB_CDC_SUBCLASS_ACM,
431         .bFunctionProtocol =    USB_CDC_PROTO_NONE,
432 };
433
434 static struct usb_endpoint_descriptor hs_in_desc = {
435         .bLength =              USB_DT_ENDPOINT_SIZE,
436         .bDescriptorType =      USB_DT_ENDPOINT,
437
438         .bmAttributes = USB_ENDPOINT_XFER_BULK,
439         .wMaxPacketSize =       __constant_cpu_to_le16(512),
440 };
441
442 static struct usb_endpoint_descriptor hs_out_desc = {
443         .bLength =              USB_DT_ENDPOINT_SIZE,
444         .bDescriptorType =      USB_DT_ENDPOINT,
445
446         .bmAttributes = USB_ENDPOINT_XFER_BULK,
447         .wMaxPacketSize =       __constant_cpu_to_le16(512),
448 };
449
450 static struct usb_endpoint_descriptor hs_int_desc = {
451         .bLength = USB_DT_ENDPOINT_SIZE,
452         .bDescriptorType = USB_DT_ENDPOINT,
453
454         .bmAttributes = USB_ENDPOINT_XFER_INT,
455         .wMaxPacketSize = __constant_cpu_to_le16(16),
456
457         .bInterval = 0x9,
458 };
459
460 static struct usb_qualifier_descriptor dev_qualifier = {
461         .bLength =              sizeof(dev_qualifier),
462         .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
463
464         .bcdUSB =               __constant_cpu_to_le16(0x0200),
465         .bDeviceClass = USB_CLASS_VENDOR_SPEC,
466
467         .bNumConfigurations =   2,
468 };
469
470 /*
471  * This attribute vendor descriptor is necessary for correct operation with
472  * Windows version of THOR download program
473  *
474  * It prevents windows driver from sending zero lenght packet (ZLP) after
475  * each THOR_PACKET_SIZE. This assures consistent behaviour with libusb
476  */
477 static struct usb_cdc_attribute_vendor_descriptor thor_downloader_cdc_av = {
478         .bLength =              sizeof(thor_downloader_cdc_av),
479         .bDescriptorType =      0x24,
480         .bDescriptorSubType =   0x80,
481         .DAUType =              0x0002,
482         .DAULength =            0x0001,
483         .DAUValue =             0x00,
484 };
485
486 static const struct usb_descriptor_header *hs_thor_downloader_function[] = {
487         (struct usb_descriptor_header *)&thor_iad_descriptor,
488
489         (struct usb_descriptor_header *)&thor_downloader_intf_int,
490         (struct usb_descriptor_header *)&thor_downloader_cdc_header,
491         (struct usb_descriptor_header *)&thor_downloader_cdc_call,
492         (struct usb_descriptor_header *)&thor_downloader_cdc_abstract,
493         (struct usb_descriptor_header *)&thor_downloader_cdc_union,
494         (struct usb_descriptor_header *)&hs_int_desc,
495
496         (struct usb_descriptor_header *)&thor_downloader_intf_data,
497         (struct usb_descriptor_header *)&thor_downloader_cdc_av,
498         (struct usb_descriptor_header *)&hs_in_desc,
499         (struct usb_descriptor_header *)&hs_out_desc,
500         NULL,
501 };
502
503 /*-------------------------------------------------------------------------*/
504 static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
505 {
506         struct usb_request *req;
507
508         req = usb_ep_alloc_request(ep, 0);
509         if (!req)
510                 return req;
511
512         req->length = length;
513         req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length);
514         if (!req->buf) {
515                 usb_ep_free_request(ep, req);
516                 req = NULL;
517         }
518
519         return req;
520 }
521
522 static int thor_rx_data(void)
523 {
524         struct thor_dev *dev = thor_func->dev;
525         int data_to_rx, tmp, status;
526
527         data_to_rx = dev->out_req->length;
528         tmp = data_to_rx;
529         do {
530                 dev->out_req->length = data_to_rx;
531                 debug("dev->out_req->length:%d dev->rxdata:%d\n",
532                       dev->out_req->length, dev->rxdata);
533
534                 status = usb_ep_queue(dev->out_ep, dev->out_req, 0);
535                 if (status) {
536                         error("kill %s:  resubmit %d bytes --> %d",
537                               dev->out_ep->name, dev->out_req->length, status);
538                         usb_ep_set_halt(dev->out_ep);
539                         return -EAGAIN;
540                 }
541
542                 while (!dev->rxdata) {
543                         usb_gadget_handle_interrupts();
544                         if (ctrlc())
545                                 return -1;
546                 }
547                 dev->rxdata = 0;
548                 data_to_rx -= dev->out_req->actual;
549         } while (data_to_rx);
550
551         return tmp;
552 }
553
554 static void thor_tx_data(unsigned char *data, int len)
555 {
556         struct thor_dev *dev = thor_func->dev;
557         unsigned char *ptr = dev->in_req->buf;
558         int status;
559
560         memset(ptr, 0, len);
561         memcpy(ptr, data, len);
562
563         dev->in_req->length = len;
564
565         debug("%s: dev->in_req->length:%d to_cpy:%d\n", __func__,
566               dev->in_req->length, sizeof(data));
567
568         status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
569         if (status) {
570                 error("kill %s:  resubmit %d bytes --> %d",
571                       dev->in_ep->name, dev->in_req->length, status);
572                 usb_ep_set_halt(dev->in_ep);
573         }
574
575         /* Wait until tx interrupt received */
576         while (!dev->txdata)
577                 usb_gadget_handle_interrupts();
578
579         dev->txdata = 0;
580 }
581
582 static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req)
583 {
584         struct thor_dev *dev = thor_func->dev;
585         int status = req->status;
586
587         debug("%s: ep_ptr:%p, req_ptr:%p\n", __func__, ep, req);
588         switch (status) {
589         case 0:
590                 if (ep == dev->out_ep)
591                         dev->rxdata = 1;
592                 else
593                         dev->txdata = 1;
594
595                 break;
596
597         /* this endpoint is normally active while we're configured */
598         case -ECONNABORTED:             /* hardware forced ep reset */
599         case -ECONNRESET:               /* request dequeued */
600         case -ESHUTDOWN:                /* disconnect from host */
601         case -EREMOTEIO:                /* short read */
602         case -EOVERFLOW:
603                 error("ERROR:%d", status);
604                 break;
605         }
606
607         debug("%s complete --> %d, %d/%d\n", ep->name,
608               status, req->actual, req->length);
609 }
610
611 static struct usb_request *thor_start_ep(struct usb_ep *ep)
612 {
613         struct usb_request *req;
614
615         req = alloc_ep_req(ep, THOR_PACKET_SIZE);
616         debug("%s: ep:%p req:%p\n", __func__, ep, req);
617
618         if (!req)
619                 return NULL;
620
621         memset(req->buf, 0, req->length);
622         req->complete = thor_rx_tx_complete;
623
624         return req;
625 }
626
627 static void thor_setup_complete(struct usb_ep *ep, struct usb_request *req)
628 {
629         if (req->status || req->actual != req->length)
630                 debug("setup complete --> %d, %d/%d\n",
631                       req->status, req->actual, req->length);
632 }
633
634 static int
635 thor_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
636 {
637         struct thor_dev *dev = thor_func->dev;
638         struct usb_request *req = dev->req;
639         struct usb_gadget *gadget = dev->gadget;
640         int value = 0;
641
642         u16 len = le16_to_cpu(ctrl->wLength);
643
644         debug("Req_Type: 0x%x Req: 0x%x wValue: 0x%x wIndex: 0x%x wLen: 0x%x\n",
645               ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
646               ctrl->wLength);
647
648         switch (ctrl->bRequest) {
649         case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
650                 value = 0;
651                 break;
652         case USB_CDC_REQ_SET_LINE_CODING:
653                 value = len;
654                 /* Line Coding set done = configuration done */
655                 thor_func->dev->configuration_done = 1;
656                 break;
657
658         default:
659                 error("thor_setup: unknown request: %d", ctrl->bRequest);
660         }
661
662         if (value >= 0) {
663                 req->length = value;
664                 req->zero = value < len;
665                 value = usb_ep_queue(gadget->ep0, req, 0);
666                 if (value < 0) {
667                         debug("%s: ep_queue: %d\n", __func__, value);
668                         req->status = 0;
669                 }
670         }
671
672         return value;
673 }
674
675 /* Specific to the THOR protocol */
676 static void thor_set_dma(void *addr, int len)
677 {
678         struct thor_dev *dev = thor_func->dev;
679
680         debug("in_req:%p, out_req:%p\n", dev->in_req, dev->out_req);
681         debug("addr:%p, len:%d\n", addr, len);
682
683         dev->out_req->buf = addr;
684         dev->out_req->length = len;
685 }
686
687 int thor_init(void)
688 {
689         struct thor_dev *dev = thor_func->dev;
690
691         /* Wait for a device enumeration and configuration settings */
692         debug("THOR enumeration/configuration setting....\n");
693         while (!dev->configuration_done)
694                 usb_gadget_handle_interrupts();
695
696         thor_set_dma(thor_rx_data_buf, strlen("THOR"));
697         /* detect the download request from Host PC */
698         if (thor_rx_data() < 0) {
699                 printf("%s: Data not received!\n", __func__);
700                 return -1;
701         }
702
703         if (!strncmp((char *)thor_rx_data_buf, "THOR", strlen("THOR"))) {
704                 puts("Download request from the Host PC\n");
705                 udelay(30 * 1000); /* 30 ms */
706
707                 strcpy((char *)thor_tx_data_buf, "ROHT");
708                 thor_tx_data(thor_tx_data_buf, strlen("ROHT"));
709         } else {
710                 puts("Wrong reply information\n");
711                 return -1;
712         }
713
714         return 0;
715 }
716
717 int thor_handle(void)
718 {
719         int ret;
720
721         /* receive the data from Host PC */
722         while (1) {
723                 thor_set_dma(thor_rx_data_buf, sizeof(struct rqt_box));
724                 ret = thor_rx_data();
725
726                 if (ret > 0) {
727                         ret = process_data();
728                         if (ret < 0)
729                                 return ret;
730                 } else {
731                         printf("%s: No data received!\n", __func__);
732                         break;
733                 }
734         }
735
736         return 0;
737 }
738
739 static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
740 {
741         struct usb_gadget *gadget = c->cdev->gadget;
742         struct f_thor *f_thor = func_to_thor(f);
743         struct thor_dev *dev;
744         struct usb_ep *ep;
745         int status;
746
747         thor_func = f_thor;
748         dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev));
749         if (!dev)
750                 return -ENOMEM;
751
752         memset(dev, 0, sizeof(*dev));
753         dev->gadget = gadget;
754         f_thor->dev = dev;
755
756         debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n",
757               __func__, c, f);
758         debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev);
759
760         /* EP0  */
761         /* preallocate control response and buffer */
762         dev->req = usb_ep_alloc_request(gadget->ep0, 0);
763         if (!dev->req) {
764                 status = -ENOMEM;
765                 goto fail;
766         }
767         dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
768                                  gadget->ep0->maxpacket);
769         if (!dev->req->buf) {
770                 status = -ENOMEM;
771                 goto fail;
772         }
773
774         dev->req->complete = thor_setup_complete;
775
776         /* DYNAMIC interface numbers assignments */
777         status = usb_interface_id(c, f);
778
779         if (status < 0)
780                 goto fail;
781
782         thor_downloader_intf_int.bInterfaceNumber = status;
783         thor_downloader_cdc_union.bMasterInterface0 = status;
784
785         status = usb_interface_id(c, f);
786
787         if (status < 0)
788                 goto fail;
789
790         thor_downloader_intf_data.bInterfaceNumber = status;
791         thor_downloader_cdc_union.bSlaveInterface0 = status;
792
793         /* allocate instance-specific endpoints */
794         ep = usb_ep_autoconfig(gadget, &fs_in_desc);
795         if (!ep) {
796                 status = -ENODEV;
797                 goto fail;
798         }
799
800         if (gadget_is_dualspeed(gadget)) {
801                 hs_in_desc.bEndpointAddress =
802                                 fs_in_desc.bEndpointAddress;
803         }
804
805         dev->in_ep = ep; /* Store IN EP for enabling @ setup */
806
807         ep = usb_ep_autoconfig(gadget, &fs_out_desc);
808         if (!ep) {
809                 status = -ENODEV;
810                 goto fail;
811         }
812
813         if (gadget_is_dualspeed(gadget))
814                 hs_out_desc.bEndpointAddress =
815                                 fs_out_desc.bEndpointAddress;
816
817         dev->out_ep = ep; /* Store OUT EP for enabling @ setup */
818
819         ep = usb_ep_autoconfig(gadget, &fs_int_desc);
820         if (!ep) {
821                 status = -ENODEV;
822                 goto fail;
823         }
824
825         dev->int_ep = ep;
826
827         if (gadget_is_dualspeed(gadget)) {
828                 hs_int_desc.bEndpointAddress =
829                                 fs_int_desc.bEndpointAddress;
830
831                 f->hs_descriptors = (struct usb_descriptor_header **)
832                         &hs_thor_downloader_function;
833
834                 if (!f->hs_descriptors)
835                         goto fail;
836         }
837
838         debug("%s: out_ep:%p out_req:%p\n", __func__,
839               dev->out_ep, dev->out_req);
840
841         return 0;
842
843  fail:
844         free(dev);
845         return status;
846 }
847
848 static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
849 {
850         free(req->buf);
851         usb_ep_free_request(ep, req);
852 }
853
854 static void thor_unbind(struct usb_configuration *c, struct usb_function *f)
855 {
856         struct f_thor *f_thor = func_to_thor(f);
857         struct thor_dev *dev = f_thor->dev;
858
859         free(dev);
860         memset(thor_func, 0, sizeof(*thor_func));
861         thor_func = NULL;
862 }
863
864 static void thor_func_disable(struct usb_function *f)
865 {
866         struct f_thor *f_thor = func_to_thor(f);
867         struct thor_dev *dev = f_thor->dev;
868
869         debug("%s:\n", __func__);
870
871         /* Avoid freeing memory when ep is still claimed */
872         if (dev->in_ep->driver_data) {
873                 free_ep_req(dev->in_ep, dev->in_req);
874                 usb_ep_disable(dev->in_ep);
875                 dev->in_ep->driver_data = NULL;
876         }
877
878         if (dev->out_ep->driver_data) {
879                 dev->out_req->buf = NULL;
880                 usb_ep_free_request(dev->out_ep, dev->out_req);
881                 usb_ep_disable(dev->out_ep);
882                 dev->out_ep->driver_data = NULL;
883         }
884
885         if (dev->int_ep->driver_data) {
886                 usb_ep_disable(dev->int_ep);
887                 dev->int_ep->driver_data = NULL;
888         }
889 }
890
891 static int thor_eps_setup(struct usb_function *f)
892 {
893         struct usb_composite_dev *cdev = f->config->cdev;
894         struct usb_gadget *gadget = cdev->gadget;
895         struct thor_dev *dev = thor_func->dev;
896         struct usb_endpoint_descriptor *d;
897         struct usb_request *req;
898         struct usb_ep *ep;
899         int result;
900
901         ep = dev->in_ep;
902         d = ep_desc(gadget, &hs_in_desc, &fs_in_desc);
903         debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
904
905         result = usb_ep_enable(ep, d);
906         if (result)
907                 goto exit;
908
909         ep->driver_data = cdev; /* claim */
910         req = thor_start_ep(ep);
911         if (!req) {
912                 usb_ep_disable(ep);
913                 result = -EIO;
914                 goto exit;
915         }
916
917         dev->in_req = req;
918         ep = dev->out_ep;
919         d = ep_desc(gadget, &hs_out_desc, &fs_out_desc);
920         debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
921
922         result = usb_ep_enable(ep, d);
923         if (result)
924                 goto exit;
925
926         ep->driver_data = cdev; /* claim */
927         req = thor_start_ep(ep);
928         if (!req) {
929                 usb_ep_disable(ep);
930                 result = -EIO;
931                 goto exit;
932         }
933
934         dev->out_req = req;
935         /* ACM control EP */
936         ep = dev->int_ep;
937         ep->driver_data = cdev; /* claim */
938
939  exit:
940         return result;
941 }
942
943 static int thor_func_set_alt(struct usb_function *f,
944                              unsigned intf, unsigned alt)
945 {
946         struct thor_dev *dev = thor_func->dev;
947         int result;
948
949         debug("%s: func: %s intf: %d alt: %d\n",
950               __func__, f->name, intf, alt);
951
952         switch (intf) {
953         case 0:
954                 debug("ACM INTR interface\n");
955                 break;
956         case 1:
957                 debug("Communication Data interface\n");
958                 result = thor_eps_setup(f);
959                 if (result)
960                         error("%s: EPs setup failed!", __func__);
961                 dev->configuration_done = 1;
962                 break;
963         }
964
965         return 0;
966 }
967
968 static int thor_func_init(struct usb_configuration *c)
969 {
970         struct f_thor *f_thor;
971         int status;
972
973         debug("%s: cdev: 0x%p\n", __func__, c->cdev);
974
975         f_thor = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_thor));
976         if (!f_thor)
977                 return -ENOMEM;
978
979         memset(f_thor, 0, sizeof(*f_thor));
980
981         f_thor->usb_function.name = "f_thor";
982         f_thor->usb_function.bind = thor_func_bind;
983         f_thor->usb_function.unbind = thor_unbind;
984         f_thor->usb_function.setup = thor_func_setup;
985         f_thor->usb_function.set_alt = thor_func_set_alt;
986         f_thor->usb_function.disable = thor_func_disable;
987
988         status = usb_add_function(c, &f_thor->usb_function);
989         if (status)
990                 free(f_thor);
991
992         return status;
993 }
994
995 int thor_add(struct usb_configuration *c)
996 {
997         debug("%s:\n", __func__);
998         return thor_func_init(c);
999 }
1000
1001 DECLARE_GADGET_BIND_CALLBACK(usb_dnl_thor, thor_add);