More USB driver change
[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, struct control_info *detail)
62 {
63   if (USB_SETUP_GET (req))
64     {
65       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
66         return usb_lld_reply_request (&line_coding, sizeof(line_coding), detail);
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 (detail->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, struct control_info *detail)
263 {
264   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
265
266   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
267     {
268       if (USB_SETUP_GET (req))
269         {
270           if (req_no == USB_FSIJ_GNUK_MEMINFO)
271             return usb_lld_reply_request (mem_info, sizeof (mem_info), detail);
272         }
273       else /* SETUP_SET */
274         {
275           uint8_t *addr = (uint8_t *)(0x20000000 + detail->value * 0x100 + detail->index);
276
277           if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
278             {
279               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
280                 return USB_UNSUPPORT;
281
282               if (addr < &_regnual_start || addr + detail->len > __heap_end__)
283                 return USB_UNSUPPORT;
284
285               if (detail->index + detail->len < 256)
286                 memset (addr + detail->index + detail->len, 0, 256 - (detail->index + detail->len));
287
288               usb_lld_set_data_to_recv (addr, detail->len);
289               return USB_SUCCESS;
290             }
291           else if (req_no == USB_FSIJ_GNUK_EXEC && detail->len == 0)
292             {
293               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
294                 return USB_UNSUPPORT;
295
296               if (((uint32_t)addr & 0x03))
297                 return USB_UNSUPPORT;
298
299               return download_check_crc32 ((uint32_t *)addr);
300             }
301           else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && detail->len == 0)
302             {
303               if (detail->value != 0 && detail->value != 1 && detail->value != 2)
304                 return USB_UNSUPPORT;
305
306               ccid_card_change_signal (detail->value);
307               return USB_SUCCESS;
308             }
309         }
310     }
311   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
312     {
313       if (detail->index == ICC_INTERFACE)
314         {
315           if (USB_SETUP_GET (req))
316             {
317               if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
318                 return usb_lld_reply_request (freq_table, sizeof (freq_table),
319                                               detail);
320               else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
321                 return usb_lld_reply_request (data_rate_table,
322                                               sizeof (data_rate_table), detail);
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_reply_request (&hid_idle_rate, 1, detail);
339             case USB_HID_REQ_SET_IDLE:
340               usb_lld_set_data_to_recv (&hid_idle_rate, 1, detail);
341               return USB_SUCCESS;
342
343             case USB_HID_REQ_GET_REPORT:
344               /* Request of LED status and key press */
345               return usb_lld_reply_request (&hid_report, 2, detail);
346
347             case USB_HID_REQ_SET_REPORT:
348               /* Received LED set request */
349               if (detail->len == 1)
350                 usb_lld_set_data_to_recv (&hid_report, detail->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, detail);
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_reply_request (lun_table, sizeof (lun_table),
374                                               detail);
375             }
376           else
377             if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
378               /* Should call resetting MSC thread, something like msc_reset() */
379               return USB_SUCCESS;
380         }
381 #endif
382     }
383
384   return USB_UNSUPPORT;
385 }
386
387
388 void
389 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value)
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)
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, struct control_info *detail)
463 {
464   const uint8_t zero = 0;
465   uint16_t interface = detail->index;
466   uint16_t alt = detail->value;
467
468   if (interface >= NUM_INTERFACES)
469     return USB_UNSUPPORT;
470
471   switch (cmd)
472     {
473     case USB_SET_INTERFACE:
474       if (alt != 0)
475         return USB_UNSUPPORT;
476       else
477         {
478           gnuk_setup_endpoints_for_interface (interface, 0);
479           return USB_SUCCESS;
480         }
481
482     case USB_GET_INTERFACE:
483       return usb_lld_reply_request (&zero, 1, detail);
484
485     case USB_QUERY_INTERFACE:
486     default:
487       return USB_SUCCESS;
488     }
489 }
490
491
492 #define INTR_REQ_USB 20
493
494 void *
495 usb_intr (void *arg)
496 {
497   chopstx_intr_t interrupt;
498
499   (void)arg;
500   usb_lld_init (USB_INITIAL_FEATURE);
501   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
502   usb_interrupt_handler ();
503
504   while (1)
505     {
506       chopstx_intr_wait (&interrupt);
507
508       /* Process interrupt. */
509       usb_interrupt_handler ();
510     }
511
512   return NULL;
513 }