📄 bsd.c
字号:
/* * (Free|Open|Net)BSD USB support * * Derived from Linux version by Richard Tobin. * * $Id: bsd.c,v 1.28 2003/12/30 01:12:38 jerdfelt Exp $ * $Name: $ * * This library is covered by the LGPL, read LICENSE for details. *//* * Note: I don't have a clue what I'm doing. I just looked at the * man pages and source to try and find things that did the same as * the Linux version. -- Richard * * johnjen@reynoldsnet.org - minor fixes with debug mode output. Consistent brace * use as well as indenting. More error messages put in to test for failure * modes with /dev/ permissions (when it happens). Note: I, like Richard, have * no clue what I'm doing. Patches to increase/fix functionality happily * accepted! *//* dirkx@webweaving.org - minor changes to make things actually work * for both read and write. */#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/* * It appears some of the BSD's (OpenBSD atleast) have switched over to a * new naming convention, so we setup some macro's for backward * compability with older versions --jerdfelt *//* struct usb_ctl_request */#define ucr_addr addr#define ucr_request request#define ucr_data data#define ucr_flags flags#define ucr_actlen actlen/* struct usb_alt_interface */#define uai_config_index config_index#define uai_interface_index interface_index#define uai_alt_no alt_no/* struct usb_config_desc */#define ucd_config_index config_index#define ucd_desc desc/* struct usb_interface_desc */#define uid_config_index config_index#define uid_interface_index interface_index#define uid_alt_index alt_index#define uid_desc desc/* struct usb_endpoint_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/* struct usb_full_desc */#define ufd_config_index config_index#define ufd_size size#define ufd_data data/* struct usb_string_desc */#define usd_string_index string_index#define usd_language_id language_id#define usd_desc desc/* struct usb_ctl_report_desc */#define ucrd_size size#define ucrd_data data/* struct usb_device_info */#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/* struct usb_ctl_report */#define ucr_report report#define ucr_data data/* struct usb_device_stats */#define uds_requests requests#endifstatic int ensure_ep_open(usb_dev_handle *dev, int ep, int mode);#define MAX_CONTROLLERS 10/* This records the file descriptors for the endpoints. It doesn't seem to work to re-open them for each read (as well as being inefficient). */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;#if __FreeBSD__ 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)); } } /* Mark the endpoints as not yet open */ 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; /* Close any open endpoints */ 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) /* Failing trying to close a file really isn't an error, so return 0 */ 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){ /* BSD doesn't have the corresponding ioctl. It seems to be sufficient to open the relevant endpoints as needed. */ dev->interface = interface; return 0;}int usb_release_interface(usb_dev_handle *dev, int interface){ /* See above */ 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]; /* Get the address for this endpoint; we could check * the mode against the direction; but we've done that * already in the usb_bulk_read/write. */ ep = UE_GET_ADDR(ep); if (info->ep_fd[ep] < 0) {#if __FreeBSD__ snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->device->filename, ep);#else snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->device->filename, ep);#endif /* Try to open it O_RDWR first for those devices which have in and out * endpoints with the same address (eg 0x02 and 0x82) */ 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, sent = 0; /* Ensure the endpoint address is correct */ ep &= ~USB_ENDPOINT_IN; fd = ensure_ep_open(dev, ep, O_WRONLY); if (fd < 0) { if (usb_debug >= 2) {#if __FreeBSD__ 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)); do { ret = write(fd, bytes+sent, size-sent); if (ret < 0)#if __FreeBSD__ 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 sent += ret; } while (ret > 0 && sent < size); return sent;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -