Added ioctls for get/set default outputs and levels. The ioctls seem to
authorMichael Brown <mbrown@fensystems.co.uk>
Tue, 6 Feb 2007 02:02:46 +0000 (02:02 +0000)
committerMichael Brown <mbrown@fensystems.co.uk>
Tue, 6 Feb 2007 02:02:46 +0000 (02:02 +0000)
work, but the actual state doesn't seem to be persistent across device
resets.

Makefile
kernel/quickusb.c
kernel/quickusb.h
setquickusb.c

index c7bb158..2cc35c2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 all :: setquickusb
 
 setquickusb : setquickusb.c kernel/quickusb.h
-       $(CC) -Wall -pedantic -O2 $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+       $(CC) -Wall -O2 $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $<
 
 clean ::
        rm -f setquickusb
index 6cdd1e0..5c694e8 100644 (file)
@@ -133,6 +133,8 @@ static int quickusb_gppio_ioctl ( struct inode *inode, struct file *file,
        void __user *user_data = ( void __user * ) arg;
        quickusb_gppio_ioctl_data_t data;
        unsigned char outputs;
+       unsigned int setting_address = QUICKUSB_SETTING_GPPIO ( gppio->port );
+       uint16_t setting;
        int rc;
 
        if ( ( rc = copy_from_user ( &data, user_data, sizeof (data) ) ) != 0 )
@@ -153,6 +155,42 @@ static int quickusb_gppio_ioctl ( struct inode *inode, struct file *file,
                                                      outputs ) ) != 0 )
                        return rc;
                break;
+       case QUICKUSB_IOC_GPPIO_GET_DEFAULT_OUTPUTS:
+               if ( ( rc = quickusb_read_setting ( gppio->quickusb->usb,
+                                                   setting_address,
+                                                   &setting ) ) != 0 )
+                       return rc;
+               data = ( setting >> 8 );
+               break;
+       case QUICKUSB_IOC_GPPIO_SET_DEFAULT_OUTPUTS:
+               if ( ( rc = quickusb_read_setting ( gppio->quickusb->usb,
+                                                   setting_address,
+                                                   &setting ) ) != 0 )
+                       return rc;
+               setting = ( ( setting & 0x00ff ) | ( data << 8 ) );
+               if ( ( rc = quickusb_write_setting ( gppio->quickusb->usb,
+                                                    setting_address,
+                                                    setting ) ) != 0 )
+                       return rc;
+               break;
+       case QUICKUSB_IOC_GPPIO_GET_DEFAULT_LEVELS:
+               if ( ( rc = quickusb_read_setting ( gppio->quickusb->usb,
+                                                   setting_address,
+                                                   &setting ) ) != 0 )
+                       return rc;
+               data = ( setting & 0xff );
+               break;
+       case QUICKUSB_IOC_GPPIO_SET_DEFAULT_LEVELS:
+               if ( ( rc = quickusb_read_setting ( gppio->quickusb->usb,
+                                                   setting_address,
+                                                   &setting ) ) != 0 )
+                       return rc;
+               setting = ( ( setting & 0xff00 ) | ( data & 0xff ) );
+               if ( ( rc = quickusb_write_setting ( gppio->quickusb->usb,
+                                                    setting_address,
+                                                    setting ) ) != 0 )
+                       return rc;
+               break;
        default:
                return -ENOTTY;
        }
@@ -268,42 +306,6 @@ static ssize_t quickusb_hspio_write_data ( struct file *file,
        return len;
 }
 
-static int quickusb_hspio_ioctl ( struct inode *inode, struct file *file,
-                                 unsigned int cmd, unsigned long arg ) {
-       struct quickusb_hspio *hspio = file->private_data;
-       void __user *user_data = ( void __user * ) arg;
-       quickusb_hspio_ioctl_data_t data;
-       uint16_t fifoconfig;
-       int rc;
-
-       if ( ( rc = copy_from_user ( &data, user_data, sizeof (data) ) ) != 0 )
-               return rc;
-
-       switch ( cmd ) {
-       case QUICKUSB_IOC_HSPIO_GET_FIFOCONFIG:
-               if ( ( rc = quickusb_read_setting ( hspio->quickusb->usb,
-                                                   QUICKUSB_FIFOCONFIG,
-                                                   &fifoconfig ) ) != 0 )
-                       return rc;
-               data = fifoconfig;
-               break;
-       case QUICKUSB_IOC_HSPIO_SET_FIFOCONFIG:
-               fifoconfig = data;
-               if ( ( rc = quickusb_write_setting ( hspio->quickusb->usb,
-                                                    QUICKUSB_FIFOCONFIG,
-                                                    fifoconfig ) ) != 0 )
-                       return rc;
-               break;
-       default:
-               return -ENOTTY;
-       }
-
-       if ( ( rc = copy_to_user ( user_data, &data, sizeof ( data ) ) ) != 0 )
-               return rc;
-
-       return 0;
-}
-
 static int quickusb_hspio_release ( struct inode *inode, struct file *file ) {
        struct quickusb_hspio *hspio = file->private_data;
        
@@ -322,7 +324,6 @@ static struct file_operations quickusb_hspio_data_fops = {
        .owner          = THIS_MODULE,
        .read           = quickusb_hspio_read_data,
        .write          = quickusb_hspio_write_data,
-       .ioctl          = quickusb_hspio_ioctl,
        .release        = quickusb_hspio_release,
 };
 
index dbfe0bb..7f5d23c 100644 (file)
@@ -22,9 +22,7 @@
 #define QUICKUSB_WINDEX_GPPIO_DIR      0
 #define QUICKUSB_WINDEX_GPPIO_DATA     1
 
-#define QUICKUSB_FIFOCONFIG            0x03
-#define QUICKUSB_FIFOCONFIG_MASTER     0xf2
-#define QUICKUSB_FIFOCONFIG_SLAVE      0xf3
+#define QUICKUSB_SETTING_GPPIO(port) ( 9 + (port) )
 
 #define QUICKUSB_TIMEOUT ( 1 * HZ )
 
@@ -309,11 +307,13 @@ typedef uint32_t quickusb_gppio_ioctl_data_t;
        _IOR ( 'Q', 0x00, quickusb_gppio_ioctl_data_t )
 #define QUICKUSB_IOC_GPPIO_SET_OUTPUTS \
        _IOW ( 'Q', 0x01, quickusb_gppio_ioctl_data_t )
-
-typedef uint32_t quickusb_hspio_ioctl_data_t;
-#define QUICKUSB_IOC_HSPIO_GET_FIFOCONFIG \
-       _IOR ( 'Q', 0x02, quickusb_hspio_ioctl_data_t )
-#define QUICKUSB_IOC_HSPIO_SET_FIFOCONFIG \
-       _IOW ( 'Q', 0x03, quickusb_hspio_ioctl_data_t )
+#define QUICKUSB_IOC_GPPIO_GET_DEFAULT_OUTPUTS \
+       _IOR ( 'Q', 0x02, quickusb_gppio_ioctl_data_t )
+#define QUICKUSB_IOC_GPPIO_SET_DEFAULT_OUTPUTS \
+       _IOW ( 'Q', 0x03, quickusb_gppio_ioctl_data_t )
+#define QUICKUSB_IOC_GPPIO_GET_DEFAULT_LEVELS \
+       _IOR ( 'Q', 0x04, quickusb_gppio_ioctl_data_t )
+#define QUICKUSB_IOC_GPPIO_SET_DEFAULT_LEVELS \
+       _IOW ( 'Q', 0x05, quickusb_gppio_ioctl_data_t )
 
 #endif /* QUICKUSB_H */
index 91d6b3e..2731df2 100644 (file)
@@ -2,6 +2,7 @@
  * setquickusb - get/set Linux quickusb information
  *
  * Copyright 2006 Dan Lynch <dlynch@fensystems.co.uk>
+ * Modifications 2006, Richard Neill <rn214@mrao.cam.ac.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  *
  */
 
+/*
+ * TODO: This doesn't yet implement the serial ports. Also, bad things will
+ * happen when we change direction of the high-speed ports, or their corresponding
+ * general-purpose ports
+ */
+
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "kernel/quickusb.h"
 
-#define UNDEFINED_UL -1UL
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define DO_NOTHING -1UL
+#define SHOW_SETTING -2UL
 
 /*
  * Options
  * --outputs=value  where value is any valid positive integer 0-255
  *                  presented in either decimal or hexadecimal form
  */
-struct options
-{
-  unsigned long outputs;
+
+struct options {
+       unsigned long outputs;
+       unsigned long default_outputs;
+       unsigned long default_levels;
 };
 
+void gppio_ioctl ( int fd, const char *name, unsigned long option,
+                  int get_ioctl, int set_ioctl );
 int parseopts ( const int, char **argv, struct options * );
 unsigned long parseint ( const char * );
 void printhelp ();
 
-/*
- * Program Usage
- * 
- * setquickusb [options] device
- *
- */
 int main ( int argc, char* argv[] ) {
-  struct options opts = { UNDEFINED_UL }; /* initialise options structure */
-  int last_index = parseopts(argc,argv,&opts), fd;
-  quickusb_gppio_ioctl_data_t outputs;
-
-  if ( last_index == ( argc - 1 ) )
-    fd = open( argv[last_index], O_RDWR );
-  else {
-    printf("No device specified!\n");
-    exit(EXIT_FAILURE);
-  }
-  if ( fd < 0 ) {
-    printf( "Error: Could not open device %s: %s\n", argv[last_index], strerror(errno) );
-    exit(EXIT_FAILURE);
-  }
-
-  if ( opts.outputs != UNDEFINED_UL ) {
-    outputs = opts.outputs;
-    if ( ioctl(fd,QUICKUSB_IOC_GPPIO_SET_OUTPUTS, &(outputs) ) == 0 ) {}
-    else {
-      printf("Error: %s\n", strerror(errno));
-      exit(EXIT_FAILURE);
-    }
-  }
-  else {
-    if ( ioctl(fd,QUICKUSB_IOC_GPPIO_GET_OUTPUTS, &(outputs) ) == 0 ) {
-      printf("Outputs: %#x\n",outputs);
-    }
-    else {
-      printf("Error: %s\n", strerror(errno));
-      exit(EXIT_FAILURE);
-    }
-  }
-
-  close(fd);
-
-  return 0;
+       struct options opts = {
+               .outputs                = DO_NOTHING,
+               .default_outputs        = DO_NOTHING,
+               .default_levels         = DO_NOTHING,
+       };
+       int last_index = parseopts(argc,argv,&opts), fd;
+
+       if ( last_index == ( argc - 1 ) ) {
+               fd = open( argv[last_index], O_RDWR );
+       } else {
+               eprintf("No device specified!\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if ( fd < 0 ) {
+               eprintf( "Error: Could not open device %s: %s\n",
+                        argv[last_index], strerror(errno) );
+               exit(EXIT_FAILURE);
+       }
+
+       gppio_ioctl ( fd, "outputs", opts.outputs,
+                     QUICKUSB_IOC_GPPIO_GET_OUTPUTS,
+                     QUICKUSB_IOC_GPPIO_SET_OUTPUTS );
+       gppio_ioctl ( fd, "default-outputs", opts.default_outputs,
+                     QUICKUSB_IOC_GPPIO_GET_DEFAULT_OUTPUTS,
+                     QUICKUSB_IOC_GPPIO_SET_DEFAULT_OUTPUTS );
+       gppio_ioctl ( fd, "default-levels", opts.default_levels,
+                     QUICKUSB_IOC_GPPIO_GET_DEFAULT_LEVELS,
+                     QUICKUSB_IOC_GPPIO_SET_DEFAULT_LEVELS );
+
+       close(fd);
+       return 0;
+}
+
+void gppio_ioctl ( int fd, const char *name, unsigned long option,
+                  int get_ioctl, int set_ioctl ) {
+       quickusb_gppio_ioctl_data_t data;
+
+       switch ( option ) {
+       case DO_NOTHING:
+               break;
+       case SHOW_SETTING:
+               if ( ioctl ( fd, get_ioctl, &data ) != 0 ) {
+                       eprintf ( "Could not get %s: %s\n", name,
+                                 strerror ( errno ) );
+                       exit ( EXIT_FAILURE );
+               }
+               printf ( "%s = %#02x\n", name, data );
+               break;
+       default:
+               data = option;
+               if ( ioctl ( fd, set_ioctl, &data ) != 0 ) {
+                       eprintf ( "Could not set %s: %s\n", name,
+                                 strerror ( errno ) );
+                       exit ( EXIT_FAILURE );
+               }
+               break;
+       }
 }
 
 /*
@@ -89,60 +119,116 @@ int main ( int argc, char* argv[] ) {
  * argument list that is not an option
  */
 int parseopts ( const int argc, char **argv, struct options *opts ) {
-  int c;
-
-  while (1) {
-    int option_index = 0;
-    static struct option long_options[] = {
-      { "outputs", 1, NULL, 'o' },
-      { "help", 0, NULL, 'h' },
-      { 0, 0, 0, 0 }
-    };
-
-    if ( ( c = getopt_long ( argc, argv, "o:h", long_options, &option_index ) ) == -1 )
-      break;
-
-    switch(c) {
-    case 'o':
-      opts->outputs = parseint(optarg);
-      break;
-    case 'h':
-    case '?':
-      printhelp();
-      break;
-    default:
-      printf("Warning: unrecognised character code %o\n", c);
-      if (optarg)
-       printf("         with arg %s\n", optarg);
-    }
-  }
-
-  return optind;
+       int c;
+
+       while (1) {
+               int option_index = 0;
+               static struct option long_options[] = {
+                       { "outputs", optional_argument, NULL, 'o' },
+                       { "default-outputs", optional_argument, NULL, 'd' },
+                       { "default-levels", optional_argument, NULL, 'l' },
+                       { "help", 0, NULL, 'h' },
+                       { 0, 0, 0, 0 }
+               };
+
+               if ( ( c = getopt_long ( argc, argv, "o::d::l::h",
+                                        long_options,
+                                        &option_index ) ) == -1 ) {
+                       break;
+               }
+
+               switch(c) {
+                       case 'o':
+                               opts->outputs = parseint(optarg);
+                               break;
+                       case 'd':
+                               opts->default_outputs = parseint(optarg);
+                               break;
+                       case 'l':
+                               opts->default_levels = parseint(optarg);
+                               break;
+                       case 'h':
+                               printhelp();
+                               break;
+                       case '?':
+                       default:
+                               eprintf("Warning: unrecognised character code "
+                                       "%o\n", c);
+                               if (optarg) {
+                                       eprintf("         with arg %s\n",
+                                               optarg);
+                               }
+                               eprintf("Use -h to print help.\n");
+                               exit(EXIT_FAILURE);
+               }
+       }
+       return optind;
 }
 
 unsigned long parseint ( const char *nPtr ) {
-  unsigned long tmp;
-  char *endPtr;
+       unsigned long tmp;
+       char *endPtr;
+
+       if ( ! nPtr )
+               return SHOW_SETTING;
 
-  if ( *nPtr == '\0' ) {
-    printf("Error: No value specified\n");
-    exit(EXIT_FAILURE);
-  }
+       if ( *nPtr == '\0' ) {
+               eprintf("Error: No value specified\n");
+               exit(EXIT_FAILURE);
+       }
 
-  tmp = strtoul ( nPtr, &endPtr, 0 );
+       tmp = strtoul ( nPtr, &endPtr, 0 );
 
-  if ( *endPtr != '\0' ) {
-    printf("Error: Invalid value \"%s\"\n", nPtr);
-    exit(EXIT_FAILURE);
-  }
+       if ( *endPtr != '\0' ) {
+               eprintf("Error: Invalid value \"%s\"\n", nPtr);
+               exit(EXIT_FAILURE);
+       }
 
-  return tmp;
+       return tmp;
 }
 
 /*
  * Print helpful message
  */
 void printhelp () {
-  printf("Usage: setquickusb [options] device\n");
-  exit(EXIT_SUCCESS);
+       eprintf("\n"
+       "Usage: setquickusb [ --outputs=MASK ] DEVICE\n"
+       "setquickusb reads or sets the I/O port directions for a QuickUSB module.\n"
+       "If there are no options, it prints the output mask (in hexadecimal):\n"
+       "\n"
+       "       Example:\n"
+       "               setquickusb /dev/qu0ga\n"
+       "       Prints:\n"
+       "               Outputs: 0xf0\n"
+       "\n");
+       eprintf("If --outputs=MASK is specified, then the I/O port concerned will\n"
+       "be set to have that output mask. MASK is an integer from 0-255,\n"
+       "specified in decimal, or hexadecimal.\n"
+       "\n"
+       "       Example:\n"
+       "               setquickusb --outputs=0xf0 /dev/quoga\n"
+       "       Result:\n"
+       "               Port A has bits 7-4 set as outputs, and 3-0 as inputs.\n"
+       "\n");
+       eprintf("DEVICE is the relevant QuickUSB device and port. For example:\n"
+       "       /dev/qu0ga      First QUSB device, General Purpose Port A\n"
+       "       /dev/qu0gb      First QUSB device, General Purpose Port B\n"
+       "       /dev/qu0gc      First QUSB device, General Purpose Port C\n"
+       "       /dev/qu0gd      First QUSB device, General Purpose Port D\n"
+       "       /dev/qu0ge      First QUSB device, General Purpose Port E\n"
+       "\n"
+       "       /dev/qu0hc      First QUSB device, High Speed Port, Control\n"
+       "       /dev/qu0hd      First QUSB device, High Speed Port, Data\n"
+       "\n");
+       eprintf("Note 1: the high-speed port uses the same pins as G.P. ports B,D.\n"
+       "Note 2: the 16-bit HSP (/dev/qu0hd) is little-endian. Byte B is read first.\n"
+       "Note 3: the RS232 serial ports are not implemented in this driver.\n"
+       "\n"
+       "WARNING:\n"
+       "       Setting the output mask on a port configured for high-speed\n"
+       "       (either hc, or the corresponding gb,gd) will MESS IT UP.\n"
+       "       Don't do it!\n"
+       "\n");
+
+       exit(EXIT_SUCCESS);
 }