/* $Id: drv_USBHUB.c 1126 2010-07-13 03:25:44Z michael $ * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_USBHUB.c $ * * driver for USBHUB * * Copyright (C) 2006 Ernst Bachmann * Copyright (C) 2004,2006 The LCD4Linux Team * * Based on the USBLCD driver Copyright (C) 2003 Michael Reinelt * * This file is part of LCD4Linux. * * LCD4Linux 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, or (at your option) * any later version. * * LCD4Linux 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * * exported fuctions: * * struct DRIVER drv_USBHUB * */ #include "config.h" #ifdef HAVE_USB_H #include #else #error The USB-HUB driver only makes sense with USB support #endif #include "debug.h" #include "cfg.h" #include "qprintf.h" #include "udelay.h" #include "drv.h" #include "drv_generic_gpio.h" #define HUB_CONTROL_PORT 0x23 #define HUB_SET_FEATURE 3 #define HUB_SET_INDICATOR 22 static char Name[] = "USBHUB"; /* TODO: Better not specify defaults here, * instead look for the first suitable HUB arround if * no Vendor/Product specified in config. */ static unsigned int hubVendor = 0x0409; static unsigned int hubProduct = 0x0058; static usb_dev_handle *hub = NULL; typedef struct _usb_hub_descriptor { u_int8_t bLength; u_int8_t bDescriptorType; u_int8_t nNbrPorts; u_int8_t wHubCharacteristicLow; u_int8_t wHubCharacteristicHigh; u_int8_t bPwrOn2PwrGood; u_int8_t bHubContrCurrent; u_int8_t deviceRemovable; u_int8_t PortPwrCtrlMask[8]; } usb_hub_descriptor; /****************************************/ /*** hardware dependant functions ***/ /****************************************/ static int drv_UH_open(void) { struct usb_bus *busses, *bus; struct usb_device *dev; hub = NULL; info("%s: scanning for an USB HUB (0x%04x:0x%04x)...", Name, hubVendor, hubProduct); usb_init(); usb_find_busses(); usb_find_devices(); busses = usb_get_busses(); for (bus = busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if ((dev->descriptor.idVendor == hubVendor) && (dev->descriptor.idProduct == hubProduct)) { unsigned int v = dev->descriptor.bcdDevice; info("%s: found USBHUB V%1d%1d.%1d%1d on bus %s device %s", Name, (v & 0xF000) >> 12, (v & 0xF00) >> 8, (v & 0xF0) >> 4, (v & 0xF), bus->dirname, dev->filename); if (dev->descriptor.bDeviceClass != USB_CLASS_HUB) { error("%s: the specified device claims to be no HUB", Name); return -1; } hub = usb_open(dev); if (!hub) { error("%s: usb_open() failed!", Name); return -1; } return 0; } } } error("%s: could not find a USB HUB", Name); return -1; } static int drv_UH_close(void) { debug("closing USB handle"); usb_close(hub); return 0; } /* * Set the Indicator status on port "num+1" to val. * according to the USB Specification, the following values would be allowed: * * 0 : Automatic color (display link state etc) * 1 : Amber * 2 : Green * 3 : Off * 4..255: Reserved * */ static int drv_UH_set(const int num, const int val) { int ret; if (!hub) return -1; if (val < 0 || val > 3) { info("%s: value %d out of range (0..3)", Name, val); return -1; } if ((ret = usb_control_msg(hub, HUB_CONTROL_PORT, HUB_SET_FEATURE, HUB_SET_INDICATOR, (val << 8) | (num + 1), NULL, 0, 1000)) != 0) { info("%s: usb_control_msg failed with %d", Name, ret); return -1; } return 0; } static int drv_UH_start(const char *section, const __attribute__ ((unused)) int quiet) { char *buf; usb_hub_descriptor hub_desc; int ret; buf = cfg_get(section, "Vendor", NULL); if (buf) { if (!*buf) { error("%s: Strange Vendor Specification", Name); return -1; } if (sscanf(buf, "0x%x", &hubVendor) != 1) { error("%s: Strange Vendor Specification: [%s]", Name, buf); return -1; } } buf = cfg_get(section, "Product", NULL); if (buf) { if (!*buf) { error("%s: Strange Product Specification", Name); return -1; } if (sscanf(buf, "0x%x", &hubProduct) != 1) { error("%s: Strange Product Specification: [%s]", Name, buf); return -1; } } if (drv_UH_open() < 0) { return -1; } if ((ret = usb_control_msg(hub, USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, USB_DT_HUB << 8, 0, (char *) &hub_desc, sizeof(hub_desc), 1000)) <= 8) { error("%s: hub_get_descriptor failed with %d", Name, ret); drv_UH_close(); return -1; } GPOS = hub_desc.nNbrPorts; debug("%s: HUB claims to have %d ports. Configuring them as GPOs", Name, GPOS); if (!(hub_desc.wHubCharacteristicLow & 0x80)) { error("%s: HUB claims to have no Indicator LEDs (Characteristics 0x%04x). Bailing out.", Name, (hub_desc.wHubCharacteristicHigh << 8) | hub_desc.wHubCharacteristicLow); /* The HUB Tells us that there are no LEDs to control. Breaking? Maybe don't trust it and continue anyways? */ drv_UH_close(); return -1; } return 0; } /****************************************/ /*** plugins ***/ /****************************************/ /* none at the moment... */ /****************************************/ /*** widget callbacks ***/ /****************************************/ /* using drv_generic_text_draw(W) */ /* using drv_generic_text_icon_draw(W) */ /* using drv_generic_text_bar_draw(W) */ /****************************************/ /*** exported functions ***/ /****************************************/ /* list models */ int drv_UH_list(void) { printf("USBHUB"); return 0; } /* initialize driver & display */ int drv_UH_init(const char *section, const int quiet) { int ret; int i; info("%s: %s", Name, "$Rev: 1126 $"); /* start display */ if ((ret = drv_UH_start(section, quiet)) != 0) return ret; /* real worker functions */ drv_generic_gpio_real_set = drv_UH_set; /* initialize generic GPIO driver */ if ((ret = drv_generic_gpio_init(section, Name)) != 0) return ret; /* register gpio widget, done already by generic_gpio */ /* register plugins */ /* none at the moment... */ /* greeting */ if (!quiet) { /* Light all LEDS green for a greeting */ for (i = 0; i < GPOS; ++i) { drv_UH_set(i, 2); } sleep(1); for (i = 0; i < GPOS; ++i) { drv_UH_set(i, 3); /* OFF */ } } return 0; } /* close driver & display */ int drv_UH_quit(const int quiet) { int i; debug("%s: shutting down.", Name); /* say goodbye... */ if (!quiet) { /* Light all LEDS amber for a goodbye */ for (i = 0; i < GPOS; ++i) { drv_UH_set(i, 1); } sleep(1); } drv_generic_gpio_quit(); drv_UH_close(); info("%s: shutdown complete.", Name); return 0; } DRIVER drv_USBHUB = { .name = Name, .list = drv_UH_list, .init = drv_UH_init, .quit = drv_UH_quit, };