/* $Id: usb_libusb.c,v 1.10 2004/03/21 10:13:11 jmuelmen Exp $ */ /* This file implements the USB-level functionality of libsurf on * systems that have libusb. On systems that don't, there are other * files (called usb_*.c) that do the same thing. */ /* Note that at this level we're dealing with a device handle and * channel number. Turning module/board name into device handle and * channel number is done in module.c and board.c. */ #ifdef HAVE_LIBUSB #include "libsurf.h" #include "surf_int.h" #include "surf_drv.h" #define INIT if (!_init) surflib_init() static int _init = 0; int surf_find_boards (); struct surf_t *surf_search (const char *); int surflib_init () { usb_init(); usb_set_debug(0); _init = 1; return 0; } int surf_write_ep (struct surf_t *b, int ep, char *buf, int count) { /* do the USB sending stuff; if it fails, call surf_find_boards() to see if the SuRF board is just hiding somewhere because of a re-enumeration. */ int n, i; usb_dev_handle *dev; INIT; i = 5; /* five tries to write to the damn thing should be enough */ while (i--) { /* try to write to the board */ dev = surft_get_dev(b); if (ep) n = usb_bulk_write(dev, ep, buf, count, SURF_TO); else n = usb_control_msg(dev, buf[0], buf[1], (buf[2] << 8) + buf[3], (buf[4] << 8) + buf[5], buf + 6, count - 6, SURF_TO); if (n >= 0) /* we succeeded; we're happy. */ return n; /* if we didn't succeed, we have to see if the bus changed */ surft_make_stale(b); if (surf_find_boards()) /* something bad happened on the bus. errno is already set. */ return -1; /* if the board is still stale (i.e. we can't talk to the device), then it's time to give up. Probably some tourist took the board as a souvenir. */ if (surft_stale(b)) { surf_errno = ENOBOARD; return -1; } /* otherwise, we just try again. It should work on the second try unless someone changed the bus in the meantime. Then it'll work on the third try unless... */ } /* we failed. No board to be had. */ surf_errno = ENOBOARD; return -1; } int surf_read_ep (struct surf_t *b, int ep, char *buf, int count) { /* do the USB receiving stuff; if it fails, call surf_find_boards() to see if the SuRF board is just hiding somewhere because of a re-enumeration. */ int n, i; usb_dev_handle *dev; INIT; i = 5; /* five tries to read from the damn thing should be enough */ while (i--) { /* try to read from the board */ dev = surft_get_dev(b); if (ep) n = usb_bulk_read(dev, ep, buf, count, SURF_TO); else n = usb_control_msg(dev, USB_ENDPOINT_OUT, buf[0], (buf[1] << 8) + buf[2], (buf[3] << 8) + buf[4], buf + 5, count - 5, SURF_TO); if (n >= 0) /* we succeeded; we're happy. */ return n; /* if we didn't succeed, we have to see if the bus changed */ surft_make_stale(b); if (surf_find_boards()) /* something bad happened on the bus. errno is already set. */ return -1; /* if the board is still stale (i.e. we can't talk to the device), then it's time to give up. Probably some tourist took the board as a souvenir. */ if (surft_stale(b)) { surf_errno = ENOBOARD; return -1; } /* otherwise, we just try again. It should work on the second try unless someone changed the bus in the meantime. Then it'll work on the third try unless... */ /* fix me! There should be a provision for resetting the endpoint before giving up. */ } /* we failed. No board to be had. */ surf_errno = ENOBOARD; return -1; } static void convert_unicode (const char *unicode, char *ascii, int len) { int i; /* printf("Unicode string (length %x) is", len); */ /* for (i = 0; i < len; ++i) */ /* printf(" %x", unicode[i]); */ /* printf("\n"); */ for (i = 0; i < len / 2 - 1; ++i) ascii[i] = unicode[2 * i + 2]; ascii[i] = 0; } /* Go through the list of existing boards; check which ones are still connected and update the device handles as necessary */ int surf_find_boards () { /* go through the USB; get the SuRF device's serial number; check if it's in the list of boards already (binary search); if it is in the list, update the device handle if necessary; if it's not in the list, add it at the end; if there have been additions to the list, remember to qsort at the end! */ struct usb_bus *bus; struct usb_device *dev; INIT; usb_find_busses(); usb_find_devices(); for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { int ret; char b_name[256], b_name_uc[256]; char rev[256], rev_uc[256]; usb_dev_handle *udev; struct surf_t *surf; /* check that this is a SuRF board */ if (dev->descriptor.idVendor != SURF_VEND || dev->descriptor.idProduct != SURF_PROD) continue; /* check that we can open the device */ if (!(udev = usb_open(dev))) { surf_errno = ESURFDEV; SURF_LOG(LOGSURF_ERROR, "Can't open device\n"); return -1; } ret = usb_get_string(udev, dev->descriptor.iSerialNumber, 0x03, b_name_uc, sizeof(b_name_uc)); if (ret <= 0) { surf_errno = ESURFDEV; SURF_LOG(LOGSURF_ERROR, "Can't get board serial number\n"); return -1; } else convert_unicode(b_name_uc, b_name, ret); SURF_LOG(LOGSURF_LOUD, "Serial Number: %s\n", b_name); ret = usb_get_string(udev, SURF_FIRM_REV, 0x03, rev_uc, sizeof(rev_uc)); if (ret <= 0) { surf_errno = ESURFDEV; SURF_LOG(LOGSURF_ERROR, "Can't get board firmware " "revision\n"); return -1; } else convert_unicode(rev_uc, rev, ret); SURF_LOG(LOGSURF_LOUD, "Revision: %02x.%02x.%02x\n", rev[0], rev[1], rev[2]); /* see if the board is already in the list */ if (!(surf = surf_search(b_name))) { if (!(surf = surft_create(b_name))) /* something failed. Errno already got set. Just get out. */ return -1; } else { /* else just close the old device */ usb_close(surft_get_dev(surf)); } surft_set_dev(surf, udev); /* board is fresh again */ surft_make_fresh(surf); surft_set_rev(surf, rev[0], rev[1], rev[2]); } } return 0; } #endif /* ifdef HAVE_LIBUSB */