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