initial commit
[armstart-ibdap] / src / usb_driver.c
1 /*
2  * usb_driver.c
3  *
4  *  Created on: Jun 18, 2015
5  *      Author: yliu
6  */
7
8 #include <stdint.h>
9 #include <string.h>
10
11 #ifdef __USE_CMSIS
12 #include "LPC11Uxx.h"
13 #endif
14
15
16 #include "usb_driver.h"
17
18 #define PDRUNCFGUSEMASK 0x0000E800
19 #define PDRUNCFGMASKTMP 0x000005FF
20
21 USBD_HANDLE_T g_usb_hnd;
22 const  USBD_API_T *g_pUsbApi;
23
24
25 /* Find the address of interface descriptor for given class type. */
26 USB_INTERFACE_DESCRIPTOR *find_IntfDesc(const uint8_t *pDesc, uint32_t intfClass)
27 {
28         USB_COMMON_DESCRIPTOR *pD;
29         USB_INTERFACE_DESCRIPTOR *pIntfDesc = 0;
30         uint32_t next_desc_adr;
31
32         pD = (USB_COMMON_DESCRIPTOR *) pDesc;
33         next_desc_adr = (uint32_t) pDesc;
34
35         while (pD->bLength) {
36                 /* is it interface descriptor */
37                 if (pD->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) {
38
39                         pIntfDesc = (USB_INTERFACE_DESCRIPTOR *) pD;
40                         /* did we find the right interface descriptor */
41                         if (pIntfDesc->bInterfaceClass == intfClass) {
42                                 break;
43                         }
44                 }
45                 pIntfDesc = 0;
46                 next_desc_adr = (uint32_t) pD + pD->bLength;
47                 pD = (USB_COMMON_DESCRIPTOR *) next_desc_adr;
48         }
49
50         return pIntfDesc;
51 }
52
53
54
55
56 void init_usb_clock () {
57         // no need to do this: LPC_SYSCON->PDRUNCFG     &= ~(1 <<  8);
58         // system_LPC11Uxx.c done that already.
59         // configure SYSAHBCLKCTRL
60
61         // no need to do this: enabled in ResetISR()
62         //LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 26; // ram1 clock source enable
63         //LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 27; // usbram clock source enable
64         // conf usb main clock
65         LPC_SYSCON->USBCLKSEL = 0;
66         LPC_SYSCON->USBCLKUEN = 0;
67         LPC_SYSCON->USBCLKUEN = 1;
68         LPC_SYSCON->USBCLKDIV = 1;
69
70         LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 14; // usb clock source
71         //LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 26;
72         LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 27;
73 }
74
75 void init_usb_power () {
76         uint32_t pdrun;
77         pdrun = LPC_SYSCON->PDRUNCFG & PDRUNCFGMASKTMP;
78         pdrun &= ~((1 << 10) & PDRUNCFGMASKTMP);
79         LPC_SYSCON->PDRUNCFG = (pdrun | PDRUNCFGUSEMASK);
80 }
81
82 void USB_IRQHandler(void) {
83         uint32_t *addr = (uint32_t *) LPC_USB->EPLISTSTART;
84
85         /*      WORKAROUND for artf32289 ROM driver BUG:
86             As part of USB specification the device should respond
87             with STALL condition for any unsupported setup packet. The host will send
88             new setup packet/request on seeing STALL condition for EP0 instead of sending
89             a clear STALL request. Current driver in ROM doesn't clear the STALL
90             condition on new setup packet which should be fixed.
91          */
92         if ( LPC_USB->DEVCMDSTAT & (1 << 8) ) { /* if setup packet is received */
93                 addr[0] &= ~(1 << 29);  /* clear EP0_OUT stall */
94                 addr[2] &= ~(1 << 29);  /* clear EP0_IN stall */
95         }
96         USBD_API->hw->ISR(g_usb_hnd);
97 }
98
99 int init_usb_driver (USBD_API_INIT_PARAM_T *usb_param) {
100         USB_CORE_DESCS_T desc;
101         ErrorCode_t ret = LPC_OK;
102
103         g_pUsbApi = (const USBD_API_T *) LPC_ROM_API->usbdApiBase;
104         memset((void *) usb_param, 0, sizeof(USBD_API_INIT_PARAM_T));
105         usb_param->usb_reg_base = LPC_USB_BASE;
106         /*      WORKAROUND for artf44835 ROM driver BUG:
107                     Code clearing STALL bits in endpoint reset routine corrupts memory area
108                     next to the endpoint control data. For example When EP0, EP1_IN, EP1_OUT,
109                     EP2_IN are used we need to specify 3 here. But as a workaround for this
110                     issue specify 4. So that extra EPs control structure acts as padding buffer
111                     to avoid data corruption. Corruption of padding memory doesn’t affect the
112                     stack/program behaviour.
113         */
114         usb_param->max_num_ep = 2 + 1;
115         usb_param->mem_base = USB_STACK_MEM_BASE;
116         usb_param->mem_size = USB_STACK_MEM_SIZE;
117
118         desc.device_desc = (uint8_t *) USB_DeviceDescriptor;
119         desc.string_desc = (uint8_t *) USB_StringDescriptor;
120
121         desc.high_speed_desc = USB_FsConfigDescriptor;
122         desc.full_speed_desc = USB_FsConfigDescriptor;
123         desc.device_qualifier = 0;
124
125         ret = USBD_API->hw->Init(&g_usb_hnd, &desc, usb_param);
126         if (ret != LPC_OK) return -1;
127
128         usb_param->mem_base = USB_STACK_MEM_BASE + (USB_STACK_MEM_SIZE - usb_param->mem_size);
129         return 0;
130 }
131
132
133
134 int init_usb_hid (USBD_API_INIT_PARAM_T *usb_param,
135                 HID_GetReport_Func_T getreport_fun, HID_SetReport_Func_T setreport_fun,
136                 HID_EpIn_Hdlr_Func_T epin_hdlr_fun, HID_EpOut_Hdlr_Func_T epout_hdlr_fun,
137                 uint8_t** report_saddr, int report_size) {
138         USBD_HID_INIT_PARAM_T hid_param;
139         USB_HID_REPORT_T reports_data[1];
140         ErrorCode_t ret = LPC_OK;
141
142         memset((void *) &hid_param, 0, sizeof(USBD_HID_INIT_PARAM_T));
143         hid_param.max_reports = 1;
144
145         /* Init reports_data */
146         reports_data[0].len = hid_report_size;
147         reports_data[0].idle_time = 0;
148         reports_data[0].desc = (uint8_t *) &HID_ReportDescriptor[0];
149
150         USB_INTERFACE_DESCRIPTOR *pIntfDesc = (USB_INTERFACE_DESCRIPTOR *) &USB_FsConfigDescriptor[sizeof(USB_CONFIGURATION_DESCRIPTOR)];
151
152         if ((pIntfDesc == 0) || (pIntfDesc->bInterfaceClass != USB_DEVICE_CLASS_HUMAN_INTERFACE)) {
153                 return -1;
154         }
155
156         hid_param.mem_base = usb_param->mem_base;
157         hid_param.mem_size = usb_param->mem_size;
158         hid_param.intf_desc = (uint8_t *) pIntfDesc;
159         /* user defined functions */
160         hid_param.HID_GetReport = getreport_fun;
161         hid_param.HID_SetReport = setreport_fun;
162         hid_param.HID_EpIn_Hdlr  = epin_hdlr_fun;
163         hid_param.HID_EpOut_Hdlr = epout_hdlr_fun;
164         hid_param.report_data  = reports_data;
165
166         ret = USBD_API->hid->init(g_usb_hnd, &hid_param);
167         if (ret != LPC_OK) return -2;
168         /* allocate USB accessable memory space for report data */
169         *report_saddr =  (uint8_t *) hid_param.mem_base;
170         memset (hid_param.mem_base, 0, report_size);
171         hid_param.mem_base += report_size;
172         hid_param.mem_size -= report_size;
173         /* update memory variables */
174         usb_param->mem_base = hid_param.mem_base;
175         usb_param->mem_size = hid_param.mem_size;
176         return 0;
177 }
178
179 void connect_to_usb_bus () {
180         NVIC_EnableIRQ (USB_IRQn);
181         USBD_API->hw->Connect (g_usb_hnd, 1);
182 }
183
184 void disconnect_to_usb_bus () {
185         USBD_API->hw->Connect (g_usb_hnd, 0);
186         NVIC_DisableIRQ (USB_IRQn);
187 }