aboutsummaryrefslogtreecommitdiffstats
path: root/drv_USBHUB.c
diff options
context:
space:
mode:
Diffstat (limited to 'drv_USBHUB.c')
-rw-r--r--drv_USBHUB.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/drv_USBHUB.c b/drv_USBHUB.c
new file mode 100644
index 0000000..f0050da
--- /dev/null
+++ b/drv_USBHUB.c
@@ -0,0 +1,340 @@
+/* $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 <e.bachmann@xebec.de>
+ * Copyright (C) 2004,2006 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
+ *
+ * Based on the USBLCD driver Copyright (C) 2003 Michael Reinelt <michael@reinelt.co.at>
+ *
+ * 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 <usb.h>
+#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,
+};