USB device stack

Dependents:   blinky_max32630fthr FTHR_USB_serial FTHR_OLED HSP_RPC_GUI_3_0_1 ... more

Fork of USBDevice by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHAL_Maxim.cpp Source File

USBHAL_Maxim.cpp

00001 /*******************************************************************************
00002  * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  * Except as contained in this notice, the name of Maxim Integrated
00023  * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024  * Products, Inc. Branding Policy.
00025  *
00026  * The mere transfer of this software does not imply any licenses
00027  * of trade secrets, proprietary technology, copyrights, patents,
00028  * trademarks, maskwork rights, or any other form of intellectual
00029  * property whatsoever. Maxim Integrated Products, Inc. retains all
00030  * ownership rights.
00031  *******************************************************************************
00032  */
00033 
00034 #if defined(TARGET_Maxim)
00035 
00036 #include "USBHAL.h"
00037 #include "usb_regs.h"
00038 #include "clkman_regs.h"
00039 
00040 #if defined(TARGET_MAX32625) || defined(TARGET_MAX32630)
00041 #include "pwrman_regs.h"
00042 #endif
00043 
00044 #define CONNECT_INTS    (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR)
00045 
00046 USBHAL *USBHAL::instance;
00047 
00048 typedef struct {
00049     volatile uint32_t buf0_desc;
00050     volatile uint32_t buf0_address;
00051     volatile uint32_t buf1_desc;
00052     volatile uint32_t buf1_address;
00053 } ep_buffer_t;
00054 
00055 typedef struct {
00056     ep_buffer_t out_buffer;
00057     ep_buffer_t in_buffer;
00058 } ep0_buffer_t;
00059 
00060 typedef struct {
00061     ep0_buffer_t ep0;
00062     ep_buffer_t ep[MXC_USB_NUM_EP - 1];
00063 } ep_buffer_descriptor_t;
00064 
00065 // Static storage for endpoint buffer descriptor table. Must be 512 byte aligned for DMA.
00066 #ifdef __IAR_SYSTEMS_ICC__
00067 #pragma data_alignment = 512
00068 #else
00069 __attribute__ ((aligned (512))) 
00070 #endif
00071 ep_buffer_descriptor_t ep_buffer_descriptor;
00072 
00073 // static storage for temporary data buffers. Must be 32 byte aligned.
00074 #ifdef __IAR_SYSTEMS_ICC__
00075 #pragma data_alignment = 4
00076 #else
00077 __attribute__ ((aligned (4))) 
00078 #endif
00079 static uint8_t aligned_buffer[NUMBER_OF_LOGICAL_ENDPOINTS][MXC_USB_MAX_PACKET];
00080 
00081 // control packet state
00082 static enum {
00083     CTRL_NONE = 0,
00084     CTRL_SETUP,
00085     CTRL_OUT,
00086     CTRL_IN,
00087 } control_state;
00088 
00089 USBHAL::USBHAL(void)
00090 {
00091     NVIC_DisableIRQ(USB_IRQn);
00092 
00093 #if defined(TARGET_MAX32600)
00094     // The PLL must be enabled for USB
00095     MBED_ASSERT(MXC_CLKMAN->clk_config & MXC_F_CLKMAN_CLK_CONFIG_PLL_ENABLE);
00096 
00097     // Enable the USB clock
00098     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_GATE_N;
00099 #elif defined(TARGET_MAX32620)
00100     // Enable the USB clock
00101     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE;
00102 #elif defined(TARGET_MAX32625) || defined(TARGET_MAX32630)
00103     MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_USB_POWERED;
00104     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE;
00105 #endif
00106 
00107     // reset the device
00108     MXC_USB->cn = 0;
00109     MXC_USB->cn = MXC_F_USB_CN_USB_EN;
00110     MXC_USB->dev_inten = 0;
00111     MXC_USB->dev_cn = 0;
00112     MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
00113     MXC_USB->dev_cn = 0;
00114 
00115     // fill in callback arrays
00116     epCallback[EP0OUT] = NULL;
00117     epCallback[EP0IN]  = NULL;
00118     epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback;
00119     epCallback[EP1IN ] = &USBHAL::EP1_IN_callback;
00120     epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback;
00121     epCallback[EP2IN ] = &USBHAL::EP2_IN_callback;
00122     epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback;
00123     epCallback[EP3IN ] = &USBHAL::EP3_IN_callback;
00124     epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback;
00125     epCallback[EP4IN ] = &USBHAL::EP4_IN_callback;
00126     epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback;
00127     epCallback[EP5IN ] = &USBHAL::EP5_IN_callback;
00128     epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback;
00129     epCallback[EP6IN ] = &USBHAL::EP6_IN_callback;
00130     epCallback[EP7OUT] = &USBHAL::EP7_OUT_callback;
00131     epCallback[EP7IN ] = &USBHAL::EP7_IN_callback;
00132 
00133     // clear driver state
00134     control_state = CTRL_NONE;
00135 
00136     // set the descriptor location
00137     MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor;
00138 
00139     // enable VBUS interrupts
00140     MXC_USB->dev_inten = MXC_F_USB_DEV_INTEN_NO_VBUS | MXC_F_USB_DEV_INTEN_VBUS;
00141 
00142     // attach IRQ handler and enable interrupts
00143     instance = this;
00144     NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
00145     NVIC_EnableIRQ(USB_IRQn);
00146 }
00147 
00148 USBHAL::~USBHAL(void)
00149 {
00150     MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
00151     MXC_USB->dev_cn = 0;
00152     MXC_USB->cn = 0;
00153 }
00154 
00155 void USBHAL::connect(void)
00156 {
00157     // enable interrupts
00158     MXC_USB->dev_inten |= CONNECT_INTS;
00159 
00160     // allow interrupts on ep0
00161     MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN;
00162 
00163     // pullup enable
00164     MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE);
00165 }
00166 
00167 void USBHAL::disconnect(void)
00168 {
00169     // disable interrupts
00170     MXC_USB->dev_inten &= ~CONNECT_INTS;
00171 
00172     // disable pullup
00173     MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT;
00174 }
00175 
00176 void USBHAL::configureDevice(void)
00177 {
00178     // do nothing
00179 }
00180 
00181 void USBHAL::unconfigureDevice(void)
00182 {
00183     // reset endpoints
00184     for (int i = 0; i < MXC_USB_NUM_EP; i++) {
00185         // Disable endpoint and clear the data toggle
00186         MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR;
00187         MXC_USB->ep[i] |= MXC_F_USB_EP_DT;
00188     }
00189 }
00190 
00191 void USBHAL::setAddress(uint8_t address)
00192 {
00193     // do nothing
00194 }
00195 
00196 void USBHAL::remoteWakeup(void)
00197 {
00198     // do nothing
00199 }
00200 
00201 static ep_buffer_t *get_desc(uint8_t endpoint)
00202 {
00203     uint8_t epnum = EP_NUM(endpoint);
00204     ep_buffer_t *desc;
00205 
00206     if (epnum == 0) {
00207         if (IN_EP(endpoint)) {
00208             desc = &ep_buffer_descriptor.ep0.in_buffer;
00209         } else {
00210             desc = &ep_buffer_descriptor.ep0.out_buffer;
00211         }
00212     } else {
00213         desc = &ep_buffer_descriptor.ep[epnum - 1];
00214     }
00215 
00216     return desc;
00217 }
00218 
00219 void USBHAL::EP0setup(uint8_t *buffer)
00220 {
00221     // Setup packet is fixed at 8 bytes
00222     // Setup registers cannot be read in byte mode
00223     uint32_t *ptr32 = (uint32_t*)buffer;
00224     ptr32[0] = (uint32_t)MXC_USB->setup0;
00225     ptr32[1] = (uint32_t)MXC_USB->setup1;
00226 }
00227 
00228 void USBHAL::EP0read(void)
00229 {
00230     if (control_state == CTRL_IN) {
00231         // This is the status stage. ACK.
00232         MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK;
00233         control_state = CTRL_NONE;
00234         return;
00235     }
00236 
00237     control_state = CTRL_OUT;
00238 
00239     endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
00240 }
00241 
00242 void USBHAL::EP0readStage(void)
00243 {
00244     // do nothing
00245 }
00246 
00247 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
00248 {
00249     uint32_t size;
00250 
00251     if (MXC_USB->out_owner & 1) {
00252         return 0;
00253     }
00254 
00255     // get the packet length and contents
00256     ep_buffer_t *desc = get_desc(EP0OUT);
00257     size = desc->buf0_desc;
00258     memcpy(buffer, aligned_buffer[0], size);
00259 
00260     return size;
00261 }
00262 
00263 void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
00264 {
00265     if ((size == 0) && (control_state != CTRL_IN)) {
00266         // This is a status stage ACK. Handle in hardware.
00267         MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK;
00268         control_state = CTRL_NONE;
00269         return;
00270     }
00271 
00272     control_state = CTRL_IN;
00273 
00274     endpointWrite(EP0IN, buffer, size);
00275 }
00276 
00277 void USBHAL::EP0stall(void)
00278 {
00279     stallEndpoint(0);
00280 }
00281 
00282 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
00283 {
00284     uint8_t epnum = EP_NUM(endpoint);
00285 
00286     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) {
00287         return EP_INVALID;
00288     }
00289 
00290     if (maximumSize > MXC_USB_MAX_PACKET) {
00291         return EP_INVALID;
00292     }
00293     
00294     uint32_t mask = (1 << epnum);
00295     if (MXC_USB->out_owner & mask) {
00296         return EP_INVALID;
00297     }
00298 
00299     ep_buffer_t *desc = get_desc(endpoint);
00300     desc->buf0_desc = maximumSize;
00301     desc->buf0_address = (uint32_t)aligned_buffer[epnum];
00302 
00303     MXC_USB->out_owner = mask;
00304 
00305     return EP_PENDING;
00306 }
00307 
00308 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead)
00309 {
00310     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) {
00311         return EP_INVALID;
00312     }
00313 
00314     uint32_t mask = (1 << EP_NUM(endpoint));
00315     if (MXC_USB->out_owner & mask) {
00316         return EP_PENDING;
00317     }
00318 
00319     // get the packet length and contents
00320     ep_buffer_t *desc = get_desc(endpoint);
00321     *bytesRead = desc->buf0_desc;
00322     memcpy(data, aligned_buffer[EP_NUM(endpoint)], *bytesRead);
00323 
00324     return EP_COMPLETED;
00325 }
00326 
00327 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
00328 {
00329     uint8_t epnum = EP_NUM(endpoint);
00330 
00331     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || OUT_EP(endpoint)) {
00332         return EP_INVALID;
00333     }
00334 
00335     if (size > MXC_USB_MAX_PACKET) {
00336         return EP_INVALID;
00337     }
00338 
00339     uint32_t mask = (1 << epnum);
00340     if (MXC_USB->in_owner & mask) {
00341         return EP_INVALID;
00342     }
00343 
00344     memcpy(aligned_buffer[epnum], data, size);
00345 
00346     ep_buffer_t *desc = get_desc(endpoint);
00347     desc->buf0_desc = size;
00348     desc->buf0_address = (uint32_t)aligned_buffer[epnum];
00349 
00350     // start the DMA
00351     MXC_USB->in_owner = mask;
00352 
00353     return EP_PENDING;
00354 }
00355 
00356 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
00357 {
00358     uint32_t mask = (1 << EP_NUM(endpoint));
00359     if (MXC_USB->in_owner & mask) {
00360         return EP_PENDING;
00361     }
00362 
00363     return EP_COMPLETED;
00364 }
00365 
00366 void USBHAL::stallEndpoint(uint8_t endpoint)
00367 {
00368     uint8_t epnum = EP_NUM(endpoint);
00369 
00370     if (epnum == 0) {
00371         MXC_USB->ep[epnum] |= MXC_F_USB_EP_ST_STALL;
00372     }
00373 
00374     MXC_USB->ep[epnum] |= MXC_F_USB_EP_STALL;
00375 }
00376 
00377 void USBHAL::unstallEndpoint(uint8_t endpoint)
00378 {
00379     MXC_USB->ep[EP_NUM(endpoint)] &= ~MXC_F_USB_EP_STALL;
00380 }
00381 
00382 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options)
00383 {
00384     uint8_t epnum = EP_NUM(endpoint);
00385     uint32_t ep_ctrl;
00386 
00387     if (epnum >= NUMBER_OF_PHYSICAL_ENDPOINTS) {
00388         return false;
00389     }
00390 
00391     if (IN_EP(endpoint)) {
00392         ep_ctrl = (MXC_V_USB_EP_DIR_IN << MXC_F_USB_EP_DIR_POS);
00393     } else {
00394         ep_ctrl = (MXC_S_USB_EP_DIR_OUT << MXC_F_USB_EP_DIR_POS);
00395     }
00396 
00397     ep_ctrl |= (MXC_F_USB_EP_DT | MXC_F_USB_EP_INT_EN);
00398 
00399     MXC_USB->ep[epnum] = ep_ctrl;
00400 
00401     return true;
00402 }
00403 
00404 bool USBHAL::getEndpointStallState(unsigned char endpoint)
00405 {
00406     return !!(MXC_USB->ep[endpoint] & MXC_F_USB_EP_STALL);
00407 }
00408 
00409 void USBHAL::_usbisr(void)
00410 {
00411     instance->usbisr();
00412 }
00413 
00414 void USBHAL::usbisr(void)
00415 {
00416     // get and clear irqs
00417     uint32_t irq_flags = MXC_USB->dev_intfl;
00418     MXC_USB->dev_intfl = irq_flags;
00419 
00420     // process only enabled interrupts
00421     irq_flags &= MXC_USB->dev_inten;
00422 
00423     // suspend 
00424     if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) {
00425         suspendStateChanged(1);
00426     }
00427 
00428     // bus reset
00429     if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) {
00430 
00431         // reset endpoints
00432         for (int i = 0; i < MXC_USB_NUM_EP; i++) {
00433             // Disable endpoint and clear the data toggle
00434             MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR;
00435             MXC_USB->ep[i] |= MXC_F_USB_EP_DT;
00436         }
00437 
00438         // clear driver state
00439         control_state = CTRL_NONE;
00440 
00441         busReset();
00442 
00443         // no need to process events after reset
00444         return;
00445     }
00446 
00447     // Setup packet
00448     if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) {
00449         control_state = CTRL_SETUP;
00450         EP0setupCallback();
00451     }
00452 
00453     // IN packets
00454     if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) {
00455         // get and clear IN irqs
00456         uint32_t in_irqs = MXC_USB->in_int;
00457         MXC_USB->in_int = in_irqs;
00458 
00459         if (in_irqs & 1) {
00460             EP0in();
00461         }
00462 
00463         for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) {
00464             uint32_t irq_mask = (1 << epnum);
00465             if (in_irqs & irq_mask) {
00466                 uint8_t endpoint = (epnum << 1) | DIR_IN;
00467                 (instance->*(epCallback[endpoint]))();
00468             }
00469         }
00470     }
00471 
00472     // OUT packets
00473     if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) {
00474         // get and clear OUT irqs
00475         uint32_t out_irqs = MXC_USB->out_int;
00476         MXC_USB->out_int = out_irqs;
00477 
00478         if (out_irqs & 1) {
00479             EP0out();
00480         }
00481 
00482         for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) {
00483             uint32_t irq_mask = (1 << epnum);
00484             if (out_irqs & irq_mask) {
00485                 uint8_t endpoint = (epnum << 1) | DIR_OUT;
00486                 (instance->*(epCallback[endpoint]))();
00487             }
00488         }
00489     }
00490 }
00491 
00492 #endif