From 543579946cacfd80e2e438b8342be6b6b84dffbc Mon Sep 17 00:00:00 2001 From: michael <michael> Date: Wed, 14 Mar 2007 23:13:37 +0000 Subject: [PATCH 1/1] Add support for Parallel Cable III (and clones) --- README | 40 ++++++++++++---- usb-driver.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++----- usb-driver.h | 1 + 3 files changed, 149 insertions(+), 20 deletions(-) diff --git a/README b/README index 8d3ca25..ae60eeb 100644 --- a/README +++ b/README @@ -1,10 +1,13 @@ -This library emulates Jungo Windrvr USB functions in userspace which are -required by XILINX impact to access the Platform cable USB. With this library -it is possible to access the cable without loading a proprietary kernel module -which breaks with every new kernel release. It uses the USB functions provided -by the libusb userspace library instead and should work on every kernel version -which is supported by libusb. It was written against impact from ISE Webpack -9.1SP1 and tested with the following software: +This library emulates Jungo Windrvr USB and parallel port functions in +userspace which are required by XILINX impact to access the Platform cable USB +and Parallel Cable III. +With this library it is possible to access the cables without loading a +proprietary kernel module which breaks with every new kernel release. It uses +the functions provided by the libusb userspace library for USB access and +the kernel interface at /dev/parport0 for parallel port access instead and +should work on every kernel version which is supported by libusb and supports +ppdev. It was written against impact from ISE Webpack 9.1SP1 and tested with +the following software: * ISE Webpack 9.1SP2 * ISE Webpack 9.1SP1 @@ -21,7 +24,11 @@ $ export LD_PRELOAD=/path/to/libusb-driver.so (for sh shells) $ setenv LD_PRELOAD /path/to/libusb-driver.so (for csh shells) $ impact -To use the device as ordinary user, put the following line in a new + +Notes for the USB cable +======================= + +To use the device as an ordinary user, put the following line in a new file in /etc/udev/rules.d/ and restart udev: ACTION=="add", BUS=="usb", SYSFS{idVendor}=="03fd", MODE="666" @@ -40,3 +47,20 @@ these steps: 3. copy the file /path/to/ISE/bin/lin/xusbdfwu.hex to /usr/share/xusbdfwu.hex 4. restart udev and re-plug the cable + + +Notes for the parallel cable +============================ + +To access the parallel port from userspace, the kernel needs to be built with +the features "Parallel port support" (CONFIG_PARPORT), "PC-style hardware" +(CONFIG_PARPORT_PC) and "Support for user-space parallel port device drivers" +(CONFIG_PPDEV) builtin or as modules. If these features are built as modules, +they need to be loaded before using this library. +These modules are called: +parport +parport_pc +ppdev + + +To use the device as an ordinary user, put the user in the group 'lp' diff --git a/usb-driver.c b/usb-driver.c index 825c35c..881b67b 100644 --- a/usb-driver.c +++ b/usb-driver.c @@ -1,4 +1,4 @@ -/* libusb connector for XILINX impact +/* libusb/ppdev connector for XILINX impact * * Copyright (c) 2007 Michael Gernoth <michael@gernoth.net> * @@ -38,10 +38,17 @@ #include <pthread.h> #include <errno.h> #include <inttypes.h> +#include <sys/ioctl.h> +#include <linux/parport.h> +#include <linux/ppdev.h> #include "usb-driver.h" static int (*ioctl_func) (int, int, void *) = NULL; static int windrvrfd = -1; +static int parportfd = -1; +static int parportnum = 0; +static unsigned long ppbase = 0; +static unsigned long ecpbase = 0; FILE *modulesfp = NULL; static int modules_read = 0; static struct usb_bus *busses = NULL; @@ -53,7 +60,6 @@ static int ints_enabled = 0; static pthread_mutex_t int_wait = PTHREAD_MUTEX_INITIALIZER; #define NO_WINDRVR 1 -#undef PARPORT #ifdef DEBUG #define DPRINTF(format, args...) fprintf(stderr, format, ##args) @@ -233,18 +239,55 @@ int usb_deviceinfo(unsigned char *buf) { int pp_transfer(WD_TRANSFER *tr, int fd, unsigned int request, unsigned char *wdioctl) { int ret = 0; + unsigned char val; DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n", (unsigned long)tr->dwPort, tr->cmdTrans, tr->dwBytes, tr->fAutoinc, tr->dwOptions); + + val = tr->Data.Byte; #ifdef DEBUG if (tr->cmdTrans == 13) - DPRINTF("write byte: %d\n", tr->Data.Byte); + DPRINTF("write byte: %d\n", val); #endif #ifndef NO_WINDRVR ret = (*ioctl_func) (fd, request, wdioctl); +#else + if (parportfd < 0) + return ret; + + switch(tr->cmdTrans) { + case 10: /* Read Byte */ + if ((unsigned long)tr->dwPort == ppbase) { /* Data Port */ + ret = 0; /* We don't support reading of the data port */ + } else if ((unsigned long)tr->dwPort == ppbase + 1) { /* Status Port */ + DPRINTF("status port\n"); + ret = ioctl(parportfd, PPRSTATUS, &val); + } else if ((unsigned long)tr->dwPort == ppbase + 2) { /* Control Port */ + DPRINTF("control port\n"); + ret = ioctl(parportfd, PPRCONTROL, &val); + } + break; + case 13: /* Write Byte */ + if ((unsigned long)tr->dwPort == ppbase) { /* Data Port */ + DPRINTF("data port\n"); + ret = ioctl(parportfd, PPWDATA, &val); + } else if ((unsigned long)tr->dwPort == ppbase + 1) { /* Status Port */ + ret = 0; /* Status Port is readonly */ + } else if ((unsigned long)tr->dwPort == ppbase + 2) { /* Control Port */ + DPRINTF("control port\n"); + ret = ioctl(parportfd, PPWCONTROL, &val); + } + break; + default: + fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr->cmdTrans); + ret = -1; + break; + } + + tr->Data.Byte = val; #endif DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n", @@ -282,20 +325,62 @@ int do_wdioctl(int fd, unsigned int request, unsigned char *wdioctl) { case CARD_REGISTER_OLD: case CARD_REGISTER: - /* TODO: Implement for LPT-support */ -#ifdef PARPORT + DPRINTF("CARD_REGISTER\n"); { struct card_register* cr = (struct card_register*)(wdheader->data); + char ppdev[32]; + + DPRINTF("Items: %lu, Addr: 0x%lx, bytes: %lu, bar: %lu\n", + cr->Card.dwItems, + (unsigned long)cr->Card.Item[0].I.IO.dwAddr, + cr->Card.Item[0].I.IO.dwBytes, + cr->Card.Item[0].I.IO.dwBar); + + DPRINTF("Items: %lu, Addr: 0x%lx, bytes: %lu, bar: %lu\n", + cr->Card.dwItems, + (unsigned long)cr->Card.Item[1].I.IO.dwAddr, + cr->Card.Item[1].I.IO.dwBytes, + cr->Card.Item[1].I.IO.dwBar); #ifndef NO_WINDRVR ret = (*ioctl_func) (fd, request, wdioctl); #else - /* TODO: Open /dev/parport, check, ... */ - cr->hCard = 1; + if (parportfd < 0) { + snprintf(ppdev, sizeof(ppdev), "/dev/parport%d", parportnum); + DPRINTF("opening %s\n", ppdev); + parportfd = open(ppdev, O_RDWR|O_EXCL); + parportnum++; + } + + if (parportfd >= 0) { + int pmode; + + if (ioctl(parportfd, PPCLAIM) == -1) + return ret; + + pmode = IEEE1284_MODE_COMPAT; + if (ioctl(parportfd, PPNEGOT, &pmode) == -1) + return ret; + + if (cr->Card.dwItems > 1) { + ecpbase = cr->Card.Item[1].I.IO.dwBytes; + /* TODO: Implement ECP mode */ +#if 0 + pmode = IEEE1284_MODE_ECP; + + if (ioctl(parportfd, PPNEGOT, &pmode) == -1) { + pmode = IEEE1284_MODE_COMPAT; + if (ioctl(parportfd, PPNEGOT, &pmode) == -1) + return ret; + } +#endif + } + + cr->hCard = parportfd; + ppbase = (unsigned long)cr->Card.Item[0].I.IO.dwAddr; + } #endif DPRINTF("hCard: %lu\n", cr->hCard); } -#endif - DPRINTF("CARD_REGISTER\n"); break; case USB_TRANSFER: @@ -565,6 +650,7 @@ int do_wdioctl(int fd, unsigned int request, unsigned char *wdioctl) { } break; + case MULTI_TRANSFER_OLD: case MULTI_TRANSFER: DPRINTF("MULTI_TRANSFER\n"); { @@ -633,9 +719,27 @@ int do_wdioctl(int fd, unsigned int request, unsigned char *wdioctl) { case CARD_UNREGISTER: DPRINTF("CARD_UNREGISTER\n"); + { + struct card_register* cr = (struct card_register*)(wdheader->data); + + DPRINTF("Addr: 0x%lx, bytes: %lu, bar: %lu\n", + (unsigned long)cr->Card.Item[0].I.IO.dwAddr, + cr->Card.Item[0].I.IO.dwBytes, + cr->Card.Item[0].I.IO.dwBar); + + DPRINTF("hCard: %lu\n", cr->hCard); + #ifndef NO_WINDRVR - ret = (*ioctl_func) (fd, request, wdioctl); + ret = (*ioctl_func) (fd, request, wdioctl); +#else + if (parportfd == cr->hCard && parportfd >= 0) { + ioctl(parportfd, PPRELEASE); + close(parportfd); + parportfd = -1; + parportnum--; + } #endif + } break; case EVENT_PULL: @@ -718,7 +822,7 @@ int do_wdioctl(int fd, unsigned int request, unsigned char *wdioctl) { return ret; } -int ioctl(int fd, int request, ...) { +int ioctl(int fd, unsigned long int request, ...) { va_list args; void *argp; int ret; @@ -826,7 +930,7 @@ char *fgets(char *s, int size, FILE *stream) { func = (char* (*) (char*, int, FILE*)) dlsym(RTLD_NEXT, "fgets"); if (modulesfp == stream) { - if (modules_read < sizeof(modules)) { + if (modules_read < sizeof(modules) / sizeof(modules[0])) { strcpy(s, modules[modules_read]); ret = s; modules_read++; diff --git a/usb-driver.h b/usb-driver.h index 1c8c779..77b60f2 100644 --- a/usb-driver.h +++ b/usb-driver.h @@ -18,6 +18,7 @@ #define USB_GET_DEVICE_DATA_OLD 0x980 #define EVENT_REGISTER_OLD 0x986 #define TRANSFER_OLD 0x903 +#define MULTI_TRANSFER_OLD 0x904 #define MAGIC 0xa410b413UL -- 2.39.5