b0089ebe6d0efe71d2cc2376a290ce57d44abbe6
[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           ccid_card_change_signal (CCID_CARD_INIT);
143         }
144       else
145         {
146           usb_lld_stall_rx (ENDP1);
147           usb_lld_stall_tx (ENDP1);
148           usb_lld_stall_tx (ENDP2);
149         }
150     }
151 #ifdef HID_CARD_CHANGE_SUPPORT
152   else if (interface == HID_INTERFACE)
153     {
154       if (!stop)
155         usb_lld_setup_endpoint (ENDP7, EP_INTERRUPT, 0, 0, ENDP7_TXADDR, 0);
156       else
157         usb_lld_stall_tx (ENDP7);
158     }
159 #endif
160 #ifdef ENABLE_VIRTUAL_COM_PORT
161   else if (interface == VCOM_INTERFACE_0)
162     {
163       if (!stop)
164         usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
165       else
166         usb_lld_stall_tx (ENDP4);
167     }
168   else if (interface == VCOM_INTERFACE_1)
169     {
170       if (!stop)
171         {
172           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
173           usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
174                                   VIRTUAL_COM_PORT_DATA_SIZE);
175         }
176       else
177         {
178           usb_lld_stall_tx (ENDP3);
179           usb_lld_stall_rx (ENDP5);
180         }
181     }
182 #endif
183 #ifdef PINPAD_DND_SUPPORT
184   else if (interface == MSC_INTERFACE)
185     {
186       if (!stop)
187         usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
188                                 ENDP6_RXADDR, ENDP6_TXADDR, 64);
189       else
190         {
191           usb_lld_stall_tx (ENDP6);
192           usb_lld_stall_rx (ENDP6);
193         }
194     }
195 #endif
196 }
197
198 void
199 usb_cb_device_reset (void)
200 {
201   int i;
202
203   /* Set DEVICE as not configured */
204   usb_lld_set_configuration (0);
205
206   /* Current Feature initialization */
207   usb_lld_set_feature (USB_INITIAL_FEATURE);
208
209   usb_lld_reset ();
210
211   /* Initialize Endpoint 0 */
212   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
213                           GNUK_MAX_PACKET_SIZE);
214
215   for (i = 0; i < NUM_INTERFACES; i++)
216     gnuk_setup_endpoints_for_interface (i, 0);
217
218   bDeviceState = ATTACHED;
219 }
220
221 #define USB_CCID_REQ_ABORT                      0x01
222 #define USB_CCID_REQ_GET_CLOCK_FREQUENCIES      0x02
223 #define USB_CCID_REQ_GET_DATA_RATES             0x03
224
225 static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
226
227 static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
228
229 #if defined(PINPAD_DND_SUPPORT)
230 static const uint8_t lun_table[] = { 0, 0, 0, 0, };
231 #endif
232
233 static const uint8_t *const mem_info[] = { &_regnual_start,  __heap_end__, };
234
235 #define USB_FSIJ_GNUK_MEMINFO     0
236 #define USB_FSIJ_GNUK_DOWNLOAD    1
237 #define USB_FSIJ_GNUK_EXEC        2
238 #define USB_FSIJ_GNUK_CARD_CHANGE 3
239
240 static uint32_t rbit (uint32_t v)
241 {
242   uint32_t r;
243
244   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
245   return r;
246 }
247
248 /* After calling this function, CRC module remain enabled.  */
249 static int download_check_crc32 (const uint32_t *end_p)
250 {
251   uint32_t crc32 = *end_p;
252   const uint32_t *p;
253
254   RCC->AHBENR |= RCC_AHBENR_CRCEN;
255   CRC->CR = CRC_CR_RESET;
256
257   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
258     CRC->DR = rbit (*p);
259
260   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
261     return USB_SUCCESS;
262
263   return USB_UNSUPPORT;
264 }
265
266 int
267 usb_cb_setup (uint8_t req, uint8_t req_no,
268               uint16_t value, uint16_t index, uint16_t len)
269 {
270   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
271
272   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
273     {
274       if (USB_SETUP_GET (req))
275         {
276           if (req_no == USB_FSIJ_GNUK_MEMINFO)
277             {
278               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
279               return USB_SUCCESS;
280             }
281         }
282       else /* SETUP_SET */
283         {
284           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
285
286           if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
287             {
288               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
289                 return USB_UNSUPPORT;
290
291               if (addr < &_regnual_start || addr + len > __heap_end__)
292                 return USB_UNSUPPORT;
293
294               if (index + len < 256)
295                 memset (addr + index + len, 0, 256 - (index + len));
296
297               usb_lld_set_data_to_recv (addr, len);
298               return USB_SUCCESS;
299             }
300           else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
301             {
302               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
303                 return USB_UNSUPPORT;
304
305               if (((uint32_t)addr & 0x03))
306                 return USB_UNSUPPORT;
307
308               return download_check_crc32 ((uint32_t *)addr);
309             }
310           else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && len == 0)
311             {
312               if (value != 0 && value != 1 && value != 2)
313                 return USB_UNSUPPORT;
314
315               ccid_card_change_signal (value);
316               return USB_SUCCESS;
317             }
318         }
319     }
320   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
321     {
322       if (index == ICC_INTERFACE)
323         {
324           if (USB_SETUP_GET (req))
325             {
326               if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
327                 {
328                   usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
329                   return USB_SUCCESS;
330                 }
331               else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
332                 {
333                   usb_lld_set_data_to_send (data_rate_table,
334                                             sizeof (data_rate_table));
335                   return USB_SUCCESS;
336                 }
337             }
338           else
339             {
340               if (req_no == USB_CCID_REQ_ABORT)
341                 /* wValue: bSeq, bSlot */
342                 /* Abortion is not supported in Gnuk */
343                 return USB_UNSUPPORT;
344             }
345         }
346 #ifdef HID_CARD_CHANGE_SUPPORT
347       else if (index == HID_INTERFACE)
348         {
349           switch (req_no)
350             {
351             case USB_HID_REQ_GET_IDLE:
352               usb_lld_set_data_to_send (&hid_idle_rate, 1);
353               return USB_SUCCESS;
354             case USB_HID_REQ_SET_IDLE:
355               usb_lld_set_data_to_recv (&hid_idle_rate, 1);
356               return USB_SUCCESS;
357
358             case USB_HID_REQ_GET_REPORT:
359               /* Request of LED status and key press */
360               usb_lld_set_data_to_send (&hid_report, 2);
361               return USB_SUCCESS;
362
363             case USB_HID_REQ_SET_REPORT:
364               /* Received LED set request */
365               if (len == 1)
366                 usb_lld_set_data_to_recv (&hid_report, len);
367               return USB_SUCCESS;
368
369             case USB_HID_REQ_GET_PROTOCOL:
370             case USB_HID_REQ_SET_PROTOCOL:
371               /* This driver doesn't support boot protocol.  */
372               return USB_UNSUPPORT;
373
374             default:
375               return USB_UNSUPPORT;
376             }
377         }
378 #endif
379 #ifdef ENABLE_VIRTUAL_COM_PORT
380       else if (index == VCOM_INTERFACE_0)
381         return vcom_port_data_setup (req, req_no, value);
382 #endif
383 #ifdef PINPAD_DND_SUPPORT
384       else if (index == MSC_INTERFACE)
385         {
386           if (USB_SETUP_GET (req))
387             {
388               if (req_no == MSC_GET_MAX_LUN_COMMAND)
389                 {
390                   usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
391                   return USB_SUCCESS;
392                 }
393             }
394           else
395             if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
396               /* Should call resetting MSC thread, something like msc_reset() */
397               return USB_SUCCESS;
398         }
399 #endif
400     }
401
402   return USB_UNSUPPORT;
403 }
404
405
406 void
407 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
408                           uint16_t index, uint16_t len)
409 {
410   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
411
412   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
413     {
414       if (USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
415         {
416           if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
417             return;
418
419           (void)value; (void)index;
420           usb_lld_prepare_shutdown (); /* No further USB communication */
421           *icc_state_p = ICC_STATE_EXEC_REQUESTED;
422         }
423     }
424 #ifdef HID_CARD_CHANGE_SUPPORT
425   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
426     {
427       if (index == HID_INTERFACE && req_no == USB_HID_REQ_SET_REPORT)
428         {
429           if ((hid_report ^ hid_report_saved) & HID_LED_STATUS_CARDCHANGE)
430             ccid_card_change_signal (CARD_CHANGE_TOGGLE);
431
432           hid_report_saved = hid_report;
433         }
434     }
435 #endif
436 }
437
438
439 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
440 {
441   int i;
442   uint8_t current_conf;
443
444   switch (event_type)
445     {
446     case USB_EVENT_ADDRESS:
447       bDeviceState = ADDRESSED;
448       return USB_SUCCESS;
449     case USB_EVENT_CONFIG:
450       current_conf = usb_lld_current_configuration ();
451       if (current_conf == 0)
452         {
453           if (value != 1)
454             return USB_UNSUPPORT;
455
456           usb_lld_set_configuration (value);
457           for (i = 0; i < NUM_INTERFACES; i++)
458             gnuk_setup_endpoints_for_interface (i, 0);
459           bDeviceState = CONFIGURED;
460         }
461       else if (current_conf != value)
462         {
463           if (value != 0)
464             return USB_UNSUPPORT;
465
466           usb_lld_set_configuration (0);
467           for (i = 0; i < NUM_INTERFACES; i++)
468             gnuk_setup_endpoints_for_interface (i, 1);
469           bDeviceState = ADDRESSED;
470         }
471       /* Do nothing when current_conf == value */
472       return USB_SUCCESS;
473     default:
474       break;
475     }
476
477   return USB_UNSUPPORT;
478 }
479
480 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
481 {
482   static const uint8_t zero = 0;
483
484   if (interface >= NUM_INTERFACES)
485     return USB_UNSUPPORT;
486
487   switch (cmd)
488     {
489     case USB_SET_INTERFACE:
490       if (alt != 0)
491         return USB_UNSUPPORT;
492       else
493         {
494           gnuk_setup_endpoints_for_interface (interface, 0);
495           return USB_SUCCESS;
496         }
497
498     case USB_GET_INTERFACE:
499       usb_lld_set_data_to_send (&zero, 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 }