[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cdi-devel] [PATCH 5/6] USB 1.1
From: Max Reitz <max@xxxxxxxxxx>
+ Added USB 1.1 bus driver
Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
usb11/control.c | 252 +++++++++++++++++++++++++++++++++++++++++++
usb11/include/control.h | 31 ++++++
usb11/include/transfer.h | 38 +++++++
usb11/include/usb-structs.h | 184 +++++++++++++++++++++++++++++++
usb11/include/usb11.h | 41 +++++++
usb11/main.c | 58 ++++++++++
usb11/transfer.c | 223 ++++++++++++++++++++++++++++++++++++++
7 files changed, 827 insertions(+), 0 deletions(-)
create mode 100644 usb11/control.c
create mode 100644 usb11/include/control.h
create mode 100644 usb11/include/transfer.h
create mode 100644 usb11/include/usb-structs.h
create mode 100644 usb11/include/usb11.h
create mode 100644 usb11/main.c
create mode 100644 usb11/transfer.c
diff --git a/usb11/control.c b/usb11/control.c
new file mode 100644
index 0000000..170341d
--- /dev/null
+++ b/usb11/control.c
@@ -0,0 +1,252 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#include <stdlib.h>
+
+#include <cdi/lists.h>
+#include <cdi/misc.h>
+#include <cdi/usb.h>
+
+#include "usb11.h"
+#include "usb-structs.h"
+#include "transfer.h"
+
+static int usb_dev_ids = 1;
+
+static void enumerate_hub(struct cdi_usb_device *usbdev);
+
+static int usb11_real_enumerate(struct cdi_usb_device *device)
+{
+ struct endpoint_desc *ep0;
+ struct device_desc *dev_desc;
+ struct cdi_usb_hcd *hcd;
+ int id;
+ char *name;
+ void *position;
+ struct config_desc *conf_desc;
+ struct interface_desc *if_desc, *best_if;
+
+ hcd = (struct cdi_usb_hcd *)device->hc->dev.driver;
+
+ //EP0 initialisieren
+ device->ep0 = malloc(sizeof(*device->ep0));
+ device->ep0->endpoint = malloc(sizeof(struct endpoint_desc));
+ ep0 = (struct endpoint_desc *)device->ep0->endpoint;
+ ep0->length = sizeof(struct endpoint_desc);
+ ep0->descriptor_type = DESC_ENDPOINT;
+ ep0->endpoint_address = 0;
+ ep0->attributes = 0;
+ ep0->max_packet_size = 8;
+ ep0->interval = 0;
+ device->ep0->device = device;
+ device->ep0->data_toggle = 0;
+
+ //Zurücksetzen
+ device->reset(device);
+
+ //Pipe erzeugen
+ hcd->add_pipe(device->ep0);
+
+ //Erste acht Bytes des Device-Descriptors abrufen und die maximale
+ //Paketgrö�e von EP0 feststellen
+ dev_desc = usb11_do_control(device, DEV_TO_HOST, NULL, 8, STD_REQUEST,
+ REC_DEVICE, GET_DESCRIPTOR, DESC_DEVICE << 8, 0);
+ if (dev_desc == NULL) {
+ return 0;
+ }
+ ep0->max_packet_size = dev_desc->max_packet_size0;
+
+ //Nochmals zurücksetzen
+ device->reset(device);
+
+ //USB-Adresse zuweisen
+ usb11_do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+ REC_DEVICE, SET_ADDRESS, (id = usb_dev_ids++), 0);
+ device->id = id;
+ if (usb_dev_ids >= 128) {
+ d0printf("Warning: USB device ID overflow.\n");
+ usb_dev_ids = 1;
+ }
+
+ //So, jetzt haben wir eine Adresse, da gibts auch eine neue Pipe
+ hcd->add_pipe(device->ep0);
+
+ //Den ganzen Device-Descriptor einlesen
+ dev_desc = usb11_do_control(device, DEV_TO_HOST, NULL, sizeof(*dev_desc),
+ STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR, DESC_DEVICE << 8, 0);
+ device->device_desc = dev_desc;
+ device->vendor_id = dev_desc->vendor_id;
+ device->device_id = dev_desc->device_id;
+
+ if (dev_desc->iManufacturer) {
+ name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+ REC_DEVICE, GET_DESCRIPTOR,
+ (DESC_STRING << 8) | dev_desc->iManufacturer, 0);
+ if (name == NULL) {
+ return 0;
+ }
+ d1printf(" -> Manufacturer: ");
+ for (int i = 2; i < name[0]; i += 2) {
+ _d1printf("%c", name[i]);
+ }
+ _d1printf("\n");
+ }
+ if (dev_desc->iProduct) {
+ name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+ REC_DEVICE, GET_DESCRIPTOR,
+ (DESC_STRING << 8) | dev_desc->iProduct, 0);
+ if (name == NULL) {
+ return 0;
+ }
+ d1printf(" -> Product: ");
+ for (int i = 2; i < name[0]; i += 2) {
+ _d1printf("%c", name[i]);
+ }
+ _d1printf("\n");
+ }
+ //TODO: Man kann doch nicht immer den ersten nehmen...
+ conf_desc = usb11_do_control(device, DEV_TO_HOST, NULL,
+ sizeof(struct config_desc), STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+ DESC_CONFIGURATION << 8, 0);
+ if (conf_desc == NULL) {
+ return 0;
+ }
+ conf_desc = usb11_do_control(device, DEV_TO_HOST, NULL,
+ conf_desc->total_length, STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+ DESC_CONFIGURATION << 8, 0);
+ if (conf_desc == NULL) {
+ return 0;
+ }
+ device->config_desc = conf_desc;
+ usb11_do_control(device, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+ SET_CONFIGURATION, conf_desc->config_value, 0);
+ if (conf_desc->iConfiguration) {
+ name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+ REC_DEVICE, GET_DESCRIPTOR,
+ (DESC_STRING << 8) | conf_desc->iConfiguration, 0);
+ if (name == NULL) {
+ return 0;
+ }
+ d1printf("Using configuration ");
+ for (int i = 2; i < name[0]; i += 2) {
+ _d1printf("%c", name[i]);
+ }
+ _d1printf(".\n");
+ }
+ position = conf_desc;
+ position = (void *)((uintptr_t)position + sizeof(struct config_desc));
+ best_if = position; //Standard-IF
+ for (int i = 0; i < conf_desc->num_interfaces; i++) {
+ if_desc = position;
+ //TODO MSD ist zwar hübsch. Aber andere auch ;-)
+ if (if_desc->interface_class == 8) {
+ best_if = if_desc;
+ break;
+ }
+ position = (void *)((uintptr_t)position +
+ sizeof(struct interface_desc) +
+ if_desc->num_endpoints * sizeof(struct endpoint_desc));
+ }
+ usb11_do_control(device, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+ SET_INTERFACE, best_if->interface_number, 0);
+ device->interface_desc = (void *)best_if;
+ if (best_if->iInterface) {
+ name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+ REC_DEVICE, GET_DESCRIPTOR,
+ (DESC_STRING << 8) | best_if->iInterface, 0);
+ if (name == NULL) {
+ return 0;
+ }
+ d1printf("Using interface ");
+ for (int i = 2; i < name[0]; i += 2) {
+ _d1printf("%c", name[i]);
+ }
+ _d1printf(".\n");
+ }
+ d1printf("Configuration: %i:%i (%i)\n", conf_desc->config_value,
+ best_if->interface_number, best_if->interface_class);
+
+ if (!dev_desc->class_id) { //Composite Device
+ device->class_id = best_if->interface_class;
+ device->subclass_id = best_if->interface_subclass;
+ device->protocol_id = best_if->interface_protocol;
+ } else {
+ device->class_id = dev_desc->class_id;
+ device->subclass_id = dev_desc->subclass_id;
+ device->protocol_id = dev_desc->protocol_id;
+ }
+
+ if (best_if->interface_class == USBDC_HUB) {
+ enumerate_hub(device);
+ }
+
+ return 1;
+}
+
+void usb11_enumerate(struct cdi_usb_device *device)
+{
+ if (!usb11_real_enumerate(device)) {
+ free(device->ep0->endpoint);
+ free(device->ep0);
+ }
+}
+
+static void reset_hub_device(struct cdi_usb_device *usbdev)
+{
+ usb11_do_control(usbdev->hub, HOST_TO_DEV, NULL, 0, CLS_REQUEST, REC_OTHER,
+ SET_FEATURE, PORTF_RESET, usbdev->port + 1);
+ cdi_sleep_ms(20);
+}
+
+static void enumerate_hub(struct cdi_usb_device *usbdev)
+{
+ struct hub_desc *hub_desc;
+ struct cdi_usb_device *down;
+ uint16_t *port_status;
+ int i;
+
+ //Mehr als 8 Ports sollte es nicht geben, die Grö�e des Deskriptors wird
+ //daher wohl nicht grö�er als sizeof()+16 werden
+ hub_desc = usb11_do_control(usbdev, DEV_TO_HOST, NULL,
+ sizeof(*hub_desc) + 16, CLS_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+ DESC_DEVICE << 8, 0);
+ for (i = 0; i < hub_desc->nbr_ports; i++) {
+ port_status = usb11_do_control(usbdev, DEV_TO_HOST, NULL, 4,
+ CLS_REQUEST,REC_OTHER, GET_STATUS, 0, i + 1);
+ if (!(port_status[0] & PORT_DEVICE)) {
+ continue;
+ }
+ //Strom an
+ usb11_do_control(usbdev, HOST_TO_DEV, NULL, 0, CLS_REQUEST, REC_OTHER,
+ SET_FEATURE, PORTF_POWER, i + 1);
+ cdi_sleep_ms(hub_desc->pwron2pwrgood * 2);
+ down = malloc(sizeof(struct cdi_usb_device));
+ down->hc = usbdev->hc;
+ down->hub = usbdev;
+ down->id = 0;
+ down->port = i;
+ down->speed = (port_status[0] & PORT_LOWSPEED) ?
+ CDI_USB_LOW_SPEED : CDI_USB_FULL_SPEED;
+ down->reset = &reset_hub_device;
+ cdi_usb_device_init(down);
+ }
+}
diff --git a/usb11/include/control.h b/usb11/include/control.h
new file mode 100644
index 0000000..97edefc
--- /dev/null
+++ b/usb11/include/control.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include <cdi/lists.h>
+#include <cdi/usb.h>
+
+void usb11_enumerate(struct cdi_usb_device *device);
+
+#endif
diff --git a/usb11/include/transfer.h b/usb11/include/transfer.h
new file mode 100644
index 0000000..3b0f086
--- /dev/null
+++ b/usb11/include/transfer.h
@@ -0,0 +1,38 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#ifndef TRANSFER_H
+#define TRANSFER_H
+
+#include <stddef.h>
+
+#include <cdi/usb.h>
+
+void *usb11_do_control(struct cdi_usb_device *device, int direction,
+ void *buffer, int length, int rtype, int recipient, int request, int value,
+ int index);
+void *usb11_export_control(struct cdi_usb_device *device,
+ struct cdi_usb_control_transfer *transfer);
+cdi_usb_status_t usb11_send_packets(struct cdi_usb_packet *packets,
+ size_t num_packets);
+
+#endif
diff --git a/usb11/include/usb-structs.h b/usb11/include/usb-structs.h
new file mode 100644
index 0000000..427d0e5
--- /dev/null
+++ b/usb11/include/usb-structs.h
@@ -0,0 +1,184 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#ifndef USB_STRUCTS_H
+#define USB_STRUCTS_H
+
+#include <stdint.h>
+
+
+#define NO_DATA 0x01
+#define DEV_TO_HOST 0x80
+#define HOST_TO_DEV 0x00
+#define STD_REQUEST 0x00
+#define CLS_REQUEST 0x20
+#define VEN_REQUEST 0x40
+#define REC_DEVICE 0x00
+#define REC_INTERFACE 0x01
+#define REC_ENDPOINT 0x02
+#define REC_OTHER 0x03
+
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+#define SET_FEATURE 3
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+#define SYNC_FRAME 12
+
+#define PORT_DEVICE 0x0001
+#define PORT_ENABLED 0x0002
+#define PORT_SUSPENDED 0x0004
+#define PORT_OVERCURRENT 0x0008
+#define PORT_RESET 0x0010
+#define PORT_POWER 0x0100
+#define PORT_LOWSPEED 0x0200
+#define PORT_HIGHSPEED 0x0400
+#define PORT_TEST 0x0800
+#define PORT_INDICATOR 0x1000
+
+#define PORTF_CONNECTION 0
+#define PORTF_ENABLE 1
+#define PORTF_SUSPEND 2
+#define PORTF_OVERCURRENT 3
+#define PORTF_RESET 4
+#define PORTF_POWER 8
+#define PORTF_LOWSPEED 9
+#define PORTF_HIGHSPEED 10
+#define PORTF_C_CONNECTION 16
+#define PORTF_C_ENABLE 17
+#define PORTF_C_SUSPEND 18
+#define PORTF_C_OVERCURRENT 19
+#define PORTF_C_RESET 20
+#define PORTF_TEST 21
+#define PORTF_INDICATOR 22
+
+#define DESC_DEVICE 1
+#define DESC_CONFIGURATION 2
+#define DESC_STRING 3
+#define DESC_INTERFACE 4
+#define DESC_ENDPOINT 5
+#define DESC_DEVICE_QUALIFIER 6
+#define DESC_OTHER_SPEED_CONFIGURATION 7
+#define DESC_INTERFACE_POWER 8
+
+
+struct setup_packet
+{
+ uint8_t request_type;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+} __attribute__((packed));
+
+struct device_desc
+{
+ uint8_t length;
+ uint8_t descriptor_type;
+ uint16_t bcdUSB;
+ uint8_t class_id;
+ uint8_t subclass_id;
+ uint8_t protocol_id;
+ uint8_t max_packet_size0;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t num_configurations;
+} __attribute__((packed));
+
+struct config_desc
+{
+ uint8_t length;
+ uint8_t descriptor_type;
+ uint16_t total_length;
+ uint8_t num_interfaces;
+ uint8_t config_value;
+ uint8_t iConfiguration;
+ uint8_t attributes;
+ uint8_t max_power;
+} __attribute__((packed));
+
+struct interface_desc
+{
+ uint8_t length;
+ uint8_t descriptor_type;
+ uint8_t interface_number;
+ uint8_t alternate_setting;
+ uint8_t num_endpoints;
+ uint8_t interface_class;
+ uint8_t interface_subclass;
+ uint8_t interface_protocol;
+ uint8_t iInterface;
+} __attribute__((packed));
+
+struct endpoint_desc
+{
+ uint8_t length;
+ uint8_t descriptor_type;
+ uint8_t endpoint_address;
+ uint8_t attributes;
+ uint16_t max_packet_size;
+ uint8_t interval;
+} __attribute__((packed));
+
+struct hub_desc
+{
+ uint8_t length;
+ uint8_t descriptor_type;
+ uint8_t nbr_ports;
+ uint16_t hub_characteristics;
+ uint8_t pwron2pwrgood;
+ uint8_t hub_contr_current;
+} __attribute__((packed));
+
+typedef enum
+{
+ USBDC_COMPOSITE = 0x00,
+ USBDC_AUDIO = 0x01,
+ USBDC_COMM_CDC = 0x02,
+ USBDC_HID = 0x03,
+ USBDC_PID = 0x05,
+ USBDC_IMAGE = 0x06,
+ USBDC_PRINTER = 0x07,
+ USBDC_MSC = 0x08,
+ USBDC_HUB = 0x09,
+ USBDC_CDC_DATA = 0x0A,
+ USBDC_CHIP = 0x0B,
+ USBDC_SECURITY = 0x0D,
+ USBDC_VIDEO = 0x0E,
+ USBDC_HEALTH = 0x0F,
+ USBDC_DIAGNOSIS = 0xDC,
+ USBDC_WIRELESS = 0xE0,
+ USBDC_MISC = 0xEF,
+ USBDC_SOFT_SPEC = 0xFE,
+ USBDC_VENDOR_SPEC = 0xFF
+} usb_class_t;
+
+#endif
diff --git a/usb11/include/usb11.h b/usb11/include/usb11.h
new file mode 100644
index 0000000..77634e9
--- /dev/null
+++ b/usb11/include/usb11.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#ifndef USB11_H
+#define USB11_H
+
+#include <stdio.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define d1printf(...) printf("[usb 1.1] " __VA_ARGS__)
+#define _d1printf(...) printf(__VA_ARGS__)
+#else
+#define d1printf(...)
+#define _d1printf(...)
+#endif
+
+#define d0printf(...) printf("[usb 1.1] " __VA_ARGS__)
+#define _d0printf(...) printf(__VA_ARGS__)
+
+#endif
diff --git a/usb11/main.c b/usb11/main.c
new file mode 100644
index 0000000..e381062
--- /dev/null
+++ b/usb11/main.c
@@ -0,0 +1,58 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#include <cdi/misc.h>
+#include <cdi/usb.h>
+
+#include "control.h"
+#include "transfer.h"
+
+#define DRIVER_NAME "USB 1.1"
+
+int init_usb11(void);
+
+static struct cdi_usb_driver driver = {
+ .drv = {
+ .type = CDI_USB,
+ .name = DRIVER_NAME,
+ .devices = NULL,
+ .init_device = NULL,
+ .remove_device = NULL,
+ .init = &init_usb11,
+ .destroy = NULL
+ },
+ .speeds = CDI_USB_LOW_SPEED | CDI_USB_FULL_SPEED,
+ .enumerate_device = &usb11_enumerate,
+ .send_packets = &usb11_send_packets,
+ .do_control = &usb11_export_control
+};
+
+CDI_DRIVER(DRIVER_NAME, driver)
+
+int init_usb11()
+{
+ cdi_init();
+
+ cdi_usb_driver_init(&driver);
+
+ return 0;
+}
diff --git a/usb11/transfer.c b/usb11/transfer.c
new file mode 100644
index 0000000..eb4f949
--- /dev/null
+++ b/usb11/transfer.c
@@ -0,0 +1,223 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <cdi/usb.h>
+
+#include "transfer.h"
+#include "usb11.h"
+#include "usb-structs.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/**
+ * Verarbeitet USB-Pakete.
+ *
+ * @param packet Die Paketliste
+ * @param num_packets Anzahl der Pakete
+ *
+ * @return Status
+ */
+
+cdi_usb_status_t usb11_send_packets(struct cdi_usb_packet *packets,
+ size_t num_packets)
+{
+ cdi_usb_status_t error = CDI_USB_NAK;
+ int i = 0, mps;
+ int num_out_packets;
+ struct cdi_usb_pipe *pipe;
+ struct cdi_usb_device *device;
+ struct cdi_usb_packet *out_packets;
+ struct endpoint_desc *ep;
+ struct cdi_usb_hcd *hcd;
+
+ if (num_packets < 1) {
+ return CDI_USB_TRIVIAL_ERROR;
+ }
+
+ // Alle Pakete muessen dieselbe Pipe benutzen
+ pipe = packets[0].pipe;
+ for (i = 1; i < (int)num_packets; i++) {
+ if (packets[i].pipe != pipe) {
+ return CDI_USB_TRIVIAL_ERROR;
+ }
+ }
+
+ device = pipe->device;
+ hcd = (struct cdi_usb_hcd *)device->hc->dev.driver;
+ ep = (struct endpoint_desc *)pipe->endpoint;
+
+ // Pruefen, wie viele Pakete wir draus machen muessen
+ mps = ep->max_packet_size;
+ num_out_packets = 0;
+ for (i = 0; i < (int)num_packets; i++) {
+ int num = (packets[i].length + mps - 1) / mps;
+ if (num > 0) {
+ num_out_packets += num;
+ } else {
+ // Pakete ohne Daten wollen auch gesendet werden
+ num_out_packets++;
+ }
+ }
+
+ // Ggf. Pakete kopieren und splitten
+ if (num_out_packets == (int)num_packets) {
+ out_packets = packets;
+ } else {
+ int j;
+ int cur = 0;
+
+ out_packets = calloc(num_out_packets, sizeof(*out_packets));
+ for (i = 0; i < (int)num_packets; i++) {
+ int num = (packets[i].length + mps - 1) / mps;
+ if (num == 0) {
+ num = 1;
+ }
+
+ for (j = 0; j < num; j++) {
+ out_packets[cur].pipe = pipe;
+ out_packets[cur].type = packets[i].type;
+ out_packets[cur].data = packets[i].data;
+ out_packets[cur].length = MIN((int)packets[i].length, mps);
+ out_packets[cur].condition = CDI_USB_NAK;
+
+ packets[i].data = (void *)((uintptr_t)packets[i].data +
+ out_packets[cur].length);
+ packets[i].length -= out_packets[cur].length;
+ cur++;
+ }
+ }
+ }
+
+ error = hcd->send_packets(out_packets, num_out_packets);
+ if (error & CDI_USB_STALLED) {
+ d0printf("ENDPOINT 0x%02X OF DEVICE %i STALLED!\n",
+ ep->endpoint_address, device->id);
+ usb11_do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+ REC_ENDPOINT, CLEAR_FEATURE, 0, ep->endpoint_address);
+ } else if (error & CDI_USB_NAK) {
+ // Nicht angenommene Pakete (FIXME: einzeln) senden
+ for (i = 0; i < num_out_packets; i++) {
+ if (!(out_packets[i].condition & CDI_USB_NAK)) {
+ continue;
+ }
+ error = CDI_USB_NAK;
+ while (error & CDI_USB_NAK) {
+ error = hcd->send_packets(&out_packets[i], 1);
+ if (error & CDI_USB_NAK) {
+ cdi_sleep_ms(5);
+ }
+ }
+ }
+ }
+
+ if (out_packets != packets) {
+ free(out_packets);
+ }
+
+ return error;
+}
+
+void *usb11_do_control(struct cdi_usb_device *device, int direction,
+ void *buffer, int length, int rtype, int recipient, int request, int value,
+ int index)
+{
+ int no_data, alloced_here = 0;
+ cdi_usb_status_t rval;
+ struct setup_packet _setup;
+ struct setup_packet *setup = &_setup;
+
+ no_data = direction & NO_DATA;
+ direction &= 0x80;
+
+ setup->request_type = direction | (rtype & 0x60) | (recipient & 0x1F);
+ setup->request = request;
+ setup->value = value;
+ setup->index = index;
+ setup->length = length;
+
+ struct cdi_usb_packet setup_packet = {
+ .pipe = device->ep0,
+ .type = CDI_USB_PACKET_SETUP,
+ .data = setup,
+ .length = sizeof(*setup),
+ .use_toggle = TOGGLE_UNSPECIFIC
+ };
+
+ if (usb11_send_packets(&setup_packet, 1)) {
+ return NULL;
+ }
+
+ if (no_data) {
+ rval = CDI_USB_NO_ERROR;
+ buffer = (void *)0xFFFFFFFF; //Kein Fehler, aber auch keine Daten
+ } else {
+ if ((direction != HOST_TO_DEV) || (length && (buffer == NULL))) {
+ buffer = malloc(length);
+ alloced_here = 1;
+ }
+
+ struct cdi_usb_packet data_packet = {
+ .pipe = device->ep0,
+ .type = (direction == DEV_TO_HOST ?
+ CDI_USB_PACKET_IN : CDI_USB_PACKET_OUT),
+ .data = buffer,
+ .length = length,
+ .use_toggle = TOGGLE_UNSPECIFIC
+ };
+
+ rval = usb11_send_packets(&data_packet, 1);
+ }
+
+ if (rval == CDI_USB_NO_ERROR) {
+ struct cdi_usb_packet ack_packet = {
+ .pipe = device->ep0,
+ .data = NULL,
+ .length = 0,
+ .use_toggle = TOGGLE_1
+ };
+
+ if (no_data || (direction == HOST_TO_DEV)) {
+ ack_packet.type = CDI_USB_PACKET_IN;
+ } else {
+ ack_packet.type = CDI_USB_PACKET_OUT;
+ }
+
+ rval = usb11_send_packets(&ack_packet, 1);
+ }
+
+ if ((rval != CDI_USB_NO_ERROR) && alloced_here) {
+ free(buffer);
+ }
+
+ return (rval == CDI_USB_NO_ERROR) ? buffer : NULL;
+}
+
+void *usb11_export_control(struct cdi_usb_device *device,
+ struct cdi_usb_control_transfer *transfer)
+{
+ return usb11_do_control(device, transfer->direction, transfer->buffer,
+ transfer->length, transfer->rtype, transfer->recipient,
+ transfer->request, transfer->value, transfer->index);
+}
--
1.6.4.2