Version 0.10
[gnuk/gnuk.git] / src / usb_prop.c
1 /*
2  * usb_prop.c - glue/interface code between Gnuk and USB-FS-Device_Lib
3  *
4  * Copyright (C) 2010, 2011 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 "config.h"
28 #include "usb_lib.h"
29 #include "usb_conf.h"
30 #include "usb_prop.h"
31 #include "usb_desc.h"
32 #include "usb_pwr.h"
33 #include "hw_config.h"
34
35 #ifdef ENABLE_VIRTUAL_COM_PORT
36 #include "usb-cdc-vport.c"
37 #endif
38
39 static uint8_t gnukStringSerial[] = {
40   13*2+2,                       /* bLength */
41   USB_STRING_DESCRIPTOR_TYPE,   /* bDescriptorType */
42   '0', 0, '.', 0, '1', 0, '0', 0, /* Version number of Gnuk */
43   '-', 0,
44   0, 0, 0, 0, 0, 0, 0, 0,
45   0, 0, 0, 0, 0, 0, 0, 0,
46 };
47 #define ID_OFFSET 12
48
49 static void
50 gnuk_device_init (void)
51 {
52   const uint8_t *u = unique_device_id ();
53   int i;
54
55   for (i = 0; i < 4; i++)
56     {
57       gnukStringSerial[i*4+ID_OFFSET+0] = (u[i*2] >> 4) + 'A';
58       gnukStringSerial[i*4+ID_OFFSET+1] = 0;
59       gnukStringSerial[i*4+ID_OFFSET+2] = (u[i*2+1] & 0x0f) + 'A';
60       gnukStringSerial[i*4+ID_OFFSET+3] = 0;
61     }
62
63   pInformation->Current_Configuration = 0;
64
65   /* Connect the device */
66   PowerOn ();
67
68   /* Perform basic device initialization operations */
69   USB_SIL_Init ();
70
71   bDeviceState = UNCONNECTED;
72 }
73
74 static void
75 gnuk_device_reset (void)
76 {
77   /* Set DEVICE as not configured */
78   pInformation->Current_Configuration = 0;
79
80   /* Current Feature initialization */
81   pInformation->Current_Feature = Config_Descriptor.Descriptor[7];
82
83   /* Set DEVICE with the default Interface*/
84   pInformation->Current_Interface = 0;
85
86   SetBTABLE (BTABLE_ADDRESS);
87
88   /* Initialize Endpoint 0 */
89   SetEPType (ENDP0, EP_CONTROL);
90   SetEPTxStatus (ENDP0, EP_TX_STALL);
91   SetEPRxAddr (ENDP0, ENDP0_RXADDR);
92   SetEPTxAddr (ENDP0, ENDP0_TXADDR);
93   Clear_Status_Out (ENDP0);
94   SetEPRxCount (ENDP0, GNUK_MAX_PACKET_SIZE);
95   SetEPRxValid (ENDP0);
96
97   /* Initialize Endpoint 1 */
98   SetEPType (ENDP1, EP_BULK);
99   SetEPTxAddr (ENDP1, ENDP1_TXADDR);
100   SetEPTxStatus (ENDP1, EP_TX_NAK);
101   SetEPRxStatus (ENDP1, EP_RX_DIS);
102
103   /* Initialize Endpoint 2 */
104   SetEPType (ENDP2, EP_BULK);
105   SetEPRxAddr (ENDP2, ENDP2_RXADDR);
106   SetEPRxCount (ENDP2, GNUK_MAX_PACKET_SIZE);
107   SetEPRxStatus (ENDP2, EP_RX_VALID);
108   SetEPTxStatus (ENDP2, EP_TX_DIS);
109
110 #ifdef ENABLE_VIRTUAL_COM_PORT
111   /* Initialize Endpoint 3 */
112   SetEPType (ENDP3, EP_BULK);
113   SetEPTxAddr (ENDP3, ENDP3_TXADDR);
114   SetEPTxStatus (ENDP3, EP_TX_NAK);
115   SetEPRxStatus (ENDP3, EP_RX_DIS);
116
117   /* Initialize Endpoint 4 */
118   SetEPType (ENDP4, EP_INTERRUPT);
119   SetEPTxAddr (ENDP4, ENDP4_TXADDR);
120   SetEPTxStatus (ENDP4, EP_TX_NAK);
121   SetEPRxStatus (ENDP4, EP_RX_DIS);
122
123   /* Initialize Endpoint 5 */
124   SetEPType (ENDP5, EP_BULK);
125   SetEPRxAddr (ENDP5, ENDP5_RXADDR);
126   SetEPRxCount (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE);
127   SetEPRxStatus (ENDP5, EP_RX_VALID);
128   SetEPTxStatus (ENDP5, EP_TX_DIS);
129 #endif
130
131   /* Set this device to response on default address */
132   SetDeviceAddress (0);
133
134   bDeviceState = ATTACHED;
135 }
136
137 static void
138 gnuk_device_SetConfiguration (void)
139 {
140   DEVICE_INFO *pInfo = &Device_Info;
141
142   if (pInfo->Current_Configuration != 0)
143     /* Device configured */
144     bDeviceState = CONFIGURED;
145 }
146
147 static void
148 gnuk_device_SetInterface (void)
149 {
150   uint16_t intf = pInformation->USBwIndex0;
151   
152   /* alternateSetting: pInformation->USBwValue0 should be 0 */
153
154   if (intf == 0)
155     {
156       ClearDTOG_RX (0x02);
157       ClearDTOG_TX (0x81);
158     }
159 #ifdef ENABLE_VIRTUAL_COM_PORT
160   else if (intf == 1)
161     {
162       ClearDTOG_TX (0x84);
163     }
164   else if (intf == 2)
165     {
166       ClearDTOG_RX (0x05);
167       ClearDTOG_TX (0x83);
168     }
169 #endif
170 }
171
172 static void
173 gnuk_device_SetDeviceAddress (void)
174 {
175   bDeviceState = ADDRESSED;
176 }
177
178 /* IN from port 0 */
179 static void
180 gnuk_device_Status_In (void)
181 {
182 }
183
184 /* OUT to port 0 */
185 static void
186 gnuk_device_Status_Out (void)
187 {
188 }
189
190 static uint8_t *
191 gnuk_device_GetDeviceDescriptor (uint16_t Length)
192 {
193   return Standard_GetDescriptorData (Length,
194                                      (PONE_DESCRIPTOR)&Device_Descriptor);
195 }
196
197 static uint8_t *
198 gnuk_device_GetConfigDescriptor (uint16_t Length)
199 {
200   return Standard_GetDescriptorData (Length,
201                                      (PONE_DESCRIPTOR)&Config_Descriptor);
202 }
203
204 static uint8_t *
205 gnuk_device_GetStringDescriptor (uint16_t Length)
206 {
207   uint8_t wValue0 = pInformation->USBwValue0;
208   uint32_t  wOffset = pInformation->Ctrl_Info.Usb_wOffset;
209
210   if (wValue0 == 3)
211     /* Serial number is requested */
212     if (Length == 0)
213       {
214         pInformation->Ctrl_Info.Usb_wLength = sizeof gnukStringSerial - wOffset;
215         return 0;
216       }
217     else
218       return gnukStringSerial + wOffset;
219   else if (wValue0 > (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR)))
220     return NULL;
221   else
222     return Standard_GetDescriptorData (Length,
223                                        (PONE_DESCRIPTOR)&String_Descriptor[wValue0]);
224 }
225
226 #ifdef ENABLE_VIRTUAL_COM_PORT
227 #define NUM_INTERFACES 3        /* two for CDC, one for CCID */
228 #else
229 #define NUM_INTERFACES 1        /* CCID only */
230 #endif
231
232 static RESULT
233 gnuk_device_Get_Interface_Setting (uint8_t Interface, uint8_t AlternateSetting)
234 {
235   if (AlternateSetting > 0)     /* Any interface, we have no alternate */
236     return USB_UNSUPPORT;
237   else if (Interface > NUM_INTERFACES)
238     return USB_UNSUPPORT;
239
240   return USB_SUCCESS;
241 }
242
243 #define USB_CCID_REQ_ABORT                      0x01
244 #define USB_CCID_REQ_GET_CLOCK_FREQUENCIES      0x02
245 #define USB_CCID_REQ_GET_DATA_RATES             0x03
246
247 static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
248 static uint8_t *
249 gnuk_clock_frequencies (uint16_t len)
250 {
251   if (len == 0)
252     {
253       pInformation->Ctrl_Info.Usb_wLength = sizeof (freq_table);
254       return NULL;
255     }
256
257   return (uint8_t *)freq_table;
258 }
259
260 static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
261 static uint8_t *
262 gnuk_data_rates (uint16_t len)
263 {
264   if (len == 0)
265     {
266       pInformation->Ctrl_Info.Usb_wLength = sizeof (data_rate_table);
267       return NULL;
268     }
269
270   return (uint8_t *)data_rate_table;
271 }
272
273 static RESULT
274 gnuk_setup_with_data (uint8_t RequestNo)
275 {
276   if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
277     if (pInformation->USBwIndex0 == 0) /* Interface */
278       {
279         if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
280           {
281             pInformation->Ctrl_Info.CopyData = gnuk_clock_frequencies;
282             pInformation->Ctrl_Info.Usb_wOffset = 0;
283             gnuk_clock_frequencies (0);
284             return USB_SUCCESS;
285           }
286         else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
287           {
288             pInformation->Ctrl_Info.CopyData = gnuk_data_rates;
289             pInformation->Ctrl_Info.Usb_wOffset = 0;
290             gnuk_data_rates (0);
291             return USB_SUCCESS;
292           }
293         else
294           return USB_UNSUPPORT;
295       }
296     else
297       {
298 #if defined(ENABLE_VIRTUAL_COM_PORT)
299         return Virtual_Com_Port_Data_Setup (RequestNo);
300 #else
301         return USB_UNSUPPORT;
302 #endif
303       }
304   else
305     return USB_UNSUPPORT;
306 }
307
308 static RESULT
309 gnuk_setup_with_nodata (uint8_t RequestNo)
310 {
311   if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
312     if (pInformation->USBwIndex0 == 0) /* Interface */
313       {
314         if (RequestNo == USB_CCID_REQ_ABORT)
315           /* wValue: bSeq, bSlot */
316           /* Abortion is not supported in Gnuk */
317           return USB_UNSUPPORT;
318         else
319           return USB_UNSUPPORT;
320       }
321     else
322       {
323 #if defined(ENABLE_VIRTUAL_COM_PORT)
324         return Virtual_Com_Port_NoData_Setup (RequestNo);
325 #else
326         return USB_UNSUPPORT;
327 #endif
328       }
329   else
330     return USB_UNSUPPORT;
331 }
332
333 /*
334  * Interface to USB core
335  */
336
337 const DEVICE_PROP Device_Property = {
338   gnuk_device_init,
339   gnuk_device_reset,
340   gnuk_device_Status_In,
341   gnuk_device_Status_Out,
342   gnuk_setup_with_data,
343   gnuk_setup_with_nodata,
344   gnuk_device_Get_Interface_Setting,
345   gnuk_device_GetDeviceDescriptor,
346   gnuk_device_GetConfigDescriptor,
347   gnuk_device_GetStringDescriptor,
348   0,
349   GNUK_MAX_PACKET_SIZE
350 };
351
352 const DEVICE Device_Table = {
353   EP_NUM,
354   1
355 };
356
357 const USER_STANDARD_REQUESTS User_Standard_Requests = {
358   NOP_Process,                  /* GetConfiguration */ 
359   gnuk_device_SetConfiguration,
360   NOP_Process,                  /* GetInterface */
361   gnuk_device_SetInterface,
362   NOP_Process,                  /* GetStatus */
363   NOP_Process,                  /* ClearFeature */
364   NOP_Process,                  /* SetEndPointFeature */
365   NOP_Process,                  /* SetDeviceFeature */
366   gnuk_device_SetDeviceAddress
367 };