/** \file server/drivers/hd44780-uss720.c * \c uss720 connection type of \c hd44780 driver for Hitachi HD44780 based LCD displays. * * The LCD is operated in its 8 bit-mode to be connected to a uss720 based Belkin F5U002. */ /* * Copyright (c) 2008 Eric Pooch * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * This is a uss720 driver module for Hitachi HD44780 based LCD displays * connected to a uss720 USB-to-IEEE 1284 Bridge chip in 8 bit mode. * The uss720 chip is found in many (but not all) * Belkin F5U002 USB->parallel printer adapters. * * Applicable Data Sheets: * - http://digilander.libero.it/demarchidaniele/qcamvc/uss-720.pdf * * Wiring is same as winamp connection. * Uncomment //#define USS720_MAC_USB_LCD_KIT_WIRING 1 below to use a * Mac USB LCD Kit instead. * */ #include "hd44780-uss720.h" #include "hd44780-low.h" #include "lpt-port.h" #include "report.h" #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif enum { SSPMode = 0, PS2Mode, HHCMode, ECPMode, EPPMode, } /*ECRMode*/; enum { StatusIndex = 0, ControlIndex, ExtControlIndex, USSSTZControlIndex, DataIndex, EPPIndex, USSSTZSetupIndex, } /*RegisterDataByteIndex*/; enum { DataRegAdr = 0, StatusRegAdr, ControlRegAdr, EPPAddressRegAdr, EPPDataRegAdr, ECPCommandRegAdr, ExtControlRegAdr, USSSTZControlRegAdr, USSSTZSetupRegAdr, } /*RegisterAddress*/; /* connection type specific functions to be exposed using pointers in init() */ void uss720_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch); void uss720_HD44780_backlight(PrivateData *p, unsigned char state); void uss720_HD44780_close(PrivateData *p); static void uss720_HD44780_uPause(PrivateData *p, int usecs); //#define USS720_MAC_USB_LCD_KIT_WIRING 1 #ifdef USS720_MAC_USB_LCD_KIT_WIRING /* Mac OS X USB LCD Kit wiring */ #define EN1 STRB #define EN2 INIT #define EN3 0 #define RS SEL #define BL INIT #define VCC LF #else /* winamp wiring */ #define EN1 STRB #define EN2 SEL #define EN3 LF #define RW LF #define RS INIT #define BL SEL #define LE LF #define VCC 0 #endif static const unsigned char EnMask[] = { EN1, EN2, EN3 }; /* local helper functions not exposed */ int uss720_get_1284_register(usb_dev_handle *usbHandle, unsigned int regIndex, unsigned char *value); int uss720_set_1284_register(usb_dev_handle *usbHandle, unsigned int regAddress, unsigned char value); int uss720_set_1284_mode(usb_dev_handle *usbHandle, unsigned int mode); /** * Initialize the driver. * \param drvthis Pointer to driver structure. * \retval 0 Success. * \retval -1 Error. */ int hd_init_uss720(Driver *drvthis) { unsigned int vendor_id, product_id; struct usb_bus *bus; PrivateData *p = (PrivateData*) drvthis->private_data; p->hd44780_functions->senddata = uss720_HD44780_senddata; p->hd44780_functions->backlight = uss720_HD44780_backlight; p->hd44780_functions->close = uss720_HD44780_close; p->hd44780_functions->uPause = uss720_HD44780_uPause; /* load config */ vendor_id = drvthis->config_get_int(drvthis->name, "VendorID", 0, 0x1293); product_id = drvthis->config_get_int(drvthis->name, "ProductID", 0, 0x0002); /* Hardware Init */ /* try to find USB device */ usb_init(); usb_find_busses(); usb_find_devices(); p->usbHandle = NULL; p->usbIndex = 0; for (bus = usb_get_busses(); bus != NULL; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev != NULL; dev = dev->next) { /* Check if this device is a uss720 device */ if (dev->descriptor.idVendor != vendor_id || dev->descriptor.idProduct != product_id) { continue; } /* uss720 device found; try to open it */ p->usbHandle = usb_open(dev); if (p->usbHandle == NULL) { report(RPT_WARNING, "hd_init_uss720: unable to open device"); continue; } debug(RPT_DEBUG, "hd_init_uss720: opening device succeeded"); errno = 0; if (usb_claim_interface(p->usbHandle, p->usbIndex) < 0) { #if defined(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP) report(RPT_WARNING, "hd_init_uss720: interface may be claimed by " "kernel driver, attempting to detach it"); errno = 0; if ((usb_detach_kernel_driver_np(p->usbHandle, p->usbIndex) < 0) || (usb_claim_interface(p->usbHandle, p->usbIndex) < 0)) { report(RPT_ERR, "hd_init_uss720: unable to re-claim interface: %s", strerror(errno)); usb_close(p->usbHandle); continue; } #else report(RPT_ERR, "hd_init_uss720: unable to claim interface: %s", strerror(errno)); usb_close(p->usbHandle); continue; #endif } /* Use the alternate, vendor-specific, interface so we have access to the registers */ errno = usb_set_altinterface(p->usbHandle, 2); if (errno) { report(RPT_WARNING, "hd_init_uss720: unable to set alt interface: %s", strerror(errno)); usb_close(p->usbHandle); continue; } /* Make sure the port is in SSP (Standard) mode for full software control. */ errno = uss720_set_1284_mode(p->usbHandle, SSPMode); if (errno) { report(RPT_WARNING, "hd_init_uss720: unable to set SSP mode: %d", errno);//strerror(errno)); /* probably not fatal, so try to keep going with this device */ } /* init the HD44780 LCD */ common_init(p, IF_8BIT); return 0; } } report(RPT_ERR, "hd_init_uss720: no (matching) USS720 device found"); return -1; } /** * Send data or commands to the display. * \param p Pointer to driver's private data structure. * \param displayID ID of the display (or 0 for all) to send data to. * \param flags Defines whether to end a command or data. * \param ch The value to send. */ void uss720_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch) { unsigned char enableLines = 0, portControl; if (flags == RS_DATA) portControl = RS; /* enable RS for data */ else portControl = 0; /* disable RS for instruction */ portControl |= VCC; /* keep the power on */ portControl |= p->backlight_bit; if (displayID == 0) enableLines = EnMask[0] | ((p->have_backlight) ? 0 : EnMask[1]) | ((p->numDisplays == 3) ? EnMask[2] : 0); else enableLines = EnMask[displayID - 1]; uss720_set_1284_register(p->usbHandle, ControlRegAdr, portControl ^ OUTMASK); uss720_set_1284_register(p->usbHandle, DataRegAdr, ch); p->hd44780_functions->uPause(p, 1); uss720_set_1284_register(p->usbHandle, ControlRegAdr, (portControl | enableLines ) ^ OUTMASK); p->hd44780_functions->uPause(p, 1); uss720_set_1284_register(p->usbHandle, ControlRegAdr, portControl ^ OUTMASK); } /** * Turn display backlight on or off. * \param p Pointer to driver's private data structure. * \param state New backlight status. */ void uss720_HD44780_backlight(PrivateData *p, unsigned char state) { p->backlight_bit = (state?0:BL); } /** * Close the driver (do necessary clean-up). * \param p Pointer to driver's private data structure. */ void uss720_HD44780_close(PrivateData *p) { if (p->usbHandle != NULL) { usb_close(p->usbHandle); p->usbHandle = NULL; } } /** * Pause as needed (= a long time). * \param p Pointer to driver's private data structure. * \param usecs Pause duration. */ static void uss720_HD44780_uPause(PrivateData *p, int usecs) { usleep(10*usecs); } #pragma mark - #pragma mark -Basic Register Methods int uss720_get_1284_register(usb_dev_handle *usbHandle, unsigned int regIndex, unsigned char *value) { int res = 0; unsigned char regData[128]; res = usb_control_msg(usbHandle, /* bmRequestType */ 0xc0,/*USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,*/ /* bRequest */ 3, /* wValue */ (unsigned int)regIndex<<8, /* wIndex */ 0, /* Data */ (char *)regData, /* wLength */ 7, 10000 ); if (res) { } else if (value && (regIndex < 8)) { *value = regData[(int)regIndex]; } return res; } int uss720_set_1284_register(usb_dev_handle *usbHandle, unsigned int regAddress, unsigned char value) { return usb_control_msg(usbHandle, /* bmRequestType */ 0x40,/*USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,*/ /* bRequest */ 4, /* wValue */ ((unsigned int)regAddress<<8 | (unsigned int) value), /* wIndex */ 0, /* Data */ NULL, /* wLength */ 0, 10000 ); } #pragma mark - #pragma mark -Extended Methods int uss720_set_1284_mode(usb_dev_handle *usbHandle, unsigned int mode) { unsigned char regByte = 0x00; int res = 0; res = uss720_get_1284_register(usbHandle, 3, ®Byte); regByte &= ~0x01; res = uss720_set_1284_register(usbHandle, 7, regByte); if (res) return res; res = uss720_get_1284_register(usbHandle, 2, ®Byte); regByte &= ~(mode<<5); /* Mask off the mode bits 7-5. */ regByte |= (mode<<5); /* Set the mode bits 7-5. */ return uss720_set_1284_register(usbHandle, 6, regByte); }