#if defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
#define __FreeBSD_kernel__ __FreeBSD__
#endif
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <dev/usb/usb.h>
#include "usbi.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_OLD_DEV_USB_USB_H
#define ucr_addr addr
#define ucr_request request
#define ucr_data data
#define ucr_flags flags
#define ucr_actlen actlen
#define uai_config_index config_index
#define uai_interface_index interface_index
#define uai_alt_no alt_no
#define ucd_config_index config_index
#define ucd_desc desc
#define uid_config_index config_index
#define uid_interface_index interface_index
#define uid_alt_index alt_index
#define uid_desc desc
#define ued_config_index config_index
#define ued_interface_index interface_index
#define ued_alt_index alt_index
#define ued_endpoint_index endpoint_index
#define ued_desc desc
#define ufd_config_index config_index
#define ufd_size size
#define ufd_data data
#define usd_string_index string_index
#define usd_language_id language_id
#define usd_desc desc
#define ucrd_size size
#define ucrd_data data
#define udi_bus bus
#define udi_addr addr
#define udi_cookie cookie
#define udi_product product
#define udi_vendor vendor
#define udi_release release
#define udi_productNo productNo
#define udi_vendorNo vendorNo
#define udi_releaseNo releaseNo
#define udi_class class
#define udi_subclass subclass
#define udi_protocol protocol
#define udi_config config
#define udi_lowspeed lowspeed
#define udi_power power
#define udi_nports nports
#define udi_devnames devnames
#define udi_ports ports
#define ucr_report report
#define ucr_data data
#define uds_requests requests
#endif
static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode);
#define MAX_CONTROLLERS 10
struct bsd_usb_dev_handle_info {
int ep_fd[USB_MAX_ENDPOINTS];
};
int usb_os_open(usb_dev_handle *dev)
{
int i;
struct bsd_usb_dev_handle_info *info;
char ctlpath[PATH_MAX + 1];
info = malloc(sizeof(struct bsd_usb_dev_handle_info));
if (!info)
USB_ERROR(-ENOMEM);
dev->impl_info = info;
#ifdef __FreeBSD_kernel__
snprintf(ctlpath, PATH_MAX, "%s", dev->device->filename);
#else
snprintf(ctlpath, PATH_MAX, "%s.00", dev->device->filename);
#endif
dev->fd = open(ctlpath, O_RDWR);
if (dev->fd < 0) {
dev->fd = open(ctlpath, O_RDONLY);
if (dev->fd < 0) {
free(info);
USB_ERROR_STR(-errno, "failed to open %s: %s",
ctlpath, strerror(errno));
}
}
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
info->ep_fd[i] = -1;
return 0;
}
int usb_os_close(usb_dev_handle *dev)
{
struct bsd_usb_dev_handle_info *info = dev->impl_info;
int i;
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
if (info->ep_fd[i] >= 0) {
if (usb_debug >= 2)
fprintf(stderr, "usb_os_close: closing endpoint %d\n", info->ep_fd[i]);
close(info->ep_fd[i]);
}
free(info);
if (dev->fd <= 0)
return 0;
if (close(dev->fd) == -1)
USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
strerror(errno));
return 0;
}
int usb_set_configuration(usb_dev_handle *dev, int configuration)
{
int ret;
ret = ioctl(dev->fd, USB_SET_CONFIG, &configuration);
if (ret < 0)
USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
strerror(errno));
dev->config = configuration;
return 0;
}
int usb_claim_interface(usb_dev_handle *dev, int interface)
{
dev->interface = interface;
return 0;
}
int usb_release_interface(usb_dev_handle *dev, int interface)
{
return 0;
}
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
{
int ret;
struct usb_alt_interface intf;
if (dev->interface < 0)
USB_ERROR(-EINVAL);
intf.uai_interface_index = dev->interface;
intf.uai_alt_no = alternate;
ret = ioctl(dev->fd, USB_SET_ALTINTERFACE, &intf);
if (ret < 0)
USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
dev->interface, alternate, strerror(errno));
dev->altsetting = alternate;
return 0;
}
static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode)
{
struct bsd_usb_dev_handle_info *info = dev->impl_info;
int fd;
char buf[20];
ep = UE_GET_ADDR(ep);
if (info->ep_fd[ep] < 0) {
#ifdef __FreeBSD_kernel__
snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->device->filename, ep);
#else
snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->device->filename, ep);
#endif
fd = open(buf, O_RDWR);
if (fd < 0 && errno == ENXIO)
fd = open(buf, mode);
if (fd < 0)
USB_ERROR_STR(-errno, "can't open %s for bulk read: %s",
buf, strerror(errno));
info->ep_fd[ep] = fd;
}
return info->ep_fd[ep];
}
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
int fd, ret;
ep &= ~USB_ENDPOINT_IN;
fd = ensure_ep_open(dev, ep, O_WRONLY);
if (fd < 0) {
if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
}
return fd;
}
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting timeout: %s",
strerror(errno));
ret = write(fd, bytes, size);
if (ret < 0)
#ifdef __FreeBSD_kernel__
USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%02d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif
return size;
}
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
int fd, ret, one = 1;
ep |= USB_ENDPOINT_IN;
fd = ensure_ep_open(dev, ep, O_RDONLY);
if (fd < 0) {
if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
}
return fd;
}
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
ret = read(fd, bytes, size);
if (ret < 0)
#ifdef __FreeBSD_kernel__
USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%02d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif
return ret;
}
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
int fd, ret, sent = 0;
ep &= ~USB_ENDPOINT_IN;
fd = ensure_ep_open(dev, ep, O_WRONLY);
if (fd < 0) {
if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
}
return fd;
}
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting timeout: %s",
strerror(errno));
do {
ret = write(fd, bytes+sent, size-sent);
if (ret < 0)
#ifdef __FreeBSD_kernel__
USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%02d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif
sent += ret;
} while (ret > 0 && sent < size);
return sent;
}
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
int fd, ret, retrieved = 0, one = 1;
ep |= USB_ENDPOINT_IN;
fd = ensure_ep_open(dev, ep, O_RDONLY);
if (fd < 0) {
if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
}
return fd;
}
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
if (ret < 0)
USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
do {
ret = read(fd, bytes+retrieved, size-retrieved);
if (ret < 0)
#ifdef __FreeBSD_kernel__
USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%02d: %s",
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif
retrieved += ret;
} while (ret > 0 && retrieved < size);
return retrieved;
}
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
int value, int index, char *bytes, int size, int timeout)
{
struct usb_ctl_request req;
int ret;
if (usb_debug >= 3)
fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n",
requesttype, request, value, index, bytes, size, timeout);
req.ucr_request.bmRequestType = requesttype;
req.ucr_request.bRequest = request;
USETW(req.ucr_request.wValue, value);
USETW(req.ucr_request.wIndex, index);
USETW(req.ucr_request.wLength, size);
req.ucr_data = bytes;
req.ucr_flags = USBD_SHORT_XFER_OK;
ret = ioctl(dev->fd, USB_SET_TIMEOUT, &timeout);
#if (__NetBSD__ || __OpenBSD__)
if (ret < 0 && errno != EINVAL)
#else
if (ret < 0)
#endif
USB_ERROR_STR(-errno, "error setting timeout: %s",
strerror(errno));
ret = ioctl(dev->fd, USB_DO_REQUEST, &req);
if (ret < 0)
USB_ERROR_STR(-errno, "error sending control message: %s",
strerror(errno));
return UGETW(req.ucr_request.wLength);
}
int usb_os_find_busses(struct usb_bus **busses)
{
struct usb_bus *fbus = NULL;
int controller;
int fd;
char buf[20];
for (controller = 0; controller < MAX_CONTROLLERS; controller++) {
struct usb_bus *bus;
snprintf(buf, sizeof(buf) - 1, "/dev/usb%d", controller);
fd = open(buf, O_RDWR);
if (fd < 0) {
if (usb_debug >= 2)
if (errno != ENXIO && errno != ENOENT)
fprintf(stderr, "usb_os_find_busses: can't open %s: %s\n",
buf, strerror(errno));
continue;
}
close(fd);
bus = malloc(sizeof(*bus));
if (!bus)
USB_ERROR(-ENOMEM);
memset((void *)bus, 0, sizeof(*bus));
strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
bus->dirname[sizeof(bus->dirname) - 1] = 0;
LIST_ADD(fbus, bus);
if (usb_debug >= 2)
fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
}
*busses = fbus;
return 0;
}
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
{
struct usb_device *fdev = NULL;
int cfd, dfd;
int device;
cfd = open(bus->dirname, O_RDONLY);
if (cfd < 0)
USB_ERROR_STR(-errno, "couldn't open(%s): %s", bus->dirname,
strerror(errno));
for (device = 1; device < USB_MAX_DEVICES; device++) {
struct usb_device_info di;
struct usb_device *dev;
unsigned char device_desc[DEVICE_DESC_LENGTH];
char buf[20];
di.udi_addr = device;
if (ioctl(cfd, USB_DEVICEINFO, &di) < 0)
continue;
if (strncmp(di.udi_devnames[0], "ugen", 4) != 0)
continue;
#ifdef __FreeBSD_kernel__
snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
#else
snprintf(buf, sizeof(buf) - 1, "/dev/%s.00", di.udi_devnames[0]);
#endif
dfd = open(buf, O_RDONLY);
if (dfd < 0) {
if (usb_debug >= 2)
fprintf(stderr, "usb_os_find_devices: couldn't open device %s: %s\n",
buf, strerror(errno));
continue;
}
dev = malloc(sizeof(*dev));
if (!dev)
USB_ERROR(-ENOMEM);
memset((void *)dev, 0, sizeof(*dev));
dev->bus = bus;
#if (__NetBSD__ || __OpenBSD__)
snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
#endif
strncpy(dev->filename, buf, sizeof(dev->filename) - 1);
dev->filename[sizeof(dev->filename) - 1] = 0;
if (ioctl(dfd, USB_GET_DEVICE_DESC, device_desc) < 0)
USB_ERROR_STR(-errno, "couldn't get device descriptor for %s: %s",
buf, strerror(errno));
close(dfd);
usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
LIST_ADD(fdev, dev);
if (usb_debug >= 2)
fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
dev->filename, bus->dirname);
}
close(cfd);
*devices = fdev;
return 0;
}
int usb_os_determine_children(struct usb_bus *bus)
{
return 0;
}
void usb_os_init(void)
{
}
int usb_resetep(usb_dev_handle *dev, unsigned int ep)
{
USB_ERROR_STR(-ENOSYS, "usb_resetep called, unimplemented on BSD");
}
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
{
USB_ERROR_STR(-ENOSYS, "usb_clear_halt called, unimplemented on BSD");
}
int usb_reset(usb_dev_handle *dev)
{
USB_ERROR_STR(-ENOSYS, "usb_reset called, unimplemented on BSD");
}