Contiki 2.6

usb-msc-bulk.c

00001 #include "usb-msc-bulk.h"
00002 #include <usb-api.h>
00003 #include <usb-core.h>
00004 #include <sys/process.h>
00005 #include <stdio.h>
00006 #include <string.h>
00007 
00008 #define DEBUG     
00009 
00010 #ifdef DEBUG
00011 #define PRINTF(...) printf(__VA_ARGS__)
00012 #else
00013 #define PRINTF(...)
00014 #endif
00015 
00016 static const uint8_t max_lun = 0;
00017 
00018 static USBBuffer data_usb_buffer[USB_MSC_BUFFERS];
00019 static unsigned int buffer_lengths[USB_MSC_BUFFERS];
00020 
00021 static unsigned int buf_first = 0; /* First prepared buffer */
00022 static unsigned int buf_free = 0;       /* First free buffer */
00023 static unsigned int buf_submitted = 0; /* Oldest submitted buffer */
00024 
00025 #define USB_BUFFER_ID_UNUSED 0
00026 #define USB_BUFFER_ID_CBW 1
00027 #define USB_BUFFER_ID_CSW 2
00028 #define USB_BUFFER_ID_DATA 3
00029 #define USB_BUFFER_ID_DISCARD 4
00030 #define USB_BUFFER_ID_HALT 5
00031 #define USB_BUFFER_ID_MASK 0x07
00032 
00033 static struct usb_msc_bulk_cbw cbw_buffer;
00034 static struct usb_msc_bulk_csw csw_buffer;
00035 
00036 #define BULK_OUT 0x02
00037 #define BULK_IN 0x81
00038 
00039 PROCESS(usb_mass_bulk_process, "USB mass storage bulk only process");
00040 
00041 static process_event_t reset_event;
00042 
00043 static struct usb_msc_command_state state;
00044 
00045 /* Handle wrapping */
00046 #define PREV_BUF(x) (((x) == 0) ? USB_MSC_BUFFERS - 1 : (x) - 1)
00047 #define NEXT_BUF(x) (((x) < (USB_MSC_BUFFERS-1)) ? (x) + 1 : 0)
00048 void
00049 usb_msc_send_data_buf_flags(const uint8_t *data, unsigned int len,
00050                             unsigned int flags, uint16_t buf_flags)
00051 {
00052   USBBuffer *buffer = &data_usb_buffer[buf_free];
00053   if (buffer->id != USB_BUFFER_ID_UNUSED) {
00054     printf("Data IN buffer busy\n");
00055     return;
00056   }
00057   buffer->flags = USB_BUFFER_NOTIFY | buf_flags;
00058   buffer->next = NULL;
00059   buffer->data = (uint8_t*)data;
00060   buffer->left = len;
00061   buffer_lengths[buf_free] = len;
00062   buffer->id = USB_BUFFER_ID_DATA | flags;
00063   if (buf_free != buf_first) {
00064     data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
00065   }
00066   state.cmd_data_submitted += len;
00067   buf_free = NEXT_BUF(buf_free);
00068   /* PRINTF("usb_msc_send_data: %d\n", len); */
00069   if (flags & USB_MSC_DATA_SEND) {
00070     usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]);
00071     buf_first = buf_free;
00072     /* PRINTF("usb_msc_send_data: sent\n"); */
00073   } else if (flags & USB_MSC_DATA_LAST) {
00074     /* Cancel transmission */
00075     PRINTF("Send last\n");
00076     buf_first = buf_free;
00077     process_poll(&usb_mass_bulk_process);
00078   }
00079 }
00080 
00081 void
00082 usb_msc_send_data(const uint8_t *data, unsigned int len, unsigned int flags)
00083 {
00084   usb_msc_send_data_buf_flags(data, len, flags,0);
00085 }
00086 
00087 void
00088 usb_msc_receive_data_buf_flags(uint8_t *data, unsigned int len,
00089                                unsigned int flags, uint16_t buf_flags)
00090 {
00091   USBBuffer *buffer = &data_usb_buffer[buf_free];
00092   if (buffer->id != USB_BUFFER_ID_UNUSED) {
00093     printf("Data OUT buffer busy\n");
00094     return;
00095   }
00096   buffer->flags = USB_BUFFER_NOTIFY | buf_flags;
00097   buffer->next = NULL;
00098   buffer->data = data;
00099   buffer->left = len;
00100   buffer_lengths[buf_free] = len;
00101   buffer->id = USB_BUFFER_ID_DATA | flags;
00102   if (buf_free != buf_first) {
00103     data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
00104   }
00105   state.cmd_data_submitted += len;
00106   buf_free = NEXT_BUF(buf_free);
00107   if (flags & USB_MSC_DATA_RECEIVE) {
00108     usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]);
00109     buf_first = buf_free;
00110   } else if (flags & USB_MSC_DATA_LAST) {
00111     usb_discard_all_buffers(BULK_OUT);
00112     /* Mark the discarded buffers as unused */
00113     while(buf_submitted !=  PREV_BUF(buf_free)) {
00114       data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
00115       buf_submitted = NEXT_BUF(buf_submitted);
00116     }
00117     buf_first = buf_free;
00118     process_poll(&usb_mass_bulk_process);
00119   }
00120 }
00121 
00122 void
00123 usb_msc_receive_data(uint8_t *data, unsigned int len, unsigned int flags)
00124 {
00125   usb_msc_receive_data_buf_flags(data,len,flags, 0);
00126 }
00127 
00128 static unsigned int
00129 handle_mass_bulk_requests()
00130 {
00131   switch(usb_setup_buffer.bmRequestType) {
00132   case 0x21: /* interface OUT requests */
00133     switch(usb_setup_buffer.bRequest) {
00134     case MASS_BULK_RESET:
00135       PRINTF("Mass storage reset\n");
00136       process_post(&usb_mass_bulk_process, reset_event, NULL);
00137       return 1;
00138     }
00139     break;
00140   case 0xa1: /* interface IN requests */
00141     switch(usb_setup_buffer.bRequest) {
00142     case MASS_BULK_GET_MAX_LUN:
00143       PRINTF("Get LUN\n");
00144       usb_send_ctrl_response(&max_lun, sizeof(max_lun));
00145       return 1;
00146     }
00147     break;
00148   }
00149   return 0;
00150 }
00151 
00152 static const struct USBRequestHandler mass_bulk_request_handler =
00153   {
00154     0x21, 0x7f,
00155     0x00, 0x00,
00156     handle_mass_bulk_requests
00157   };
00158 
00159 static struct USBRequestHandlerHook mass_bulk_request_hook =
00160   {
00161     NULL,
00162     &mass_bulk_request_handler
00163   };
00164 
00165 static void
00166 send_csw(void)
00167 {
00168   USBBuffer *buffer = &data_usb_buffer[buf_free];
00169   if (buffer->id != USB_BUFFER_ID_UNUSED) {
00170     printf("CSW buffer busy\n");
00171     return;
00172   }
00173 
00174   csw_buffer.dCSWSignature = MASS_BULK_CSW_SIGNATURE;
00175   csw_buffer.dCSWTag = cbw_buffer.dCBWTag;
00176   csw_buffer.dCSWDataResidue =
00177     cbw_buffer.dCBWDataTransferLength - state.cmd_data_submitted;
00178   csw_buffer.bCSWStatus = state.status;
00179   
00180   buffer->flags = USB_BUFFER_NOTIFY;
00181   buffer->next = NULL;
00182   buffer->data =(uint8_t*)&csw_buffer ;
00183   buffer->left = sizeof(csw_buffer);
00184   buffer->id = USB_BUFFER_ID_CSW;
00185   if (buf_free != buf_first) {
00186     data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
00187   }
00188   buf_free = NEXT_BUF(buf_free);
00189   usb_submit_xmit_buffer(BULK_IN, &data_usb_buffer[buf_first]);
00190   buf_first = buf_free;
00191 
00192   PRINTF("CSW sent: %ld\n", sizeof(csw_buffer));
00193 }
00194 
00195 static void
00196 submit_cbw_buffer(void)
00197 {
00198   USBBuffer *buffer = &data_usb_buffer[buf_free];
00199   if (buffer->id != USB_BUFFER_ID_UNUSED) {
00200     printf("CBW buffer busy\n");
00201     return;
00202   }
00203   buffer->flags = USB_BUFFER_NOTIFY;
00204   buffer->next = NULL;
00205   buffer->data = (uint8_t*)&cbw_buffer;
00206   buffer->left = sizeof(cbw_buffer);
00207   buffer->id = USB_BUFFER_ID_CBW;
00208   if (buf_free != buf_first) {
00209     data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
00210   }
00211   buf_free = NEXT_BUF(buf_free);
00212   usb_submit_recv_buffer(BULK_OUT, &data_usb_buffer[buf_first]);
00213   PRINTF("CBW submitted: %d\n", buf_first);
00214   buf_first = buf_free;
00215 }
00216 
00217 static void
00218 submit_halt(uint8_t addr)
00219 {
00220   USBBuffer *buffer = &data_usb_buffer[buf_free];
00221   if (buffer->id != USB_BUFFER_ID_UNUSED) {
00222     printf("CBW buffer busy\n");
00223     return;
00224   }
00225   buffer->flags = USB_BUFFER_NOTIFY | USB_BUFFER_HALT;
00226   buffer->next = NULL;
00227   buffer->data = NULL;
00228   buffer->left = 0;
00229   buffer->id = USB_BUFFER_ID_HALT;
00230   if (buf_free != buf_first) {
00231     data_usb_buffer[PREV_BUF(buf_free)].next = buffer;
00232   }
00233   buf_free = NEXT_BUF(buf_free);
00234   if (addr & 0x80) {
00235     usb_submit_xmit_buffer(addr, &data_usb_buffer[buf_first]);
00236   } else {
00237     usb_submit_recv_buffer(addr, &data_usb_buffer[buf_first]);
00238   }
00239   PRINTF("HALT submitted %p\n",buffer);
00240   buf_first = buf_free;
00241 }
00242 
00243 static USBBuffer *
00244 get_next_buffer(uint8_t addr, uint32_t id)
00245 {
00246   unsigned int events;
00247   events = usb_get_ep_events(addr);
00248   if (events & USB_EP_EVENT_NOTIFICATION) {
00249     USBBuffer *buffer = &data_usb_buffer[buf_submitted];
00250     if (!(buffer->flags & USB_BUFFER_SUBMITTED)) {
00251 #ifdef DEBUG
00252       if (id != (buffer->id & USB_BUFFER_ID_MASK)) {
00253         printf("Wrong buffer ID expected %d, got %d\n",
00254                (int)id, (int)buffer->id);
00255       }
00256 #endif
00257       if ((buffer->id & USB_BUFFER_ID_MASK) == USB_BUFFER_ID_DATA) {
00258         state.cmd_data_transfered +=
00259           buffer_lengths[buf_submitted] - buffer->left;
00260       }
00261       buffer->id = USB_BUFFER_ID_UNUSED;
00262       buf_submitted =NEXT_BUF(buf_submitted);
00263       return buffer;
00264     }
00265   }
00266   return NULL;
00267 }
00268 
00269 PROCESS(usb_mass_bulk_request_process, "USB mass storage request process");
00270 
00271 PROCESS_THREAD(usb_mass_bulk_request_process, ev , data)
00272 {
00273   PROCESS_BEGIN();
00274  reset_state:
00275   usb_discard_all_buffers(BULK_OUT);
00276   usb_discard_all_buffers(BULK_IN);
00277   memset(data_usb_buffer, 0, sizeof(data_usb_buffer));
00278   buf_first = 0;
00279   buf_free = 0;
00280   buf_submitted = 0;
00281   submit_cbw_buffer();
00282  receive_cbw_state:
00283   PRINTF("receive_cbw_state\n");
00284   while(1) {
00285     PROCESS_WAIT_EVENT();
00286     if (ev == reset_event) goto reset_state;
00287     if (ev == PROCESS_EVENT_POLL) {
00288       USBBuffer *buffer;
00289       if ((buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_CBW))) {
00290         
00291         /* CBW */
00292         if (cbw_buffer.dCBWSignature == MASS_BULK_CBW_SIGNATURE) {
00293           usb_msc_handler_status ret;
00294           PRINTF("Got CBW seq %d\n",(int)cbw_buffer.dCBWTag);
00295           state.command = cbw_buffer.CBWCB;
00296           state.command_length = cbw_buffer.bCBWCBLength;
00297           state.status = MASS_BULK_CSW_STATUS_FAILED;
00298           state.data_cb = NULL;
00299           state.cmd_data_submitted = 0;
00300           state.cmd_data_transfered = 0;
00301           ret = usb_msc_handle_command(&state);
00302           if (ret == USB_MSC_HANDLER_OK) {
00303             state.status = MASS_BULK_CSW_STATUS_PASSED;
00304           } else if (ret == USB_MSC_HANDLER_FAILED) {
00305             state.status = MASS_BULK_CSW_STATUS_FAILED;
00306           }
00307           if (ret != USB_MSC_HANDLER_DELAYED
00308               && buf_submitted == buf_free) {
00309             if (cbw_buffer.dCBWDataTransferLength > 0) {
00310               /* HALT the apropriate endpoint */
00311               if (cbw_buffer.bmCBWFlags & MASS_BULK_CBW_FLAG_IN) {
00312                 submit_halt(BULK_IN);
00313               } else {
00314                 submit_halt(BULK_OUT);
00315               }
00316               /* Wait for HALT */
00317               while(1) {
00318                 PROCESS_WAIT_EVENT();
00319                 if (ev == reset_event) goto reset_state;
00320                 if (ev == PROCESS_EVENT_POLL) {
00321                   USBBuffer *buffer =
00322                     get_next_buffer(BULK_IN, USB_BUFFER_ID_HALT);
00323                   if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
00324                 }
00325               }
00326             }
00327             goto send_csw_state;
00328           }
00329           if (cbw_buffer.bmCBWFlags & MASS_BULK_CBW_FLAG_IN) {
00330             goto send_data_state;
00331           } else {
00332             goto receive_data_state;
00333           }
00334         } else {
00335           printf("Invalid CBW\n");
00336           submit_halt(BULK_IN);
00337           submit_halt(BULK_OUT);
00338           while(1) {
00339             PROCESS_WAIT_EVENT();
00340             if (ev == reset_event) goto reset_state;
00341             if (ev == PROCESS_EVENT_POLL) {
00342               USBBuffer *buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_HALT);
00343               if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
00344             }
00345           }
00346           while(1) {
00347             PROCESS_WAIT_EVENT();
00348             if (ev == reset_event) goto reset_state;
00349             if (ev == PROCESS_EVENT_POLL) {
00350               USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT);
00351               if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
00352             }
00353           }
00354           /* CBW */
00355           goto receive_cbw_state;
00356         }
00357       }
00358     }
00359   }
00360   
00361  send_data_state:
00362   PRINTF("send_data_state\n");
00363   while(1) {
00364     uint8_t id = 0;
00365     /* Wait for any data to be sent */
00366     while (buf_submitted == buf_free) {
00367       PRINTF("Wait data\n");
00368       PROCESS_WAIT_EVENT();
00369     }
00370 #if 0
00371     /* Send CSW early to improve throughput, unless we need to HALT
00372        the endpoint due to short data */
00373     if ((data_usb_buffer[PREV_BUF(buf_free)].id & USB_MSC_DATA_LAST)
00374         && state.cmd_data_submitted == cbw_buffer.dCBWDataTransferLength) {
00375       send_csw();
00376     }
00377 #endif
00378     /* Wait until the current buffer is free */
00379     while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) {
00380       PROCESS_WAIT_EVENT();
00381     }
00382     while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) {
00383       id = data_usb_buffer[buf_submitted].id;
00384       /* PRINTF("id: %02x\n", id);  */
00385       if (id == USB_BUFFER_ID_UNUSED) break;
00386       state.cmd_data_transfered += buffer_lengths[buf_submitted];
00387       data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
00388       buf_submitted =NEXT_BUF(buf_submitted);
00389       if (id & USB_MSC_DATA_DO_CALLBACK) {
00390         if (state.data_cb) {
00391           state.data_cb(&state);
00392         }
00393       }
00394       
00395      
00396       if (id & USB_MSC_DATA_LAST) {
00397         break;
00398       }
00399     }
00400     if (id & USB_MSC_DATA_LAST) {
00401       break;
00402     }
00403   }
00404   if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) {
00405     submit_halt(BULK_IN);
00406     while(1) {
00407       PROCESS_WAIT_EVENT();
00408       if (ev == reset_event) goto reset_state;
00409       if (ev == PROCESS_EVENT_POLL) {
00410         USBBuffer *buffer = get_next_buffer(BULK_IN , USB_BUFFER_ID_HALT);
00411         if (buffer) {
00412           if (buffer->flags & USB_BUFFER_HALT) break;
00413         }
00414       }
00415     }
00416   }
00417   goto send_csw_state;
00418 
00419  receive_data_state:
00420   PRINTF("receive_data_state\n");
00421   while(1) {
00422     uint8_t id = 0;
00423     /* Wait for any buffers to be submitted */
00424     while (buf_submitted == buf_free) {
00425       PROCESS_WAIT_EVENT();
00426     }
00427     /* Wait until the current buffer is free */
00428     while (data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED) {
00429       PROCESS_WAIT_EVENT();
00430     }
00431     while (!(data_usb_buffer[buf_submitted].flags & USB_BUFFER_SUBMITTED)) {
00432       id = data_usb_buffer[buf_submitted].id;
00433       /* PRINTF("id: %02x\n", id); */
00434       state.cmd_data_transfered += buffer_lengths[buf_submitted];
00435       if (id == USB_BUFFER_ID_UNUSED) break;
00436       data_usb_buffer[buf_submitted].id = USB_BUFFER_ID_UNUSED;
00437       buf_submitted =NEXT_BUF(buf_submitted);
00438       if (id & USB_MSC_DATA_DO_CALLBACK) {
00439         if (state.data_cb) {
00440           state.data_cb(&state);
00441         }
00442       }
00443       
00444       if (id & USB_MSC_DATA_LAST) {
00445         break;
00446       }
00447     }
00448     if (id & USB_MSC_DATA_LAST) {
00449       break;
00450     }
00451   
00452   }
00453   
00454   if (state.cmd_data_submitted < cbw_buffer.dCBWDataTransferLength) {
00455     submit_halt(BULK_OUT);
00456     while(1) {
00457       PROCESS_WAIT_EVENT();
00458       if (ev == reset_event) goto reset_state;
00459       if (ev == PROCESS_EVENT_POLL) {
00460         USBBuffer *buffer = get_next_buffer(BULK_OUT, USB_BUFFER_ID_HALT);
00461         if (buffer && (buffer->flags & USB_BUFFER_HALT)) break;
00462       }
00463     }
00464   }
00465   goto send_csw_state;
00466 
00467   
00468  send_csw_state:
00469   PRINTF("send_csw_state\n");
00470   if (data_usb_buffer[PREV_BUF(buf_free)].id != USB_BUFFER_ID_CSW) {
00471     send_csw();
00472   }
00473   submit_cbw_buffer();
00474   while(1) {
00475     if (ev == reset_event) goto reset_state;
00476     PROCESS_WAIT_EVENT();
00477     if (ev == PROCESS_EVENT_POLL) {
00478       USBBuffer *buffer;
00479       if ((buffer = get_next_buffer(BULK_IN, USB_BUFFER_ID_CSW))) {
00480         goto receive_cbw_state;
00481       }
00482     }
00483   }
00484   goto receive_cbw_state;
00485   PROCESS_END();
00486 }
00487      
00488 PROCESS_THREAD(usb_mass_bulk_process, ev , data)
00489 {
00490   PROCESS_BEGIN();
00491   reset_event = process_alloc_event();
00492   usb_msc_command_handler_init();
00493   usb_setup();
00494   usb_set_ep_event_process(BULK_IN, &usb_mass_bulk_request_process);
00495   usb_set_ep_event_process(BULK_OUT, &usb_mass_bulk_request_process);
00496   usb_set_global_event_process(process_current);
00497   usb_register_request_handler(&mass_bulk_request_hook);
00498   while(1) {
00499     PROCESS_WAIT_EVENT();
00500     if (ev == PROCESS_EVENT_EXIT) break;
00501     if (ev == PROCESS_EVENT_POLL) {
00502       unsigned int events = usb_get_global_events();
00503       if (events) {
00504         if (events & USB_EVENT_CONFIG) {
00505           if (usb_get_current_configuration() != 0) {
00506             PRINTF("Configured\n");
00507             memset(data_usb_buffer, 0, sizeof(data_usb_buffer));
00508             usb_setup_bulk_endpoint(BULK_IN);
00509             usb_setup_bulk_endpoint(BULK_OUT);
00510             process_start(&usb_mass_bulk_request_process,NULL);
00511           } else {
00512             process_exit(&usb_mass_bulk_request_process);
00513             usb_disable_endpoint(BULK_IN);
00514             usb_disable_endpoint(BULK_OUT);
00515           }
00516         }
00517         if (events & USB_EVENT_RESET) {
00518           PRINTF("RESET\n");
00519           process_exit(&usb_mass_bulk_request_process);
00520         }
00521       }
00522     }
00523   }
00524   PROCESS_END();
00525 }
00526 
00527 void
00528 usb_msc_bulk_setup()
00529 {
00530   process_start(&usb_mass_bulk_process, NULL);
00531 }