[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cdi-devel] [PATCH 5/8] cdi/usb: Add headers
From: Max Reitz <max@xxxxxxxxxx>
+ 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 | 118 +++++++++++++++++++++++
include/cdi/usb.h | 217 +++++++++++++++++++++++++++++++++++++++++++
include/cdi/usb_hcd.h | 159 +++++++++++++++++++++++++++++++
3 files changed, 494 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..70a74ce
--- /dev/null
+++ b/include/cdi/usb-structures.h
@@ -0,0 +1,118 @@
+/*
+ * 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));
+
+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));
+
+
+/// Control request numbers
+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,
+};
+
+/// 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)
+
+#endif
diff --git a/include/cdi/usb.h b/include/cdi/usb.h
new file mode 100644
index 0000000..111e723
--- /dev/null
+++ b/include/cdi/usb.h
@@ -0,0 +1,217 @@
+/*
+ * 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;
+};
+
+
+/**
+ * This function is provided by the reference USB bus driver, it must only be
+ * called by the CDI library.
+ *
+ * It is called once a host controller driver provides a host controller device
+ * (returned by its init_device() function) which is passed to this function.
+ */
+void cdi_usb_provide_hc(struct cdi_device* dev);
+
+/**
+ * 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..774c0a9
--- /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
+ int dev;
+
+ /// Endpoint ID
+ int ep;
+
+ /// Endpoint type
+ cdi_usb_endpoint_type_t ep_type;
+
+ /// Transfer speed
+ cdi_usb_speed_t speed;
+
+ /// Maximum packet size for this endpoint
+ int 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.
+ */
+ int 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.
+ */
+ int 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.3.4