USB driver update
[gnuk/gnuk.git] / src / usb_ctrl.c
1 /*
2  * usb_ctrl.c - USB control pipe device specific code for Gnuk
3  *
4  * Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
5  * Author: NIIBE Yutaka <gniibe@fsij.org>
6  *
7  * This file is a part of Gnuk, a GnuPG USB Token implementation.
8  *
9  * Gnuk is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /* Packet size of USB Bulk transfer for full speed */
25 #define GNUK_MAX_PACKET_SIZE 64
26
27 #include <stdint.h>
28 #include <string.h>
29 #include <chopstx.h>
30
31 #include "config.h"
32
33 #ifdef DEBUG
34 #include "debug.h"
35 #endif
36
37 #include "usb_lld.h"
38 #include "usb_conf.h"
39 #include "gnuk.h"
40 #include "stm32f103.h"
41
42 #ifdef ENABLE_VIRTUAL_COM_PORT
43 #include "usb-cdc.h"
44
45 struct line_coding
46 {
47   uint32_t bitrate;
48   uint8_t format;
49   uint8_t paritytype;
50   uint8_t datatype;
51 };
52
53 static struct line_coding line_coding = {
54   115200, /* baud rate: 115200    */
55   0x00,   /* stop bits: 1         */
56   0x00,   /* parity:    none      */
57   0x08    /* bits:      8         */
58 };
59
60 static int
61 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
62 {
63   if (USB_SETUP_GET (req))
64     {
65       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
66         return usb_lld_answer_control (&line_coding, sizeof(line_coding));
67     }
68   else  /* USB_SETUP_SET (req) */
69     {
70       if (req_no == USB_CDC_REQ_SET_LINE_CODING)
71         {
72           usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
73           return USB_SUCCESS;
74         }
75       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
76         {
77           uint8_t connected_saved = stdout.connected;
78
79           if (value != 0)
80             {
81               if (stdout.connected == 0)
82                 /* It's Open call */
83                 stdout.connected++;
84             }
85           else
86             {
87               if (stdout.connected)
88                 /* Close call */
89                 stdout.connected = 0;
90             }
91
92           chopstx_mutex_lock (&stdout.m_dev);
93           if (stdout.connected != connected_saved)
94             chopstx_cond_signal (&stdout.cond_dev);
95           chopstx_mutex_unlock (&stdout.m_dev);
96
97           return USB_SUCCESS;
98         }
99     }
100
101   return USB_UNSUPPORT;
102 }
103 #endif
104
105 #ifdef PINPAD_DND_SUPPORT
106 #include "usb-msc.h"
107 #endif
108
109 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
110
111 #define USB_HID_REQ_GET_REPORT   1
112 #define USB_HID_REQ_GET_IDLE     2
113 #define USB_HID_REQ_GET_PROTOCOL 3
114 #define USB_HID_REQ_SET_REPORT   9
115 #define USB_HID_REQ_SET_IDLE     10
116 #define USB_HID_REQ_SET_PROTOCOL 11
117
118 #ifndef HID_LED_STATUS_CARDCHANGE
119 /* NumLock=1, CapsLock=2, ScrollLock=4 */
120 #define HID_LED_STATUS_CARDCHANGE 0x04
121 #endif
122
123 #ifdef HID_CARD_CHANGE_SUPPORT
124 static uint8_t hid_idle_rate;   /* in 4ms */
125 static uint8_t hid_report_saved;
126 static uint16_t hid_report;
127 #endif
128
129 static void
130 gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
131 {
132   if (interface == ICC_INTERFACE)
133     {
134       if (!stop)
135         {
136           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR,
137                                   ENDP1_TXADDR, GNUK_MAX_PACKET_SIZE);
138           usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
139         }
140       else
141         {
142           usb_lld_stall_rx (ENDP1);
143           usb_lld_stall_tx (ENDP1);
144           usb_lld_stall_tx (ENDP2);
145         }
146     }
147 #ifdef HID_CARD_CHANGE_SUPPORT
148   else if (interface == HID_INTERFACE)
149     {
150       if (!stop)
151         usb_lld_setup_endpoint (ENDP7, EP_INTERRUPT, 0, 0, ENDP7_TXADDR, 0);
152       else
153         usb_lld_stall_tx (ENDP7);
154     }
155 #endif
156 #ifdef ENABLE_VIRTUAL_COM_PORT
157   else if (interface == VCOM_INTERFACE_0)
158     {
159       if (!stop)
160         usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
161       else
162         usb_lld_stall_tx (ENDP4);
163     }
164   else if (interface == VCOM_INTERFACE_1)
165     {
166       if (!stop)
167         {
168           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
169           usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
170                                   VIRTUAL_COM_PORT_DATA_SIZE);
171         }
172       else
173         {
174           usb_lld_stall_tx (ENDP3);
175           usb_lld_stall_rx (ENDP5);
176         }
177     }
178 #endif
179 #ifdef PINPAD_DND_SUPPORT
180   else if (interface == MSC_INTERFACE)
181     {
182       if (!stop)
183         usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
184                                 ENDP6_RXADDR, ENDP6_TXADDR, 64);
185       else
186         {
187           usb_lld_stall_tx (ENDP6);
188           usb_lld_stall_rx (ENDP6);
189         }
190     }
191 #endif
192 }
193
194 void
195 usb_cb_device_reset (void)
196 {
197   int i;
198
199   /* Set DEVICE as not configured */
200   usb_lld_set_configuration (0);
201
202   /* Current Feature initialization */
203   usb_lld_set_feature (USB_INITIAL_FEATURE);
204
205   usb_lld_reset ();
206
207   /* Initialize Endpoint 0 */
208   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
209                           GNUK_MAX_PACKET_SIZE);
210
211   for (i = 0; i < NUM_INTERFACES; i++)
212     gnuk_setup_endpoints_for_interface (i, 0);
213
214   bDeviceState = ATTACHED;
215 }
216
217 #define USB_CCID_REQ_ABORT                      0x01
218 #define USB_CCID_REQ_GET_CLOCK_FREQUENCIES      0x02
219 #define USB_CCID_REQ_GET_DATA_RATES             0x03
220
221 static const uint8_t freq_table[] = { 0xa0, 0x0f, 0, 0, }; /* dwDefaultClock */
222 static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
223
224 #if defined(PINPAD_DND_SUPPORT)
225 static const uint8_t lun_table[] = { 0, 0, 0, 0, };
226 #endif
227
228 static const uint8_t *const mem_info[] = { &_regnual_start,  __heap_end__, };
229
230 #define USB_FSIJ_GNUK_MEMINFO     0
231 #define USB_FSIJ_GNUK_DOWNLOAD    1
232 #define USB_FSIJ_GNUK_EXEC        2
233 #define USB_FSIJ_GNUK_CARD_CHANGE 3
234
235 static uint32_t rbit (uint32_t v)
236 {
237   uint32_t r;
238
239   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
240   return r;
241 }
242
243 /* After calling this function, CRC module remain enabled.  */
244 static int download_check_crc32 (const uint32_t *end_p)
245 {
246   uint32_t crc32 = *end_p;
247   const uint32_t *p;
248
249   RCC->AHBENR |= RCC_AHBENR_CRCEN;
250   CRC->CR = CRC_CR_RESET;
251
252   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
253     CRC->DR = rbit (*p);
254
255   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
256     return USB_SUCCESS;
257
258   return USB_UNSUPPORT;
259 }
260
261 int
262 usb_cb_setup (uint8_t req, uint8_t req_no,
263               uint16_t value, uint16_t index, uint16_t len)
264 {
265   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
266
267   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
268     {
269       if (USB_SETUP_GET (req))
270         {
271           if (req_no == USB_FSIJ_GNUK_MEMINFO)
272             return usb_lld_answer_control (mem_info, sizeof (mem_info));
273         }
274       else /* SETUP_SET */
275         {
276           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
277
278           if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
279             {
280               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
281                 return USB_UNSUPPORT;
282
283               if (addr < &_regnual_start || addr + len > __heap_end__)
284                 return USB_UNSUPPORT;
285
286               if (index + len < 256)
287                 memset (addr + index + len, 0, 256 - (index + len));
288
289               usb_lld_set_data_to_recv (addr, len);
290               return USB_SUCCESS;
291             }
292           else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
293             {
294               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
295                 return USB_UNSUPPORT;
296
297               if (((uint32_t)addr & 0x03))
298                 return USB_UNSUPPORT;
299
300               return download_check_crc32 ((uint32_t *)addr);
301             }
302           else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && len == 0)
303             {
304               if (value != 0 && value != 1 && value != 2)
305                 return USB_UNSUPPORT;
306
307               ccid_card_change_signal (value);
308               return USB_SUCCESS;
309             }
310         }
311     }
312   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
313     {
314       if (index == ICC_INTERFACE)
315         {
316           if (USB_SETUP_GET (req))
317             {
318               if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
319                 return usb_lld_answer_control (freq_table, sizeof (freq_table));
320               else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
321                 return usb_lld_answer_control (data_rate_table,
322                                                sizeof (data_rate_table));
323             }
324           else
325             {
326               if (req_no == USB_CCID_REQ_ABORT)
327                 /* wValue: bSeq, bSlot */
328                 /* Abortion is not supported in Gnuk */
329                 return USB_UNSUPPORT;
330             }
331         }
332 #ifdef HID_CARD_CHANGE_SUPPORT
333       else if (index == HID_INTERFACE)
334         {
335           switch (req_no)
336             {
337             case USB_HID_REQ_GET_IDLE:
338               return usb_lld_answer_control (&hid_idle_rate, 1);
339             case USB_HID_REQ_SET_IDLE:
340               usb_lld_set_data_to_recv (&hid_idle_rate, 1);
341               return USB_SUCCESS;
342
343             case USB_HID_REQ_GET_REPORT:
344               /* Request of LED status and key press */
345               return usb_lld_answer_control (&hid_report, 2);
346
347             case USB_HID_REQ_SET_REPORT:
348               /* Received LED set request */
349               if (len == 1)
350                 usb_lld_set_data_to_recv (&hid_report, len);
351               return USB_SUCCESS;
352
353             case USB_HID_REQ_GET_PROTOCOL:
354             case USB_HID_REQ_SET_PROTOCOL:
355               /* This driver doesn't support boot protocol.  */
356               return USB_UNSUPPORT;
357
358             default:
359               return USB_UNSUPPORT;
360             }
361         }
362 #endif
363 #ifdef ENABLE_VIRTUAL_COM_PORT
364       else if (index == VCOM_INTERFACE_0)
365         return vcom_port_data_setup (req, req_no, value);
366 #endif
367 #ifdef PINPAD_DND_SUPPORT
368       else if (index == MSC_INTERFACE)
369         {
370           if (USB_SETUP_GET (req))
371             {
372               if (req_no == MSC_GET_MAX_LUN_COMMAND)
373                 return usb_lld_answer_control (lun_table, sizeof (lun_table));
374             }
375           else
376             if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
377               /* Should call resetting MSC thread, something like msc_reset() */
378               return USB_SUCCESS;
379         }
380 #endif
381     }
382
383   return USB_UNSUPPORT;
384 }
385
386
387 void
388 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
389                           uint16_t index, uint16_t len)
390 {
391   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
392
393   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
394     {
395       if (USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
396         {
397           if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
398             return;
399
400           (void)value; (void)index;
401           usb_lld_prepare_shutdown (); /* No further USB communication */
402           *icc_state_p = ICC_STATE_EXEC_REQUESTED;
403         }
404     }
405 #ifdef HID_CARD_CHANGE_SUPPORT
406   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
407     {
408       if (index == HID_INTERFACE && req_no == USB_HID_REQ_SET_REPORT)
409         {
410           if ((hid_report ^ hid_report_saved) & HID_LED_STATUS_CARDCHANGE)
411             ccid_card_change_signal (CARD_CHANGE_TOGGLE);
412
413           hid_report_saved = hid_report;
414         }
415     }
416 #endif
417 }
418
419
420 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
421 {
422   int i;
423   uint8_t current_conf;
424
425   switch (event_type)
426     {
427     case USB_EVENT_ADDRESS:
428       bDeviceState = ADDRESSED;
429       return USB_SUCCESS;
430     case USB_EVENT_CONFIG:
431       current_conf = usb_lld_current_configuration ();
432       if (current_conf == 0)
433         {
434           if (value != 1)
435             return USB_UNSUPPORT;
436
437           usb_lld_set_configuration (value);
438           for (i = 0; i < NUM_INTERFACES; i++)
439             gnuk_setup_endpoints_for_interface (i, 0);
440           ccid_card_change_signal (CCID_CARD_INIT);
441           bDeviceState = CONFIGURED;
442         }
443       else if (current_conf != value)
444         {
445           if (value != 0)
446             return USB_UNSUPPORT;
447
448           usb_lld_set_configuration (0);
449           for (i = 0; i < NUM_INTERFACES; i++)
450             gnuk_setup_endpoints_for_interface (i, 1);
451           bDeviceState = ADDRESSED;
452         }
453       /* Do nothing when current_conf == value */
454       return USB_SUCCESS;
455     default:
456       break;
457     }
458
459   return USB_UNSUPPORT;
460 }
461
462 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
463 {
464   const uint8_t zero = 0;
465
466   if (interface >= NUM_INTERFACES)
467     return USB_UNSUPPORT;
468
469   switch (cmd)
470     {
471     case USB_SET_INTERFACE:
472       if (alt != 0)
473         return USB_UNSUPPORT;
474       else
475         {
476           gnuk_setup_endpoints_for_interface (interface, 0);
477           return USB_SUCCESS;
478         }
479
480     case USB_GET_INTERFACE:
481       return usb_lld_answer_control (&zero, 1);
482
483     default:
484     case USB_QUERY_INTERFACE:
485       return USB_SUCCESS;
486     }
487 }
488
489
490 #define INTR_REQ_USB 20
491
492 void *
493 usb_intr (void *arg)
494 {
495   chopstx_intr_t interrupt;
496
497   (void)arg;
498   usb_lld_init (USB_INITIAL_FEATURE);
499   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
500   usb_interrupt_handler ();
501
502   while (1)
503     {
504       chopstx_intr_wait (&interrupt);
505
506       /* Process interrupt. */
507       usb_interrupt_handler ();
508     }
509
510   return NULL;
511 }