Logo Search packages:      
Sourcecode: udev-extras version File versions

modem-modeswitch.c

/*
 * Modem mode switcher
 *
 * Copyright (C) 2008  Dan Williams <dcbw@redhat.com>
 * Copyright (C) 2008  Peter Henn <support@option.com>
 *
 * Heavily based on the 'ozerocdoff' tool by Peter Henn.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details:
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
#include <getopt.h>

#include <usb.h>

#include "utils.h"

#include "ma8280p_us.h"
#include "option.h"

struct usb_dev_handle *handle = NULL;

typedef struct usb_device * (*FindFunc) (int vid, int pid);
typedef int (*SwitchFunc) (struct usb_dev_handle *dh, struct usb_device *dev);

typedef enum {
      ST_UNKNOWN = 0,
      ST_OPTION_ZEROCD,
      ST_MA8280P
} SwitchType;

typedef struct SwitchEntry {
      SwitchType st;
      const char *clopt;
      FindFunc find_func;
      SwitchFunc switch_func;
} SwitchEntry;

static SwitchEntry switch_types[] = {
      { ST_OPTION_ZEROCD, "option-zerocd", option_zerocd_find, option_zerocd_switch },
      { ST_MA8280P, "mobile-action-8280p", NULL, ma8280p_switch },
      { ST_UNKNOWN, NULL, NULL }
};

static struct usb_device *
generic_find (int vid, int pid)
{
      struct usb_bus *bus;
      struct usb_device *dev;

      for (bus = usb_get_busses(); bus; bus = bus->next) {
            for (dev = bus->devices; dev; dev = dev->next) {
                  if (dev->descriptor.idVendor == vid && dev->descriptor.idProduct == pid) {
                        debug ("Found device '%s'", dev->filename);
                        return dev;
                  }
            }
      }
      return NULL;
}

static void
release_usb_device (int param)
{
      usb_release_interface (handle, 0);
      usb_close (handle);
}

static void
print_usage (void)
{
      printf ("Usage: modem-modeswitch [-hdq] [-l <file>] -v <vendor-id> -p <product-id> -t <type>\n"
              " -h, --help               show this help message\n"
              " -v, --vendor <n>         target USB vendor ID\n"
              " -p, --product <n>        target USB product ID\n"
              " -t, --type <type>        type of switch to attempt, varies by device:\n"
              "                               option-zerocd         - For many newer Option N.V. devices\n"
              "                               mobile-action-8280p   - For Mobile Action 8xxxP USB cables\n"
              " -l, --log <file>         log output to a file\n"
              " -q, --quiet              don't print anything to stdout\n"
              " -d, --debug              display debugging messages\n\n"
              "Examples:\n"
              "   modem-modeswitch -v 0x0af0 -p 0xc031 -t option-zerocd\n");
}

static SwitchEntry *
parse_type (const char *s)
{
      SwitchEntry *entry = &switch_types[0];

      while (entry->clopt) {
            if (!strcmp (entry->clopt, s))
                  return entry;
            entry++;
      }

      return NULL;
}

static void
do_exit (int val)
{
      log_shutdown ();
      exit (val);
}

int main(int argc, char **argv)
{
      static struct option options[] = {
            { "help",    no_argument,       NULL, 'h' },
            { "vendor",  required_argument, NULL, 'v' },
            { "product", required_argument, NULL, 'p' },
            { "type",    required_argument, NULL, 't' },
            { "log",     required_argument, NULL, 'l' },
            { "debug",   no_argument,       NULL, 'd' },
            { "quiet",   no_argument,       NULL, 'q' },
            { NULL, 0, NULL, 0}
      };

      struct usb_device *dev;
      int vid = 0, pid = 0;
      const char *logpath = NULL;
      char buffer[256];
      int ret, quiet = 0, debug = 0;
      SwitchEntry *sentry = NULL;

      while (1) {
            int option;

            option = getopt_long(argc, argv, "hv:p:l:t:dq", options, NULL);
            if (option == -1)
                  break;

            switch (option) {
            case 'v':
                  vid = strtol (optarg, NULL, 0);
                  break;
            case 'p':
                  pid = strtol (optarg, NULL, 0);
                  break;
            case 't':
                  sentry = parse_type (optarg);
                  if (!sentry) {
                        error ("unknown switch type '%s'", optarg);
                        print_usage ();
                        exit (1);
                  }
                  break;
            case 'l':
                  logpath = optarg;
                  break;
            case 'q':
                  quiet = 1;
                  break;
            case 'd':
                  debug = 1;
                  break;
            case 'h':
            default:
                  print_usage ();
                  exit (1);
            }
      }

      if (log_startup (logpath, debug, quiet)) {
            fprintf (stderr, "Couldn't open/create logfile %s", logpath);
            exit (2);
      }

      if (!sentry) {
            if (!quiet)
                  print_usage ();
            else
                  error ("missing device switch type.");
            do_exit (3);
      }

      if (!vid || !pid) {
            if (!quiet)
                  print_usage ();
            else
                  error ("missing vendor and device IDs.");
            do_exit (3);
      }

      usb_init();

      if (usb_find_busses() < 0) {
            error ("no USB busses found.");
            do_exit (4);
      }

      if (usb_find_devices() < 0) {
            error ("no USB devices found.");
            do_exit (4);
      }

      if (sentry->find_func)
            dev = (*sentry->find_func) (vid, pid);
      else
            dev = generic_find (vid, pid);
      if (dev == NULL) {
            error ("no device found.");
            do_exit (5);
      }

      handle = usb_open (dev);
      if (handle == NULL) {
            error ("%s: could not access the device.",
                     dev->filename);
            do_exit (6);
      }

      /* detach running default driver */
      signal (SIGTERM, release_usb_device);
      ret = usb_get_driver_np (handle, 0, buffer, sizeof (buffer));
      if (ret == 0) {
            debug ("%s: found already attached driver '%s'", dev->filename, buffer);

            ret = usb_detach_kernel_driver_np (handle, 0);
            if (ret != 0) {
                  debug ("%s: error: unable to detach current driver.", dev->filename);
                  usb_close (handle);
                  do_exit (7);
            }
      }

      ret = usb_claim_interface (handle, 0);
      if (ret != 0) {
            debug ("%s: couldn't claim device's USB interface: %d.",
                   dev->filename, ret);
            usb_close (handle);
            do_exit (8);
      }

      ret = (*sentry->switch_func) (handle, dev);
      if (ret < 0) {
            debug ("%s: failed to switch device to modem mode.", dev->filename);
            usb_release_interface (handle, 0);
            usb_close (handle);
            do_exit(9);
      }

      usb_release_interface (handle, 0);

      ret = usb_close (handle);
      if (ret < 0)
            debug ("%s: failed to close the device.", dev->filename);

      do_exit (0);
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index