Added ioctls for get/set default outputs and levels. The ioctls seem to
[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 #define DO_NOTHING -1UL
35 #define SHOW_SETTING -2UL
36
37 /*
38  * Options
39  *
40  * --outputs=value  where value is any valid positive integer 0-255
41  *                  presented in either decimal or hexadecimal form
42  */
43
44 struct options {
45         unsigned long outputs;
46         unsigned long default_outputs;
47         unsigned long default_levels;
48 };
49
50 void gppio_ioctl ( int fd, const char *name, unsigned long option,
51                    int get_ioctl, int set_ioctl );
52 int parseopts ( const int, char **argv, struct options * );
53 unsigned long parseint ( const char * );
54 void printhelp ();
55
56 int main ( int argc, char* argv[] ) {
57         struct options opts = {
58                 .outputs                = DO_NOTHING,
59                 .default_outputs        = DO_NOTHING,
60                 .default_levels         = DO_NOTHING,
61         };
62         int last_index = parseopts(argc,argv,&opts), fd;
63
64         if ( last_index == ( argc - 1 ) ) {
65                 fd = open( argv[last_index], O_RDWR );
66         } else {
67                 eprintf("No device specified!\n");
68                 exit(EXIT_FAILURE);
69         }
70
71         if ( fd < 0 ) {
72                 eprintf( "Error: Could not open device %s: %s\n",
73                          argv[last_index], strerror(errno) );
74                 exit(EXIT_FAILURE);
75         }
76
77         gppio_ioctl ( fd, "outputs", opts.outputs,
78                       QUICKUSB_IOC_GPPIO_GET_OUTPUTS,
79                       QUICKUSB_IOC_GPPIO_SET_OUTPUTS );
80         gppio_ioctl ( fd, "default-outputs", opts.default_outputs,
81                       QUICKUSB_IOC_GPPIO_GET_DEFAULT_OUTPUTS,
82                       QUICKUSB_IOC_GPPIO_SET_DEFAULT_OUTPUTS );
83         gppio_ioctl ( fd, "default-levels", opts.default_levels,
84                       QUICKUSB_IOC_GPPIO_GET_DEFAULT_LEVELS,
85                       QUICKUSB_IOC_GPPIO_SET_DEFAULT_LEVELS );
86
87         close(fd);
88         return 0;
89 }
90
91 void gppio_ioctl ( int fd, const char *name, unsigned long option,
92                    int get_ioctl, int set_ioctl ) {
93         quickusb_gppio_ioctl_data_t data;
94
95         switch ( option ) {
96         case DO_NOTHING:
97                 break;
98         case SHOW_SETTING:
99                 if ( ioctl ( fd, get_ioctl, &data ) != 0 ) {
100                         eprintf ( "Could not get %s: %s\n", name,
101                                   strerror ( errno ) );
102                         exit ( EXIT_FAILURE );
103                 }
104                 printf ( "%s = %#02x\n", name, data );
105                 break;
106         default:
107                 data = option;
108                 if ( ioctl ( fd, set_ioctl, &data ) != 0 ) {
109                         eprintf ( "Could not set %s: %s\n", name,
110                                   strerror ( errno ) );
111                         exit ( EXIT_FAILURE );
112                 }
113                 break;
114         }
115 }
116
117 /*
118  * Parse command-line options and return index of last element in
119  * argument list that is not an option
120  */
121 int parseopts ( const int argc, char **argv, struct options *opts ) {
122         int c;
123
124         while (1) {
125                 int option_index = 0;
126                 static struct option long_options[] = {
127                         { "outputs", optional_argument, NULL, 'o' },
128                         { "default-outputs", optional_argument, NULL, 'd' },
129                         { "default-levels", optional_argument, NULL, 'l' },
130                         { "help", 0, NULL, 'h' },
131                         { 0, 0, 0, 0 }
132                 };
133
134                 if ( ( c = getopt_long ( argc, argv, "o::d::l::h",
135                                          long_options,
136                                          &option_index ) ) == -1 ) {
137                         break;
138                 }
139
140                 switch(c) {
141                         case 'o':
142                                 opts->outputs = parseint(optarg);
143                                 break;
144                         case 'd':
145                                 opts->default_outputs = parseint(optarg);
146                                 break;
147                         case 'l':
148                                 opts->default_levels = parseint(optarg);
149                                 break;
150                         case 'h':
151                                 printhelp();
152                                 break;
153                         case '?':
154                         default:
155                                 eprintf("Warning: unrecognised character code "
156                                         "%o\n", c);
157                                 if (optarg) {
158                                         eprintf("         with arg %s\n",
159                                                 optarg);
160                                 }
161                                 eprintf("Use -h to print help.\n");
162                                 exit(EXIT_FAILURE);
163                 }
164         }
165         return optind;
166 }
167
168 unsigned long parseint ( const char *nPtr ) {
169         unsigned long tmp;
170         char *endPtr;
171
172         if ( ! nPtr )
173                 return SHOW_SETTING;
174
175         if ( *nPtr == '\0' ) {
176                 eprintf("Error: No value specified\n");
177                 exit(EXIT_FAILURE);
178         }
179
180         tmp = strtoul ( nPtr, &endPtr, 0 );
181
182         if ( *endPtr != '\0' ) {
183                 eprintf("Error: Invalid value \"%s\"\n", nPtr);
184                 exit(EXIT_FAILURE);
185         }
186
187         return tmp;
188 }
189
190 /*
191  * Print helpful message
192  */
193 void printhelp () {
194         eprintf("\n"
195         "Usage: setquickusb [ --outputs=MASK ] DEVICE\n"
196         "setquickusb reads or sets the I/O port directions for a QuickUSB module.\n"
197         "If there are no options, it prints the output mask (in hexadecimal):\n"
198         "\n"
199         "       Example:\n"
200         "               setquickusb /dev/qu0ga\n"
201         "       Prints:\n"
202         "               Outputs: 0xf0\n"
203         "\n");
204         eprintf("If --outputs=MASK is specified, then the I/O port concerned will\n"
205         "be set to have that output mask. MASK is an integer from 0-255,\n"
206         "specified in decimal, or hexadecimal.\n"
207         "\n"
208         "       Example:\n"
209         "               setquickusb --outputs=0xf0 /dev/quoga\n"
210         "       Result:\n"
211         "               Port A has bits 7-4 set as outputs, and 3-0 as inputs.\n"
212         "\n");
213         eprintf("DEVICE is the relevant QuickUSB device and port. For example:\n"
214         "       /dev/qu0ga      First QUSB device, General Purpose Port A\n"
215         "       /dev/qu0gb      First QUSB device, General Purpose Port B\n"
216         "       /dev/qu0gc      First QUSB device, General Purpose Port C\n"
217         "       /dev/qu0gd      First QUSB device, General Purpose Port D\n"
218         "       /dev/qu0ge      First QUSB device, General Purpose Port E\n"
219         "\n"
220         "       /dev/qu0hc      First QUSB device, High Speed Port, Control\n"
221         "       /dev/qu0hd      First QUSB device, High Speed Port, Data\n"
222         "\n");
223         eprintf("Note 1: the high-speed port uses the same pins as G.P. ports B,D.\n"
224         "Note 2: the 16-bit HSP (/dev/qu0hd) is little-endian. Byte B is read first.\n"
225         "Note 3: the RS232 serial ports are not implemented in this driver.\n"
226         "\n"
227         "WARNING:\n"
228         "       Setting the output mask on a port configured for high-speed\n"
229         "       (either hc, or the corresponding gb,gd) will MESS IT UP.\n"
230         "       Don't do it!\n"
231         "\n");
232
233         exit(EXIT_SUCCESS);
234 }