Commit | Line | Data |
---|---|---|
81eb669b DC |
1 | /* Cypress West Bridge API header file (cyasmtp.h) |
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/cyasmtp.h" | |
24 | #include "../../include/linux/westbridge/cyaserr.h" | |
25 | #include "../../include/linux/westbridge/cyasdma.h" | |
26 | #include "../../include/linux/westbridge/cyaslowlevel.h" | |
27 | ||
28 | static void | |
29 | cy_as_mtp_func_callback(cy_as_device *dev_p, | |
30 | uint8_t context, | |
31 | cy_as_ll_request_response *rqt, | |
32 | cy_as_ll_request_response *resp, | |
0769c38d | 33 | cy_as_return_status_t stat); |
81eb669b DC |
34 | |
35 | static cy_as_return_status_t | |
36 | is_mtp_active(cy_as_device *dev_p) | |
37 | { | |
38 | if (!cy_as_device_is_configured(dev_p)) | |
0769c38d | 39 | return CY_AS_ERROR_NOT_CONFIGURED; |
81eb669b DC |
40 | |
41 | if (!cy_as_device_is_firmware_loaded(dev_p)) | |
0769c38d | 42 | return CY_AS_ERROR_NO_FIRMWARE; |
81eb669b DC |
43 | |
44 | if (dev_p->mtp_count == 0) | |
0769c38d | 45 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
46 | |
47 | if (cy_as_device_is_in_suspend_mode(dev_p)) | |
0769c38d | 48 | return CY_AS_ERROR_IN_SUSPEND; |
81eb669b | 49 | |
0769c38d | 50 | return CY_AS_ERROR_SUCCESS; |
81eb669b DC |
51 | } |
52 | ||
53 | static void | |
54 | my_mtp_request_callback(cy_as_device *dev_p, | |
55 | uint8_t context, | |
56 | cy_as_ll_request_response *req_p, | |
57 | cy_as_ll_request_response *resp_p, | |
58 | cy_as_return_status_t ret) | |
59 | { | |
0769c38d DC |
60 | uint16_t val, ev, status; |
61 | uint16_t mtp_datalen = 0; | |
62 | uint32_t bytecount_l, bytecount_h; | |
63 | cy_as_mtp_send_object_complete_data send_obj_data; | |
64 | cy_as_mtp_get_object_complete_data get_obj_data; | |
65 | cy_as_dma_end_point *ep_p; | |
81eb669b | 66 | |
0769c38d | 67 | uint8_t code = cy_as_ll_request_response__get_code(req_p); |
81eb669b | 68 | |
0769c38d DC |
69 | (void)resp_p; |
70 | (void)context; | |
71 | (void)ret; | |
81eb669b DC |
72 | |
73 | switch (code) { | |
74 | case CY_RQT_MTP_EVENT: | |
0769c38d | 75 | val = cy_as_ll_request_response__get_word(req_p, 0); |
81eb669b | 76 | /* MSB indicates status of read/write */ |
0769c38d | 77 | status = (val >> 8) & 0xFF; |
81eb669b | 78 | /* event type */ |
0769c38d | 79 | ev = val & 0xFF; |
81eb669b DC |
80 | switch (ev) { |
81 | case 0: /* SendObject Complete */ | |
82 | { | |
83 | bytecount_l = | |
84 | cy_as_ll_request_response__get_word | |
0769c38d | 85 | (req_p, 1); |
81eb669b DC |
86 | bytecount_h = |
87 | cy_as_ll_request_response__get_word | |
0769c38d | 88 | (req_p, 2); |
81eb669b | 89 | send_obj_data.byte_count = |
0769c38d | 90 | (bytecount_h << 16) | bytecount_l; |
81eb669b | 91 | |
0769c38d | 92 | send_obj_data.status = status; |
81eb669b DC |
93 | |
94 | /* use the byte count again */ | |
95 | bytecount_l = | |
96 | cy_as_ll_request_response__get_word | |
0769c38d | 97 | (req_p, 3); |
81eb669b DC |
98 | bytecount_h = |
99 | cy_as_ll_request_response__get_word | |
0769c38d | 100 | (req_p, 4); |
81eb669b | 101 | send_obj_data.transaction_id = |
0769c38d | 102 | (bytecount_h << 16) | bytecount_l; |
81eb669b | 103 | |
0769c38d | 104 | dev_p->mtp_turbo_active = cy_false; |
81eb669b DC |
105 | |
106 | if (dev_p->mtp_event_cb) | |
107 | dev_p->mtp_event_cb( | |
108 | (cy_as_device_handle) dev_p, | |
109 | cy_as_mtp_send_object_complete, | |
0769c38d | 110 | &send_obj_data); |
81eb669b | 111 | } |
0769c38d | 112 | break; |
81eb669b DC |
113 | |
114 | case 1: /* GetObject Complete */ | |
115 | { | |
116 | bytecount_l = | |
117 | cy_as_ll_request_response__get_word | |
0769c38d | 118 | (req_p, 1); |
81eb669b DC |
119 | bytecount_h = |
120 | cy_as_ll_request_response__get_word | |
0769c38d | 121 | (req_p, 2); |
81eb669b DC |
122 | |
123 | get_obj_data.byte_count = | |
0769c38d | 124 | (bytecount_h << 16) | bytecount_l; |
81eb669b | 125 | |
0769c38d | 126 | get_obj_data.status = status; |
81eb669b | 127 | |
0769c38d | 128 | dev_p->mtp_turbo_active = cy_false; |
81eb669b DC |
129 | |
130 | if (dev_p->mtp_event_cb) | |
131 | dev_p->mtp_event_cb( | |
132 | (cy_as_device_handle) dev_p, | |
133 | cy_as_mtp_get_object_complete, | |
134 | &get_obj_data); | |
135 | } | |
0769c38d | 136 | break; |
81eb669b DC |
137 | |
138 | case 2: /* BlockTable Needed */ | |
139 | { | |
140 | if (dev_p->mtp_event_cb) | |
141 | dev_p->mtp_event_cb( | |
142 | (cy_as_device_handle) dev_p, | |
143 | cy_as_mtp_block_table_needed, 0); | |
144 | } | |
0769c38d | 145 | break; |
81eb669b | 146 | default: |
0769c38d | 147 | cy_as_hal_print_message("invalid event type\n"); |
81eb669b DC |
148 | cy_as_ll_send_data_response(dev_p, |
149 | CY_RQT_TUR_RQT_CONTEXT, | |
150 | CY_RESP_MTP_INVALID_EVENT, | |
0769c38d DC |
151 | sizeof(ev), &ev); |
152 | break; | |
81eb669b | 153 | } |
0769c38d | 154 | break; |
81eb669b DC |
155 | |
156 | case CY_RQT_TURBO_CMD_FROM_HOST: | |
157 | { | |
158 | mtp_datalen = | |
0769c38d | 159 | cy_as_ll_request_response__get_word(req_p, 1); |
81eb669b DC |
160 | |
161 | /* Get the endpoint pointer based on | |
162 | * the endpoint number */ | |
0769c38d | 163 | ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_READ_ENDPOINT); |
81eb669b DC |
164 | |
165 | /* The event should arrive only after the DMA operation | |
166 | * has been queued. */ | |
0769c38d | 167 | cy_as_hal_assert(ep_p->queue_p != 0); |
81eb669b DC |
168 | |
169 | /* Put the len in ep data information in | |
170 | * dmaqueue and kick start the queue */ | |
0769c38d | 171 | cy_as_hal_assert(ep_p->queue_p->size >= mtp_datalen); |
81eb669b DC |
172 | |
173 | if (mtp_datalen == 0) { | |
174 | cy_as_dma_completed_callback(dev_p->tag, | |
175 | CY_AS_MTP_READ_ENDPOINT, 0, | |
0769c38d | 176 | CY_AS_ERROR_SUCCESS); |
81eb669b | 177 | } else { |
0769c38d | 178 | ep_p->maxhwdata = mtp_datalen; |
81eb669b DC |
179 | |
180 | /* | |
181 | * make sure that the DMA status for this | |
182 | * EP is not running, so that the call to | |
183 | * cy_as_dma_kick_start gets this transfer | |
184 | * going. note: in MTP mode, we never leave | |
185 | * a DMA transfer of greater than one packet | |
186 | * running. so, it is okay to override the | |
187 | * status here and start the next packet | |
188 | * transfer. | |
189 | */ | |
0769c38d | 190 | cy_as_dma_end_point_set_stopped(ep_p); |
81eb669b DC |
191 | |
192 | /* Kick start the queue if it is not running */ | |
193 | cy_as_dma_kick_start(dev_p, | |
194 | CY_AS_MTP_READ_ENDPOINT); | |
195 | } | |
196 | } | |
0769c38d | 197 | break; |
81eb669b DC |
198 | |
199 | case CY_RQT_TURBO_START_WRITE_DMA: | |
200 | { | |
201 | /* | |
202 | * now that the firmware is ready to receive the | |
203 | * next packet of data, start the corresponding | |
204 | * DMA transfer. first, ensure that a DMA | |
205 | * operation is still pending in the queue for the | |
206 | * write endpoint. | |
207 | */ | |
208 | cy_as_ll_send_status_response(dev_p, | |
209 | CY_RQT_TUR_RQT_CONTEXT, | |
0769c38d | 210 | CY_AS_ERROR_SUCCESS, 0); |
81eb669b | 211 | |
0769c38d DC |
212 | ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_WRITE_ENDPOINT); |
213 | cy_as_hal_assert(ep_p->queue_p != 0); | |
81eb669b | 214 | |
0769c38d DC |
215 | cy_as_dma_end_point_set_stopped(ep_p); |
216 | cy_as_dma_kick_start(dev_p, CY_AS_MTP_WRITE_ENDPOINT); | |
81eb669b | 217 | } |
0769c38d | 218 | break; |
81eb669b DC |
219 | |
220 | default: | |
221 | cy_as_hal_print_message("invalid request received " | |
0769c38d DC |
222 | "on TUR context\n"); |
223 | val = req_p->box0; | |
81eb669b | 224 | cy_as_ll_send_data_response(dev_p, CY_RQT_TUR_RQT_CONTEXT, |
0769c38d DC |
225 | CY_RESP_INVALID_REQUEST, sizeof(val), &val); |
226 | break; | |
81eb669b DC |
227 | } |
228 | } | |
229 | ||
230 | static cy_as_return_status_t | |
231 | my_handle_response_no_data(cy_as_device *dev_p, | |
232 | cy_as_ll_request_response *req_p, | |
233 | cy_as_ll_request_response *reply_p) | |
234 | { | |
0769c38d | 235 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; |
81eb669b DC |
236 | |
237 | if (cy_as_ll_request_response__get_code(reply_p) != | |
238 | CY_RESP_SUCCESS_FAILURE) { | |
0769c38d DC |
239 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
240 | goto destroy; | |
81eb669b DC |
241 | } |
242 | ||
0769c38d | 243 | ret = cy_as_ll_request_response__get_word(reply_p, 0); |
81eb669b DC |
244 | |
245 | destroy: | |
0769c38d DC |
246 | cy_as_ll_destroy_request(dev_p, req_p); |
247 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 248 | |
0769c38d | 249 | return ret; |
81eb669b DC |
250 | } |
251 | ||
252 | static cy_as_return_status_t | |
253 | my_handle_response_mtp_start(cy_as_device *dev_p, | |
254 | cy_as_ll_request_response *req_p, | |
255 | cy_as_ll_request_response *reply_p, | |
256 | cy_as_return_status_t ret) | |
257 | { | |
258 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 259 | goto destroy; |
81eb669b DC |
260 | |
261 | if (cy_as_ll_request_response__get_code(reply_p) != | |
262 | CY_RESP_SUCCESS_FAILURE) { | |
0769c38d DC |
263 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
264 | goto destroy; | |
81eb669b DC |
265 | } |
266 | ||
0769c38d | 267 | ret = cy_as_ll_request_response__get_word(reply_p, 0); |
81eb669b | 268 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 269 | goto destroy; |
81eb669b | 270 | |
0769c38d | 271 | dev_p->mtp_count++; |
81eb669b DC |
272 | |
273 | cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_READ_ENDPOINT, | |
0769c38d DC |
274 | cy_true, cy_as_direction_out); |
275 | dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].enabled = cy_true; | |
276 | dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].dir = cy_as_usb_out; | |
277 | dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].type = cy_as_usb_bulk; | |
81eb669b DC |
278 | |
279 | cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_WRITE_ENDPOINT, | |
0769c38d DC |
280 | cy_true, cy_as_direction_in); |
281 | dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].enabled = cy_true; | |
282 | dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].dir = cy_as_usb_in; | |
283 | dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].type = cy_as_usb_bulk; | |
81eb669b DC |
284 | |
285 | /* Packet size is 512 bytes */ | |
0769c38d | 286 | cy_as_dma_set_max_dma_size(dev_p, 0x02, 0x0200); |
81eb669b | 287 | /* Packet size is 64 bytes until a switch to high speed happens.*/ |
0769c38d | 288 | cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40); |
81eb669b DC |
289 | |
290 | destroy: | |
0769c38d DC |
291 | cy_as_ll_destroy_request(dev_p, req_p); |
292 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b DC |
293 | |
294 | if (ret != CY_AS_ERROR_SUCCESS) | |
295 | cy_as_ll_register_request_callback(dev_p, | |
0769c38d | 296 | CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 297 | |
0769c38d | 298 | cy_as_device_clear_m_s_s_pending(dev_p); |
81eb669b | 299 | |
0769c38d | 300 | return ret; |
81eb669b DC |
301 | } |
302 | ||
303 | ||
304 | cy_as_return_status_t | |
305 | cy_as_mtp_start(cy_as_device_handle handle, | |
306 | cy_as_mtp_event_callback event_c_b, | |
307 | cy_as_function_callback cb, | |
308 | uint32_t client | |
309 | ) | |
310 | { | |
0769c38d DC |
311 | cy_as_ll_request_response *req_p, *reply_p; |
312 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
313 | cy_as_device *dev_p; | |
81eb669b | 314 | |
0769c38d | 315 | dev_p = (cy_as_device *)handle; |
81eb669b | 316 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 317 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
318 | |
319 | if (!cy_as_device_is_configured(dev_p)) | |
0769c38d | 320 | return CY_AS_ERROR_NOT_CONFIGURED; |
81eb669b DC |
321 | |
322 | if (!cy_as_device_is_firmware_loaded(dev_p)) | |
0769c38d | 323 | return CY_AS_ERROR_NO_FIRMWARE; |
81eb669b DC |
324 | |
325 | if (cy_as_device_is_in_suspend_mode(dev_p)) | |
0769c38d | 326 | return CY_AS_ERROR_IN_SUSPEND; |
81eb669b DC |
327 | |
328 | if (cy_as_device_is_in_callback(dev_p)) | |
0769c38d | 329 | return CY_AS_ERROR_INVALID_IN_CALLBACK; |
81eb669b DC |
330 | |
331 | if (cy_as_device_is_m_s_s_pending(dev_p)) | |
0769c38d | 332 | return CY_AS_ERROR_STARTSTOP_PENDING; |
81eb669b DC |
333 | |
334 | if (dev_p->storage_count == 0) | |
0769c38d | 335 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
336 | |
337 | if (dev_p->usb_count == 0) | |
0769c38d | 338 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
339 | |
340 | if (dev_p->is_mtp_firmware == 0) | |
0769c38d | 341 | return CY_AS_ERROR_NOT_SUPPORTED; |
81eb669b | 342 | |
0769c38d | 343 | cy_as_device_set_m_s_s_pending(dev_p); |
81eb669b DC |
344 | |
345 | if (dev_p->mtp_count == 0) { | |
346 | ||
0769c38d | 347 | dev_p->mtp_event_cb = event_c_b; |
81eb669b | 348 | /* |
25985edc | 349 | * we register here because the start request may cause |
81eb669b DC |
350 | * events to occur before the response to the start request. |
351 | */ | |
352 | cy_as_ll_register_request_callback(dev_p, | |
0769c38d | 353 | CY_RQT_TUR_RQT_CONTEXT, my_mtp_request_callback); |
81eb669b DC |
354 | |
355 | /* Create the request to send to the West Bridge device */ | |
356 | req_p = cy_as_ll_create_request(dev_p, | |
0769c38d | 357 | CY_RQT_START_MTP, CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 358 | if (req_p == 0) { |
0769c38d DC |
359 | cy_as_device_clear_m_s_s_pending(dev_p); |
360 | return CY_AS_ERROR_OUT_OF_MEMORY; | |
81eb669b DC |
361 | } |
362 | ||
363 | /* Reserve space for the reply, the reply data will | |
364 | * not exceed one word */ | |
0769c38d | 365 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 366 | if (reply_p == 0) { |
0769c38d DC |
367 | cy_as_ll_destroy_request(dev_p, req_p); |
368 | cy_as_device_clear_m_s_s_pending(dev_p); | |
369 | return CY_AS_ERROR_OUT_OF_MEMORY; | |
81eb669b DC |
370 | } |
371 | ||
372 | if (cb == 0) { | |
373 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 374 | req_p, reply_p); |
81eb669b | 375 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 376 | goto destroy; |
81eb669b DC |
377 | |
378 | return my_handle_response_mtp_start(dev_p, req_p, | |
0769c38d | 379 | reply_p, ret); |
81eb669b DC |
380 | } else { |
381 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
382 | CY_FUNCT_CB_MTP_START, 0, dev_p->func_cbs_mtp, | |
383 | CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, | |
0769c38d | 384 | cy_as_mtp_func_callback); |
81eb669b DC |
385 | |
386 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 387 | goto destroy; |
81eb669b | 388 | |
0769c38d | 389 | return ret; |
81eb669b DC |
390 | } |
391 | ||
392 | destroy: | |
0769c38d DC |
393 | cy_as_ll_destroy_request(dev_p, req_p); |
394 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 395 | } else { |
0769c38d | 396 | dev_p->mtp_count++; |
81eb669b | 397 | if (cb) |
0769c38d | 398 | cb(handle, ret, client, CY_FUNCT_CB_MTP_START, 0); |
81eb669b DC |
399 | } |
400 | ||
0769c38d | 401 | cy_as_device_clear_m_s_s_pending(dev_p); |
81eb669b | 402 | |
0769c38d | 403 | return ret; |
81eb669b | 404 | } |
af109f2e | 405 | EXPORT_SYMBOL(cy_as_mtp_start); |
81eb669b DC |
406 | |
407 | static cy_as_return_status_t | |
408 | my_handle_response_mtp_stop(cy_as_device *dev_p, | |
409 | cy_as_ll_request_response *req_p, | |
410 | cy_as_ll_request_response *reply_p, | |
411 | cy_as_return_status_t ret) | |
412 | { | |
413 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 414 | goto destroy; |
81eb669b DC |
415 | |
416 | if (cy_as_ll_request_response__get_code(reply_p) != | |
417 | CY_RESP_SUCCESS_FAILURE) { | |
0769c38d DC |
418 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
419 | goto destroy; | |
81eb669b DC |
420 | } |
421 | ||
0769c38d | 422 | ret = cy_as_ll_request_response__get_word(reply_p, 0); |
81eb669b | 423 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 424 | goto destroy; |
81eb669b DC |
425 | |
426 | /* | |
25985edc | 427 | * we successfully shutdown the stack, so decrement |
81eb669b DC |
428 | * to make the count zero. |
429 | */ | |
0769c38d | 430 | dev_p->mtp_count--; |
81eb669b DC |
431 | |
432 | destroy: | |
0769c38d DC |
433 | cy_as_ll_destroy_request(dev_p, req_p); |
434 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b DC |
435 | |
436 | if (ret != CY_AS_ERROR_SUCCESS) | |
437 | cy_as_ll_register_request_callback(dev_p, | |
0769c38d | 438 | CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 439 | |
0769c38d | 440 | cy_as_device_clear_m_s_s_pending(dev_p); |
81eb669b | 441 | |
0769c38d | 442 | return ret; |
81eb669b DC |
443 | } |
444 | ||
445 | cy_as_return_status_t | |
446 | cy_as_mtp_stop(cy_as_device_handle handle, | |
447 | cy_as_function_callback cb, | |
448 | uint32_t client | |
449 | ) | |
450 | { | |
0769c38d DC |
451 | cy_as_ll_request_response *req_p = 0, *reply_p = 0; |
452 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
81eb669b | 453 | |
0769c38d | 454 | cy_as_device *dev_p; |
81eb669b | 455 | |
0769c38d | 456 | cy_as_log_debug_message(6, "cy_as_mtp_stop called"); |
81eb669b | 457 | |
0769c38d | 458 | dev_p = (cy_as_device *)handle; |
81eb669b | 459 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 460 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b | 461 | |
0769c38d | 462 | ret = is_mtp_active(dev_p); |
81eb669b | 463 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 464 | return ret; |
81eb669b DC |
465 | |
466 | if (cy_as_device_is_in_callback(dev_p)) | |
0769c38d | 467 | return CY_AS_ERROR_INVALID_IN_CALLBACK; |
81eb669b DC |
468 | |
469 | if (cy_as_device_is_m_s_s_pending(dev_p)) | |
0769c38d | 470 | return CY_AS_ERROR_STARTSTOP_PENDING; |
81eb669b | 471 | |
0769c38d | 472 | cy_as_device_set_m_s_s_pending(dev_p); |
81eb669b DC |
473 | |
474 | if (dev_p->mtp_count == 1) { | |
475 | /* Create the request to send to the West | |
476 | * Bridge device */ | |
477 | req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_MTP, | |
0769c38d | 478 | CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 479 | if (req_p == 0) { |
0769c38d DC |
480 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
481 | goto destroy; | |
81eb669b DC |
482 | } |
483 | ||
484 | /* Reserve space for the reply, the reply data will | |
485 | * not exceed one word */ | |
0769c38d | 486 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 487 | if (reply_p == 0) { |
0769c38d DC |
488 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
489 | goto destroy; | |
81eb669b DC |
490 | } |
491 | ||
492 | if (cb == 0) { | |
493 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 494 | req_p, reply_p); |
81eb669b | 495 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 496 | goto destroy; |
81eb669b DC |
497 | |
498 | return my_handle_response_mtp_stop(dev_p, req_p, | |
0769c38d | 499 | reply_p, ret); |
81eb669b DC |
500 | } else { |
501 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
502 | CY_FUNCT_CB_MTP_STOP, 0, dev_p->func_cbs_mtp, | |
503 | CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, | |
0769c38d | 504 | cy_as_mtp_func_callback); |
81eb669b DC |
505 | |
506 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 507 | goto destroy; |
81eb669b | 508 | |
0769c38d | 509 | return ret; |
81eb669b DC |
510 | } |
511 | ||
512 | destroy: | |
0769c38d DC |
513 | cy_as_ll_destroy_request(dev_p, req_p); |
514 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b DC |
515 | } else if (dev_p->mtp_count > 1) { |
516 | ||
0769c38d | 517 | dev_p->mtp_count--; |
81eb669b DC |
518 | |
519 | if (cb) | |
0769c38d | 520 | cb(handle, ret, client, CY_FUNCT_CB_MTP_STOP, 0); |
81eb669b DC |
521 | } |
522 | ||
0769c38d | 523 | cy_as_device_clear_m_s_s_pending(dev_p); |
81eb669b | 524 | |
0769c38d | 525 | return ret; |
81eb669b DC |
526 | } |
527 | ||
528 | static void | |
529 | mtp_write_callback( | |
530 | cy_as_device *dev_p, | |
531 | uint8_t context, | |
532 | cy_as_ll_request_response *rqt, | |
533 | cy_as_ll_request_response *resp, | |
534 | cy_as_return_status_t ret) | |
535 | { | |
0769c38d | 536 | cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT); |
81eb669b DC |
537 | |
538 | if (ret == CY_AS_ERROR_SUCCESS) { | |
539 | if (cy_as_ll_request_response__get_code(resp) != | |
540 | CY_RESP_SUCCESS_FAILURE) | |
0769c38d | 541 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
81eb669b | 542 | else |
0769c38d | 543 | ret = cy_as_ll_request_response__get_word(resp, 0); |
81eb669b DC |
544 | } |
545 | ||
546 | if (ret != CY_AS_ERROR_SUCCESS) { | |
547 | /* Firmware failed the request. Cancel the DMA transfer. */ | |
0769c38d DC |
548 | cy_as_dma_cancel(dev_p, 0x04, CY_AS_ERROR_CANCELED); |
549 | cy_as_device_clear_storage_async_pending(dev_p); | |
81eb669b DC |
550 | } |
551 | ||
0769c38d DC |
552 | cy_as_ll_destroy_response(dev_p, resp); |
553 | cy_as_ll_destroy_request(dev_p, rqt); | |
81eb669b DC |
554 | } |
555 | ||
556 | static void | |
557 | async_write_request_callback(cy_as_device *dev_p, | |
558 | cy_as_end_point_number_t ep, void *buf_p, uint32_t size, | |
559 | cy_as_return_status_t err) | |
560 | { | |
0769c38d DC |
561 | cy_as_device_handle h; |
562 | cy_as_function_callback cb; | |
81eb669b | 563 | |
0769c38d DC |
564 | (void)size; |
565 | (void)buf_p; | |
566 | (void)ep; | |
81eb669b DC |
567 | |
568 | ||
0769c38d | 569 | cy_as_log_debug_message(6, "async_write_request_callback called"); |
81eb669b | 570 | |
0769c38d | 571 | h = (cy_as_device_handle)dev_p; |
81eb669b | 572 | |
0769c38d DC |
573 | cb = dev_p->mtp_cb; |
574 | dev_p->mtp_cb = 0; | |
81eb669b | 575 | |
0769c38d | 576 | cy_as_device_clear_storage_async_pending(dev_p); |
81eb669b DC |
577 | |
578 | if (cb) | |
0769c38d | 579 | cb(h, err, dev_p->mtp_client, dev_p->mtp_op, 0); |
81eb669b DC |
580 | |
581 | } | |
582 | ||
583 | static void | |
584 | sync_mtp_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep, | |
585 | void *buf_p, uint32_t size, cy_as_return_status_t err) | |
586 | { | |
0769c38d DC |
587 | (void)ep; |
588 | (void)buf_p; | |
589 | (void)size; | |
81eb669b | 590 | |
0769c38d | 591 | dev_p->mtp_error = err; |
81eb669b DC |
592 | } |
593 | ||
594 | static cy_as_return_status_t | |
595 | cy_as_mtp_operation(cy_as_device *dev_p, | |
596 | cy_as_mtp_block_table *blk_table, | |
597 | uint32_t num_bytes, | |
598 | uint32_t transaction_id, | |
599 | cy_as_function_callback cb, | |
600 | uint32_t client, | |
601 | uint8_t rqttype | |
602 | ) | |
603 | { | |
0769c38d DC |
604 | cy_as_ll_request_response *req_p = 0, *reply_p = 0; |
605 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
606 | uint32_t mask = 0; | |
607 | cy_as_funct_c_b_type mtp_cb_op = 0; | |
608 | uint16_t size = 2; | |
81eb669b DC |
609 | |
610 | if (dev_p->mtp_count == 0) | |
0769c38d | 611 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
612 | |
613 | if (rqttype == CY_RQT_INIT_SEND_OBJECT) { | |
0769c38d DC |
614 | mtp_cb_op = CY_FUNCT_CB_MTP_INIT_SEND_OBJECT; |
615 | dev_p->mtp_turbo_active = cy_true; | |
81eb669b | 616 | } else if (rqttype == CY_RQT_INIT_GET_OBJECT) { |
0769c38d DC |
617 | mtp_cb_op = CY_FUNCT_CB_MTP_INIT_GET_OBJECT; |
618 | dev_p->mtp_turbo_active = cy_true; | |
81eb669b | 619 | } else |
0769c38d | 620 | mtp_cb_op = CY_FUNCT_CB_MTP_SEND_BLOCK_TABLE; |
81eb669b | 621 | |
0769c38d | 622 | ret = is_mtp_active(dev_p); |
81eb669b | 623 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 624 | return ret; |
81eb669b DC |
625 | |
626 | if (CY_RQT_INIT_GET_OBJECT == rqttype) | |
0769c38d | 627 | size = 4; |
81eb669b DC |
628 | |
629 | /* Create the request to send to the West | |
630 | * Bridge device */ | |
631 | req_p = cy_as_ll_create_request(dev_p, rqttype, | |
0769c38d | 632 | CY_RQT_TUR_RQT_CONTEXT, size); |
81eb669b | 633 | if (req_p == 0) { |
0769c38d DC |
634 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
635 | goto destroy; | |
81eb669b DC |
636 | } |
637 | ||
638 | /* Reserve space for the reply, the reply data will | |
639 | * not exceed one word */ | |
0769c38d | 640 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 641 | if (reply_p == 0) { |
0769c38d DC |
642 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
643 | goto destroy; | |
81eb669b DC |
644 | } |
645 | ||
646 | cy_as_ll_request_response__set_word(req_p, 0, | |
0769c38d | 647 | (uint16_t)(num_bytes & 0xFFFF)); |
81eb669b | 648 | cy_as_ll_request_response__set_word(req_p, 1, |
0769c38d | 649 | (uint16_t)((num_bytes >> 16) & 0xFFFF)); |
81eb669b DC |
650 | |
651 | /* If it is GET_OBJECT, send transaction id as well*/ | |
652 | if (CY_RQT_INIT_GET_OBJECT == rqttype) { | |
653 | cy_as_ll_request_response__set_word(req_p, 2, | |
0769c38d | 654 | (uint16_t)(transaction_id & 0xFFFF)); |
81eb669b | 655 | cy_as_ll_request_response__set_word(req_p, 3, |
0769c38d | 656 | (uint16_t)((transaction_id >> 16) & 0xFFFF)); |
81eb669b DC |
657 | } |
658 | ||
659 | if (cb == 0) { | |
660 | /* Queue the DMA request for block table write */ | |
661 | ret = cy_as_dma_queue_request(dev_p, 4, blk_table, | |
662 | sizeof(cy_as_mtp_block_table), cy_false, | |
0769c38d | 663 | cy_false, sync_mtp_callback); |
81eb669b DC |
664 | |
665 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 666 | req_p, reply_p); |
81eb669b | 667 | if (ret != CY_AS_ERROR_SUCCESS) { |
0769c38d DC |
668 | cy_as_dma_cancel(dev_p, 4, CY_AS_ERROR_CANCELED); |
669 | cy_as_device_clear_storage_async_pending(dev_p); | |
81eb669b | 670 | |
0769c38d | 671 | goto destroy; |
81eb669b DC |
672 | } |
673 | ||
0769c38d | 674 | ret = cy_as_dma_drain_queue(dev_p, 4, cy_true); |
81eb669b | 675 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 676 | goto destroy; |
81eb669b | 677 | |
0769c38d DC |
678 | ret = dev_p->mtp_error; |
679 | goto destroy; | |
81eb669b DC |
680 | } else { |
681 | #if 0 | |
682 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
683 | CY_FUNCT_CB_MTP_INIT_SEND_OBJECT, | |
684 | 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, | |
0769c38d | 685 | req_p, reply_p, cy_as_mtp_func_callback); |
81eb669b DC |
686 | |
687 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 688 | goto destroy; |
81eb669b DC |
689 | #endif |
690 | ||
691 | /* Protection from interrupt driven code */ | |
692 | /* since we are using storage EP4 check if any | |
693 | * storage activity is pending */ | |
0769c38d | 694 | mask = cy_as_hal_disable_interrupts(); |
81eb669b DC |
695 | if ((cy_as_device_is_storage_async_pending(dev_p)) || |
696 | (dev_p->storage_wait)) { | |
0769c38d DC |
697 | cy_as_hal_enable_interrupts(mask); |
698 | return CY_AS_ERROR_ASYNC_PENDING; | |
81eb669b | 699 | } |
0769c38d DC |
700 | cy_as_device_set_storage_async_pending(dev_p); |
701 | cy_as_hal_enable_interrupts(mask); | |
81eb669b | 702 | |
0769c38d DC |
703 | dev_p->mtp_cb = cb; |
704 | dev_p->mtp_client = client; | |
705 | dev_p->mtp_op = mtp_cb_op; | |
81eb669b DC |
706 | |
707 | ret = cy_as_ll_send_request(dev_p, req_p, reply_p, | |
0769c38d | 708 | cy_false, mtp_write_callback); |
81eb669b | 709 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 710 | goto destroy; |
81eb669b DC |
711 | |
712 | ret = cy_as_dma_queue_request(dev_p, 4, blk_table, | |
713 | sizeof(cy_as_mtp_block_table), cy_false, cy_false, | |
0769c38d | 714 | async_write_request_callback); |
81eb669b | 715 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 716 | return ret; |
81eb669b DC |
717 | |
718 | /* Kick start the queue if it is not running */ | |
0769c38d | 719 | cy_as_dma_kick_start(dev_p, 4); |
81eb669b | 720 | |
0769c38d | 721 | return CY_AS_ERROR_SUCCESS; |
81eb669b DC |
722 | } |
723 | ||
724 | destroy: | |
0769c38d DC |
725 | cy_as_ll_destroy_request(dev_p, req_p); |
726 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 727 | |
0769c38d | 728 | return ret; |
81eb669b DC |
729 | } |
730 | ||
731 | cy_as_return_status_t | |
732 | cy_as_mtp_init_send_object(cy_as_device_handle handle, | |
733 | cy_as_mtp_block_table *blk_table, | |
734 | uint32_t num_bytes, | |
735 | cy_as_function_callback cb, | |
736 | uint32_t client | |
737 | ) | |
738 | { | |
0769c38d DC |
739 | cy_as_device *dev_p; |
740 | dev_p = (cy_as_device *)handle; | |
81eb669b | 741 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 742 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
743 | |
744 | return cy_as_mtp_operation(dev_p, blk_table, num_bytes, 0, cb, | |
0769c38d | 745 | client, CY_RQT_INIT_SEND_OBJECT); |
81eb669b DC |
746 | |
747 | } | |
af109f2e | 748 | EXPORT_SYMBOL(cy_as_mtp_init_send_object); |
81eb669b DC |
749 | |
750 | cy_as_return_status_t | |
751 | cy_as_mtp_init_get_object(cy_as_device_handle handle, | |
752 | cy_as_mtp_block_table *blk_table, | |
753 | uint32_t num_bytes, | |
754 | uint32_t transaction_id, | |
755 | cy_as_function_callback cb, | |
756 | uint32_t client | |
757 | ) | |
758 | { | |
0769c38d DC |
759 | cy_as_device *dev_p; |
760 | dev_p = (cy_as_device *)handle; | |
81eb669b | 761 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 762 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
763 | |
764 | return cy_as_mtp_operation(dev_p, blk_table, num_bytes, | |
0769c38d | 765 | transaction_id, cb, client, CY_RQT_INIT_GET_OBJECT); |
81eb669b DC |
766 | |
767 | } | |
af109f2e | 768 | EXPORT_SYMBOL(cy_as_mtp_init_get_object); |
81eb669b DC |
769 | |
770 | static cy_as_return_status_t | |
771 | my_handle_response_cancel_send_object(cy_as_device *dev_p, | |
772 | cy_as_ll_request_response *req_p, | |
773 | cy_as_ll_request_response *reply_p, | |
774 | cy_as_return_status_t ret) | |
775 | { | |
776 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 777 | goto destroy; |
81eb669b DC |
778 | |
779 | if (cy_as_ll_request_response__get_code(reply_p) != | |
780 | CY_RESP_SUCCESS_FAILURE) { | |
0769c38d DC |
781 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
782 | goto destroy; | |
81eb669b DC |
783 | } |
784 | ||
0769c38d | 785 | ret = cy_as_ll_request_response__get_word(reply_p, 0); |
81eb669b | 786 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 787 | goto destroy; |
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 | |
0769c38d | 794 | return ret; |
81eb669b DC |
795 | } |
796 | ||
797 | cy_as_return_status_t | |
798 | cy_as_mtp_cancel_send_object(cy_as_device_handle handle, | |
799 | cy_as_function_callback cb, | |
800 | uint32_t client | |
801 | ) | |
802 | { | |
0769c38d DC |
803 | cy_as_ll_request_response *req_p = 0, *reply_p = 0; |
804 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
805 | cy_as_device *dev_p; | |
81eb669b | 806 | |
0769c38d | 807 | dev_p = (cy_as_device *)handle; |
81eb669b | 808 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 809 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
810 | |
811 | if (dev_p->mtp_count == 0) | |
0769c38d | 812 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
813 | |
814 | /* Create the request to send to the West Bridge device */ | |
815 | req_p = cy_as_ll_create_request(dev_p, | |
0769c38d | 816 | CY_RQT_CANCEL_SEND_OBJECT, CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 817 | if (req_p == 0) { |
0769c38d DC |
818 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
819 | goto destroy; | |
81eb669b DC |
820 | } |
821 | ||
822 | /* Reserve space for the reply, the reply data will | |
823 | * not exceed one word */ | |
0769c38d | 824 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 825 | if (reply_p == 0) { |
0769c38d DC |
826 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
827 | goto destroy; | |
81eb669b DC |
828 | } |
829 | ||
830 | if (cb == 0) { | |
831 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 832 | req_p, reply_p); |
81eb669b | 833 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 834 | goto destroy; |
81eb669b DC |
835 | |
836 | return my_handle_response_cancel_send_object(dev_p, | |
0769c38d | 837 | req_p, reply_p, ret); |
81eb669b DC |
838 | } else { |
839 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
840 | CY_FUNCT_CB_MTP_CANCEL_SEND_OBJECT, 0, | |
841 | dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, | |
0769c38d | 842 | req_p, reply_p, cy_as_mtp_func_callback); |
81eb669b DC |
843 | |
844 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 845 | goto destroy; |
81eb669b | 846 | |
0769c38d | 847 | return ret; |
81eb669b DC |
848 | } |
849 | ||
850 | destroy: | |
0769c38d DC |
851 | cy_as_ll_destroy_request(dev_p, req_p); |
852 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 853 | |
0769c38d | 854 | return ret; |
81eb669b | 855 | } |
af109f2e | 856 | EXPORT_SYMBOL(cy_as_mtp_cancel_send_object); |
81eb669b DC |
857 | |
858 | static cy_as_return_status_t | |
859 | my_handle_response_cancel_get_object(cy_as_device *dev_p, | |
860 | cy_as_ll_request_response *req_p, | |
861 | cy_as_ll_request_response *reply_p, | |
862 | cy_as_return_status_t ret) | |
863 | { | |
864 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 865 | goto destroy; |
81eb669b DC |
866 | |
867 | if (cy_as_ll_request_response__get_code(reply_p) != | |
868 | CY_RESP_SUCCESS_FAILURE) { | |
0769c38d DC |
869 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
870 | goto destroy; | |
81eb669b DC |
871 | } |
872 | ||
0769c38d | 873 | ret = cy_as_ll_request_response__get_word(reply_p, 0); |
81eb669b | 874 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 875 | goto destroy; |
81eb669b DC |
876 | |
877 | ||
878 | destroy: | |
0769c38d DC |
879 | cy_as_ll_destroy_request(dev_p, req_p); |
880 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 881 | |
0769c38d | 882 | return ret; |
81eb669b DC |
883 | } |
884 | ||
885 | cy_as_return_status_t | |
886 | cy_as_mtp_cancel_get_object(cy_as_device_handle handle, | |
887 | cy_as_function_callback cb, | |
888 | uint32_t client | |
889 | ) | |
890 | { | |
0769c38d DC |
891 | cy_as_ll_request_response *req_p = 0, *reply_p = 0; |
892 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
893 | cy_as_device *dev_p; | |
81eb669b | 894 | |
0769c38d | 895 | dev_p = (cy_as_device *)handle; |
81eb669b | 896 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 897 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
898 | |
899 | if (dev_p->mtp_count == 0) | |
0769c38d | 900 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
901 | |
902 | /* Create the request to send to the West Bridge device */ | |
903 | req_p = cy_as_ll_create_request(dev_p, CY_RQT_CANCEL_GET_OBJECT, | |
0769c38d | 904 | CY_RQT_TUR_RQT_CONTEXT, 0); |
81eb669b | 905 | if (req_p == 0) { |
0769c38d DC |
906 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
907 | goto destroy; | |
81eb669b DC |
908 | } |
909 | ||
910 | /* Reserve space for the reply, the reply data will | |
911 | * not exceed one word */ | |
0769c38d | 912 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 913 | if (reply_p == 0) { |
0769c38d DC |
914 | ret = CY_AS_ERROR_OUT_OF_MEMORY; |
915 | goto destroy; | |
81eb669b DC |
916 | } |
917 | ||
918 | if (cb == 0) { | |
919 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 920 | req_p, reply_p); |
81eb669b | 921 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 922 | goto destroy; |
81eb669b DC |
923 | |
924 | return my_handle_response_cancel_get_object(dev_p, | |
0769c38d | 925 | req_p, reply_p, ret); |
81eb669b DC |
926 | } else { |
927 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
928 | CY_FUNCT_CB_MTP_CANCEL_GET_OBJECT, 0, | |
929 | dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, | |
0769c38d | 930 | req_p, reply_p, cy_as_mtp_func_callback); |
81eb669b DC |
931 | |
932 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 933 | goto destroy; |
81eb669b | 934 | |
0769c38d | 935 | return ret; |
81eb669b DC |
936 | } |
937 | ||
938 | destroy: | |
0769c38d DC |
939 | cy_as_ll_destroy_request(dev_p, req_p); |
940 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 941 | |
0769c38d | 942 | return ret; |
81eb669b | 943 | } |
af109f2e | 944 | EXPORT_SYMBOL(cy_as_mtp_cancel_get_object); |
81eb669b DC |
945 | |
946 | cy_as_return_status_t | |
947 | cy_as_mtp_send_block_table(cy_as_device_handle handle, | |
948 | cy_as_mtp_block_table *blk_table, | |
949 | cy_as_function_callback cb, | |
950 | uint32_t client) | |
951 | { | |
0769c38d DC |
952 | cy_as_device *dev_p; |
953 | dev_p = (cy_as_device *)handle; | |
81eb669b | 954 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 955 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
956 | |
957 | return cy_as_mtp_operation(dev_p, blk_table, 0, 0, cb, | |
0769c38d | 958 | client, CY_RQT_SEND_BLOCK_TABLE); |
81eb669b DC |
959 | } |
960 | ||
961 | static void | |
962 | cy_as_mtp_func_callback(cy_as_device *dev_p, | |
963 | uint8_t context, | |
964 | cy_as_ll_request_response *rqt, | |
965 | cy_as_ll_request_response *resp, | |
966 | cy_as_return_status_t stat) | |
967 | { | |
968 | cy_as_func_c_b_node* node = (cy_as_func_c_b_node *) | |
0769c38d DC |
969 | dev_p->func_cbs_mtp->head_p; |
970 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
971 | uint8_t code; | |
972 | cy_bool delay_callback = cy_false; | |
81eb669b | 973 | |
0769c38d DC |
974 | cy_as_hal_assert(dev_p->func_cbs_mtp->count != 0); |
975 | cy_as_hal_assert(dev_p->func_cbs_mtp->type == CYAS_FUNC_CB); | |
81eb669b | 976 | |
0769c38d | 977 | (void)context; |
81eb669b DC |
978 | |
979 | /* The Handlers are responsible for Deleting the | |
980 | * rqt and resp when they are finished | |
981 | */ | |
0769c38d | 982 | code = cy_as_ll_request_response__get_code(rqt); |
81eb669b DC |
983 | switch (code) { |
984 | case CY_RQT_START_MTP: | |
985 | ret = my_handle_response_mtp_start(dev_p, rqt, | |
0769c38d DC |
986 | resp, stat); |
987 | break; | |
81eb669b DC |
988 | case CY_RQT_STOP_MTP: |
989 | ret = my_handle_response_mtp_stop(dev_p, rqt, | |
0769c38d DC |
990 | resp, stat); |
991 | break; | |
81eb669b DC |
992 | #if 0 |
993 | case CY_RQT_INIT_SEND_OBJECT: | |
994 | ret = my_handle_response_init_send_object(dev_p, | |
0769c38d DC |
995 | rqt, resp, stat, cy_true); |
996 | delay_callback = cy_true; | |
997 | break; | |
81eb669b DC |
998 | #endif |
999 | case CY_RQT_CANCEL_SEND_OBJECT: | |
1000 | ret = my_handle_response_cancel_send_object(dev_p, | |
0769c38d DC |
1001 | rqt, resp, stat); |
1002 | break; | |
81eb669b DC |
1003 | #if 0 |
1004 | case CY_RQT_INIT_GET_OBJECT: | |
1005 | ret = my_handle_response_init_get_object(dev_p, | |
0769c38d DC |
1006 | rqt, resp, stat, cy_true); |
1007 | delay_callback = cy_true; | |
1008 | break; | |
81eb669b DC |
1009 | #endif |
1010 | case CY_RQT_CANCEL_GET_OBJECT: | |
1011 | ret = my_handle_response_cancel_get_object(dev_p, | |
0769c38d DC |
1012 | rqt, resp, stat); |
1013 | break; | |
81eb669b DC |
1014 | #if 0 |
1015 | case CY_RQT_SEND_BLOCK_TABLE: | |
1016 | ret = my_handle_response_send_block_table(dev_p, rqt, | |
0769c38d DC |
1017 | resp, stat, cy_true); |
1018 | delay_callback = cy_true; | |
1019 | break; | |
81eb669b DC |
1020 | #endif |
1021 | case CY_RQT_ENABLE_USB_PATH: | |
0769c38d | 1022 | ret = my_handle_response_no_data(dev_p, rqt, resp); |
81eb669b | 1023 | if (ret == CY_AS_ERROR_SUCCESS) |
0769c38d DC |
1024 | dev_p->is_storage_only_mode = cy_false; |
1025 | break; | |
81eb669b | 1026 | default: |
0769c38d DC |
1027 | ret = CY_AS_ERROR_INVALID_RESPONSE; |
1028 | cy_as_hal_assert(cy_false); | |
1029 | break; | |
81eb669b DC |
1030 | } |
1031 | ||
1032 | /* | |
1033 | * if the low level layer returns a direct error, use the | |
1034 | * corresponding error code. if not, use the error code | |
1035 | * based on the response from firmware. | |
1036 | */ | |
1037 | if (stat == CY_AS_ERROR_SUCCESS) | |
0769c38d | 1038 | stat = ret; |
81eb669b DC |
1039 | |
1040 | if (!delay_callback) { | |
1041 | node->cb_p((cy_as_device_handle)dev_p, stat, node->client_data, | |
0769c38d DC |
1042 | node->data_type, node->data); |
1043 | cy_as_remove_c_b_node(dev_p->func_cbs_mtp); | |
81eb669b DC |
1044 | } |
1045 | } | |
1046 | ||
1047 | cy_as_return_status_t | |
1048 | cy_as_mtp_storage_only_start(cy_as_device_handle handle) | |
1049 | { | |
0769c38d | 1050 | cy_as_device *dev_p = (cy_as_device *)handle; |
81eb669b | 1051 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) |
0769c38d | 1052 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
1053 | |
1054 | if (!cy_as_device_is_configured(dev_p)) | |
0769c38d | 1055 | return CY_AS_ERROR_NOT_CONFIGURED; |
81eb669b DC |
1056 | |
1057 | if (!cy_as_device_is_firmware_loaded(dev_p)) | |
0769c38d | 1058 | return CY_AS_ERROR_NO_FIRMWARE; |
81eb669b DC |
1059 | |
1060 | if (dev_p->storage_count == 0) | |
0769c38d | 1061 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b | 1062 | |
0769c38d DC |
1063 | dev_p->is_storage_only_mode = cy_true; |
1064 | return CY_AS_ERROR_SUCCESS; | |
81eb669b | 1065 | } |
af109f2e | 1066 | EXPORT_SYMBOL(cy_as_mtp_storage_only_start); |
81eb669b DC |
1067 | |
1068 | cy_as_return_status_t | |
1069 | cy_as_mtp_storage_only_stop(cy_as_device_handle handle, | |
1070 | cy_as_function_callback cb, | |
1071 | uint32_t client) | |
1072 | { | |
0769c38d DC |
1073 | cy_as_device *dev_p = (cy_as_device *)handle; |
1074 | cy_as_ll_request_response *req_p, *reply_p; | |
1075 | cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; | |
81eb669b DC |
1076 | |
1077 | if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) | |
0769c38d | 1078 | return CY_AS_ERROR_INVALID_HANDLE; |
81eb669b DC |
1079 | |
1080 | if (!cy_as_device_is_configured(dev_p)) | |
0769c38d | 1081 | return CY_AS_ERROR_NOT_CONFIGURED; |
81eb669b DC |
1082 | |
1083 | if (!cy_as_device_is_firmware_loaded(dev_p)) | |
0769c38d | 1084 | return CY_AS_ERROR_NO_FIRMWARE; |
81eb669b DC |
1085 | |
1086 | if (dev_p->storage_count == 0) | |
0769c38d | 1087 | return CY_AS_ERROR_NOT_RUNNING; |
81eb669b DC |
1088 | |
1089 | if (dev_p->is_storage_only_mode == cy_false) | |
0769c38d | 1090 | return CY_AS_ERROR_SUCCESS; |
81eb669b DC |
1091 | |
1092 | if (cy_as_device_is_in_callback(dev_p)) | |
0769c38d | 1093 | return CY_AS_ERROR_INVALID_IN_CALLBACK; |
81eb669b DC |
1094 | |
1095 | req_p = cy_as_ll_create_request(dev_p, | |
0769c38d | 1096 | CY_RQT_ENABLE_USB_PATH, CY_RQT_TUR_RQT_CONTEXT, 1); |
81eb669b | 1097 | if (req_p == 0) |
0769c38d | 1098 | return CY_AS_ERROR_OUT_OF_MEMORY; |
81eb669b | 1099 | |
0769c38d | 1100 | reply_p = cy_as_ll_create_response(dev_p, 1); |
81eb669b | 1101 | if (reply_p == 0) { |
0769c38d DC |
1102 | cy_as_ll_destroy_request(dev_p, req_p); |
1103 | return CY_AS_ERROR_OUT_OF_MEMORY; | |
81eb669b DC |
1104 | } |
1105 | ||
1106 | if (cb == 0) { | |
1107 | ret = cy_as_ll_send_request_wait_reply(dev_p, | |
0769c38d | 1108 | req_p, reply_p); |
81eb669b | 1109 | if (ret != CY_AS_ERROR_SUCCESS) |
0769c38d | 1110 | goto destroy; |
81eb669b DC |
1111 | |
1112 | ret = my_handle_response_no_data(dev_p, req_p, | |
0769c38d | 1113 | reply_p); |
81eb669b | 1114 | if (ret == CY_AS_ERROR_SUCCESS) |
0769c38d DC |
1115 | dev_p->is_storage_only_mode = cy_false; |
1116 | return ret; | |
81eb669b DC |
1117 | } else { |
1118 | ret = cy_as_misc_send_request(dev_p, cb, client, | |
1119 | CY_FUNCT_CB_MTP_STOP_STORAGE_ONLY, 0, | |
1120 | dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, | |
0769c38d | 1121 | req_p, reply_p, cy_as_mtp_func_callback); |
81eb669b DC |
1122 | |
1123 | if (ret != CY_AS_ERROR_SUCCESS) | |
0769c38d | 1124 | goto destroy; |
81eb669b | 1125 | |
0769c38d | 1126 | return ret; |
81eb669b DC |
1127 | } |
1128 | ||
1129 | destroy: | |
0769c38d DC |
1130 | cy_as_ll_destroy_request(dev_p, req_p); |
1131 | cy_as_ll_destroy_response(dev_p, reply_p); | |
81eb669b | 1132 | |
0769c38d | 1133 | return ret; |
81eb669b | 1134 | } |
af109f2e SR |
1135 | EXPORT_SYMBOL(cy_as_mtp_storage_only_stop); |
1136 |