• Main Page
  • Modules
  • Index
  • File List
  • Globals

projects/nrfgo_sdk/bootloader_32k/firmware/usb.c

Go to the documentation of this file.
00001 /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is confidential property of Nordic 
00004  * Semiconductor ASA.Terms and conditions of usage are described in detail 
00005  * in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRENTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *              
00011  * $LastChangedRevision: 133 $
00012  */
00013 
00018 #include <Nordic\reg24lu1.h>
00019 #include <intrins.h>
00020 #include <stdbool.h>
00021 
00022 #include "config.h"
00023 #include "usb.h"
00024 
00025 // Place all code and constants in this file in the segment "BOOTLOADER":
00026 #pragma userclass (code = BOOTLOADER)
00027 #pragma userclass (const = BOOTLOADER)
00028 
00030 #define MIN(a, b) ((a) < (b) ? (a) : (b))
00031 
00032 // USB map:
00033 xdata volatile uint8_t out1buf[USB_EP1_SIZE]        _at_ 0xC640;
00034 xdata volatile uint8_t in1buf[USB_EP1_SIZE]         _at_ 0xC680;
00035 xdata volatile uint8_t out0buf[MAX_PACKET_SIZE_EP0] _at_ 0xC6C0;
00036 xdata volatile uint8_t in0buf[MAX_PACKET_SIZE_EP0]  _at_ 0xC700;
00037 xdata volatile uint8_t bout1addr                    _at_ 0xC781;
00038 xdata volatile uint8_t bout2addr                    _at_ 0xC782;
00039 xdata volatile uint8_t bout3addr                    _at_ 0xC783;
00040 xdata volatile uint8_t bout4addr                    _at_ 0xC784;
00041 xdata volatile uint8_t bout5addr                    _at_ 0xC785;
00042 xdata volatile uint8_t binstaddr                    _at_ 0xC788;
00043 xdata volatile uint8_t bin1addr                     _at_ 0xC789;
00044 xdata volatile uint8_t bin2addr                     _at_ 0xC78A;
00045 xdata volatile uint8_t bin3addr                     _at_ 0xC78B;
00046 xdata volatile uint8_t bin4addr                     _at_ 0xC78C;
00047 xdata volatile uint8_t bin5addr                     _at_ 0xC78D;
00048 xdata volatile uint8_t ivec                         _at_ 0xC7A8;
00049 xdata volatile uint8_t in_irq                       _at_ 0xC7A9;
00050 xdata volatile uint8_t out_irq                      _at_ 0xC7AA;
00051 xdata volatile uint8_t usbirq                       _at_ 0xC7AB;
00052 xdata volatile uint8_t in_ien                       _at_ 0xC7AC;
00053 xdata volatile uint8_t out_ien                      _at_ 0xC7AD;
00054 xdata volatile uint8_t usbien                       _at_ 0xC7AE;
00055 xdata volatile uint8_t ep0cs                        _at_ 0xC7B4;
00056 xdata volatile uint8_t in0bc                        _at_ 0xC7B5;
00057 xdata volatile uint8_t in1cs                        _at_ 0xC7B6;
00058 xdata volatile uint8_t in1bc                        _at_ 0xC7B7;
00059 xdata volatile uint8_t out0bc                       _at_ 0xC7C5;
00060 xdata volatile uint8_t out1cs                       _at_ 0xC7C6;
00061 xdata volatile uint8_t out1bc                       _at_ 0xC7C7;
00062 xdata volatile uint8_t usbcs                        _at_ 0xC7D6;
00063 xdata volatile uint8_t inbulkval                    _at_ 0xC7DE;
00064 xdata volatile uint8_t outbulkval                   _at_ 0xC7DF;
00065 xdata volatile uint8_t inisoval                     _at_ 0xC7E0;
00066 xdata volatile uint8_t outisoval                    _at_ 0xC7E1;
00067 xdata volatile uint8_t setupbuf[8]                  _at_ 0xC7E8;
00068 
00069 static uint8_t usb_bm_state;
00070 static uint8_t usb_current_config;
00071 static uint8_t usb_current_alt_interface;
00072 static usb_state_t usb_state;
00073 
00074 static uint8_t code * packetizer_data_ptr;
00075 static uint8_t packetizer_data_size;
00076 static uint8_t packetizer_pkt_size;
00077 static uint8_t bmRequestType;
00078 
00079 bool packet_received;
00080 
00081 static void packetizer_isr_ep0_in();
00082 static void usb_process_get_status();
00083 static void usb_process_get_descriptor();
00084 
00085 static void delay_ms(uint16_t ms)
00086 {
00087     uint16_t i, j;
00088     
00089     for(i = 0; i < ms; i++ )
00090     {
00091         for( j = 0; j < 1403; j++)
00092         {
00093             _nop_();
00094         }
00095     }
00096 }
00097 
00098 void usb_init(void)
00099 {
00100     // Setup state information
00101     usb_state = DEFAULT;
00102     usb_bm_state = 0;
00103 
00104     // Setconfig configuration information
00105     usb_current_config = 0;
00106     usb_current_alt_interface = 0;
00107     
00108     // Disconnect from USB-bus since we are in this routine from a power on and not a soft reset:
00109 
00110     usbcs |= 0x08;
00111     delay_ms(50);
00112     usbcs &= ~0x08;
00113 
00114     usbien = 0x1d;
00115     in_ien = 0x01;
00116     in_irq = 0x1f;
00117     out_ien = 0x01;
00118     out_irq = 0x1f;
00119 
00120     // Setup the USB RAM with some OK default values:
00121     bout1addr = MAX_PACKET_SIZE_EP0/2;
00122     bout2addr = MAX_PACKET_SIZE_EP0/2 + USB_EP1_SIZE/2;
00123     bout3addr = MAX_PACKET_SIZE_EP0/2 + 2*USB_EP1_SIZE/2;
00124     bout4addr = MAX_PACKET_SIZE_EP0/2 + 3*USB_EP1_SIZE/2;
00125     bout5addr = MAX_PACKET_SIZE_EP0/2 + 4*USB_EP1_SIZE/2;
00126     binstaddr = 0xc0;
00127     bin1addr = MAX_PACKET_SIZE_EP0/2;
00128     bin2addr = MAX_PACKET_SIZE_EP0/2 + USB_EP1_SIZE/2;
00129     bin3addr = MAX_PACKET_SIZE_EP0/2 + 2*USB_EP1_SIZE/2;
00130     bin4addr = MAX_PACKET_SIZE_EP0/2 + 3*USB_EP1_SIZE/2;
00131     bin5addr = MAX_PACKET_SIZE_EP0/2 + 4*USB_EP1_SIZE/2;
00132 
00133     // Set all endpoints to not valid (except EP0IN and EP0OUT)
00134     inbulkval = 0x01;
00135     outbulkval = 0x01;
00136     inisoval = 0x00;
00137     outisoval = 0x00;
00138 
00139     in_ien |= 0x02;; 
00140     inbulkval |= 0x02;
00141     out_ien |= 0x02;
00142     outbulkval |= 0x02;
00143     out1bc = 0xff;
00144 }
00145 
00146 static void packetizer_isr_ep0_in()
00147 {
00148     uint8_t code* data_ptr; 
00149     uint8_t size, i;
00150     // We are getting a ep0in interupt when the host send ACK and do not have any more data to send
00151     if(packetizer_data_size == 0)
00152     {
00153         in0bc = 0;
00154         USB_EP0_HSNAK();
00155         return;
00156     }
00157 
00158     size = MIN(packetizer_data_size, packetizer_pkt_size);
00159 
00160     // Copy data to the USB-controller buffer
00161     data_ptr = packetizer_data_ptr;
00162     for(i = 0; i < size;i++)
00163     {
00164         in0buf[i] = *data_ptr++;
00165     }
00166 
00167     // Tell the USB-controller how many bytes to send
00168     // If a IN is received from host after this the USB-controller will send the data
00169     in0bc = size;
00170 
00171     // Update the packetizer data
00172     packetizer_data_ptr += size;
00173     packetizer_data_size -= size;
00174 }
00175 
00176 static void usb_process_get_status()
00177 {
00178     in0buf[0] = in0buf[1] = 0x00;
00179     if((usb_state == ADDRESSED) && (setupbuf[4] == 0x00))
00180     {
00181         in0bc = 0x02;
00182     }
00183     else if(usb_state == CONFIGURED)
00184     {
00185         switch(bmRequestType)
00186         {
00187             case 0x80: // Device
00188                 if((usb_bm_state & USB_BM_STATE_ALLOW_REMOTE_WAKEUP ) == USB_BM_STATE_ALLOW_REMOTE_WAKEUP)
00189                 {
00190                     in0buf[0] = 0x02;
00191                 }
00192                 in0bc = 0x02;
00193                 break;
00194 
00195             case 0x81: // Interface
00196                 in0bc = 0x02;
00197                 break;
00198 
00199             case 0x82: // Endpoint
00200                 if((setupbuf[4] & 0x80) == 0x80) // IN endpoints
00201                     in0buf[0] = in1cs;
00202                 else
00203                     in0buf[0] = out1cs;
00204                 in0bc = 0x02;
00205                 break;
00206             default:
00207                 USB_EP0_STALL();
00208                 break;
00209         }
00210     }
00211     else
00212     {
00213         // We should not be in this state
00214         USB_EP0_STALL();
00215     }
00216 }
00217 
00218 static void usb_process_get_descriptor()
00219 { 
00220     packetizer_pkt_size = MAX_PACKET_SIZE_EP0;
00221     // Switch on descriptor type
00222     switch(setupbuf[3])
00223     {
00224         case USB_DESC_DEVICE:
00225             packetizer_data_ptr = (uint8_t*)&g_usb_dev_desc;
00226             packetizer_data_size = MIN(setupbuf[6], sizeof(usb_dev_desc_t));
00227             packetizer_isr_ep0_in();
00228             break;
00229 
00230         case USB_DESC_CONFIGURATION:
00231             // For now we just support one configuration. The asked configuration is stored in LSB(wValue).
00232             packetizer_data_ptr = (uint8_t*)&g_usb_conf_desc;
00233             packetizer_data_size = MIN(setupbuf[6], sizeof(usb_conf_desc_bootloader_t));
00234             packetizer_isr_ep0_in();
00235             break;
00236 
00237         case USB_DESC_STRING:
00238             // For now we just support english as string descriptor language.
00239             if(setupbuf[2] == 0x00)
00240             {
00241                 packetizer_data_ptr = string_zero;
00242                 packetizer_data_size = MIN(setupbuf[6], sizeof(string_zero));
00243                 packetizer_isr_ep0_in();
00244             }
00245             else
00246             {
00247                 if((setupbuf[2] - 1) < USB_STRING_DESC_COUNT)
00248                 {
00249                     if (setupbuf[2] == 1)
00250                         packetizer_data_ptr = g_usb_string_desc_1;
00251                     else
00252                         packetizer_data_ptr = g_usb_string_desc_2;;
00253                     packetizer_data_size = MIN(setupbuf[6], packetizer_data_ptr[0]);
00254                     packetizer_isr_ep0_in();
00255                 }
00256                 else
00257                 {
00258                     USB_EP0_STALL();
00259                 }
00260             }
00261             break;
00262         case USB_DESC_INTERFACE:
00263         case USB_DESC_ENDPOINT:
00264         case USB_DESC_DEVICE_QUAL:
00265         case USB_DESC_OTHER_SPEED_CONF:
00266         case USB_DESC_INTERFACE_POWER:
00267             USB_EP0_STALL();
00268             break;
00269         default:
00270             USB_EP0_HSNAK();
00271             break;
00272     }
00273 }
00274 
00275 static void isr_sudav()
00276 {
00277     bmRequestType = setupbuf[0];
00278     if((bmRequestType & 0x60 ) == 0x00)
00279     {
00280         switch(setupbuf[1])
00281         {
00282            case USB_REQ_GET_DESCRIPTOR:
00283                usb_process_get_descriptor();
00284                break;
00285 
00286            case USB_REQ_GET_STATUS:
00287                usb_process_get_status();
00288                break;
00289 
00290             case USB_REQ_SET_ADDRESS:
00291                usb_state = ADDRESSED;
00292                usb_current_config = 0x00;
00293                break;
00294 
00295             case USB_REQ_GET_CONFIGURATION:
00296                 switch(usb_state)
00297                 {
00298                     case ADDRESSED:
00299                         in0buf[0] = 0x00;
00300                         in0bc = 0x01;
00301                         break;
00302                     case CONFIGURED:
00303                         in0buf[0] = usb_current_config;
00304                         in0bc = 0x01;
00305                         break;
00306                     case ATTACHED:
00307                     case POWERED:
00308                     case SUSPENDED:
00309                     case DEFAULT:
00310                     default:
00311                         USB_EP0_STALL();
00312                         break;
00313                 }
00314                 break;
00315 
00316             case USB_REQ_SET_CONFIGURATION:
00317                 switch(setupbuf[2])
00318                 {
00319                     case 0x00:
00320                         usb_state = ADDRESSED;
00321                         usb_current_config = 0x00;
00322                         USB_EP0_HSNAK();
00323                         break;
00324                     case 0x01:
00325                         usb_state = CONFIGURED;
00326                         usb_bm_state |= USB_BM_STATE_CONFIGURED;
00327                         usb_current_config = 0x01;
00328                         USB_EP0_HSNAK();
00329                         break;
00330                     default:
00331                         USB_EP0_STALL();
00332                         break;
00333                 }
00334                break;
00335 
00336             case USB_REQ_GET_INTERFACE: // GET_INTERFACE
00337                 in0buf[0] = usb_current_alt_interface;
00338                 in0bc = 0x01;
00339                 break;
00340 
00341             case USB_REQ_SET_DESCRIPTOR:
00342             case USB_REQ_SET_INTERFACE: // SET_INTERFACE
00343             case USB_REQ_SYNCH_FRAME:   // SYNCH_FRAME
00344             default:
00345                 USB_EP0_STALL();
00346                 break;
00347         }
00348     } 
00349     // bmRequestType = 0 01 xxxxx : Data transfer direction: Host-to-device, Type: Class
00350     else if((bmRequestType & 0x60 ) == 0x20)  // Class request
00351     {
00352         if(setupbuf[6] != 0 && ((bmRequestType & 0x80) == 0x00))
00353         {
00354             // If there is a OUT-transaction associated with the Control-Transfer-Write we call the callback
00355             // when the OUT-transaction is finished. Note that this function do not handle several out transactions.
00356             out0bc = 0xff;
00357         }
00358         else
00359         {
00360             USB_EP0_HSNAK();
00361         }
00362     } 
00363     else  // Unknown request type
00364     {
00365         USB_EP0_STALL();
00366     }
00367 }
00368 
00369 void usb_irq(void)
00370 {
00371     //
00372     // Split case into an if and a switch to force Keil into not using a library function:
00373     if (ivec == INT_USBRESET)
00374     {
00375         usbirq = 0x10;
00376         usb_state = DEFAULT;
00377         usb_current_config = 0;
00378         usb_current_alt_interface = 0;
00379         usb_bm_state = 0;
00380     }
00381     else
00382     {
00383         switch(ivec)
00384         {
00385             case INT_SUDAV:
00386                 usbirq = 0x01;
00387                 isr_sudav();
00388                 break;
00389             case INT_SOF:
00390                 usbirq = 0x02;
00391                 break;
00392             case INT_SUTOK:
00393                 usbirq = 0x04;
00394                 packetizer_data_ptr = NULL;
00395                 packetizer_data_size = 0;
00396                 packetizer_pkt_size = 0;
00397                 break;
00398             case INT_SUSPEND:
00399                 usbirq = 0x08;
00400                 break;
00401             case INT_EP0IN:
00402                 in_irq = 0x01;
00403                 packetizer_isr_ep0_in();
00404                 break;
00405             case INT_EP0OUT:
00406                 out_irq = 0x01;
00407                 packetizer_data_size = 0;
00408                 //        req.misc_data = out0buf;
00409                 USB_EP0_HSNAK();
00410                 break;
00411             case INT_EP1IN:
00412                 // Clear interrupt 
00413                 in_irq = 0x02;
00414                 in1cs = 0x02;
00415                 break;
00416             case INT_EP1OUT:
00417                 // Clear interrupt
00418                 out_irq = 0x02;     
00419                 packet_received = true;
00420                 out1bc = 0xff;
00421                 break;
00422             default:
00423                 break;
00424         }
00425     }
00426 }
00427 

Generated on Fri Apr 20 2012 14:11:45 for nRFGo SDK by  doxygen 1.7.2