Пример #1
0
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));
        }
    }

    /* Mark the endpoints as not yet open */
    for (i = 0; i < USB_MAX_ENDPOINTS; i++)
        info->ep_fd[i] = -1;

    return 0;
}
Пример #2
0
EFI_STATUS
UsbRemoveDevice (
  IN USB_DEVICE           *Device
  )
/*++

Routine Description:

  Remove the device and all its children from the bus.

Arguments:

  Device  - The device to remove 

Returns:

  EFI_SUCCESS - The device is removed

--*/
{
  USB_BUS                 *Bus;
  USB_DEVICE              *Child;
  EFI_STATUS              Status;
  UINT8                   Index;

  Bus = Device->Bus;

  //
  // Remove all the devices on its downstream ports. Search from devices[1]. 
  // Devices[0] is the root hub.
  //
  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
    Child = Bus->Devices[Index];

    if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
      continue;
    }

    Status = UsbRemoveDevice (Child);

    if (EFI_ERROR (Status)) {
      USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n"));
      Bus->Devices[Index] = NULL;
    }
  }

  UsbRemoveConfig (Device);

  USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address));

  Bus->Devices[Device->Address] = NULL;
  UsbFreeDevice (Device);

  return EFI_SUCCESS;
}
Пример #3
0
int usb_os_find_busses(struct usb_bus **busses)
{
    struct usb_bus *fbus = NULL;
    DIR *dir;
    struct dirent *entry;

    dir = opendir(usb_path);
    if (!dir)
        USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
                      strerror(errno));

    while ((entry = readdir(dir)) != NULL)
    {
        struct usb_bus *bus;

        /* Skip anything starting with a . */
        if (entry->d_name[0] == '.')
            continue;

        if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1]))
        {
            if (usb_debug >= 2)
                fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
                        entry->d_name);
            continue;
        }

        bus = malloc(sizeof(*bus));
        if (!bus)
            USB_ERROR(-ENOMEM);

        memset((void *)bus, 0, sizeof(*bus));

        strncpy(bus->dirname, entry->d_name, 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);
    }

    closedir(dir);

    *busses = fbus;

    return 0;
}
Пример #4
0
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
{
  int ret;
  struct usb_setinterface setintf;

  if (dev->interface < 0)
    USB_ERROR(-EINVAL);

  setintf.interface = dev->interface;
  setintf.altsetting = alternate;

  ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
  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;
}
Пример #5
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;
}
Пример #6
0
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;
}
Пример #7
0
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
{
  struct usb_device *fdev = NULL;
  DIR *dir;
  struct dirent *entry;
  char dirpath[PATH_MAX + 1];

  snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);

  dir = opendir(dirpath);
  if (!dir)
    USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
	strerror(errno));

  while ((entry = readdir(dir)) != NULL) {
    unsigned char device_desc[DEVICE_DESC_LENGTH];
    char filename[PATH_MAX + 1];
    struct usb_device *dev;
    struct usb_connectinfo connectinfo;
    int i, fd, ret;

    /* Skip anything starting with a . */
    if (entry->d_name[0] == '.')
      continue;

    dev = malloc(sizeof(*dev));
    if (!dev)
      USB_ERROR(-ENOMEM);

    memset((void *)dev, 0, sizeof(*dev));

    dev->bus = bus;

    strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
    dev->filename[sizeof(dev->filename) - 1] = 0;

    snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
    fd = open(filename, O_RDWR);
    if (fd < 0) {
      fd = open(filename, O_RDONLY);
      if (fd < 0) {
        if (usb_debug >= 2)
          fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
                  filename);

        free(dev);
        continue;
      }
    }

    /* Get the device number */
    ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
    if (ret < 0) {
      if (usb_debug)
        fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
    } else
      dev->devnum = connectinfo.devnum;

    ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
    if (ret < 0) {
      if (usb_debug)
        fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");

      free(dev);

      goto err;
    }

    /*
     * Linux kernel converts the words in this descriptor to CPU endian, so
     * we use the undocumented W character for usb_parse_descriptor() that
     * doesn't convert endianess when parsing the descriptor
     */
    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);

    /* Now try to fetch the rest of the descriptors */
    if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
      /* Silent since we'll try again later */
      goto err;

    if (dev->descriptor.bNumConfigurations < 1)
      /* Silent since we'll try again later */
      goto err;

    dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
    if (!dev->config)
      /* Silent since we'll try again later */
      goto err;

    memset(dev->config, 0, dev->descriptor.bNumConfigurations *
          sizeof(struct usb_config_descriptor));

    for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
      unsigned char buffer[8], *bigbuffer;
      struct usb_config_descriptor config;

      /* Get the first 8 bytes so we can figure out what the total length is */
      ret = read(fd, (void *)buffer, 8);
      if (ret < 8) {
        if (usb_debug >= 1) {
          if (ret < 0)
            fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
          else
            fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
        }

        goto err;
      }

      usb_parse_descriptor(buffer, "bbw", &config);

      bigbuffer = malloc(config.wTotalLength);
      if (!bigbuffer) {
        if (usb_debug >= 1)
          fprintf(stderr, "Unable to allocate memory for descriptors\n");
        goto err;
      }

      /* Read the rest of the config descriptor */
      memcpy(bigbuffer, buffer, 8);

      ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
      if (ret < config.wTotalLength - 8) {
        if (usb_debug >= 1) {
          if (ret < 0)
            fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
          else
            fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
        }

        free(bigbuffer);
        goto err;
      }

      ret = usb_parse_configuration(&dev->config[i], bigbuffer);
      if (usb_debug >= 2) {
        if (ret > 0)
          fprintf(stderr, "Descriptor data still left\n");
        else if (ret < 0)
          fprintf(stderr, "Unable to parse descriptors\n");
      }

      free(bigbuffer);
    }

err:
    close(fd);
  }

  closedir(dir);

  *devices = fdev;

  return 0;
}
Пример #8
0
STATIC
EFI_STATUS
UsbEnumeratePort (
  IN USB_INTERFACE        *HubIf,
  IN UINT8                Port
  )
/*++

Routine Description:

  Process the events on the port.

Arguments:

  HubIf - The HUB that has the device connected
  Port  - The port index of the hub (started with zero)

Returns:

  EFI_SUCCESS          - The device is enumerated (added or removed)
  EFI_OUT_OF_RESOURCES - Failed to allocate resource for the device
  Others               - Failed to enumerate the device

--*/
{
  USB_HUB_API             *HubApi;
  USB_DEVICE              *Child;
  EFI_USB_PORT_STATUS     PortState;
  EFI_STATUS              Status;

  Child   = NULL;
  HubApi  = HubIf->HubApi;
  
  //
  // Host learns of the new device by polling the hub for port changes.
  //
  Status = HubApi->GetPortStatus (HubIf, Port, &PortState);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port));
    return Status;
  }

  if (PortState.PortChangeStatus == 0) {
    return EFI_SUCCESS;
  }

  USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n", 
              Port, PortState.PortStatus, PortState.PortChangeStatus));

  //
  // This driver only process two kinds of events now: over current and 
  // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
  // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
  //
  
  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {     

    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
      //
      // Case1:
      //   Both OverCurrent and OverCurrentChange set, means over current occurs, 
      //   which probably is caused by short circuit. It has to wait system hardware
      //   to perform recovery.
      //
      USB_DEBUG (("UsbEnumeratePort: Critical Over Current\n", Port));
      return EFI_DEVICE_ERROR;
      
    } 
    //
    // Case2:
    //   Only OverCurrentChange set, means system has been recoveried from 
    //   over current. As a result, all ports are nearly power-off, so
    //   it's necessary to detach and enumerate all ports again. 
    //
    USB_DEBUG (("UsbEnumeratePort: 2.0 Device Recovery Over Current\n", Port)); 
  }

  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {  
    //
    // Case3:
    //   1.1 roothub port reg doesn't reflect over-current state, while its counterpart
    //   on 2.0 roothub does. When over-current has influence on 1.1 device, the port 
    //   would be disabled, so it's also necessary to detach and enumerate again.
    //
    USB_DEBUG (("UsbEnumeratePort: 1.1 Device Recovery Over Current\n", Port));
  }
  
  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
    //
    // Case4:
    //   Device connected or disconnected normally. 
    //
    USB_DEBUG (("UsbEnumeratePort: Device Connect/Discount Normally\n", Port));
  }

  // 
  // Following as the above cases, it's safety to remove and create again.
  //
  Child = UsbFindChild (HubIf, Port);
  
  if (Child != NULL) {
    USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));
    UsbRemoveDevice (Child);
  }
  
  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
    //
    // Now, new device connected, enumerate and configure the device 
    //
    USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));
    Status = UsbEnumerateNewDev (HubIf, Port);
  
  } else {
    USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));
  }
  
  HubApi->ClearPortChange (HubIf, Port);
  return Status;
}
Пример #9
0
STATIC
EFI_STATUS
UsbEnumerateNewDev (
  IN USB_INTERFACE        *HubIf,
  IN UINT8                Port
  )
/*++

Routine Description:

  Enumerate and configure the new device on the port of this HUB interface.

Arguments:

  HubIf - The HUB that has the device connected
  Port  - The port index of the hub (started with zero)

Returns:

  EFI_SUCCESS          - The device is enumerated (added or removed)
  EFI_OUT_OF_RESOURCES - Failed to allocate resource for the device
  Others               - Failed to enumerate the device

--*/
{
  USB_BUS                 *Bus;
  USB_HUB_API             *HubApi;
  USB_DEVICE              *Child;
  USB_DEVICE              *Parent;
  EFI_USB_PORT_STATUS     PortState;
  UINT8                   Address;
  UINT8                   Config;
  EFI_STATUS              Status;

  Address = USB_MAX_DEVICES;
  Parent  = HubIf->Device;
  Bus     = Parent->Bus;
  HubApi  = HubIf->HubApi;
  
  gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
  
  //
  // Hub resets the device for at least 10 milliseconds.
  // Host learns device speed. If device is of low/full speed
  // and the hub is a EHCI root hub, ResetPort will release
  // the device to its companion UHCI and return an error.
  //
  Status = HubApi->ResetPort (HubIf, Port);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));

    return Status;
  }

  USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port));

  Child = UsbCreateDevice (HubIf, Port);

  if (Child == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  
  //
  // OK, now identify the device speed. After reset, hub
  // fully knows the actual device speed.
  //
  Status = HubApi->GetPortStatus (HubIf, Port, &PortState);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
    goto ON_ERROR;
  }

  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
    Child->Speed = EFI_USB_SPEED_LOW;  

  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
    Child->Speed = EFI_USB_SPEED_HIGH; 

  } else {
    Child->Speed = EFI_USB_SPEED_FULL;
  }

  USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));

  if (Child->Speed != EFI_USB_SPEED_HIGH) {
    //
    // If the child isn't a high speed device, it is necessary to
    // set the transaction translator. Port TT is 1-based.
    // This is quite simple:
    //  1. if parent is of high speed, then parent is our translator
    //  2. otherwise use parent's translator.
    //
    if (Parent->Speed == EFI_USB_SPEED_HIGH) {
      Child->Translator.TranslatorHubAddress  = Parent->Address;
      Child->Translator.TranslatorPortNumber  = Port + 1;

    } else {
      Child->Translator = Parent->Translator;
    }

    USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n", 
                Child->Translator.TranslatorHubAddress, 
                Child->Translator.TranslatorPortNumber));
  }
  
  //
  // After port is reset, hub establishes a signal path between
  // the device and host (DEFALUT state). Device¡¯s registers are
  // reset, use default address 0 (host enumerates one device at
  // a time) , and ready to respond to control transfer at EP 0.
  //
  
  //
  // Host sends a Get_Descriptor request to learn the max packet
  // size of default pipe (only part of the device¡¯s descriptor).
  //
  Status = UsbGetMaxPacketSize0 (Child);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
    goto ON_ERROR;
  }

  USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));

  //
  // Host assigns an address to the device. Device completes the
  // status stage with default address, then switches to new address.
  // ADDRESS state. Address zero is reserved for root hub.
  //
  for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
    if (Bus->Devices[Address] == NULL) {
      break;
    }
  }

  if (Address == USB_MAX_DEVICES) {
    USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port));
    
    Status = EFI_ACCESS_DENIED;
    goto ON_ERROR;
  }

  Bus->Devices[Address] = Child;
  Status                = UsbSetAddress (Child, Address);
  Child->Address        = Address;
  
  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status));
    goto ON_ERROR;
  }
  
  gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);

  USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));

  //
  // Host learns about the device¡¯s abilities by requesting device's
  // entire descriptions.
  //
  Status = UsbBuildDescTable (Child);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
    goto ON_ERROR;
  }
  
  //
  // Select a default configuration: UEFI must set the configuration
  // before the driver can connect to the device.
  //
  Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
  Status = UsbSetConfig (Child, Config);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
    goto ON_ERROR;
  }

  USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
  
  //
  // Host assigns and loads a device driver. 
  //
  Status = UsbSelectConfig (Child, Config);

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));  
    goto ON_ERROR;
  }

  return EFI_SUCCESS;

ON_ERROR:
  if (Address != USB_MAX_DEVICES) {
    Bus->Devices[Address] = NULL;
  }

  if (Child != NULL) {
    UsbFreeDevice (Child);
  }

  return Status;
}
Пример #10
0
EFI_STATUS
UsbSelectConfig (
  IN USB_DEVICE           *Device,
  IN UINT8                ConfigValue
  )
/*++

Routine Description:

  Select a new configuration for the device. Each
  device may support several configurations. 

Arguments:

  Device      - The device to select configuration
  ConfigValue - The index of the configuration ( != 0)

Returns:

  EFI_NOT_FOUND        - There is no configuration with the index
  EFI_OUT_OF_RESOURCES - Failed to allocate resource
  EFI_SUCCESS          - The configuration is selected.

--*/
{
  USB_DEVICE_DESC         *DevDesc;
  USB_CONFIG_DESC         *ConfigDesc;
  USB_INTERFACE_DESC      *IfDesc;
  USB_INTERFACE           *UsbIf;
  EFI_STATUS              Status;
  UINT8                   Index;

  //
  // Locate the active config, then set the device's pointer
  //
  DevDesc     = Device->DevDesc;
  ConfigDesc  = NULL;

  for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
    ConfigDesc = DevDesc->Configs[Index];

    if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
      break;
    }
  }

  if (Index == DevDesc->Desc.NumConfigurations) {
    return EFI_NOT_FOUND;
  }

  Device->ActiveConfig = ConfigDesc;

  USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n", 
              ConfigValue, Device->Address));

  //
  // Create interfaces for each USB interface descriptor.
  //
  for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
    //
    // First select the default interface setting, and reset
    // the endpoint toggles to zero for its endpoints.
    //
    IfDesc = ConfigDesc->Interfaces[Index];
    UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);

    //
    // Create a USB_INTERFACE and install USB_IO and other protocols
    //
    UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);

    if (UsbIf == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    Device->Interfaces[Index] = UsbIf;

    //
    // Connect the device to drivers, if it failed, ignore 
    // the error. Don't let the unsupported interfaces to block
    // the supported interfaces.
    //
    Status = UsbConnectDriver (UsbIf);

    if (EFI_ERROR (Status)) {
      USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status));
    }
  }

  Device->NumOfInterface = Index;

  return EFI_SUCCESS;
}
Пример #11
0
STATIC
USB_INTERFACE *
UsbCreateInterface (
  IN USB_DEVICE           *Device,
  IN USB_INTERFACE_DESC   *IfDesc
  )
/*++

Routine Description:

  Create an interface for the descriptor IfDesc. Each
  device's configuration can have several interfaces.

Arguments:

  Device  - The device has the interface descriptor
  IfDesc  - The interface descriptor

Returns:

  The created USB interface for the descriptor, or NULL.

--*/
{
  USB_DEVICE_PATH         UsbNode;
  USB_INTERFACE           *UsbIf;
  USB_INTERFACE           *HubIf;
  EFI_STATUS              Status;

  UsbIf = EfiLibAllocateZeroPool (sizeof (USB_INTERFACE));

  if (UsbIf == NULL) {
    return NULL;
  }

  UsbIf->Signature  = USB_INTERFACE_SIGNATURE;
  UsbIf->Device     = Device;
  UsbIf->IfDesc     = IfDesc;
  UsbIf->IfSetting  = IfDesc->Settings[IfDesc->ActiveIndex];
  UsbIf->UsbIo      = mUsbIoProtocol;
  
  //
  // Install protocols for USBIO and device path
  //
  UsbNode.Header.Type       = MESSAGING_DEVICE_PATH;
  UsbNode.Header.SubType    = MSG_USB_DP;
  UsbNode.ParentPortNumber  = Device->ParentPort;
  UsbNode.InterfaceNumber   = UsbIf->IfSetting->Desc.InterfaceNumber;

  SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));

  HubIf = Device->ParentIf;
  ASSERT (HubIf != NULL);

  UsbIf->DevicePath = EfiAppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);

  if (UsbIf->DevicePath == NULL) {
    USB_ERROR (("UsbCreateInterface: failed to create device path\n"));

    Status = EFI_OUT_OF_RESOURCES;
    goto ON_ERROR;
  }

  Status = gBS->InstallMultipleProtocolInterfaces (
                  &UsbIf->Handle,
                  &gEfiDevicePathProtocolGuid,
                  UsbIf->DevicePath,
                  &gEfiUsbIoProtocolGuid,
                  &UsbIf->UsbIo,
                  NULL
                  );

  if (EFI_ERROR (Status)) {
    USB_ERROR (("UsbCreateInterface: failed to install UsbIo - %r\n", Status));
    goto ON_ERROR;
  }

  //
  // Open USB Host Controller Protocol by Child
  //
  Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);

  if (EFI_ERROR (Status)) {
    gBS->UninstallMultipleProtocolInterfaces (
           &UsbIf->Handle,
           &gEfiDevicePathProtocolGuid,
           UsbIf->DevicePath,
           &gEfiUsbIoProtocolGuid,
           &UsbIf->UsbIo,
           NULL
           );

    USB_ERROR (("UsbCreateInterface: failed to open host for child - %r\n", Status));
    goto ON_ERROR;
  }

  return UsbIf;

ON_ERROR:
  if (UsbIf->DevicePath) {
    gBS->FreePool (UsbIf->DevicePath);
  }

  gBS->FreePool (UsbIf);
  return NULL;
}
Пример #12
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;

        /* There's a device; is it one we should mess with? */

        if (strncmp(di.udi_devnames[0], "ugen", 4) != 0)
            /* best not to play with things we don't understand */
            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

        /* Open its control endpoint */
        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;

        /* we need to report the device name as /dev/ugenx NOT /dev/ugenx.00
         * This seemed easier than having 2 variables...
         */
#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;
}