6a668a4921eeccdebf5125c8bf05b5d847407e0a
[gnuk/gnuk.git] / src / main.c
1 /*
2  * main.c - main routine of Gnuk
3  *
4  * Copyright (C) 2010 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 #include "config.h"
25
26 #include "usb_lib.h"
27
28 #include "ch.h"
29 #include "gnuk.h"
30 #include "usb_lld.h"
31 #include "usb_istr.h"
32 #include "usb_desc.h"
33 #include "hw_config.h"
34 #include "usb_pwr.h"
35
36 #ifdef DEBUG
37 struct stdout {
38   Mutex m;
39   CondVar start_cnd;
40   CondVar finish_cnd;
41   const char *str;
42   int size;
43 };
44
45 static struct stdout stdout;
46
47 static void
48 stdout_init (void)
49 {
50   chMtxInit (&stdout.m);
51   chCondInit (&stdout.start_cnd);
52   chCondInit (&stdout.finish_cnd);
53   stdout.size = 0;
54   stdout.str = NULL;
55 }
56
57 void
58 _write (const char *s, int size)
59 {
60   if (size == 0)
61     return;
62
63   chMtxLock (&stdout.m);
64   while (stdout.str)
65     chCondWait (&stdout.finish_cnd);
66   stdout.str = s;
67   stdout.size = size;
68   chCondSignal (&stdout.start_cnd);
69   chCondWait (&stdout.finish_cnd);
70   chMtxUnlock ();
71 }
72
73 Thread *stdout_thread;
74 uint32_t count_in;
75 uint8_t buffer_in[VIRTUAL_COM_PORT_DATA_SIZE];
76
77 static WORKING_AREA(waSTDOUTthread, 128);
78
79 static msg_t
80 STDOUTthread (void *arg)
81 {
82   (void)arg;
83   stdout_thread = chThdSelf ();
84
85  again:
86
87   while (1)
88     {
89       if (bDeviceState == CONFIGURED)
90         break;
91
92       chThdSleepMilliseconds (100);
93     }
94
95   while (1)
96     {
97       const char *p;
98       int len;
99
100       if (bDeviceState != CONFIGURED)
101         break;
102
103       chMtxLock (&stdout.m);
104       if (stdout.str == NULL)
105         chCondWait (&stdout.start_cnd);
106
107       p = stdout.str;
108       len = stdout.size;
109       while (len > 0)
110         {
111           int i;
112
113           if (len < VIRTUAL_COM_PORT_DATA_SIZE)
114             {
115               for (i = 0; i < len; i++)
116                 buffer_in[i] = p[i];
117               count_in = len;
118               len = 0;
119             }
120           else
121             {
122               for (i = 0; i < VIRTUAL_COM_PORT_DATA_SIZE; i++)
123                 buffer_in[i] = p[i];
124               len -= VIRTUAL_COM_PORT_DATA_SIZE;
125               count_in = VIRTUAL_COM_PORT_DATA_SIZE;
126               p += count_in;
127             }
128
129           chEvtClear (EV_TX_READY);
130
131           USB_SIL_Write (EP3_IN, buffer_in, count_in);
132           SetEPTxValid (ENDP3);
133
134           chEvtWaitOne (EV_TX_READY);
135         }
136
137       stdout.str = NULL;
138       stdout.size = 0;
139       chCondBroadcast (&stdout.finish_cnd);
140       chMtxUnlock ();
141     }
142
143   goto again;
144   return 0;
145 }
146 #else
147 void
148 _write (const char *s, int size)
149 {
150   (void)s;
151   (void)size;
152 }
153 #endif
154
155 static WORKING_AREA(waUSBthread, 128);
156 extern msg_t USBthread (void *arg);
157
158 Thread *blinker_thread;
159 /*
160  * LEDs blinks.
161  * When GPGthread execute some command, LED stop blinking, but always ON.
162  */
163 #define LED_BLINKER_TIMEOUT MS2ST(200)
164
165
166 /*
167  * Entry point, note, the main() function is already a thread in the system
168  * on entry.
169  */
170 int
171 main (int argc, char **argv)
172 {
173   eventmask_t m;
174   uint8_t led_state = 0;
175   int count = 0;
176
177   (void)argc;
178   (void)argv;
179
180   blinker_thread = chThdSelf ();
181
182   usb_lld_init ();
183   USB_Init();
184
185 #ifdef DEBUG
186   stdout_init ();
187
188   /*
189    * Creates 'stdout' thread.
190    */
191   chThdCreateStatic (waSTDOUTthread, sizeof(waSTDOUTthread),
192                      NORMALPRIO, STDOUTthread, NULL);
193 #endif
194
195   chThdCreateStatic (waUSBthread, sizeof(waUSBthread),
196                      NORMALPRIO, USBthread, NULL);
197
198   while (1)
199     {
200       count++;
201
202       m = chEvtWaitOneTimeout (ALL_EVENTS, LED_BLINKER_TIMEOUT);
203       if (m == EV_LED_ON)
204         led_state = 1;
205       else if (m == EV_LED_OFF)
206         led_state = 0;
207
208       if (led_state)
209         set_led (1);
210       else
211         {
212           if ((count & 1))
213             set_led (1);
214           else
215             set_led (0);
216         }
217
218 #ifdef DEBUG_MORE
219       if (bDeviceState == CONFIGURED && (count % 100) == 0)
220         {
221           DEBUG_SHORT (count / 100);
222           _write ("\r\nThis is ChibiOS 2.0.8 on STM32.\r\n"
223                   "Testing USB driver.\n\n"
224                   "Hello world\r\n\r\n", 35+21+15);
225         }
226 #endif
227     }
228
229   return 0;
230 }
231
232 void
233 fatal (void)
234 {
235   _write ("fatal\r\n", 7);
236   for (;;);
237 }