[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cdi-devel] [PATCH v3 07/10] cdi/usb: Add headers



+ Add headers to be used by USB host controller drivers, the USB bus
  driver, and USB device drivers.
  These headers are still lacking functions for periodic transactions
  (interrupt/isochronous), hotplugging, suspend/resume, etc. pp..

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 include/cdi/usb-structures.h | 174 ++++++++++++++++++++++++++++++++++++
 include/cdi/usb.h            | 208 +++++++++++++++++++++++++++++++++++++++++++
 include/cdi/usb_hcd.h        | 159 +++++++++++++++++++++++++++++++++
 3 files changed, 541 insertions(+)
 create mode 100644 include/cdi/usb-structures.h
 create mode 100644 include/cdi/usb.h
 create mode 100644 include/cdi/usb_hcd.h

diff --git a/include/cdi/usb-structures.h b/include/cdi/usb-structures.h
new file mode 100644
index 0000000..fecb609
--- /dev/null
+++ b/include/cdi/usb-structures.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015 Max Reitz
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+/**
+ * This file contains some standard USB structures such as descriptors.
+ */
+
+#ifndef _CDI_USB_STRUCTURES_H_
+#define _CDI_USB_STRUCTURES_H_
+
+#include <stdint.h>
+
+
+struct cdi_usb_device_descriptor {
+    uint8_t b_length;
+    uint8_t b_descriptor_type;
+    uint16_t bcd_usb;
+    uint8_t b_device_class;
+    uint8_t b_device_sub_class;
+    uint8_t b_device_protocol;
+    uint8_t b_max_packet_size_0;
+    uint16_t id_vendor;
+    uint16_t id_product;
+    uint16_t bcd_device;
+    uint8_t i_manufacturer;
+    uint8_t i_product;
+    uint8_t i_serial_number;
+    uint8_t b_num_configurations;
+} __attribute__((packed));
+
+struct cdi_usb_configuration_descriptor {
+    uint8_t b_length;
+    uint8_t b_descriptor_type;
+    uint16_t w_total_length;
+    uint8_t b_num_interfaces;
+    uint8_t b_configuration_value;
+    uint8_t i_configuration;
+    uint8_t bm_attributes;
+    uint8_t b_max_power;
+} __attribute__((packed));
+
+struct cdi_usb_string_descriptor {
+    uint8_t b_length;
+    uint8_t b_descriptor_type;
+    uint16_t b_string[127];
+} __attribute__((packed));
+
+struct cdi_usb_interface_descriptor {
+    uint8_t b_length;
+    uint8_t b_descriptor_type;
+    uint8_t b_interface_number;
+    uint8_t b_alternate_setting;
+    uint8_t b_num_endpoints;
+    uint8_t b_interface_class;
+    uint8_t b_interface_sub_class;
+    uint8_t b_interface_protocol;
+    uint8_t i_interface;
+} __attribute__((packed));
+
+
+struct cdi_usb_endpoint_descriptor {
+    uint8_t b_length;
+    uint8_t b_descriptor_type;
+    uint8_t b_endpoint_address;
+    uint8_t bm_attributes;
+    uint16_t w_max_packet_size;
+    uint8_t b_interval;
+} __attribute__((packed));
+
+/// cdi_usb_endpoint_descriptor.b_endpoint_address
+#define CDI_USB_EPDSC_EPADR_ID(x)   ((x) & 0xf)
+#define CDI_USB_EPDSC_EPADR_DIR     (1 << 7) // IN if set
+
+/// cdi_usb_endpoint_descriptor.bm_attributes
+#define CDI_USB_EPDSC_ATTR_XFER_TYPE_MASK   0x03 // Transfer Type mask
+#define CDI_USB_EPDSC_ATTR_CONTROL          0x00
+#define CDI_USB_EPDSC_ATTR_ISOCHRONOUS      0x01
+#define CDI_USB_EPDSC_ATTR_BULK             0x02
+#define CDI_USB_EPDSC_ATTR_INTERRUPT        0x03
+#define CDI_USB_EPDSC_ATTR_SYNC_TYPE_MASK   0x0c // Synchronization Type mask
+#define CDI_USB_EPDSC_ATTR_NO_SYNC          0x00
+#define CDI_USB_EPDSC_ATTR_ASYNC            0x04
+#define CDI_USB_EPDSC_ATTR_ADAPTIVE         0x08
+#define CDI_USB_EPDSC_ATTR_SYNC             0x0c
+#define CDI_USB_EPDSC_ATTR_USAGE_TYPE_MASK  0x30 // Usage Type mask
+#define CDI_USB_EPDSC_ATTR_DATA             0x00
+#define CDI_USB_EPDSC_ATTR_FEEDBACK         0x10
+#define CDI_USB_EPDSC_ATTR_IMPL_FB_DATA     0x20 // Implicit Feedback Data
+
+/// cdi_usb_endpoint_descriptor.w_max_packet_size
+#define CDI_USB_EPDSC_MPS_MPS(x)    ((x) & 0x7ff)
+
+
+struct cdi_usb_setup_packet {
+    uint8_t bm_request_type;
+    uint8_t b_request;
+    uint16_t w_value;
+    uint16_t w_index;
+    uint16_t w_length;
+} __attribute__((packed));
+
+/// Values constituting cdi_usb_setup_packet.bm_request_type
+#define CDI_USB_CREQ_DEVICE     0
+#define CDI_USB_CREQ_INTERFACE  1
+#define CDI_USB_CREQ_ENDPOINT   2
+#define CDI_USB_CREQ_OTHER      3
+#define CDI_USB_CREQ_CLASS      (1 << 5)
+#define CDI_USB_CREQ_OUT        (0 << 7)
+#define CDI_USB_CREQ_IN         (1 << 7)
+
+/// Control request numbers (cdi_usb_setup_packet.b_request)
+enum {
+    CDI_USB_CREQ_GET_STATUS         =  0,
+    CDI_USB_CREQ_CLEAR_FEATURE      =  1,
+    CDI_USB_CREQ_SET_FEATURE        =  3,
+    CDI_USB_CREQ_SET_ADDRESS        =  5,
+    CDI_USB_CREQ_GET_DESCRIPTOR     =  6,
+    CDI_USB_CREQ_SET_DESCRIPTOR     =  7,
+    CDI_USB_CREQ_GET_CONFIGURATION  =  8,
+    CDI_USB_CREQ_SET_CONFIGURATION  =  9,
+    CDI_USB_CREQ_GET_INTERFACE      = 10,
+    CDI_USB_CREQ_SET_INTERFACE      = 11,
+    CDI_USB_CREQ_SYNCH_FRAME        = 12,
+};
+
+/// Descriptor IDs
+enum {
+    CDI_USB_DESC_DEVICE         = 1,
+    CDI_USB_DESC_CONFIGURATION  = 2,
+    CDI_USB_DESC_STRING         = 3,
+    CDI_USB_DESC_INTERFACE      = 4,
+    CDI_USB_DESC_ENDPOINT       = 5,
+};
+
+/// USB class codes. Defined here because they are not part of their respective
+/// specifications.
+
+/// USB class codes on the device level
+#define CDI_USB_DEVCLS_NONE     0x00 // No device-wide class, use interfaces
+#define CDI_USB_DEVCLS_CCDCC    0x02 // Communications and CDC Control
+#define CDI_USB_DEVCLS_HUB      0x09 // Hub
+#define CDI_USB_DEVCLS_BILLBD   0x11 // Billboard Device
+#define CDI_USB_DEVCLS_DIAG     0xdc // Diagnostic Device
+#define CDI_USB_DEVCLS_MISC     0xef // Miscellaneous
+#define CDI_USB_DEVCLS_VENDOR   0xff // Vendor-specific
+
+/// USB class codes on the interface level
+#define CDI_USB_IFCCLS_AUDIO    0x01 // Audio
+#define CDI_USB_IFCCLS_CCDCC    CDI_USB_DEVCLS_CCDCC
+#define CDI_USB_IFCCLS_HID      0x03 // Human Interface Device
+#define CDI_USB_IFCCLS_PHYS     0x05 // Physical
+#define CDI_USB_IFCCLS_IMAGE    0x06 // Image
+#define CDI_USB_IFCCLS_PRINTER  0x07 // Printer
+#define CDI_USB_IFCCLS_STORAGE  0x08 // Mass Storage
+#define CDI_USB_IFCCLS_CDCDATA  0x0a // CDC Data
+#define CDI_USB_IFCCLS_SMARTCD  0x0b // Smart Card
+#define CDI_USB_IFCCLS_CNTTSEC  0x0d // Content Security
+#define CDI_USB_IFCCLS_VIDEO    0x0e // Video
+#define CDI_USB_IFCCLS_HEALTH   0x0f // Personal Healthcare
+#define CDI_USB_IFCCLS_AV       0x10 // Audio/Video
+#define CDI_USB_IFCCLS_DIAG     CDI_USB_DEVCLS_DIAG
+#define CDI_USB_IFCCLS_WIRELESS 0xe0 // Wireless Controller
+#define CDI_USB_IFCCLS_MISC     CDI_USB_DEVCLS_MISC
+#define CDI_USB_IFCCLS_APP      0xfe // Application-specific
+#define CDI_USB_IFCCLS_VENDOR   CDI_USB_DEVCLS_VENDOR
+
+#endif
diff --git a/include/cdi/usb.h b/include/cdi/usb.h
new file mode 100644
index 0000000..c95931d
--- /dev/null
+++ b/include/cdi/usb.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015 Max Reitz
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+#ifndef _CDI_USB_H_
+#define _CDI_USB_H_
+
+#include <stdint.h>
+
+#include <cdi.h>
+#include <cdi/usb-structures.h>
+
+
+struct cdi_usb_hc;
+
+typedef enum {
+    CDI_USB_CONTROL,
+    CDI_USB_BULK,
+    CDI_USB_INTERRUPT,
+    CDI_USB_ISOCHRONOUS,
+} cdi_usb_endpoint_type_t;
+
+typedef enum {
+    CDI_USB_LOW_SPEED,
+    CDI_USB_FULL_SPEED,
+    CDI_USB_HIGH_SPEED,
+    CDI_USB_SUPERSPEED,
+} cdi_usb_speed_t;
+
+typedef enum {
+    CDI_USB_OK = 0,
+
+    CDI_USB_DRIVER_ERROR,
+    CDI_USB_TIMEOUT,
+    CDI_USB_BABBLE,
+    CDI_USB_STALL,
+    CDI_USB_HC_ERROR,
+    CDI_USB_BAD_RESPONSE,
+} cdi_usb_transmission_result_t;
+
+/* Bitmask of CDI_USB_PORT_* and CDI_USB_*_SPEED values */
+typedef uint32_t cdi_usb_port_status_t;
+
+#define CDI_USB_PORT_SPEED_MASK (0x7)
+#define CDI_USB_PORT_CONNECTED  (1 << 3)
+
+struct cdi_usb_hub;
+
+/**
+ * Describes a hub driver. This is not a CDI driver in the common sense. When
+ * used for a root hub, it is part of the host controller driver; when used for
+ * a device hub, it is only used internally by the USB driver.
+ */
+struct cdi_usb_hub_driver {
+    /**
+     * Makes a port unreachable by traffic which reaches the hub. @index is a
+     * 0-based index.
+     */
+    void (*port_disable)(struct cdi_usb_hub* hub, int index);
+
+    /**
+     * Makes a port reachable by traffic which reaches the hub and drives the
+     * reset signal for at least 50 ms on the port. @index is a 0-based index.
+     */
+    void (*port_reset_enable)(struct cdi_usb_hub* hub, int index);
+
+    /**
+     * Retrieves information about the given port. This should only be called
+     * after the port has been reset using port_reset_enable(). @index is a
+     * 0-based index.
+     */
+    cdi_usb_port_status_t (*port_status)(struct cdi_usb_hub* hub, int index);
+};
+
+/**
+ * Describes a USB hub. This is not a CDI device in the common sense. When used
+ * for a root hub, it is part of the host controller object; when used for a
+ * device hub, it is only used internally by the USB driver.
+ *
+ * For this reason, there is no struct cdi_usb_hub_driver object reachable from
+ * this object. If it is a root hub, the hub driver will be part of the host
+ * controller driver. Otherwise (if it is a device hub), the hub driver will be
+ * internal to the USB driver.
+ */
+struct cdi_usb_hub {
+    /**
+     * Number of ports provided by this hub.
+     */
+    int ports;
+};
+
+/**
+ * Describes a USB device as given to cdi_provide_device() and the init_device()
+ * function provided by USB device drivers.
+ */
+struct cdi_usb_device {
+    struct cdi_bus_data bus_data;
+
+    /**
+     * Various information which can be used for identifying a USB device.
+     */
+    uint16_t vendor_id, product_id;
+    uint8_t class_id, subclass_id, protocol_id;
+
+    /**
+     * If negative, this logical device is defined on the USB device level;
+     * otherwise, this is the index of the interface which this logical device
+     * represents.
+     */
+    int interface;
+
+    /**
+     * Number of endpoints available for this device; this does include the
+     * default pipe (endpoint 0) which can be used both on the physical device
+     * level and from any interface.
+     */
+    int endpoint_count;
+};
+
+/**
+ * Describes the USB bus driver.
+ */
+struct cdi_usb_driver {
+    struct cdi_driver drv;
+
+    /**
+     * Returns the endpoint descriptor for endpoint @ep (0 up until
+     * dev->endpoint_count - 1) of device @dev in @desc.
+     */
+    void (*get_endpoint_descriptor)(struct cdi_usb_device* dev, int ep,
+                                    struct cdi_usb_endpoint_descriptor* desc);
+
+    /**
+     * Executes a control transfer to endpoint @ep (0 up until
+     * dev->endpoint_count - 1) of device @dev, using @setup for the setup stage
+     * and @data for the data stage. The length and direction of transfer is
+     * deduced from @setup.
+     */
+    cdi_usb_transmission_result_t
+        (*control_transfer)(struct cdi_usb_device* dev, int ep,
+                            const struct cdi_usb_setup_packet* setup,
+                            void* data);
+
+    /**
+     * Executes a bulk transfer to endpoint @ep (0 up until
+     * dev->endpoint_count - 1) of device @dev, transferring @size bytes from/to
+     * @data. The direction of transfer is deduced from the endpoint given.
+     */
+    cdi_usb_transmission_result_t (*bulk_transfer)(struct cdi_usb_device* dev,
+                                                   int ep, void* data,
+                                                   size_t size);
+};
+
+/**
+ * Describes patterns for USB devices a device driver can use to specify which
+ * devices it can handle.
+ */
+struct cdi_usb_bus_device_pattern {
+    struct cdi_bus_device_pattern pattern;
+
+    /**
+     * Any field may be negative to signify "don't care".
+     */
+    int vendor_id, product_id;
+    int class_id, subclass_id, protocol_id;
+};
+
+
+/**
+ * Registers a USB bus driver. Should be called by the CDI library, ideally,
+ * after the USB bus driver's init() function has run.
+ */
+void cdi_usb_driver_register(struct cdi_usb_driver* drv);
+
+/**
+ * Returns the endpoint descriptor for endpoint @ep (0 up until
+ * dev->endpoint_count - 1) of device @dev in @desc.
+ */
+void cdi_usb_get_endpoint_descriptor(struct cdi_usb_device* dev, int ep,
+                                     struct cdi_usb_endpoint_descriptor* desc);
+
+/**
+ * Executes a control transfer to endpoint @ep (0 up until
+ * dev->endpoint_count - 1) of device @dev, using @setup for the setup stage and
+ * @data for the data stage. The length and direction of transfer is deduced
+ * from @setup.
+ */
+cdi_usb_transmission_result_t
+    cdi_usb_control_transfer(struct cdi_usb_device* dev, int ep,
+                             const struct cdi_usb_setup_packet* setup,
+                             void* data);
+
+/**
+ * Executes a bulk transfer to endpoint @ep (0 up until dev->endpoint_count - 1)
+ * of device @dev, transferring @size bytes from/to @data. The direction of
+ * transfer is deduced from the endpoint given.
+ */
+cdi_usb_transmission_result_t cdi_usb_bulk_transfer(struct cdi_usb_device* dev,
+                                                    int ep, void* data,
+                                                    size_t size);
+
+#endif
diff --git a/include/cdi/usb_hcd.h b/include/cdi/usb_hcd.h
new file mode 100644
index 0000000..5481535
--- /dev/null
+++ b/include/cdi/usb_hcd.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015 Max Reitz
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+#ifndef _CDI_USB_HCD_H_
+#define _CDI_USB_HCD_H_
+
+#include <cdi.h>
+#include <cdi/usb.h>
+
+
+/**
+ * Opaque value identifying a transaction for the host controller.
+ */
+typedef void* cdi_usb_hc_transaction_t;
+
+typedef enum {
+    CDI_USB_IN,
+    CDI_USB_OUT,
+    CDI_USB_SETUP,
+} cdi_usb_transfer_token_t;
+
+
+/**
+ * Describes a USB host controller.
+ */
+struct cdi_usb_hc {
+    struct cdi_device dev;
+
+    /**
+     * Root hub provided by the HC. The hub driver responsible for this root hub
+     * is part of the cdi_usb_hcd structure.
+     */
+    struct cdi_usb_hub rh;
+};
+
+/**
+ * Describes the USB bus provided by a USB host controller and its root hub. All
+ * buses are handled by the USB bus driver, therefore there are no "identifying"
+ * fields in this structure.
+ */
+struct cdi_usb_hc_bus {
+    struct cdi_bus_data bus_data;
+    struct cdi_usb_hc* hc;
+};
+
+/**
+ * Contains information about a communication pipe to a USB device endpoint used
+ * for USB transactions.
+ */
+struct cdi_usb_hc_ep_info {
+    /// Device ID
+    uint8_t dev;
+
+    /// Endpoint ID
+    uint8_t ep;
+
+    /// Endpoint type
+    cdi_usb_endpoint_type_t ep_type;
+
+    /// Transfer speed
+    cdi_usb_speed_t speed;
+
+    /// Maximum packet size for this endpoint
+    size_t mps;
+
+    /**
+     * For low and full speed devices operated behind a high speed hub: @tt_addr
+     * is the USB device address of the translating USB hub (the last high speed
+     * hub), @tt_port is the port (0-based index) of that hub where the first
+     * non-high-speed device of this device's tree is plugged into.
+     */
+    uint8_t tt_addr, tt_port;
+};
+
+/**
+ * Describes a single USB transmission.
+ */
+struct cdi_usb_hc_transmission {
+    /// Transaction this transmission is part of
+    cdi_usb_hc_transaction_t ta;
+
+    /// Type of transfer to be performed
+    cdi_usb_transfer_token_t token;
+
+    /// Buffer to be used (may be NULL if @size is 0)
+    void* buffer;
+
+    /// Number of bytes to be transferred (may be 0, and may exceed the MPS)
+    size_t size;
+
+    /**
+     * Toggle bit to be used for the first packet issued in this transmission.
+     * If @size exceeds the MPS and thus multiple packets are transmitted, the
+     * toggle bit will be toggled automatically.
+     */
+    unsigned toggle;
+
+    /**
+     * Result of this transmission. Only valid after wait_transaction() has
+     * returned.
+     */
+    cdi_usb_transmission_result_t* result;
+};
+
+/**
+ * Describes a USB host controller driver.
+ */
+struct cdi_usb_hcd {
+    struct cdi_driver drv;
+
+    /**
+     * USB hub driver which is responsible for all root hubs provided by this
+     * HCD.
+     */
+    struct cdi_usb_hub_driver rh_drv;
+
+    /**
+     * Creates a USB transaction. A transaction consists of one or more
+     * transmissions to a single endpoint.
+     */
+    cdi_usb_hc_transaction_t
+        (*create_transaction)(struct cdi_usb_hc* hc,
+                              const struct cdi_usb_hc_ep_info* target);
+
+    /**
+     * Enters a transmission into a transaction. The transmission will be
+     * executed asynchronously.
+     */
+    void (*enqueue)(struct cdi_usb_hc* hc,
+                    const struct cdi_usb_hc_transmission* trans);
+
+    /**
+     * Wait until all transmissions enqueued in the given transaction have been
+     * executed. The variables pointed to by the @result field of the
+     * transmissions enqueued will only be valid when the first call to this
+     * function after the enqueue() calls returns.
+     */
+    void (*wait_transaction)(struct cdi_usb_hc* hc,
+                             cdi_usb_hc_transaction_t ta);
+
+    /**
+     * Destroys a transaction. Transmissions which have not been waited on may
+     * or may not have been executed by the time this function returns. The
+     * values of the variables pointed to by the @result field of unwaited-for
+     * transmissions are not valid, neither are the buffer contents for
+     * receiving transmissions.
+     */
+    void (*destroy_transaction)(struct cdi_usb_hc* hc,
+                                cdi_usb_hc_transaction_t ta);
+};
+
+#endif
-- 
2.4.0