Attached is initial version of mine, which implements port power
control in user space.

It works fine for me.  Thanks Alan and David for the suggestions and
patience.

The problem is that we need to select proper USB hub.  It seems that
many USB hub (especially root hub) omits this feature.

I found that there are three products which support this feature.

   Elecom's U2H-G4S: www.elecom.co.jp (indicator depends on power)
   Sanwa Supply's USB-HUB14GPH: www.sanwa.co.jp (indicators don't)
   Targus, Inc.'s PAUH212: www.targus.com (indicators don't)
-- 
/*
 * Copyright (C) 2006 Free Software Initiative of Japan
 *
 * Author: NIIBE Yutaka  <gniibe at fsij.org>
 *
 * This file can be distributed under the terms and conditions of the
 * GNU General Public License version 2 (or later).
 *
 */

#include <usb.h>
#include <stdio.h>

#define USB_RT_HUB			(USB_TYPE_CLASS | USB_RECIP_DEVICE)
#define USB_RT_PORT			(USB_TYPE_CLASS | USB_RECIP_OTHER)
#define USB_PORT_FEAT_POWER		8
#define USB_PORT_FEAT_INDICATOR         22
#define USB_DIR_IN			0x80		/* to host */

#define COMMAND_SET_LED   0
#define COMMAND_SET_POWER 1
#define HUB_LED_GREEN 2

static void
usage (const char *progname)
{
  fprintf (stderr, "Usage: %s [-b BUSNUM] [-d DEVNUM] [-P PORT] [{-l [VALUE]}|{-p [VALUE]}]\n", progname);
}

/*
 * HUB-CTRL  -  program to control port power/led of USB hub
 *
 *   # hub-ctrl -b 1 -d 2 -P 1 -p            // Power off at port 1
 *   # hub-ctrl -b 1 -d 2 -P 1 -p 1          // Power on at port 1
 *   # hub-ctrl -b 1 -d 2 -P 2 -l            // LED on at port 1
 *
 * Requirement: USB hub which implements port power control / indicator control
 *      Work fine:
 *              Elecom's U2H-G4S: www.elecom.co.jp (indicator depends on power)
 *		Sanwa Supply's USB-HUB14GPH: www.sanwa.co.jp (indicators don't)
 *		Targus, Inc.'s PAUH212: www.targus.com (indicators don't)
 *
 */
int
main (int argc, const char *argv[])
{
  int busnum = 0, devnum = 0;
  int cmd = COMMAND_SET_POWER;
  int port = 1;
  int value = 0;
  struct usb_bus *busses;
  struct usb_bus *bus;
  int i;

  for (i = 1; i < argc; i++)
    if (argv[i][0] == '-')
      switch (argv[i][1])
	{
	case 'b':
	  if (++i >= argc)
	    {
	      usage (argv[0]);
	      exit (1);
	    }
	  busnum = atoi (argv[i]);
	  break;

	case 'd':
	  if (++i >= argc)
	    {
	      usage (argv[0]);
	      exit (1);
	    }
	  devnum = atoi (argv[i]);
	  break;

	case 'P':
	  if (++i >= argc)
	    {
	      usage (argv[0]);
	      exit (1);
	    }
	  port = atoi (argv[i]);
	  break;

	case 'l':
	  cmd = COMMAND_SET_LED;
	  if (++i < argc)
	    value = atoi (argv[i]);
	  else
	    value = HUB_LED_GREEN;
	  break;

	case 'p':
	  cmd = COMMAND_SET_POWER;
	  if (++i < argc)
	    value = atoi (argv[i]);
	  else
	    value= 0;
	  break;

	default:
	  usage (argv[0]);
	  exit (1);
	}

  usb_init();
  usb_find_busses();
  usb_find_devices();

  busses = usb_get_busses();
  if (busses == NULL)
    {
      perror ("failed to access USB");
      exit (1);
    }

  bus = busses->next;
  for (bus = busses; bus; bus = bus->next)
    {
      struct usb_device *dev;
      usb_dev_handle *uh;
      int result = 0;
      int request, feature, index;

      if (atoi (bus->dirname) != busnum)
	continue;

      for (dev = bus->devices; dev; dev = dev->next)
	{
	  if (dev->devnum != devnum)
	    continue;

	  if (dev->descriptor.bDeviceClass != USB_CLASS_HUB)
	    {
	      fprintf (stderr, "Device is not hub.\n");
	      exit (1);
	    }

	  uh = usb_open (dev);

	  if (uh != NULL)
	    {
	      unsigned char buf[1024];
	      int len;

	      if ((len = usb_control_msg (uh, 
					  USB_DIR_IN | USB_RT_HUB,
					  USB_REQ_GET_DESCRIPTOR,
					  USB_DT_HUB << 8, 0, 
					  buf, 1024, 1000)) > 0)
		{
		  /* Should check wHubCharacteristic for power control */
		  ;
		}
	      else
		perror ("usb_get_descriptor");

	      if (cmd == COMMAND_SET_POWER)
		if (value)
		  {
		    request = USB_REQ_SET_FEATURE;
		    feature = USB_PORT_FEAT_POWER;
		    index = port;
		  }
		else
		  {
		    request = USB_REQ_CLEAR_FEATURE;
		    feature = USB_PORT_FEAT_POWER;
		    index = port;
		  }
	      else
		{
		  request = USB_REQ_SET_FEATURE;
		  feature = USB_PORT_FEAT_INDICATOR;
		  index = (value << 8) | port;
		}

	      if (usb_control_msg (uh, USB_RT_PORT, request, feature, index,
				   NULL, 0, 1000) < 0)
		{
		  perror ("failed to control.\n");
		  result = 1;
		}
	    }
	  else
	    {
	      perror ("failed to open");
	      result = 1;
	    }

	  usb_release_interface(uh, 0);
	  usb_close (uh);
	  exit (result);
	}
    }

  fprintf (stderr, "Device not found.\n");
  exit (1);
}

Reply via email to