Avoid compilation warning on 2.6.28
[people/mcb30/quickusb.git] / setquickusb.c
1 /*
2  * setquickusb - get/set Linux quickusb information
3  *
4  * Copyright 2006 Dan Lynch <dlynch@fensystems.co.uk>
5  * Modifications 2006, Richard Neill <rn214@mrao.cam.ac.uk>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  */
13
14 /*
15  * TODO: This doesn't yet implement the serial ports. Also, bad things will
16  * happen when we change direction of the high-speed ports, or their corresponding
17  * general-purpose ports
18  */
19
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <getopt.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29
30 #include "kernel/quickusb.h"
31
32 #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
33
34 /*
35  * Options
36  *
37  * --outputs=value  where value is any valid positive integer 0-255
38  *                  presented in either decimal or hexadecimal form
39  */
40
41 enum action_type {
42         DO_NOTHING = 0,
43         SHOW = 1,
44         SET = 2,
45 };
46
47 struct action {
48         unsigned int type;
49         unsigned int value;
50 };
51
52 struct options {
53         struct action outputs;
54         struct action default_outputs;
55         struct action default_levels;
56         struct action settings[16];
57 };
58
59 void gppio_ioctl ( int fd, const char *name, struct action *action,
60                    int get_ioctl, int set_ioctl );
61 void setting_ioctl ( int fd, unsigned int setting, struct action *action );
62 int parseopts ( const int, char **argv, struct options * );
63 void parsegppio ( struct action *action, const char *arg );
64 void parsesetting ( struct options *options, const char *arg );
65 void printhelp ();
66
67 int main ( int argc, char* argv[] ) {
68         struct options opts;
69         int last_index;
70         int fd;
71         unsigned int i;
72
73         memset ( &opts, 0, sizeof ( opts ) );
74
75         last_index = parseopts ( argc, argv, &opts );
76         if ( last_index == ( argc - 1 ) ) {
77                 fd = open( argv[last_index], O_RDWR );
78         } else {
79                 eprintf("No device specified!\n");
80                 exit(EXIT_FAILURE);
81         }
82
83         if ( fd < 0 ) {
84                 eprintf( "Error: Could not open device %s: %s\n",
85                          argv[last_index], strerror(errno) );
86                 exit(EXIT_FAILURE);
87         }
88
89         gppio_ioctl ( fd, "outputs", &opts.outputs,
90                       QUICKUSB_IOC_GPPIO_GET_OUTPUTS,
91                       QUICKUSB_IOC_GPPIO_SET_OUTPUTS );
92         gppio_ioctl ( fd, "default-outputs", &opts.default_outputs,
93                       QUICKUSB_IOC_GPPIO_GET_DEFAULT_OUTPUTS,
94                       QUICKUSB_IOC_GPPIO_SET_DEFAULT_OUTPUTS );
95         gppio_ioctl ( fd, "default-levels", &opts.default_levels,
96                       QUICKUSB_IOC_GPPIO_GET_DEFAULT_LEVELS,
97                       QUICKUSB_IOC_GPPIO_SET_DEFAULT_LEVELS );
98
99         for ( i = 0 ; ( i < ( sizeof ( opts.settings ) /
100                               sizeof ( opts.settings[0] ) ) ) ; i++ ) {
101                 setting_ioctl ( fd, i, &opts.settings[i] );
102         }
103
104         close(fd);
105         return 0;
106 }
107
108 void gppio_ioctl ( int fd, const char *name, struct action *action,
109                    int get_ioctl, int set_ioctl ) {
110         quickusb_gppio_ioctl_data_t data;
111
112         switch ( action->type ) {
113         case DO_NOTHING:
114                 break;
115         case SHOW:
116                 if ( ioctl ( fd, get_ioctl, &data ) != 0 ) {
117                         eprintf ( "Could not get %s: %s\n", name,
118                                   strerror ( errno ) );
119                         exit ( EXIT_FAILURE );
120                 }
121                 printf ( "%s = 0x%02x\n", name, data );
122                 break;
123         case SET:
124                 data = action->value;
125                 if ( ioctl ( fd, set_ioctl, &data ) != 0 ) {
126                         eprintf ( "Could not set %s: %s\n", name,
127                                   strerror ( errno ) );
128                         exit ( EXIT_FAILURE );
129                 }
130                 break;
131         }
132 }
133
134 void setting_ioctl ( int fd, unsigned int setting, struct action *action ) {
135         struct quickusb_setting_ioctl_data data;
136
137         data.address = setting;
138         data.value = action->value;
139
140         switch ( action->type ) {
141         case DO_NOTHING:
142                 break;
143         case SHOW:
144                 if ( ioctl ( fd, QUICKUSB_IOC_GET_SETTING, &data ) != 0 ) {
145                         eprintf ( "Could not get setting %d: %s\n",
146                                   setting, strerror ( errno ) );
147                         exit ( EXIT_FAILURE );
148                 }
149                 printf ( "setting[%d] = 0x%04x\n", setting, data.value );
150                 break;
151         case SET:
152                 if ( ioctl ( fd, QUICKUSB_IOC_SET_SETTING, &data ) != 0 ) {
153                         eprintf ( "Could not set setting %d: %s\n",
154                                   setting, strerror ( errno ) );
155                         exit ( EXIT_FAILURE );
156                 }
157                 break;
158         }
159 }
160
161 /*
162  * Parse command-line options and return index of last element in
163  * argument list that is not an option
164  */
165 int parseopts ( const int argc, char **argv, struct options *opts ) {
166         int c;
167
168         while (1) {
169                 int option_index = 0;
170                 static struct option long_options[] = {
171                         { "outputs", optional_argument, NULL, 'o' },
172                         { "default-outputs", optional_argument, NULL, 'd' },
173                         { "default-levels", optional_argument, NULL, 'l' },
174                         { "setting", required_argument, NULL, 's' },
175                         { "help", 0, NULL, 'h' },
176                         { 0, 0, 0, 0 }
177                 };
178
179                 if ( ( c = getopt_long ( argc, argv, "o::d::l::s:h",
180                                          long_options,
181                                          &option_index ) ) == -1 ) {
182                         break;
183                 }
184
185                 switch ( c ) {
186                 case 'o':
187                         parsegppio ( &opts->outputs, optarg );
188                         break;
189                 case 'd':
190                         parsegppio ( &opts->default_outputs, optarg );
191                         break;
192                 case 'l':
193                         parsegppio ( &opts->default_levels, optarg );
194                         break;
195                 case 's':
196                         parsesetting ( opts, optarg );
197                         break;
198                 case 'h':
199                         printhelp();
200                         break;
201                 case '?':
202                 default:
203                         eprintf ( "Warning: unrecognised character code %o\n",
204                                   c );
205                         if ( optarg ) {
206                                 eprintf ( "         with arg %s\n", optarg );
207                         }
208                         eprintf ( "Use -h to print help.\n" );
209                         exit ( EXIT_FAILURE );
210                 }
211         }
212         return optind;
213 }
214
215 void parsegppio ( struct action *action, const char *arg ) {
216         unsigned long tmp;
217         char *end;
218
219         if ( arg ) {
220                 if ( *arg == '\0' ) {
221                         eprintf ( "Error: No value specified\n" );
222                         exit ( EXIT_FAILURE );
223                 }
224                 
225                 tmp = strtoul ( arg, &end, 0 );
226                 if ( *end != '\0' ) {
227                         eprintf ( "Error: Invalid value \"%s\"\n", arg );
228                         exit ( EXIT_FAILURE );
229                 }
230                 
231                 action->type = SET;
232                 action->value = tmp;
233         } else {
234                 action->type = SHOW;
235         }
236 }
237
238 void parsesetting ( struct options *options, const char *arg ) {
239         unsigned long setting;
240         unsigned long value = 0;
241         int type = SHOW;
242         char *end;
243         
244         if ( *arg == '\0' ) {
245                 eprintf ( "Error: No setting specified\n" );
246                 exit ( EXIT_FAILURE );
247         }
248         setting = strtoul ( arg, &end, 0 );
249         if ( *end == '=' ) {
250                 end++;
251                 if ( *end == '\0' ) {
252                         eprintf ( "Error: No setting value specified\n" );
253                         exit ( EXIT_FAILURE );
254                 }
255                 type = SET;
256                 value = strtoul ( end, &end, 0 );
257         }
258         if ( *end != '\0' ) {
259                 eprintf ( "Error: Invalid setting string \"%s\"\n", arg );
260                 exit ( EXIT_FAILURE );
261         }
262
263         if ( setting >= ( sizeof ( options->settings ) /
264                           sizeof ( options->settings[0] ) ) ) {
265                 eprintf ( "Error: Setting %ld out of range\n", setting );
266                 exit ( EXIT_FAILURE );
267         }
268
269         options->settings[setting].type = type;
270         options->settings[setting].value = value;
271 }
272
273 /*
274  * Print helpful message
275  */
276 void printhelp () {
277         eprintf("\n"
278         "Usage: setquickusb [ --outputs=MASK ] DEVICE\n"
279         "setquickusb reads or sets the I/O port directions for a QuickUSB module.\n"
280         "If there are no options, it prints the output mask (in hexadecimal):\n"
281         "\n"
282         "       Example:\n"
283         "               setquickusb /dev/qu0ga\n"
284         "       Prints:\n"
285         "               Outputs: 0xf0\n"
286         "\n");
287         eprintf("If --outputs=MASK is specified, then the I/O port concerned will\n"
288         "be set to have that output mask. MASK is an integer from 0-255,\n"
289         "specified in decimal, or hexadecimal.\n"
290         "\n"
291         "       Example:\n"
292         "               setquickusb --outputs=0xf0 /dev/quoga\n"
293         "       Result:\n"
294         "               Port A has bits 7-4 set as outputs, and 3-0 as inputs.\n"
295         "\n");
296         eprintf("DEVICE is the relevant QuickUSB device and port. For example:\n"
297         "       /dev/qu0ga      First QUSB device, General Purpose Port A\n"
298         "       /dev/qu0gb      First QUSB device, General Purpose Port B\n"
299         "       /dev/qu0gc      First QUSB device, General Purpose Port C\n"
300         "       /dev/qu0gd      First QUSB device, General Purpose Port D\n"
301         "       /dev/qu0ge      First QUSB device, General Purpose Port E\n"
302         "\n"
303         "       /dev/qu0hc      First QUSB device, High Speed Port, Control\n"
304         "       /dev/qu0hd      First QUSB device, High Speed Port, Data\n"
305         "\n");
306         eprintf("Note 1: the high-speed port uses the same pins as G.P. ports B,D.\n"
307         "Note 2: the 16-bit HSP (/dev/qu0hd) is little-endian. Byte B is read first.\n"
308         "Note 3: the RS232 serial ports are not implemented in this driver.\n"
309         "\n"
310         "WARNING:\n"
311         "       Setting the output mask on a port configured for high-speed\n"
312         "       (either hc, or the corresponding gb,gd) will MESS IT UP.\n"
313         "       Don't do it!\n"
314         "\n");
315
316         exit(EXIT_SUCCESS);
317 }