f5a12bbb123aa29ac9469eef3f07aa876d441417
[gnuk/gnuk.git] / regnual / regnual.c
1 /*
2  * regnual.c -- Firmware installation for STM32F103 Flash ROM
3  *
4  * Copyright (C) 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 /*
25  * ReGNUal
26  */
27
28 #include "types.h"
29 #include "usb_lld.h"
30 #include "sys.h"
31
32 extern void *memset (void *s, int c, size_t n);
33
34 extern void set_led (int);
35 extern uint8_t _flash_start,  _flash_end;
36 extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len);
37 extern int flash_protect (void);
38 extern void nvic_system_reset (void);
39
40
41 #define ENDP0_RXADDR        (0x40)
42 #define ENDP0_TXADDR        (0x80)
43
44 /* USB Standard Device Descriptor */
45 static const uint8_t regnual_device_desc[] = {
46   18,   /* bLength */
47   USB_DEVICE_DESCRIPTOR_TYPE,     /* bDescriptorType */
48   0x10, 0x01,   /* bcdUSB = 1.1 */
49   0xFF,   /* bDeviceClass: VENDOR */
50   0x00,   /* bDeviceSubClass */
51   0x00,   /* bDeviceProtocol */
52   0x40,   /* bMaxPacketSize0 */
53 #include "../src/usb-vid-pid-ver.c.inc"
54   1, /* Index of string descriptor describing manufacturer */
55   2, /* Index of string descriptor describing product */
56   3, /* Index of string descriptor describing the device's serial number */
57   0x01    /* bNumConfigurations */
58 };
59
60 static const uint8_t regnual_config_desc[] = {
61   9,
62   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
63   18, 0,                        /* wTotalLength: no of returned bytes */
64   1,                    /* bNumInterfaces: single vender interface */
65   0x01,                 /* bConfigurationValue: Configuration value */
66   0x00,                 /* iConfiguration: None */
67 #if defined(USB_SELF_POWERED)
68   0xC0,                         /* bmAttributes: self powered */
69 #else
70   0x80,                         /* bmAttributes: bus powered */
71 #endif
72   50,                           /* MaxPower 100 mA */
73
74   /* Interface Descriptor */
75   9,
76   USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
77   0,                             /* bInterfaceNumber: Index of this interface */
78   0,                        /* Alternate setting for this interface */
79   0,                        /* bNumEndpoints: None */
80   0xFF,
81   0,
82   0,
83   0,                            /* string index for interface */
84 };
85
86 static const uint8_t regnual_string_lang_id[] = {
87   4,                            /* bLength */
88   USB_STRING_DESCRIPTOR_TYPE,
89   0x09, 0x04                    /* LangID = 0x0409: US-English */
90 };
91
92 #include "../src/usb-strings.c.inc"
93
94 static const uint8_t regnual_string_serial[] = {
95   8*2+2,
96   USB_STRING_DESCRIPTOR_TYPE,
97   /* FSIJ-0.0 */
98   'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0, 
99   '0', 0, '.', 0, '0', 0,
100 };
101
102
103 void
104 usb_cb_device_reset (void)
105 {
106   /* Set DEVICE as not configured */
107   usb_lld_set_configuration (0);
108
109   /* Current Feature initialization */
110   usb_lld_set_feature (regnual_config_desc[7]);
111
112   usb_lld_reset ();
113
114   /* Initialize Endpoint 0 */
115   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
116                           64);
117 }
118
119 #define USB_REGNUAL_MEMINFO     0
120 #define USB_REGNUAL_SEND        1
121 #define USB_REGNUAL_RESULT      2
122 #define USB_REGNUAL_FLASH       3
123 #define USB_REGNUAL_PROTECT     4
124 #define USB_REGNUAL_FINISH      5
125
126 static uint32_t mem[256/4];
127 static uint32_t result;
128
129
130 static uint32_t rbit (uint32_t v)
131 {
132   uint32_t r;
133
134   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
135   return r;
136 }
137
138 static uint32_t fetch (int i)
139 {
140   uint32_t v;
141
142   v = mem[i];
143   return rbit (v);
144 }
145
146 struct CRC {
147   __IO uint32_t DR;
148   __IO uint8_t  IDR;
149   uint8_t   RESERVED0;
150   uint16_t  RESERVED1;
151   __IO uint32_t CR;
152 };
153
154 #define  CRC_CR_RESET 0x01
155 static uint32_t calc_crc32 (void)
156 {
157   struct CRC *CRC = (struct CRC *)0x40023000;
158   int i;
159
160   CRC->CR = CRC_CR_RESET;
161
162   for (i = 0; i < 256/4; i++)
163     CRC->DR = fetch (i);
164
165   return rbit (CRC->DR);
166 }
167
168
169 void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
170                                uint16_t index, uint16_t len)
171 {
172   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
173
174   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
175     {
176       if (req_no == USB_REGNUAL_SEND && value == 0)
177         result = calc_crc32 ();
178       else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
179         {
180           uint32_t dst_addr = (0x08000000 + value * 0x100);
181
182           result = flash_write (dst_addr, (const uint8_t *)mem, 256);
183         }
184       else if (req_no == USB_REGNUAL_PROTECT && len == 0
185                && value == 0 && index == 0)
186         result = flash_protect ();
187       else if (req_no == USB_REGNUAL_FINISH && len == 0
188                && value == 0 && index == 0)
189         nvic_system_reset ();
190     }
191 }
192
193 int
194 usb_cb_setup (uint8_t req, uint8_t req_no,
195               uint16_t value, uint16_t index, uint16_t len)
196 {
197   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
198
199   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
200     {
201       if (USB_SETUP_GET (req))
202         {
203           if (req_no == USB_REGNUAL_MEMINFO)
204             {
205               static const uint8_t *mem_info[2];
206
207               mem_info[0] = &_flash_start;
208               mem_info[1] = &_flash_end;
209               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
210               return USB_SUCCESS;
211             }
212           else if (req_no == USB_REGNUAL_RESULT)
213             {
214               usb_lld_set_data_to_send (&result, sizeof (uint32_t));
215               return USB_SUCCESS;
216             }
217         }
218       else /* SETUP_SET */
219         {
220           if (req_no == USB_REGNUAL_SEND)
221             {
222               if (value != 0 || index + len > 256)
223                 return USB_UNSUPPORT;
224
225               if (index + len < 256)
226                 memset ((uint8_t *)mem + index + len, 0xff,
227                         256 - (index + len));
228
229               usb_lld_set_data_to_recv (mem + index, len);
230               return USB_SUCCESS;
231             }
232           else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
233             {
234               uint32_t dst_addr = (0x08000000 + value * 0x100);
235
236               if (dst_addr + 256 <= (uint32_t)&_flash_end)
237                 return USB_SUCCESS;
238             }
239           else if (req_no == USB_REGNUAL_PROTECT && len == 0
240                    && value == 0 && index == 0)
241             return USB_SUCCESS;
242           else if (req_no == USB_REGNUAL_FINISH && len == 0
243                    && value == 0 && index == 0)
244             return USB_SUCCESS;
245         }
246     }
247
248   return USB_UNSUPPORT;
249 }
250
251 int
252 usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
253 {
254   (void)index;
255   if (desc_type == DEVICE_DESCRIPTOR)
256     {
257       usb_lld_set_data_to_send (regnual_device_desc,
258                                 sizeof (regnual_device_desc));
259       return USB_SUCCESS;
260     }
261   else if (desc_type == CONFIG_DESCRIPTOR)
262     {
263       usb_lld_set_data_to_send (regnual_config_desc,
264                                 sizeof (regnual_config_desc));
265       return USB_SUCCESS;
266     }
267   else if (desc_type == STRING_DESCRIPTOR)
268     {
269       uint8_t desc_index = value & 0xff;
270       const uint8_t *str;
271       int size;
272
273       switch (desc_index)
274         {
275         case 0:
276           str = regnual_string_lang_id;
277           size = sizeof (regnual_string_lang_id);
278           break;
279         case 1:
280           str = gnukStringVendor;
281           size = sizeof (gnukStringVendor);
282           break;
283         case 2:
284           str = gnukStringProduct;
285           size = sizeof (gnukStringProduct);
286           break;
287         case 3:
288           str = regnual_string_serial;
289           size = sizeof (regnual_string_serial);
290           break;
291         default:
292           return USB_UNSUPPORT;
293         }
294
295       usb_lld_set_data_to_send (str, size);
296       return USB_SUCCESS;
297     }
298
299   return USB_UNSUPPORT;
300 }
301
302 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
303 {
304   (void)value;
305
306   switch (event_type)
307     {
308     case USB_EVENT_ADDRESS:
309     case USB_EVENT_CONFIG:
310       return USB_SUCCESS;
311     default:
312       break;
313     }
314
315   return USB_UNSUPPORT;
316 }
317
318 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
319 {
320   (void)cmd; (void)interface; (void)alt;
321   return USB_UNSUPPORT;
322 }
323
324
325 static void wait (int count)
326 {
327   int i;
328
329   for (i = 0; i < count; i++)
330     asm volatile ("" : : "r" (i) : "memory");
331 }
332
333 #define WAIT 2400000
334
335 int
336 main (int argc, char *argv[])
337 {
338   (void)argc; (void)argv;
339
340   set_led (0);
341
342   usb_lld_init (regnual_config_desc[7]);
343
344   while (1)
345     {
346       set_led (1);
347       wait (WAIT);
348       set_led (0);
349       wait (WAIT);
350     }
351 }