Commit | Line | Data |
---|---|---|
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 | ||
31 | static cy_as_return_status_t | |
32 | cy_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 | |
41 | static void | |
42 | cy_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 | */ | |
51 | static void | |
52 | cy_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 | */ | |
67 | static cy_as_return_status_t | |
68 | is_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 | ||
85 | static void | |
86 | usb_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 | ||
116 | static void | |
117 | my_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 | ||
236 | static void | |
237 | my_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 | ||
319 | static void | |
320 | my_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 | ||
424 | static void | |
425 | my_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 | ||
471 | static void | |
472 | my_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 | ||
547 | static void | |
548 | my_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 | */ | |
583 | static void | |
584 | my_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 | ||
636 | static cy_as_return_status_t | |
637 | my_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 | |
663 | destroy: | |
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 | */ | |
689 | cy_as_return_status_t | |
690 | cy_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 | ||
790 | destroy: | |
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 | 803 | EXPORT_SYMBOL(cy_as_usb_start); |
81eb669b DC |
804 | |
805 | void | |
806 | cy_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 | */ | |
836 | void | |
837 | cy_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 | ||
850 | static cy_as_return_status_t | |
851 | my_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 | |
875 | destroy: | |
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 | */ | |
894 | cy_as_return_status_t | |
895 | cy_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 | ||
962 | destroy: | |
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 | 981 | EXPORT_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 | */ | |
987 | cy_as_return_status_t | |
988 | cy_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 | 1009 | EXPORT_SYMBOL(cy_as_usb_register_callback); |
81eb669b DC |
1010 | |
1011 | static cy_as_return_status_t | |
1012 | my_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 | ||
1030 | static cy_as_return_status_t | |
1031 | my_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 | |
1049 | destroy: | |
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 | */ | |
1065 | cy_as_return_status_t | |
1066 | cy_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 | ||
1123 | destroy: | |
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 | 1129 | EXPORT_SYMBOL(cy_as_usb_connect); |
81eb669b DC |
1130 | |
1131 | static cy_as_return_status_t | |
1132 | my_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 | |
1150 | destroy: | |
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 | */ | |
1162 | cy_as_return_status_t | |
1163 | cy_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 | } |
1222 | destroy: | |
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 | 1228 | EXPORT_SYMBOL(cy_as_usb_disconnect); |
81eb669b DC |
1229 | |
1230 | static cy_as_return_status_t | |
1231 | my_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 | ||
1261 | destroy: | |
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 | */ | |
1272 | static cy_as_return_status_t | |
1273 | my_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 | ||
1383 | destroy: | |
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 | */ | |
1394 | cy_as_return_status_t | |
1395 | cy_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 | 1444 | EXPORT_SYMBOL(cy_as_usb_set_enum_config); |
81eb669b DC |
1445 | |
1446 | static cy_as_return_status_t | |
1447 | my_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 | ||
1534 | destroy: | |
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 | */ | |
1546 | static cy_as_return_status_t | |
1547 | my_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 | ||
1607 | destroy: | |
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 | */ | |
1620 | cy_as_return_status_t | |
1621 | cy_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 | 1629 | EXPORT_SYMBOL(cy_as_usb_get_enum_config); |
81eb669b DC |
1630 | |
1631 | /* | |
1632 | * This method sets the USB descriptor for a given entity. | |
1633 | */ | |
1634 | cy_as_return_status_t | |
1635 | cy_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 | ||
1706 | destroy: | |
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 | 1712 | EXPORT_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 | */ | |
1718 | cy_as_return_status_t | |
1719 | cy_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 | ||
1773 | destroy: | |
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 | 1779 | EXPORT_SYMBOL(cy_as_usb_clear_descriptors); |
81eb669b DC |
1780 | |
1781 | static cy_as_return_status_t | |
1782 | my_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 | |
1810 | destroy: | |
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 | */ | |
1820 | cy_as_return_status_t | |
1821 | cy_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 | ||
1884 | destroy: | |
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 | 1890 | EXPORT_SYMBOL(cy_as_usb_get_descriptor); |
81eb669b DC |
1891 | |
1892 | cy_as_return_status_t | |
1893 | cy_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 | 1920 | EXPORT_SYMBOL(cy_as_usb_set_physical_configuration); |
81eb669b DC |
1921 | |
1922 | static cy_bool | |
1923 | is_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 | */ | |
1946 | cy_as_return_status_t | |
1947 | cy_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 | 2038 | EXPORT_SYMBOL(cy_as_usb_set_end_point_config); |
81eb669b DC |
2039 | |
2040 | cy_as_return_status_t | |
2041 | cy_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 | 2065 | EXPORT_SYMBOL(cy_as_usb_get_end_point_config); |
81eb669b DC |
2066 | |
2067 | /* | |
2068 | * Commit the configuration of the various endpoints to the hardware. | |
2069 | */ | |
2070 | cy_as_return_status_t | |
2071 | cy_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 | ||
2187 | destroy: | |
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 | 2193 | EXPORT_SYMBOL(cy_as_usb_commit_config); |
81eb669b DC |
2194 | |
2195 | static void | |
2196 | sync_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 | ||
2207 | static void | |
2208 | async_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 | ||
2235 | static void | |
2236 | async_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 | ||
2266 | static void | |
2267 | my_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 */ | |
2295 | static cy_as_return_status_t | |
2296 | my_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 | ||
2333 | cy_as_return_status_t | |
2334 | cy_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 | 2395 | EXPORT_SYMBOL(cy_as_usb_read_data); |
81eb669b DC |
2396 | |
2397 | cy_as_return_status_t | |
2398 | cy_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 | 2474 | EXPORT_SYMBOL(cy_as_usb_read_data_async); |
81eb669b DC |
2475 | |
2476 | cy_as_return_status_t | |
2477 | cy_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 | 2587 | EXPORT_SYMBOL(cy_as_usb_write_data); |
81eb669b DC |
2588 | |
2589 | static void | |
2590 | mtp_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 | ||
2631 | destroy: | |
0769c38d DC |
2632 | cy_as_ll_destroy_response(dev_p, resp); |
2633 | cy_as_ll_destroy_request(dev_p, rqt); | |
81eb669b DC |
2634 | } |
2635 | ||
2636 | cy_as_return_status_t | |
2637 | cy_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 | 2753 | EXPORT_SYMBOL(cy_as_usb_write_data_async); |
81eb669b DC |
2754 | |
2755 | static void | |
2756 | my_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 | ||
2785 | cy_as_return_status_t | |
2786 | cy_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 | 2845 | EXPORT_SYMBOL(cy_as_usb_cancel_async); |
81eb669b DC |
2846 | |
2847 | static void | |
2848 | cy_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 | ||
2877 | static cy_as_return_status_t | |
2878 | cy_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 | */ | |
2934 | static void | |
2935 | cy_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 | ||
2954 | static cy_as_return_status_t | |
2955 | cy_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 | ||
3062 | destroy: | |
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 | ||
3070 | static cy_as_return_status_t | |
3071 | my_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 | ||
3091 | destroy: | |
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 | ||
3098 | static cy_as_return_status_t | |
3099 | my_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 | ||
3119 | destroy: | |
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 | ||
3126 | static cy_as_return_status_t | |
3127 | cy_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 | ||
3200 | destroy: | |
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 | ||
3207 | cy_as_return_status_t | |
3208 | cy_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 | 3231 | EXPORT_SYMBOL(cy_as_usb_set_nak); |
81eb669b DC |
3232 | |
3233 | cy_as_return_status_t | |
3234 | cy_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 | 3257 | EXPORT_SYMBOL(cy_as_usb_clear_nak); |
81eb669b DC |
3258 | |
3259 | cy_as_return_status_t | |
3260 | cy_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 | 3285 | EXPORT_SYMBOL(cy_as_usb_get_nak); |
81eb669b DC |
3286 | |
3287 | cy_as_return_status_t | |
3288 | cy_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 | 3311 | EXPORT_SYMBOL(cy_as_usb_set_stall); |
81eb669b DC |
3312 | |
3313 | cy_as_return_status_t | |
3314 | cy_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 | 3337 | EXPORT_SYMBOL(cy_as_usb_clear_stall); |
81eb669b DC |
3338 | |
3339 | cy_as_return_status_t | |
3340 | cy_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 | 3364 | EXPORT_SYMBOL(cy_as_usb_get_stall); |
81eb669b DC |
3365 | |
3366 | cy_as_return_status_t | |
3367 | cy_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 | ||
3422 | destroy: | |
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 | 3428 | EXPORT_SYMBOL(cy_as_usb_signal_remote_wakeup); |
81eb669b DC |
3429 | |
3430 | cy_as_return_status_t | |
3431 | cy_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 | ||
3500 | destroy: | |
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 | 3506 | EXPORT_SYMBOL(cy_as_usb_set_m_s_report_threshold); |
81eb669b DC |
3507 | |
3508 | cy_as_return_status_t | |
3509 | cy_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 | ||
3582 | destroy: | |
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 | 3588 | EXPORT_SYMBOL(cy_as_usb_select_m_s_partitions); |
81eb669b DC |
3589 | |
3590 | static void | |
3591 | cy_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 | /*[]*/ |