USB clean up
[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[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
225
226 static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
227
228 #if defined(PINPAD_DND_SUPPORT)
229 static const uint8_t lun_table[] = { 0, 0, 0, 0, };
230 #endif
231
232 static const uint8_t *const mem_info[] = { &_regnual_start,  __heap_end__, };
233
234 #define USB_FSIJ_GNUK_MEMINFO     0
235 #define USB_FSIJ_GNUK_DOWNLOAD    1
236 #define USB_FSIJ_GNUK_EXEC        2
237 #define USB_FSIJ_GNUK_CARD_CHANGE 3
238
239 static uint32_t rbit (uint32_t v)
240 {
241   uint32_t r;
242
243   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
244   return r;
245 }
246
247 /* After calling this function, CRC module remain enabled.  */
248 static int download_check_crc32 (const uint32_t *end_p)
249 {
250   uint32_t crc32 = *end_p;
251   const uint32_t *p;
252
253   RCC->AHBENR |= RCC_AHBENR_CRCEN;
254   CRC->CR = CRC_CR_RESET;
255
256   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
257     CRC->DR = rbit (*p);
258
259   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
260     return USB_SUCCESS;
261
262   return USB_UNSUPPORT;
263 }
264
265 int
266 usb_cb_setup (uint8_t req, uint8_t req_no,
267               uint16_t value, uint16_t index, uint16_t len)
268 {
269   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
270
271   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
272     {
273       if (USB_SETUP_GET (req))
274         {
275           if (req_no == USB_FSIJ_GNUK_MEMINFO)
276             {
277               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
278               return USB_SUCCESS;
279             }
280         }
281       else /* SETUP_SET */
282         {
283           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
284
285           if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
286             {
287               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
288                 return USB_UNSUPPORT;
289
290               if (addr < &_regnual_start || addr + len > __heap_end__)
291                 return USB_UNSUPPORT;
292
293               if (index + len < 256)
294                 memset (addr + index + len, 0, 256 - (index + len));
295
296               usb_lld_set_data_to_recv (addr, len);
297               return USB_SUCCESS;
298             }
299           else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
300             {
301               if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
302                 return USB_UNSUPPORT;
303
304               if (((uint32_t)addr & 0x03))
305                 return USB_UNSUPPORT;
306
307               return download_check_crc32 ((uint32_t *)addr);
308             }
309           else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && len == 0)
310             {
311               if (value != 0 && value != 1 && value != 2)
312                 return USB_UNSUPPORT;
313
314               ccid_card_change_signal (value);
315               return USB_SUCCESS;
316             }
317         }
318     }
319   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
320     {
321       if (index == ICC_INTERFACE)
322         {
323           if (USB_SETUP_GET (req))
324             {
325               if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
326                 {
327                   usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
328                   return USB_SUCCESS;
329                 }
330               else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
331                 {
332                   usb_lld_set_data_to_send (data_rate_table,
333                                             sizeof (data_rate_table));
334                   return USB_SUCCESS;
335                 }
336             }
337           else
338             {
339               if (req_no == USB_CCID_REQ_ABORT)
340                 /* wValue: bSeq, bSlot */
341                 /* Abortion is not supported in Gnuk */
342                 return USB_UNSUPPORT;
343             }
344         }
345 #ifdef HID_CARD_CHANGE_SUPPORT
346       else if (index == HID_INTERFACE)
347         {
348           switch (req_no)
349             {
350             case USB_HID_REQ_GET_IDLE:
351               usb_lld_set_data_to_send (&hid_idle_rate, 1);
352               return USB_SUCCESS;
353             case USB_HID_REQ_SET_IDLE:
354               usb_lld_set_data_to_recv (&hid_idle_rate, 1);
355               return USB_SUCCESS;
356
357             case USB_HID_REQ_GET_REPORT:
358               /* Request of LED status and key press */
359               usb_lld_set_data_to_send (&hid_report, 2);
360               return USB_SUCCESS;
361
362             case USB_HID_REQ_SET_REPORT:
363               /* Received LED set request */
364               if (len == 1)
365                 usb_lld_set_data_to_recv (&hid_report, len);
366               return USB_SUCCESS;
367
368             case USB_HID_REQ_GET_PROTOCOL:
369             case USB_HID_REQ_SET_PROTOCOL:
370               /* This driver doesn't support boot protocol.  */
371               return USB_UNSUPPORT;
372
373             default:
374               return USB_UNSUPPORT;
375             }
376         }
377 #endif
378 #ifdef ENABLE_VIRTUAL_COM_PORT
379       else if (index == VCOM_INTERFACE_0)
380         return vcom_port_data_setup (req, req_no, value);
381 #endif
382 #ifdef PINPAD_DND_SUPPORT
383       else if (index == MSC_INTERFACE)
384         {
385           if (USB_SETUP_GET (req))
386             {
387               if (req_no == MSC_GET_MAX_LUN_COMMAND)
388                 {
389                   usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
390                   return USB_SUCCESS;
391                 }
392             }
393           else
394             if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
395               /* Should call resetting MSC thread, something like msc_reset() */
396               return USB_SUCCESS;
397         }
398 #endif
399     }
400
401   return USB_UNSUPPORT;
402 }
403
404
405 void
406 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
407                           uint16_t index, uint16_t len)
408 {
409   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
410
411   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
412     {
413       if (USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
414         {
415           if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
416             return;
417
418           (void)value; (void)index;
419           usb_lld_prepare_shutdown (); /* No further USB communication */
420           *icc_state_p = ICC_STATE_EXEC_REQUESTED;
421         }
422     }
423 #ifdef HID_CARD_CHANGE_SUPPORT
424   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
425     {
426       if (index == HID_INTERFACE && req_no == USB_HID_REQ_SET_REPORT)
427         {
428           if ((hid_report ^ hid_report_saved) & HID_LED_STATUS_CARDCHANGE)
429             ccid_card_change_signal (CARD_CHANGE_TOGGLE);
430
431           hid_report_saved = hid_report;
432         }
433     }
434 #endif
435 }
436
437
438 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
439 {
440   int i;
441   uint8_t current_conf;
442
443   switch (event_type)
444     {
445     case USB_EVENT_ADDRESS:
446       bDeviceState = ADDRESSED;
447       return USB_SUCCESS;
448     case USB_EVENT_CONFIG:
449       current_conf = usb_lld_current_configuration ();
450       if (current_conf == 0)
451         {
452           if (value != 1)
453             return USB_UNSUPPORT;
454
455           usb_lld_set_configuration (value);
456           for (i = 0; i < NUM_INTERFACES; i++)
457             gnuk_setup_endpoints_for_interface (i, 0);
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   static 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_set_data_to_send (&zero, 1);
499       return USB_SUCCESS;
500
501     default:
502     case USB_QUERY_INTERFACE:
503       return USB_SUCCESS;
504     }
505 }
506
507
508 #define INTR_REQ_USB 20
509
510 void *
511 usb_intr (void *arg)
512 {
513   chopstx_intr_t interrupt;
514
515   (void)arg;
516   usb_lld_init (USB_INITIAL_FEATURE);
517   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
518   usb_interrupt_handler ();
519
520   while (1)
521     {
522       chopstx_intr_wait (&interrupt);
523
524       /* Process interrupt. */
525       usb_interrupt_handler ();
526     }
527
528   return NULL;
529 }