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 
16 static const uint8_t max_lun = 0;
17 
18 static USBBuffer data_usb_buffer[USB_MSC_BUFFERS];
19 static unsigned int buffer_lengths[USB_MSC_BUFFERS];
20 
21 static unsigned int buf_first = 0; /* First prepared buffer */
22 static unsigned int buf_free = 0; /* First free buffer */
23 static 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 
33 static struct usb_msc_bulk_cbw cbw_buffer;
34 static struct usb_msc_bulk_csw csw_buffer;
35 
36 #define BULK_OUT 0x02
37 #define BULK_IN 0x81
38 
39 PROCESS(usb_mass_bulk_process, "USB mass storage bulk only process");
40 
41 static process_event_t reset_event;
42 
43 static 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)
48 void
49 usb_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 
81 void
82 usb_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 
87 void
88 usb_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 
122 void
123 usb_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 
128 static unsigned int
129 handle_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 
152 static const struct USBRequestHandler mass_bulk_request_handler =
153  {
154  0x21, 0x7f,
155  0x00, 0x00,
156  handle_mass_bulk_requests
157  };
158 
159 static struct USBRequestHandlerHook mass_bulk_request_hook =
160  {
161  NULL,
162  &mass_bulk_request_handler
163  };
164 
165 static void
166 send_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 
195 static void
196 submit_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 
217 static void
218 submit_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 
243 static USBBuffer *
244 get_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 
269 PROCESS(usb_mass_bulk_request_process, "USB mass storage request process");
270 
271 PROCESS_THREAD(usb_mass_bulk_request_process, ev , data)
272 {
273  PROCESS_BEGIN();
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 
488 PROCESS_THREAD(usb_mass_bulk_process, ev , data)
489 {
490  PROCESS_BEGIN();
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 
527 void
528 usb_msc_bulk_setup()
529 {
530  process_start(&usb_mass_bulk_process, NULL);
531 }
#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
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
#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_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
Header file for the Contiki process interface.
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1097
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99