Contiki-NG
usb-msc-bulk.c
1#include "usb-msc-bulk.h"
2#include <usb-api.h>
3#include <usb-core.h>
4#include <sys/process.h>
5#include <stdio.h>
6#include <string.h>
7
8#define DEBUG
9
10#ifdef DEBUG
11#define PRINTF(...) printf(__VA_ARGS__)
12#else
13#define PRINTF(...)
14#endif
15
16static const uint8_t max_lun = 0;
17
18static USBBuffer data_usb_buffer[USB_MSC_BUFFERS];
19static unsigned int buffer_lengths[USB_MSC_BUFFERS];
20
21static unsigned int buf_first = 0; /* First prepared buffer */
22static unsigned int buf_free = 0; /* First free buffer */
23static unsigned int buf_submitted = 0; /* Oldest submitted buffer */
24
25#define USB_BUFFER_ID_UNUSED 0
26#define USB_BUFFER_ID_CBW 1
27#define USB_BUFFER_ID_CSW 2
28#define USB_BUFFER_ID_DATA 3
29#define USB_BUFFER_ID_DISCARD 4
30#define USB_BUFFER_ID_HALT 5
31#define USB_BUFFER_ID_MASK 0x07
32
33static struct usb_msc_bulk_cbw cbw_buffer;
34static struct usb_msc_bulk_csw csw_buffer;
35
36#define BULK_OUT 0x02
37#define BULK_IN 0x81
38
39PROCESS(usb_mass_bulk_process, "USB mass storage bulk only process");
40
41static process_event_t reset_event;
42
43static struct usb_msc_command_state state;
44
45/* Handle wrapping */
46#define PREV_BUF(x) (((x) == 0) ? USB_MSC_BUFFERS - 1 : (x) - 1)
47#define NEXT_BUF(x) (((x) < (USB_MSC_BUFFERS-1)) ? (x) + 1 : 0)
48void
49usb_msc_send_data_buf_flags(const uint8_t *data, unsigned int len,
50 unsigned int flags, uint16_t buf_flags)
51{
52 USBBuffer *buffer = &data_usb_buffer[buf_free];
53 if (buffer->id != USB_BUFFER_ID_UNUSED) {
54 printf("Data IN buffer busy\n");
55 return;
56 }
57 buffer->flags = USB_BUFFER_NOTIFY | buf_flags;
58 buffer->next = NULL;
59 buffer->data = (uint8_t*)data;
60 buffer->left = len;
61 buffer_lengths[buf_free] = len;
62 buffer->id = USB_BUFFER_ID_DATA | flags;
63 if (buf_free != buf_first) {
64 data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
65 }
66 state.cmd_data_submitted += len;
67 buf_free = NEXT_BUF(buf_free);
68 /* PRINTF("usb_msc_send_data: %d\n", len); */
69 if (flags & USB_MSC_DATA_SEND) {
70 usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]);
71 buf_first = buf_free;
72 /* PRINTF("usb_msc_send_data: sent\n"); */
73 } else if (flags & USB_MSC_DATA_LAST) {
74 /* Cancel transmission */
75 PRINTF("Send last\n");
76 buf_first = buf_free;
77 process_poll(&usb_mass_bulk_process);
78 }
79}
80
81void
82usb_msc_send_data(const uint8_t *data, unsigned int len, unsigned int flags)
83{
84 usb_msc_send_data_buf_flags(data, len, flags,0);
85}
86
87void
88usb_msc_receive_data_buf_flags(uint8_t *data, unsigned int len,
89 unsigned int flags, uint16_t buf_flags)
90{
91 USBBuffer *buffer = &data_usb_buffer[buf_free];
92 if (buffer->id != USB_BUFFER_ID_UNUSED) {
93 printf("Data OUT buffer busy\n");
94 return;
95 }
96 buffer->flags = USB_BUFFER_NOTIFY | buf_flags;
97 buffer->next = NULL;
98 buffer->data = data;
99 buffer->left = len;
100 buffer_lengths[buf_free] = len;
101 buffer->id = USB_BUFFER_ID_DATA | flags;
102 if (buf_free != buf_first) {
103 data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
104 }
105 state.cmd_data_submitted += len;
106 buf_free = NEXT_BUF(buf_free);
107 if (flags & USB_MSC_DATA_RECEIVE) {
108 usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]);
109 buf_first = buf_free;
110 } else if (flags & USB_MSC_DATA_LAST) {
111 usb_discard_all_buffers(BULK_OUT);
112 /* Mark the discarded buffers as unused */
113 while(buf_submitted != PREV_BUF(buf_free)) {
114 data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
115 buf_submitted = NEXT_BUF(buf_submitted);
116 }
117 buf_first = buf_free;
118 process_poll(&usb_mass_bulk_process);
119 }
120}
121
122void
123usb_msc_receive_data(uint8_t *data, unsigned int len, unsigned int flags)
124{
125 usb_msc_receive_data_buf_flags(data,len,flags, 0);
126}
127
128static unsigned int
129handle_mass_bulk_requests()
130{
131 switch(usb_setup_buffer.bmRequestType) {
132 case 0x21: /* interface OUT requests */
133 switch(usb_setup_buffer.bRequest) {
134 case MASS_BULK_RESET:
135 PRINTF("Mass storage reset\n");
136 process_post(&usb_mass_bulk_process, reset_event, NULL);
137 return 1;
138 }
139 break;
140 case 0xa1: /* interface IN requests */
141 switch(usb_setup_buffer.bRequest) {
142 case MASS_BULK_GET_MAX_LUN:
143 PRINTF("Get LUN\n");
144 usb_send_ctrl_response(&max_lun, sizeof(max_lun));
145 return 1;
146 }
147 break;
148 }
149 return 0;
150}
151
152static const struct USBRequestHandler mass_bulk_request_handler =
153 {
154 0x21, 0x7f,
155 0x00, 0x00,
156 handle_mass_bulk_requests
157 };
158
159static struct USBRequestHandlerHook mass_bulk_request_hook =
160 {
161 NULL,
162 &mass_bulk_request_handler
163 };
164
165static void
166send_csw(void)
167{
168 USBBuffer *buffer = &data_usb_buffer[buf_free];
169 if (buffer->id != USB_BUFFER_ID_UNUSED) {
170 printf("CSW buffer busy\n");
171 return;
172 }
173
174 csw_buffer.dCSWSignature = MASS_BULK_CSW_SIGNATURE;
175 csw_buffer.dCSWTag = cbw_buffer.dCBWTag;
176 csw_buffer.dCSWDataResidue =
177 cbw_buffer.dCBWDataTransferLength - state.cmd_data_submitted;
178 csw_buffer.bCSWStatus = state.status;
179
180 buffer->flags = USB_BUFFER_NOTIFY;
181 buffer->next = NULL;
182 buffer->data =(uint8_t*)&csw_buffer ;
183 buffer->left = sizeof(csw_buffer);
184 buffer->id = USB_BUFFER_ID_CSW;
185 if (buf_free != buf_first) {
186 data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
187 }
188 buf_free = NEXT_BUF(buf_free);
189 usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]);
190 buf_first = buf_free;
191
192 PRINTF("CSW sent: %ld\n", sizeof(csw_buffer));
193}
194
195static void
196submit_cbw_buffer(void)
197{
198 USBBuffer *buffer = &data_usb_buffer[buf_free];
199 if (buffer->id != USB_BUFFER_ID_UNUSED) {
200 printf("CBW buffer busy\n");
201 return;
202 }
203 buffer->flags = USB_BUFFER_NOTIFY;
204 buffer->next = NULL;
205 buffer->data = (uint8_t*)&cbw_buffer;
206 buffer->left = sizeof(cbw_buffer);
207 buffer->id = USB_BUFFER_ID_CBW;
208 if (buf_free != buf_first) {
209 data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
210 }
211 buf_free = NEXT_BUF(buf_free);
212 usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]);
213 PRINTF("CBW submitted: %d\n", buf_first);
214 buf_first = buf_free;
215}
216
217static void
218submit_halt(uint8_t addr)
219{
220 USBBuffer *buffer = &data_usb_buffer[buf_free];
221 if (buffer->id != USB_BUFFER_ID_UNUSED) {
222 printf("CBW buffer busy\n");
223 return;
224 }
225 buffer->flags = USB_BUFFER_NOTIFY | USB_BUFFER_HALT;
226 buffer->next = NULL;
227 buffer->data = NULL;
228 buffer->left = 0;
229 buffer->id = USB_BUFFER_ID_HALT;
230 if (buf_free != buf_first) {
231 data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
232 }
233 buf_free = NEXT_BUF(buf_free);
234 if (addr & 0x80) {
235 usb_submit_xmit_buffer(addr, &data_usb_buffer[buf_first]);
236 } else {
237 usb_submit_recv_buffer(addr, &data_usb_buffer[buf_first]);
238 }
239 PRINTF("HALT submitted %p\n",buffer);
240 buf_first = buf_free;
241}
242
243static USBBuffer *
244get_next_buffer(uint8_t addr, uint32_t id)
245{
246 unsigned int events;
247 events = usb_get_ep_events(addr);
248 if (events & USB_EP_EVENT_NOTIFICATION) {
249 USBBuffer *buffer = &data_usb_buffer[buf_submitted];
250 if (!(buffer->flags & USB_BUFFER_SUBMITTED)) {
251#ifdef DEBUG
252 if (id != (buffer->id & USB_BUFFER_ID_MASK)) {
253 printf("Wrong buffer ID expected %d, got %d\n",
254 (int)id, (int)buffer->id);
255 }
256#endif
257 if ((buffer->id & USB_BUFFER_ID_MASK) == USB_BUFFER_ID_DATA) {
258 state.cmd_data_transfered +=
259 buffer_lengths[buf_submitted] - buffer->left;
260 }
261 buffer->id = USB_BUFFER_ID_UNUSED;
262 buf_submitted =NEXT_BUF(buf_submitted);
263 return buffer;
264 }
265 }
266 return NULL;
267}
268
269PROCESS(usb_mass_bulk_request_process, "USB mass storage request process");
270
271PROCESS_THREAD(usb_mass_bulk_request_process, ev , data)
272{
274 reset_state:
275 usb_discard_all_buffers(BULK_OUT);
276 usb_discard_all_buffers(BULK_IN);
277 memset(data_usb_buffer, 0, sizeof(data_usb_buffer));
278 buf_first = 0;
279 buf_free = 0;
280 buf_submitted = 0;
281 submit_cbw_buffer();
282 receive_cbw_state:
283 PRINTF("receive_cbw_state\n");
284 while(1) {
286 if (ev == reset_event) goto reset_state;
287 if (ev == PROCESS_EVENT_POLL) {
288 USBBuffer *buffer;
289 if ((buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_CBW))) {
290
291 /* CBW */
292 if (cbw_buffer.dCBWSignature == MASS_BULK_CBW_SIGNATURE) {
293 usb_msc_handler_status ret;
294 PRINTF("Got CBW seq %d\n",(int)cbw_buffer.dCBWTag);
295 state.command = cbw_buffer.CBWCB;
296 state.command_length = cbw_buffer.bCBWCBLength;
297 state.status = MASS_BULK_CSW_STATUS_FAILED;
298 state.data_cb = NULL;
299 state.cmd_data_submitted = 0;
300 state.cmd_data_transfered = 0;
301 ret = usb_msc_handle_command(&state);
302 if (ret == USB_MSC_HANDLER_OK) {
303 state.status = MASS_BULK_CSW_STATUS_PASSED;
304 } else if (ret == USB_MSC_HANDLER_FAILED) {
305 state.status = MASS_BULK_CSW_STATUS_FAILED;
306 }
307 if (ret != USB_MSC_HANDLER_DELAYED
308 && buf_submitted == buf_free) {
309 if (cbw_buffer.dCBWDataTransferLength > 0) {
310 /* HALT the apropriate endpoint */
311 if (cbw_buffer.bmCBWFlags & MASS_BULK_CBW_FLAG_IN) {
312 submit_halt(BULK_IN);
313 } else {
314 submit_halt(BULK_OUT);
315 }
316 /* Wait for HALT */
317 while(1) {
319 if (ev == reset_event) goto reset_state;
320 if (ev == PROCESS_EVENT_POLL) {
321 USBBuffer *buffer =
322 get_next_buffer(BULK_IN, USB_BUFFER_ID_HALT);
323 if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
324 }
325 }
326 }
327 goto send_csw_state;
328 }
329 if (cbw_buffer.bmCBWFlags & MASS_BULK_CBW_FLAG_IN) {
330 goto send_data_state;
331 } else {
332 goto receive_data_state;
333 }
334 } else {
335 printf("Invalid CBW\n");
336 submit_halt(BULK_IN);
337 submit_halt(BULK_OUT);
338 while(1) {
340 if (ev == reset_event) goto reset_state;
341 if (ev == PROCESS_EVENT_POLL) {
342 USBBuffer *buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_HALT);
343 if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
344 }
345 }
346 while(1) {
348 if (ev == reset_event) goto reset_state;
349 if (ev == PROCESS_EVENT_POLL) {
350 USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT);
351 if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
352 }
353 }
354 /* CBW */
355 goto receive_cbw_state;
356 }
357 }
358 }
359 }
360
361 send_data_state:
362 PRINTF("send_data_state\n");
363 while(1) {
364 uint8_t id = 0;
365 /* Wait for any data to be sent */
366 while (buf_submitted == buf_free) {
367 PRINTF("Wait data\n");
369 }
370#if 0
371 /* Send CSW early to improve throughput, unless we need to HALT
372 the endpoint due to short data */
373 if ((data_usb_buffer[PREV_BUF(buf_free)].id & USB_MSC_DATA_LAST)
374 && state.cmd_data_submitted == cbw_buffer.dCBWDataTransferLength) {
375 send_csw();
376 }
377#endif
378 /* Wait until the current buffer is free */
379 while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) {
381 }
382 while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) {
383 id = data_usb_buffer[buf_submitted].id;
384 /* PRINTF("id: %02x\n", id); */
385 if (id == USB_BUFFER_ID_UNUSED) break;
386 state.cmd_data_transfered += buffer_lengths[buf_submitted];
387 data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
388 buf_submitted =NEXT_BUF(buf_submitted);
389 if (id & USB_MSC_DATA_DO_CALLBACK) {
390 if (state.data_cb) {
391 state.data_cb(&state);
392 }
393 }
394
395
396 if (id & USB_MSC_DATA_LAST) {
397 break;
398 }
399 }
400 if (id & USB_MSC_DATA_LAST) {
401 break;
402 }
403 }
404 if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) {
405 submit_halt(BULK_IN);
406 while(1) {
408 if (ev == reset_event) goto reset_state;
409 if (ev == PROCESS_EVENT_POLL) {
410 USBBuffer *buffer = get_next_buffer(BULK_IN , USB_BUFFER_ID_HALT);
411 if (buffer) {
412 if (buffer->flags & USB_BUFFER_HALT) break;
413 }
414 }
415 }
416 }
417 goto send_csw_state;
418
419 receive_data_state:
420 PRINTF("receive_data_state\n");
421 while(1) {
422 uint8_t id = 0;
423 /* Wait for any buffers to be submitted */
424 while (buf_submitted == buf_free) {
426 }
427 /* Wait until the current buffer is free */
428 while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) {
430 }
431 while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) {
432 id = data_usb_buffer[buf_submitted].id;
433 /* PRINTF("id: %02x\n", id); */
434 state.cmd_data_transfered += buffer_lengths[buf_submitted];
435 if (id == USB_BUFFER_ID_UNUSED) break;
436 data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
437 buf_submitted =NEXT_BUF(buf_submitted);
438 if (id & USB_MSC_DATA_DO_CALLBACK) {
439 if (state.data_cb) {
440 state.data_cb(&state);
441 }
442 }
443
444 if (id & USB_MSC_DATA_LAST) {
445 break;
446 }
447 }
448 if (id & USB_MSC_DATA_LAST) {
449 break;
450 }
451
452 }
453
454 if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) {
455 submit_halt(BULK_OUT);
456 while(1) {
458 if (ev == reset_event) goto reset_state;
459 if (ev == PROCESS_EVENT_POLL) {
460 USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT);
461 if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
462 }
463 }
464 }
465 goto send_csw_state;
466
467
468 send_csw_state:
469 PRINTF("send_csw_state\n");
470 if (data_usb_buffer[PREV_BUF(buf_free)].id != USB_BUFFER_ID_CSW) {
471 send_csw();
472 }
473 submit_cbw_buffer();
474 while(1) {
475 if (ev == reset_event) goto reset_state;
477 if (ev == PROCESS_EVENT_POLL) {
478 USBBuffer *buffer;
479 if ((buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_CSW))) {
480 goto receive_cbw_state;
481 }
482 }
483 }
484 goto receive_cbw_state;
485 PROCESS_END();
486}
487
488PROCESS_THREAD(usb_mass_bulk_process, ev , data)
489{
491 reset_event = process_alloc_event();
492 usb_msc_command_handler_init();
493 usb_setup();
494 usb_set_ep_event_process(BULK_IN, &usb_mass_bulk_request_process);
495 usb_set_ep_event_process(BULK_OUT, &usb_mass_bulk_request_process);
496 usb_set_global_event_process(process_current);
497 usb_register_request_handler(&mass_bulk_request_hook);
498 while(1) {
500 if (ev == PROCESS_EVENT_EXIT) break;
501 if (ev == PROCESS_EVENT_POLL) {
502 unsigned int events = usb_get_global_events();
503 if (events) {
504 if (events & USB_EVENT_CONFIG) {
505 if (usb_get_current_configuration() != 0) {
506 PRINTF("Configured\n");
507 memset(data_usb_buffer, 0, sizeof(data_usb_buffer));
508 usb_setup_bulk_endpoint(BULK_IN);
509 usb_setup_bulk_endpoint(BULK_OUT);
510 process_start(&usb_mass_bulk_request_process,NULL);
511 } else {
512 process_exit(&usb_mass_bulk_request_process);
513 usb_disable_endpoint(BULK_IN);
514 usb_disable_endpoint(BULK_OUT);
515 }
516 }
517 if (events & USB_EVENT_RESET) {
518 PRINTF("RESET\n");
519 process_exit(&usb_mass_bulk_request_process);
520 }
521 }
522 }
523 }
524 PROCESS_END();
525}
526
527void
528usb_msc_bulk_setup()
529{
530 process_start(&usb_mass_bulk_process, NULL);
531}
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
Header file for the Contiki process interface.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107