]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/westbridge/astoria/gadget/cyasgadget.c
staging: westbridge: improve error path
[net-next-2.6.git] / drivers / staging / westbridge / astoria / gadget / cyasgadget.c
CommitLineData
81eb669b
DC
1/* cyangadget.c - Linux USB Gadget driver file for the Cypress West Bridge
2## ===========================
3## Copyright (C) 2010 Cypress Semiconductor
4##
5## This program is free software; you can redistribute it and/or
6## modify it under the terms of the GNU General Public License
7## as published by the Free Software Foundation; either version 2
8## of the License, or (at your option) any later version.
9##
10## This program is distributed in the hope that it will be useful,
11## but WITHOUT ANY WARRANTY; without even the implied warranty of
12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13## GNU General Public License for more details.
14##
15## You should have received a copy of the GNU General Public License
16## along with this program; if not, write to the Free Software
17## Foundation, Inc., 51 Franklin Street, Fifth Floor
18## Boston, MA 02110-1301, USA.
19## ===========================
20*/
21
22/*
23 * Cypress West Bridge high/full speed usb device controller code
24 * Based on the Netchip 2280 device controller by David Brownell
25 * in the linux 2.6.10 kernel
26 *
27 * linux/drivers/usb/gadget/net2280.c
28 */
29
30/*
31 * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
32 * Copyright (C) 2003 David Brownell
33 *
34 * This program is free software; you can redistribute it and/or modify
35 * it under the terms of the GNU General Public License as published by
36 * the Free Software Foundation; either version 2 of the License, or
37 * (at your option) any later version.
38 *
39 * This program is distributed in the hope that it will be useful,
40 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 * GNU General Public License for more details.
43 *
44 * You should have received a copy of the GNU General Public License
45 * along with this program; if not, write to the Free Software
46 * Foundation, Inc., 59 Temple Place, Suite 330
47 * Boston, MA 02111-1307 USA
48 */
49
50#include "cyasgadget.h"
51
52#define CY_AS_DRIVER_DESC "cypress west bridge usb gadget"
53#define CY_AS_DRIVER_VERSION "REV B"
54#define DMA_ADDR_INVALID (~(dma_addr_t)0)
55
56static const char cy_as_driver_name[] = "cy_astoria_gadget";
57static const char cy_as_driver_desc[] = CY_AS_DRIVER_DESC;
58
59static const char cy_as_ep0name[] = "EP0";
60static const char *cy_as_ep_names[] = {
61 cy_as_ep0name, "EP1",
62 "EP2", "EP3", "EP4", "EP5", "EP6", "EP7", "EP8",
63 "EP9", "EP10", "EP11", "EP12", "EP13", "EP14", "EP15"
64};
65
66/* forward declarations */
67static void
68cyas_ep_reset(
69 struct cyasgadget_ep *an_ep) ;
70
71static int
72cyasgadget_fifo_status(
73 struct usb_ep *_ep) ;
74
75static void
76cyasgadget_stallcallback(
77 cy_as_device_handle h,
78 cy_as_return_status_t status,
79 uint32_t tag,
80 cy_as_funct_c_b_type cbtype,
81 void *cbdata);
82
83/* variables */
84static cyasgadget *cy_as_gadget_controller;
85
86static int append_mtp;
87module_param(append_mtp, bool, S_IRUGO | S_IWUSR);
88MODULE_PARM_DESC(append_mtp,
89 "west bridge to append descriptors for mtp 0=no 1=yes");
90
91static int msc_enum_bus_0;
92module_param(msc_enum_bus_0, bool, S_IRUGO | S_IWUSR);
93MODULE_PARM_DESC(msc_enum_bus_0,
94 "west bridge to enumerate bus 0 as msc 0=no 1=yes");
95
96static int msc_enum_bus_1;
97module_param(msc_enum_bus_1, bool, S_IRUGO | S_IWUSR);
98MODULE_PARM_DESC(msc_enum_bus_1,
99 "west bridge to enumerate bus 1 as msc 0=no 1=yes");
100
101/* all Callbacks are placed in this subsection*/
102static void cy_as_gadget_usb_event_callback(
103 cy_as_device_handle h,
104 cy_as_usb_event ev,
105 void *evdata
106 )
107{
108 cyasgadget *cy_as_dev ;
109 #ifndef WESTBRIDGE_NDEBUG
110 struct usb_ctrlrequest *ctrlreq;
111 #endif
112
113 /* cy_as_dev = container_of(h, cyasgadget, dev_handle); */
114 cy_as_dev = cy_as_gadget_controller ;
115 switch (ev) {
116 case cy_as_event_usb_suspend:
117 #ifndef WESTBRIDGE_NDEBUG
118 cy_as_hal_print_message(
119 "<1>_cy_as_event_usb_suspend received\n") ;
120 #endif
121 cy_as_dev->driver->suspend(&cy_as_dev->gadget) ;
122 break;
123
124 case cy_as_event_usb_resume:
125 #ifndef WESTBRIDGE_NDEBUG
126 cy_as_hal_print_message(
127 "<1>_cy_as_event_usb_resume received\n") ;
128 #endif
129 cy_as_dev->driver->resume(&cy_as_dev->gadget) ;
130 break;
131
132 case cy_as_event_usb_reset:
133 #ifndef WESTBRIDGE_NDEBUG
134 cy_as_hal_print_message(
135 "<1>_cy_as_event_usb_reset received\n") ;
136 #endif
137 break;
138
139 case cy_as_event_usb_speed_change:
140 #ifndef WESTBRIDGE_NDEBUG
141 cy_as_hal_print_message(
142 "<1>_cy_as_event_usb_speed_change received\n") ;
143 #endif
144 break;
145
146 case cy_as_event_usb_set_config:
147 #ifndef WESTBRIDGE_NDEBUG
148 cy_as_hal_print_message(
149 "<1>_cy_as_event_usb_set_config received\n") ;
150 #endif
151 break;
152
153 case cy_as_event_usb_setup_packet:
154 #ifndef WESTBRIDGE_NDEBUG
155 ctrlreq = (struct usb_ctrlrequest *)evdata;
156
157 cy_as_hal_print_message("<1>_cy_as_event_usb_setup_packet "
158 "received"
159 "bRequestType=0x%x,"
160 "bRequest=0x%x,"
161 "wValue=x%x,"
162 "wIndex=0x%x,"
163 "wLength=0x%x,",
164 ctrlreq->bRequestType,
165 ctrlreq->bRequest,
166 ctrlreq->wValue,
167 ctrlreq->wIndex,
168 ctrlreq->wLength
169 ) ;
170 #endif
171 cy_as_dev->outsetupreq = 0;
172 if ((((uint8_t *)evdata)[0] & USB_DIR_IN) == USB_DIR_OUT)
173 cy_as_dev->outsetupreq = 1;
174 cy_as_dev->driver->setup(&cy_as_dev->gadget,
175 (struct usb_ctrlrequest *)evdata) ;
176 break;
177
178 case cy_as_event_usb_status_packet:
179 #ifndef WESTBRIDGE_NDEBUG
180 cy_as_hal_print_message(
181 "<1>_cy_as_event_usb_status_packet received\n") ;
182 #endif
183 break;
184
185 case cy_as_event_usb_inquiry_before:
186 #ifndef WESTBRIDGE_NDEBUG
187 cy_as_hal_print_message(
188 "<1>_cy_as_event_usb_inquiry_before received\n") ;
189 #endif
190 break;
191
192 case cy_as_event_usb_inquiry_after:
193 #ifndef WESTBRIDGE_NDEBUG
194 cy_as_hal_print_message(
195 "<1>_cy_as_event_usb_inquiry_after received\n") ;
196 #endif
197 break;
198
199 case cy_as_event_usb_start_stop:
200 #ifndef WESTBRIDGE_NDEBUG
201 cy_as_hal_print_message(
202 "<1>_cy_as_event_usb_start_stop received\n") ;
203 #endif
204 break;
205
206 default:
207 break;
208 }
209}
210
211static void cy_as_gadget_mtp_event_callback(
212 cy_as_device_handle handle,
213 cy_as_mtp_event evtype,
214 void *evdata
215 )
216{
217
218 cyasgadget *dev = cy_as_gadget_controller ;
219 (void) handle;
220
221 switch (evtype) {
222 case cy_as_mtp_send_object_complete:
223 {
224 cy_as_mtp_send_object_complete_data *send_obj_data =
225 (cy_as_mtp_send_object_complete_data *) evdata ;
226
227 #ifndef WESTBRIDGE_NDEBUG
228 cy_as_hal_print_message(
229 "<6>MTP EVENT: send_object_complete\n");
230 cy_as_hal_print_message(
231 "<6>_bytes sent = %d\n_send status = %d",
232 send_obj_data->byte_count,
233 send_obj_data->status);
234 #endif
235
236 dev->tmtp_send_complete_data.byte_count =
237 send_obj_data->byte_count;
238 dev->tmtp_send_complete_data.status =
239 send_obj_data->status;
240 dev->tmtp_send_complete_data.transaction_id =
241 send_obj_data->transaction_id ;
242 dev->tmtp_send_complete = cy_true ;
243 break;
244 }
245 case cy_as_mtp_get_object_complete:
246 {
247 cy_as_mtp_get_object_complete_data *get_obj_data =
248 (cy_as_mtp_get_object_complete_data *) evdata ;
249
250 #ifndef WESTBRIDGE_NDEBUG
251 cy_as_hal_print_message(
252 "<6>MTP EVENT: get_object_complete\n");
253 cy_as_hal_print_message(
254 "<6>_bytes got = %d\n_get status = %d",
255 get_obj_data->byte_count, get_obj_data->status);
256 #endif
257
258 dev->tmtp_get_complete_data.byte_count =
259 get_obj_data->byte_count;
260 dev->tmtp_get_complete_data.status =
261 get_obj_data->status ;
262 dev->tmtp_get_complete = cy_true ;
263 break;
264 }
265 case cy_as_mtp_block_table_needed:
266 {
267 dev->tmtp_need_new_blk_tbl = cy_true ;
268 #ifndef WESTBRIDGE_NDEBUG
269 cy_as_hal_print_message(
270 "<6>MTP EVENT: cy_as_mtp_block_table_needed\n");
271 #endif
272 break;
273 }
274 default:
275 break;
276 }
277}
278
279static void
280cyasgadget_setupreadcallback(
281 cy_as_device_handle h,
282 cy_as_end_point_number_t ep,
283 uint32_t count,
284 void *buf,
285 cy_as_return_status_t status)
286{
287 cyasgadget_ep *an_ep;
288 cyasgadget_req *an_req;
289 cyasgadget *cy_as_dev ;
290 unsigned stopped ;
291 unsigned long flags;
292 (void)buf ;
293
294 cy_as_dev = cy_as_gadget_controller ;
295 if (cy_as_dev->driver == NULL)
296 return;
297
298 an_ep = &cy_as_dev->an_gadget_ep[ep] ;
299 spin_lock_irqsave(&cy_as_dev->lock, flags);
300 stopped = an_ep->stopped ;
301
302#ifndef WESTBRIDGE_NDEBUG
303 cy_as_hal_print_message(
304 "%s: ep=%d, count=%d, "
305 "status=%d\n", __func__, ep, count, status) ;
306#endif
307
308 an_req = list_entry(an_ep->queue.next,
309 cyasgadget_req, queue) ;
310 list_del_init(&an_req->queue) ;
311
312 if (status == CY_AS_ERROR_SUCCESS)
313 an_req->req.status = 0;
314 else
315 an_req->req.status = -status;
316 an_req->req.actual = count ;
317 an_ep->stopped = 1;
318
319 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
320
321 an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req);
322
323 an_ep->stopped = stopped;
324
325}
326/*called when the write of a setup packet has been completed*/
327static void cyasgadget_setupwritecallback(
328 cy_as_device_handle h,
329 cy_as_end_point_number_t ep,
330 uint32_t count,
331 void *buf,
332 cy_as_return_status_t status
333 )
334{
335 cyasgadget_ep *an_ep;
336 cyasgadget_req *an_req;
337 cyasgadget *cy_as_dev ;
338 unsigned stopped ;
339 unsigned long flags;
340
341 (void)buf ;
342
343 #ifndef WESTBRIDGE_NDEBUG
344 cy_as_hal_print_message("<1>%s called status=0x%x\n",
345 __func__, status);
346 #endif
347
348 cy_as_dev = cy_as_gadget_controller ;
349
350 if (cy_as_dev->driver == NULL)
351 return;
352
353 an_ep = &cy_as_dev->an_gadget_ep[ep] ;
354
355 spin_lock_irqsave(&cy_as_dev->lock, flags);
356
357 stopped = an_ep->stopped ;
358
359#ifndef WESTBRIDGE_NDEBUG
360 cy_as_hal_print_message("setup_write_callback: ep=%d, "
361 "count=%d, status=%d\n", ep, count, status) ;
362#endif
363
364 an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue) ;
365 list_del_init(&an_req->queue) ;
366
367 an_req->req.actual = count ;
368 an_req->req.status = 0 ;
369 an_ep->stopped = 1;
370
371 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
372
373 an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req);
374
375 an_ep->stopped = stopped;
376
377}
378
379/* called when a read operation has completed.*/
380static void cyasgadget_readcallback(
381 cy_as_device_handle h,
382 cy_as_end_point_number_t ep,
383 uint32_t count,
384 void *buf,
385 cy_as_return_status_t status
386 )
387{
388 cyasgadget_ep *an_ep;
389 cyasgadget_req *an_req;
390 cyasgadget *cy_as_dev ;
391 unsigned stopped ;
392 cy_as_return_status_t ret ;
393 unsigned long flags;
394
395 (void)h ;
396 (void)buf ;
397
398 cy_as_dev = cy_as_gadget_controller ;
399
400 if (cy_as_dev->driver == NULL)
401 return;
402
403 an_ep = &cy_as_dev->an_gadget_ep[ep] ;
404 stopped = an_ep->stopped ;
405
406 #ifndef WESTBRIDGE_NDEBUG
407 cy_as_hal_print_message("%s: ep=%d, count=%d, status=%d\n",
408 __func__, ep, count, status) ;
409 #endif
410
411 if (status == CY_AS_ERROR_CANCELED)
412 return ;
413
414 spin_lock_irqsave(&cy_as_dev->lock, flags);
415
416 an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue) ;
417 list_del_init(&an_req->queue) ;
418
419 if (status == CY_AS_ERROR_SUCCESS)
420 an_req->req.status = 0 ;
421 else
422 an_req->req.status = -status ;
423
424 an_req->complete = 1;
425 an_req->req.actual = count ;
426 an_ep->stopped = 1;
427
428 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
429 an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req);
430
431 an_ep->stopped = stopped;
432
433 /* We need to call ReadAsync on this end-point
434 * again, so as to not miss any data packets. */
435 if (!an_ep->stopped) {
436 spin_lock_irqsave(&cy_as_dev->lock, flags);
437 an_req = 0 ;
438 if (!list_empty(&an_ep->queue))
439 an_req = list_entry(an_ep->queue.next,
440 cyasgadget_req, queue) ;
441
442 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
443
444 if ((an_req) && (an_req->req.status == -EINPROGRESS)) {
445 ret = cy_as_usb_read_data_async(cy_as_dev->dev_handle,
446 an_ep->num, cy_false, an_req->req.length,
447 an_req->req.buf, cyasgadget_readcallback);
448
449 if (ret != CY_AS_ERROR_SUCCESS)
450 cy_as_hal_print_message("<1>_cy_as_gadget: "
451 "cy_as_usb_read_data_async failed "
452 "with error code %d\n", ret) ;
453 else
454 an_req->req.status = -EALREADY ;
455 }
456 }
457}
458
459/* function is called when a usb write operation has completed*/
460static void cyasgadget_writecallback(
461 cy_as_device_handle h,
462 cy_as_end_point_number_t ep,
463 uint32_t count,
464 void *buf,
465 cy_as_return_status_t status
466 )
467{
468 cyasgadget_ep *an_ep;
469 cyasgadget_req *an_req;
470 cyasgadget *cy_as_dev ;
471 unsigned stopped = 0;
472 cy_as_return_status_t ret ;
473 unsigned long flags;
474
475 (void)h ;
476 (void)buf ;
477
478 cy_as_dev = cy_as_gadget_controller ;
479 if (cy_as_dev->driver == NULL)
480 return;
481
482 an_ep = &cy_as_dev->an_gadget_ep[ep] ;
483
484 if (status == CY_AS_ERROR_CANCELED)
485 return ;
486
487 #ifndef WESTBRIDGE_NDEBUG
488 cy_as_hal_print_message("%s: ep=%d, count=%d, status=%d\n",
489 __func__, ep, count, status) ;
490 #endif
491
492 spin_lock_irqsave(&cy_as_dev->lock, flags);
493
494 an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue) ;
495 list_del_init(&an_req->queue) ;
496 an_req->req.actual = count ;
497
498 /* Verify the status value before setting req.status to zero */
499 if (status == CY_AS_ERROR_SUCCESS)
500 an_req->req.status = 0 ;
501 else
502 an_req->req.status = -status ;
503
504 an_ep->stopped = 1;
505
506 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
507
508 an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req);
509 an_ep->stopped = stopped;
510
511 /* We need to call WriteAsync on this end-point again, so as to not
512 miss any data packets. */
513 if (!an_ep->stopped) {
514 spin_lock_irqsave(&cy_as_dev->lock, flags);
515 an_req = 0 ;
516 if (!list_empty(&an_ep->queue))
517 an_req = list_entry(an_ep->queue.next,
518 cyasgadget_req, queue) ;
519 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
520
521 if ((an_req) && (an_req->req.status == -EINPROGRESS)) {
522 ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle,
523 an_ep->num, an_req->req.length, an_req->req.buf,
524 cy_false, cyasgadget_writecallback);
525
526 if (ret != CY_AS_ERROR_SUCCESS)
527 cy_as_hal_print_message("<1>_cy_as_gadget: "
528 "cy_as_usb_write_data_async "
529 "failed with error code %d\n", ret) ;
530 else
531 an_req->req.status = -EALREADY ;
532 }
533 }
534}
535
536static void cyasgadget_stallcallback(
537 cy_as_device_handle h,
538 cy_as_return_status_t status,
539 uint32_t tag,
540 cy_as_funct_c_b_type cbtype,
541 void *cbdata
542 )
543{
544 #ifndef WESTBRIDGE_NDEBUG
545 if (status != CY_AS_ERROR_SUCCESS)
546 cy_as_hal_print_message("<1>_set/_clear stall "
547 "failed with status %d\n", status) ;
548 #endif
549}
550
551
552/*******************************************************************/
553/* All usb_ep_ops (cyasgadget_ep_ops) are placed in this subsection*/
554/*******************************************************************/
555static int cyasgadget_enable(
556 struct usb_ep *_ep,
557 const struct usb_endpoint_descriptor *desc
558 )
559{
560 cyasgadget *an_dev;
561 cyasgadget_ep *an_ep;
562 u32 max, tmp;
563 unsigned long flags;
564
565 an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
566 if (!_ep || !desc || an_ep->desc || _ep->name == cy_as_ep0name
567 || desc->bDescriptorType != USB_DT_ENDPOINT)
568 return -EINVAL;
569
570 an_dev = an_ep->dev;
571 if (!an_dev->driver || an_dev->gadget.speed == USB_SPEED_UNKNOWN)
572 return -ESHUTDOWN;
573
574 max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
575
576 spin_lock_irqsave(&an_dev->lock, flags);
577 _ep->maxpacket = max & 0x7ff;
578 an_ep->desc = desc;
579
580 /* ep_reset() has already been called */
581 an_ep->stopped = 0;
582 an_ep->out_overflow = 0;
583
584 if (an_ep->cyepconfig.enabled != cy_true) {
585 #ifndef WESTBRIDGE_NDEBUG
586 cy_as_hal_print_message("<1>_cy_as_gadget: "
587 "cy_as_usb_end_point_config EP %s mismatch "
588 "on enabled\n", an_ep->usb_ep_inst.name) ;
589 #endif
590 return -EINVAL;
591 }
592
593 tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
594 an_ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
595
596 spin_unlock_irqrestore(&an_dev->lock, flags);
597
598 switch (tmp) {
599 case USB_ENDPOINT_XFER_ISOC:
600 if (an_ep->cyepconfig.type != cy_as_usb_iso) {
601 #ifndef WESTBRIDGE_NDEBUG
602 cy_as_hal_print_message("<1>_cy_as_gadget: "
603 "cy_as_usb_end_point_config EP %s mismatch "
604 "on type %d %d\n", an_ep->usb_ep_inst.name,
605 an_ep->cyepconfig.type, cy_as_usb_iso) ;
606 #endif
607 return -EINVAL;
608 }
609 break;
610 case USB_ENDPOINT_XFER_INT:
611 if (an_ep->cyepconfig.type != cy_as_usb_int) {
612 #ifndef WESTBRIDGE_NDEBUG
613 cy_as_hal_print_message("<1>_cy_as_gadget: "
614 "cy_as_usb_end_point_config EP %s mismatch "
615 "on type %d %d\n", an_ep->usb_ep_inst.name,
616 an_ep->cyepconfig.type, cy_as_usb_int) ;
617 #endif
618 return -EINVAL;
619 }
620 break;
621 default:
622 if (an_ep->cyepconfig.type != cy_as_usb_bulk) {
623 #ifndef WESTBRIDGE_NDEBUG
624 cy_as_hal_print_message("<1>_cy_as_gadget: "
625 "cy_as_usb_end_point_config EP %s mismatch "
626 "on type %d %d\n", an_ep->usb_ep_inst.name,
627 an_ep->cyepconfig.type, cy_as_usb_bulk) ;
628 #endif
629 return -EINVAL;
630 }
631 break;
632 }
633
634 tmp = desc->bEndpointAddress;
635 an_ep->is_in = (tmp & USB_DIR_IN) != 0;
636
637 if ((an_ep->cyepconfig.dir == cy_as_usb_in) &&
638 (!an_ep->is_in)) {
639 #ifndef WESTBRIDGE_NDEBUG
640 cy_as_hal_print_message("<1>_cy_as_gadget: "
641 "cy_as_usb_end_point_config EP %s mismatch "
642 "on dir %d %d\n", an_ep->usb_ep_inst.name,
643 an_ep->cyepconfig.dir, cy_as_usb_in) ;
644 #endif
645 return -EINVAL;
646 } else if ((an_ep->cyepconfig.dir == cy_as_usb_out) &&
647 (an_ep->is_in)) {
648 #ifndef WESTBRIDGE_NDEBUG
649 cy_as_hal_print_message("<1>_cy_as_gadget: "
650 "cy_as_usb_end_point_config EP %s mismatch "
651 "on dir %d %d\n", an_ep->usb_ep_inst.name,
652 an_ep->cyepconfig.dir, cy_as_usb_out) ;
653 #endif
654 return -EINVAL;
655 }
656
657 cy_as_usb_clear_stall(an_dev->dev_handle, an_ep->num,
658 cyasgadget_stallcallback, 0);
659
660 cy_as_hal_print_message("%s enabled %s (ep%d-%d) max %04x\n",
661 __func__, _ep->name, an_ep->num, tmp, max);
662
663 return 0;
664}
665
666static int cyasgadget_disable(
667 struct usb_ep *_ep
668 )
669{
670 cyasgadget_ep *an_ep;
671 unsigned long flags;
672
673 an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
674 if (!_ep || !an_ep->desc || _ep->name == cy_as_ep0name)
675 return -EINVAL;
676
677 spin_lock_irqsave(&an_ep->dev->lock, flags);
678 cyas_ep_reset(an_ep);
679
680 spin_unlock_irqrestore(&an_ep->dev->lock, flags);
681 return 0;
682}
683
684static struct usb_request *cyasgadget_alloc_request(
685 struct usb_ep *_ep, gfp_t gfp_flags
686 )
687{
688 cyasgadget_ep *an_ep;
689 cyasgadget_req *an_req;
690
691 if (!_ep)
692 return NULL;
693
694 an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
695
696 an_req = kzalloc(sizeof(cyasgadget_req), gfp_flags);
697 if (!an_req)
698 return NULL;
699
700 an_req->req.dma = DMA_ADDR_INVALID;
701 INIT_LIST_HEAD(&an_req->queue);
702
703 return &an_req->req;
704}
705
706static void cyasgadget_free_request(
707 struct usb_ep *_ep,
708 struct usb_request *_req
709 )
710{
711 cyasgadget_req *an_req ;
712
713 if (!_ep || !_req)
714 return ;
715
716 an_req = container_of(_req, cyasgadget_req, req) ;
717
718 kfree(an_req);
719}
720
721/* Load a packet into the fifo we use for usb IN transfers.
722 * works for all endpoints. */
723static int cyasgadget_queue(
724 struct usb_ep *_ep,
725 struct usb_request *_req,
726 gfp_t gfp_flags
727 )
728{
729 cyasgadget_req *as_req;
730 cyasgadget_ep *as_ep;
731 cyasgadget *cy_as_dev;
732 unsigned long flags;
733 cy_as_return_status_t ret = 0;
734
735 as_req = container_of(_req, cyasgadget_req, req);
736 if (!_req || !_req->complete || !_req->buf
737 || !list_empty(&as_req->queue))
738 return -EINVAL;
739
740 as_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
741
742 if (!_ep || (!as_ep->desc && (as_ep->num != 0)))
743 return -EINVAL;
744
745 cy_as_dev = as_ep->dev;
746 if (!cy_as_dev->driver ||
747 cy_as_dev->gadget.speed == USB_SPEED_UNKNOWN)
748 return -ESHUTDOWN;
749
750 spin_lock_irqsave(&cy_as_dev->lock, flags);
751
752 _req->status = -EINPROGRESS;
753 _req->actual = 0;
754
755 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
756
757 /* Call Async functions */
758 if (as_ep->is_in) {
759 #ifndef WESTBRIDGE_NDEBUG
760 cy_as_hal_print_message("<1>_cy_as_gadget: "
761 "cy_as_usb_write_data_async being called "
762 "on ep %d\n", as_ep->num) ;
763 #endif
764
765 ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle,
766 as_ep->num, _req->length, _req->buf,
767 cy_false, cyasgadget_writecallback) ;
768 if (ret != CY_AS_ERROR_SUCCESS)
769 cy_as_hal_print_message("<1>_cy_as_gadget: "
770 "cy_as_usb_write_data_async failed with "
771 "error code %d\n", ret) ;
772 else
773 _req->status = -EALREADY ;
774 } else if (as_ep->num == 0) {
775 /*
776 ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle,
777 as_ep->num, _req->length, _req->buf, cy_false,
778 cyasgadget_setupwritecallback) ;
779
780 if (ret != CY_AS_ERROR_SUCCESS)
781 cy_as_hal_print_message("<1>_cy_as_gadget: "
782 "cy_as_usb_write_data_async failed with error "
783 "code %d\n", ret) ;
784 */
785 if ((cy_as_dev->outsetupreq) && (_req->length)) {
786 #ifndef WESTBRIDGE_NDEBUG
787 cy_as_hal_print_message("<1>_cy_as_gadget: "
788 "cy_as_usb_read_data_async "
789 "being called on ep %d\n",
790 as_ep->num) ;
791 #endif
792
793 ret = cy_as_usb_read_data_async (
794 cy_as_dev->dev_handle, as_ep->num,
795 cy_true, _req->length, _req->buf,
796 cyasgadget_setupreadcallback);
797
798 if (ret != CY_AS_ERROR_SUCCESS)
799 cy_as_hal_print_message("<1>_cy_as_gadget: "
800 "cy_as_usb_read_data_async failed with "
801 "error code %d\n", ret) ;
802
803 } else {
804 #ifndef WESTBRIDGE_NDEBUG
805 cy_as_hal_print_message("<1>_cy_as_gadget: "
806 "cy_as_usb_write_data_async "
807 "being called on ep %d\n",
808 as_ep->num) ;
809 #endif
810
811 ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle,
812 as_ep->num, _req->length, _req->buf, cy_false,
813 cyasgadget_setupwritecallback) ;
814
815 if (ret != CY_AS_ERROR_SUCCESS)
816 cy_as_hal_print_message("<1>_cy_as_gadget: "
817 "cy_as_usb_write_data_async failed with "
818 "error code %d\n", ret) ;
819 }
820
821 } else if (list_empty(&as_ep->queue)) {
822 #ifndef WESTBRIDGE_NDEBUG
823 cy_as_hal_print_message("<1>_cy_as_gadget: "
824 "cy_as_usb_read_data_async being called since "
825 "ep queue empty%d\n", ret) ;
826 #endif
827
828 ret = cy_as_usb_read_data_async(cy_as_dev->dev_handle,
829 as_ep->num, cy_false, _req->length, _req->buf,
830 cyasgadget_readcallback) ;
831 if (ret != CY_AS_ERROR_SUCCESS)
832 cy_as_hal_print_message("<1>_cy_as_gadget: "
833 "cy_as_usb_read_data_async failed with error "
834 "code %d\n", ret) ;
835 else
836 _req->status = -EALREADY ;
837 }
838
839 spin_lock_irqsave(&cy_as_dev->lock, flags);
840
841 if (as_req)
842 list_add_tail(&as_req->queue, &as_ep->queue);
843
844 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
845
846 return 0;
847}
848
849/* dequeue request */
850static int cyasgadget_dequeue(
851 struct usb_ep *_ep,
852 struct usb_request *_req
853 )
854{
855 cyasgadget_ep *an_ep;
856 cyasgadget *dev;
857 an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
858 dev = an_ep->dev ;
859
860 #ifndef WESTBRIDGE_NDEBUG
861 cy_as_hal_print_message("<1>%s called\n", __func__);
862 #endif
863
864 cy_as_usb_cancel_async(dev->dev_handle, an_ep->num);
865
866 return 0;
867}
868
869static int cyasgadget_set_halt(
870 struct usb_ep *_ep,
871 int value
872 )
873{
874 cyasgadget_ep *an_ep;
875 int retval = 0;
876
877 #ifndef WESTBRIDGE_NDEBUG
878 cy_as_hal_print_message("<1>%s called\n", __func__);
879 #endif
880
881 an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst);
882 if (!_ep || (!an_ep->desc && an_ep->num != 0))
883 return -EINVAL;
884
885 if (!an_ep->dev->driver || an_ep->dev->gadget.speed ==
886 USB_SPEED_UNKNOWN)
887 return -ESHUTDOWN;
888
889 if (an_ep->desc /* not ep0 */ &&
890 (an_ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
891 return -EINVAL;
892
893 if (!list_empty(&an_ep->queue))
894 retval = -EAGAIN;
895 else if (an_ep->is_in && value &&
896 cyasgadget_fifo_status(_ep) != 0)
897 retval = -EAGAIN;
898 else {
899 if (value) {
900 cy_as_usb_set_stall(an_ep->dev->dev_handle,
901 an_ep->num, cyasgadget_stallcallback, 0) ;
902 } else {
903 cy_as_usb_clear_stall(an_ep->dev->dev_handle,
904 an_ep->num, cyasgadget_stallcallback, 0) ;
905 }
906 }
907
908 return retval;
909}
910
911static int cyasgadget_fifo_status(
912 struct usb_ep *_ep
913 )
914{
915 #ifndef WESTBRIDGE_NDEBUG
916 cy_as_hal_print_message("<1>%s called\n", __func__);
917 #endif
918
919 return 0 ;
920}
921
922static void cyasgadget_fifo_flush(
923 struct usb_ep *_ep
924 )
925{
926 #ifndef WESTBRIDGE_NDEBUG
927 cy_as_hal_print_message("<1>%s called\n", __func__);
928 #endif
929}
930
931static struct usb_ep_ops cyasgadget_ep_ops = {
932 .enable = cyasgadget_enable,
933 .disable = cyasgadget_disable,
934 .alloc_request = cyasgadget_alloc_request,
935 .free_request = cyasgadget_free_request,
936 .queue = cyasgadget_queue,
937 .dequeue = cyasgadget_dequeue,
938 .set_halt = cyasgadget_set_halt,
939 .fifo_status = cyasgadget_fifo_status,
940 .fifo_flush = cyasgadget_fifo_flush,
941};
942
943/*************************************************************/
944/*This subsection contains all usb_gadget_ops cyasgadget_ops */
945/*************************************************************/
946static int cyasgadget_get_frame(
947 struct usb_gadget *_gadget
948 )
949{
950 #ifndef WESTBRIDGE_NDEBUG
951 cy_as_hal_print_message("<1>%s called\n", __func__);
952 #endif
953 return 0 ;
954}
955
956static int cyasgadget_wakeup(
957 struct usb_gadget *_gadget
958 )
959{
960 #ifndef WESTBRIDGE_NDEBUG
961 cy_as_hal_print_message("<1>%s called\n", __func__);
962 #endif
963 return 0;
964}
965
966static int cyasgadget_set_selfpowered(
967 struct usb_gadget *_gadget,
968 int value
969 )
970{
971 #ifndef WESTBRIDGE_NDEBUG
972 cy_as_hal_print_message("<1>%s called\n", __func__);
973 #endif
974 return 0;
975}
976
977static int cyasgadget_pullup(
978 struct usb_gadget *_gadget,
979 int is_on
980 )
981{
982 struct cyasgadget *cy_as_dev ;
983 unsigned long flags;
984
985 #ifndef WESTBRIDGE_NDEBUG
986 cy_as_hal_print_message("<1>%s called\n", __func__);
987 #endif
988
989 if (!_gadget)
990 return -ENODEV;
991
992 cy_as_dev = container_of(_gadget, cyasgadget, gadget);
993
994 spin_lock_irqsave(&cy_as_dev->lock, flags);
995 cy_as_dev->softconnect = (is_on != 0);
996 if (is_on)
997 cy_as_usb_connect(cy_as_dev->dev_handle, 0, 0) ;
998 else
999 cy_as_usb_disconnect(cy_as_dev->dev_handle, 0, 0) ;
1000
1001 spin_unlock_irqrestore(&cy_as_dev->lock, flags);
1002
1003 return 0;
1004}
1005
1006static int cyasgadget_ioctl(
1007 struct usb_gadget *_gadget,
1008 unsigned code,
1009 unsigned long param
1010 )
1011{
1012 int err = 0;
1013 int retval = 0;
1014 int ret_stat = 0;
1015 cyasgadget *dev = cy_as_gadget_controller ;
1016
1017 #ifndef WESTBRIDGE_NDEBUG
1018 cy_as_hal_print_message("<1>%s called, code=%d, param=%ld\n",
1019 __func__, code, param);
1020 #endif
1021 /*
1022 * extract the type and number bitfields, and don't decode
1023 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
1024 */
1025 if (_IOC_TYPE(code) != CYASGADGET_IOC_MAGIC) {
1026 #ifndef WESTBRIDGE_NDEBUG
1027 cy_as_hal_print_message("%s, bad magic number = 0x%x\n",
1028 __func__, _IOC_TYPE(code));
1029 #endif
1030 return -ENOTTY;
1031 }
1032
1033 if (_IOC_NR(code) > CYASGADGET_IOC_MAXNR) {
1034 #ifndef WESTBRIDGE_NDEBUG
1035 cy_as_hal_print_message("%s, bad ioctl code = 0x%x\n",
1036 __func__, _IOC_NR(code));
1037 #endif
1038 return -ENOTTY;
1039 }
1040
1041 /*
1042 * the direction is a bitmask, and VERIFY_WRITE catches R/W
1043 * transfers. `Type' is user-oriented, while
1044 * access_ok is kernel-oriented, so the concept of "read" and
1045 * "write" is reversed
1046 */
1047 if (_IOC_DIR(code) & _IOC_READ)
1048 err = !access_ok(VERIFY_WRITE,
1049 (void __user *)param, _IOC_SIZE(code));
1050 else if (_IOC_DIR(code) & _IOC_WRITE)
1051 err = !access_ok(VERIFY_READ,
1052 (void __user *)param, _IOC_SIZE(code));
1053
1054 if (err) {
1055 cy_as_hal_print_message("%s, bad ioctl dir = 0x%x\n",
1056 __func__, _IOC_DIR(code));
1057 return -EFAULT;
1058 }
1059
1060 switch (code) {
1061 case CYASGADGET_GETMTPSTATUS:
1062 {
1063 cy_as_gadget_ioctl_tmtp_status *usr_d =
1064 (cy_as_gadget_ioctl_tmtp_status *)param ;
1065
1066 #ifndef WESTBRIDGE_NDEBUG
1067 cy_as_hal_print_message("%s: got CYASGADGET_GETMTPSTATUS\n",
1068 __func__);
1069 #endif
1070
1071 retval = __put_user(dev->tmtp_send_complete,
1072 (uint32_t __user *)(&(usr_d->tmtp_send_complete)));
1073 retval = __put_user(dev->tmtp_get_complete,
1074 (uint32_t __user *)(&(usr_d->tmtp_get_complete)));
1075 retval = __put_user(dev->tmtp_need_new_blk_tbl,
1076 (uint32_t __user *)(&(usr_d->tmtp_need_new_blk_tbl)));
1077
1078 if (copy_to_user((&(usr_d->tmtp_send_complete_data)),
1079 (&(dev->tmtp_send_complete_data)),
1080 sizeof(cy_as_gadget_ioctl_send_object)))
1081 return -EFAULT;
1082
1083 if (copy_to_user((&(usr_d->tmtp_get_complete_data)),
1084 (&(dev->tmtp_get_complete_data)),
1085 sizeof(cy_as_gadget_ioctl_get_object)))
1086 return -EFAULT;
1087 break;
1088 }
1089 case CYASGADGET_CLEARTMTPSTATUS:
1090 {
1091 #ifndef WESTBRIDGE_NDEBUG
1092 cy_as_hal_print_message("%s got CYASGADGET_CLEARTMTPSTATUS\n",
1093 __func__);
1094 #endif
1095
1096 dev->tmtp_send_complete = 0 ;
1097 dev->tmtp_get_complete = 0 ;
1098 dev->tmtp_need_new_blk_tbl = 0 ;
1099
1100 break;
1101 }
1102 case CYASGADGET_INITSOJ:
1103 {
1104 cy_as_gadget_ioctl_i_s_o_j_d k_d ;
1105 cy_as_gadget_ioctl_i_s_o_j_d *usr_d =
1106 (cy_as_gadget_ioctl_i_s_o_j_d *)param ;
1107 cy_as_mtp_block_table blk_table ;
1108 struct scatterlist sg ;
1109 char *alloc_filename;
1110 struct file *file_to_allocate;
1111
1112 #ifndef WESTBRIDGE_NDEBUG
1113 cy_as_hal_print_message("%s got CYASGADGET_INITSOJ\n",
1114 __func__);
1115 #endif
1116
1117 memset(&blk_table, 0, sizeof(blk_table));
1118
1119 /* Get user argument structure */
1120 if (copy_from_user(&k_d, usr_d,
1121 sizeof(cy_as_gadget_ioctl_i_s_o_j_d)))
1122 return -EFAULT;
1123
1124 /* better use fixed size buff*/
1125 alloc_filename = kmalloc(k_d.name_length + 1, GFP_KERNEL);
7b1f6bfb
VK
1126 if (alloc_filename == NULL)
1127 return -ENOMEM;
81eb669b
DC
1128
1129 /* get the filename */
1130 if (copy_from_user(alloc_filename, k_d.file_name,
1131 k_d.name_length + 1)) {
1132 #ifndef WESTBRIDGE_NDEBUG
1133 cy_as_hal_print_message("%s: CYASGADGET_INITSOJ, "
1134 "copy file name from user space failed\n",
1135 __func__);
1136 #endif
7b1f6bfb 1137 kfree(alloc_filename);
81eb669b
DC
1138 return -EFAULT;
1139 }
1140
1141 file_to_allocate = filp_open(alloc_filename, O_RDWR, 0);
1142
7b1f6bfb 1143 if (!IS_ERR(file_to_allocate)) {
81eb669b
DC
1144
1145 struct address_space *mapping =
1146 file_to_allocate->f_mapping;
1147 const struct address_space_operations *a_ops =
1148 mapping->a_ops;
1149 struct inode *inode = mapping->host;
1150 struct inode *alloc_inode =
1151 file_to_allocate->f_path.dentry->d_inode;
1152 int cluster = 0;
1153 uint32_t num_clusters = 0;
1154 struct buffer_head bh;
1155 struct kstat stat;
1156 struct iattr alloc_iattr;
1157 int nr_pages = 0;
1158 int ret_stat = 0;
1159
1160 #ifndef WESTBRIDGE_NDEBUG
1161 cy_as_hal_print_message("%s: fhandle is OK, "
1162 "calling vfs_getattr\n", __func__);
1163 #endif
1164
1165 ret_stat = vfs_getattr(file_to_allocate->f_path.mnt,
1166 file_to_allocate->f_path.dentry, &stat);
1167
1168 #ifndef WESTBRIDGE_NDEBUG
1169 cy_as_hal_print_message("%s: returned from "
1170 "vfs_getattr() stat->blksize=0x%lx\n",
1171 __func__, stat.blksize);
1172 #endif
1173
1174 /* TODO: get this from disk properties
1175 * (from blockdevice)*/
1176 #define SECTOR_SIZE 512
1177 if (stat.blksize != 0) {
1178 num_clusters = (k_d.num_bytes) / SECTOR_SIZE;
1179
1180 if (((k_d.num_bytes) % SECTOR_SIZE) != 0)
1181 num_clusters++;
1182 } else {
1183 goto initsoj_safe_exit;
1184 }
1185
1186 bh.b_state = 0;
1187 bh.b_blocknr = 0;
1188 /* block size is arbitrary , we'll use sector size*/
1189 bh.b_size = SECTOR_SIZE ;
1190
1191 #ifndef WESTBRIDGE_NDEBUG
1192 cy_as_hal_print_message("%s: getting fat blocks %d "
1193 "size of %d\n", __func__,
1194 num_clusters, bh.b_size);
1195 #endif
1196 for (cluster = 0; cluster < num_clusters; cluster++) {
1197 ret_stat = fat_get_block(inode,
1198 cluster, &bh, 1);
1199 if (ret_stat) {
1200 cy_as_hal_print_message(
1201 "%s: unable to get fat block, "
1202 "ret_stat=0x%d\n",
1203 __func__, ret_stat);
1204 goto initsoj_safe_exit;
1205 }
1206 }
1207
1208 #ifndef WESTBRIDGE_NDEBUG
1209 cy_as_hal_print_message("%s: allocated clusters "
1210 "successfully (fat_get_block), check bmap..."
1211 "\n", __func__);
1212 #endif
1213
1214 alloc_iattr.ia_valid = ATTR_SIZE;
1215 alloc_iattr.ia_size = k_d.num_bytes;
1216
1217 #ifndef WESTBRIDGE_NDEBUG
1218 cy_as_hal_print_message("%s: calling fat_notify_change "
1219 "(ia_valid:%d, ia_size:%d)\n", __func__,
1220 alloc_iattr.ia_valid,
1221 (int)alloc_iattr.ia_size);
1222 #endif
1223
1224 /* adjust the filesize */
1225 ret_stat = alloc_inode->i_op->setattr(
1226 file_to_allocate->f_path.dentry, &alloc_iattr);
1227 #ifndef WESTBRIDGE_NDEBUG
1228 cy_as_hal_print_message("%s: fat_setattr() "
1229 "returned 0x%x\n",
1230 __func__, ret_stat);
1231 #endif
1232
1233 /* clear dirty pages in page cache
1234 * (if were any allocated) */
1235 nr_pages = (k_d.num_bytes) / (PAGE_CACHE_SIZE);
1236
1237 if (((k_d.num_bytes) % (PAGE_CACHE_SIZE)) != 0)
1238 nr_pages++;
1239
1240 #ifndef WESTBRIDGE_NDEBUG
1241 /*check out how many pages where actually allocated */
1242 if (mapping->nrpages != nr_pages)
1243 cy_as_hal_print_message("%s mpage_cleardirty "
1244 "mapping->nrpages %d != num_pages %d\n",
1245 __func__, (int) mapping->nrpages,
1246 nr_pages);
1247
1248 cy_as_hal_print_message("%s: calling "
1249 "mpage_cleardirty() "
1250 "for %d pages\n", __func__, nr_pages);
1251 #endif
1252
1253 ret_stat = mpage_cleardirty(mapping, nr_pages);
1254
1255 /*fill up the the block table from the addr mapping */
1256 if (a_ops->bmap) {
1257 int8_t blk_table_idx = -1;
1258 uint32_t file_block_idx = 0;
1259 uint32_t last_blk_addr_map = 0,
1260 curr_blk_addr_map = 0;
1261
1262 #ifndef WESTBRIDGE_NDEBUG
1263 if (alloc_inode->i_bytes == 0)
1264 cy_as_hal_print_message(
1265 "%s: alloc_inode->ibytes =0\n",
1266 __func__);
1267 #endif
1268
1269 /* iterate through the list of
1270 * blocks (not clusters)*/
1271 for (file_block_idx = 0;
1272 file_block_idx < num_clusters
1273 /*inode->i_bytes*/; file_block_idx++) {
1274
1275 /* returns starting sector number */
1276 curr_blk_addr_map =
1277 a_ops->bmap(mapping,
1278 file_block_idx);
1279
1280 /*no valid mapping*/
1281 if (curr_blk_addr_map == 0) {
1282 #ifndef WESTBRIDGE_NDEBUG
1283 cy_as_hal_print_message(
1284 "%s:hit invalid "
1285 "mapping\n", __func__);
1286 #endif
1287 break;
1288 } else if (curr_blk_addr_map !=
1289 (last_blk_addr_map + 1) ||
1290 (blk_table.num_blocks
1291 [blk_table_idx] == 65535)) {
1292
1293 /* next table entry */
1294 blk_table_idx++;
1295 /* starting sector of a
1296 * scattered cluster*/
1297 blk_table.start_blocks
1298 [blk_table_idx] =
1299 curr_blk_addr_map;
1300 /* ++ num of blocks in cur
1301 * table entry*/
1302 blk_table.
1303 num_blocks[blk_table_idx]++;
1304
1305 #ifndef WESTBRIDGE_NDEBUG
1306 if (file_block_idx != 0)
1307 cy_as_hal_print_message(
1308 "<*> next table "
1309 "entry:%d required\n",
1310 blk_table_idx);
1311 #endif
1312 } else {
1313 /*add contiguous block*/
1314 blk_table.num_blocks
1315 [blk_table_idx]++;
1316 } /*if (curr_blk_addr_map == 0)*/
1317
1318 last_blk_addr_map = curr_blk_addr_map;
1319 } /* end for (file_block_idx = 0; file_block_idx
1320 < inode->i_bytes;) */
1321
1322 #ifndef WESTBRIDGE_NDEBUG
1323 /*print result for verification*/
1324 {
1325 int i;
1326 cy_as_hal_print_message(
1327 "%s: print block table "
1328 "mapping:\n",
1329 __func__);
1330 for (i = 0; i <= blk_table_idx; i++) {
1331 cy_as_hal_print_message(
1332 "<1> %d 0x%x 0x%x\n", i,
1333 blk_table.start_blocks[i],
1334 blk_table.num_blocks[i]);
1335 }
1336 }
1337 #endif
1338
1339 /* copy the block table to user
1340 * space (for debug purposes) */
1341 retval = __put_user(
1342 blk_table.start_blocks[blk_table_idx],
1343 (uint32_t __user *)
1344 (&(usr_d->blk_addr_p)));
1345
1346 retval = __put_user(
1347 blk_table.num_blocks[blk_table_idx],
1348 (uint32_t __user *)
1349 (&(usr_d->blk_count_p)));
1350
1351 blk_table_idx++;
1352 retval = __put_user(blk_table_idx,
1353 (uint32_t __user *)
1354 (&(usr_d->item_count)));
1355
1356 } /*end if (a_ops->bmap)*/
1357
1358 filp_close(file_to_allocate, NULL);
1359
1360 dev->tmtp_send_complete = 0 ;
1361 dev->tmtp_need_new_blk_tbl = 0 ;
1362
1363 #ifndef WESTBRIDGE_NDEBUG
1364 cy_as_hal_print_message(
1365 "%s: calling cy_as_mtp_init_send_object()\n",
1366 __func__);
1367 #endif
1368 sg_init_one(&sg, &blk_table, sizeof(blk_table));
1369 ret_stat = cy_as_mtp_init_send_object(dev->dev_handle,
1370 (cy_as_mtp_block_table *)&sg,
1371 k_d.num_bytes, 0, 0);
1372 #ifndef WESTBRIDGE_NDEBUG
1373 cy_as_hal_print_message("%s: returned from "
1374 "cy_as_mtp_init_send_object()\n", __func__);
1375 #endif
1376
1377 }
1378 #ifndef WESTBRIDGE_NDEBUG
1379 else {
1380 cy_as_hal_print_message(
1381 "%s: failed to allocate the file %s\n",
1382 __func__, alloc_filename);
1383 } /* end if (file_to_allocate)*/
1384 #endif
7b1f6bfb 1385 kfree(alloc_filename);
81eb669b
DC
1386initsoj_safe_exit:
1387 ret_stat = 0;
1388 retval = __put_user(ret_stat,
1389 (uint32_t __user *)(&(usr_d->ret_val)));
1390
1391 break;
1392 }
1393 case CYASGADGET_INITGOJ:
1394 {
1395 cy_as_gadget_ioctl_i_g_o_j_d k_d ;
1396 cy_as_gadget_ioctl_i_g_o_j_d *usr_d =
1397 (cy_as_gadget_ioctl_i_g_o_j_d *)param ;
1398 cy_as_mtp_block_table blk_table ;
1399 struct scatterlist sg ;
1400 char *map_filename;
1401 struct file *file_to_map;
1402
1403 #ifndef WESTBRIDGE_NDEBUG
1404 cy_as_hal_print_message(
1405 "%s: got CYASGADGET_INITGOJ\n",
1406 __func__);
1407 #endif
1408
1409 memset(&blk_table, 0, sizeof(blk_table));
1410
1411 /* Get user argument sturcutre */
1412 if (copy_from_user(&k_d, usr_d,
1413 sizeof(cy_as_gadget_ioctl_i_g_o_j_d)))
1414 return -EFAULT;
1415
1416 map_filename = kmalloc(k_d.name_length + 1, GFP_KERNEL);
7b1f6bfb
VK
1417 if (map_filename == NULL)
1418 return -ENOMEM;
81eb669b
DC
1419 if (copy_from_user(map_filename, k_d.file_name,
1420 k_d.name_length + 1)) {
1421 #ifndef WESTBRIDGE_NDEBUG
1422 cy_as_hal_print_message("%s: copy file name from "
1423 "user space failed\n", __func__);
1424 #endif
7b1f6bfb 1425 kfree(map_filename);
81eb669b
DC
1426 return -EFAULT;
1427 }
1428
1429 #ifndef WESTBRIDGE_NDEBUG
1430 cy_as_hal_print_message("<*>%s: opening %s for kernel "
1431 "mode access map\n", __func__, map_filename);
1432 #endif
1433 file_to_map = filp_open(map_filename, O_RDWR, 0);
1434 if (file_to_map) {
1435 struct address_space *mapping = file_to_map->f_mapping;
1436 const struct address_space_operations
1437 *a_ops = mapping->a_ops;
1438 struct inode *inode = mapping->host;
1439
1440 int8_t blk_table_idx = -1;
1441 uint32_t file_block_idx = 0;
1442 uint32_t last_blk_addr_map = 0, curr_blk_addr_map = 0;
1443
1444 /*verify operation exists*/
1445 if (a_ops->bmap) {
1446 #ifndef WESTBRIDGE_NDEBUG
1447 cy_as_hal_print_message(
1448 "<*>%s: bmap found, i_bytes=0x%x, "
1449 "i_size=0x%x, i_blocks=0x%x\n",
1450 __func__, inode->i_bytes,
1451 (unsigned int) inode->i_size,
1452 (unsigned int) inode->i_blocks);
1453 #endif
1454
1455 k_d.num_bytes = inode->i_size;
1456
1457 #ifndef WESTBRIDGE_NDEBUG
1458 cy_as_hal_print_message(
1459 "<*>%s: k_d.num_bytes=0x%x\n",
1460 __func__, k_d.num_bytes);
1461 #endif
1462
1463 for (file_block_idx = 0;
1464 file_block_idx < inode->i_size;
1465 file_block_idx++) {
1466 curr_blk_addr_map =
1467 a_ops->bmap(mapping,
1468 file_block_idx);
1469
1470 if (curr_blk_addr_map == 0) {
1471 /*no valid mapping*/
1472 #ifndef WESTBRIDGE_NDEBUG
1473 cy_as_hal_print_message(
1474 "%s: no valid "
1475 "mapping\n", __func__);
1476 #endif
1477 break;
1478 } else if (curr_blk_addr_map !=
1479 (last_blk_addr_map + 1)) {
1480 /*non-contiguous break*/
1481 blk_table_idx++;
1482 blk_table.start_blocks
1483 [blk_table_idx] =
1484 curr_blk_addr_map;
1485 blk_table.num_blocks
1486 [blk_table_idx]++;
1487 #ifndef WESTBRIDGE_NDEBUG
1488 cy_as_hal_print_message(
1489 "%s: found non-"
1490 "contiguous break",
1491 __func__);
1492 #endif
1493 } else {
1494 /*add contiguous block*/
1495 blk_table.num_blocks
1496 [blk_table_idx]++;
1497 }
1498 last_blk_addr_map = curr_blk_addr_map;
1499 }
1500
1501 /*print result for verification*/
1502 #ifndef WESTBRIDGE_NDEBUG
1503 {
1504 int i = 0;
1505
1506 for (i = 0 ; i <= blk_table_idx; i++) {
1507 cy_as_hal_print_message(
1508 "%s %d 0x%x 0x%x\n",
1509 __func__, i,
1510 blk_table.start_blocks[i],
1511 blk_table.num_blocks[i]);
1512 }
1513 }
1514 #endif
1515 } else {
1516 #ifndef WESTBRIDGE_NDEBUG
1517 cy_as_hal_print_message(
1518 "%s: could not find "
1519 "a_ops->bmap\n", __func__);
1520 #endif
1521 return -EFAULT;
1522 }
1523
1524 filp_close(file_to_map, NULL);
1525
1526 dev->tmtp_get_complete = 0 ;
1527 dev->tmtp_need_new_blk_tbl = 0 ;
1528
1529 ret_stat = __put_user(
1530 blk_table.start_blocks[blk_table_idx],
1531 (uint32_t __user *)(&(usr_d->blk_addr_p)));
1532
1533 ret_stat = __put_user(
1534 blk_table.num_blocks[blk_table_idx],
1535 (uint32_t __user *)(&(usr_d->blk_count_p)));
1536
1537 sg_init_one(&sg, &blk_table, sizeof(blk_table));
1538
1539 #ifndef WESTBRIDGE_NDEBUG
1540 cy_as_hal_print_message(
1541 "%s: calling cy_as_mtp_init_get_object() "
1542 "start=0x%x, num =0x%x, tid=0x%x, "
1543 "num_bytes=0x%x\n",
1544 __func__,
1545 blk_table.start_blocks[0],
1546 blk_table.num_blocks[0],
1547 k_d.tid,
1548 k_d.num_bytes);
1549 #endif
1550
1551 ret_stat = cy_as_mtp_init_get_object(
1552 dev->dev_handle,
1553 (cy_as_mtp_block_table *)&sg,
1554 k_d.num_bytes, k_d.tid, 0, 0);
1555 if (ret_stat != CY_AS_ERROR_SUCCESS) {
1556 #ifndef WESTBRIDGE_NDEBUG
1557 cy_as_hal_print_message(
1558 "%s: cy_as_mtp_init_get_object "
1559 "failed ret_stat=0x%x\n",
1560 __func__, ret_stat);
1561 #endif
1562 }
1563 }
1564 #ifndef WESTBRIDGE_NDEBUG
1565 else {
1566 cy_as_hal_print_message(
1567 "%s: failed to open file %s\n",
1568 __func__, map_filename);
1569 }
1570 #endif
7b1f6bfb 1571 kfree(map_filename);
81eb669b
DC
1572
1573 ret_stat = 0;
1574 retval = __put_user(ret_stat, (uint32_t __user *)
1575 (&(usr_d->ret_val)));
1576 break;
1577 }
1578 case CYASGADGET_CANCELSOJ:
1579 {
1580 cy_as_gadget_ioctl_cancel *usr_d =
1581 (cy_as_gadget_ioctl_cancel *)param ;
1582
1583 #ifndef WESTBRIDGE_NDEBUG
1584 cy_as_hal_print_message(
1585 "%s: got CYASGADGET_CANCELSOJ\n",
1586 __func__);
1587 #endif
1588
1589 ret_stat = cy_as_mtp_cancel_send_object(dev->dev_handle, 0, 0);
1590
1591 retval = __put_user(ret_stat, (uint32_t __user *)
1592 (&(usr_d->ret_val)));
1593 break;
1594 }
1595 case CYASGADGET_CANCELGOJ:
1596 {
1597 cy_as_gadget_ioctl_cancel *usr_d =
1598 (cy_as_gadget_ioctl_cancel *)param ;
1599
1600 #ifndef WESTBRIDGE_NDEBUG
1601 cy_as_hal_print_message("%s: got CYASGADGET_CANCELGOJ\n",
1602 __func__);
1603 #endif
1604
1605 ret_stat = cy_as_mtp_cancel_get_object(dev->dev_handle, 0, 0);
1606
1607 retval = __put_user(ret_stat,
1608 (uint32_t __user *)(&(usr_d->ret_val)));
1609 break;
1610 }
1611 default:
1612 {
1613 #ifndef WESTBRIDGE_NDEBUG
1614 cy_as_hal_print_message("%s: unknown ioctl received: %d\n",
1615 __func__, code);
1616
1617 cy_as_hal_print_message("%s: known codes:\n"
1618 "CYASGADGET_GETMTPSTATUS=%d\n"
1619 "CYASGADGET_CLEARTMTPSTATUS=%d\n"
1620 "CYASGADGET_INITSOJ=%d\n"
1621 "CYASGADGET_INITGOJ=%d\n"
1622 "CYASGADGET_CANCELSOJ=%d\n"
1623 "CYASGADGET_CANCELGOJ=%d\n",
1624 __func__,
1625 CYASGADGET_GETMTPSTATUS,
1626 CYASGADGET_CLEARTMTPSTATUS,
1627 CYASGADGET_INITSOJ,
1628 CYASGADGET_INITGOJ,
1629 CYASGADGET_CANCELSOJ,
1630 CYASGADGET_CANCELGOJ);
1631 #endif
1632 break;
1633 }
1634 }
1635
1636 return 0;
1637}
1638
1639static const struct usb_gadget_ops cyasgadget_ops = {
1640 .get_frame = cyasgadget_get_frame,
1641 .wakeup = cyasgadget_wakeup,
1642 .set_selfpowered = cyasgadget_set_selfpowered,
1643 .pullup = cyasgadget_pullup,
1644 .ioctl = cyasgadget_ioctl,
1645};
1646
1647
1648/* keeping it simple:
1649 * - one bus driver, initted first;
1650 * - one function driver, initted second
1651 *
1652 * most of the work to support multiple controllers would
1653 * be to associate this gadget driver with all of them, or
1654 * perhaps to bind specific drivers to specific devices.
1655 */
1656
1657static void cyas_ep_reset(
1658 cyasgadget_ep *an_ep
1659 )
1660{
1661 #ifndef WESTBRIDGE_NDEBUG
1662 cy_as_hal_print_message("<1>%s called\n", __func__);
1663 #endif
1664
1665 an_ep->desc = NULL;
1666 INIT_LIST_HEAD(&an_ep->queue);
1667
1668 an_ep->stopped = 0 ;
1669 an_ep->is_in = 0 ;
1670 an_ep->is_iso = 0 ;
1671 an_ep->usb_ep_inst.maxpacket = ~0;
1672 an_ep->usb_ep_inst.ops = &cyasgadget_ep_ops;
1673}
1674
1675static void cyas_usb_reset(
1676 cyasgadget *cy_as_dev
1677 )
1678{
1679 cy_as_return_status_t ret;
1680 cy_as_usb_enum_control config ;
1681
1682 #ifndef WESTBRIDGE_NDEBUG
1683 cy_as_device *dev_p = (cy_as_device *)cy_as_dev->dev_handle ;
1684
1685 cy_as_hal_print_message("<1>%s called mtp_firmware=0x%x\n",
1686 __func__, dev_p->is_mtp_firmware);
1687 #endif
1688
1689 ret = cy_as_misc_release_resource(cy_as_dev->dev_handle,
1690 cy_as_bus_u_s_b) ;
1691 if (ret != CY_AS_ERROR_SUCCESS && ret !=
1692 CY_AS_ERROR_RESOURCE_NOT_OWNED) {
1693 cy_as_hal_print_message("<1>_cy_as_gadget: cannot "
1694 "release usb resource: failed with error code %d\n",
1695 ret) ;
1696 return ;
1697 }
1698
1699 cy_as_dev->gadget.speed = USB_SPEED_HIGH ;
1700
1701 ret = cy_as_usb_start(cy_as_dev->dev_handle, 0, 0) ;
1702 if (ret != CY_AS_ERROR_SUCCESS) {
1703 cy_as_hal_print_message("<1>_cy_as_gadget: "
1704 "cy_as_usb_start failed with error code %d\n",
1705 ret) ;
1706 return ;
1707 }
1708 /* P port will do enumeration, not West Bridge */
1709 config.antioch_enumeration = cy_false ;
1710 /* 1 2 : 1-BUS_NUM , 2:Storage_device number, SD - is bus 1*/
1711
1712 /* TODO: add module param to enumerate mass storage */
1713 config.mass_storage_interface = 0 ;
1714
1715 if (append_mtp) {
1716 ret = cy_as_mtp_start(cy_as_dev->dev_handle,
1717 cy_as_gadget_mtp_event_callback, 0, 0);
1718 if (ret == CY_AS_ERROR_SUCCESS) {
1719 cy_as_hal_print_message("MTP start passed, enumerating "
1720 "MTP interface\n");
1721 config.mtp_interface = append_mtp ;
1722 /*Do not enumerate NAND storage*/
1723 config.devices_to_enumerate[0][0] = cy_false;
1724
1725 /*enumerate SD storage as MTP*/
1726 config.devices_to_enumerate[1][0] = cy_true;
1727 }
1728 } else {
1729 cy_as_hal_print_message("MTP start not attempted, not "
1730 "enumerating MTP interface\n");
1731 config.mtp_interface = 0 ;
1732 /* enumerate mass storage based on module parameters */
1733 config.devices_to_enumerate[0][0] = msc_enum_bus_0;
1734 config.devices_to_enumerate[1][0] = msc_enum_bus_1;
1735 }
1736
1737 ret = cy_as_usb_set_enum_config(cy_as_dev->dev_handle,
1738 &config, 0, 0) ;
1739 if (ret != CY_AS_ERROR_SUCCESS) {
1740 cy_as_hal_print_message("<1>_cy_as_gadget: "
1741 "cy_as_usb_set_enum_config failed with error "
1742 "code %d\n", ret) ;
1743 return ;
1744 }
1745
1746 cy_as_usb_set_physical_configuration(cy_as_dev->dev_handle, 1);
1747
1748}
1749
1750static void cyas_usb_reinit(
1751 cyasgadget *cy_as_dev
1752 )
1753{
1754 int index = 0;
1755 cyasgadget_ep *an_ep_p;
1756 cy_as_return_status_t ret;
1757 cy_as_device *dev_p = (cy_as_device *)cy_as_dev->dev_handle ;
1758
1759 INIT_LIST_HEAD(&cy_as_dev->gadget.ep_list);
1760
1761 #ifndef WESTBRIDGE_NDEBUG
1762 cy_as_hal_print_message("<1>%s called, is_mtp_firmware = "
1763 "0x%x\n", __func__, dev_p->is_mtp_firmware);
1764 #endif
1765
1766 /* Init the end points */
1767 for (index = 1; index <= 15; index++) {
1768 an_ep_p = &cy_as_dev->an_gadget_ep[index] ;
1769 cyas_ep_reset(an_ep_p) ;
1770 an_ep_p->usb_ep_inst.name = cy_as_ep_names[index] ;
1771 an_ep_p->dev = cy_as_dev ;
1772 an_ep_p->num = index ;
1773 memset(&an_ep_p->cyepconfig, 0, sizeof(an_ep_p->cyepconfig));
1774
1775 /* EP0, EPs 2,4,6,8 need not be added */
1776 if ((index <= 8) && (index % 2 == 0) &&
1777 (!dev_p->is_mtp_firmware)) {
1778 /* EP0 is 64 and EPs 2,4,6,8 not allowed */
1779 cy_as_dev->an_gadget_ep[index].fifo_size = 0 ;
1780 } else {
1781 if (index == 1)
1782 an_ep_p->fifo_size = 64;
1783 else
1784 an_ep_p->fifo_size = 512 ;
1785 list_add_tail(&an_ep_p->usb_ep_inst.ep_list,
1786 &cy_as_dev->gadget.ep_list);
1787 }
1788 }
1789 /* need to setendpointconfig before usb connect, this is not
1790 * quite compatible with gadget methodology (ep_enable called
1791 * by gadget after connect), therefore need to set config in
1792 * initialization and verify compatibility in ep_enable,
1793 * kick up error otherwise*/
1794 an_ep_p = &cy_as_dev->an_gadget_ep[3] ;
1795 an_ep_p->cyepconfig.enabled = cy_true ;
1796 an_ep_p->cyepconfig.dir = cy_as_usb_out ;
1797 an_ep_p->cyepconfig.type = cy_as_usb_bulk ;
1798 an_ep_p->cyepconfig.size = 0 ;
1799 an_ep_p->cyepconfig.physical = 1 ;
1800 ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle,
1801 3, &an_ep_p->cyepconfig) ;
1802 if (ret != CY_AS_ERROR_SUCCESS) {
1803 cy_as_hal_print_message("cy_as_usb_set_end_point_config "
1804 "failed with error code %d\n", ret) ;
1805 }
1806
1807 cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 3, 0, 0);
1808
1809 an_ep_p = &cy_as_dev->an_gadget_ep[5] ;
1810 an_ep_p->cyepconfig.enabled = cy_true ;
1811 an_ep_p->cyepconfig.dir = cy_as_usb_in ;
1812 an_ep_p->cyepconfig.type = cy_as_usb_bulk ;
1813 an_ep_p->cyepconfig.size = 0 ;
1814 an_ep_p->cyepconfig.physical = 2 ;
1815 ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle,
1816 5, &an_ep_p->cyepconfig) ;
1817 if (ret != CY_AS_ERROR_SUCCESS) {
1818 cy_as_hal_print_message("cy_as_usb_set_end_point_config "
1819 "failed with error code %d\n", ret) ;
1820 }
1821
1822 cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 5, 0, 0);
1823
1824 an_ep_p = &cy_as_dev->an_gadget_ep[9] ;
1825 an_ep_p->cyepconfig.enabled = cy_true ;
1826 an_ep_p->cyepconfig.dir = cy_as_usb_in ;
1827 an_ep_p->cyepconfig.type = cy_as_usb_bulk ;
1828 an_ep_p->cyepconfig.size = 0 ;
1829 an_ep_p->cyepconfig.physical = 4 ;
1830 ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle,
1831 9, &an_ep_p->cyepconfig) ;
1832 if (ret != CY_AS_ERROR_SUCCESS) {
1833 cy_as_hal_print_message("cy_as_usb_set_end_point_config "
1834 "failed with error code %d\n", ret) ;
1835 }
1836
1837 cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 9, 0, 0);
1838
1839 if (dev_p->mtp_count != 0) {
1840 /* these need to be set for compatibility with
1841 * the gadget_enable logic */
1842 an_ep_p = &cy_as_dev->an_gadget_ep[2] ;
1843 an_ep_p->cyepconfig.enabled = cy_true ;
1844 an_ep_p->cyepconfig.dir = cy_as_usb_out ;
1845 an_ep_p->cyepconfig.type = cy_as_usb_bulk ;
1846 an_ep_p->cyepconfig.size = 0 ;
1847 an_ep_p->cyepconfig.physical = 0 ;
1848 cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 2, 0, 0);
1849
1850 an_ep_p = &cy_as_dev->an_gadget_ep[6] ;
1851 an_ep_p->cyepconfig.enabled = cy_true ;
1852 an_ep_p->cyepconfig.dir = cy_as_usb_in ;
1853 an_ep_p->cyepconfig.type = cy_as_usb_bulk ;
1854 an_ep_p->cyepconfig.size = 0 ;
1855 an_ep_p->cyepconfig.physical = 0 ;
1856 cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 6, 0, 0);
1857 }
1858
1859 cyas_ep_reset(&cy_as_dev->an_gadget_ep[0]) ;
1860 cy_as_dev->an_gadget_ep[0].usb_ep_inst.name = cy_as_ep_names[0] ;
1861 cy_as_dev->an_gadget_ep[0].dev = cy_as_dev ;
1862 cy_as_dev->an_gadget_ep[0].num = 0 ;
1863 cy_as_dev->an_gadget_ep[0].fifo_size = 64 ;
1864
1865 cy_as_dev->an_gadget_ep[0].usb_ep_inst.maxpacket = 64;
1866 cy_as_dev->gadget.ep0 = &cy_as_dev->an_gadget_ep[0].usb_ep_inst;
1867 cy_as_dev->an_gadget_ep[0].stopped = 0;
1868 INIT_LIST_HEAD(&cy_as_dev->gadget.ep0->ep_list);
1869}
1870
1871static void cyas_ep0_start(
1872 cyasgadget *dev
1873 )
1874{
1875 cy_as_return_status_t ret ;
1876
1877 #ifndef WESTBRIDGE_NDEBUG
1878 cy_as_hal_print_message("<1>%s called\n", __func__);
1879 #endif
1880
1881 ret = cy_as_usb_register_callback(dev->dev_handle,
1882 cy_as_gadget_usb_event_callback) ;
1883 if (ret != CY_AS_ERROR_SUCCESS) {
1884 #ifndef WESTBRIDGE_NDEBUG
1885 cy_as_hal_print_message("%s: cy_as_usb_register_callback "
1886 "failed with error code %d\n", __func__, ret) ;
1887 #endif
1888 return ;
1889 }
1890
1891 ret = cy_as_usb_commit_config(dev->dev_handle, 0, 0) ;
1892 if (ret != CY_AS_ERROR_SUCCESS) {
1893 #ifndef WESTBRIDGE_NDEBUG
1894 cy_as_hal_print_message("%s: cy_as_usb_commit_config "
1895 "failed with error code %d\n", __func__, ret) ;
1896 #endif
1897 return ;
1898 }
1899
1900 #ifndef WESTBRIDGE_NDEBUG
1901 cy_as_hal_print_message("%s: cy_as_usb_commit_config "
1902 "message sent\n", __func__) ;
1903 #endif
1904
1905 ret = cy_as_usb_connect(dev->dev_handle, 0, 0) ;
1906 if (ret != CY_AS_ERROR_SUCCESS) {
1907 #ifndef WESTBRIDGE_NDEBUG
1908 cy_as_hal_print_message("%s: cy_as_usb_connect failed "
1909 "with error code %d\n", __func__, ret) ;
1910 #endif
1911 return ;
1912 }
1913
1914 #ifndef WESTBRIDGE_NDEBUG
1915 cy_as_hal_print_message("%s: cy_as_usb_connect message "
1916 "sent\n", __func__) ;
1917 #endif
1918}
1919
1920/*
1921 * When a driver is successfully registered, it will receive
1922 * control requests including set_configuration(), which enables
1923 * non-control requests. then usb traffic follows until a
1924 * disconnect is reported. then a host may connect again, or
1925 * the driver might get unbound.
1926 */
1927int usb_gadget_register_driver(
1928 struct usb_gadget_driver *driver
1929 )
1930{
1931 cyasgadget *dev = cy_as_gadget_controller ;
1932 int retval;
1933
1934 #ifndef WESTBRIDGE_NDEBUG
1935 cy_as_hal_print_message("<1>%s called driver=0x%x\n",
1936 __func__, (unsigned int) driver);
1937 #endif
1938
1939 /* insist on high speed support from the driver, since
1940 * "must not be used in normal operation"
1941 */
1942 if (!driver
1943 || !driver->bind
1944 || !driver->unbind
1945 || !driver->setup)
1946 return -EINVAL;
1947
1948 if (!dev)
1949 return -ENODEV;
1950
1951 if (dev->driver)
1952 return -EBUSY;
1953
1954 /* hook up the driver ... */
1955 dev->softconnect = 1;
1956 driver->driver.bus = NULL;
1957 dev->driver = driver;
1958 dev->gadget.dev.driver = &driver->driver;
1959
1960 /* Do the needful */
1961 cyas_usb_reset(dev) ; /* External usb */
1962 cyas_usb_reinit(dev) ; /* Internal */
1963
1964 retval = driver->bind(&dev->gadget);
1965 if (retval) {
1966 #ifndef WESTBRIDGE_NDEBUG
1967 cy_as_hal_print_message("%s bind to driver %s --> %d\n",
1968 __func__, driver->driver.name, retval);
1969 #endif
1970
1971 dev->driver = NULL;
1972 dev->gadget.dev.driver = NULL;
1973 return retval;
1974 }
1975
1976 /* ... then enable host detection and ep0; and we're ready
1977 * for set_configuration as well as eventual disconnect.
1978 */
1979 cyas_ep0_start(dev);
1980
1981 return 0;
1982}
1983EXPORT_SYMBOL(usb_gadget_register_driver);
1984
1985static void cyasgadget_nuke(
1986 cyasgadget_ep *an_ep
1987 )
1988{
1989 cyasgadget *dev = cy_as_gadget_controller ;
1990
1991 #ifndef WESTBRIDGE_NDEBUG
1992 cy_as_hal_print_message("<1>%s called\n", __func__);
1993 #endif
1994
1995 cy_as_usb_cancel_async(dev->dev_handle, an_ep->num);
1996 an_ep->stopped = 1 ;
1997
1998 while (!list_empty(&an_ep->queue)) {
1999 cyasgadget_req *an_req = list_entry
2000 (an_ep->queue.next, cyasgadget_req, queue) ;
2001 list_del_init(&an_req->queue) ;
2002 an_req->req.status = -ESHUTDOWN ;
2003 an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req) ;
2004 }
2005}
2006
2007static void cyasgadget_stop_activity(
2008 cyasgadget *dev,
2009 struct usb_gadget_driver *driver
2010 )
2011{
2012 int index ;
2013
2014 #ifndef WESTBRIDGE_NDEBUG
2015 cy_as_hal_print_message("<1>%s called\n", __func__);
2016 #endif
2017
2018 /* don't disconnect if it's not connected */
2019 if (dev->gadget.speed == USB_SPEED_UNKNOWN)
2020 driver = NULL;
2021
2022 if (spin_is_locked(&dev->lock))
2023 spin_unlock(&dev->lock);
2024
2025 /* Stop hardware; prevent new request submissions;
2026 * and kill any outstanding requests.
2027 */
2028 cy_as_usb_disconnect(dev->dev_handle, 0, 0) ;
2029
2030 for (index = 3; index <= 7; index += 2) {
2031 cyasgadget_ep *an_ep_p = &dev->an_gadget_ep[index] ;
2032 cyasgadget_nuke(an_ep_p) ;
2033 }
2034
2035 for (index = 9; index <= 15; index++) {
2036 cyasgadget_ep *an_ep_p = &dev->an_gadget_ep[index] ;
2037 cyasgadget_nuke(an_ep_p) ;
2038 }
2039
2040 /* report disconnect; the driver is already quiesced */
2041 if (driver)
2042 driver->disconnect(&dev->gadget);
2043
2044 #ifndef WESTBRIDGE_NDEBUG
2045 cy_as_hal_print_message("cy_as_usb_disconnect returned success");
2046 #endif
2047
2048 /* Stop Usb */
2049 cy_as_usb_stop(dev->dev_handle, 0, 0) ;
2050
2051 #ifndef WESTBRIDGE_NDEBUG
2052 cy_as_hal_print_message("cy_as_usb_stop returned success");
2053 #endif
2054}
2055
2056int usb_gadget_unregister_driver(
2057 struct usb_gadget_driver *driver
2058 )
2059{
2060 cyasgadget *dev = cy_as_gadget_controller ;
2061
2062 #ifndef WESTBRIDGE_NDEBUG
2063 cy_as_hal_print_message("<1>%s called\n", __func__);
2064 #endif
2065
2066 if (!dev)
2067 return -ENODEV;
2068
2069 if (!driver || driver != dev->driver)
2070 return -EINVAL;
2071
2072 cyasgadget_stop_activity(dev, driver);
2073
2074 driver->unbind(&dev->gadget);
2075 dev->gadget.dev.driver = NULL;
2076 dev->driver = NULL;
2077
2078 #ifndef WESTBRIDGE_NDEBUG
2079 cy_as_hal_print_message("unregistered driver '%s'\n",
2080 driver->driver.name) ;
2081 #endif
2082
2083 return 0;
2084}
2085EXPORT_SYMBOL(usb_gadget_unregister_driver);
2086
2087static void cyas_gadget_release(
2088 struct device *_dev
2089 )
2090{
2091 cyasgadget *dev = dev_get_drvdata(_dev);
2092
2093 #ifndef WESTBRIDGE_NDEBUG
2094 cy_as_hal_print_message("<1>%s called\n", __func__);
2095 #endif
2096
2097 kfree(dev);
2098}
2099
2100/* DeInitialize gadget driver */
2101static void cyasgadget_deinit(
2102 cyasgadget *cy_as_dev
2103 )
2104{
2105 #ifndef WESTBRIDGE_NDEBUG
2106 cy_as_hal_print_message("<1>_cy_as_gadget deinitialize called\n") ;
2107 #endif
2108
2109 if (!cy_as_dev) {
2110 #ifndef WESTBRIDGE_NDEBUG
2111 cy_as_hal_print_message("<1>_cy_as_gadget_deinit: "
2112 "invalid cyasgadget device\n") ;
2113 #endif
2114 return ;
2115 }
2116
2117 if (cy_as_dev->driver) {
2118 /* should have been done already by driver model core */
2119 #ifndef WESTBRIDGE_NDEBUG
2120 cy_as_hal_print_message("<1> cy_as_gadget: '%s' "
2121 "is still registered\n",
2122 cy_as_dev->driver->driver.name);
2123 #endif
2124 usb_gadget_unregister_driver(cy_as_dev->driver);
2125 }
2126
2127 kfree(cy_as_dev) ;
2128 cy_as_gadget_controller = NULL ;
2129}
2130
2131/* Initialize gadget driver */
2132static int cyasgadget_initialize(void)
2133{
2134 cyasgadget *cy_as_dev = 0 ;
2135 int retval = 0 ;
2136
2137 #ifndef WESTBRIDGE_NDEBUG
2138 cy_as_hal_print_message("<1>_cy_as_gadget [V1.1] initialize called\n") ;
2139 #endif
2140
2141 if (cy_as_gadget_controller != 0) {
2142 cy_as_hal_print_message("<1> cy_as_gadget: the device has "
2143 "already been initilaized. ignoring\n") ;
2144 return -EBUSY ;
2145 }
2146
2147 cy_as_dev = kzalloc(sizeof(cyasgadget), GFP_ATOMIC);
2148 if (cy_as_dev == NULL) {
2149 cy_as_hal_print_message("<1> cy_as_gadget: memory "
2150 "allocation failed\n") ;
2151 return -ENOMEM;
2152 }
2153
2154 spin_lock_init(&cy_as_dev->lock);
2155 cy_as_dev->gadget.ops = &cyasgadget_ops;
2156 cy_as_dev->gadget.is_dualspeed = 1;
2157
2158 /* the "gadget" abstracts/virtualizes the controller */
2159 /*strcpy(cy_as_dev->gadget.dev.bus_id, "cyasgadget");*/
2160 cy_as_dev->gadget.dev.release = cyas_gadget_release;
2161 cy_as_dev->gadget.name = cy_as_driver_name;
2162
2163 /* Get the device handle */
2164 cy_as_dev->dev_handle = cyasdevice_getdevhandle() ;
2165 if (0 == cy_as_dev->dev_handle) {
2166 #ifndef NDEBUG
2167 cy_as_hal_print_message("<1> cy_as_gadget: "
2168 "no west bridge device\n") ;
2169 #endif
2170 retval = -EFAULT ;
2171 goto done ;
2172 }
2173
2174 /* We are done now */
2175 cy_as_gadget_controller = cy_as_dev ;
2176 return 0 ;
2177
2178/*
2179 * in case of an error
2180 */
2181done:
2182 if (cy_as_dev)
2183 cyasgadget_deinit(cy_as_dev) ;
2184
2185 return retval ;
2186}
2187
2188static int __init cyas_init(void)
2189{
2190 int init_res = 0;
2191
2192 init_res = cyasgadget_initialize();
2193
2194 if (init_res != 0) {
2195 printk(KERN_WARNING "<1> gadget ctl instance "
2196 "init error:%d\n", init_res);
2197 if (init_res > 0) {
2198 /* force -E/0 linux convention */
2199 init_res = init_res * -1;
2200 }
2201 }
2202
2203 return init_res;
2204}
2205module_init(cyas_init);
2206
2207static void __exit cyas_cleanup(void)
2208{
2209 if (cy_as_gadget_controller != NULL)
2210 cyasgadget_deinit(cy_as_gadget_controller);
2211}
2212module_exit(cyas_cleanup);
2213
2214
2215MODULE_LICENSE("GPL");
2216MODULE_DESCRIPTION(CY_AS_DRIVER_DESC);
2217MODULE_AUTHOR("cypress semiconductor");
2218
2219/*[]*/