Fix common misspellings
[linux-block.git] / drivers / staging / westbridge / astoria / api / src / cyasusb.c
CommitLineData
81eb669b
DC
1/* Cypress West Bridge API source file (cyasusb.c)
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#include "../../include/linux/westbridge/cyashal.h"
23#include "../../include/linux/westbridge/cyasusb.h"
24#include "../../include/linux/westbridge/cyaserr.h"
25#include "../../include/linux/westbridge/cyasdma.h"
26#include "../../include/linux/westbridge/cyaslowlevel.h"
27#include "../../include/linux/westbridge/cyaslep2pep.h"
28#include "../../include/linux/westbridge/cyasregs.h"
29#include "../../include/linux/westbridge/cyasstorage.h"
30
31static cy_as_return_status_t
32cy_as_usb_ack_setup_packet(
33 /* Handle to the West Bridge device */
34 cy_as_device_handle handle,
35 /* The callback if async call */
36 cy_as_function_callback cb,
37 /* Client supplied data */
38 uint32_t client
0769c38d 39 );
81eb669b
DC
40
41static void
42cy_as_usb_func_callback(
43 cy_as_device *dev_p,
44 uint8_t context,
45 cy_as_ll_request_response *rqt,
46 cy_as_ll_request_response *resp,
0769c38d 47 cy_as_return_status_t ret);
81eb669b
DC
48/*
49* Reset the USB EP0 state
50*/
51static void
52cy_as_usb_reset_e_p0_state(cy_as_device *dev_p)
53{
0769c38d 54 cy_as_log_debug_message(6, "cy_as_usb_reset_e_p0_state called");
81eb669b 55
0769c38d
DC
56 cy_as_device_clear_ack_delayed(dev_p);
57 cy_as_device_clear_setup_packet(dev_p);
81eb669b 58 if (cy_as_device_is_usb_async_pending(dev_p, 0))
0769c38d 59 cy_as_usb_cancel_async((cy_as_device_handle)dev_p, 0);
81eb669b 60
0769c38d 61 dev_p->usb_pending_buffer = 0;
81eb669b
DC
62}
63
64/*
65* External function to map logical endpoints to physical endpoints
66*/
67static cy_as_return_status_t
68is_usb_active(cy_as_device *dev_p)
69{
70 if (!cy_as_device_is_configured(dev_p))
0769c38d 71 return CY_AS_ERROR_NOT_CONFIGURED;
81eb669b
DC
72
73 if (!cy_as_device_is_firmware_loaded(dev_p))
0769c38d 74 return CY_AS_ERROR_NO_FIRMWARE;
81eb669b
DC
75
76 if (dev_p->usb_count == 0)
0769c38d 77 return CY_AS_ERROR_NOT_RUNNING;
81eb669b
DC
78
79 if (cy_as_device_is_in_suspend_mode(dev_p))
0769c38d 80 return CY_AS_ERROR_IN_SUSPEND;
81eb669b 81
0769c38d 82 return CY_AS_ERROR_SUCCESS;
81eb669b
DC
83}
84
85static void
86usb_ack_callback(cy_as_device_handle h,
87 cy_as_return_status_t status,
88 uint32_t client,
89 cy_as_funct_c_b_type type,
90 void *data)
91{
0769c38d 92 cy_as_device *dev_p = (cy_as_device *)h;
81eb669b 93
0769c38d
DC
94 (void)client;
95 (void)status;
96 (void)data;
81eb669b 97
0769c38d 98 cy_as_hal_assert(type == CY_FUNCT_CB_NODATA);
81eb669b
DC
99
100 if (dev_p->usb_pending_buffer) {
0769c38d 101 cy_as_usb_io_callback cb;
81eb669b 102
0769c38d
DC
103 cb = dev_p->usb_cb[0];
104 dev_p->usb_cb[0] = 0;
105 cy_as_device_clear_usb_async_pending(dev_p, 0);
81eb669b
DC
106 if (cb)
107 cb(h, 0, dev_p->usb_pending_size,
0769c38d 108 dev_p->usb_pending_buffer, dev_p->usb_error);
81eb669b 109
0769c38d 110 dev_p->usb_pending_buffer = 0;
81eb669b
DC
111 }
112
0769c38d 113 cy_as_device_clear_setup_packet(dev_p);
81eb669b
DC
114}
115
116static void
117my_usb_request_callback_usb_event(cy_as_device *dev_p,
118 cy_as_ll_request_response *req_p)
119{
0769c38d
DC
120 uint16_t ev;
121 uint16_t val;
122 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b 123
0769c38d 124 ev = cy_as_ll_request_response__get_word(req_p, 0);
81eb669b
DC
125 switch (ev) {
126 case 0: /* Reserved */
127 cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
0769c38d
DC
128 CY_AS_ERROR_INVALID_REQUEST, 0);
129 break;
81eb669b
DC
130
131 case 1: /* Reserved */
132 cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
0769c38d
DC
133 CY_AS_ERROR_INVALID_REQUEST, 0);
134 break;
81eb669b
DC
135
136 case 2: /* USB Suspend */
0769c38d 137 dev_p->usb_last_event = cy_as_event_usb_suspend;
81eb669b 138 if (dev_p->usb_event_cb_ms)
0769c38d 139 dev_p->usb_event_cb_ms(h, cy_as_event_usb_suspend, 0);
81eb669b 140 else if (dev_p->usb_event_cb)
0769c38d 141 dev_p->usb_event_cb(h, cy_as_event_usb_suspend, 0);
81eb669b 142 cy_as_ll_send_status_response(dev_p,
0769c38d 143 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
81eb669b
DC
144 break;
145
146 case 3: /* USB Resume */
0769c38d 147 dev_p->usb_last_event = cy_as_event_usb_resume;
81eb669b 148 if (dev_p->usb_event_cb_ms)
0769c38d 149 dev_p->usb_event_cb_ms(h, cy_as_event_usb_resume, 0);
81eb669b 150 else if (dev_p->usb_event_cb)
0769c38d 151 dev_p->usb_event_cb(h, cy_as_event_usb_resume, 0);
81eb669b 152 cy_as_ll_send_status_response(dev_p,
0769c38d
DC
153 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
154 break;
81eb669b
DC
155
156 case 4: /* USB Reset */
157 /*
158 * if we get a USB reset, the USB host did not understand
159 * our response or we timed out for some reason. reset
160 * our internal state to be ready for another set of
161 * enumeration based requests.
162 */
163 if (cy_as_device_is_ack_delayed(dev_p))
0769c38d 164 cy_as_usb_reset_e_p0_state(dev_p);
81eb669b 165
0769c38d 166 dev_p->usb_last_event = cy_as_event_usb_reset;
81eb669b 167 if (dev_p->usb_event_cb_ms)
0769c38d 168 dev_p->usb_event_cb_ms(h, cy_as_event_usb_reset, 0);
81eb669b 169 else if (dev_p->usb_event_cb)
0769c38d 170 dev_p->usb_event_cb(h, cy_as_event_usb_reset, 0);
81eb669b
DC
171
172 cy_as_ll_send_status_response(dev_p,
0769c38d
DC
173 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
174 cy_as_device_clear_usb_high_speed(dev_p);
175 cy_as_usb_set_dma_sizes(dev_p);
176 dev_p->usb_max_tx_size = 0x40;
177 cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40);
178 break;
81eb669b
DC
179
180 case 5: /* USB Set Configuration */
181 /* The configuration to set */
0769c38d
DC
182 val = cy_as_ll_request_response__get_word(req_p, 1);
183 dev_p->usb_last_event = cy_as_event_usb_set_config;
81eb669b
DC
184 if (dev_p->usb_event_cb_ms)
185 dev_p->usb_event_cb_ms(h,
0769c38d 186 cy_as_event_usb_set_config, &val);
81eb669b
DC
187 else if (dev_p->usb_event_cb)
188 dev_p->usb_event_cb(h,
0769c38d 189 cy_as_event_usb_set_config, &val);
81eb669b
DC
190
191 cy_as_ll_send_status_response(dev_p,
0769c38d
DC
192 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
193 break;
81eb669b
DC
194
195 case 6: /* USB Speed change */
196 /* Connect speed */
0769c38d
DC
197 val = cy_as_ll_request_response__get_word(req_p, 1);
198 dev_p->usb_last_event = cy_as_event_usb_speed_change;
81eb669b
DC
199 if (dev_p->usb_event_cb_ms)
200 dev_p->usb_event_cb_ms(h,
0769c38d 201 cy_as_event_usb_speed_change, &val);
81eb669b
DC
202 else if (dev_p->usb_event_cb)
203 dev_p->usb_event_cb(h,
0769c38d 204 cy_as_event_usb_speed_change, &val);
81eb669b
DC
205
206 cy_as_ll_send_status_response(dev_p,
0769c38d
DC
207 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
208 cy_as_device_set_usb_high_speed(dev_p);
209 cy_as_usb_set_dma_sizes(dev_p);
210 dev_p->usb_max_tx_size = 0x200;
211 cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x200);
212 break;
81eb669b
DC
213
214 case 7: /* USB Clear Feature */
215 /* EP Number */
0769c38d 216 val = cy_as_ll_request_response__get_word(req_p, 1);
81eb669b
DC
217 if (dev_p->usb_event_cb_ms)
218 dev_p->usb_event_cb_ms(h,
0769c38d 219 cy_as_event_usb_clear_feature, &val);
81eb669b
DC
220 if (dev_p->usb_event_cb)
221 dev_p->usb_event_cb(h,
0769c38d 222 cy_as_event_usb_clear_feature, &val);
81eb669b
DC
223
224 cy_as_ll_send_status_response(dev_p,
0769c38d
DC
225 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
226 break;
81eb669b
DC
227
228 default:
0769c38d 229 cy_as_hal_print_message("invalid event type\n");
81eb669b 230 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
0769c38d
DC
231 CY_RESP_USB_INVALID_EVENT, sizeof(ev), &ev);
232 break;
81eb669b
DC
233 }
234}
235
236static void
237my_usb_request_callback_usb_data(cy_as_device *dev_p,
238 cy_as_ll_request_response *req_p)
239{
0769c38d
DC
240 cy_as_end_point_number_t ep;
241 uint8_t type;
242 uint16_t len;
243 uint16_t val;
244 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b 245
0769c38d
DC
246 val = cy_as_ll_request_response__get_word(req_p, 0);
247 ep = (cy_as_end_point_number_t)((val >> 13) & 0x01);
248 len = (val & 0x1ff);
81eb669b 249
0769c38d 250 cy_as_hal_assert(len <= 64);
81eb669b 251 cy_as_ll_request_response__unpack(req_p,
0769c38d 252 1, len, dev_p->usb_ep_data);
81eb669b 253
0769c38d 254 type = (uint8_t)((val >> 14) & 0x03);
81eb669b
DC
255 if (type == 0) {
256 if (cy_as_device_is_ack_delayed(dev_p)) {
257 /*
258 * A setup packet has arrived while we are
259 * processing a previous setup packet. reset
260 * our state with respect to EP0 to be ready
261 * to process the new packet.
262 */
0769c38d 263 cy_as_usb_reset_e_p0_state(dev_p);
81eb669b
DC
264 }
265
266 if (len != 8)
267 cy_as_ll_send_status_response(dev_p,
268 CY_RQT_USB_RQT_CONTEXT,
0769c38d 269 CY_AS_ERROR_INVALID_REQUEST, 0);
81eb669b 270 else {
0769c38d
DC
271 cy_as_device_clear_ep0_stalled(dev_p);
272 cy_as_device_set_setup_packet(dev_p);
81eb669b
DC
273 cy_as_ll_send_status_response(dev_p,
274 CY_RQT_USB_RQT_CONTEXT,
0769c38d 275 CY_AS_ERROR_SUCCESS, 0);
81eb669b
DC
276
277 if (dev_p->usb_event_cb_ms)
278 dev_p->usb_event_cb_ms(h,
279 cy_as_event_usb_setup_packet,
0769c38d 280 dev_p->usb_ep_data);
81eb669b
DC
281 else
282 dev_p->usb_event_cb(h,
283 cy_as_event_usb_setup_packet,
0769c38d 284 dev_p->usb_ep_data);
81eb669b
DC
285
286 if ((!cy_as_device_is_ack_delayed(dev_p)) &&
287 (!cy_as_device_is_ep0_stalled(dev_p)))
288 cy_as_usb_ack_setup_packet(h,
0769c38d 289 usb_ack_callback, 0);
81eb669b
DC
290 }
291 } else if (type == 2) {
292 if (len != 0)
293 cy_as_ll_send_status_response(dev_p,
294 CY_RQT_USB_RQT_CONTEXT,
0769c38d 295 CY_AS_ERROR_INVALID_REQUEST, 0);
81eb669b
DC
296 else {
297 if (dev_p->usb_event_cb_ms)
298 dev_p->usb_event_cb_ms(h,
0769c38d 299 cy_as_event_usb_status_packet, 0);
81eb669b
DC
300 else
301 dev_p->usb_event_cb(h,
0769c38d 302 cy_as_event_usb_status_packet, 0);
81eb669b
DC
303
304 cy_as_ll_send_status_response(dev_p,
305 CY_RQT_USB_RQT_CONTEXT,
0769c38d 306 CY_AS_ERROR_SUCCESS, 0);
81eb669b
DC
307 }
308 } else if (type == 1) {
309 /*
310 * we need to hand the data associated with these
311 * endpoints to the DMA module.
312 */
0769c38d 313 cy_as_dma_received_data(dev_p, ep, len, dev_p->usb_ep_data);
81eb669b 314 cy_as_ll_send_status_response(dev_p,
0769c38d 315 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
81eb669b
DC
316 }
317}
318
319static void
320my_usb_request_callback_inquiry(cy_as_device *dev_p,
321 cy_as_ll_request_response *req_p)
322{
0769c38d
DC
323 cy_as_usb_inquiry_data_dep cbdata;
324 cy_as_usb_inquiry_data cbdata_ms;
325 void *data;
326 uint16_t val;
327 cy_as_device_handle h = (cy_as_device_handle)dev_p;
328 uint8_t def_inq_data[64];
329 uint8_t evpd;
330 uint8_t codepage;
331 cy_bool updated;
332 uint16_t length;
81eb669b 333
0769c38d
DC
334 cy_as_bus_number_t bus;
335 uint32_t device;
336 cy_as_media_type media;
81eb669b 337
0769c38d
DC
338 val = cy_as_ll_request_response__get_word(req_p, 0);
339 bus = cy_as_storage_get_bus_from_address(val);
340 device = cy_as_storage_get_device_from_address(val);
341 media = cy_as_storage_get_media_from_address(val);
81eb669b 342
0769c38d
DC
343 val = cy_as_ll_request_response__get_word(req_p, 1);
344 evpd = (uint8_t)((val >> 8) & 0x01);
345 codepage = (uint8_t)(val & 0xff);
81eb669b 346
0769c38d
DC
347 length = cy_as_ll_request_response__get_word(req_p, 2);
348 data = (void *)def_inq_data;
81eb669b 349
0769c38d 350 updated = cy_false;
81eb669b
DC
351
352 if (dev_p->usb_event_cb_ms) {
0769c38d
DC
353 cbdata_ms.bus = bus;
354 cbdata_ms.device = device;
355 cbdata_ms.updated = updated;
356 cbdata_ms.evpd = evpd;
357 cbdata_ms.codepage = codepage;
358 cbdata_ms.length = length;
359 cbdata_ms.data = data;
360
361 cy_as_hal_assert(cbdata_ms.length <= sizeof(def_inq_data));
81eb669b 362 cy_as_ll_request_response__unpack(req_p,
0769c38d 363 3, cbdata_ms.length, cbdata_ms.data);
81eb669b
DC
364
365 dev_p->usb_event_cb_ms(h,
0769c38d 366 cy_as_event_usb_inquiry_before, &cbdata_ms);
81eb669b
DC
367
368 updated = cbdata_ms.updated;
0769c38d
DC
369 data = cbdata_ms.data;
370 length = cbdata_ms.length;
81eb669b 371 } else if (dev_p->usb_event_cb) {
0769c38d
DC
372 cbdata.media = media;
373 cbdata.updated = updated;
374 cbdata.evpd = evpd;
375 cbdata.codepage = codepage;
376 cbdata.length = length;
377 cbdata.data = data;
81eb669b
DC
378
379 cy_as_hal_assert(cbdata.length <=
0769c38d 380 sizeof(def_inq_data));
81eb669b 381 cy_as_ll_request_response__unpack(req_p, 3,
0769c38d 382 cbdata.length, cbdata.data);
81eb669b
DC
383
384 dev_p->usb_event_cb(h,
0769c38d 385 cy_as_event_usb_inquiry_before, &cbdata);
81eb669b 386
0769c38d
DC
387 updated = cbdata.updated;
388 data = cbdata.data;
389 length = cbdata.length;
81eb669b
DC
390 }
391
392 if (updated && length > 192)
393 cy_as_hal_print_message("an inquiry result from a "
394 "cy_as_event_usb_inquiry_before event "
0769c38d 395 "was greater than 192 bytes.");
81eb669b
DC
396
397 /* Now send the reply with the data back
398 * to the West Bridge device */
399 if (updated && length <= 192) {
400 /*
401 * the callback function modified the inquiry
402 * data, ship the data back to the west bridge firmware.
403 */
404 cy_as_ll_send_data_response(dev_p,
405 CY_RQT_USB_RQT_CONTEXT,
0769c38d 406 CY_RESP_INQUIRY_DATA, length, data);
81eb669b
DC
407 } else {
408 /*
409 * the callback did not modify the data, just acknowledge
410 * that we processed the request
411 */
412 cy_as_ll_send_status_response(dev_p,
0769c38d 413 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
81eb669b
DC
414 }
415
416 if (dev_p->usb_event_cb_ms)
417 dev_p->usb_event_cb_ms(h,
0769c38d 418 cy_as_event_usb_inquiry_after, &cbdata_ms);
81eb669b
DC
419 else if (dev_p->usb_event_cb)
420 dev_p->usb_event_cb(h,
0769c38d 421 cy_as_event_usb_inquiry_after, &cbdata);
81eb669b
DC
422}
423
424static void
425my_usb_request_callback_start_stop(cy_as_device *dev_p,
426 cy_as_ll_request_response *req_p)
427{
0769c38d
DC
428 cy_as_bus_number_t bus;
429 cy_as_media_type media;
430 uint32_t device;
431 uint16_t val;
81eb669b
DC
432
433 if (dev_p->usb_event_cb_ms || dev_p->usb_event_cb) {
0769c38d
DC
434 cy_bool loej;
435 cy_bool start;
436 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b 437
0769c38d
DC
438 val = cy_as_ll_request_response__get_word(req_p, 0);
439 bus = cy_as_storage_get_bus_from_address(val);
440 device = cy_as_storage_get_device_from_address(val);
441 media = cy_as_storage_get_media_from_address(val);
81eb669b 442
0769c38d
DC
443 val = cy_as_ll_request_response__get_word(req_p, 1);
444 loej = (val & 0x02) ? cy_true : cy_false;
445 start = (val & 0x01) ? cy_true : cy_false;
81eb669b
DC
446
447 if (dev_p->usb_event_cb_ms) {
0769c38d 448 cy_as_usb_start_stop_data cbdata_ms;
81eb669b 449
0769c38d
DC
450 cbdata_ms.bus = bus;
451 cbdata_ms.device = device;
452 cbdata_ms.loej = loej;
453 cbdata_ms.start = start;
81eb669b 454 dev_p->usb_event_cb_ms(h,
0769c38d 455 cy_as_event_usb_start_stop, &cbdata_ms);
81eb669b
DC
456
457 } else if (dev_p->usb_event_cb) {
0769c38d 458 cy_as_usb_start_stop_data_dep cbdata;
81eb669b 459
0769c38d
DC
460 cbdata.media = media;
461 cbdata.loej = loej;
462 cbdata.start = start;
81eb669b 463 dev_p->usb_event_cb(h,
0769c38d 464 cy_as_event_usb_start_stop, &cbdata);
81eb669b
DC
465 }
466 }
467 cy_as_ll_send_status_response(dev_p,
0769c38d 468 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
81eb669b
DC
469}
470
471static void
472my_usb_request_callback_uknown_c_b_w(cy_as_device *dev_p,
473 cy_as_ll_request_response *req_p)
474{
0769c38d
DC
475 uint16_t val;
476 cy_as_device_handle h = (cy_as_device_handle)dev_p;
477 uint8_t buf[16];
81eb669b 478
0769c38d
DC
479 uint8_t response[4];
480 uint16_t reqlen;
481 void *request;
482 uint8_t status;
483 uint8_t key;
484 uint8_t asc;
485 uint8_t ascq;
81eb669b 486
0769c38d 487 val = cy_as_ll_request_response__get_word(req_p, 0);
81eb669b 488 /* Failed by default */
0769c38d 489 status = 1;
81eb669b 490 /* Invalid command */
0769c38d 491 key = 0x05;
81eb669b 492 /* Invalid command */
0769c38d 493 asc = 0x20;
81eb669b 494 /* Invalid command */
0769c38d
DC
495 ascq = 0x00;
496 reqlen = cy_as_ll_request_response__get_word(req_p, 1);
497 request = buf;
81eb669b 498
0769c38d
DC
499 cy_as_hal_assert(reqlen <= sizeof(buf));
500 cy_as_ll_request_response__unpack(req_p, 2, reqlen, request);
81eb669b
DC
501
502 if (dev_p->usb_event_cb_ms) {
0769c38d
DC
503 cy_as_usb_unknown_command_data cbdata_ms;
504 cbdata_ms.bus = cy_as_storage_get_bus_from_address(val);
81eb669b 505 cbdata_ms.device =
0769c38d
DC
506 cy_as_storage_get_device_from_address(val);
507 cbdata_ms.reqlen = reqlen;
508 cbdata_ms.request = request;
509 cbdata_ms.status = status;
510 cbdata_ms.key = key;
511 cbdata_ms.asc = asc;
512 cbdata_ms.ascq = ascq;
81eb669b
DC
513
514 dev_p->usb_event_cb_ms(h,
0769c38d
DC
515 cy_as_event_usb_unknown_storage, &cbdata_ms);
516 status = cbdata_ms.status;
517 key = cbdata_ms.key;
518 asc = cbdata_ms.asc;
519 ascq = cbdata_ms.ascq;
81eb669b 520 } else if (dev_p->usb_event_cb) {
0769c38d 521 cy_as_usb_unknown_command_data_dep cbdata;
81eb669b 522 cbdata.media =
0769c38d
DC
523 cy_as_storage_get_media_from_address(val);
524 cbdata.reqlen = reqlen;
525 cbdata.request = request;
526 cbdata.status = status;
527 cbdata.key = key;
528 cbdata.asc = asc;
529 cbdata.ascq = ascq;
81eb669b
DC
530
531 dev_p->usb_event_cb(h,
0769c38d
DC
532 cy_as_event_usb_unknown_storage, &cbdata);
533 status = cbdata.status;
534 key = cbdata.key;
535 asc = cbdata.asc;
536 ascq = cbdata.ascq;
81eb669b
DC
537 }
538
0769c38d
DC
539 response[0] = status;
540 response[1] = key;
541 response[2] = asc;
542 response[3] = ascq;
81eb669b 543 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
0769c38d 544 CY_RESP_UNKNOWN_SCSI_COMMAND, sizeof(response), response);
81eb669b
DC
545}
546
547static void
548my_usb_request_callback_m_s_c_progress(cy_as_device *dev_p,
549 cy_as_ll_request_response *req_p)
550{
0769c38d
DC
551 uint16_t val1, val2;
552 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b
DC
553
554 if ((dev_p->usb_event_cb) || (dev_p->usb_event_cb_ms)) {
0769c38d 555 cy_as_m_s_c_progress_data cbdata;
81eb669b 556
0769c38d
DC
557 val1 = cy_as_ll_request_response__get_word(req_p, 0);
558 val2 = cy_as_ll_request_response__get_word(req_p, 1);
559 cbdata.wr_count = (uint32_t)((val1 << 16) | val2);
81eb669b 560
0769c38d
DC
561 val1 = cy_as_ll_request_response__get_word(req_p, 2);
562 val2 = cy_as_ll_request_response__get_word(req_p, 3);
563 cbdata.rd_count = (uint32_t)((val1 << 16) | val2);
81eb669b
DC
564
565 if (dev_p->usb_event_cb)
566 dev_p->usb_event_cb(h,
0769c38d 567 cy_as_event_usb_m_s_c_progress, &cbdata);
81eb669b
DC
568 else
569 dev_p->usb_event_cb_ms(h,
0769c38d 570 cy_as_event_usb_m_s_c_progress, &cbdata);
81eb669b
DC
571 }
572
573 cy_as_ll_send_status_response(dev_p,
0769c38d 574 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
81eb669b
DC
575}
576
577/*
578* This function processes the requests delivered from the
579* firmware within the West Bridge device that are delivered
580* in the USB context. These requests generally are EP0 and
581* EP1 related requests or USB events.
582*/
583static void
584my_usb_request_callback(cy_as_device *dev_p, uint8_t context,
585 cy_as_ll_request_response *req_p,
586 cy_as_ll_request_response *resp_p,
587 cy_as_return_status_t ret)
588{
0769c38d
DC
589 uint16_t val;
590 uint8_t code = cy_as_ll_request_response__get_code(req_p);
81eb669b 591
0769c38d
DC
592 (void)resp_p;
593 (void)context;
594 (void)ret;
81eb669b
DC
595
596 switch (code) {
597 case CY_RQT_USB_EVENT:
0769c38d
DC
598 my_usb_request_callback_usb_event(dev_p, req_p);
599 break;
81eb669b
DC
600
601 case CY_RQT_USB_EP_DATA:
0769c38d
DC
602 dev_p->usb_last_event = cy_as_event_usb_setup_packet;
603 my_usb_request_callback_usb_data(dev_p, req_p);
604 break;
81eb669b
DC
605
606 case CY_RQT_SCSI_INQUIRY_COMMAND:
0769c38d
DC
607 dev_p->usb_last_event = cy_as_event_usb_inquiry_after;
608 my_usb_request_callback_inquiry(dev_p, req_p);
609 break;
81eb669b
DC
610
611 case CY_RQT_SCSI_START_STOP_COMMAND:
0769c38d
DC
612 dev_p->usb_last_event = cy_as_event_usb_start_stop;
613 my_usb_request_callback_start_stop(dev_p, req_p);
614 break;
81eb669b
DC
615
616 case CY_RQT_SCSI_UNKNOWN_COMMAND:
0769c38d
DC
617 dev_p->usb_last_event = cy_as_event_usb_unknown_storage;
618 my_usb_request_callback_uknown_c_b_w(dev_p, req_p);
619 break;
81eb669b
DC
620
621 case CY_RQT_USB_ACTIVITY_UPDATE:
0769c38d
DC
622 dev_p->usb_last_event = cy_as_event_usb_m_s_c_progress;
623 my_usb_request_callback_m_s_c_progress(dev_p, req_p);
624 break;
81eb669b
DC
625
626 default:
627 cy_as_hal_print_message("invalid request "
0769c38d
DC
628 "received on USB context\n");
629 val = req_p->box0;
81eb669b 630 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
0769c38d
DC
631 CY_RESP_INVALID_REQUEST, sizeof(val), &val);
632 break;
81eb669b
DC
633 }
634}
635
636static cy_as_return_status_t
637my_handle_response_usb_start(cy_as_device *dev_p,
638 cy_as_ll_request_response *req_p,
639 cy_as_ll_request_response *reply_p,
640 cy_as_return_status_t ret)
641{
642 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 643 goto destroy;
81eb669b
DC
644
645 if (cy_as_ll_request_response__get_code(reply_p) !=
646 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
647 ret = CY_AS_ERROR_INVALID_RESPONSE;
648 goto destroy;
81eb669b
DC
649 }
650
0769c38d 651 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 652 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 653 goto destroy;
81eb669b
DC
654
655 /*
656 * mark EP 0 and EP1 as 64 byte endpoints
657 */
0769c38d
DC
658 cy_as_dma_set_max_dma_size(dev_p, 0, 64);
659 cy_as_dma_set_max_dma_size(dev_p, 1, 64);
81eb669b 660
0769c38d 661 dev_p->usb_count++;
81eb669b
DC
662
663destroy:
0769c38d
DC
664 cy_as_ll_destroy_request(dev_p, req_p);
665 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b
DC
666
667 if (ret != CY_AS_ERROR_SUCCESS) {
0769c38d 668 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
81eb669b 669 cy_as_ll_register_request_callback(dev_p,
0769c38d 670 CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b
DC
671 }
672
0769c38d 673 cy_as_device_clear_u_s_s_pending(dev_p);
81eb669b 674
0769c38d 675 return ret;
81eb669b
DC
676
677}
678
679/*
680* This function starts the USB stack. The stack is reference
681* counted so if the stack is already started, this function
682* just increments the count. If the stack has not been started,
683* a start request is sent to the West Bridge device.
684*
685* Note: Starting the USB stack does not cause the USB signals
686* to be connected to the USB pins. To do this and therefore
687* initiate enumeration, CyAsUsbConnect() must be called.
688*/
689cy_as_return_status_t
690cy_as_usb_start(cy_as_device_handle handle,
691 cy_as_function_callback cb,
692 uint32_t client)
693{
0769c38d
DC
694 cy_as_ll_request_response *req_p, *reply_p;
695 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 696
0769c38d 697 cy_as_device *dev_p;
81eb669b 698
0769c38d 699 cy_as_log_debug_message(6, "cy_as_usb_start called");
81eb669b 700
0769c38d 701 dev_p = (cy_as_device *)handle;
81eb669b 702 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 703 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
704
705 if (!cy_as_device_is_configured(dev_p))
0769c38d 706 return CY_AS_ERROR_NOT_CONFIGURED;
81eb669b
DC
707
708 if (!cy_as_device_is_firmware_loaded(dev_p))
0769c38d 709 return CY_AS_ERROR_NO_FIRMWARE;
81eb669b
DC
710
711 if (cy_as_device_is_in_suspend_mode(dev_p))
0769c38d 712 return CY_AS_ERROR_IN_SUSPEND;
81eb669b
DC
713
714 if (cy_as_device_is_in_callback(dev_p))
0769c38d 715 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
716
717 if (cy_as_device_is_u_s_s_pending(dev_p))
0769c38d 718 return CY_AS_ERROR_STARTSTOP_PENDING;
81eb669b 719
0769c38d 720 cy_as_device_set_u_s_s_pending(dev_p);
81eb669b
DC
721
722 if (dev_p->usb_count == 0) {
723 /*
724 * since we are just starting the stack,
725 * mark USB as not connected to the remote host
726 */
0769c38d
DC
727 cy_as_device_clear_usb_connected(dev_p);
728 dev_p->usb_phy_config = 0;
81eb669b
DC
729
730 /* Queue for 1.0 Async Requests, kept for
731 * backwards compatibility */
0769c38d 732 dev_p->usb_func_cbs = cy_as_create_c_b_queue(CYAS_USB_FUNC_CB);
81eb669b 733 if (dev_p->usb_func_cbs == 0) {
0769c38d
DC
734 cy_as_device_clear_u_s_s_pending(dev_p);
735 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
736 }
737
738 /* Reset the EP0 state */
0769c38d 739 cy_as_usb_reset_e_p0_state(dev_p);
81eb669b
DC
740
741 /*
25985edc 742 * we register here because the start request may cause
81eb669b
DC
743 * events to occur before the response to the start request.
744 */
745 cy_as_ll_register_request_callback(dev_p,
0769c38d 746 CY_RQT_USB_RQT_CONTEXT, my_usb_request_callback);
81eb669b
DC
747
748 /* Create the request to send to the West Bridge device */
749 req_p = cy_as_ll_create_request(dev_p,
0769c38d 750 CY_RQT_START_USB, CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b 751 if (req_p == 0) {
0769c38d
DC
752 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
753 dev_p->usb_func_cbs = 0;
754 cy_as_device_clear_u_s_s_pending(dev_p);
755 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
756 }
757
758 /* Reserve space for the reply, the reply data
759 * will not exceed one word */
0769c38d 760 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 761 if (reply_p == 0) {
0769c38d
DC
762 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
763 dev_p->usb_func_cbs = 0;
764 cy_as_ll_destroy_request(dev_p, req_p);
765 cy_as_device_clear_u_s_s_pending(dev_p);
766 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
767 }
768
769 if (cb == 0) {
770 ret = cy_as_ll_send_request_wait_reply(dev_p,
0769c38d 771 req_p, reply_p);
81eb669b 772 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 773 goto destroy;
81eb669b
DC
774
775 return my_handle_response_usb_start(dev_p,
0769c38d 776 req_p, reply_p, ret);
81eb669b
DC
777 } else {
778 ret = cy_as_misc_send_request(dev_p, cb,
779 client, CY_FUNCT_CB_USB_START, 0,
780 dev_p->func_cbs_usb,
781 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 782 cy_as_usb_func_callback);
81eb669b
DC
783
784 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 785 goto destroy;
81eb669b 786
0769c38d 787 return ret;
81eb669b
DC
788 }
789
790destroy:
0769c38d
DC
791 cy_as_ll_destroy_request(dev_p, req_p);
792 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 793 } else {
0769c38d 794 dev_p->usb_count++;
81eb669b 795 if (cb)
0769c38d 796 cb(handle, ret, client, CY_FUNCT_CB_USB_START, 0);
81eb669b
DC
797 }
798
0769c38d 799 cy_as_device_clear_u_s_s_pending(dev_p);
81eb669b 800
0769c38d 801 return ret;
81eb669b 802}
af109f2e 803EXPORT_SYMBOL(cy_as_usb_start);
81eb669b
DC
804
805void
806cy_as_usb_reset(cy_as_device *dev_p)
807{
0769c38d 808 int i;
81eb669b 809
0769c38d 810 cy_as_device_clear_usb_connected(dev_p);
81eb669b 811
0769c38d
DC
812 for (i = 0; i < sizeof(dev_p->usb_config) /
813 sizeof(dev_p->usb_config[0]); i++) {
81eb669b
DC
814 /*
815 * cancel all pending USB read/write operations, as it is
816 * possible that the USB stack comes up in a different
817 * configuration with a different set of endpoints.
818 */
819 if (cy_as_device_is_usb_async_pending(dev_p, i))
820 cy_as_usb_cancel_async(dev_p,
0769c38d 821 (cy_as_end_point_number_t)i);
81eb669b 822
0769c38d
DC
823 dev_p->usb_cb[i] = 0;
824 dev_p->usb_config[i].enabled = cy_false;
81eb669b
DC
825 }
826
0769c38d 827 dev_p->usb_phy_config = 0;
81eb669b
DC
828}
829
830/*
831 * This function does all the API side clean-up associated
832 * with CyAsUsbStop, without any communication with firmware.
833 * This needs to be done when the device is being reset while
834 * the USB stack is active.
835 */
836void
837cy_as_usb_cleanup(cy_as_device *dev_p)
838{
839 if (dev_p->usb_count) {
0769c38d
DC
840 cy_as_usb_reset_e_p0_state(dev_p);
841 cy_as_usb_reset(dev_p);
81eb669b 842 cy_as_hal_mem_set(dev_p->usb_config, 0,
0769c38d
DC
843 sizeof(dev_p->usb_config));
844 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
81eb669b 845
0769c38d 846 dev_p->usb_count = 0;
81eb669b
DC
847 }
848}
849
850static cy_as_return_status_t
851my_handle_response_usb_stop(cy_as_device *dev_p,
852 cy_as_ll_request_response *req_p,
853 cy_as_ll_request_response *reply_p,
854 cy_as_return_status_t ret)
855{
856 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 857 goto destroy;
81eb669b
DC
858
859 if (cy_as_ll_request_response__get_code(reply_p) !=
860 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
861 ret = CY_AS_ERROR_INVALID_RESPONSE;
862 goto destroy;
81eb669b
DC
863 }
864
0769c38d 865 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 866 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 867 goto destroy;
81eb669b
DC
868
869 /*
25985edc 870 * we successfully shutdown the stack, so
81eb669b
DC
871 * decrement to make the count zero.
872 */
0769c38d 873 cy_as_usb_cleanup(dev_p);
81eb669b
DC
874
875destroy:
0769c38d
DC
876 cy_as_ll_destroy_request(dev_p, req_p);
877 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b
DC
878
879 if (ret != CY_AS_ERROR_SUCCESS)
880 cy_as_ll_register_request_callback(dev_p,
0769c38d 881 CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b 882
0769c38d 883 cy_as_device_clear_u_s_s_pending(dev_p);
81eb669b 884
0769c38d 885 return ret;
81eb669b
DC
886}
887
888/*
889* This function stops the USB stack. The USB stack is reference
890* counted so first is reference count is decremented. If the
891* reference count is then zero, a request is sent to the West
892* Bridge device to stop the USB stack on the West Bridge device.
893*/
894cy_as_return_status_t
895cy_as_usb_stop(cy_as_device_handle handle,
896 cy_as_function_callback cb,
897 uint32_t client)
898{
0769c38d
DC
899 cy_as_ll_request_response *req_p = 0, *reply_p = 0;
900 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 901
0769c38d 902 cy_as_device *dev_p;
81eb669b 903
0769c38d 904 cy_as_log_debug_message(6, "cy_as_usb_stop called");
81eb669b 905
0769c38d 906 dev_p = (cy_as_device *)handle;
81eb669b 907 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 908 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 909
0769c38d 910 ret = is_usb_active(dev_p);
81eb669b 911 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 912 return ret;
81eb669b
DC
913
914 if (cy_as_device_is_usb_connected(dev_p))
0769c38d 915 return CY_AS_ERROR_USB_CONNECTED;
81eb669b
DC
916
917 if (cy_as_device_is_in_callback(dev_p))
0769c38d 918 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
919
920 if (cy_as_device_is_u_s_s_pending(dev_p))
0769c38d 921 return CY_AS_ERROR_STARTSTOP_PENDING;
81eb669b 922
0769c38d 923 cy_as_device_set_u_s_s_pending(dev_p);
81eb669b
DC
924
925 if (dev_p->usb_count == 1) {
926 /* Create the request to send to the West Bridge device */
927 req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_USB,
0769c38d 928 CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b 929 if (req_p == 0) {
0769c38d
DC
930 ret = CY_AS_ERROR_OUT_OF_MEMORY;
931 goto destroy;
81eb669b
DC
932 }
933
934 /* Reserve space for the reply, the reply data will not
935 * exceed one word */
0769c38d 936 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 937 if (reply_p == 0) {
0769c38d
DC
938 ret = CY_AS_ERROR_OUT_OF_MEMORY;
939 goto destroy;
81eb669b
DC
940 }
941
942 if (cb == 0) {
943 ret = cy_as_ll_send_request_wait_reply(dev_p,
0769c38d 944 req_p, reply_p);
81eb669b 945 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 946 goto destroy;
81eb669b
DC
947
948 return my_handle_response_usb_stop(dev_p,
0769c38d 949 req_p, reply_p, ret);
81eb669b
DC
950 } else {
951 ret = cy_as_misc_send_request(dev_p, cb, client,
952 CY_FUNCT_CB_USB_STOP, 0, dev_p->func_cbs_usb,
953 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 954 cy_as_usb_func_callback);
81eb669b
DC
955
956 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 957 goto destroy;
81eb669b 958
0769c38d 959 return ret;
81eb669b
DC
960 }
961
962destroy:
0769c38d
DC
963 cy_as_ll_destroy_request(dev_p, req_p);
964 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b
DC
965 } else if (dev_p->usb_count > 1) {
966 /*
967 * reset all LE_ps to inactive state, after cleaning
968 * up any pending async read/write calls.
969 */
0769c38d
DC
970 cy_as_usb_reset(dev_p);
971 dev_p->usb_count--;
81eb669b
DC
972
973 if (cb)
0769c38d 974 cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0);
81eb669b
DC
975 }
976
0769c38d 977 cy_as_device_clear_u_s_s_pending(dev_p);
81eb669b 978
0769c38d 979 return ret;
81eb669b 980}
af109f2e 981EXPORT_SYMBOL(cy_as_usb_stop);
81eb669b
DC
982
983/*
984* This function registers a callback to be called when
985* USB events are processed
986*/
987cy_as_return_status_t
988cy_as_usb_register_callback(cy_as_device_handle handle,
989 cy_as_usb_event_callback callback)
990{
0769c38d 991 cy_as_device *dev_p;
81eb669b 992
0769c38d 993 cy_as_log_debug_message(6, "cy_as_usb_register_callback called");
81eb669b 994
0769c38d 995 dev_p = (cy_as_device *)handle;
81eb669b 996 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 997 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
998
999 if (!cy_as_device_is_configured(dev_p))
0769c38d 1000 return CY_AS_ERROR_NOT_CONFIGURED;
81eb669b
DC
1001
1002 if (!cy_as_device_is_firmware_loaded(dev_p))
0769c38d 1003 return CY_AS_ERROR_NO_FIRMWARE;
81eb669b 1004
0769c38d
DC
1005 dev_p->usb_event_cb = NULL;
1006 dev_p->usb_event_cb_ms = callback;
1007 return CY_AS_ERROR_SUCCESS;
81eb669b 1008}
af109f2e 1009EXPORT_SYMBOL(cy_as_usb_register_callback);
81eb669b
DC
1010
1011static cy_as_return_status_t
1012my_handle_response_no_data(cy_as_device *dev_p,
1013 cy_as_ll_request_response *req_p,
1014 cy_as_ll_request_response *reply_p)
1015{
0769c38d 1016 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b
DC
1017
1018 if (cy_as_ll_request_response__get_code(reply_p) !=
1019 CY_RESP_SUCCESS_FAILURE)
0769c38d 1020 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b 1021 else
0769c38d 1022 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 1023
0769c38d
DC
1024 cy_as_ll_destroy_request(dev_p, req_p);
1025 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1026
0769c38d 1027 return ret;
81eb669b
DC
1028}
1029
1030static cy_as_return_status_t
1031my_handle_response_connect(cy_as_device *dev_p,
1032 cy_as_ll_request_response *req_p,
1033 cy_as_ll_request_response *reply_p,
1034 cy_as_return_status_t ret)
1035{
1036 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1037 goto destroy;
81eb669b
DC
1038
1039 if (cy_as_ll_request_response__get_code(reply_p) !=
1040 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
1041 ret = CY_AS_ERROR_INVALID_RESPONSE;
1042 goto destroy;
81eb669b
DC
1043 }
1044
0769c38d 1045 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 1046 if (ret == CY_AS_ERROR_SUCCESS)
0769c38d 1047 cy_as_device_set_usb_connected(dev_p);
81eb669b
DC
1048
1049destroy:
0769c38d
DC
1050 cy_as_ll_destroy_request(dev_p, req_p);
1051 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1052
0769c38d 1053 return ret;
81eb669b
DC
1054}
1055
1056
1057/*
1058* This method asks the West Bridge device to connect the
1059* internal USB D+ and D- signals to the USB pins, thus
1060* starting the enumeration processes if the external pins
979cdcc9
JM
1061* are connected to a USB host. If the external pins are
1062* not connected to a USB host, enumeration will begin as soon
81eb669b
DC
1063* as the USB pins are connected to a host.
1064*/
1065cy_as_return_status_t
1066cy_as_usb_connect(cy_as_device_handle handle,
1067 cy_as_function_callback cb,
1068 uint32_t client)
1069{
0769c38d
DC
1070 cy_as_ll_request_response *req_p , *reply_p;
1071 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 1072
0769c38d 1073 cy_as_device *dev_p;
81eb669b 1074
0769c38d 1075 cy_as_log_debug_message(6, "cy_as_usb_connect called");
81eb669b 1076
0769c38d 1077 dev_p = (cy_as_device *)handle;
81eb669b 1078 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1079 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1080
0769c38d 1081 ret = is_usb_active(dev_p);
81eb669b 1082 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1083 return ret;
81eb669b
DC
1084
1085 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1086 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1087
1088 /* Create the request to send to the West Bridge device */
1089 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1090 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
81eb669b 1091 if (req_p == 0)
0769c38d 1092 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1093
1094 /* 1 = Connect request */
0769c38d 1095 cy_as_ll_request_response__set_word(req_p, 0, 1);
81eb669b
DC
1096
1097 /* Reserve space for the reply, the reply
1098 * data will not exceed one word */
0769c38d 1099 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 1100 if (reply_p == 0) {
0769c38d
DC
1101 cy_as_ll_destroy_request(dev_p, req_p);
1102 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1103 }
1104
1105 if (cb == 0) {
0769c38d 1106 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1107 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1108 goto destroy;
81eb669b 1109
0769c38d 1110 return my_handle_response_connect(dev_p, req_p, reply_p, ret);
81eb669b
DC
1111 } else {
1112 ret = cy_as_misc_send_request(dev_p, cb, client,
1113 CY_FUNCT_CB_USB_CONNECT, 0, dev_p->func_cbs_usb,
1114 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 1115 cy_as_usb_func_callback);
81eb669b
DC
1116
1117 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1118 goto destroy;
81eb669b 1119
0769c38d 1120 return ret;
81eb669b
DC
1121 }
1122
1123destroy:
0769c38d
DC
1124 cy_as_ll_destroy_request(dev_p, req_p);
1125 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1126
0769c38d 1127 return ret;
81eb669b 1128}
af109f2e 1129EXPORT_SYMBOL(cy_as_usb_connect);
81eb669b
DC
1130
1131static cy_as_return_status_t
1132my_handle_response_disconnect(cy_as_device *dev_p,
1133 cy_as_ll_request_response *req_p,
1134 cy_as_ll_request_response *reply_p,
1135 cy_as_return_status_t ret)
1136{
1137 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1138 goto destroy;
81eb669b
DC
1139
1140 if (cy_as_ll_request_response__get_code(reply_p) !=
1141 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
1142 ret = CY_AS_ERROR_INVALID_RESPONSE;
1143 goto destroy;
81eb669b
DC
1144 }
1145
0769c38d 1146 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 1147 if (ret == CY_AS_ERROR_SUCCESS)
0769c38d 1148 cy_as_device_clear_usb_connected(dev_p);
81eb669b
DC
1149
1150destroy:
0769c38d
DC
1151 cy_as_ll_destroy_request(dev_p, req_p);
1152 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1153
0769c38d 1154 return ret;
81eb669b
DC
1155}
1156/*
1157* This method forces a disconnect of the D+ and D- pins
1158* external to the West Bridge device from the D+ and D-
1159* signals internally, effectively disconnecting the West
1160* Bridge device from any connected USB host.
1161*/
1162cy_as_return_status_t
1163cy_as_usb_disconnect(cy_as_device_handle handle,
1164 cy_as_function_callback cb,
1165 uint32_t client)
1166{
0769c38d
DC
1167 cy_as_ll_request_response *req_p , *reply_p;
1168 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 1169
0769c38d 1170 cy_as_device *dev_p;
81eb669b 1171
0769c38d 1172 cy_as_log_debug_message(6, "cy_as_usb_disconnect called");
81eb669b 1173
0769c38d 1174 dev_p = (cy_as_device *)handle;
81eb669b 1175 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1176 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1177
0769c38d 1178 ret = is_usb_active(dev_p);
81eb669b 1179 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1180 return ret;
81eb669b
DC
1181
1182 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1183 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1184
1185 if (!cy_as_device_is_usb_connected(dev_p))
0769c38d 1186 return CY_AS_ERROR_USB_NOT_CONNECTED;
81eb669b
DC
1187
1188 /* Create the request to send to the West Bridge device */
1189 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1190 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
81eb669b 1191 if (req_p == 0)
0769c38d 1192 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b 1193
0769c38d 1194 cy_as_ll_request_response__set_word(req_p, 0, 0);
81eb669b
DC
1195
1196 /* Reserve space for the reply, the reply
1197 * data will not exceed two bytes */
0769c38d 1198 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 1199 if (reply_p == 0) {
0769c38d
DC
1200 cy_as_ll_destroy_request(dev_p, req_p);
1201 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1202 }
1203
1204 if (cb == 0) {
0769c38d 1205 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1206 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1207 goto destroy;
81eb669b
DC
1208
1209 return my_handle_response_disconnect(dev_p,
0769c38d 1210 req_p, reply_p, ret);
81eb669b
DC
1211 } else {
1212 ret = cy_as_misc_send_request(dev_p, cb, client,
1213 CY_FUNCT_CB_USB_DISCONNECT, 0, dev_p->func_cbs_usb,
1214 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 1215 cy_as_usb_func_callback);
81eb669b
DC
1216
1217 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1218 goto destroy;
81eb669b 1219
0769c38d 1220 return ret;
81eb669b
DC
1221 }
1222destroy:
0769c38d
DC
1223 cy_as_ll_destroy_request(dev_p, req_p);
1224 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1225
0769c38d 1226 return ret;
81eb669b 1227}
af109f2e 1228EXPORT_SYMBOL(cy_as_usb_disconnect);
81eb669b
DC
1229
1230static cy_as_return_status_t
1231my_handle_response_set_enum_config(cy_as_device *dev_p,
1232 cy_as_ll_request_response *req_p,
1233 cy_as_ll_request_response *reply_p)
1234{
0769c38d 1235 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b
DC
1236
1237 if (cy_as_ll_request_response__get_code(reply_p) !=
1238 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
1239 ret = CY_AS_ERROR_INVALID_RESPONSE;
1240 goto destroy;
81eb669b
DC
1241 }
1242
0769c38d 1243 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b
DC
1244
1245 if (ret == CY_AS_ERROR_SUCCESS) {
1246 /*
1247 * we configured the west bridge device and
1248 * enumeration is going to happen on the P port
1249 * processor. now we must enable endpoint zero
1250 */
0769c38d 1251 cy_as_usb_end_point_config config;
81eb669b 1252
0769c38d
DC
1253 config.dir = cy_as_usb_in_out;
1254 config.type = cy_as_usb_control;
1255 config.enabled = cy_true;
81eb669b
DC
1256
1257 ret = cy_as_usb_set_end_point_config((cy_as_device_handle *)
0769c38d 1258 dev_p, 0, &config);
81eb669b
DC
1259 }
1260
1261destroy:
0769c38d
DC
1262 cy_as_ll_destroy_request(dev_p, req_p);
1263 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1264
0769c38d 1265 return ret;
81eb669b
DC
1266}
1267
1268/*
1269* This method sets how the USB is enumerated and should
1270* be called before the CyAsUsbConnect() is called.
1271*/
1272static cy_as_return_status_t
1273my_usb_set_enum_config(cy_as_device *dev_p,
1274 uint8_t bus_mask,
1275 uint8_t media_mask,
1276 cy_bool use_antioch_enumeration,
1277 uint8_t mass_storage_interface,
1278 uint8_t mtp_interface,
1279 cy_bool mass_storage_callbacks,
1280 cy_as_function_callback cb,
1281 uint32_t client)
1282{
0769c38d
DC
1283 cy_as_ll_request_response *req_p , *reply_p;
1284 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 1285
0769c38d 1286 cy_as_log_debug_message(6, "cy_as_usb_set_enum_config called");
81eb669b
DC
1287
1288 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1289 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1290
0769c38d 1291 ret = is_usb_active(dev_p);
81eb669b 1292 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1293 return ret;
81eb669b
DC
1294
1295 if (cy_as_device_is_usb_connected(dev_p))
0769c38d 1296 return CY_AS_ERROR_USB_CONNECTED;
81eb669b
DC
1297
1298 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1299 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1300
1301 /* if we are using MTP firmware: */
1302 if (dev_p->is_mtp_firmware == 1) {
1303 /* we cannot enumerate MSC */
1304 if (mass_storage_interface != 0)
0769c38d 1305 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1306
1307 if (bus_mask == 0) {
1308 if (mtp_interface != 0)
0769c38d 1309 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1310 } else if (bus_mask == 2) {
1311 /* enable EP 1 as it will be used */
1312 cy_as_dma_enable_end_point(dev_p, 1, cy_true,
0769c38d
DC
1313 cy_as_direction_in);
1314 dev_p->usb_config[1].enabled = cy_true;
1315 dev_p->usb_config[1].dir = cy_as_usb_in;
1316 dev_p->usb_config[1].type = cy_as_usb_int;
81eb669b 1317 } else {
0769c38d 1318 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1319 }
1320 /* if we are not using MTP firmware, we cannot enumerate MTP */
1321 } else if (mtp_interface != 0)
0769c38d 1322 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1323
1324 /*
1325 * if we are not enumerating mass storage, we should
1326 * not be providing an interface number.
1327 */
1328 if (bus_mask == 0 && mass_storage_interface != 0)
0769c38d 1329 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1330
1331 /*
1332 * if we are going to use mtp_interface, bus mask must be 2.
1333 */
1334 if (mtp_interface != 0 && bus_mask != 2)
0769c38d 1335 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1336
1337
1338 /* Create the request to send to the West Bridge device */
1339 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1340 CY_RQT_SET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 4);
81eb669b 1341 if (req_p == 0)
0769c38d 1342 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1343
1344 /* Marshal the structure */
1345 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 1346 (uint16_t)((media_mask << 8) | bus_mask));
81eb669b 1347 cy_as_ll_request_response__set_word(req_p, 1,
0769c38d 1348 (uint16_t)use_antioch_enumeration);
81eb669b
DC
1349 cy_as_ll_request_response__set_word(req_p, 2,
1350 dev_p->is_mtp_firmware ? mtp_interface :
0769c38d 1351 mass_storage_interface);
81eb669b 1352 cy_as_ll_request_response__set_word(req_p, 3,
0769c38d 1353 (uint16_t)mass_storage_callbacks);
81eb669b
DC
1354
1355 /* Reserve space for the reply, the reply
1356 * data will not exceed one word */
0769c38d 1357 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 1358 if (reply_p == 0) {
0769c38d
DC
1359 cy_as_ll_destroy_request(dev_p, req_p);
1360 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1361 }
1362
1363 if (cb == 0) {
1364
0769c38d 1365 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1366 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1367 goto destroy;
81eb669b
DC
1368
1369 return my_handle_response_set_enum_config(dev_p,
0769c38d 1370 req_p, reply_p);
81eb669b
DC
1371 } else {
1372 ret = cy_as_misc_send_request(dev_p, cb, client,
1373 CY_FUNCT_CB_USB_SETENUMCONFIG, 0, dev_p->func_cbs_usb,
1374 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 1375 cy_as_usb_func_callback);
81eb669b
DC
1376
1377 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1378 goto destroy;
81eb669b 1379
0769c38d 1380 return ret;
81eb669b
DC
1381 }
1382
1383destroy:
0769c38d
DC
1384 cy_as_ll_destroy_request(dev_p, req_p);
1385 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1386
0769c38d 1387 return ret;
81eb669b
DC
1388}
1389
1390/*
1391 * This method sets how the USB is enumerated and should
1392 * be called before the CyAsUsbConnect() is called.
1393 */
1394cy_as_return_status_t
1395cy_as_usb_set_enum_config(cy_as_device_handle handle,
1396 cy_as_usb_enum_control *config_p,
1397 cy_as_function_callback cb,
1398 uint32_t client)
1399{
0769c38d
DC
1400 cy_as_device *dev_p = (cy_as_device *)handle;
1401 uint8_t bus_mask, media_mask;
1402 uint32_t bus, device;
1403 cy_as_return_status_t ret;
81eb669b 1404
0769c38d 1405 dev_p = (cy_as_device *)handle;
81eb669b 1406 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1407 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1408
0769c38d 1409 ret = is_usb_active(dev_p);
81eb669b 1410 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1411 return ret;
81eb669b
DC
1412
1413 if ((cy_as_device_is_in_callback(dev_p)) && (cb != 0))
0769c38d 1414 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1415
1416 /* Since we are mapping the media types to bus with NAND to 0
1417 * and the rest to 1, and we are only allowing for enumerating
1418 * all the devices on a bus we just scan the array for any
1419 * positions where there a device is enabled and mark the bus
1420 * to be enumerated.
1421 */
0769c38d
DC
1422 bus_mask = 0;
1423 media_mask = 0;
81eb669b
DC
1424 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1425 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
1426 if (config_p->devices_to_enumerate[bus][device] ==
1427 cy_true) {
0769c38d
DC
1428 bus_mask |= (0x01 << bus);
1429 media_mask |= dev_p->media_supported[bus];
1430 media_mask |= dev_p->media_supported[bus];
81eb669b
DC
1431 }
1432 }
1433 }
1434
1435 return my_usb_set_enum_config(dev_p, bus_mask, media_mask,
1436 config_p->antioch_enumeration,
1437 config_p->mass_storage_interface,
1438 config_p->mtp_interface,
1439 config_p->mass_storage_callbacks,
1440 cb,
1441 client
0769c38d 1442 );
81eb669b 1443}
af109f2e 1444EXPORT_SYMBOL(cy_as_usb_set_enum_config);
81eb669b
DC
1445
1446static cy_as_return_status_t
1447my_handle_response_get_enum_config(cy_as_device *dev_p,
1448 cy_as_ll_request_response *req_p,
1449 cy_as_ll_request_response *reply_p,
1450 void *config_p)
1451{
0769c38d
DC
1452 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1453 uint16_t val;
1454 uint8_t bus_mask;
1455 uint32_t bus;
81eb669b
DC
1456
1457 if (cy_as_ll_request_response__get_code(reply_p) !=
1458 CY_RESP_USB_CONFIG) {
0769c38d
DC
1459 ret = CY_AS_ERROR_INVALID_RESPONSE;
1460 goto destroy;
81eb669b
DC
1461 }
1462
1463 /* Marshal the reply */
1464 if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
0769c38d 1465 uint32_t device;
81eb669b
DC
1466 cy_bool state;
1467 cy_as_usb_enum_control *ms_config_p =
1468 (cy_as_usb_enum_control *)config_p;
1469
1470 bus_mask = (uint8_t)
1471 (cy_as_ll_request_response__get_word
0769c38d 1472 (reply_p, 0) & 0xFF);
81eb669b
DC
1473 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1474 if (bus_mask & (1 << bus))
0769c38d 1475 state = cy_true;
81eb669b 1476 else
0769c38d 1477 state = cy_false;
81eb669b
DC
1478
1479 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES;
1480 device++)
1481 ms_config_p->devices_to_enumerate[bus][device]
0769c38d 1482 = state;
81eb669b
DC
1483 }
1484
1485 ms_config_p->antioch_enumeration =
1486 (cy_bool)cy_as_ll_request_response__get_word
0769c38d 1487 (reply_p, 1);
81eb669b 1488
0769c38d 1489 val = cy_as_ll_request_response__get_word(reply_p, 2);
81eb669b 1490 if (dev_p->is_mtp_firmware) {
0769c38d
DC
1491 ms_config_p->mass_storage_interface = 0;
1492 ms_config_p->mtp_interface = (uint8_t)(val & 0xFF);
81eb669b
DC
1493 } else {
1494 ms_config_p->mass_storage_interface =
0769c38d
DC
1495 (uint8_t)(val & 0xFF);
1496 ms_config_p->mtp_interface = 0;
81eb669b 1497 }
0769c38d 1498 ms_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
81eb669b
DC
1499
1500 /*
1501 * firmware returns an invalid interface number for mass storage,
1502 * if mass storage is not enabled. this needs to be converted to
1503 * zero to match the input configuration.
1504 */
1505 if (bus_mask == 0) {
1506 if (dev_p->is_mtp_firmware)
0769c38d 1507 ms_config_p->mtp_interface = 0;
81eb669b 1508 else
0769c38d 1509 ms_config_p->mass_storage_interface = 0;
81eb669b
DC
1510 }
1511 } else {
1512 cy_as_usb_enum_control_dep *ex_config_p =
1513 (cy_as_usb_enum_control_dep *)config_p;
1514
1515 ex_config_p->enum_mass_storage = (uint8_t)
1516 ((cy_as_ll_request_response__get_word
0769c38d 1517 (reply_p, 0) >> 8) & 0xFF);
81eb669b 1518 ex_config_p->antioch_enumeration = (cy_bool)
0769c38d 1519 cy_as_ll_request_response__get_word(reply_p, 1);
81eb669b 1520
0769c38d
DC
1521 val = cy_as_ll_request_response__get_word(reply_p, 2);
1522 ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF);
1523 ex_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
81eb669b
DC
1524
1525 /*
1526 * firmware returns an invalid interface number for mass
1527 * storage, if mass storage is not enabled. this needs to
1528 * be converted to zero to match the input configuration.
1529 */
1530 if (ex_config_p->enum_mass_storage == 0)
0769c38d 1531 ex_config_p->mass_storage_interface = 0;
81eb669b
DC
1532 }
1533
1534destroy:
0769c38d
DC
1535 cy_as_ll_destroy_request(dev_p, req_p);
1536 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1537
0769c38d 1538 return ret;
81eb669b
DC
1539}
1540
1541/*
1542* This sets up the request for the enumerateion configuration
1543* information, based on if the request is from the old pre-1.2
1544* functions.
1545*/
1546static cy_as_return_status_t
1547my_usb_get_enum_config(cy_as_device_handle handle,
1548 uint16_t req_flags,
1549 void *config_p,
1550 cy_as_function_callback cb,
1551 uint32_t client)
1552{
0769c38d
DC
1553 cy_as_ll_request_response *req_p , *reply_p;
1554 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 1555
0769c38d 1556 cy_as_device *dev_p;
81eb669b 1557
0769c38d 1558 cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called");
81eb669b 1559
0769c38d 1560 dev_p = (cy_as_device *)handle;
81eb669b 1561 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1562 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1563
0769c38d 1564 ret = is_usb_active(dev_p);
81eb669b 1565 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1566 return ret;
81eb669b
DC
1567
1568 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1569 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1570
1571 /* Create the request to send to the West Bridge device */
1572 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1573 CY_RQT_GET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b 1574 if (req_p == 0)
0769c38d 1575 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1576
1577 /* Reserve space for the reply, the reply data
1578 * will not exceed two bytes */
0769c38d 1579 reply_p = cy_as_ll_create_response(dev_p, 3);
81eb669b 1580 if (reply_p == 0) {
0769c38d
DC
1581 cy_as_ll_destroy_request(dev_p, req_p);
1582 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1583 }
1584
1585 if (cb == 0) {
0769c38d 1586 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1587 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1588 goto destroy;
81eb669b
DC
1589
1590 /* we need to know the type of request to
1591 * know how to manage the data */
1592 req_p->flags |= req_flags;
1593 return my_handle_response_get_enum_config(dev_p,
0769c38d 1594 req_p, reply_p, config_p);
81eb669b
DC
1595 } else {
1596 ret = cy_as_misc_send_request(dev_p, cb, client,
1597 CY_FUNCT_CB_USB_GETENUMCONFIG, config_p,
1598 dev_p->func_cbs_usb, req_flags, req_p, reply_p,
0769c38d 1599 cy_as_usb_func_callback);
81eb669b
DC
1600
1601 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1602 goto destroy;
81eb669b 1603
0769c38d 1604 return ret;
81eb669b
DC
1605 }
1606
1607destroy:
0769c38d
DC
1608 cy_as_ll_destroy_request(dev_p, req_p);
1609 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1610
0769c38d 1611 return ret;
81eb669b
DC
1612}
1613
1614/*
1615 * This method returns the enumerateion configuration information
1616 * from the West Bridge device. Generally this is not used by
1617 * client software but is provided mostly for debug information.
1618 * We want a method to read all state information from the device.
1619 */
1620cy_as_return_status_t
1621cy_as_usb_get_enum_config(cy_as_device_handle handle,
1622 cy_as_usb_enum_control *config_p,
1623 cy_as_function_callback cb,
1624 uint32_t client)
1625{
1626 return my_usb_get_enum_config(handle,
1627 CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
1628}
af109f2e 1629EXPORT_SYMBOL(cy_as_usb_get_enum_config);
81eb669b
DC
1630
1631/*
1632* This method sets the USB descriptor for a given entity.
1633*/
1634cy_as_return_status_t
1635cy_as_usb_set_descriptor(cy_as_device_handle handle,
1636 cy_as_usb_desc_type type,
1637 uint8_t index,
1638 void *desc_p,
1639 uint16_t length,
1640 cy_as_function_callback cb,
1641 uint32_t client)
1642{
0769c38d
DC
1643 cy_as_ll_request_response *req_p , *reply_p;
1644 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1645 uint16_t pktlen;
81eb669b 1646
0769c38d 1647 cy_as_device *dev_p;
81eb669b 1648
0769c38d 1649 cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called");
81eb669b 1650
0769c38d 1651 dev_p = (cy_as_device *)handle;
81eb669b 1652 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1653 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1654
0769c38d 1655 ret = is_usb_active(dev_p);
81eb669b 1656 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1657 return ret;
81eb669b
DC
1658
1659 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1660 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1661
1662 if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
0769c38d 1663 return CY_AS_ERROR_INVALID_DESCRIPTOR;
81eb669b 1664
0769c38d 1665 pktlen = (uint16_t)length / 2;
81eb669b 1666 if (length % 2)
0769c38d
DC
1667 pktlen++;
1668 pktlen += 2; /* 1 for type, 1 for length */
81eb669b
DC
1669
1670 /* Create the request to send to the West Bridge device */
1671 req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_DESCRIPTOR,
0769c38d 1672 CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen);
81eb669b 1673 if (req_p == 0)
0769c38d 1674 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1675
1676 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 1677 (uint16_t)((uint8_t)type | (index << 8)));
81eb669b 1678 cy_as_ll_request_response__set_word(req_p, 1,
0769c38d
DC
1679 (uint16_t)length);
1680 cy_as_ll_request_response__pack(req_p, 2, length, desc_p);
81eb669b 1681
0769c38d 1682 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 1683 if (reply_p == 0) {
0769c38d
DC
1684 cy_as_ll_destroy_request(dev_p, req_p);
1685 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1686 }
1687
1688 if (cb == 0) {
0769c38d 1689 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1690 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1691 goto destroy;
81eb669b 1692
0769c38d 1693 return my_handle_response_no_data(dev_p, req_p, reply_p);
81eb669b
DC
1694 } else {
1695 ret = cy_as_misc_send_request(dev_p, cb, client,
1696 CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb,
1697 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 1698 cy_as_usb_func_callback);
81eb669b
DC
1699
1700 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1701 goto destroy;
81eb669b 1702
0769c38d 1703 return ret;
81eb669b
DC
1704 }
1705
1706destroy:
0769c38d
DC
1707 cy_as_ll_destroy_request(dev_p, req_p);
1708 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1709
0769c38d 1710 return ret;
81eb669b 1711}
af109f2e 1712EXPORT_SYMBOL(cy_as_usb_set_descriptor);
81eb669b
DC
1713
1714/*
1715 * This method clears all descriptors that were previously
1716 * stored on the West Bridge through CyAsUsbSetDescriptor calls.
1717 */
1718cy_as_return_status_t
1719cy_as_usb_clear_descriptors(cy_as_device_handle handle,
1720 cy_as_function_callback cb,
1721 uint32_t client)
1722{
0769c38d
DC
1723 cy_as_ll_request_response *req_p , *reply_p;
1724 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 1725
0769c38d 1726 cy_as_device *dev_p;
81eb669b 1727
0769c38d 1728 cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called");
81eb669b 1729
0769c38d 1730 dev_p = (cy_as_device *)handle;
81eb669b 1731 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1732 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1733
0769c38d 1734 ret = is_usb_active(dev_p);
81eb669b 1735 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1736 return ret;
81eb669b
DC
1737
1738 if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0))
0769c38d 1739 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1740
1741 /* Create the request to send to the West Bridge device */
1742 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1743 CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1);
81eb669b 1744 if (req_p == 0)
0769c38d 1745 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b 1746
0769c38d 1747 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 1748 if (reply_p == 0) {
0769c38d
DC
1749 cy_as_ll_destroy_request(dev_p, req_p);
1750 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1751 }
1752
1753 if (cb == 0) {
1754
0769c38d 1755 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 1756 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1757 goto destroy;
81eb669b 1758
0769c38d 1759 return my_handle_response_no_data(dev_p, req_p, reply_p);
81eb669b
DC
1760 } else {
1761 ret = cy_as_misc_send_request(dev_p, cb, client,
1762 CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0,
1763 dev_p->func_cbs_usb,
1764 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 1765 cy_as_usb_func_callback);
81eb669b
DC
1766
1767 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1768 goto destroy;
81eb669b 1769
0769c38d 1770 return ret;
81eb669b
DC
1771 }
1772
1773destroy:
0769c38d
DC
1774 cy_as_ll_destroy_request(dev_p, req_p);
1775 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1776
0769c38d 1777 return ret;
81eb669b 1778}
af109f2e 1779EXPORT_SYMBOL(cy_as_usb_clear_descriptors);
81eb669b
DC
1780
1781static cy_as_return_status_t
1782my_handle_response_get_descriptor(cy_as_device *dev_p,
1783 cy_as_ll_request_response *req_p,
1784 cy_as_ll_request_response *reply_p,
1785 cy_as_get_descriptor_data *data)
1786{
0769c38d
DC
1787 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1788 uint32_t retlen;
81eb669b
DC
1789
1790 if (cy_as_ll_request_response__get_code(reply_p) ==
1791 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
1792 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1793 goto destroy;
81eb669b
DC
1794 } else if (cy_as_ll_request_response__get_code(reply_p) !=
1795 CY_RESP_USB_DESCRIPTOR) {
0769c38d
DC
1796 ret = CY_AS_ERROR_INVALID_RESPONSE;
1797 goto destroy;
81eb669b
DC
1798 }
1799
0769c38d 1800 retlen = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 1801 if (retlen > data->length) {
0769c38d
DC
1802 ret = CY_AS_ERROR_INVALID_SIZE;
1803 goto destroy;
81eb669b
DC
1804 }
1805
0769c38d 1806 ret = CY_AS_ERROR_SUCCESS;
81eb669b 1807 cy_as_ll_request_response__unpack(reply_p, 1,
0769c38d 1808 retlen, data->desc_p);
81eb669b
DC
1809
1810destroy:
0769c38d
DC
1811 cy_as_ll_destroy_request(dev_p, req_p);
1812 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1813
0769c38d 1814 return ret;
81eb669b
DC
1815}
1816
1817/*
1818* This method retreives the USB descriptor for a given type.
1819*/
1820cy_as_return_status_t
1821cy_as_usb_get_descriptor(cy_as_device_handle handle,
1822 cy_as_usb_desc_type type,
1823 uint8_t index,
1824 cy_as_get_descriptor_data *data,
1825 cy_as_function_callback cb,
1826 uint32_t client)
1827{
0769c38d
DC
1828 cy_as_return_status_t ret;
1829 cy_as_ll_request_response *req_p , *reply_p;
81eb669b 1830
0769c38d 1831 cy_as_device *dev_p;
81eb669b 1832
0769c38d 1833 cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called");
81eb669b 1834
0769c38d 1835 dev_p = (cy_as_device *)handle;
81eb669b 1836 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1837 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1838
0769c38d 1839 ret = is_usb_active(dev_p);
81eb669b 1840 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1841 return ret;
81eb669b
DC
1842
1843 if (cy_as_device_is_in_callback(dev_p))
0769c38d 1844 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
1845
1846 /* Create the request to send to the West Bridge device */
1847 req_p = cy_as_ll_create_request(dev_p,
0769c38d 1848 CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1);
81eb669b 1849 if (req_p == 0)
0769c38d 1850 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1851
1852 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 1853 (uint16_t)((uint8_t)type | (index << 8)));
81eb669b
DC
1854
1855 /* Add one for the length field */
1856 reply_p = cy_as_ll_create_response(dev_p,
0769c38d 1857 CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1);
81eb669b 1858 if (reply_p == 0) {
0769c38d
DC
1859 cy_as_ll_destroy_request(dev_p, req_p);
1860 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
1861 }
1862
1863 if (cb == 0) {
1864 ret = cy_as_ll_send_request_wait_reply(
0769c38d 1865 dev_p, req_p, reply_p);
81eb669b 1866 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1867 goto destroy;
81eb669b
DC
1868
1869 return my_handle_response_get_descriptor(dev_p,
0769c38d 1870 req_p, reply_p, data);
81eb669b
DC
1871 } else {
1872 ret = cy_as_misc_send_request(dev_p, cb, client,
1873 CY_FUNCT_CB_USB_GETDESCRIPTOR, data,
1874 dev_p->func_cbs_usb,
1875 CY_AS_REQUEST_RESPONSE_EX, req_p,
0769c38d 1876 reply_p, cy_as_usb_func_callback);
81eb669b
DC
1877
1878 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1879 goto destroy;
81eb669b 1880
0769c38d 1881 return ret;
81eb669b
DC
1882 }
1883
1884destroy:
0769c38d
DC
1885 cy_as_ll_destroy_request(dev_p, req_p);
1886 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 1887
0769c38d 1888 return ret;
81eb669b 1889}
af109f2e 1890EXPORT_SYMBOL(cy_as_usb_get_descriptor);
81eb669b
DC
1891
1892cy_as_return_status_t
1893cy_as_usb_set_physical_configuration(cy_as_device_handle handle,
1894 uint8_t config)
1895{
0769c38d
DC
1896 cy_as_return_status_t ret;
1897 cy_as_device *dev_p;
81eb669b
DC
1898
1899 cy_as_log_debug_message(6,
0769c38d 1900 "cy_as_usb_set_physical_configuration called");
81eb669b 1901
0769c38d 1902 dev_p = (cy_as_device *)handle;
81eb669b 1903 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1904 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1905
0769c38d 1906 ret = is_usb_active(dev_p);
81eb669b 1907 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1908 return ret;
81eb669b
DC
1909
1910 if (cy_as_device_is_usb_connected(dev_p))
0769c38d 1911 return CY_AS_ERROR_USB_CONNECTED;
81eb669b
DC
1912
1913 if (config < 1 || config > 12)
0769c38d 1914 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b 1915
0769c38d 1916 dev_p->usb_phy_config = config;
81eb669b 1917
0769c38d 1918 return CY_AS_ERROR_SUCCESS;
81eb669b 1919}
af109f2e 1920EXPORT_SYMBOL(cy_as_usb_set_physical_configuration);
81eb669b
DC
1921
1922static cy_bool
1923is_physical_valid(uint8_t config, cy_as_end_point_number_t ep)
1924{
1925 static uint8_t validmask[12] = {
1926 0x0f, /* Config 1 - 1, 2, 3, 4 */
1927 0x07, /* Config 2 - 1, 2, 3 */
1928 0x07, /* Config 3 - 1, 2, 3 */
1929 0x0d, /* Config 4 - 1, 3, 4 */
1930 0x05, /* Config 5 - 1, 3 */
1931 0x05, /* Config 6 - 1, 3 */
1932 0x0d, /* Config 7 - 1, 3, 4 */
1933 0x05, /* Config 8 - 1, 3 */
1934 0x05, /* Config 9 - 1, 3 */
1935 0x0d, /* Config 10 - 1, 3, 4 */
1936 0x09, /* Config 11 - 1, 4 */
1937 0x01 /* Config 12 - 1 */
0769c38d 1938 };
81eb669b 1939
0769c38d 1940 return (validmask[config - 1] & (1 << (ep - 1))) ? cy_true : cy_false;
81eb669b
DC
1941}
1942
1943/*
1944* This method sets the configuration for an endpoint
1945*/
1946cy_as_return_status_t
1947cy_as_usb_set_end_point_config(cy_as_device_handle handle,
1948 cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
1949{
0769c38d
DC
1950 cy_as_return_status_t ret;
1951 cy_as_device *dev_p;
81eb669b 1952
0769c38d 1953 cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called");
81eb669b 1954
0769c38d 1955 dev_p = (cy_as_device *)handle;
81eb669b 1956 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 1957 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 1958
0769c38d 1959 ret = is_usb_active(dev_p);
81eb669b 1960 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 1961 return ret;
81eb669b
DC
1962
1963 if (cy_as_device_is_usb_connected(dev_p))
0769c38d 1964 return CY_AS_ERROR_USB_CONNECTED;
81eb669b
DC
1965
1966 if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
0769c38d 1967 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
1968
1969 if (ep == 0) {
1970 /* Endpoint 0 must be 64 byte, dir IN/OUT,
1971 * and control type */
1972 if (config_p->dir != cy_as_usb_in_out ||
1973 config_p->type != cy_as_usb_control)
0769c38d 1974 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1975 } else if (ep == 1) {
1976 if ((dev_p->is_mtp_firmware == 1) &&
1977 (dev_p->usb_config[1].enabled == cy_true)) {
0769c38d 1978 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
1979 }
1980
1981 /*
1982 * EP1 can only be used either as an OUT ep, or as an IN ep.
1983 */
1984 if ((config_p->type == cy_as_usb_control) ||
1985 (config_p->type == cy_as_usb_iso) ||
1986 (config_p->dir == cy_as_usb_in_out))
0769c38d 1987 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1988 } else {
1989 if (config_p->dir == cy_as_usb_in_out ||
1990 config_p->type == cy_as_usb_control)
0769c38d 1991 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
1992
1993 if (!is_physical_valid(dev_p->usb_phy_config,
1994 config_p->physical))
0769c38d 1995 return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT;
81eb669b
DC
1996
1997 /*
1998 * ISO endpoints must be on E_ps 3, 5, 7 or 9 as
1999 * they need to align directly with the underlying
2000 * physical endpoint.
2001 */
2002 if (config_p->type == cy_as_usb_iso) {
2003 if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
0769c38d 2004 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
2005
2006 if (ep == 3 && config_p->physical != 1)
0769c38d 2007 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
2008
2009 if (ep == 5 && config_p->physical != 2)
0769c38d 2010 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
2011
2012 if (ep == 7 && config_p->physical != 3)
0769c38d 2013 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
2014
2015 if (ep == 9 && config_p->physical != 4)
0769c38d 2016 return CY_AS_ERROR_INVALID_CONFIGURATION;
81eb669b
DC
2017 }
2018 }
2019
2020 /* Store the configuration information until a
2021 * CyAsUsbCommitConfig is done */
0769c38d 2022 dev_p->usb_config[ep] = *config_p;
81eb669b
DC
2023
2024 /* If the endpoint is enabled, enable DMA associated
2025 * with the endpoint */
2026 /*
2027 * we make some assumptions that we check here. we assume
2028 * that the direction fields for the DMA module are the same
2029 * values as the direction values for the USB module.
2030 */
2031 cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in);
2032 cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out);
0769c38d 2033 cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out);
81eb669b
DC
2034
2035 return cy_as_dma_enable_end_point(dev_p, ep,
0769c38d 2036 config_p->enabled, (cy_as_dma_direction)config_p->dir);
81eb669b 2037}
af109f2e 2038EXPORT_SYMBOL(cy_as_usb_set_end_point_config);
81eb669b
DC
2039
2040cy_as_return_status_t
2041cy_as_usb_get_end_point_config(cy_as_device_handle handle,
2042 cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
2043{
0769c38d 2044 cy_as_return_status_t ret;
81eb669b 2045
0769c38d 2046 cy_as_device *dev_p;
81eb669b 2047
0769c38d 2048 cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called");
81eb669b 2049
0769c38d 2050 dev_p = (cy_as_device *)handle;
81eb669b 2051 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2052 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2053
0769c38d 2054 ret = is_usb_active(dev_p);
81eb669b 2055 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2056 return ret;
81eb669b
DC
2057
2058 if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
0769c38d 2059 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b 2060
0769c38d 2061 *config_p = dev_p->usb_config[ep];
81eb669b 2062
0769c38d 2063 return CY_AS_ERROR_SUCCESS;
81eb669b 2064}
af109f2e 2065EXPORT_SYMBOL(cy_as_usb_get_end_point_config);
81eb669b
DC
2066
2067/*
2068* Commit the configuration of the various endpoints to the hardware.
2069*/
2070cy_as_return_status_t
2071cy_as_usb_commit_config(cy_as_device_handle handle,
2072 cy_as_function_callback cb,
2073 uint32_t client)
2074{
0769c38d
DC
2075 uint32_t i;
2076 cy_as_return_status_t ret;
2077 cy_as_ll_request_response *req_p , *reply_p;
2078 cy_as_device *dev_p;
2079 uint16_t data;
81eb669b 2080
0769c38d 2081 cy_as_log_debug_message(6, "cy_as_usb_commit_config called");
81eb669b 2082
0769c38d 2083 dev_p = (cy_as_device *)handle;
81eb669b 2084 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2085 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2086
0769c38d 2087 ret = is_usb_active(dev_p);
81eb669b 2088 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2089 return ret;
81eb669b
DC
2090
2091 if (cy_as_device_is_usb_connected(dev_p))
0769c38d 2092 return CY_AS_ERROR_USB_CONNECTED;
81eb669b
DC
2093
2094 if (cy_as_device_is_in_callback(dev_p))
0769c38d 2095 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
2096
2097 /*
2098 * this performs the mapping based on informatation that was
2099 * previously stored on the device about the various endpoints
2100 * and how they are configured. the output of this mapping is
2101 * setting the the 14 register values contained in usb_lepcfg
2102 * and usb_pepcfg
2103 */
0769c38d 2104 ret = cy_as_usb_map_logical2_physical(dev_p);
81eb669b 2105 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2106 return ret;
81eb669b
DC
2107
2108 /*
2109 * now, package the information about the various logical and
2110 * physical endpoint configuration registers and send it
2111 * across to the west bridge device.
2112 */
2113 req_p = cy_as_ll_create_request(dev_p,
0769c38d 2114 CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8);
81eb669b 2115 if (req_p == 0)
0769c38d 2116 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2117
2118 cy_as_hal_print_message("USB configuration: %d\n",
0769c38d 2119 dev_p->usb_phy_config);
81eb669b 2120 cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n",
0769c38d 2121 dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]);
81eb669b
DC
2122 cy_as_hal_print_message("PEP registers: 0x%02x 0x%02x 0x%02x 0x%02x\n",
2123 dev_p->usb_pepcfg[0], dev_p->usb_pepcfg[1],
0769c38d 2124 dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]);
81eb669b
DC
2125
2126 cy_as_hal_print_message("LEP registers: 0x%02x 0x%02x 0x%02x "
2127 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
2128 dev_p->usb_lepcfg[0], dev_p->usb_lepcfg[1],
2129 dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
2130 dev_p->usb_lepcfg[4], dev_p->usb_lepcfg[5],
2131 dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
0769c38d 2132 dev_p->usb_lepcfg[8], dev_p->usb_lepcfg[9]);
81eb669b
DC
2133
2134 /* Write the EP1OUTCFG and EP1INCFG data in the first word. */
2135 data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) |
0769c38d
DC
2136 dev_p->usb_ep1cfg[1]);
2137 cy_as_ll_request_response__set_word(req_p, 0, data);
81eb669b
DC
2138
2139 /* Write the PEP CFG data in the next 2 words */
0769c38d 2140 for (i = 0; i < 4; i += 2) {
81eb669b 2141 data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) |
0769c38d 2142 dev_p->usb_pepcfg[i + 1]);
81eb669b 2143 cy_as_ll_request_response__set_word(req_p,
0769c38d 2144 1 + i / 2, data);
81eb669b
DC
2145 }
2146
2147 /* Write the LEP CFG data in the next 5 words */
0769c38d 2148 for (i = 0; i < 10; i += 2) {
81eb669b 2149 data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) |
0769c38d 2150 dev_p->usb_lepcfg[i + 1]);
81eb669b 2151 cy_as_ll_request_response__set_word(req_p,
0769c38d 2152 3 + i / 2, data);
81eb669b
DC
2153 }
2154
2155 /* A single status word response type */
0769c38d 2156 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2157 if (reply_p == 0) {
0769c38d
DC
2158 cy_as_ll_destroy_request(dev_p, req_p);
2159 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2160 }
2161
2162 if (cb == 0) {
2163 ret = cy_as_ll_send_request_wait_reply(dev_p,
0769c38d 2164 req_p, reply_p);
81eb669b 2165 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2166 goto destroy;
81eb669b
DC
2167
2168 ret = my_handle_response_no_data(dev_p,
0769c38d 2169 req_p, reply_p);
81eb669b
DC
2170
2171 if (ret == CY_AS_ERROR_SUCCESS)
0769c38d 2172 ret = cy_as_usb_setup_dma(dev_p);
81eb669b 2173
0769c38d 2174 return ret;
81eb669b
DC
2175 } else {
2176 ret = cy_as_misc_send_request(dev_p, cb, client,
2177 CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb,
2178 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 2179 cy_as_usb_func_callback);
81eb669b
DC
2180
2181 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2182 goto destroy;
81eb669b 2183
0769c38d 2184 return ret;
81eb669b
DC
2185 }
2186
2187destroy:
0769c38d
DC
2188 cy_as_ll_destroy_request(dev_p, req_p);
2189 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 2190
0769c38d 2191 return ret;
81eb669b 2192}
af109f2e 2193EXPORT_SYMBOL(cy_as_usb_commit_config);
81eb669b
DC
2194
2195static void
2196sync_request_callback(cy_as_device *dev_p,
2197 cy_as_end_point_number_t ep, void *buf_p,
2198 uint32_t size, cy_as_return_status_t err)
2199{
0769c38d
DC
2200 (void)ep;
2201 (void)buf_p;
81eb669b 2202
0769c38d
DC
2203 dev_p->usb_error = err;
2204 dev_p->usb_actual_cnt = size;
81eb669b
DC
2205}
2206
2207static void
2208async_read_request_callback(cy_as_device *dev_p,
2209 cy_as_end_point_number_t ep, void *buf_p,
2210 uint32_t size, cy_as_return_status_t err)
2211{
0769c38d 2212 cy_as_device_handle h;
81eb669b
DC
2213
2214 cy_as_log_debug_message(6,
0769c38d 2215 "async_read_request_callback called");
81eb669b 2216
0769c38d 2217 h = (cy_as_device_handle)dev_p;
81eb669b
DC
2218
2219 if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
0769c38d
DC
2220 dev_p->usb_pending_buffer = buf_p;
2221 dev_p->usb_pending_size = size;
2222 dev_p->usb_error = err;
2223 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
81eb669b 2224 } else {
0769c38d 2225 cy_as_usb_io_callback cb;
81eb669b 2226
0769c38d
DC
2227 cb = dev_p->usb_cb[ep];
2228 dev_p->usb_cb[ep] = 0;
2229 cy_as_device_clear_usb_async_pending(dev_p, ep);
81eb669b 2230 if (cb)
0769c38d 2231 cb(h, ep, size, buf_p, err);
81eb669b
DC
2232 }
2233}
2234
2235static void
2236async_write_request_callback(cy_as_device *dev_p,
2237 cy_as_end_point_number_t ep, void *buf_p,
2238 uint32_t size, cy_as_return_status_t err)
2239{
0769c38d 2240 cy_as_device_handle h;
81eb669b
DC
2241
2242 cy_as_log_debug_message(6,
0769c38d 2243 "async_write_request_callback called");
81eb669b 2244
0769c38d 2245 h = (cy_as_device_handle)dev_p;
81eb669b
DC
2246
2247 if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
0769c38d
DC
2248 dev_p->usb_pending_buffer = buf_p;
2249 dev_p->usb_pending_size = size;
2250 dev_p->usb_error = err;
81eb669b
DC
2251
2252 /* The west bridge protocol generates ZLPs as required. */
0769c38d 2253 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
81eb669b 2254 } else {
0769c38d 2255 cy_as_usb_io_callback cb;
81eb669b 2256
0769c38d
DC
2257 cb = dev_p->usb_cb[ep];
2258 dev_p->usb_cb[ep] = 0;
81eb669b 2259
0769c38d 2260 cy_as_device_clear_usb_async_pending(dev_p, ep);
81eb669b 2261 if (cb)
0769c38d 2262 cb(h, ep, size, buf_p, err);
81eb669b
DC
2263 }
2264}
2265
2266static void
2267my_turbo_rqt_callback(cy_as_device *dev_p,
2268 uint8_t context,
2269 cy_as_ll_request_response *rqt,
2270 cy_as_ll_request_response *resp,
2271 cy_as_return_status_t stat)
2272{
0769c38d 2273 uint8_t code;
81eb669b 2274
0769c38d
DC
2275 (void)context;
2276 (void)stat;
81eb669b
DC
2277
2278 /* The Handlers are responsible for Deleting the rqt and resp when
2279 * they are finished
2280 */
0769c38d 2281 code = cy_as_ll_request_response__get_code(rqt);
81eb669b
DC
2282 switch (code) {
2283 case CY_RQT_TURBO_SWITCH_ENDPOINT:
0769c38d
DC
2284 cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS);
2285 cy_as_ll_destroy_request(dev_p, rqt);
2286 cy_as_ll_destroy_response(dev_p, resp);
81eb669b
DC
2287 break;
2288 default:
0769c38d
DC
2289 cy_as_hal_assert(cy_false);
2290 break;
81eb669b
DC
2291 }
2292}
2293
2294/* Send a mailbox request to prepare the endpoint for switching */
2295static cy_as_return_status_t
2296my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread)
2297{
0769c38d
DC
2298 cy_as_return_status_t ret;
2299 cy_as_ll_request_response *req_p , *reply_p;
81eb669b
DC
2300
2301 /* Create the request to send to the West Bridge device */
2302 req_p = cy_as_ll_create_request(dev_p,
0769c38d 2303 CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3);
81eb669b 2304 if (req_p == 0)
0769c38d 2305 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2306
2307 /* Reserve space for the reply, the reply data will
2308 * not exceed one word */
0769c38d 2309 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2310 if (reply_p == 0) {
0769c38d
DC
2311 cy_as_ll_destroy_request(dev_p, req_p);
2312 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2313 }
2314
2315 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 2316 (uint16_t)pktread);
81eb669b 2317 cy_as_ll_request_response__set_word(req_p, 1,
0769c38d 2318 (uint16_t)((size >> 16) & 0xFFFF));
81eb669b 2319 cy_as_ll_request_response__set_word(req_p, 2,
0769c38d 2320 (uint16_t)(size & 0xFFFF));
81eb669b
DC
2321
2322 ret = cy_as_ll_send_request(dev_p, req_p,
0769c38d 2323 reply_p, cy_false, my_turbo_rqt_callback);
81eb669b 2324 if (ret != CY_AS_ERROR_SUCCESS) {
0769c38d
DC
2325 cy_as_ll_destroy_request(dev_p, req_p);
2326 cy_as_ll_destroy_request(dev_p, reply_p);
2327 return ret;
81eb669b
DC
2328 }
2329
0769c38d 2330 return CY_AS_ERROR_SUCCESS;
81eb669b
DC
2331}
2332
2333cy_as_return_status_t
2334cy_as_usb_read_data(cy_as_device_handle handle,
2335 cy_as_end_point_number_t ep, cy_bool pktread,
2336 uint32_t dsize, uint32_t *dataread, void *data)
2337{
0769c38d
DC
2338 cy_as_return_status_t ret;
2339 cy_as_device *dev_p;
81eb669b 2340
0769c38d 2341 cy_as_log_debug_message(6, "cy_as_usb_read_data called");
81eb669b 2342
0769c38d 2343 dev_p = (cy_as_device *)handle;
81eb669b 2344 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2345 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2346
0769c38d 2347 ret = is_usb_active(dev_p);
81eb669b 2348 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2349 return ret;
81eb669b
DC
2350
2351 if (cy_as_device_is_in_callback(dev_p))
0769c38d 2352 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
2353
2354 if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
0769c38d 2355 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2356
2357 /* EP2 is available for reading when MTP is active */
2358 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
0769c38d 2359 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2360
2361 /* If the endpoint is disabled, we cannot
2362 * write data to the endpoint */
2363 if (!dev_p->usb_config[ep].enabled)
0769c38d 2364 return CY_AS_ERROR_ENDPOINT_DISABLED;
81eb669b
DC
2365
2366 if (dev_p->usb_config[ep].dir != cy_as_usb_out)
0769c38d 2367 return CY_AS_ERROR_USB_BAD_DIRECTION;
81eb669b
DC
2368
2369 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
0769c38d 2370 pktread, cy_true, sync_request_callback);
81eb669b 2371 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2372 return ret;
81eb669b
DC
2373
2374 if (ep == CY_AS_MTP_READ_ENDPOINT) {
0769c38d 2375 ret = my_send_turbo_switch(dev_p, dsize, pktread);
81eb669b 2376 if (ret != CY_AS_ERROR_SUCCESS) {
0769c38d
DC
2377 cy_as_dma_cancel(dev_p, ep, ret);
2378 return ret;
81eb669b
DC
2379 }
2380
0769c38d 2381 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
81eb669b 2382 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2383 return ret;
81eb669b 2384 } else {
0769c38d 2385 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
81eb669b 2386 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2387 return ret;
81eb669b
DC
2388 }
2389
0769c38d
DC
2390 ret = dev_p->usb_error;
2391 *dataread = dev_p->usb_actual_cnt;
81eb669b 2392
0769c38d 2393 return ret;
81eb669b 2394}
af109f2e 2395EXPORT_SYMBOL(cy_as_usb_read_data);
81eb669b
DC
2396
2397cy_as_return_status_t
2398cy_as_usb_read_data_async(cy_as_device_handle handle,
2399 cy_as_end_point_number_t ep, cy_bool pktread,
2400 uint32_t dsize, void *data, cy_as_usb_io_callback cb)
2401{
0769c38d
DC
2402 cy_as_return_status_t ret;
2403 uint32_t mask;
2404 cy_as_device *dev_p;
81eb669b 2405
0769c38d 2406 cy_as_log_debug_message(6, "cy_as_usb_read_data_async called");
81eb669b 2407
0769c38d 2408 dev_p = (cy_as_device *)handle;
81eb669b 2409 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2410 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2411
0769c38d 2412 ret = is_usb_active(dev_p);
81eb669b 2413 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2414 return ret;
81eb669b
DC
2415
2416 if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
0769c38d 2417 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2418
2419 /* EP2 is available for reading when MTP is active */
2420 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
0769c38d 2421 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2422
2423 /* If the endpoint is disabled, we cannot
2424 * write data to the endpoint */
2425 if (!dev_p->usb_config[ep].enabled)
0769c38d 2426 return CY_AS_ERROR_ENDPOINT_DISABLED;
81eb669b
DC
2427
2428 if (dev_p->usb_config[ep].dir != cy_as_usb_out &&
2429 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
0769c38d 2430 return CY_AS_ERROR_USB_BAD_DIRECTION;
81eb669b
DC
2431
2432 /*
2433 * since async operations can be triggered by interrupt
2434 * code, we must insure that we do not get multiple async
2435 * operations going at one time and protect this test and
2436 * set operation from interrupts.
2437 */
0769c38d 2438 mask = cy_as_hal_disable_interrupts();
81eb669b 2439 if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
0769c38d
DC
2440 cy_as_hal_enable_interrupts(mask);
2441 return CY_AS_ERROR_ASYNC_PENDING;
81eb669b 2442 }
0769c38d 2443 cy_as_device_set_usb_async_pending(dev_p, ep);
81eb669b
DC
2444
2445 /*
2446 * if this is for EP0, we set this bit to delay the
2447 * ACK response until after this read has completed.
2448 */
2449 if (ep == 0)
0769c38d 2450 cy_as_device_set_ack_delayed(dev_p);
81eb669b 2451
0769c38d 2452 cy_as_hal_enable_interrupts(mask);
81eb669b 2453
0769c38d
DC
2454 cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2455 dev_p->usb_cb[ep] = cb;
81eb669b
DC
2456
2457 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
0769c38d 2458 pktread, cy_true, async_read_request_callback);
81eb669b 2459 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2460 return ret;
81eb669b
DC
2461
2462 if (ep == CY_AS_MTP_READ_ENDPOINT) {
0769c38d 2463 ret = my_send_turbo_switch(dev_p, dsize, pktread);
81eb669b 2464 if (ret != CY_AS_ERROR_SUCCESS) {
0769c38d
DC
2465 cy_as_dma_cancel(dev_p, ep, ret);
2466 return ret;
81eb669b
DC
2467 }
2468 } else {
2469 /* Kick start the queue if it is not running */
0769c38d 2470 cy_as_dma_kick_start(dev_p, ep);
81eb669b 2471 }
0769c38d 2472 return ret;
81eb669b 2473}
af109f2e 2474EXPORT_SYMBOL(cy_as_usb_read_data_async);
81eb669b
DC
2475
2476cy_as_return_status_t
2477cy_as_usb_write_data(cy_as_device_handle handle,
2478 cy_as_end_point_number_t ep, uint32_t dsize, void *data)
2479{
0769c38d
DC
2480 cy_as_return_status_t ret;
2481 cy_as_device *dev_p;
81eb669b 2482
0769c38d 2483 cy_as_log_debug_message(6, "cy_as_usb_write_data called");
81eb669b 2484
0769c38d 2485 dev_p = (cy_as_device *)handle;
81eb669b 2486 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2487 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2488
0769c38d 2489 ret = is_usb_active(dev_p);
81eb669b 2490 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2491 return ret;
81eb669b
DC
2492
2493 if (cy_as_device_is_in_callback(dev_p))
0769c38d 2494 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
2495
2496 if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
0769c38d 2497 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2498
2499 /* EP6 is available for writing when MTP is active */
2500 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
0769c38d 2501 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2502
2503 /* If the endpoint is disabled, we cannot
2504 * write data to the endpoint */
2505 if (!dev_p->usb_config[ep].enabled)
0769c38d 2506 return CY_AS_ERROR_ENDPOINT_DISABLED;
81eb669b
DC
2507
2508 if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2509 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
0769c38d 2510 return CY_AS_ERROR_USB_BAD_DIRECTION;
81eb669b
DC
2511
2512 /* Write on Turbo endpoint */
2513 if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
0769c38d 2514 cy_as_ll_request_response *req_p, *reply_p;
81eb669b
DC
2515
2516 req_p = cy_as_ll_create_request(dev_p,
2517 CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
0769c38d 2518 CY_RQT_TUR_RQT_CONTEXT, 3);
81eb669b 2519 if (req_p == 0)
0769c38d 2520 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2521
2522 cy_as_ll_request_response__set_word(req_p,
0769c38d 2523 0, 0x0006); /* EP number to use. */
81eb669b 2524 cy_as_ll_request_response__set_word(req_p,
0769c38d 2525 1, (uint16_t)((dsize >> 16) & 0xFFFF));
81eb669b 2526 cy_as_ll_request_response__set_word(req_p,
0769c38d 2527 2, (uint16_t)(dsize & 0xFFFF));
81eb669b
DC
2528
2529 /* Reserve space for the reply, the reply data
2530 * will not exceed one word */
0769c38d 2531 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2532 if (reply_p == 0) {
0769c38d
DC
2533 cy_as_ll_destroy_request(dev_p, req_p);
2534 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2535 }
2536
2537 if (dsize) {
2538 ret = cy_as_dma_queue_request(dev_p,
2539 ep, data, dsize, cy_false,
0769c38d 2540 cy_false, sync_request_callback);
81eb669b 2541 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2542 return ret;
81eb669b
DC
2543 }
2544
0769c38d 2545 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b
DC
2546 if (ret == CY_AS_ERROR_SUCCESS) {
2547 if (cy_as_ll_request_response__get_code(reply_p) !=
2548 CY_RESP_SUCCESS_FAILURE)
0769c38d 2549 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b
DC
2550 else
2551 ret = cy_as_ll_request_response__get_word
2552 (reply_p, 0);
2553 }
2554
0769c38d
DC
2555 cy_as_ll_destroy_request(dev_p, req_p);
2556 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b
DC
2557
2558 if (ret != CY_AS_ERROR_SUCCESS) {
2559 if (dsize)
0769c38d
DC
2560 cy_as_dma_cancel(dev_p, ep, ret);
2561 return ret;
81eb669b
DC
2562 }
2563
2564 /* If this is a zero-byte write, firmware will
2565 * handle it. there is no need to do any work here.
2566 */
2567 if (!dsize)
0769c38d 2568 return CY_AS_ERROR_SUCCESS;
81eb669b
DC
2569 } else {
2570 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
0769c38d 2571 cy_false, cy_false, sync_request_callback);
81eb669b 2572 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2573 return ret;
81eb669b
DC
2574 }
2575
2576 if (ep != CY_AS_MTP_WRITE_ENDPOINT)
0769c38d 2577 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
81eb669b 2578 else
0769c38d 2579 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
81eb669b
DC
2580
2581 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2582 return ret;
81eb669b 2583
0769c38d
DC
2584 ret = dev_p->usb_error;
2585 return ret;
81eb669b 2586}
af109f2e 2587EXPORT_SYMBOL(cy_as_usb_write_data);
81eb669b
DC
2588
2589static void
2590mtp_write_callback(
2591 cy_as_device *dev_p,
2592 uint8_t context,
2593 cy_as_ll_request_response *rqt,
2594 cy_as_ll_request_response *resp,
2595 cy_as_return_status_t ret)
2596{
0769c38d
DC
2597 cy_as_usb_io_callback cb;
2598 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b 2599
0769c38d 2600 cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
81eb669b
DC
2601
2602 if (ret == CY_AS_ERROR_SUCCESS) {
2603 if (cy_as_ll_request_response__get_code(resp) !=
2604 CY_RESP_SUCCESS_FAILURE)
0769c38d 2605 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b 2606 else
0769c38d 2607 ret = cy_as_ll_request_response__get_word(resp, 0);
81eb669b
DC
2608 }
2609
2610 /* If this was a zero byte transfer request, we can
2611 * call the callback from here. */
2612 if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) &&
2613 (cy_as_ll_request_response__get_word(rqt, 2) == 0)) {
0769c38d
DC
2614 cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT];
2615 dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0;
81eb669b 2616 cy_as_device_clear_usb_async_pending(dev_p,
0769c38d 2617 CY_AS_MTP_WRITE_ENDPOINT);
81eb669b 2618 if (cb)
0769c38d 2619 cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret);
81eb669b 2620
0769c38d 2621 goto destroy;
81eb669b
DC
2622 }
2623
2624 if (ret != CY_AS_ERROR_SUCCESS) {
2625 /* Firmware failed the request. Cancel the DMA transfer. */
0769c38d
DC
2626 cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED);
2627 dev_p->usb_cb[0x06] = 0;
2628 cy_as_device_clear_usb_async_pending(dev_p, 0x06);
81eb669b
DC
2629 }
2630
2631destroy:
0769c38d
DC
2632 cy_as_ll_destroy_response(dev_p, resp);
2633 cy_as_ll_destroy_request(dev_p, rqt);
81eb669b
DC
2634}
2635
2636cy_as_return_status_t
2637cy_as_usb_write_data_async(cy_as_device_handle handle,
2638 cy_as_end_point_number_t ep, uint32_t dsize, void *data,
2639 cy_bool spacket, cy_as_usb_io_callback cb)
2640{
0769c38d
DC
2641 uint32_t mask;
2642 cy_as_return_status_t ret;
2643 cy_as_device *dev_p;
81eb669b 2644
0769c38d 2645 cy_as_log_debug_message(6, "cy_as_usb_write_data_async called");
81eb669b 2646
0769c38d 2647 dev_p = (cy_as_device *)handle;
81eb669b 2648 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2649 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2650
0769c38d 2651 ret = is_usb_active(dev_p);
81eb669b 2652 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2653 return ret;
81eb669b
DC
2654
2655 if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
0769c38d 2656 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2657
2658 /* EP6 is available for writing when MTP is active */
2659 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
0769c38d 2660 return CY_AS_ERROR_INVALID_ENDPOINT;
81eb669b
DC
2661
2662 /* If the endpoint is disabled, we cannot
2663 * write data to the endpoint */
2664 if (!dev_p->usb_config[ep].enabled)
0769c38d 2665 return CY_AS_ERROR_ENDPOINT_DISABLED;
81eb669b
DC
2666
2667 if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2668 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
0769c38d 2669 return CY_AS_ERROR_USB_BAD_DIRECTION;
81eb669b
DC
2670
2671 /*
2672 * since async operations can be triggered by interrupt
2673 * code, we must insure that we do not get multiple
2674 * async operations going at one time and
2675 * protect this test and set operation from interrupts.
2676 */
0769c38d 2677 mask = cy_as_hal_disable_interrupts();
81eb669b 2678 if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
0769c38d
DC
2679 cy_as_hal_enable_interrupts(mask);
2680 return CY_AS_ERROR_ASYNC_PENDING;
81eb669b
DC
2681 }
2682
0769c38d 2683 cy_as_device_set_usb_async_pending(dev_p, ep);
81eb669b
DC
2684
2685 if (ep == 0)
0769c38d 2686 cy_as_device_set_ack_delayed(dev_p);
81eb669b 2687
0769c38d 2688 cy_as_hal_enable_interrupts(mask);
81eb669b 2689
0769c38d
DC
2690 cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2691 dev_p->usb_cb[ep] = cb;
2692 dev_p->usb_spacket[ep] = spacket;
81eb669b
DC
2693
2694 /* Write on Turbo endpoint */
2695 if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
0769c38d 2696 cy_as_ll_request_response *req_p, *reply_p;
81eb669b
DC
2697
2698 req_p = cy_as_ll_create_request(dev_p,
2699 CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
0769c38d 2700 CY_RQT_TUR_RQT_CONTEXT, 3);
81eb669b
DC
2701
2702 if (req_p == 0)
0769c38d 2703 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2704
2705 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 2706 0x0006); /* EP number to use. */
81eb669b 2707 cy_as_ll_request_response__set_word(req_p, 1,
0769c38d 2708 (uint16_t)((dsize >> 16) & 0xFFFF));
81eb669b 2709 cy_as_ll_request_response__set_word(req_p, 2,
0769c38d 2710 (uint16_t)(dsize & 0xFFFF));
81eb669b
DC
2711
2712 /* Reserve space for the reply, the reply data
2713 * will not exceed one word */
0769c38d 2714 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2715 if (reply_p == 0) {
0769c38d
DC
2716 cy_as_ll_destroy_request(dev_p, req_p);
2717 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2718 }
2719
2720 if (dsize) {
2721 ret = cy_as_dma_queue_request(dev_p, ep, data,
2722 dsize, cy_false, cy_false,
0769c38d 2723 async_write_request_callback);
81eb669b 2724 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2725 return ret;
81eb669b
DC
2726 }
2727
2728 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
0769c38d 2729 cy_false, mtp_write_callback);
81eb669b
DC
2730 if (ret != CY_AS_ERROR_SUCCESS) {
2731 if (dsize)
0769c38d
DC
2732 cy_as_dma_cancel(dev_p, ep, ret);
2733 return ret;
81eb669b
DC
2734 }
2735
2736 /* Firmware will handle a zero byte transfer
2737 * without any DMA transfers. */
2738 if (!dsize)
0769c38d 2739 return CY_AS_ERROR_SUCCESS;
81eb669b
DC
2740 } else {
2741 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
0769c38d 2742 cy_false, cy_false, async_write_request_callback);
81eb669b 2743 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2744 return ret;
81eb669b
DC
2745 }
2746
2747 /* Kick start the queue if it is not running */
2748 if (ep != CY_AS_MTP_WRITE_ENDPOINT)
0769c38d 2749 cy_as_dma_kick_start(dev_p, ep);
81eb669b 2750
0769c38d 2751 return CY_AS_ERROR_SUCCESS;
81eb669b 2752}
af109f2e 2753EXPORT_SYMBOL(cy_as_usb_write_data_async);
81eb669b
DC
2754
2755static void
2756my_usb_cancel_async_callback(
2757 cy_as_device *dev_p,
2758 uint8_t context,
2759 cy_as_ll_request_response *rqt,
2760 cy_as_ll_request_response *resp,
2761 cy_as_return_status_t ret)
2762{
0769c38d
DC
2763 uint8_t ep;
2764 (void)context;
81eb669b 2765
0769c38d 2766 ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
81eb669b
DC
2767 if (ret == CY_AS_ERROR_SUCCESS) {
2768 if (cy_as_ll_request_response__get_code(resp) !=
2769 CY_RESP_SUCCESS_FAILURE)
0769c38d 2770 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b 2771 else
0769c38d 2772 ret = cy_as_ll_request_response__get_word(resp, 0);
81eb669b
DC
2773 }
2774
0769c38d
DC
2775 cy_as_ll_destroy_request(dev_p, rqt);
2776 cy_as_ll_destroy_response(dev_p, resp);
81eb669b
DC
2777
2778 if (ret == CY_AS_ERROR_SUCCESS) {
0769c38d
DC
2779 cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2780 dev_p->usb_cb[ep] = 0;
2781 cy_as_device_clear_usb_async_pending(dev_p, ep);
81eb669b
DC
2782 }
2783}
2784
2785cy_as_return_status_t
2786cy_as_usb_cancel_async(cy_as_device_handle handle,
2787 cy_as_end_point_number_t ep)
2788{
0769c38d
DC
2789 cy_as_return_status_t ret;
2790 cy_as_ll_request_response *req_p, *reply_p;
81eb669b 2791
0769c38d 2792 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 2793 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2794 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
2795
2796 ep &= 0x7F; /* Remove the direction bit. */
2797 if (!cy_as_device_is_usb_async_pending(dev_p, ep))
2798 return CY_AS_ERROR_ASYNC_NOT_PENDING;
2799
0769c38d 2800 ret = is_usb_active(dev_p);
81eb669b 2801 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2802 return ret;
81eb669b
DC
2803
2804 if (cy_as_device_is_in_suspend_mode(dev_p))
0769c38d 2805 return CY_AS_ERROR_IN_SUSPEND;
81eb669b
DC
2806
2807 if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
2808 (ep == CY_AS_MTP_READ_ENDPOINT)) {
2809 /* Need firmware support for the cancel operation. */
2810 req_p = cy_as_ll_create_request(dev_p,
2811 CY_RQT_CANCEL_ASYNC_TRANSFER,
0769c38d 2812 CY_RQT_TUR_RQT_CONTEXT, 1);
81eb669b
DC
2813
2814 if (req_p == 0)
0769c38d 2815 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b 2816
0769c38d 2817 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2818 if (reply_p == 0) {
0769c38d
DC
2819 cy_as_ll_destroy_request(dev_p, req_p);
2820 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2821 }
2822
2823 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 2824 (uint16_t)ep);
81eb669b
DC
2825
2826 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
0769c38d 2827 cy_false, my_usb_cancel_async_callback);
81eb669b
DC
2828
2829 if (ret != CY_AS_ERROR_SUCCESS) {
0769c38d
DC
2830 cy_as_ll_destroy_request(dev_p, req_p);
2831 cy_as_ll_destroy_response(dev_p, reply_p);
2832 return ret;
81eb669b
DC
2833 }
2834 } else {
0769c38d 2835 ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
81eb669b 2836 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2837 return ret;
81eb669b 2838
0769c38d
DC
2839 dev_p->usb_cb[ep] = 0;
2840 cy_as_device_clear_usb_async_pending(dev_p, ep);
81eb669b
DC
2841 }
2842
0769c38d 2843 return CY_AS_ERROR_SUCCESS;
81eb669b 2844}
af109f2e 2845EXPORT_SYMBOL(cy_as_usb_cancel_async);
81eb669b
DC
2846
2847static void
2848cy_as_usb_ack_callback(
2849 cy_as_device *dev_p,
2850 uint8_t context,
2851 cy_as_ll_request_response *rqt,
2852 cy_as_ll_request_response *resp,
2853 cy_as_return_status_t ret)
2854{
2855 cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
0769c38d 2856 dev_p->func_cbs_usb->head_p;
81eb669b 2857
0769c38d 2858 (void)context;
81eb669b
DC
2859
2860 if (ret == CY_AS_ERROR_SUCCESS) {
2861 if (cy_as_ll_request_response__get_code(resp) !=
2862 CY_RESP_SUCCESS_FAILURE)
0769c38d 2863 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b 2864 else
0769c38d 2865 ret = cy_as_ll_request_response__get_word(resp, 0);
81eb669b
DC
2866 }
2867
2868 node->cb_p((cy_as_device_handle)dev_p, ret,
0769c38d
DC
2869 node->client_data, node->data_type, node->data);
2870 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
81eb669b 2871
0769c38d
DC
2872 cy_as_ll_destroy_request(dev_p, rqt);
2873 cy_as_ll_destroy_response(dev_p, resp);
2874 cy_as_device_clear_ack_delayed(dev_p);
81eb669b
DC
2875}
2876
2877static cy_as_return_status_t
2878cy_as_usb_ack_setup_packet(cy_as_device_handle handle,
2879 cy_as_function_callback cb,
2880 uint32_t client)
2881{
0769c38d
DC
2882 cy_as_return_status_t ret;
2883 cy_as_ll_request_response *req_p;
2884 cy_as_ll_request_response *reply_p;
2885 cy_as_func_c_b_node *cbnode;
81eb669b 2886
0769c38d 2887 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 2888 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2889 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 2890
0769c38d 2891 ret = is_usb_active(dev_p);
81eb669b 2892 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2893 return ret;
81eb669b
DC
2894
2895 if (cy_as_device_is_in_callback(dev_p) && cb == 0)
0769c38d 2896 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b 2897
0769c38d 2898 cy_as_hal_assert(cb != 0);
81eb669b
DC
2899
2900 cbnode = cy_as_create_func_c_b_node(cb, client);
2901 if (cbnode == 0)
0769c38d 2902 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2903
2904 req_p = cy_as_ll_create_request(dev_p, 0,
0769c38d 2905 CY_RQT_USB_RQT_CONTEXT, 2);
81eb669b 2906 if (req_p == 0)
0769c38d 2907 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b 2908
0769c38d 2909 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2910 if (reply_p == 0) {
0769c38d
DC
2911 cy_as_ll_destroy_request(dev_p, req_p);
2912 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2913 }
2914
2915 cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET,
0769c38d
DC
2916 CY_RQT_USB_RQT_CONTEXT, 1);
2917 cy_as_ll_init_response(reply_p, 1);
81eb669b 2918
0769c38d 2919 req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
81eb669b 2920
0769c38d 2921 cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode);
81eb669b
DC
2922
2923 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
0769c38d 2924 cy_false, cy_as_usb_ack_callback);
81eb669b 2925
0769c38d 2926 return ret;
81eb669b
DC
2927}
2928
2929/*
2930 * Flush all data in logical EP that is being NAK-ed or
2931 * Stall-ed, so that this does not continue to block data
2932 * on other LEPs that use the same physical EP.
2933 */
2934static void
2935cy_as_usb_flush_logical_e_p(
2936 cy_as_device *dev_p,
2937 uint16_t ep)
2938{
0769c38d 2939 uint16_t addr, val, count;
81eb669b 2940
0769c38d
DC
2941 addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
2942 val = cy_as_hal_read_register(dev_p->tag, addr);
81eb669b
DC
2943
2944 while (val) {
0769c38d 2945 count = ((val & 0xFFF) + 1) / 2;
81eb669b 2946 while (count--)
0769c38d 2947 val = cy_as_hal_read_register(dev_p->tag, ep);
81eb669b 2948
0769c38d
DC
2949 cy_as_hal_write_register(dev_p->tag, addr, 0);
2950 val = cy_as_hal_read_register(dev_p->tag, addr);
81eb669b
DC
2951 }
2952}
2953
2954static cy_as_return_status_t
2955cy_as_usb_nak_stall_request(cy_as_device_handle handle,
2956 cy_as_end_point_number_t ep,
2957 uint16_t request,
2958 cy_bool state,
2959 cy_as_usb_function_callback cb,
2960 cy_as_function_callback fcb,
2961 uint32_t client)
2962{
0769c38d
DC
2963 cy_as_return_status_t ret;
2964 cy_as_ll_request_response *req_p , *reply_p;
2965 uint16_t data;
81eb669b 2966
0769c38d 2967 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 2968 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 2969 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
2970
2971 if (cb)
0769c38d 2972 cy_as_hal_assert(fcb == 0);
81eb669b 2973 if (fcb)
0769c38d 2974 cy_as_hal_assert(cb == 0);
81eb669b 2975
0769c38d 2976 ret = is_usb_active(dev_p);
81eb669b 2977 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 2978 return ret;
81eb669b
DC
2979
2980 if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0)
0769c38d 2981 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
2982
2983 req_p = cy_as_ll_create_request(dev_p,
0769c38d 2984 request, CY_RQT_USB_RQT_CONTEXT, 2);
81eb669b 2985 if (req_p == 0)
0769c38d 2986 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2987
2988 /* A single status word response type */
0769c38d 2989 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 2990 if (reply_p == 0) {
0769c38d
DC
2991 cy_as_ll_destroy_request(dev_p, req_p);
2992 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
2993 }
2994
2995 /* Set the endpoint */
0769c38d
DC
2996 data = (uint8_t)ep;
2997 cy_as_ll_request_response__set_word(req_p, 0, data);
81eb669b
DC
2998
2999 /* Set stall state to stalled */
0769c38d 3000 cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state);
81eb669b
DC
3001
3002 if (cb || fcb) {
0769c38d
DC
3003 void *cbnode;
3004 cy_as_c_b_queue *queue;
81eb669b 3005 if (cb) {
0769c38d
DC
3006 cbnode = cy_as_create_usb_func_c_b_node(cb, client);
3007 queue = dev_p->usb_func_cbs;
81eb669b 3008 } else {
0769c38d
DC
3009 cbnode = cy_as_create_func_c_b_node(fcb, client);
3010 queue = dev_p->func_cbs_usb;
3011 req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
81eb669b
DC
3012 }
3013
3014 if (cbnode == 0) {
0769c38d
DC
3015 ret = CY_AS_ERROR_OUT_OF_MEMORY;
3016 goto destroy;
81eb669b 3017 } else
0769c38d 3018 cy_as_insert_c_b_node(queue, cbnode);
81eb669b
DC
3019
3020
3021 if (cy_as_device_is_setup_packet(dev_p)) {
3022 /* No Ack is needed on a stall request on EP0 */
3023 if ((state == cy_true) && (ep == 0)) {
0769c38d 3024 cy_as_device_set_ep0_stalled(dev_p);
81eb669b 3025 } else {
0769c38d 3026 cy_as_device_set_ack_delayed(dev_p);
81eb669b 3027 req_p->flags |=
0769c38d 3028 CY_AS_REQUEST_RESPONSE_DELAY_ACK;
81eb669b
DC
3029 }
3030 }
3031
3032 ret = cy_as_ll_send_request(dev_p, req_p,
0769c38d 3033 reply_p, cy_false, cy_as_usb_func_callback);
81eb669b
DC
3034 if (ret != CY_AS_ERROR_SUCCESS) {
3035 if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
0769c38d
DC
3036 cy_as_device_rem_ack_delayed(dev_p);
3037 cy_as_remove_c_b_tail_node(queue);
81eb669b 3038
0769c38d 3039 goto destroy;
81eb669b
DC
3040 }
3041 } else {
3042 ret = cy_as_ll_send_request_wait_reply(dev_p,
0769c38d 3043 req_p, reply_p);
81eb669b 3044 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3045 goto destroy;
81eb669b
DC
3046
3047 if (cy_as_ll_request_response__get_code(reply_p) !=
3048 CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
3049 ret = CY_AS_ERROR_INVALID_RESPONSE;
3050 goto destroy;
81eb669b
DC
3051 }
3052
0769c38d 3053 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b
DC
3054
3055 if ((ret == CY_AS_ERROR_SUCCESS) &&
3056 (request == CY_RQT_STALL_ENDPOINT)) {
3057 if ((ep > 1) && (state != 0) &&
3058 (dev_p->usb_config[ep].dir == cy_as_usb_out))
0769c38d 3059 cy_as_usb_flush_logical_e_p(dev_p, ep);
81eb669b
DC
3060 }
3061
3062destroy:
0769c38d
DC
3063 cy_as_ll_destroy_request(dev_p, req_p);
3064 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b
DC
3065 }
3066
0769c38d 3067 return ret;
81eb669b
DC
3068}
3069
3070static cy_as_return_status_t
3071my_handle_response_get_stall(cy_as_device *dev_p,
3072 cy_as_ll_request_response *req_p,
3073 cy_as_ll_request_response *reply_p,
3074 cy_bool *state_p)
3075{
0769c38d
DC
3076 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3077 uint8_t code = cy_as_ll_request_response__get_code(reply_p);
81eb669b
DC
3078
3079 if (code == CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
3080 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3081 goto destroy;
81eb669b 3082 } else if (code != CY_RESP_ENDPOINT_STALL) {
0769c38d
DC
3083 ret = CY_AS_ERROR_INVALID_RESPONSE;
3084 goto destroy;
81eb669b
DC
3085 }
3086
0769c38d
DC
3087 *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3088 ret = CY_AS_ERROR_SUCCESS;
81eb669b
DC
3089
3090
3091destroy:
0769c38d
DC
3092 cy_as_ll_destroy_request(dev_p, req_p);
3093 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3094
0769c38d 3095 return ret;
81eb669b
DC
3096}
3097
3098static cy_as_return_status_t
3099my_handle_response_get_nak(cy_as_device *dev_p,
3100 cy_as_ll_request_response *req_p,
3101 cy_as_ll_request_response *reply_p,
3102 cy_bool *state_p)
3103{
0769c38d
DC
3104 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3105 uint8_t code = cy_as_ll_request_response__get_code(reply_p);
81eb669b
DC
3106
3107 if (code == CY_RESP_SUCCESS_FAILURE) {
0769c38d
DC
3108 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3109 goto destroy;
81eb669b 3110 } else if (code != CY_RESP_ENDPOINT_NAK) {
0769c38d
DC
3111 ret = CY_AS_ERROR_INVALID_RESPONSE;
3112 goto destroy;
81eb669b
DC
3113 }
3114
0769c38d
DC
3115 *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3116 ret = CY_AS_ERROR_SUCCESS;
81eb669b
DC
3117
3118
3119destroy:
0769c38d
DC
3120 cy_as_ll_destroy_request(dev_p, req_p);
3121 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3122
0769c38d 3123 return ret;
81eb669b
DC
3124}
3125
3126static cy_as_return_status_t
3127cy_as_usb_get_nak_stall(cy_as_device_handle handle,
3128 cy_as_end_point_number_t ep,
3129 uint16_t request,
3130 uint16_t response,
3131 cy_bool *state_p,
3132 cy_as_function_callback cb,
3133 uint32_t client)
3134{
0769c38d
DC
3135 cy_as_return_status_t ret;
3136 cy_as_ll_request_response *req_p , *reply_p;
3137 uint16_t data;
81eb669b 3138
0769c38d 3139 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3140
0769c38d 3141 (void)response;
81eb669b
DC
3142
3143 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3144 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 3145
0769c38d 3146 ret = is_usb_active(dev_p);
81eb669b 3147 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3148 return ret;
81eb669b
DC
3149
3150 if (cy_as_device_is_in_callback(dev_p) && !cb)
0769c38d 3151 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
3152
3153 req_p = cy_as_ll_create_request(dev_p, request,
0769c38d 3154 CY_RQT_USB_RQT_CONTEXT, 1);
81eb669b 3155 if (req_p == 0)
0769c38d 3156 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3157
3158 /* Set the endpoint */
0769c38d
DC
3159 data = (uint8_t)ep;
3160 cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep);
81eb669b
DC
3161
3162 /* A single status word response type */
0769c38d 3163 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 3164 if (reply_p == 0) {
0769c38d
DC
3165 cy_as_ll_destroy_request(dev_p, req_p);
3166 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3167 }
3168
3169 if (cb == 0) {
3170 ret = cy_as_ll_send_request_wait_reply(dev_p,
0769c38d 3171 req_p, reply_p);
81eb669b 3172 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3173 goto destroy;
81eb669b
DC
3174
3175 if (request == CY_RQT_GET_STALL)
3176 return my_handle_response_get_stall(dev_p,
0769c38d 3177 req_p, reply_p, state_p);
81eb669b
DC
3178 else
3179 return my_handle_response_get_nak(dev_p,
0769c38d 3180 req_p, reply_p, state_p);
81eb669b
DC
3181
3182 } else {
0769c38d 3183 cy_as_funct_c_b_type type;
81eb669b
DC
3184
3185 if (request == CY_RQT_GET_STALL)
0769c38d 3186 type = CY_FUNCT_CB_USB_GETSTALL;
81eb669b 3187 else
0769c38d 3188 type = CY_FUNCT_CB_USB_GETNAK;
81eb669b
DC
3189
3190 ret = cy_as_misc_send_request(dev_p, cb, client, type,
3191 state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
0769c38d 3192 req_p, reply_p, cy_as_usb_func_callback);
81eb669b
DC
3193
3194 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3195 goto destroy;
81eb669b 3196
0769c38d 3197 return ret;
81eb669b
DC
3198 }
3199
3200destroy:
0769c38d
DC
3201 cy_as_ll_destroy_request(dev_p, req_p);
3202 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3203
0769c38d 3204 return ret;
81eb669b
DC
3205}
3206
3207cy_as_return_status_t
3208cy_as_usb_set_nak(cy_as_device_handle handle,
3209 cy_as_end_point_number_t ep,
3210 cy_as_function_callback cb,
3211 uint32_t client)
3212{
0769c38d 3213 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3214 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3215 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3216
3217 /*
3218 * we send the firmware the EP# with the appropriate direction
3219 * bit, regardless of what the user gave us.
3220 */
0769c38d 3221 ep &= 0x0f;
81eb669b 3222 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3223 ep |= 0x80;
81eb669b
DC
3224
3225 if (dev_p->mtp_count > 0)
0769c38d 3226 return CY_AS_ERROR_NOT_VALID_IN_MTP;
81eb669b
DC
3227
3228 return cy_as_usb_nak_stall_request(handle, ep,
0769c38d 3229 CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client);
81eb669b 3230}
af109f2e 3231EXPORT_SYMBOL(cy_as_usb_set_nak);
81eb669b
DC
3232
3233cy_as_return_status_t
3234cy_as_usb_clear_nak(cy_as_device_handle handle,
3235 cy_as_end_point_number_t ep,
3236 cy_as_function_callback cb,
3237 uint32_t client)
3238{
0769c38d 3239 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3240 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3241 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3242
3243 /*
3244 * we send the firmware the EP# with the appropriate
3245 * direction bit, regardless of what the user gave us.
3246 */
0769c38d 3247 ep &= 0x0f;
81eb669b 3248 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3249 ep |= 0x80;
81eb669b
DC
3250
3251 if (dev_p->mtp_count > 0)
0769c38d 3252 return CY_AS_ERROR_NOT_VALID_IN_MTP;
81eb669b
DC
3253
3254 return cy_as_usb_nak_stall_request(handle, ep,
0769c38d 3255 CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client);
81eb669b 3256}
af109f2e 3257EXPORT_SYMBOL(cy_as_usb_clear_nak);
81eb669b
DC
3258
3259cy_as_return_status_t
3260cy_as_usb_get_nak(cy_as_device_handle handle,
3261 cy_as_end_point_number_t ep,
3262 cy_bool *nak_p,
3263 cy_as_function_callback cb,
3264 uint32_t client)
3265{
0769c38d 3266 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3267 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3268 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3269
3270 /*
3271 * we send the firmware the EP# with the appropriate
3272 * direction bit, regardless of what the user gave us.
3273 */
0769c38d 3274 ep &= 0x0f;
81eb669b 3275 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3276 ep |= 0x80;
81eb669b
DC
3277
3278 if (dev_p->mtp_count > 0)
0769c38d 3279 return CY_AS_ERROR_NOT_VALID_IN_MTP;
81eb669b
DC
3280
3281 return cy_as_usb_get_nak_stall(handle, ep,
3282 CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK,
0769c38d 3283 nak_p, cb, client);
81eb669b 3284}
af109f2e 3285EXPORT_SYMBOL(cy_as_usb_get_nak);
81eb669b
DC
3286
3287cy_as_return_status_t
3288cy_as_usb_set_stall(cy_as_device_handle handle,
3289 cy_as_end_point_number_t ep,
3290 cy_as_function_callback cb,
3291 uint32_t client)
3292{
0769c38d 3293 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3294 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3295 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3296
3297 /*
3298 * we send the firmware the EP# with the appropriate
3299 * direction bit, regardless of what the user gave us.
3300 */
0769c38d 3301 ep &= 0x0f;
81eb669b 3302 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3303 ep |= 0x80;
81eb669b
DC
3304
3305 if (dev_p->mtp_turbo_active)
0769c38d 3306 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
81eb669b
DC
3307
3308 return cy_as_usb_nak_stall_request(handle, ep,
0769c38d 3309 CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client);
81eb669b 3310}
af109f2e 3311EXPORT_SYMBOL(cy_as_usb_set_stall);
81eb669b
DC
3312
3313cy_as_return_status_t
3314cy_as_usb_clear_stall(cy_as_device_handle handle,
3315 cy_as_end_point_number_t ep,
3316 cy_as_function_callback cb,
3317 uint32_t client)
3318{
0769c38d 3319 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3320 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3321 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3322
3323 /*
3324 * we send the firmware the EP# with the appropriate
3325 * direction bit, regardless of what the user gave us.
3326 */
0769c38d 3327 ep &= 0x0f;
81eb669b 3328 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3329 ep |= 0x80;
81eb669b
DC
3330
3331 if (dev_p->mtp_turbo_active)
0769c38d 3332 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
81eb669b
DC
3333
3334 return cy_as_usb_nak_stall_request(handle, ep,
0769c38d 3335 CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client);
81eb669b 3336}
af109f2e 3337EXPORT_SYMBOL(cy_as_usb_clear_stall);
81eb669b
DC
3338
3339cy_as_return_status_t
3340cy_as_usb_get_stall(cy_as_device_handle handle,
3341 cy_as_end_point_number_t ep,
3342 cy_bool *stall_p,
3343 cy_as_function_callback cb,
3344 uint32_t client)
3345{
0769c38d 3346 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3347 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3348 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b
DC
3349
3350 /*
3351 * we send the firmware the EP# with the appropriate
3352 * direction bit, regardless of what the user gave us.
3353 */
0769c38d 3354 ep &= 0x0f;
81eb669b 3355 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
0769c38d 3356 ep |= 0x80;
81eb669b
DC
3357
3358 if (dev_p->mtp_turbo_active)
0769c38d 3359 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
81eb669b
DC
3360
3361 return cy_as_usb_get_nak_stall(handle, ep,
0769c38d 3362 CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client);
81eb669b 3363}
af109f2e 3364EXPORT_SYMBOL(cy_as_usb_get_stall);
81eb669b
DC
3365
3366cy_as_return_status_t
3367cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle,
3368 cy_as_function_callback cb,
3369 uint32_t client)
3370{
0769c38d
DC
3371 cy_as_return_status_t ret;
3372 cy_as_ll_request_response *req_p , *reply_p;
81eb669b 3373
0769c38d 3374 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3375 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3376 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 3377
0769c38d 3378 ret = is_usb_active(dev_p);
81eb669b 3379 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3380 return ret;
81eb669b
DC
3381
3382 if (cy_as_device_is_in_callback(dev_p))
0769c38d 3383 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
3384
3385 if (dev_p->usb_last_event != cy_as_event_usb_suspend)
0769c38d 3386 return CY_AS_ERROR_NOT_IN_SUSPEND;
81eb669b
DC
3387
3388 req_p = cy_as_ll_create_request(dev_p,
0769c38d 3389 CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0);
81eb669b 3390 if (req_p == 0)
0769c38d 3391 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3392
3393 /* A single status word response type */
0769c38d 3394 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 3395 if (reply_p == 0) {
0769c38d
DC
3396 cy_as_ll_destroy_request(dev_p, req_p);
3397 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3398 }
3399
3400 if (cb == 0) {
0769c38d 3401 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 3402 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3403 goto destroy;
81eb669b
DC
3404
3405 if (cy_as_ll_request_response__get_code(reply_p) ==
3406 CY_RESP_SUCCESS_FAILURE)
0769c38d 3407 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 3408 else
0769c38d 3409 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b
DC
3410 } else {
3411 ret = cy_as_misc_send_request(dev_p, cb, client,
3412 CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0,
3413 dev_p->func_cbs_usb,
3414 CY_AS_REQUEST_RESPONSE_EX, req_p,
0769c38d 3415 reply_p, cy_as_usb_func_callback);
81eb669b
DC
3416
3417 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d
DC
3418 goto destroy;
3419 return ret;
81eb669b
DC
3420 }
3421
3422destroy:
0769c38d
DC
3423 cy_as_ll_destroy_request(dev_p, req_p);
3424 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3425
0769c38d 3426 return ret;
81eb669b 3427}
af109f2e 3428EXPORT_SYMBOL(cy_as_usb_signal_remote_wakeup);
81eb669b
DC
3429
3430cy_as_return_status_t
3431cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle,
3432 uint32_t wr_sectors,
3433 uint32_t rd_sectors,
3434 cy_as_function_callback cb,
3435 uint32_t client)
3436{
0769c38d
DC
3437 cy_as_return_status_t ret;
3438 cy_as_ll_request_response *req_p , *reply_p;
81eb669b 3439
0769c38d 3440 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3441 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3442 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 3443
0769c38d 3444 ret = is_usb_active(dev_p);
81eb669b 3445 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3446 return ret;
81eb669b
DC
3447
3448 if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
0769c38d 3449 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
3450
3451 /* Check if the firmware version supports this feature. */
3452 if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] ==
3453 (1 << cy_as_media_nand)))
0769c38d 3454 return CY_AS_ERROR_NOT_SUPPORTED;
81eb669b
DC
3455
3456 req_p = cy_as_ll_create_request(dev_p, CY_RQT_USB_STORAGE_MONITOR,
0769c38d 3457 CY_RQT_USB_RQT_CONTEXT, 4);
81eb669b 3458 if (req_p == 0)
0769c38d 3459 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3460
3461 /* A single status word response type */
0769c38d 3462 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 3463 if (reply_p == 0) {
0769c38d
DC
3464 cy_as_ll_destroy_request(dev_p, req_p);
3465 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3466 }
3467
3468 /* Set the read and write count parameters into
3469 * the request structure. */
3470 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 3471 (uint16_t)((wr_sectors >> 16) & 0xFFFF));
81eb669b 3472 cy_as_ll_request_response__set_word(req_p, 1,
0769c38d 3473 (uint16_t)(wr_sectors & 0xFFFF));
81eb669b 3474 cy_as_ll_request_response__set_word(req_p, 2,
0769c38d 3475 (uint16_t)((rd_sectors >> 16) & 0xFFFF));
81eb669b 3476 cy_as_ll_request_response__set_word(req_p, 3,
0769c38d 3477 (uint16_t)(rd_sectors & 0xFFFF));
81eb669b
DC
3478
3479 if (cb == 0) {
0769c38d 3480 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 3481 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3482 goto destroy;
81eb669b
DC
3483
3484 if (cy_as_ll_request_response__get_code(reply_p) ==
3485 CY_RESP_SUCCESS_FAILURE)
0769c38d 3486 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 3487 else
0769c38d 3488 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b
DC
3489 } else {
3490 ret = cy_as_misc_send_request(dev_p, cb, client,
3491 CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD, 0,
3492 dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
0769c38d 3493 req_p, reply_p, cy_as_usb_func_callback);
81eb669b
DC
3494
3495 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d
DC
3496 goto destroy;
3497 return ret;
81eb669b
DC
3498 }
3499
3500destroy:
0769c38d
DC
3501 cy_as_ll_destroy_request(dev_p, req_p);
3502 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3503
0769c38d 3504 return ret;
81eb669b 3505}
af109f2e 3506EXPORT_SYMBOL(cy_as_usb_set_m_s_report_threshold);
81eb669b
DC
3507
3508cy_as_return_status_t
3509cy_as_usb_select_m_s_partitions(
3510 cy_as_device_handle handle,
3511 cy_as_bus_number_t bus,
3512 uint32_t device,
3513 cy_as_usb_m_s_type_t type,
3514 cy_as_function_callback cb,
3515 uint32_t client)
3516{
0769c38d
DC
3517 cy_as_return_status_t ret;
3518 cy_as_ll_request_response *req_p , *reply_p;
3519 uint16_t val;
81eb669b 3520
0769c38d 3521 cy_as_device *dev_p = (cy_as_device *)handle;
81eb669b 3522 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
0769c38d 3523 return CY_AS_ERROR_INVALID_HANDLE;
81eb669b 3524
0769c38d 3525 ret = is_usb_active(dev_p);
81eb669b 3526 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3527 return ret;
81eb669b
DC
3528
3529 /* This API has to be made before SetEnumConfig is called. */
3530 if (dev_p->usb_config[0].enabled)
0769c38d 3531 return CY_AS_ERROR_INVALID_CALL_SEQUENCE;
81eb669b
DC
3532
3533 if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
0769c38d 3534 return CY_AS_ERROR_INVALID_IN_CALLBACK;
81eb669b
DC
3535
3536 req_p = cy_as_ll_create_request(dev_p, CY_RQT_MS_PARTITION_SELECT,
0769c38d 3537 CY_RQT_USB_RQT_CONTEXT, 2);
81eb669b 3538 if (req_p == 0)
0769c38d 3539 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3540
3541 /* A single status word response type */
0769c38d 3542 reply_p = cy_as_ll_create_response(dev_p, 1);
81eb669b 3543 if (reply_p == 0) {
0769c38d
DC
3544 cy_as_ll_destroy_request(dev_p, req_p);
3545 return CY_AS_ERROR_OUT_OF_MEMORY;
81eb669b
DC
3546 }
3547
3548 /* Set the read and write count parameters into
3549 * the request structure. */
3550 cy_as_ll_request_response__set_word(req_p, 0,
0769c38d 3551 (uint16_t)((bus << 8) | device));
81eb669b 3552
0769c38d 3553 val = 0;
81eb669b 3554 if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both))
0769c38d 3555 val |= 1;
81eb669b 3556 if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both))
0769c38d 3557 val |= (1 << 8);
81eb669b 3558
0769c38d 3559 cy_as_ll_request_response__set_word(req_p, 1, val);
81eb669b
DC
3560
3561 if (cb == 0) {
0769c38d 3562 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
81eb669b 3563 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d 3564 goto destroy;
81eb669b
DC
3565
3566 if (cy_as_ll_request_response__get_code(reply_p) ==
3567 CY_RESP_SUCCESS_FAILURE)
0769c38d 3568 ret = cy_as_ll_request_response__get_word(reply_p, 0);
81eb669b 3569 else
0769c38d 3570 ret = CY_AS_ERROR_INVALID_RESPONSE;
81eb669b
DC
3571 } else {
3572 ret = cy_as_misc_send_request(dev_p, cb, client,
3573 CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb,
3574 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
0769c38d 3575 cy_as_usb_func_callback);
81eb669b
DC
3576
3577 if (ret != CY_AS_ERROR_SUCCESS)
0769c38d
DC
3578 goto destroy;
3579 return ret;
81eb669b
DC
3580 }
3581
3582destroy:
0769c38d
DC
3583 cy_as_ll_destroy_request(dev_p, req_p);
3584 cy_as_ll_destroy_response(dev_p, reply_p);
81eb669b 3585
0769c38d 3586 return ret;
81eb669b 3587}
af109f2e 3588EXPORT_SYMBOL(cy_as_usb_select_m_s_partitions);
81eb669b
DC
3589
3590static void
3591cy_as_usb_func_callback(
3592 cy_as_device *dev_p,
3593 uint8_t context,
3594 cy_as_ll_request_response *rqt,
3595 cy_as_ll_request_response *resp,
3596 cy_as_return_status_t stat)
3597{
3598 cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *)
0769c38d 3599 dev_p->usb_func_cbs->head_p;
81eb669b 3600 cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *)
0769c38d
DC
3601 dev_p->func_cbs_usb->head_p;
3602 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
81eb669b 3603
0769c38d 3604 cy_as_device_handle h = (cy_as_device_handle)dev_p;
81eb669b
DC
3605 cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3606 == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3607 cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
0769c38d 3608 == CY_AS_REQUEST_RESPONSE_EX;
81eb669b 3609 cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
0769c38d
DC
3610 == CY_AS_REQUEST_RESPONSE_MS;
3611 uint8_t code;
3612 uint8_t ep, state;
81eb669b
DC
3613
3614 if (!ex_request && !ms_request) {
0769c38d 3615 cy_as_hal_assert(dev_p->usb_func_cbs->count != 0);
81eb669b 3616 cy_as_hal_assert(dev_p->usb_func_cbs->type ==
0769c38d 3617 CYAS_USB_FUNC_CB);
81eb669b 3618 } else {
0769c38d
DC
3619 cy_as_hal_assert(dev_p->func_cbs_usb->count != 0);
3620 cy_as_hal_assert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB);
81eb669b
DC
3621 }
3622
0769c38d 3623 (void)context;
81eb669b
DC
3624
3625 /* The Handlers are responsible for Deleting the rqt and resp when
3626 * they are finished
3627 */
0769c38d 3628 code = cy_as_ll_request_response__get_code(rqt);
81eb669b
DC
3629 switch (code) {
3630 case CY_RQT_START_USB:
0769c38d
DC
3631 ret = my_handle_response_usb_start(dev_p, rqt, resp, stat);
3632 break;
81eb669b 3633 case CY_RQT_STOP_USB:
0769c38d
DC
3634 ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat);
3635 break;
81eb669b
DC
3636 case CY_RQT_SET_CONNECT_STATE:
3637 if (!cy_as_ll_request_response__get_word(rqt, 0))
3638 ret = my_handle_response_disconnect(
0769c38d 3639 dev_p, rqt, resp, stat);
81eb669b
DC
3640 else
3641 ret = my_handle_response_connect(
0769c38d
DC
3642 dev_p, rqt, resp, stat);
3643 break;
81eb669b 3644 case CY_RQT_GET_CONNECT_STATE:
0769c38d 3645 break;
81eb669b 3646 case CY_RQT_SET_USB_CONFIG:
0769c38d
DC
3647 ret = my_handle_response_set_enum_config(dev_p, rqt, resp);
3648 break;
81eb669b 3649 case CY_RQT_GET_USB_CONFIG:
0769c38d 3650 cy_as_hal_assert(fnode->data != 0);
81eb669b 3651 ret = my_handle_response_get_enum_config(dev_p,
0769c38d
DC
3652 rqt, resp, fnode->data);
3653 break;
81eb669b 3654 case CY_RQT_STALL_ENDPOINT:
0769c38d
DC
3655 ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
3656 state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1);
3657 ret = my_handle_response_no_data(dev_p, rqt, resp);
81eb669b
DC
3658 if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0)
3659 && (dev_p->usb_config[ep].dir == cy_as_usb_out))
0769c38d
DC
3660 cy_as_usb_flush_logical_e_p(dev_p, ep);
3661 break;
81eb669b 3662 case CY_RQT_GET_STALL:
0769c38d 3663 cy_as_hal_assert(fnode->data != 0);
81eb669b 3664 ret = my_handle_response_get_stall(dev_p,
0769c38d
DC
3665 rqt, resp, (cy_bool *)fnode->data);
3666 break;
81eb669b 3667 case CY_RQT_SET_DESCRIPTOR:
0769c38d
DC
3668 ret = my_handle_response_no_data(dev_p, rqt, resp);
3669 break;
81eb669b 3670 case CY_RQT_GET_DESCRIPTOR:
0769c38d 3671 cy_as_hal_assert(fnode->data != 0);
81eb669b 3672 ret = my_handle_response_get_descriptor(dev_p,
0769c38d 3673 rqt, resp, (cy_as_get_descriptor_data *)fnode->data);
81eb669b
DC
3674 break;
3675 case CY_RQT_SET_USB_CONFIG_REGISTERS:
0769c38d 3676 ret = my_handle_response_no_data(dev_p, rqt, resp);
81eb669b 3677 if (ret == CY_AS_ERROR_SUCCESS)
0769c38d
DC
3678 ret = cy_as_usb_setup_dma(dev_p);
3679 break;
81eb669b 3680 case CY_RQT_ENDPOINT_SET_NAK:
0769c38d
DC
3681 ret = my_handle_response_no_data(dev_p, rqt, resp);
3682 break;
81eb669b 3683 case CY_RQT_GET_ENDPOINT_NAK:
0769c38d 3684 cy_as_hal_assert(fnode->data != 0);
81eb669b 3685 ret = my_handle_response_get_nak(dev_p,
0769c38d
DC
3686 rqt, resp, (cy_bool *)fnode->data);
3687 break;
81eb669b 3688 case CY_RQT_ACK_SETUP_PACKET:
0769c38d 3689 break;
81eb669b 3690 case CY_RQT_USB_REMOTE_WAKEUP:
0769c38d
DC
3691 ret = my_handle_response_no_data(dev_p, rqt, resp);
3692 break;
81eb669b 3693 case CY_RQT_CLEAR_DESCRIPTORS:
0769c38d
DC
3694 ret = my_handle_response_no_data(dev_p, rqt, resp);
3695 break;
81eb669b 3696 case CY_RQT_USB_STORAGE_MONITOR:
0769c38d
DC
3697 ret = my_handle_response_no_data(dev_p, rqt, resp);
3698 break;
81eb669b 3699 case CY_RQT_MS_PARTITION_SELECT:
0769c38d
DC
3700 ret = my_handle_response_no_data(dev_p, rqt, resp);
3701 break;
81eb669b 3702 default:
0769c38d
DC
3703 ret = CY_AS_ERROR_INVALID_RESPONSE;
3704 cy_as_hal_assert(cy_false);
3705 break;
81eb669b
DC
3706 }
3707
3708 /*
3709 * if the low level layer returns a direct error, use
3710 * the corresponding error code. if not, use the error
3711 * code based on the response from firmware.
3712 */
3713 if (stat == CY_AS_ERROR_SUCCESS)
0769c38d 3714 stat = ret;
81eb669b
DC
3715
3716 if (ex_request || ms_request) {
3717 fnode->cb_p((cy_as_device_handle)dev_p, stat,
0769c38d
DC
3718 fnode->client_data, fnode->data_type, fnode->data);
3719 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
81eb669b
DC
3720 } else {
3721 node->cb_p((cy_as_device_handle)dev_p, stat,
0769c38d
DC
3722 node->client_data);
3723 cy_as_remove_c_b_node(dev_p->usb_func_cbs);
81eb669b
DC
3724 }
3725
3726 if (delayed_ack) {
0769c38d
DC
3727 cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p));
3728 cy_as_device_rem_ack_delayed(dev_p);
81eb669b
DC
3729
3730 /*
3731 * send the ACK if required.
3732 */
3733 if (!cy_as_device_is_ack_delayed(dev_p))
3734 cy_as_usb_ack_setup_packet(h,
0769c38d 3735 usb_ack_callback, 0);
81eb669b
DC
3736 }
3737}
3738
3739
3740/*[]*/