01e71398836949f1996dee0bf3531b00105ec64f
[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         {
67           usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
68           return USB_SUCCESS;
69         }
70     }
71   else  /* USB_SETUP_SET (req) */
72     {
73       if (req_no == USB_CDC_REQ_SET_LINE_CODING)
74         {
75           usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
76           return USB_SUCCESS;
77         }
78       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
79         {
80           uint8_t connected_saved = stdout.connected;
81
82           if (value != 0)
83             {
84               if (stdout.connected == 0)
85                 /* It's Open call */
86                 stdout.connected++;
87             }
88           else
89             {
90               if (stdout.connected)
91                 /* Close call */
92                 stdout.connected = 0;
93             }
94
95           chopstx_mutex_lock (&stdout.m_dev);
96           if (stdout.connected != connected_saved)
97             chopstx_cond_signal (&stdout.cond_dev);
98           chopstx_mutex_unlock (&stdout.m_dev);
99
100           return USB_SUCCESS;
101         }
102     }
103
104   return USB_UNSUPPORT;
105 }
106 #endif
107
108 #ifdef PINPAD_DND_SUPPORT
109 #include "usb-msc.h"
110 #endif
111
112 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
113
114 #define USB_HID_REQ_GET_REPORT   1
115 #define USB_HID_REQ_GET_IDLE     2
116 #define USB_HID_REQ_GET_PROTOCOL 3
117 #define USB_HID_REQ_SET_REPORT   9
118 #define USB_HID_REQ_SET_IDLE     10
119 #define USB_HID_REQ_SET_PROTOCOL 11
120
121 #ifndef HID_LED_STATUS_CARDCHANGE
122 /* NumLock=1, CapsLock=2, ScrollLock=4 */
123 #define HID_LED_STATUS_CARDCHANGE 0x04
124 #endif
125
126 #ifdef HID_CARD_CHANGE_SUPPORT
127 static uint8_t hid_idle_rate;   /* in 4ms */
128 static uint8_t hid_report_saved;
129 static uint16_t hid_report;
130 #endif
131
132 static void
133 gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
134 {
135   if (interface == ICC_INTERFACE)
136     {
137       if (!stop)
138         {
139           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR,
140                                   ENDP1_TXADDR, GNUK_MAX_PACKET_SIZE);
141           usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
142         }
143       else
144         {
145           usb_lld_stall_rx (ENDP1);
146           usb_lld_stall_tx (ENDP1);
147           usb_lld_stall_tx (ENDP2);
148         }
149     }
150 #ifdef HID_CARD_CHANGE_SUPPORT
151   else if (interface == HID_INTERFACE)
152     {
153       if (!stop)
154         usb_lld_setup_endpoint (ENDP7, EP_INTERRUPT, 0, 0, ENDP7_TXADDR, 0);
155       else
156         usb_lld_stall_tx (ENDP7);
157     }
158 #endif
159 #ifdef ENABLE_VIRTUAL_COM_PORT
160   else if (interface == VCOM_INTERFACE_0)
161     {
162       if (!stop)
163         usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
164       else
165         usb_lld_stall_tx (ENDP4);
166     }
167   else if (interface == VCOM_INTERFACE_1)
168     {
169       if (!stop)
170         {
171           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
172           usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
173                                   VIRTUAL_COM_PORT_DATA_SIZE);
174         }
175       else
176         {
177           usb_lld_stall_tx (ENDP3);
178           usb_lld_stall_rx (ENDP5);
179         }
180     }
181 #endif
182 #ifdef PINPAD_DND_SUPPORT
183   else if (interface == MSC_INTERFACE)
184     {
185       if (!stop)
186         usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
187                                 ENDP6_RXADDR, ENDP6_TXADDR, 64);
188       else
189         {
190           usb_lld_stall_tx (ENDP6);
191           usb_lld_stall_rx (ENDP6);
192         }
193     }
194 #endif
195 }
196
197 void
198 usb_cb_device_reset (void)
199 {
200   int i;
201
202   /* Set DEVICE as not configured */
203   usb_lld_set_configuration (0);
204
205   /* Current Feature initialization */
206   usb_lld_set_feature (USB_INITIAL_FEATURE);
207
208   usb_lld_reset ();
209
210   /* Initialize Endpoint 0 */
211   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
212                           GNUK_MAX_PACKET_SIZE);
213
214   for (i = 0; i < NUM_INTERFACES; i++)
215     gnuk_setup_endpoints_for_interface (i, 0);
216
217   bDeviceState = ATTACHED;
218 }
219
220 #define USB_CCID_REQ_ABORT                      0x01
221 #define USB_CCID_REQ_GET_CLOCK_FREQUENCIES      0x02
222 #define USB_CCID_REQ_GET_DATA_RATES             0x03
223
224 static const uint8_t freq_table[] = { 0xa0, 0x0f, 0, 0, }; /* dwDefaultClock */
225 static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
226
227 #if defined(PINPAD_DND_SUPPORT)
228 static const uint8_t lun_table[] = { 0, 0, 0, 0, };
229 #endif
230
231 static const uint8_t *const mem_info[] = { &_regnual_start,  __heap_end__, };
232
233 #define USB_FSIJ_GNUK_MEMINFO     0
234 #define USB_FSIJ_GNUK_DOWNLOAD    1
235 #define USB_FSIJ_GNUK_EXEC        2
236 #define USB_FSIJ_GNUK_CARD_CHANGE 3
237
238 static uint32_t rbit (uint32_t v)
239 {
240   uint32_t r;
241
242   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
243   return r;
244 }
245
246 /* After calling this function, CRC module remain enabled.  */
247 static int download_check_crc32 (const uint32_t *end_p)
248 {
249   uint32_t crc32 = *end_p;
250   const uint32_t *p;
251
252   RCC->AHBENR |= RCC_AHBENR_CRCEN;
253   CRC->CR = CRC_CR_RESET;
254
255   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
256     CRC->DR = rbit (*p);
257
258   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
259     return USB_SUCCESS;
260
261   return USB_UNSUPPORT;
262 }
263
264 int
265 usb_cb_setup (uint8_t req, uint8_t req_no,
266               uint16_t value, uint16_t index, uint16_t len)
267 {
268   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
269
270   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
271     {
272       if (USB_SETUP_GET (req))
273         {
274           if (req_no == USB_FSIJ_GNUK_MEMINFO)
275             {
276               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
277               return USB_SUCCESS;
278             }
279         }
280       else /* SETUP_SET */
281         {
282           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
283
284           if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
285             {
286               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
287                 return USB_UNSUPPORT;
288
289               if (addr < &_regnual_start || addr + len > __heap_end__)
290                 return USB_UNSUPPORT;
291
292               if (index + len < 256)
293                 memset (addr + index + len, 0, 256 - (index + len));
294
295               usb_lld_set_data_to_recv (addr, len);
296               return USB_SUCCESS;
297             }
298           else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
299             {
300               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
301                 return USB_UNSUPPORT;
302
303               if (((uint32_t)addr & 0x03))
304                 return USB_UNSUPPORT;
305
306               return download_check_crc32 ((uint32_t *)addr);
307             }
308           else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && len == 0)
309             {
310               if (value != 0 && value != 1 && value != 2)
311                 return USB_UNSUPPORT;
312
313               ccid_card_change_signal (value);
314               return USB_SUCCESS;
315             }
316         }
317     }
318   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
319     {
320       if (index == ICC_INTERFACE)
321         {
322           if (USB_SETUP_GET (req))
323             {
324               if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
325                 {
326                   usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
327                   return USB_SUCCESS;
328                 }
329               else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
330                 {
331                   usb_lld_set_data_to_send (data_rate_table,
332                                             sizeof (data_rate_table));
333                   return USB_SUCCESS;
334                 }
335             }
336           else
337             {
338               if (req_no == USB_CCID_REQ_ABORT)
339                 /* wValue: bSeq, bSlot */
340                 /* Abortion is not supported in Gnuk */
341                 return USB_UNSUPPORT;
342             }
343         }
344 #ifdef HID_CARD_CHANGE_SUPPORT
345       else if (index == HID_INTERFACE)
346         {
347           switch (req_no)
348             {
349             case USB_HID_REQ_GET_IDLE:
350               usb_lld_set_data_to_send (&hid_idle_rate, 1);
351               return USB_SUCCESS;
352             case USB_HID_REQ_SET_IDLE:
353               usb_lld_set_data_to_recv (&hid_idle_rate, 1);
354               return USB_SUCCESS;
355
356             case USB_HID_REQ_GET_REPORT:
357               /* Request of LED status and key press */
358               usb_lld_set_data_to_send (&hid_report, 2);
359               return USB_SUCCESS;
360
361             case USB_HID_REQ_SET_REPORT:
362               /* Received LED set request */
363               if (len == 1)
364                 usb_lld_set_data_to_recv (&hid_report, len);
365               return USB_SUCCESS;
366
367             case USB_HID_REQ_GET_PROTOCOL:
368             case USB_HID_REQ_SET_PROTOCOL:
369               /* This driver doesn't support boot protocol.  */
370               return USB_UNSUPPORT;
371
372             default:
373               return USB_UNSUPPORT;
374             }
375         }
376 #endif
377 #ifdef ENABLE_VIRTUAL_COM_PORT
378       else if (index == VCOM_INTERFACE_0)
379         return vcom_port_data_setup (req, req_no, value);
380 #endif
381 #ifdef PINPAD_DND_SUPPORT
382       else if (index == MSC_INTERFACE)
383         {
384           if (USB_SETUP_GET (req))
385             {
386               if (req_no == MSC_GET_MAX_LUN_COMMAND)
387                 {
388                   usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
389                   return USB_SUCCESS;
390                 }
391             }
392           else
393             if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
394               /* Should call resetting MSC thread, something like msc_reset() */
395               return USB_SUCCESS;
396         }
397 #endif
398     }
399
400   return USB_UNSUPPORT;
401 }
402
403
404 void
405 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
406                           uint16_t index, uint16_t len)
407 {
408   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
409
410   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
411     {
412       if (USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
413         {
414           if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
415             return;
416
417           (void)value; (void)index;
418           usb_lld_prepare_shutdown (); /* No further USB communication */
419           *icc_state_p = ICC_STATE_EXEC_REQUESTED;
420         }
421     }
422 #ifdef HID_CARD_CHANGE_SUPPORT
423   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
424     {
425       if (index == HID_INTERFACE && req_no == USB_HID_REQ_SET_REPORT)
426         {
427           if ((hid_report ^ hid_report_saved) & HID_LED_STATUS_CARDCHANGE)
428             ccid_card_change_signal (CARD_CHANGE_TOGGLE);
429
430           hid_report_saved = hid_report;
431         }
432     }
433 #endif
434 }
435
436
437 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
438 {
439   int i;
440   uint8_t current_conf;
441
442   switch (event_type)
443     {
444     case USB_EVENT_ADDRESS:
445       bDeviceState = ADDRESSED;
446       return USB_SUCCESS;
447     case USB_EVENT_CONFIG:
448       current_conf = usb_lld_current_configuration ();
449       if (current_conf == 0)
450         {
451           if (value != 1)
452             return USB_UNSUPPORT;
453
454           usb_lld_set_configuration (value);
455           for (i = 0; i < NUM_INTERFACES; i++)
456             gnuk_setup_endpoints_for_interface (i, 0);
457           ccid_card_change_signal (CCID_CARD_INIT);
458           bDeviceState = CONFIGURED;
459         }
460       else if (current_conf != value)
461         {
462           if (value != 0)
463             return USB_UNSUPPORT;
464
465           usb_lld_set_configuration (0);
466           for (i = 0; i < NUM_INTERFACES; i++)
467             gnuk_setup_endpoints_for_interface (i, 1);
468           bDeviceState = ADDRESSED;
469         }
470       /* Do nothing when current_conf == value */
471       return USB_SUCCESS;
472     default:
473       break;
474     }
475
476   return USB_UNSUPPORT;
477 }
478
479 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
480 {
481   const uint8_t zero = 0;
482
483   if (interface >= NUM_INTERFACES)
484     return USB_UNSUPPORT;
485
486   switch (cmd)
487     {
488     case USB_SET_INTERFACE:
489       if (alt != 0)
490         return USB_UNSUPPORT;
491       else
492         {
493           gnuk_setup_endpoints_for_interface (interface, 0);
494           return USB_SUCCESS;
495         }
496
497     case USB_GET_INTERFACE:
498       usb_lld_write (ENDP0, &zero, 1);
499       usb_lld_set_data_to_send (NULL, 1);
500       return USB_SUCCESS;
501
502     default:
503     case USB_QUERY_INTERFACE:
504       return USB_SUCCESS;
505     }
506 }
507
508
509 #define INTR_REQ_USB 20
510
511 void *
512 usb_intr (void *arg)
513 {
514   chopstx_intr_t interrupt;
515
516   (void)arg;
517   usb_lld_init (USB_INITIAL_FEATURE);
518   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
519   usb_interrupt_handler ();
520
521   while (1)
522     {
523       chopstx_intr_wait (&interrupt);
524
525       /* Process interrupt. */
526       usb_interrupt_handler ();
527     }
528
529   return NULL;
530 }