[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 3/3] USB-Stack
From: Max Reitz <max@xxxxxxxxxx>
+ UHCI-Treiber für Control/Bulk und natürlich die Initialisierung
+ USB-1.x-Treiber für Control/Bulk und Hubs (die auf echter Hardware
aber noch leichte Probleme bereiten)
+ USB-MSC-Treiber für Bulk-Only und CBI (wobei letzteres noch nicht
so richtig arbeitet); mit Debugausgaben, damit man sieht, dass auch
etwas passiert
Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
src/modules/usb/include/usb-ddrv.h | 59 +++++
src/modules/usb/include/usb-hc.h | 141 +++++++++++
src/modules/usb/include/usb-hub.h | 49 ++++
src/modules/usb/include/usb-server.h | 153 ++++++++++++
src/modules/usb/include/usb-structs.h | 176 +++++++++++++
src/modules/usb/include/usb-trans.h | 66 +++++
src/modules/usb/msd/Makefile.all | 8 +
src/modules/usb/msd/init.c | 197 +++++++++++++++
src/modules/usb/msd/lostio.c | 218 ++++++++++++++++
src/modules/usb/msd/main.c | 65 +++++
src/modules/usb/msd/msd-bo.c | 104 ++++++++
src/modules/usb/msd/msd-bo.h | 99 ++++++++
src/modules/usb/msd/msd-cbi.c | 86 +++++++
src/modules/usb/msd/msd-cbi.h | 71 ++++++
src/modules/usb/msd/msd.h | 146 +++++++++++
src/modules/usb/msd/rpc.c | 83 ++++++
src/modules/usb/msd/scsi.c | 240 ++++++++++++++++++
src/modules/usb/msd/scsi.h | 219 ++++++++++++++++
src/modules/usb/msd/usb-lib.c | 207 ++++++++++++++++
src/modules/usb/msd/usb-lib.h | 124 +++++++++
src/modules/usb/uhci/Makefile.all | 8 +
src/modules/usb/uhci/ctrl.c | 96 +++++++
src/modules/usb/uhci/init.c | 265 ++++++++++++++++++++
src/modules/usb/uhci/main.c | 73 ++++++
src/modules/usb/uhci/rpc.c | 297 ++++++++++++++++++++++
src/modules/usb/uhci/trans.c | 316 +++++++++++++++++++++++
src/modules/usb/uhci/uhci.h | 269 ++++++++++++++++++++
src/modules/usb/usb1/Makefile.all | 8 +
src/modules/usb/usb1/detect.c | 440 +++++++++++++++++++++++++++++++++
src/modules/usb/usb1/hub.c | 180 ++++++++++++++
src/modules/usb/usb1/main.c | 59 +++++
src/modules/usb/usb1/rpc.c | 327 ++++++++++++++++++++++++
src/modules/usb/usb1/transfer.c | 123 +++++++++
src/modules/usb/usb1/usb.h | 209 ++++++++++++++++
34 files changed, 5181 insertions(+), 0 deletions(-)
create mode 100644 src/modules/usb/include/usb-ddrv.h
create mode 100644 src/modules/usb/include/usb-hc.h
create mode 100644 src/modules/usb/include/usb-hub.h
create mode 100644 src/modules/usb/include/usb-server.h
create mode 100644 src/modules/usb/include/usb-structs.h
create mode 100644 src/modules/usb/include/usb-trans.h
create mode 100644 src/modules/usb/msd/Makefile.all
create mode 100644 src/modules/usb/msd/init.c
create mode 100644 src/modules/usb/msd/lostio.c
create mode 100644 src/modules/usb/msd/main.c
create mode 100644 src/modules/usb/msd/msd-bo.c
create mode 100644 src/modules/usb/msd/msd-bo.h
create mode 100644 src/modules/usb/msd/msd-cbi.c
create mode 100644 src/modules/usb/msd/msd-cbi.h
create mode 100644 src/modules/usb/msd/msd.h
create mode 100644 src/modules/usb/msd/rpc.c
create mode 100644 src/modules/usb/msd/scsi.c
create mode 100644 src/modules/usb/msd/scsi.h
create mode 100644 src/modules/usb/msd/usb-lib.c
create mode 100644 src/modules/usb/msd/usb-lib.h
create mode 100644 src/modules/usb/uhci/Makefile.all
create mode 100644 src/modules/usb/uhci/ctrl.c
create mode 100644 src/modules/usb/uhci/init.c
create mode 100644 src/modules/usb/uhci/main.c
create mode 100644 src/modules/usb/uhci/rpc.c
create mode 100644 src/modules/usb/uhci/trans.c
create mode 100644 src/modules/usb/uhci/uhci.h
create mode 100644 src/modules/usb/usb1/Makefile.all
create mode 100644 src/modules/usb/usb1/detect.c
create mode 100644 src/modules/usb/usb1/hub.c
create mode 100644 src/modules/usb/usb1/main.c
create mode 100644 src/modules/usb/usb1/rpc.c
create mode 100644 src/modules/usb/usb1/transfer.c
create mode 100644 src/modules/usb/usb1/usb.h
diff --git a/src/modules/usb/include/usb-ddrv.h b/src/modules/usb/include/usb-ddrv.h
new file mode 100644
index 0000000..d213cd7
--- /dev/null
+++ b/src/modules/usb/include/usb-ddrv.h
@@ -0,0 +1,59 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_DDRV_H
+#define USB_DDRV_H
+
+#include <stdbool.h>
+
+
+#define RPC_USB_DDRV_PLUG_FNN "USB_DDRV_PLUG"
+
+// Ein Wert ist -1, wenn der Treiber alle Geräte annimmt.
+struct usb_handle_devs {
+ int vendor_id, device_id;
+ int class, subclass, protocol;
+};
+
+// Wird vom USB-Bustreiber an einen Gerätetreiber weitergegeben, wenn ein Gerät
+// gefunden wurde
+struct usb_prov_dev {
+ // Handelt es sich beim Gerät um ein Interface und nicht um ein physisches
+ // Gerät, so ist dies true
+ bool is_interface;
+ // Geräte-ID (vom USB-Bustreiber zu verwenden)
+ void* dev_id;
+ // Interface-ID
+ int interface_id;
+ // Typ des Geräts
+ struct usb_handle_devs type;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-hc.h b/src/modules/usb/include/usb-hc.h
new file mode 100644
index 0000000..a70598a
--- /dev/null
+++ b/src/modules/usb/include/usb-hc.h
@@ -0,0 +1,141 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_HC_H
+#define USB_HC_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+// Beschreibt einen USB-Hostcontroller
+struct usb_hc {
+ // Anzahl der Rootports
+ int root_ports;
+ // Für den HCD frei verfügbar
+ void* hcd_avail;
+ // PID des HCD
+ pid_t pid;
+ // USB-Adressenzähler
+ int addr_counter;
+};
+
+// RPC-Funktion für USB-Bustreiber (vorrangig Roothubfunktionen)
+#define RPC_USB_HC_CONTROL_FNN "HC_CONTROL"
+// RPC-Funktion für USB-Bustreiber (vorrangig Transferfunktionen)
+#define RPC_USB_HC_TRANSFER_FNN "HC_TRANSFER"
+
+// PIDs für IN, OUT und SETUP
+#define USB_OUT 0xE1
+#define USB_IN 0x69
+#define USB_SETUP 0x2D
+
+// Roothubfunktionen
+enum usb_hc_ctrl_rt {
+ // Portstatus überprüfen
+ HC_CTRL_SCAN_PORT = 0,
+ // Port deaktivieren
+ HC_CTRL_DSBL_PORT,
+ // Resetsignal treiben
+ HC_CTRL_RESET,
+ // Pipe erstellen
+ HC_CTRL_ADD_PIPE
+};
+
+
+// Allgemeiner HC_CONTROL-Request
+struct usb_hc_ctrl_req {
+ // Funktion
+ enum usb_hc_ctrl_rt type;
+ // Hostcontroller
+ struct usb_hc hc;
+};
+
+// Rootport überprüfen
+struct usb_hc_ctrl_scan {
+ struct usb_hc_ctrl_req req;
+ // Portindex
+ int port;
+};
+
+// Rootport deaktivieren
+struct usb_hc_ctrl_dsbl {
+ struct usb_hc_ctrl_req req;
+ // Portindex
+ int port;
+};
+
+// Resetsignal an einem Rootport treiben
+struct usb_hc_ctrl_rst {
+ struct usb_hc_ctrl_req req;
+ // Portindex
+ int port;
+};
+
+// Pipe hinzufügen
+struct usb_hc_ctrl_appe {
+ struct usb_hc_ctrl_req req;
+ // Informationen zur neuen Pipe
+ struct usb_trans_pipe pipe;
+};
+
+// Allgemeine Transferanfrage
+struct usb_hc_trs {
+ // Funktion
+ enum usb_trans_type type;
+ // Hostcontroller
+ struct usb_hc hc;
+ // Pipe, durch die der Transfer laufen soll
+ struct usb_trans_pipe pipe;
+};
+
+// Controltransfer
+struct usb_hc_trs_ctrl {
+ struct usb_hc_trs trs;
+ // SETUP-Paket
+ struct usb_setup_packet setup;
+ // SHM-Bereich für die Datenphase
+ uint32_t shm;
+};
+
+// Bulktransfer
+struct usb_hc_trs_bulk {
+ struct usb_hc_trs trs;
+ // true zum Empfangen
+ bool receive;
+ // Anzahl der zu übertragenden Bytes
+ size_t length;
+ // SHM-Bereich für die übertragenen Daten
+ uint32_t shm;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-hub.h b/src/modules/usb/include/usb-hub.h
new file mode 100644
index 0000000..478c2bc
--- /dev/null
+++ b/src/modules/usb/include/usb-hub.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_HUB_H
+#define USB_HUB_H
+
+// In den unteren acht Bits wird die Geschwindigkeit gespeichert (viel Platz
+// für zukünftige Neuerungen...)
+#define USB_HUB_SPEED 0xFF
+// Low Speed
+#define USB_HUB_LOW_SPEED (1 << 0)
+// Full Speed
+#define USB_HUB_FULL_SPEED (1 << 1)
+// High Speed
+#define USB_HUB_HIGH_SPEED (1 << 2)
+
+// Gerät angeschlossen
+#define USB_HUB_DEVICE (1 << 8)
+// Status hat sich seit der letzten Anfrage verändert
+#define USB_HUB_CHANGE (1 << 9)
+
+#endif
diff --git a/src/modules/usb/include/usb-server.h b/src/modules/usb/include/usb-server.h
new file mode 100644
index 0000000..6a98707
--- /dev/null
+++ b/src/modules/usb/include/usb-server.h
@@ -0,0 +1,153 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_SERVER_H
+#define USB_SERVER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+// Funktion zum Registrieren von Hostcontrollern
+#define RPC_USB_SV_REGHC_FNN "HCD_REG"
+// Funktion zum Registrieren von Gerätetreibern
+#define RPC_USB_SV_REGDD_FNN "DDRV_REG"
+// Funktion zur Steuerung von Geräten (Daten austauschen, etc.)
+#define RPC_USB_SV_DEVCT_FNN "DEV_CTL"
+
+// Beschreibt eine USB-Pipe
+struct usb_pipe {
+ // Da die von normalen Treibern sowieso nicht dereferenziert werden dürfen,
+ // können diese Strukturen auch undefiniert bleiben.
+ // USB-Gerät (nur für den Bustreiber)
+ struct usb_device* dev;
+ // Endpunktdeskriptor (nur für den Bustreiber)
+ struct usb_endpoint_descriptor* ep;
+
+ // Pipe, zur Kommunikation mit dem Hostcontroller
+ struct usb_trans_pipe trs;
+};
+
+// Funktionen für DEV_CTRL (mit Rückgabetypen)
+enum usb_devctrl_reqtype {
+ // Gibt Anzahl der Endpunkte zurück
+ USB_DC_NUM_ENDPOINTS = 0, // int
+ // Gibt die Interface-ID zurück
+ USB_DC_GET_IFC_ID, // int
+ // Gibt den Endpunktdeskriptor zurück
+ USB_DC_GET_ENDPOINT, // response
+ // Gibt eine Pipe zurück (und erstellt sie)
+ USB_DC_GET_PIPE, // response
+ // Entstallt eine Pipe/den Endpunkt
+ USB_DC_CLEAR_HALT, // int
+ // Führt einen Controltransfer durch
+ USB_DC_TRSF_CONTROL, // int
+ // Führt einen Bulktransfer durch
+ USB_DC_TRSF_BULK // int
+};
+
+// Allgemeine Anfrage für DEV_CTRL
+struct usb_devctrl_req {
+ // Typ der Anrage
+ enum usb_devctrl_reqtype type;
+};
+
+// Gibt die Anzahl der Endpunkte zurück
+struct usb_devctrl_gne {
+ struct usb_devctrl_req req;
+ // Abzufragendes USB-Gerät
+ struct usb_prov_dev dev;
+};
+
+// Gibt die Interface-ID zurück
+struct usb_devctrl_gii {
+ struct usb_devctrl_req req;
+ // Abzufrasgendes USB-Gerät
+ struct usb_prov_dev dev;
+};
+
+// Gibt den Endpunktdeskriptor zurück
+struct usb_devctrl_gep {
+ struct usb_devctrl_req req;
+ // USB-Gerät
+ struct usb_prov_dev dev;
+ // Nummer des Endpunkts (nicht die ID)
+ int ep_number;
+};
+
+// Erstellt eine USB-Pipe und gibt sie zurück
+struct usb_devctrl_gpp {
+ struct usb_devctrl_req req;
+ // USB-Gerät
+ struct usb_prov_dev dev;
+ // Nummer des Zielendpunkts
+ int ep_number;
+};
+
+// Entstallt eine Pipe resp. den Endpunkt
+struct usb_devctrl_clh {
+ struct usb_devctrl_req req;
+ // USB-Pipe
+ struct usb_pipe pipe;
+};
+
+// Führt einen Controltransfer durch
+struct usb_devctrl_tct {
+ struct usb_devctrl_req req;
+ // Ist EP0 das Ziel, so muss dev_id auf den Wert aus usb_prov_dev gesetzt
+ // werden, sonst pipe auf die entsprechende USB-Pipe.
+ union {
+ struct usb_pipe pipe;
+ void* dev_id;
+ } dst;
+ // true, wenn durch die Default Control Pipe übertragen werden soll
+ bool ep0;
+ // SETUP-Paket
+ struct usb_setup_packet setup;
+ // SHM-Bereich für die Datenphase
+ uint32_t shm;
+};
+
+// Führt einen Bulktransfer durch
+struct usb_devctrl_tbk {
+ struct usb_devctrl_req req;
+ // USB-Pipe
+ struct usb_pipe pipe;
+ // Anzahl der zu übertragenden Bytes
+ size_t length;
+ // SHM-Bereich für die Daten
+ uint32_t shm;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-structs.h b/src/modules/usb/include/usb-structs.h
new file mode 100644
index 0000000..f0b5927
--- /dev/null
+++ b/src/modules/usb/include/usb-structs.h
@@ -0,0 +1,176 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_STRUCTS_H
+#define USB_STRUCTS_H
+
+#include <stdint.h>
+
+#define USB_LOW_SPEED USB_HUB_LOW_SPEED
+#define USB_FULL_SPEED USB_HUB_FULL_SPEED
+#define USB_HIGH_SPEED USB_HUB_HIGH_SPEED
+
+enum usb_state {
+ USB_ATTACHED = 0,
+ USB_POWERED,
+ USB_DEFAULT,
+ USB_ADDRESS,
+ USB_CONFIGURED,
+ USB_SUSPENDED
+};
+
+struct usb_setup_packet {
+ uint8_t type;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+} __attribute__((packed));
+
+struct usb_descriptor {
+ uint8_t length;
+ uint8_t desc_type;
+} __attribute__((packed));
+
+
+#define USB_SETUP_OUT (0 << 7)
+#define USB_SETUP_IN (1 << 7)
+#define USB_SETUP_REQ_STD (0 << 5)
+#define USB_SETUP_REQ_CLS (1 << 5)
+#define USB_SETUP_REQ_VDR (2 << 5)
+#define USB_SETUP_REC_DEV 0
+#define USB_SETUP_REC_IF 1
+#define USB_SETUP_REC_EP 2
+#define USB_SETUP_REC_OTH 3
+
+enum usb_setup_requst {
+ USB_GET_STATUS = 0,
+ USB_CLEAR_FEATURE = 1,
+ USB_SET_FEATURE = 3,
+ USB_SET_ADDRESS = 5,
+ USB_GET_DESCRIPTOR = 6,
+ USB_SET_DESCRIPTOR = 7,
+ USB_GET_CONFIGURATION = 8,
+ USB_SET_CONFIGURATION = 9,
+ USB_GET_INTERFACE = 10,
+ USB_SET_INTERFACE = 11,
+ USB_SYNC_FRAME = 12
+};
+
+enum usb_features {
+ USB_ENDPOINT_HALT = 0,
+ USB_DEVICE_REMOTE_WAKEUP = 1,
+ USB_TEST_MODE = 2
+};
+
+enum usb_setup_descriptor {
+ USB_DESC_DEVICE = 1 << 8,
+ USB_DESC_CONFIGURATION = 2 << 8,
+ USB_DESC_STRING = 3 << 8,
+ USB_DESC_INTERFACE = 4 << 8,
+ USB_DESC_ENDPOINT = 5 << 8,
+ USB_DESC_DEVICE_QUALIFIER = 6 << 8,
+ USB_DESC_OTHER_SPEED_CONFIGURATION = 7 << 8,
+ USB_DESC_INTERFACE_POWER = 8 << 8,
+
+ USB_DESC_HUB = 41 << 8
+};
+
+struct usb_device_descriptor {
+ struct usb_descriptor desc;
+ uint16_t bcd_usb;
+ uint8_t class, subclass, protocol;
+ uint8_t mps0;
+ uint16_t vendor_id, device_id;
+ uint16_t bcd_device;
+ uint8_t i_manufacturer, i_product, i_serial;
+ uint8_t num_configurations;
+} __attribute__((packed));
+
+struct usb_config_descriptor
+{
+ struct usb_descriptor desc;
+ uint16_t total_length;
+ uint8_t num_interfaces;
+ uint8_t configuration_value;
+ uint8_t i_configuration;
+ unsigned rsvd0 : 5;
+ unsigned remote_wakeup : 1;
+ unsigned self_powered : 1;
+ unsigned rsvd1 : 1;
+ uint8_t max_power;
+} __attribute__((packed));
+
+struct usb_interface_descriptor
+{
+ struct usb_descriptor desc;
+ uint8_t interface_number;
+ uint8_t alternate_setting;
+ uint8_t num_endpoints;
+ uint8_t class, subclass, protocol;
+ uint8_t i_interface;
+} __attribute__((packed));
+
+#define USB_EP_CONTROL 0
+#define USB_EP_ISOCHRONOUS 1
+#define USB_EP_BULK 2
+#define USB_EP_INTERRUPT 3
+
+struct usb_endpoint_descriptor {
+ struct usb_descriptor desc;
+ unsigned number : 4;
+ unsigned rsvd1 : 3;
+ unsigned direction : 1;
+ unsigned type : 2;
+ unsigned sync : 2;
+ unsigned usage : 2;
+ unsigned rsvd2 : 2;
+ unsigned mps : 11;
+ unsigned trans_opp : 2;
+ unsigned rsvd3 : 3;
+ uint8_t interval;
+} __attribute__((packed));
+
+struct usb_hub_descriptor {
+ struct usb_descriptor desc;
+ uint8_t nbr_ports;
+ unsigned power_mode : 2;
+ unsigned compound : 1;
+ unsigned oc_protect : 2;
+ unsigned tt : 2;
+ unsigned pindicator : 1;
+ uint8_t rsvd;
+ uint8_t pwr_on_2_pwr_good;
+ uint8_t hub_contr_current;
+ // Die folgenden Felder haben eine variable Größe
+} __attribute__((packed));
+
+#endif
+
diff --git a/src/modules/usb/include/usb-trans.h b/src/modules/usb/include/usb-trans.h
new file mode 100644
index 0000000..c5d3a1f
--- /dev/null
+++ b/src/modules/usb/include/usb-trans.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_TRANS_H
+#define USB_TRANS_H
+
+#include <stdbool.h>
+
+#include "usb-hub.h"
+
+// Übertragunsart
+enum usb_trans_type {
+ USB_TRST_CONTROL = 0,
+ USB_TRST_ISOCHRONOUS = 1,
+ USB_TRST_BULK = 2,
+ USB_TRST_INTERRUPT = 3
+};
+
+// USB-Pipe für die Kommunikation mit dem Hostcontroller
+struct usb_trans_pipe {
+ // USB-Adresse (0 bis 127)
+ int usb_addr;
+ // Endpunkt-ID
+ int ep_id;
+ // MPS des Endpunkts
+ int mps;
+
+ // Typ der Pipe
+ enum usb_trans_type type;
+ // Geschwindigkeit des Geräts
+ int speed;
+
+ // Toggle-Bit
+ int toggle;
+ // true, wenn der Endpunkt gestallt ist
+ bool stalled;
+};
+
+#endif
diff --git a/src/modules/usb/msd/Makefile.all b/src/modules/usb/msd/Makefile.all
new file mode 100644
index 0000000..681ef87
--- /dev/null
+++ b/src/modules/usb/msd/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD $1/modules/usb-msd"
+$LOST_TOOLS_LD $LDSCRIPT -ousb-msd.mod *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s usb-msd.mod -o $1/modules/usb-msd
diff --git a/src/modules/usb/msd/init.c b/src/modules/usb/msd/init.c
new file mode 100644
index 0000000..aa0d4a6
--- /dev/null
+++ b/src/modules/usb/msd/init.c
@@ -0,0 +1,197 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-bo.h"
+#include "msd-cbi.h"
+#include "usb-lib.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+void got_bo_msd(struct usb_prov_dev* dev);
+void got_cbi_msd(struct usb_prov_dev* dev);
+
+int got_msd(struct usb_prov_dev* dev)
+{
+ if (dev->type.protocol == 0x50) { // Bulk-only
+ got_bo_msd(dev);
+ return 1;
+ } else if ((dev->type.subclass == 0x04) && !dev->type.protocol) { // UFI/CBI
+ got_cbi_msd(dev);
+ return 1;
+ }
+
+ return 0;
+}
+
+void got_bo_msd(struct usb_prov_dev* dev)
+{
+ int endpoints = usb_get_number_of_endpoints(dev);
+ int ifc_id = usb_get_interface_id(dev);
+ struct usb_endpoint_descriptor* epd = calloc(1, sizeof(*epd));
+ struct usb_endpoint_descriptor* bulk_in = malloc(sizeof(*bulk_in));
+ struct usb_endpoint_descriptor* bulk_out = malloc(sizeof(*bulk_out));
+ int bin = -1, bon = -1;
+
+ int i;
+ for (i = 0; i < endpoints; i++) {
+ usb_get_endpoint_info(dev, i, epd);
+
+ if (epd->type == USB_EP_BULK) {
+ if (epd->direction) {
+ memcpy(bulk_in, epd, sizeof(*epd));
+ bin = i;
+ } else {
+ memcpy(bulk_out, epd, sizeof(*epd));
+ bon = i;
+ }
+ }
+ }
+
+ free(epd);
+
+ if ((bin == -1) || (bon == -1)) {
+ free(bulk_in);
+ free(bulk_out);
+ return;
+ }
+
+ struct usb_pipe* bip = calloc(1, sizeof(*bip));
+ struct usb_pipe* bop = calloc(1, sizeof(*bop));
+
+ usb_create_pipe(dev, bin, bip);
+ usb_create_pipe(dev, bon, bop);
+
+ int max_lun = 0;
+ usb_control_transfer(dev, NULL, &(struct usb_setup_packet){
+ .type = USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_IF,
+ .request = 0xFE, // GET MAX LUN
+ .index = ifc_id,
+ .length = 1,
+ }, &max_lun);
+
+ for (i = 0; i <= max_lun; i++) {
+ struct msc_bo_dev* new = calloc(1, sizeof(*new));
+
+ new->gen.lun = i;
+ new->gen.issue_scsi_cmd = &msd_bo_issue_scsi_cmd;
+ new->gen.send = &msd_bo_send;
+ new->gen.recv = &msd_bo_recv;
+
+ new->bulk_in = bulk_in;
+ new->bulk_out = bulk_out;
+
+ new->bip = bip;
+ new->bop = bop;
+
+ provide_msd(&new->gen);
+ }
+}
+
+void got_cbi_msd(struct usb_prov_dev* dev)
+{
+ int endpoints = usb_get_number_of_endpoints(dev);
+ int ifc_id = usb_get_interface_id(dev);
+ struct usb_endpoint_descriptor* epd = calloc(1, sizeof(*epd));
+ struct usb_endpoint_descriptor* bulk_in = malloc(sizeof(*bulk_in));
+ struct usb_endpoint_descriptor* bulk_out = malloc(sizeof(*bulk_out));
+ struct usb_endpoint_descriptor* interrupt = malloc(sizeof(*interrupt));
+ int bin = -1, bon = -1, ien = -1;
+
+ int i;
+ for (i = 0; i < endpoints; i++) {
+ usb_get_endpoint_info(dev, i, epd);
+
+ if (epd->type == USB_EP_BULK) {
+ if (epd->direction) {
+ memcpy(bulk_in, epd, sizeof(*epd));
+ bin = i;
+ } else {
+ memcpy(bulk_out, epd, sizeof(*epd));
+ bon = i;
+ }
+ } else if (epd->type == USB_EP_INTERRUPT) {
+ memcpy(interrupt, epd, sizeof(*epd));
+ ien = i;
+ }
+ }
+
+ free(epd);
+
+ if (dev->type.protocol || (ien == -1)) {
+ free(interrupt);
+ ien = -1;
+ }
+
+ if ((bin == -1) || (bon == -1)) {
+ free(bulk_in);
+ free(bulk_out);
+ return;
+ }
+
+ struct usb_pipe* bip = calloc(1, sizeof(*bip));
+ struct usb_pipe* bop = calloc(1, sizeof(*bop));
+ struct usb_pipe* ip;
+
+ usb_create_pipe(dev, bin, bip);
+ usb_create_pipe(dev, bon, bop);
+
+ if (ien != -1) {
+ ip = calloc(1, sizeof(*ip));
+ usb_create_pipe(dev, ien, ip);
+ }
+
+ struct msc_cbi_dev* new = calloc(1, sizeof(*new));
+
+ new->gen.lun = 0;
+ new->gen.issue_scsi_cmd = &msd_cbi_issue_scsi_cmd;
+ new->gen.send = &msd_cbi_send;
+ new->gen.recv = &msd_cbi_recv;
+
+ new->dev = dev;
+ new->ifc_id = ifc_id;
+
+ new->bulk_in = bulk_in;
+ new->bulk_out = bulk_out;
+
+ new->bip = bip;
+ new->bop = bop;
+
+ if (ien != -1) {
+ new->interrupt = interrupt;
+ new->ip = ip;
+ }
+
+ provide_msd(&new->gen);
+}
diff --git a/src/modules/usb/msd/lostio.c b/src/modules/usb/msd/lostio.c
new file mode 100644
index 0000000..6a2b503
--- /dev/null
+++ b/src/modules/usb/msd/lostio.c
@@ -0,0 +1,218 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <init.h>
+#include <lostio.h>
+
+#include "msd.h"
+
+static size_t msd_read(lostio_filehandle_t* liofh, void* dest,
+ size_t blocksize, size_t blockcount);
+static size_t msd_write(lostio_filehandle_t* liofh, size_t blocksize,
+ size_t blockcount, void* data);
+static int msd_seek(lostio_filehandle_t* liofh, uint64_t offset, int origin);
+
+struct partition {
+ struct msc_gen_dev* dev;
+ uint64_t block_offset;
+ uint64_t blocks;
+};
+
+struct parttbl_entry {
+ uint8_t active;
+ uint8_t chs_start[3];
+ uint8_t type;
+ uint8_t chs_end[3];
+ uint32_t start;
+ uint32_t size;
+} __attribute__((packed));
+
+void init_lostio_interface(void)
+{
+ lostio_init();
+ lostio_type_ramfile_use();
+ lostio_type_directory_use();
+
+ typehandle_t* msds = calloc(1, sizeof(*msds));
+
+ msds->id = 42;
+ msds->read = &msd_read;
+ msds->write = &msd_write;
+ msds->seek = &msd_seek;
+
+ lostio_register_typehandle(msds);
+}
+
+static void detect_partitions(int msd_number, struct msc_gen_dev* dev)
+{
+ uint8_t* bootsec = malloc(512);
+
+ msd_scsi_read(dev, 0, bootsec, 1);
+
+ if (*(uint16_t*)&bootsec[510] != 0xAA55) {
+ free(bootsec);
+ return;
+ }
+
+ struct parttbl_entry* ptbl = (struct parttbl_entry*)&bootsec[446];
+
+ int p;
+ for (p = 0; p < 4; p++) {
+ if (ptbl[p].size) {
+ if ((ptbl[p].type == 0x0F) || (ptbl[p].type == 0x85)) {
+ continue;
+ }
+
+ struct partition* part = calloc(1, sizeof(*part));
+ part->dev = dev;
+ part->block_offset = ptbl[p].start;
+ part->blocks = ptbl[p].size;
+
+ char name[13];
+ sprintf(name, "/msd%i_p%i", msd_number, p);
+
+ vfstree_create_node(name, 42, ptbl[p].size * dev->block_size, part,
+ 0);
+ }
+ }
+
+ free(bootsec);
+}
+
+void provide_msd(struct msc_gen_dev* dev)
+{
+ static int msds = 0;
+
+ uint64_t bc, bs;
+ if (!msd_scsi_init(dev, &bc, &bs)) {
+ return;
+ }
+
+ printf("[usb-msd] New SCSI block device, %lli %lli-byte blocks: ", bc, bs);
+ uint64_t fs = bc * bs;
+ if (fs >= 10 << 30) {
+ printf("%lli GB\n", fs >> 30);
+ } else if (fs >= 10 << 20) {
+ printf("%lli MB\n", fs >> 20);
+ } else if (fs >= 10 << 10) {
+ printf("%lli kB\n", fs >> 10);
+ } else {
+ printf("%lli B\n", fs);
+ }
+
+ dev->block_size = bs;
+ dev->blocks = bc;
+
+ char name[10];
+ int num = msds++;
+ sprintf(name, "/msd%i", num);
+
+ struct partition* part = calloc(1, sizeof(*part));
+ part->dev = dev;
+ part->blocks = bc;
+
+ vfstree_create_node(name, 42, fs, part, 0);
+
+ // Bei 2880 Sektoren ist es vermutlich eine Diskette (ja, es gibt noch
+ // andere Diskettenarten als 3,5" HD, aber die sind halt selten), und die
+ // hat keine Partitionen (verhindert das Erkennen scheinbarer Partitionen)
+ if (bc != 2880) {
+ detect_partitions(num, dev);
+ }
+
+ // TODO: Das vielleicht erst irgendwie registrieren, wenn alle Geräte
+ // angekommen sind
+ init_service_register("usb-msd");
+
+ uint16_t* mem = calloc(1, 512);
+ msd_scsi_read(dev, 0, mem, 1);
+}
+
+static size_t msd_read(lostio_filehandle_t* liofh, void* dest,
+ size_t blocksize, size_t blockcount)
+{
+ struct partition* part = liofh->node->data;
+ struct msc_gen_dev* dev = part->dev;
+
+ uint64_t begin = liofh->pos / dev->block_size + part->block_offset;
+
+ // Diese Debuginformationen mögen nervig erscheinen, sind aber sehr
+ // wichtig, da man oft nur so erkennen kann, dass überhaupt etwas
+ // geschieht
+ printf("[usb-msd] read from %lli (%i blocks)\n", begin,
+ (blockcount * blocksize + dev->block_size - 1) / dev->block_size);
+ size_t ret = msd_scsi_read(dev, begin, dest,
+ (blockcount * blocksize + dev->block_size - 1) / dev->block_size);
+ msd_seek(liofh, ret, SEEK_CUR);
+
+ return ret;
+}
+
+static size_t msd_write(lostio_filehandle_t* liofh, size_t blocksize,
+ size_t blockcount, void* data)
+{
+ return 0;
+}
+
+static int msd_seek(lostio_filehandle_t* liofh, uint64_t offset, int origin)
+{
+ struct partition* part = liofh->node->data;
+ struct msc_gen_dev* dev = part->dev;
+ uint64_t new_pos = liofh->pos;
+ uint64_t size = part->blocks * dev->block_size;
+
+ switch (origin) {
+ case SEEK_SET:
+ new_pos = offset;
+ break;
+ case SEEK_CUR:
+ new_pos += offset;
+ break;
+ case SEEK_END:
+ new_pos = size;
+ break;
+ }
+
+ if (new_pos > size) {
+ return -1;
+ } else if (new_pos == size) {
+ liofh->flags |= LOSTIO_FLAG_EOF;
+ } else {
+ liofh->flags &= ~LOSTIO_FLAG_EOF;
+ }
+
+ liofh->pos = new_pos;
+ return 0;
+}
diff --git a/src/modules/usb/msd/main.c b/src/modules/usb/msd/main.c
new file mode 100644
index 0000000..cebca5c
--- /dev/null
+++ b/src/modules/usb/msd/main.c
@@ -0,0 +1,65 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "msd.h"
+
+extern pid_t usb_pid;
+
+int main(void)
+{
+ init_messaging();
+ init_lostio_interface();
+
+ // Warten, damit, falls alle Treiber relativ gleichzeitig gestartet werden
+ // (Boot), dieser Prozess nach usb1 (und möglichst vor uhci) weiterläuft
+ msleep(1000);
+
+ usb_pid = init_service_get("usb1");
+ if (!usb_pid)
+ {
+ fprintf(stderr, "You need to start the usb1 driver first.\n");
+ return 1;
+ }
+
+ init_rpc_interface();
+ register_msddrv();
+
+ for (;;) {
+ wait_for_rpc();
+ }
+}
diff --git a/src/modules/usb/msd/msd-bo.c b/src/modules/usb/msd/msd-bo.c
new file mode 100644
index 0000000..0007b80
--- /dev/null
+++ b/src/modules/usb/msd/msd-bo.c
@@ -0,0 +1,104 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-bo.h"
+#include "usb-lib.h"
+
+int check_csw(struct msc_bo_dev* dev)
+{
+ struct msd_bo_csw csw;
+
+ int ret = usb_bulk_transfer(dev->bip, &csw, sizeof(csw), true);
+ if (ret) {
+ return ret;
+ }
+
+ // Man könnte wohl noch ein bisschen was überprüfen...
+ // Some checks might be nice...
+ return 0;
+}
+
+int msd_bo_issue_scsi_cmd(struct msc_gen_dev* dev, const void* cmd_buffer,
+ size_t cmd_length, bool receive, size_t req_length)
+{
+ struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+ if (cmd_length > 16) {
+ cmd_length = 16;
+ }
+
+ struct msd_bo_cbw cbw = {
+ .signature = CBW_SIGNATURE,
+ .data_transfer_length = req_length,
+ .flags = receive ? CBW_IN : CBW_OUT,
+ .lun = dev->lun,
+ .cb_length = cmd_length
+ };
+
+ memcpy(cbw.cb, cmd_buffer, cmd_length);
+
+ int ret = usb_bulk_transfer(bo->bop, &cbw, sizeof(cbw), false);
+ if (ret || req_length) {
+ return ret;
+ }
+
+ return check_csw(bo);
+}
+
+int msd_bo_send(struct msc_gen_dev* dev, const void* buffer, size_t size)
+{
+ struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+ int ret = usb_bulk_transfer(bo->bop, (void*)buffer, size, false);
+ if (ret) {
+ return ret;
+ }
+
+ return check_csw(bo);
+}
+
+int msd_bo_recv(struct msc_gen_dev* dev, void* buffer, size_t size)
+{
+ struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+ int ret = usb_bulk_transfer(bo->bip, buffer, size, true);
+ if (ret) {
+ return ret;
+ }
+
+ return check_csw(bo);
+}
diff --git a/src/modules/usb/msd/msd-bo.h b/src/modules/usb/msd/msd-bo.h
new file mode 100644
index 0000000..49451cb
--- /dev/null
+++ b/src/modules/usb/msd/msd-bo.h
@@ -0,0 +1,99 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef MSD_BO_H
+#define MSD_BO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+
+#define CBW_IN 0x80
+#define CBW_OUT 0x00
+
+#define CBW_SIGNATURE 0x43425355 //'USBC' => USB command
+#define CSW_SIGNATURE 0x53425355 //'USBS' => USB status
+
+
+// Beschreibt ein MSC-Bulk-Only-Gerät
+struct msc_bo_dev {
+ // Das MSD an sich
+ struct msc_gen_dev gen;
+
+ // Bulk-Endpunkte
+ struct usb_endpoint_descriptor* bulk_in;
+ struct usb_endpoint_descriptor* bulk_out;
+
+ // Pipes zu diesen Endpunkten
+ struct usb_pipe* bip;
+ struct usb_pipe* bop;
+};
+
+// Command Block Wrapper für BO-MSDs
+struct msd_bo_cbw {
+ // CBW_SIGNATURE
+ uint32_t signature;
+ // Ein Wert, der im CSW wiederholt wird
+ uint32_t tag;
+ // Länge des Datentransfers
+ uint32_t data_transfer_length;
+ // Flags (vorrangig Richtung des Transfers)
+ uint8_t flags;
+ // LUN
+ uint8_t lun;
+ // Länge des Befehls
+ uint8_t cb_length;
+ // SCSI-Befehl
+ uint8_t cb[16];
+} __attribute__((packed));
+
+// Command Status Wrapper für BO-MSDs
+struct msd_bo_csw {
+ // CSW_SIGNATURE
+ uint32_t signature;
+ // Tagwert aus dem CBW
+ uint32_t tag;
+ // Größe der Daten, die erwartet, aber nicht übertragen wurden
+ uint32_t data_residue;
+ // Status
+ uint8_t status;
+} __attribute__((packed));
+
+// Sendet einen SCSI-Befehl
+int msd_bo_issue_scsi_cmd(struct msc_gen_dev* dev, const void* buffer,
+ size_t cmd_length, bool receive, size_t req_length);
+// Sendet Daten an das Gerät
+int msd_bo_send(struct msc_gen_dev* dev, const void* buffer, size_t size);
+// Empfängt Daten vom Gerät
+int msd_bo_recv(struct msc_gen_dev* dev, void* buffer, size_t size);
+
+#endif
diff --git a/src/modules/usb/msd/msd-cbi.c b/src/modules/usb/msd/msd-cbi.c
new file mode 100644
index 0000000..66590fd
--- /dev/null
+++ b/src/modules/usb/msd/msd-cbi.c
@@ -0,0 +1,86 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-cbi.h"
+#include "usb-lib.h"
+
+int msd_cbi_issue_scsi_cmd(struct msc_gen_dev* dev, const void* cmd_buffer,
+ size_t cmd_length, bool receive, size_t req_length)
+{
+ struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+ int8_t cmd[12] = { 0 };
+ struct usb_setup_packet setup = {
+ .type = USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_IF,
+ .request = 0,
+ .value = 0,
+ .index = cbi->ifc_id,
+ .length = sizeof(cmd)
+ };
+
+ if (cmd_length > 12) {
+ cmd_length = 12;
+ }
+
+ memcpy(cmd, cmd_buffer, cmd_length);
+
+ int ret = usb_control_transfer(cbi->dev, NULL, &setup, cmd);
+
+ /*
+ if (ret == -EHOSTDOWN) {
+ // kA, ob das etwas bringt
+ if (receive == true) {
+ usb_clear_halt(cbi->bip);
+ } else {
+ usb_clear_halt(cbi->bop);
+ }
+ }
+ */
+
+ return ret;
+}
+
+int msd_cbi_send(struct msc_gen_dev* dev, const void* buffer, size_t size)
+{
+ struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+ return usb_bulk_transfer(cbi->bop, (void*)buffer, size, false);
+}
+
+int msd_cbi_recv(struct msc_gen_dev* dev, void* buffer, size_t size)
+{
+ struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+ return usb_bulk_transfer(cbi->bip, buffer, size, true);
+}
diff --git a/src/modules/usb/msd/msd-cbi.h b/src/modules/usb/msd/msd-cbi.h
new file mode 100644
index 0000000..66ff221
--- /dev/null
+++ b/src/modules/usb/msd/msd-cbi.h
@@ -0,0 +1,71 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef MSD_CBI_H
+#define MSD_CBI_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+
+// Beschreibt ein MSC-CBI-Gerät
+struct msc_cbi_dev {
+ // Das MSD an sich
+ struct msc_gen_dev gen;
+
+ // Das zugrunde liegende USB-Gerät
+ struct usb_prov_dev* dev;
+ // Die Interface-ID (MSDs sind immer Interfaces)
+ int ifc_id;
+
+ // Alle wichtigen Endpunkte (EP0 ist in dev enthalten), interrupt darf NULL
+ // sein
+ struct usb_endpoint_descriptor* bulk_in;
+ struct usb_endpoint_descriptor* bulk_out;
+ struct usb_endpoint_descriptor* interrupt;
+
+ // Die Pipes zu diesen Endpunkten, ip darf NULL sein
+ struct usb_pipe* bip;
+ struct usb_pipe* bop;
+ struct usb_pipe* ip;
+};
+
+
+// Sendet einen SCSI-Befehl
+int msd_cbi_issue_scsi_cmd(struct msc_gen_dev* dev, const void* buffer,
+ size_t cmd_length, bool receive, size_t req_length);
+// Sendet Daten zum Gerät
+int msd_cbi_send(struct msc_gen_dev* dev, const void* buffer, size_t size);
+// Empfängt Daten vom Gerät
+int msd_cbi_recv(struct msc_gen_dev* dev, void* buffer, size_t size);
+
+#endif
diff --git a/src/modules/usb/msd/msd.h b/src/modules/usb/msd/msd.h
new file mode 100644
index 0000000..892b207
--- /dev/null
+++ b/src/modules/usb/msd/msd.h
@@ -0,0 +1,146 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef MSD_H
+#define MSD_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "usb-ddrv.h"
+
+// Beschreibt eine LUN eines MSC-Geräts (MSD) im Allgemeinen
+struct msc_gen_dev {
+ // LUN
+ int lun;
+
+ // Größe eines Blocks
+ uint64_t block_size;
+ // Anzahl Blöcke
+ uint64_t blocks;
+
+ /**
+ * Führt einen SCSI-Befehl aus.
+ *
+ * @param dev Zielgerät
+ * @param cmd_buffer Speicherbereich, der den Befehl enthält
+ * @param cmd_length Länge dieses Befehls in Byte
+ * @param receive true, wenn empfangen werden soll
+ * @param req_length Länge der zu übertragenden Daten
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+ int (*issue_scsi_cmd)(struct msc_gen_dev* dev, const void* cmd_buffer,
+ size_t cmd_length, bool receive, size_t req_length);
+
+ /**
+ * Sendet Daten zu einem Gerät.
+ *
+ * @param dev Zielgerät
+ * @param buffer Speicherbereich, der die Daten enthält
+ * @param size Anzahl der zu sendenden Bytes
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+ int (*send)(struct msc_gen_dev* dev, const void* buffer, size_t size);
+
+ /**
+ * Empfängt Daten von einem Gerät.
+ *
+ * @param dev Quellgerät
+ * @param buffer Speicherbereich, in den die Daten gelesen werden sollen
+ * @param size Anzahl der zu empfangenden Bytes
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+ int (*recv)(struct msc_gen_dev* dev, void* buffer, size_t size);
+};
+
+/**
+ * Wird von einem RPC-Handler aufgerufen, sobald ein neues MSD gefunden wurde.
+ *
+ * @param dev Neues Gerät
+ *
+ * @return 1 bei Erfolg, sonst 0
+ */
+int got_msd(struct usb_prov_dev* dev);
+
+/**
+ * Initialisiert das LostIO-Interface.
+ */
+void init_lostio_interface(void);
+
+/**
+ * Initialisiert das RPC-Interface.
+ */
+void init_rpc_interface(void);
+
+/**
+ * Initialisiert ein MSD auf SCSI-Ebene.
+ *
+ * @param dev Das MSD
+ * @param blocks Pointer zu einer Variable, in die die Anzahl der vorhandenen
+ * Blöcke geschrieben wird
+ * @param bsize Pointer zu einer Variable, in die die Größe eines Blocks
+ * geschrieben wird
+ *
+ * @return 1 bei Erfolg, sonst 0
+ */
+int msd_scsi_init(struct msc_gen_dev* dev, uint64_t* blocks,
+ uint64_t* bsize);
+
+/**
+ * Liest von einem MSD per SCSI.
+ *
+ * @param dev Das MSD
+ * @param start_lba LBA des ersten zu lesenden Blocks
+ * @param dest Zielspeicherbereich
+ * @param blocks Anzahl der zu lesenden Blöcke
+ *
+ * @return Anzahl der gelesenen Bytes
+ */
+size_t msd_scsi_read(struct msc_gen_dev* dev, uint64_t start_lba, void* dest,
+ uint64_t blocks);
+
+/**
+ * Wird von einer MSD-spezifischen Initialisierungsroutine aufgerufen, um ein
+ * für die SCSI-Initialisierung vorbereitetes MSD bereitzustellen.
+ *
+ * @param dev Das neue Gerät
+ */
+void provide_msd(struct msc_gen_dev* dev);
+
+/**
+ * Registriert diesen Treiber beim USB-Bustreiber.
+ */
+void register_msddrv(void);
+
+#endif
diff --git a/src/modules/usb/msd/rpc.c b/src/modules/usb/msd/rpc.c
new file mode 100644
index 0000000..ae48d68
--- /dev/null
+++ b/src/modules/usb/msd/rpc.c
@@ -0,0 +1,83 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <ports.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+#include "usb-server.h"
+
+extern pid_t usb_pid;
+
+void msd_got_device_handler(pid_t src, uint32_t corr_id, size_t length,
+ void* data)
+{
+ struct usb_prov_dev* pd;
+
+ if (length < sizeof(*pd)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ pd = malloc(sizeof(*pd));
+ memcpy(pd, data, sizeof(*pd));
+
+ rpc_send_int_response(src, corr_id, got_msd(pd));
+}
+
+void init_rpc_interface(void)
+{
+ register_message_handler(RPC_USB_DDRV_PLUG_FNN, &msd_got_device_handler);
+}
+
+void register_msddrv(void)
+{
+ struct usb_handle_devs hd = {
+ .vendor_id = -1,
+ .device_id = -1,
+ .class = 8, // MSC
+ .subclass = -1,
+ .protocol = -1
+ };
+
+ if (!rpc_get_int(usb_pid, RPC_USB_SV_REGDD_FNN, sizeof(hd), (char*)&hd)) {
+ fprintf(stderr, "Could not register USB MSD driver.\n");
+ }
+}
diff --git a/src/modules/usb/msd/scsi.c b/src/modules/usb/msd/scsi.c
new file mode 100644
index 0000000..5a4e007
--- /dev/null
+++ b/src/modules/usb/msd/scsi.c
@@ -0,0 +1,240 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "msd.h"
+#include "scsi.h"
+
+const char *dev_type[] =
+{
+ "magnetic disk",
+ "magnetic tape",
+ "printer",
+ "processor",
+ "write-once device",
+ "CD-ROM",
+ "scanner",
+ "optical medium",
+ "medium changer",
+ "communications device",
+ "?",
+ "?",
+ "RAID",
+ "enclosure services device",
+ "magnetic disk (simplified)",
+ "card reader/writer (optical)",
+ "?",
+ "object-based storage",
+ "automation/drive interface",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "well known LUN",
+ "?"
+};
+
+static int do_pkt(struct msc_gen_dev* dev, int receive, void* buffer1,
+ size_t length1, void* buffer2, size_t length2)
+{
+ while (dev->issue_scsi_cmd(dev, buffer1, length1, !!(receive == 1),
+ length2))
+ {
+ struct scsi_sense sense;
+ struct scsi_cmd_request_sense req_sense = {
+ .cmd = {
+ .operation = SCSI_REQUEST_SENSE
+ },
+ .alloc_len = sizeof(sense),
+ .lun = dev->lun
+ };
+
+ if (dev->issue_scsi_cmd(dev, &req_sense, sizeof(req_sense), true,
+ sizeof(sense)))
+ {
+ fprintf(stderr, "[usb-msd] Could not request sense\n");
+ return -1;
+ }
+
+ if (dev->recv(dev, &sense, sizeof(sense))) {
+ fprintf(stderr, "[usb-msd] Could not sense\n");
+ return -1;
+ }
+ }
+
+ if (receive == 1) {
+ return dev->recv(dev, buffer2, length2);
+ } else if (!receive) {
+ return dev->send(dev, buffer2, length2);
+ }
+
+ return 0;
+}
+
+int msd_scsi_init(struct msc_gen_dev* dev, uint64_t* blocks, uint64_t* bsize)
+{
+ struct scsi_inq_answer inq_ans;
+ struct scsi_cmd_inquiry inq = {
+ .cmd = {
+ .operation = SCSI_INQUIRY
+ },
+ .alloc_len = htobe16(sizeof(inq_ans)),
+ .lun = dev->lun
+ };
+
+ if (do_pkt(dev, 1, &inq, sizeof(inq), &inq_ans, sizeof(inq_ans))) {
+ return 0;
+ }
+
+ printf("[usb-msd] LUN %i: %s, ", dev->lun, dev_type[inq_ans.dev_type]);
+
+ int last;
+ for (last = (int)sizeof(inq_ans.vendor) - 1; last >= 0; last--) {
+ if (inq_ans.vendor[last] != ' ') {
+ break;
+ }
+ }
+
+ last++;
+
+ int i;
+
+ if (last) {
+ for (i = 0; i < last; i++) {
+ printf("%c", inq_ans.vendor[i]);
+ }
+ printf(" ");
+ }
+
+
+ for (last = (int)sizeof(inq_ans.product) - 1; last >= 0; last--) {
+ if (inq_ans.product[last] != ' ') {
+ break;
+ }
+ }
+
+ last++;
+
+ for (i = 0; i < last; i++) {
+ printf("%c", inq_ans.product[i]);
+ }
+ printf("\n");
+
+ // Erklär mir mal einer, wieso man das braucht
+ // I'd appreciate any explanation why this is required
+ int8_t zero[6] = { 0 };
+ if (do_pkt(dev, -1, &zero, sizeof(zero), NULL, 0)) {
+ return 0;
+ }
+
+ uint32_t cap_ans[2];
+ struct scsi_cmd_read_capacity cap = {
+ .cmd = {
+ .operation = SCSI_READ_CAPACITY
+ }
+ };
+
+ if (do_pkt(dev, 1, &cap, sizeof(cap), &cap_ans, sizeof(cap_ans))) {
+ return 0;
+ }
+
+ *blocks = (uint64_t)betoh32(cap_ans[0]) + 1LL;
+ *bsize = betoh32(cap_ans[1]);
+
+ return 1;
+}
+
+#define SCSI_READ 10
+
+size_t msd_scsi_read(struct msc_gen_dev* dev, uint64_t start_lba, void* dest,
+ uint64_t blocks)
+{
+ #if SCSI_READ == 10
+ struct scsi_cmd_read10 r10 = {
+ .cmd = {
+ .operation = SCSI_READ10
+ },
+ .lun = dev->lun,
+ .lba = htobe32(start_lba),
+ .length = htobe16(blocks)
+ };
+ #elif SCSI_READ == 6
+ struct scsi_cmd_read6 r6 = {
+ .cmd = {
+ .operation = SCSI_READ6
+ },
+ .lun = dev->lun,
+ .lba_lo = htobe16(start_lba),
+ .lba_hi = start_lba >> 16,
+ .length = blocks
+ };
+ #else
+ struct scsi_cmd_read12 r12 = {
+ .cmd = {
+ .operation = SCSI_READ12
+ },
+ .lun = dev->lun,
+ .lba = htobe32(start_lba),
+ .length = htobe32(blocks)
+ };
+ #endif
+
+ #if SCSI_READ == 10
+ if ((start_lba >> 32) || (blocks >> 16)) {
+ #elif SCSI_READ == 6
+ if ((start_lba >> 21) || (blocks >> 8)) {
+ #else
+ if ((start_lba >> 32) || (blocks >> 32)) {
+ #endif
+ return 0;
+ }
+
+ #if SCSI_READ == 10
+ int ret = do_pkt(dev, 1, &r10, sizeof(r10), dest, blocks * dev->block_size);
+ #elif SCSI_READ == 6
+ int ret = do_pkt(dev, 1, &r6, sizeof(r6), dest, blocks * dev->block_size);
+ #else
+ int ret = do_pkt(dev, 1, &r12, sizeof(r12), dest, blocks * dev->block_size);
+ #endif
+
+ if (ret < 0) {
+ return 0;
+ }
+ return blocks * dev->block_size;
+}
diff --git a/src/modules/usb/msd/scsi.h b/src/modules/usb/msd/scsi.h
new file mode 100644
index 0000000..98b88f9
--- /dev/null
+++ b/src/modules/usb/msd/scsi.h
@@ -0,0 +1,219 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef SCSI_H
+#define SCSI_H
+
+#include <stdint.h>
+#include <arpa/inet.h>
+
+// Funktionen zum Konvertieren von/zu Big Endian
+#define htobe16(val) htons(val)
+#define htobe32(val) htonl(val)
+#define betoh16(val) htobe16(val)
+#define betoh32(val) htobe32(val)
+
+// SCSI-Befehlscodes
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_READ6 0x08
+#define SCSI_INQUIRY 0x12
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ10 0x28
+#define SCSI_WRITE10 0x2A
+#define SCSI_READ12 0xA8
+
+// Minimaler SCSI-Befehl
+struct scsi_cmd {
+ // Befehlscode
+ uint8_t operation;
+} __attribute__((packed));
+
+// REQUEST SENSE
+// Gibt Informationen im Fehlerfall zurück.
+struct scsi_cmd_request_sense {
+ struct scsi_cmd cmd;
+ unsigned rsvd1 : 5;
+ // LUN
+ unsigned lun : 3;
+ uint16_t rsvd2;
+ // Anzahl der Bytes, die der Host zu empfangen bereit ist
+ uint8_t alloc_len;
+ uint8_t control;
+} __attribute__((packed));
+
+// INQUIRY
+// Gibt Informationen zum Gerät zurück.
+struct scsi_cmd_inquiry {
+ struct scsi_cmd cmd;
+ unsigned evpd : 1;
+ unsigned rsvd : 4;
+ // LUN
+ unsigned lun : 3;
+ uint8_t page;
+ // Anzahl der Bytes, die der Host zu empfangen bereit ist
+ uint16_t alloc_len;
+ uint8_t control;
+} __attribute__((packed));
+
+// READ CAPACITY
+// Gibt die LBA des letzten Blocks zurück sowie die Blockgröße
+struct scsi_cmd_read_capacity {
+ struct scsi_cmd cmd;
+ unsigned reladdr : 1;
+ unsigned rsvd1 : 4;
+ // LUN
+ unsigned lun : 3;
+ uint32_t lba;
+ uint32_t rsvd2;
+} __attribute__((packed));
+
+// READ6
+// Liest Daten
+struct scsi_cmd_read6 {
+ struct scsi_cmd cmd;
+ // Höherwertiger Teil der LBA
+ unsigned lba_hi : 5;
+ // LUN
+ unsigned lun : 3;
+ // Niederwertiger Teil der LBA
+ uint16_t lba_lo;
+ // Anzahl zu lesende Blöcke
+ uint8_t length;
+ uint8_t control;
+} __attribute__((packed));
+
+// READ10
+// Liest Daten
+struct scsi_cmd_read10 {
+ struct scsi_cmd cmd;
+ unsigned reladdr : 1;
+ unsigned rsvd1 : 2;
+ unsigned fua : 1;
+ unsigned dpo : 1;
+ // LUN
+ unsigned lun : 3;
+ // LBA
+ uint32_t lba;
+ uint8_t rsvd2;
+ // Anzahl zu lesende Blöcke
+ uint16_t length;
+ uint8_t control;
+} __attribute__((packed));
+
+// READ12
+// Liest Daten
+struct scsi_cmd_read12 {
+ struct scsi_cmd cmd;
+ unsigned reladdr : 1;
+ unsigned rsvd1 : 2;
+ unsigned fua : 1;
+ unsigned dpo : 1;
+ // LUN
+ unsigned lun : 3;
+ // LBA
+ uint32_t lba;
+ // Anzahl zu lesende Blöcke
+ uint32_t length;
+ uint16_t rsvd2;
+} __attribute__((packed));
+
+// WRITE10
+// Schreibt Daten
+struct scsi_cmd_write10 {
+ struct scsi_cmd cmd;
+ unsigned reladdr : 1;
+ unsigned rsvd1 : 1;
+ unsigned ebp : 1;
+ unsigned fua : 1;
+ unsigned dpo : 1;
+ // LUN
+ unsigned lun : 3;
+ // LBA
+ uint32_t lba;
+ uint8_t rsvd2;
+ // Anzahl zu lesende Blöcke
+ uint16_t length;
+ uint8_t control;
+} __attribute__((packed));
+
+// Rückgabestruktur von SCSI SENSE
+struct scsi_sense {
+ unsigned resp_code : 7;
+ unsigned valid : 1;
+ uint8_t segment;
+ unsigned sense_key : 4;
+ unsigned rsvd1 : 1;
+ unsigned ili : 1;
+ unsigned eom : 1;
+ unsigned filemark : 1;
+ uint32_t information;
+ uint8_t add_sense_length;
+ uint32_t cmd_spec_info;
+ uint8_t add_sense_code;
+ uint8_t add_sense_code_qual;
+ uint8_t field_replacable_unit_code;
+ unsigned sense_key_spec1 : 7;
+ unsigned sksv : 1;
+ uint8_t sense_key_spec2;
+ uint8_t sense_key_spec3;
+} __attribute__((packed));
+
+// Rückgabestruktur von SCSI INQUIRY
+struct scsi_inq_answer {
+ // Gerätetype
+ unsigned dev_type : 5;
+ unsigned qualifier : 3;
+ unsigned type_mod : 7;
+ unsigned rmb : 1;
+ unsigned ansi_version : 3;
+ unsigned ecma_version : 3;
+ unsigned iso_version : 2;
+ unsigned resp_data_format : 4;
+ unsigned rsvd1 : 2;
+ unsigned trm_iop : 1;
+ unsigned aec : 1;
+ uint8_t add_length;
+ uint16_t rsvd2;
+ unsigned soft_rst : 1;
+ unsigned cmd_queue : 1;
+ unsigned rsvd3 : 1;
+ unsigned linked : 1;
+ unsigned sync : 1;
+ unsigned wbus16 : 1;
+ unsigned wbus32 : 1;
+ unsigned rel_adr : 1;
+ // Herstellername
+ char vendor[8];
+ // Produktname
+ char product[16];
+ uint32_t revision;
+} __attribute__((packed));
+
+#endif
diff --git a/src/modules/usb/msd/usb-lib.c b/src/modules/usb/msd/usb-lib.c
new file mode 100644
index 0000000..fe4eb69
--- /dev/null
+++ b/src/modules/usb/msd/usb-lib.c
@@ -0,0 +1,207 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+pid_t usb_pid;
+
+int usb_get_number_of_endpoints(struct usb_prov_dev* dev)
+{
+ struct usb_devctrl_gne rq = {
+ .req = {
+ .type = USB_DC_NUM_ENDPOINTS
+ },
+ .dev = *dev
+ };
+
+ return rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(rq), (char*)&rq);
+}
+
+int usb_get_interface_id(struct usb_prov_dev* dev)
+{
+ struct usb_devctrl_gii giid = {
+ .req = {
+ .type = USB_DC_GET_IFC_ID
+ },
+ .dev = *dev
+ };
+
+ return rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(giid),
+ (char*)&giid);
+}
+
+void usb_get_endpoint_info(struct usb_prov_dev* dev, int ep_number,
+ struct usb_endpoint_descriptor* ep_desc)
+{
+ struct usb_devctrl_gep gep = {
+ .req = {
+ .type = USB_DC_GET_ENDPOINT
+ },
+ .dev = *dev,
+ .ep_number = ep_number
+ };
+
+ response_t* r = rpc_get_response(usb_pid, RPC_USB_SV_DEVCT_FNN,
+ sizeof(gep), (char*)&gep);
+
+ memcpy(ep_desc, r->data, sizeof(*ep_desc));
+ free(r->data);
+ free(r);
+}
+
+void usb_create_pipe(struct usb_prov_dev* dev, int ep_number,
+ struct usb_pipe* pipe)
+{
+ struct usb_devctrl_gpp gp = {
+ .req = {
+ .type = USB_DC_GET_PIPE
+ },
+ .dev = *dev,
+ .ep_number = ep_number
+ };
+
+ response_t* r = rpc_get_response(usb_pid, RPC_USB_SV_DEVCT_FNN,
+ sizeof(gp), (char*)&gp);
+
+ memcpy(pipe, r->data, sizeof(*pipe));
+ free(r->data);
+ free(r);
+}
+
+int usb_control_transfer(struct usb_prov_dev* dev, struct usb_pipe* pipe,
+ struct usb_setup_packet* setup, void* buffer)
+{
+ uint32_t shm = 0;
+ void* shm_addr = NULL;
+
+ if (setup->length) {
+ shm = create_shared_memory(setup->length);
+ shm_addr = open_shared_memory(shm);
+
+ if ((buffer != NULL) && !(setup->type & USB_SETUP_IN)) {
+ memcpy(shm_addr, buffer, setup->length);
+ }
+ }
+
+ struct usb_devctrl_tct tctrq = {
+ .req = {
+ .type = USB_DC_TRSF_CONTROL
+ },
+ .setup = *setup,
+ .shm = shm
+ };
+
+ if (pipe != NULL) {
+ tctrq.dst.pipe = *pipe;
+ tctrq.ep0 = false;
+ } else {
+ tctrq.dst.dev_id = dev->dev_id;
+ tctrq.ep0 = true;
+ }
+
+ int ret = rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(tctrq),
+ (char*)&tctrq);
+
+ if (setup->length && (buffer != NULL) && (setup->type & USB_SETUP_IN)) {
+ memcpy(buffer, shm_addr, setup->length);
+ }
+
+ if (shm_addr != NULL) {
+ close_shared_memory(shm);
+ }
+
+ return ret;
+}
+
+int usb_bulk_transfer(struct usb_pipe* pipe, void* buffer, size_t length,
+ bool receive)
+{
+ uint32_t shm = 0;
+ void* shm_addr = NULL;
+
+ if (length) {
+ shm = create_shared_memory(length);
+ shm_addr = open_shared_memory(shm);
+
+ if ((buffer != NULL) && !receive) {
+ memcpy(shm_addr, buffer, length);
+ }
+ }
+
+ struct usb_devctrl_tbk tbkrq = {
+ .req = {
+ .type = USB_DC_TRSF_BULK
+ },
+ .pipe = *pipe,
+ .length = length,
+ .shm = shm
+ };
+
+ int ret = rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(tbkrq),
+ (char*)&tbkrq);
+
+ if (length && (buffer != NULL) && receive) {
+ memcpy(buffer, shm_addr, length);
+ }
+
+ if (shm_addr != NULL) {
+ close_shared_memory(shm);
+ }
+
+ if (ret >= 0) {
+ pipe->trs.toggle = ret;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+void usb_clear_halt(struct usb_pipe* pipe)
+{
+ struct usb_devctrl_clh clh = {
+ .req = {
+ .type = USB_DC_CLEAR_HALT
+ },
+ .pipe = *pipe
+ };
+
+ rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(clh), (char*)&clh);
+}
diff --git a/src/modules/usb/msd/usb-lib.h b/src/modules/usb/msd/usb-lib.h
new file mode 100644
index 0000000..2f7fb9b
--- /dev/null
+++ b/src/modules/usb/msd/usb-lib.h
@@ -0,0 +1,124 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_LIB_H
+#define USB_LIB_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+/*
+ * Hinweis: Wenn hier die Rede von einem USB-Gerät ist, so ist ein logisches
+ * USB-Gerät gemeint. Dies kann sowohl ein echtes (physisches) Gerät sein oder
+ * aber auch nur ein Interface dieses Geräts (meistens letzteres, da so gut
+ * wie alle USB-Geräteklassen auf Interfaceebene arbeiten und somit die meisten
+ * physischen USB-Geräte genau ein Interface besitzen).
+ */
+
+/**
+ * Führt einen USB-Bulktransfer durch.
+ *
+ * @param pipe Zu verwendende Pipe
+ * @param buffer Zu bearbeitender Speicherbereich
+ * @param length Länge des Transfers
+ * @param receive true, wenn empfangen werden soll, sonst false.
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_bulk_transfer(struct usb_pipe* pipe, void* buffer, size_t length,
+ bool receive);
+
+/**
+ * Entstallt einen Endpunkt.
+ *
+ * @param pipe Eine zum Endpunkt gehörige Pipe.
+ */
+void usb_clear_halt(struct usb_pipe* pipe);
+
+/**
+ * Führt einen USB-Controltransfer durch.
+ *
+ * @param dev Gerät
+ * @param pipe Zu verwendende Pipe oder NULL für die Default Control Pipe
+ * @param setup SETUP-Paket
+ * @param buffer Speicherbereich für die Datenphase
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_control_transfer(struct usb_prov_dev* dev, struct usb_pipe* pipe,
+ struct usb_setup_packet* setup, void* buffer);
+
+/**
+ * Erstellt eine USB-Pipe.
+ *
+ * @param dev Zielgerät
+ * @param ep_number Nummer des Zielendpunkts (Nummer innerhalb des Interfaces,
+ * nicht ID!)
+ * @param pipe Speicherbereich, in dem die Daten der Pipe abgelegt werden
+ * sollen.
+ */
+void usb_create_pipe(struct usb_prov_dev* dev, int ep_number,
+ struct usb_pipe* pipe);
+
+/**
+ * Empfängt Informationen zu einem Endpunkt.
+ *
+ * @param dev Gerät
+ * @param ep_number Nummer des Endpunkts
+ * @param ep_desc Pointer zu einem Speicherbereich, der einen Endpoint-
+ * Descriptor aufnehmen kann.
+ */
+void usb_get_endpoint_info(struct usb_prov_dev* dev, int ep_number,
+ struct usb_endpoint_descriptor* ep_desc);
+
+/**
+ * Gibt die Interface-ID des logischen USB-Geräts zurück.
+ *
+ * @param dev Gerät
+ *
+ * @return Interface-ID
+ */
+int usb_get_interface_id(struct usb_prov_dev* dev);
+
+/**
+ * Gibt die Anzahl an Endpunkten des USB-Geräts zurück.
+ *
+ * @param dev Logisches Gerät
+ *
+ * @return Anzahl Endpunkte
+ */
+int usb_get_number_of_endpoints(struct usb_prov_dev* dev);
+
+#endif
diff --git a/src/modules/usb/uhci/Makefile.all b/src/modules/usb/uhci/Makefile.all
new file mode 100644
index 0000000..d0d0f5c
--- /dev/null
+++ b/src/modules/usb/uhci/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD $1/modules/uhci"
+$LOST_TOOLS_LD $LDSCRIPT -ouhci.mod *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s uhci.mod -o $1/modules/uhci
diff --git a/src/modules/usb/uhci/ctrl.c b/src/modules/usb/uhci/ctrl.c
new file mode 100644
index 0000000..ad1c3a0
--- /dev/null
+++ b/src/modules/usb/uhci/ctrl.c
@@ -0,0 +1,96 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <ports.h>
+#include <sleep.h>
+
+#include "uhci.h"
+#include "usb-hub.h"
+
+void uhci_reset_port(struct uhci* hc, int port)
+{
+ if (hc == NULL)
+ return;
+
+ outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_RESET | RPORT_CSC);
+ msleep(50);
+ uhci_set_port_status(hc, port, 1);
+ msleep(10);
+}
+
+int uhci_scan_port(struct uhci* hc, int port)
+{
+ int ret;
+
+ if (hc == NULL)
+ return 0;
+
+ uint_fast16_t val = inw(hc->iobase + UHCI_RPORTS + port * 2);
+
+ if (!(val & RPORT_DEVICE)) {
+ ret = 0;
+ } else {
+ ret = USB_HUB_DEVICE;
+ if (val & RPORT_LOSPD) {
+ ret |= USB_HUB_LOW_SPEED;
+ } else {
+ ret |= USB_HUB_FULL_SPEED;
+ }
+
+ if (val & RPORT_CSC) {
+ ret |= USB_HUB_CHANGE;
+ outw(hc->iobase + UHCI_RPORTS + port * 2, (val & RPORT_ENABLE) | RPORT_CSC);
+ }
+ }
+
+ return ret;
+}
+
+void uhci_set_port_status(struct uhci* hc, int port, int status)
+{
+ if (hc == NULL)
+ return;
+
+ int previous = inw(hc->iobase + UHCI_RPORTS + port * 2) & RPORT_ENABLE;
+ outw(hc->iobase + UHCI_RPORTS + port * 2, (status ? RPORT_ENABLE : 0) | RPORT_CSC);
+ msleep(50);
+ if (status && !previous)
+ {
+ outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_RESUME);
+ msleep(20);
+ outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_CSC);
+ msleep(10);
+ }
+}
diff --git a/src/modules/usb/uhci/init.c b/src/modules/usb/uhci/init.c
new file mode 100644
index 0000000..7a4d6f6
--- /dev/null
+++ b/src/modules/usb/uhci/init.c
@@ -0,0 +1,265 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <pci.h>
+#include <ports.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "uhci.h"
+
+extern pid_t usb_pid, pci_pid;
+
+
+extern struct uhci* uhcis[IRQ_COUNT];
+extern void uhci_irq_handler(uint8_t irq);
+
+static uint16_t pci_inw(struct pci_device* dev, int reg)
+{
+ struct pci_config_space_access csa = {
+ .type = PCI_CSA_READ16,
+ .bus = dev->bus,
+ .device = dev->device,
+ .function = dev->function,
+ .reg = reg
+ };
+
+ return rpc_get_dword(pci_pid, RPC_PCI_CONFIG_SPACE_ACCESS, sizeof(csa),
+ (char*)&csa);
+}
+
+static void pci_outw(struct pci_device* dev, int reg, uint16_t val)
+{
+ struct pci_config_space_access csa = {
+ .type = PCI_CSA_WRITE16,
+ .bus = dev->bus,
+ .device = dev->device,
+ .function = dev->function,
+ .reg = reg,
+ .value = val
+ };
+
+ rpc_get_dword(pci_pid, RPC_PCI_CONFIG_SPACE_ACCESS, sizeof(csa),
+ (char*)&csa);
+}
+
+void init_uhc(struct pci_device* dev, size_t devlen)
+{
+ devlen -= sizeof(*dev);
+ int8_t* data = (int8_t*)(dev + 1);
+
+ struct pci_resource pres;
+ uint16_t iobase = 0, iosize = 0;
+
+ while (devlen >= sizeof(pres)) {
+ memcpy(&pres, data, sizeof(pres));
+
+ devlen -= sizeof(pres);
+ data += sizeof(pres);
+
+ if (pres.type == PCI_RESOURCE_PORT) {
+ iobase = pres.start;
+ iosize = pres.length;
+ break;
+ }
+ }
+
+ if (!iobase) {
+ return;
+ }
+
+ struct uhci* ndev = calloc(1, sizeof(*ndev));
+ ndev->pci = dev;
+ ndev->iobase = iobase;
+ ndev->rh = calloc(1, sizeof(*ndev->rh));
+
+ ndev->rh->ports = (iosize - 0x10) >> 1;
+
+ request_ports(iobase, iosize);
+ uhcis[dev->irq] = ndev;
+ register_intr_handler(TYNDUR_IRQ_OFFSET + dev->irq, &uhci_irq_handler);
+
+ outw(iobase + UHCI_USBCMD, GRESET);
+ msleep(50);
+ outw(iobase + UHCI_USBCMD, 0);
+
+ int i;
+ for (i = 2; i < ndev->rh->ports; i++) {
+ if (!(inw(iobase + UHCI_RPORTS + i*2) & 0x0080) ||
+ (inw(iobase + UHCI_RPORTS + i*2) == 0xFFFF))
+ {
+ // Ungültige Werte für einen Rootport, also ist das hier keiner
+ ndev->rh->ports = i;
+ break;
+ }
+ }
+
+ // Mehr als sieben Rootports sind leicht ungewöhnlich
+ if (ndev->rh->ports > 7) {
+ ndev->rh->ports = 2;
+ }
+
+ int legsup = pci_inw(dev, UHCI_PCI_LEGSUP);
+ int cmd = inw(iobase + UHCI_USBCMD);
+ int intr = inw(iobase + UHCI_USBINTR);
+
+ if ((legsup &
+ ~(UHCI_LEGSUP_STATUS | UHCI_LEGSUP_NO_CHG | UHCI_LEGSUP_PIRQ)) ||
+ (cmd & USB_RUN) || (cmd & CONFIGURE) || !(cmd & GLOB_SUSP_MODE) ||
+ (intr & 0x000F))
+ {
+ // Damit uns nicht die IRQs um die Ohren fliegen
+ outw(iobase + UHCI_USBSTS, 0x3F);
+
+ // Einen Frame abwarten
+ msleep(1);
+
+ // Alle LEGSUP-Statusbits löschen
+ pci_outw(dev, UHCI_PCI_LEGSUP, UHCI_LEGSUP_STATUS);
+
+ // Resetten
+ outw(iobase + UHCI_USBCMD, HCRESET);
+ // Ende des Resets abwarten
+ for (i = 0; (inw(iobase + UHCI_USBCMD) & HCRESET) && (i < 50); i++) {
+ msleep(10);
+ }
+
+ // Interrupts erstmal deaktivieren
+ outw(iobase + UHCI_USBINTR, 0);
+ // Den gesamten HC ebenso
+ outw(iobase + UHCI_USBCMD, 0);
+
+ // Alle Ports "runterfahren"
+ for (i = 0; i < ndev->rh->ports; i++) {
+ outw(iobase + UHCI_RPORTS + i * 2, 0);
+ }
+ }
+
+ ndev->frame_list = mem_allocate(4096, 0);
+ assert(ndev->frame_list);
+ ndev->p_frame_list = (uintptr_t)get_phys_addr(ndev->frame_list);
+ assert(ndev->p_frame_list);
+ ndev->frame_list_lock = 0;
+
+ ndev->queue_head = mem_allocate(sizeof(*ndev->queue_head), 0);
+ assert(ndev->queue_head);
+ ndev->p_queue_head = (uintptr_t)get_phys_addr(ndev->queue_head);
+ assert(ndev->p_queue_head);
+ ndev->queue_head_lock = 0;
+
+ // Alle Pointer auf "invalid" setzen
+ ndev->queue_head->next = 1;
+ ndev->queue_head->transfer = 1;
+ ndev->queue_head->q_first = NULL;
+ ndev->queue_head->q_last = NULL;
+
+ for (i = 0; i < 1024; i++) {
+ ndev->frame_list[i] = ndev->p_queue_head | 2;
+ }
+
+ // Alle 1000 µs ein Frame (Standardwert)
+ outb(iobase + UHCI_SOFMOD, 0x40);
+ // Unsere Frameliste eintragen
+ outl(iobase + UHCI_FRBASEADD, ndev->p_frame_list);
+ // Framenummer zurücksetzen
+ outw(iobase + UHCI_FRNUM, 0);
+
+ // Hier setzen wir das PIRQ-Bit und deaktivieren sämtlichen Legacy Support
+ pci_outw(dev, UHCI_PCI_LEGSUP, UHCI_LEGSUP_PIRQ);
+
+ // HC starten
+ outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP);
+ // Alle Interrupts aktivieren
+ outw(iobase + UHCI_USBINTR, 0xF);
+
+ // Connect-Status-Change-Bit zurücksetzen
+ for (i = 0; i < ndev->rh->ports; i++) {
+ outw(iobase + UHCI_RPORTS + i * 2, RPORT_CSC);
+ }
+
+ // Resumesignal treiben (egal, obs was bringt)
+ outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP | FORCE_GRESUME);
+ msleep(20);
+ outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP);
+ msleep(100);
+
+ register_uhci(ndev);
+}
+
+int check_pci(void)
+{
+ struct init_dev_desc* devs;
+
+ int ret = init_dev_list(&devs);
+ if (ret < 0) {
+ return 0;
+ }
+
+ int got_something = 0;
+
+ int8_t* data = (int8_t*)devs;
+ for (;;) {
+ size_t size;
+
+ if (ret < sizeof(*devs)) {
+ break;
+ }
+
+ devs = (struct init_dev_desc*)data;
+ size = sizeof(*devs) + devs->bus_data_size;
+ if (ret < size) {
+ break;
+ }
+
+ if (devs->type == 10) {
+ struct pci_device* dev = (struct pci_device*)devs->bus_data;
+ if ((dev->class_id == 0x0C) && (dev->subclass_id == 0x03) &&
+ (dev->interface_id == 0x00))
+ {
+ got_something = 1;
+ init_uhc(dev, size);
+ }
+ }
+
+ ret -= size;
+ data += size;
+ }
+
+ return got_something;
+}
diff --git a/src/modules/usb/uhci/main.c b/src/modules/usb/uhci/main.c
new file mode 100644
index 0000000..452f2ad
--- /dev/null
+++ b/src/modules/usb/uhci/main.c
@@ -0,0 +1,73 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "uhci.h"
+
+extern pid_t usb_pid, pci_pid;
+
+int main(void)
+{
+ init_messaging();
+
+ // Warten, damit dieser Prozess nach usb1 (und möglichst nach usb-msd)
+ // weiterläuft, sollten diese Treiber gleichzeitig gestartet werden
+ // (z. B. Bootvorgang)
+ msleep(2000);
+
+ usb_pid = init_service_get("usb1");
+ if (!usb_pid) {
+ fprintf(stderr, "You need to start the usb1 driver first.\n");
+ return 1;
+ }
+
+ pci_pid = init_service_get("pci");
+ if (!pci_pid) {
+ fprintf(stderr, "You need to start the pci driver first.\n");
+ return 1;
+ }
+
+ init_rpc_interface();
+
+ if (!check_pci()) {
+ return 0;
+ }
+
+ for (;;) {
+ wait_for_rpc();
+ }
+}
diff --git a/src/modules/usb/uhci/rpc.c b/src/modules/usb/uhci/rpc.c
new file mode 100644
index 0000000..e3f862e
--- /dev/null
+++ b/src/modules/usb/uhci/rpc.c
@@ -0,0 +1,297 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <ports.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "uhci.h"
+#include "usb-hc.h"
+#include "usb-server.h"
+
+// #define DEBUG
+// #define SHOW_ERRORS
+
+pid_t usb_pid, pci_pid;
+
+struct uhci* uhcis[IRQ_COUNT] = { NULL };
+
+void uhci_irq_handler(uint8_t irq)
+{
+ if ((irq < TYNDUR_IRQ_OFFSET) || (irq >= TYNDUR_IRQ_OFFSET + IRQ_COUNT)) {
+ return;
+ }
+
+ struct uhci* hc = uhcis[irq - TYNDUR_IRQ_OFFSET];
+
+ int status = inw(hc->iobase + UHCI_USBSTS);
+
+ if (!status) {
+ return;
+ }
+
+ if ((status & 0x10) || (status & 0x08)) {
+ fprintf(stderr, "[uhci] SERIOUS HOST ERROR CONDITION (STS: 0x%02X)\n", status);
+ return;
+ }
+
+ if (status & 0x20) {
+ fprintf(stderr, "[uhci] Erm, wtf. HC halted...\n");
+ return;
+ }
+
+ if (status & ~0x03) {
+ return;
+ }
+
+ struct uhci_td *td, *ntd;
+
+ lock(&hc->queue_head_lock);
+
+ td = (struct uhci_td*)hc->queue_head->q_first;
+
+ while (td != NULL) {
+ /*
+ #ifdef DEBUG
+ printf("Active: %i (next: 0x%08X)\n", td->flags.bits.active, td->next);
+ #endif
+ */
+ if (td->flags.bits.active) {
+ if (td->active_count--) {
+ break;
+ } else {
+ #ifdef DEBUG
+ printf("Active timeout on 0x%08X/0x%08X, QH -> 0x%08X/0x%08X\n",
+ td, td->ptd, hc->queue_head->q_first,
+ hc->queue_head->transfer);
+ #endif
+ td->flags.bits.active = 0;
+ }
+ }
+
+ #ifdef DEBUG
+ printf("Finished td %s %i:%i, flags: 0x%08X\n",
+ (td->pid == 0x69) ? "from" : "to", td->addr, td->ep,
+ td->flags.flags);
+ #endif
+
+ if (td->result != NULL) {
+ if (td->flags.bits.spd) {
+ #ifdef SHOW_ERRORS
+ printf("[uhci] Short packet detected\n");
+ #endif
+
+ if (hc->queue_head->transfer == td->ptd) {
+ hc->queue_head->transfer = td->next;
+ }
+
+ *td->result = EMSGSIZE;
+ } else if ((status == 0x01) && !td->flags.bits.e_stall) {
+ #ifdef DEBUG
+ printf("[uhci] Fine, actual len: %i; max len: %i\n",
+ td->flags.bits.act_len, td->maxlen);
+ #endif
+ if (((td->flags.bits.act_len + 1) & 0x7FF) < ((td->maxlen + 1) & 0x7FF)) {
+ *td->result = EMSGSIZE;
+ } else {
+ *td->result = 0;
+ }
+ } else {
+ td->pipe->toggle = td->toggle;
+ // TODO Weitere Transfers aus der Liste entfernen
+ #ifdef SHOW_ERRORS
+ printf("[uhci] Something failed, errors: %c%c%c%c%c%c\n",
+ td->flags.bits.e_bitstuff ? 'b' : '-',
+ td->flags.bits.e_crc_timeout ? 'c' : '-',
+ td->flags.bits.e_nak ? 'n' : '-',
+ td->flags.bits.e_babble ? 'q' : '-',
+ td->flags.bits.e_buffer ? 'f' : '-',
+ td->flags.bits.e_stall ? 's' : '-');
+ printf("[uhci] Next'll be: 0x%08X/0x%08X\n", td->next,
+ td->q_next);
+ #endif
+
+ if (hc->queue_head->transfer == td->ptd) {
+ hc->queue_head->transfer = td->next;
+ }
+
+ if (td->flags.bits.e_stall) {
+ *td->result = EHOSTDOWN;
+ } else {
+ *td->result = EAGAIN;
+ }
+ }
+ }
+
+ ntd = td->q_next;
+ if (td->free_on_completion) {
+ mem_free(td, 4096);
+ }
+
+ if (td->next & 1) {
+ td = ntd;
+ break;
+ }
+
+ td = ntd;
+ }
+
+ hc->queue_head->q_first = td;
+ if (td == NULL) {
+ hc->queue_head->q_last = NULL;
+ hc->queue_head->transfer = 1;
+ }
+
+ unlock(&hc->queue_head_lock);
+
+ outw(hc->iobase + UHCI_USBSTS, status);
+}
+
+void uhci_hct_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+ struct usb_hc_trs* trs = data;
+ void* shm;
+ int result;
+
+ if (length < sizeof(*trs)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+
+ switch (trs->type)
+ {
+ case USB_TRST_CONTROL:
+ if (length < sizeof(struct usb_hc_trs_ctrl)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+ struct usb_hc_trs_ctrl* ctrl = data;
+
+ shm = open_shared_memory(ctrl->shm);
+ result = uhci_do_control(trs->hc.hcd_avail, &trs->pipe,
+ &ctrl->setup, shm);
+ close_shared_memory(ctrl->shm);
+ rpc_send_int_response(src, corr_id, result);
+ break;
+ case USB_TRST_BULK:
+ if (length < sizeof(struct usb_hc_trs_bulk)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+ struct usb_hc_trs_bulk* bulk = data;
+
+ shm = open_shared_memory(bulk->shm);
+ result = uhci_do_bulk(trs->hc.hcd_avail, &trs->pipe,
+ bulk->receive, shm, bulk->length);
+ close_shared_memory(bulk->shm);
+
+ if (!result) {
+ // Irgendwie muss der Status des Bits ja zurück
+ result = trs->pipe.toggle;
+ }
+ rpc_send_int_response(src, corr_id, result);
+ break;
+ default:
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ break;
+ }
+}
+
+void uhci_hcc_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+ struct usb_hc_ctrl_req* rq = data;
+ struct usb_hc_ctrl_scan* rqsc = data;
+ struct usb_hc_ctrl_dsbl* rqdbl = data;
+ struct usb_hc_ctrl_rst* rqrst = data;
+
+ if (length < sizeof(*rq)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ switch (rq->type)
+ {
+ case HC_CTRL_SCAN_PORT:
+ if (length < sizeof(*rqsc)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+ int result = uhci_scan_port(rq->hc.hcd_avail, rqsc->port);
+ rpc_send_int_response(src, corr_id, result);
+ break;
+ case HC_CTRL_DSBL_PORT:
+ if (length < sizeof(*rqdbl)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+ uhci_set_port_status(rq->hc.hcd_avail, rqdbl->port, 0);
+ rpc_send_int_response(src, corr_id, 1);
+ break;
+ case HC_CTRL_RESET:
+ if (length < sizeof(*rqrst)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+ uhci_reset_port(rq->hc.hcd_avail, rqrst->port);
+ rpc_send_int_response(src, corr_id, 1);
+ break;
+ case HC_CTRL_ADD_PIPE:
+ rpc_send_int_response(src, corr_id, 1);
+ break;
+ default:
+ rpc_send_int_response(src, corr_id, 0);
+ break;
+ }
+}
+
+void init_rpc_interface(void)
+{
+ register_message_handler(RPC_USB_HC_CONTROL_FNN, &uhci_hcc_handler);
+ register_message_handler(RPC_USB_HC_TRANSFER_FNN, &uhci_hct_handler);
+}
+
+void register_uhci(struct uhci* hc)
+{
+ struct usb_hc rhc = {
+ .root_ports = hc->rh->ports,
+ .hcd_avail = hc
+ };
+
+ if (!rpc_get_int(usb_pid, RPC_USB_SV_REGHC_FNN, sizeof(rhc), (char*)&rhc)) {
+ fprintf(stderr, "Could not register UHCI.\n");
+ }
+}
diff --git a/src/modules/usb/uhci/trans.c b/src/modules/usb/uhci/trans.c
new file mode 100644
index 0000000..b9c82c2
--- /dev/null
+++ b/src/modules/usb/uhci/trans.c
@@ -0,0 +1,316 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <syscall.h>
+
+#include "uhci.h"
+#include "usb-hc.h"
+#include "usb-trans.h"
+
+#define USB_SETUP_OUT (0 << 7)
+#define USB_SETUP_IN (1 << 7)
+
+int insert_td(struct uhci* hc, uintptr_t ptd, struct uhci_td* td);
+
+int uhci_do_control(struct uhci* hc, struct usb_trans_pipe* pipe,
+ struct usb_setup_packet* setup, void* buffer)
+{
+ if ((pipe->speed != USB_HUB_LOW_SPEED) &&
+ (pipe->speed != USB_HUB_FULL_SPEED))
+ {
+ return -EPROTOTYPE;
+ }
+
+ struct uhci_td* td = mem_allocate(sizeof(*td), 0);
+ assert(td);
+ uintptr_t ptd = (uintptr_t)get_phys_addr(td);
+ assert(ptd);
+
+ volatile int status;
+
+ do {
+ status = EALREADY;
+
+ td->next = 1;
+ if (pipe->speed == USB_HUB_LOW_SPEED) {
+ td->flags.flags = 0x1D800000;
+ } else {
+ td->flags.flags = 0x19800000;
+ }
+ td->pid = USB_SETUP;
+ td->toggle = 0;
+ td->addr = pipe->usb_addr;
+ td->ep = pipe->ep_id;
+
+ td->maxlen = sizeof(*setup) - 1;
+ td->buffer = (uintptr_t)get_phys_addr(setup);
+
+ td->result = &status;
+ td->free_on_completion = 0;
+
+ td->pipe = pipe;
+
+ while (insert_td(hc, ptd, td));
+
+ while (status == EALREADY);
+ } while (status == EAGAIN);
+
+ if (status) {
+ if (status == EHOSTDOWN) {
+ pipe->stalled = 1;
+ }
+
+ mem_free(td, 4096);
+ return -status;
+ }
+
+ pipe->toggle = 1;
+
+ int remaining = setup->length;
+ int direction, done = 0;
+
+ if (setup->type & USB_SETUP_IN) {
+ direction = USB_IN;
+ } else {
+ direction = USB_OUT;
+ }
+
+ while (remaining) {
+ int this_len = (remaining > pipe->mps) ? pipe->mps : remaining;
+
+ remaining -= this_len;
+
+ do {
+ status = EALREADY;
+
+ td->next = 1;
+ if (pipe->speed == USB_HUB_LOW_SPEED) {
+ td->flags.flags = 0x1D800000;
+ } else {
+ td->flags.flags = 0x19800000;
+ }
+ td->pid = direction;
+ td->toggle = pipe->toggle;
+ td->addr = pipe->usb_addr;
+ td->ep = pipe->ep_id;
+
+ td->maxlen = (unsigned int)(this_len - 1) & 0x7FF;
+ td->buffer = (uintptr_t)get_phys_addr((void*)((uintptr_t)buffer + done));
+
+ td->result = &status;
+ td->free_on_completion = 0;
+
+ while (insert_td(hc, ptd, td));
+
+ while (status == EALREADY);
+ } while (status == EAGAIN);
+
+ if (status && (status != EMSGSIZE)) {
+ if (status == EHOSTDOWN) {
+ pipe->stalled = 1;
+ }
+
+ mem_free(td, 4096);
+ return -status;
+ }
+
+ pipe->toggle ^= 1;
+ done += this_len;
+
+ if (status == EMSGSIZE)
+ break;
+ }
+
+ if (direction == USB_IN) {
+ direction = USB_OUT;
+ } else {
+ direction = USB_IN;
+ }
+
+ do {
+ status = EALREADY;
+
+ td->next = 1;
+ if (pipe->speed == USB_HUB_LOW_SPEED) {
+ td->flags.flags = 0x1D800000;
+ } else {
+ td->flags.flags = 0x19800000;
+ }
+ td->pid = direction;
+ td->toggle = 1;
+ td->addr = pipe->usb_addr;
+ td->ep = pipe->ep_id;
+
+ td->maxlen = 0x7FF;
+ td->buffer = 0;
+
+ td->result = &status;
+ td->free_on_completion = 0;
+
+ while (insert_td(hc, ptd, td));
+
+ while (status == EALREADY);
+ } while (status == EAGAIN);
+
+ if (status == EHOSTDOWN) {
+ pipe->stalled = 1;
+ }
+
+ pipe->toggle = 0;
+ mem_free(td, sizeof(*td));
+
+ return -status;
+}
+
+int uhci_do_bulk(struct uhci* hc, struct usb_trans_pipe* pipe, bool receive,
+ void* buffer, size_t length)
+{
+ if ((pipe->speed != USB_HUB_LOW_SPEED) &&
+ (pipe->speed != USB_HUB_FULL_SPEED))
+ {
+ return -EPROTOTYPE;
+ }
+
+ if (!length) {
+ return -EINVAL;
+ }
+
+ // printf("Issuing bulk (%i B expected)\n", length);
+
+ struct uhci_td* td = mem_allocate(sizeof(*td), 0);
+ assert(td);
+ uintptr_t ptd = (uintptr_t)get_phys_addr(td);
+ assert(ptd);
+
+ volatile int res;
+
+ int remaining = length;
+ int done = 0;
+
+ while (remaining) {
+ // printf("%i B to go\n", remaining);
+ int this_len = (remaining > pipe->mps) ? pipe->mps : remaining;
+
+ remaining -= this_len;
+
+ td->next = 1;
+ if (pipe->speed == USB_LOW_SPEED) {
+ td->flags.flags = 0x1D800000;
+ } else {
+ td->flags.flags = 0x19800000;
+ }
+ if (receive) {
+ td->pid = USB_IN;
+ } else {
+ td->pid = USB_OUT;
+ }
+ td->toggle = pipe->toggle;
+ td->addr = pipe->usb_addr;
+ td->ep = pipe->ep_id;
+
+ td->maxlen = (unsigned int)(this_len - 1) & 0x7FF;
+ td->buffer = (uintptr_t)
+ get_phys_addr((void *)((uintptr_t)buffer + done));
+
+ res = EALREADY;
+ td->result = &res;
+ td->free_on_completion = 0;
+ td->pipe = pipe;
+
+ // printf("Inserting TD\n");
+ while (insert_td(hc, ptd, td));
+
+ // printf("Waiting for transmission\n");
+ while (res == EALREADY);
+ // printf("Thru\n");
+
+ if (res == EAGAIN) {
+ remaining += this_len;
+ continue;
+ }
+
+ if (res) {
+ return -res;
+ }
+
+ pipe->toggle ^= 1;
+
+ done += this_len;
+ }
+
+ if (res == EHOSTDOWN) {
+ pipe->stalled = 1;
+ }
+
+ mem_free(td, sizeof(*td));
+
+ return -res;
+}
+
+int insert_td(struct uhci* hc, uintptr_t ptd, struct uhci_td* td)
+{
+ struct uhci_td *last;
+
+ lock(&hc->queue_head_lock);
+
+ td->ptd = ptd;
+ td->q_next = NULL;
+ td->active_count = 10;
+
+ if (hc->queue_head->transfer & 1) {
+ // Insert as first element to be done
+ if (hc->queue_head->q_last != NULL) {
+ hc->queue_head->q_last->q_next = td;
+ } else {
+ hc->queue_head->q_first = td;
+ }
+
+ hc->queue_head->q_last = td;
+ hc->queue_head->transfer = ptd;
+ } else {
+ last = (struct uhci_td*)hc->queue_head->q_last;
+ #ifdef DEBUG
+ printf("[uhci] Will append to 0x%08X (p 0x%08X)\n", last, hc->queue_head->transfer);
+ #endif
+
+ last->q_next = td;
+ hc->queue_head->q_last = td;
+ last->next = ptd | 4;
+ }
+
+ unlock(&hc->queue_head_lock);
+
+ return 0;
+}
diff --git a/src/modules/usb/uhci/uhci.h b/src/modules/usb/uhci/uhci.h
new file mode 100644
index 0000000..c6b758c
--- /dev/null
+++ b/src/modules/usb/uhci/uhci.h
@@ -0,0 +1,269 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef UHCI_H
+#define UHCI_H
+
+#include <stdint.h>
+#include <lock.h>
+
+#include "usb-hc.h"
+#include "usb-trans.h"
+
+
+#define TYNDUR_IRQ_OFFSET 0x20
+#define IRQ_COUNT 0x10
+
+// Befehlsregister (uint16_t)
+#define UHCI_USBCMD 0x00
+// Statusregister (uint16_t)
+#define UHCI_USBSTS 0x02
+// Interruptregister (uint16_t)
+#define UHCI_USBINTR 0x04
+// Aktuelle Framenummer (uint16_t)
+#define UHCI_FRNUM 0x06
+// Pointer zur Frameliste (uint32_t)
+#define UHCI_FRBASEADD 0x08
+// Bestimmt die genaue Länge eines Frames (uint8_t)
+#define UHCI_SOFMOD 0x0C
+// Array von Informationen über je einen Rootport (je uint16_t)
+#define UHCI_RPORTS 0x10
+
+#define MAXP (1 << 7)
+#define CONFIGURE (1 << 6)
+// Resumesignal treiben
+#define FORCE_GRESUME (1 << 4)
+// Alle Rootports befinden sich im Suspendmodus
+#define GLOB_SUSP_MODE (1 << 3)
+// RESET-Signal wird an allen Rootports getrieben
+#define GRESET (1 << 2)
+// HC wird zurückgesetzt
+#define HCRESET (1 << 1)
+// Normaler Ausführungsmodus
+#define USB_RUN (1 << 0)
+
+// Setzt einen Rootport zurück
+#define RPORT_RESET (1 << 9)
+// Gibt an, ob ein Low-Speed-Gerät angeschlossen ist
+#define RPORT_LOSPD (1 << 8)
+// Treibt das Resume-Signal auf dem Bus
+#define RPORT_RESUME (1 << 6)
+// Schaltet den Rootport ein
+#define RPORT_ENABLE (1 << 2)
+// Wird gesetzt, wenn ein Gerät angeschlossen oder entfernt wird
+#define RPORT_CSC (1 << 1)
+// Gibt an, ob ein Gerät angeschlossen ist
+#define RPORT_DEVICE (1 << 0)
+
+// Das Legacy-Support-Register im PCI-Konfigurationsraum (uint16_t)
+#define UHCI_PCI_LEGSUP 0xC0
+
+// Alle Statusbits, die mittels Schreiben einer 1 gelöscht werden
+#define UHCI_LEGSUP_STATUS 0x8F00
+// Unveränderliche Bits (RO oder reserviert)
+#define UHCI_LEGSUP_NO_CHG 0x5040
+// Interrupt wird als PCI-IRQ ausgeführt
+#define UHCI_LEGSUP_PIRQ 0x2000
+
+
+struct uhci_td {
+ volatile uint32_t next;
+
+ union {
+ volatile uint32_t flags;
+ struct {
+ volatile unsigned act_len : 11;
+ unsigned rsvd1 : 6;
+ volatile unsigned e_bitstuff : 1;
+ volatile unsigned e_crc_timeout : 1;
+ volatile unsigned e_nak : 1;
+ volatile unsigned e_babble : 1;
+ volatile unsigned e_buffer : 1;
+ volatile unsigned e_stall : 1;
+ volatile unsigned active : 1;
+ unsigned ioc : 1;
+ unsigned isochronous : 1;
+ unsigned low_speed : 1;
+ volatile unsigned errors : 2;
+ unsigned spd : 1;
+ unsigned rsvd2 : 2;
+ } __attribute__((packed)) bits;
+ } __attribute__((packed)) flags;
+
+ unsigned pid : 8;
+ unsigned addr : 7;
+ unsigned ep : 4;
+ unsigned toggle : 1;
+ unsigned rsvd : 1;
+ unsigned maxlen : 11;
+
+ uint32_t buffer;
+
+ // Diese Felder sind für den HCD
+
+ // Nächster TD in der Warteschlange
+ struct uhci_td* q_next;
+
+ // Pointer zu einer Variable, die einen errno-Wert aufnimmt
+ volatile int* result;
+
+ // Ist dieses Flag gesetzt, so wird der TD nach Abarbeitung vom IRQ-Handler
+ // automatisch freigegeben
+ int free_on_completion;
+
+ // Physische Adresse
+ uintptr_t ptd;
+
+ // Entsprechende Pipe
+ struct usb_trans_pipe* pipe;
+
+ int active_count;
+} __attribute__((packed));
+
+struct uhci_qh {
+ volatile uint32_t next;
+ volatile uint32_t transfer;
+
+ // Diese Felder sind für den HCD
+
+ // Erster TD in der Warteschlange (oder NULL, wenn keiner)
+ volatile struct uhci_td* q_first;
+
+ // Letzter TD in der Warteschlange (oder NULL, wenn keiner)
+ volatile struct uhci_td* q_last;
+} __attribute__((packed));
+
+// Beschreibt ein UHCI
+struct uhci {
+ // PCI-Geräteinformationen
+ struct pci_device* pci;
+ // Beginn des I/O-Raums
+ uint16_t iobase;
+
+ // Physische Adresse der Framelist
+ uintptr_t p_frame_list;
+ // Virtuelle Adresse der Framelist
+ uint32_t* frame_list;
+ // Lock für den Zugriff auf diese Liste
+ lock_t frame_list_lock;
+
+ // Physische Adresse des (bisher einzigen) QHs
+ uintptr_t p_queue_head;
+ // Virtuelle Adresse des QHs
+ struct uhci_qh* queue_head;
+ // Lock für den Zugriff auf diesen
+ lock_t queue_head_lock;
+
+ // Roothub, der durch das UHCI bereitgestellt wird
+ struct usb_rh* rh;
+};
+
+// Beschreibt einen Roothub (nur für UHCI)
+struct usb_rh {
+ // Anzahl der Rootports
+ int ports;
+};
+
+
+/**
+ * Durchsucht alle verfügbaren PCI-Geräte nach einem UHCI.
+ *
+ * @return 1, wenn ein UHCI gefunden wurde, sonst 0.
+ */
+int check_pci(void);
+
+/**
+ * Initialisiert das RPC-Interface (Handler)
+ */
+void init_rpc_interface(void);
+
+/**
+ * Registriert einen UHCI als HC beim USB-Treiber.
+ *
+ * @param hc Das zu registrierende UHCI
+ */
+void register_uhci(struct uhci* hc);
+
+/**
+ * Führt einen Bulktransfer durch.
+ *
+ * @param hc UHCI
+ * @param pipe Pipe, durch die die Übertragung stattfinden soll
+ * @param receive true, wenn empfangen werden soll, sonst false
+ * @param buffer Zielspeicherbereich
+ * @param length (Angestrebte) Länge des Transfers
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+int uhci_do_bulk(struct uhci* hc, struct usb_trans_pipe* pipe, bool receive,
+ void* buffer, size_t length);
+
+/**
+ * Führt einen Controltransfer durch.
+ *
+ * @param hc UHCI
+ * @param pipe Pipe, durch die die Übertragung stattfinden soll
+ * @param setup SETUP-Paket
+ * @param buffer Speicherbereich, mit dem während der Datenphase gearbeitet
+ * werden soll.
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+int uhci_do_control(struct uhci* hc, struct usb_trans_pipe* pipe,
+ struct usb_setup_packet* setup, void* buffer);
+
+/**
+ * Treibt das Resetsignal auf einem Port und aktiviert ihn.
+ *
+ * @param hc UHCI
+ * @param port Der Portindex
+ */
+void uhci_reset_port(struct uhci* hc, int port);
+
+/**
+ * Überprüft einen Port.
+ *
+ * @param hc UHCI
+ * @param port Zu überprüfender Port
+ *
+ * @return Status (USB_HUB_...)
+ */
+int uhci_scan_port(struct uhci* hc, int port);
+
+/**
+ * Aktiviert oder deaktiviert einen Port.
+ *
+ * @param hc UHCI
+ * @param port Portindex
+ * @param status 1 zum Aktivieren, 0 zum Deaktivieren
+ */
+void uhci_set_port_status(struct uhci* hc, int port, int status);
+
+#endif
diff --git a/src/modules/usb/usb1/Makefile.all b/src/modules/usb/usb1/Makefile.all
new file mode 100644
index 0000000..a0f9525
--- /dev/null
+++ b/src/modules/usb/usb1/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD $1/modules/usb1"
+$LOST_TOOLS_LD $LDSCRIPT -ousb1.mod *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s usb1.mod -o $1/modules/usb1
diff --git a/src/modules/usb/usb1/detect.c b/src/modules/usb/usb1/detect.c
new file mode 100644
index 0000000..54ed6d7
--- /dev/null
+++ b/src/modules/usb/usb1/detect.c
@@ -0,0 +1,440 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <collections.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-hub.h"
+
+extern void usb_found_hub(struct usb_device* dev);
+
+extern list_t* usb_ddrvs;
+extern list_t* unhandled_devs;
+
+static const char* speed_name(int speed)
+{
+ switch (speed) {
+ case USB_LOW_SPEED:
+ return "low speed";
+ case USB_FULL_SPEED:
+ return "full speed";
+ case USB_HIGH_SPEED:
+ return "high speed";
+ default:
+ return "unknown speed";
+ }
+}
+
+static int fits(int is, int want)
+{
+ if (want == -1)
+ return -1;
+ return !!(is == want);
+}
+
+static int provide_to(struct usb_device* dev, int ifc_num,
+ struct usb_interface_descriptor* ifc, struct usb_ddrv* drv)
+{
+ struct usb_prov_dev pd = {
+ .is_interface = (ifc == NULL) ? false : true,
+ .dev_id = dev,
+ .interface_id = ifc_num,
+ .type = {
+ .vendor_id = dev->dev_desc->vendor_id,
+ .device_id = dev->dev_desc->device_id,
+ .class = (ifc == NULL) ? dev->dev_desc->class : ifc->class,
+ .subclass = (ifc == NULL) ? dev->dev_desc->subclass : ifc->subclass,
+ .protocol = (ifc == NULL) ? dev->dev_desc->protocol : ifc->protocol
+ }
+ };
+
+ return rpc_get_int(drv->pid, RPC_USB_DDRV_PLUG_FNN, sizeof(pd), (char*)&pd);
+}
+
+static void dev_is_unhandled(struct usb_device* dev, int ifc_num,
+ struct usb_interface_descriptor* ifc)
+{
+ struct usb_prov_dev* pd = calloc(1, sizeof(*pd));
+
+ pd->is_interface = (ifc == NULL) ? false : true;
+ pd->dev_id = dev;
+ pd->interface_id = ifc_num;
+ pd->type.vendor_id = dev->dev_desc->vendor_id;
+ pd->type.device_id = dev->dev_desc->device_id;
+ pd->type.class = (ifc == NULL) ? dev->dev_desc->class : ifc->class;
+ pd->type.subclass = (ifc == NULL) ? dev->dev_desc->subclass : ifc->subclass;
+ pd->type.protocol = (ifc == NULL) ? dev->dev_desc->protocol : ifc->protocol;
+
+ list_push(unhandled_devs, pd);
+}
+
+#define check(svar, lname) int svar##f = fits(svar, drv->handle.lname); \
+ if (!svar##f) { continue; }
+
+#define provto(check) if (check && provide_to(dev, ifc_num, ifc, drv)) \
+ { break; }
+
+static void provide(struct usb_device* dev, int ifc_num,
+ struct usb_interface_descriptor* ifc)
+{
+ int vid, did, cls, scl, ptc;
+
+ vid = dev->dev_desc->vendor_id;
+ did = dev->dev_desc->device_id;
+ if (ifc == NULL) {
+ cls = dev->dev_desc->class;
+ scl = dev->dev_desc->subclass;
+ ptc = dev->dev_desc->protocol;
+ } else {
+ cls = ifc->class;
+ scl = ifc->subclass;
+ ptc = ifc->protocol;
+ }
+
+ int i, s = list_size(usb_ddrvs);
+ for (i = 0; i < s; i++) {
+ struct usb_ddrv* drv = list_get_element_at(usb_ddrvs, i);
+
+ check(vid, vendor_id)
+ check(did, device_id)
+ check(cls, class)
+ check(scl, subclass)
+ check(ptc, protocol)
+
+ // Wenn jemandem noch eine sinnvolle Kombination einfällt, kann er die
+ // gern hier eintragen.
+ // If anyone knows another combination making sense, he is encouraged
+ // to insert it here.
+ provto(vidf && didf)
+ provto(vidf && clsf && sclf && ptcf)
+ provto( clsf && sclf && ptcf)
+ provto(vidf && clsf && sclf)
+ provto( clsf && sclf)
+ provto(vidf && clsf)
+ provto( clsf)
+ }
+
+ if (i == s) {
+ dev_is_unhandled(dev, ifc_num, ifc);
+ }
+}
+
+void update_ep_trs_info(struct usb_pipe* ep)
+{
+ ep->trs.usb_addr = ep->dev->addr;
+ ep->trs.ep_id = ep->ep->number;
+ ep->trs.mps = ep->ep->mps;
+ ep->trs.type = ep->ep->type;
+ ep->trs.speed = ep->dev->speed;
+}
+
+#define TNC(fnc) if ((ret = fnc)) { \
+ printf("[usb1] err@%i, ret is %i\n" # fnc "\n", __LINE__, ret); return; }
+
+void enumerate_device(struct usb_device* dev)
+{
+ struct usb_hub* hub = dev->parent;
+ int p = dev->hub_port;
+
+ printf("[usb1] Enumerating %s device on port %i of some hub\n", speed_name(dev->speed), dev->hub_port);
+
+ hub->reset_port(hub, p);
+ dev->addr = 0;
+ dev->state = USB_DEFAULT;
+
+ struct usb_pipe* ep0;
+ dev->ep0 = ep0 = calloc(1, sizeof(*ep0));
+
+ ep0->dev = dev;
+ ep0->ep = calloc(1, sizeof(*ep0->ep));
+ ep0->ep->number = 0;
+ ep0->ep->mps = 8;
+ ep0->ep->type = USB_EP_CONTROL;
+
+ update_ep_trs_info(ep0);
+
+ ep0->trs.toggle = 0;
+ ep0->trs.stalled = false;
+
+ if (hub->add_pipe != NULL) {
+ hub->add_pipe(hub, ep0);
+ }
+
+ dev->dev_desc = calloc(1, sizeof(*dev->dev_desc));
+
+ int ret = usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_DEVICE | 0, 0, 8, dev->dev_desc);
+
+ printf("[usb1] mps0 is %i B\n", dev->dev_desc->mps0);
+
+ if (ret) {
+ fprintf(stderr, "[usb1] Warning: first transfer returned %i\n", ret);
+ }
+
+ if (!dev->dev_desc->mps0) {
+ return;
+ }
+
+ hub->reset_port(hub, p);
+ ep0->ep->mps = dev->dev_desc->mps0;
+ ep0->trs.stalled = false;
+ update_ep_trs_info(ep0);
+
+ int address = dev->hc->addr_counter++;
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV, USB_SET_ADDRESS,
+ address, 0, 0, NULL));
+ dev->addr = address;
+ update_ep_trs_info(ep0);
+
+ if (hub->add_pipe != NULL) {
+ hub->add_pipe(hub, dev->ep0);
+ }
+
+ dev->state = USB_ADDRESS;
+
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_DEVICE | 0, 0, sizeof(*dev->dev_desc),
+ dev->dev_desc));
+
+ printf("[usb1] 0x%04X:0x%04X (%i configs)\n", dev->dev_desc->vendor_id,
+ dev->dev_desc->device_id, dev->dev_desc->num_configurations);
+
+ int i;
+
+ if (dev->dev_desc->i_manufacturer) {
+ uint8_t name[255];
+
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_STRING | dev->dev_desc->i_manufacturer,
+ 0, 255, name));
+
+ printf("[usb1] -> Manufacturer: ");
+ for (i = 2; i < name[0]; i += 2) {
+ printf("%c", name[i]);
+ }
+ printf("\n");
+ }
+ if (dev->dev_desc->i_product) {
+ uint8_t name[255];
+
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_STRING | dev->dev_desc->i_product,
+ 0, 255, name));
+
+ printf("[usb1] -> Product: ");
+ for (i = 2; i < name[0]; i += 2) {
+ printf("%c", name[i]);
+ }
+ printf("\n");
+ }
+
+ dev->cfg_desc = calloc(dev->dev_desc->num_configurations, sizeof(*dev->cfg_desc));
+ for (i = 0; i < dev->dev_desc->num_configurations; i++) {
+ uint8_t tmp[9];
+
+ // Erstmal Länge aller Deskriptoren herausfinden
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_CONFIGURATION | i, 0, 9, tmp));
+ dev->cfg_desc[i] = calloc(1, tmp[2] | (tmp[3] << 8));
+ TNC(usb_control_transfer(ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_CONFIGURATION | i, 0,
+ tmp[2] | (tmp[3] << 8), dev->cfg_desc[i]));
+ }
+
+ if (dev->dev_desc->class == 9) {
+ usb_found_hub(dev);
+ return;
+ }
+
+ if (dev->dev_desc->class) {
+ provide(dev, 0, NULL);
+ }
+
+ struct usb_config_descriptor* best_cfg = dev->cfg_desc[0];
+
+ int c;
+ for (c = 0; c < dev->dev_desc->num_configurations; c++) {
+ struct usb_config_descriptor* cur_cfg = dev->cfg_desc[c];
+
+ if (cur_cfg->self_powered && !best_cfg->self_powered) {
+ // Wir wollen möglichst Self-powered
+ best_cfg = cur_cfg;
+ } else if (cur_cfg->max_power > best_cfg->max_power) {
+ // Und möglichst hohen Stromverbrauch (FIXME: Das aber nicht immer)
+ best_cfg = cur_cfg;
+ }
+ }
+
+ dev->cur_cfg = best_cfg;
+ usb_set_configuration(dev, best_cfg->configuration_value);
+
+ struct usb_interface_descriptor* cur_ifc = (struct usb_interface_descriptor*)(best_cfg + 1);
+
+ for (i = 0; i < best_cfg->num_interfaces; i++) {
+ if (cur_ifc->class && !cur_ifc->alternate_setting) {
+ provide(dev, i, cur_ifc);
+ }
+
+ cur_ifc = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(cur_ifc + 1) +
+ cur_ifc->num_endpoints);
+ }
+}
+
+void scan_hub(struct usb_hub* hub)
+{
+ int p;
+
+ printf("[usb1] Hub with %i ports detected.\n", hub->ports);
+
+ for (p = 0; p < hub->ports; p++) {
+ hub->disable_port(hub, p);
+ }
+
+ for (p = 0; p < hub->ports; p++) {
+ int stat = hub->scan_port(hub, p);
+
+ if (stat & USB_HUB_DEVICE) {
+ struct usb_device* dev = calloc(1, sizeof(*dev));
+
+ dev->parent = hub;
+ dev->hub_port = p;
+
+ if (hub->root_hub) {
+ dev->hc = hub->dev.hc;
+ } else {
+ dev->hc = hub->dev.usb->hc;
+ }
+
+ dev->addr = 0;
+ dev->state = USB_ATTACHED;
+ dev->speed = stat & USB_HUB_SPEED;
+
+ enumerate_device(dev);
+ }
+ }
+}
+
+static void rh_addpipe(struct usb_hub* hub, struct usb_pipe* pipe)
+{
+ struct usb_hc* hc;
+
+ if (hub->root_hub) {
+ hc = hub->dev.hc;
+ } else {
+ hc = hub->dev.usb->hc;
+ }
+
+ struct usb_hc_ctrl_appe appe = {
+ .req = {
+ .type = HC_CTRL_ADD_PIPE,
+ .hc = *hc
+ },
+ .pipe = pipe->trs
+ };
+
+ rpc_get_int(hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(appe),
+ (char*)&appe);
+}
+
+static void rh_rst(struct usb_hub* hub, int port)
+{
+ struct usb_hc_ctrl_rst rqrst = {
+ .req = {
+ .type = HC_CTRL_RESET,
+ .hc = *hub->dev.hc
+ },
+ .port = port
+ };
+
+ rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqrst),
+ (char*)&rqrst);
+}
+
+static int rh_scan(struct usb_hub* hub, int port)
+{
+ struct usb_hc_ctrl_scan rqsc = {
+ .req = {
+ .type = HC_CTRL_SCAN_PORT,
+ .hc = *hub->dev.hc
+ },
+ .port = port
+ };
+
+ return rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqsc),
+ (char*)&rqsc);
+}
+
+static void rh_disable(struct usb_hub* hub, int port)
+{
+ struct usb_hc_ctrl_dsbl rqdbl = {
+ .req = {
+ .type = HC_CTRL_DSBL_PORT,
+ .hc = *hub->dev.hc
+ },
+ .port = port
+ };
+
+ rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqdbl),
+ (char*)&rqdbl);
+}
+
+void scan_hc(struct usb_hc* hc)
+{
+ struct usb_hub rh = {
+ .dev = {
+ .hc = hc
+ },
+ .root_hub = true,
+ .ports = hc->root_ports,
+ .add_pipe = &rh_addpipe,
+ .disable_port = &rh_disable,
+ .reset_port = &rh_rst,
+ .scan_port = &rh_scan
+ };
+
+ scan_hub(&rh);
+}
diff --git a/src/modules/usb/usb1/hub.c b/src/modules/usb/usb1/hub.c
new file mode 100644
index 0000000..b1d0597
--- /dev/null
+++ b/src/modules/usb/usb1/hub.c
@@ -0,0 +1,180 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <rpc.h>
+#include <sleep.h>
+
+#include "usb.h"
+#include "usb-hc.h"
+
+static int scan_hub_port(struct usb_hub* hub, int port)
+{
+ uint32_t status;
+
+ usb_control_transfer(hub->dev.usb->ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH, USB_GET_STATUS,
+ 0, port + 1, 4, &status);
+
+ if (!(status & (1 << 0))) {
+ return 0;
+ }
+
+ if (status & (1 << 9)) {
+ return USB_HUB_DEVICE | USB_HUB_LOW_SPEED;
+ } else if (status & (1 << 10)) {
+ return USB_HUB_DEVICE | USB_HUB_HIGH_SPEED;
+ } else {
+ return USB_HUB_DEVICE | USB_HUB_FULL_SPEED;
+ }
+}
+
+static void disable_hub_port(struct usb_hub *hub, int port)
+{
+ // Deaktivieren
+ usb_control_transfer(hub->dev.usb->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_CLEAR_FEATURE, 1, port + 1, 0, NULL);
+}
+
+static void reset_hub_port(struct usb_hub* hub, int port)
+{
+ uint32_t cur;
+
+ port++;
+
+ usb_control_transfer(hub->dev.usb->ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH, USB_GET_STATUS,
+ 0, port, 4, &cur);
+
+ // Zurücksetzen
+ usb_control_transfer(hub->dev.usb->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_SET_FEATURE, 4, port, 0, NULL);
+
+ msleep(20);
+
+ if (!(cur & (1 << 1)) || (cur & (1 << 2))) {
+ // Vorher deaktiviert oder im Suspendmodus, Resume treiben
+ usb_control_transfer(hub->dev.usb->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_CLEAR_FEATURE, 2, port, 0, NULL);
+ msleep(30);
+ }
+}
+
+void usb_found_hub(struct usb_device* dev)
+{
+ struct usb_config_descriptor* ccfg;
+ struct usb_interface_descriptor* cint;
+ struct usb_hub* hub;
+ struct usb_hub_descriptor* chub;
+ uint8_t chub_buf[256];
+
+ dev->cur_cfg = NULL;
+
+ int c, i;
+
+ for (c = 0; c < dev->dev_desc->num_configurations; c++) {
+ ccfg = dev->cfg_desc[c];
+ cint = (struct usb_interface_descriptor*)(dev->cfg_desc[c] + 1);
+ for (i = 0; i < ccfg->num_interfaces; i++) {
+ if (cint->class == 9) {
+ dev->cur_cfg = ccfg;
+ break;
+ }
+
+ cint = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(cint + 1) +
+ cint->num_endpoints);
+ }
+ }
+
+ if (dev->cur_cfg == NULL) {
+ return;
+ }
+
+ usb_set_configuration(dev, dev->cur_cfg->configuration_value);
+
+ hub = calloc(1, sizeof(*hub));
+ if (hub == NULL) {
+ return;
+ }
+
+ hub->dev.usb = dev;
+ hub->root_hub = false;
+
+ usb_control_transfer(dev->ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_DEV,
+ USB_GET_DESCRIPTOR, USB_DESC_HUB, 0, 256, chub_buf);
+
+ chub = (struct usb_hub_descriptor*)chub_buf;
+
+ hub->ports = chub->nbr_ports;
+
+ for (i = 1; i <= hub->ports; i++) {
+ // Strom einschalten
+ usb_control_transfer(dev->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_SET_FEATURE, 8, i, 0, NULL);
+
+ msleep(chub->pwr_on_2_pwr_good * 2);
+ }
+
+ msleep(100);
+
+ for (i = 1; i <= hub->ports; i++) {
+ uint32_t status;
+
+ usb_control_transfer(dev->ep0,
+ USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_GET_STATUS, 0, i, 4, &status);
+
+ if (status & (1 << 1)) {
+ // Port deaktivieren
+ usb_control_transfer(dev->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+ USB_CLEAR_FEATURE, 1, i, 0, NULL);
+ }
+ }
+
+ hub->add_pipe = dev->parent->add_pipe;
+ hub->disable_port = &disable_hub_port;
+ hub->reset_port = &reset_hub_port;
+ hub->scan_port = &scan_hub_port;
+
+ scan_hub(hub);
+}
diff --git a/src/modules/usb/usb1/main.c b/src/modules/usb/usb1/main.c
new file mode 100644
index 0000000..a7611ff
--- /dev/null
+++ b/src/modules/usb/usb1/main.c
@@ -0,0 +1,59 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <init.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+
+extern list_t* usb_hcs;
+extern list_t* usb_ddrvs;
+extern list_t* unhandled_devs;
+
+int main(void)
+{
+ usb_hcs = list_create();
+ usb_ddrvs = list_create();
+ unhandled_devs = list_create();
+
+ init_messaging();
+ register_rpc_interface();
+
+ for (;;) {
+ wait_for_rpc();
+ }
+}
diff --git a/src/modules/usb/usb1/rpc.c b/src/modules/usb/usb1/rpc.c
new file mode 100644
index 0000000..5d55306
--- /dev/null
+++ b/src/modules/usb/usb1/rpc.c
@@ -0,0 +1,327 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <init.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-server.h"
+
+list_t* usb_hcs;
+list_t* usb_ddrvs;
+list_t* unhandled_devs;
+
+extern void scan_hc(struct usb_hc* hc);
+
+static void hcd_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+ struct usb_hc* hc;
+
+ if (length < sizeof(*hc)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ hc = malloc(sizeof(*hc));
+ memcpy(hc, data, sizeof(*hc));
+
+ hc->pid = src;
+ hc->addr_counter = 1;
+ list_push(usb_hcs, hc);
+
+ scan_hc(hc);
+
+ rpc_send_int_response(src, corr_id, 42);
+}
+
+#define check(name) if ((dev->type.name != hd->name) && (hd->name != -1)) \
+ { continue; }
+
+static void ddrv_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+ struct usb_handle_devs* hd = data;
+
+ if (length < sizeof(*hd)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ struct usb_ddrv* drv = calloc(1, sizeof(*drv));
+ drv->pid = src;
+ drv->handle = *hd;
+ list_push(usb_ddrvs, drv);
+
+ int i, s = list_size(unhandled_devs);
+ for (i = 0; i < s; i++) {
+ struct usb_prov_dev* dev = list_get_element_at(unhandled_devs, i);
+
+ check(vendor_id)
+ check(device_id)
+ check(class)
+ check(subclass)
+ check(protocol)
+
+ if (rpc_get_int(src, RPC_USB_DDRV_PLUG_FNN, sizeof(*dev), (char*)dev)) {
+ list_remove(unhandled_devs, i--);
+ s--;
+ }
+ }
+
+ rpc_send_int_response(src, corr_id, 42);
+}
+
+static void devctl_handler(pid_t src, uint32_t corr_id, size_t length,
+ void* data)
+{
+ struct usb_devctrl_req* rq = data;
+
+ if (length < sizeof(*rq)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ struct usb_device* dev;
+ struct usb_interface_descriptor* ifc;
+ int ifcs, ifc_num, i, ret;
+
+ switch (rq->type) {
+ case USB_DC_NUM_ENDPOINTS:
+ if (length < sizeof(struct usb_devctrl_gne)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ struct usb_devctrl_gne* ne = data;
+ dev = ne->dev.dev_id;
+ ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+ ifcs = dev->cur_cfg->num_interfaces;
+ ifc_num = ne->dev.interface_id;
+ if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+ ifc_num = 0;
+ }
+
+ for (i = 0; i < ifcs; i++) {
+ if (i == ifc_num) {
+ rpc_send_int_response(src, corr_id, ifc->num_endpoints);
+ return;
+ }
+
+ ifc = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(ifc + 1) +
+ ifc->num_endpoints);
+ }
+ // Hierhin sollte der Code nie gelangen
+ // Execution should never get here
+ break;
+ case USB_DC_GET_IFC_ID:
+ if (length < sizeof(struct usb_devctrl_gii)) {
+ rpc_send_int_response(src, corr_id, 0);
+ return;
+ }
+
+ struct usb_devctrl_gii* ii = data;
+ dev = ii->dev.dev_id;
+ ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+ ifcs = dev->cur_cfg->num_interfaces;
+ // Das ist nicht die, die wir suchen
+ // This is not the one we're looking for
+ ifc_num = ne->dev.interface_id;
+ if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+ ifc_num = 0;
+ }
+
+ for (i = 0; i < ifcs; i++) {
+ if (i == ifc_num) {
+ rpc_send_int_response(src, corr_id, ifc->interface_number);
+ return;
+ }
+
+ ifc = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(ifc + 1) +
+ ifc->num_endpoints);
+ }
+ // s. o.
+ case USB_DC_GET_ENDPOINT:
+ if (length < sizeof(struct usb_devctrl_gep)) {
+ // Hm, geht wohl nicht anders (und vertretbar, da dieser Fall
+ // nie auftreten sollte)
+ rpc_send_response(src, corr_id, 0, NULL);
+ return;
+ }
+
+ struct usb_devctrl_gep* ge = data;
+ dev = ge->dev.dev_id;
+ ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+ ifcs = dev->cur_cfg->num_interfaces;
+ ifc_num = ne->dev.interface_id;
+ if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+ ifc_num = 0;
+ }
+
+ for (i = 0; i < ifcs; i++) {
+ if (i == ifc_num) {
+ struct usb_endpoint_descriptor* epd =
+ (struct usb_endpoint_descriptor*)(ifc + 1);
+ rpc_send_response(src, corr_id, sizeof(*epd),
+ (char*)&epd[ge->ep_number]);
+ return;
+ }
+
+ ifc = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(ifc + 1) +
+ ifc->num_endpoints);
+ }
+ // s. o.
+ break;
+ case USB_DC_GET_PIPE:
+ if (length < sizeof(struct usb_devctrl_gpp)) {
+ // Auch hier wohl nur so möglich
+ rpc_send_response(src, corr_id, 0, NULL);
+ return;
+ }
+
+ struct usb_devctrl_gpp* gp = data;
+ dev = gp->dev.dev_id;
+ ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+ ifcs = dev->cur_cfg->num_interfaces;
+ ifc_num = ne->dev.interface_id;
+ if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+ ifc_num = 0;
+ }
+
+ for (i = 0; i < ifcs; i++) {
+ if (i == ifc_num) {
+ if ((gp->ep_number < 0) ||
+ (gp->ep_number >= ifc->num_endpoints))
+ {
+ gp->ep_number = 0;
+ }
+
+ struct usb_endpoint_descriptor* epd =
+ (struct usb_endpoint_descriptor*)(ifc + 1);
+ epd += gp->ep_number;
+
+ struct usb_pipe pp = {
+ .dev = dev,
+ .ep = epd,
+ .trs = {
+ .usb_addr = dev->addr,
+ .ep_id = epd->number,
+ .mps = epd->mps,
+ .type = epd->type,
+ .speed = dev->speed,
+ .toggle = 0,
+ .stalled = false
+ }
+ };
+
+ if (dev->parent->add_pipe != NULL) {
+ dev->parent->add_pipe(dev->parent, &pp);
+ }
+
+ rpc_send_response(src, corr_id, sizeof(pp), (char*)&pp);
+ return;
+ }
+
+ ifc = (struct usb_interface_descriptor*)
+ ((struct usb_endpoint_descriptor*)(ifc + 1) +
+ ifc->num_endpoints);
+ }
+ // s. o.
+ break;
+ case USB_DC_CLEAR_HALT:
+ if (length < sizeof(struct usb_devctrl_clh)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+
+ struct usb_devctrl_clh* clrh = data;
+ usb_clear_halt(&clrh->pipe);
+ rpc_send_int_response(src, corr_id, 0);
+ break;
+ case USB_DC_TRSF_CONTROL:
+ if (length < sizeof(struct usb_devctrl_tct)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+
+ struct usb_devctrl_tct* tctrq = data;
+ if (tctrq->ep0) {
+ dev = tctrq->dst.dev_id;
+ ret = usb_shm_control_transfer(dev->ep0, tctrq->setup.type,
+ tctrq->setup.request, tctrq->setup.value,
+ tctrq->setup.index, tctrq->setup.length, tctrq->shm);
+ } else {
+ ret = usb_shm_control_transfer(&tctrq->dst.pipe,
+ tctrq->setup.type, tctrq->setup.request, tctrq->setup.value,
+ tctrq->setup.index, tctrq->setup.length, tctrq->shm);
+ }
+
+ rpc_send_int_response(src, corr_id, ret);
+ break;
+ case USB_DC_TRSF_BULK:
+ if (length < sizeof(struct usb_devctrl_tbk)) {
+ rpc_send_int_response(src, corr_id, -EINVAL);
+ return;
+ }
+
+ struct usb_devctrl_tbk* tbkrq = data;
+ ret = usb_shm_bulk_transfer(&tbkrq->pipe, tbkrq->shm,
+ tbkrq->length);
+
+ // Senden des Togglebitstatus erwünscht
+ rpc_send_int_response(src, corr_id, ret);
+ break;
+ }
+}
+
+void register_rpc_interface(void)
+{
+ register_message_handler(RPC_USB_SV_REGHC_FNN, &hcd_handler);
+ register_message_handler(RPC_USB_SV_REGDD_FNN, &ddrv_handler);
+ register_message_handler(RPC_USB_SV_DEVCT_FNN, &devctl_handler);
+ init_service_register("usb1");
+}
diff --git a/src/modules/usb/usb1/transfer.c b/src/modules/usb/usb1/transfer.c
new file mode 100644
index 0000000..8c96c4d
--- /dev/null
+++ b/src/modules/usb/usb1/transfer.c
@@ -0,0 +1,123 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <string.h>
+
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+
+int usb_control_transfer(struct usb_pipe* pipe, int type, int request,
+ int value, int index, int length, void* buffer)
+{
+ uint32_t shm = 0;
+ void *shm_addr = NULL;
+
+ if (length) {
+ shm = create_shared_memory(length);
+ shm_addr = open_shared_memory(shm);
+
+ if ((buffer != NULL) && !(type & USB_SETUP_IN)) {
+ memcpy(shm_addr, buffer, length);
+ }
+ }
+
+ int ret = usb_shm_control_transfer(pipe, type, request, value, index,
+ length, shm);
+
+ if (length && (buffer != NULL) && (type & USB_SETUP_IN)) {
+ memcpy(buffer, shm_addr, length);
+ }
+
+ if (shm_addr != NULL) {
+ close_shared_memory(shm);
+ }
+
+ return ret;
+}
+
+int usb_shm_control_transfer(struct usb_pipe* pipe, int type, int request,
+ int value, int index, int length, uint32_t shm)
+{
+ struct usb_hc_trs_ctrl trs = {
+ .trs = {
+ .type = USB_TRST_CONTROL,
+ .hc = *pipe->dev->hc,
+ .pipe = pipe->trs
+ },
+ .setup = {
+ .type = type,
+ .request = request,
+ .value = value,
+ .index = index,
+ .length = length
+ },
+ .shm = shm
+ };
+
+ return rpc_get_int(pipe->dev->hc->pid, RPC_USB_HC_TRANSFER_FNN,
+ sizeof(trs), (char*)&trs);
+}
+
+int usb_shm_bulk_transfer(struct usb_pipe* pipe, uint32_t shm, size_t length)
+{
+ struct usb_hc_trs_bulk trs = {
+ .trs = {
+ .type = USB_TRST_BULK,
+ .hc = *pipe->dev->hc,
+ .pipe = pipe->trs
+ },
+ .receive = pipe->ep->direction ? true : false,
+ .length = length,
+ .shm = shm
+ };
+
+ return rpc_get_int(pipe->dev->hc->pid, RPC_USB_HC_TRANSFER_FNN,
+ sizeof(trs), (char*)&trs);
+}
+
+void usb_set_configuration(struct usb_device* dev, int config)
+{
+ usb_control_transfer(dev->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+ USB_SET_CONFIGURATION, config, 0, 0, NULL);
+ dev->state = USB_CONFIGURED;
+}
+
+void usb_clear_halt(struct usb_pipe* pipe)
+{
+ usb_control_transfer(pipe->dev->ep0,
+ USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_EP,
+ USB_CLEAR_FEATURE, USB_ENDPOINT_HALT, pipe->ep->number, 0, NULL);
+}
diff --git a/src/modules/usb/usb1/usb.h b/src/modules/usb/usb1/usb.h
new file mode 100644
index 0000000..6efc729
--- /dev/null
+++ b/src/modules/usb/usb1/usb.h
@@ -0,0 +1,209 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz *
+* *
+* THE COKE-WARE LICENSE *
+* *
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions are *
+* met: *
+* *
+* 1. Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* 2. Redistribution in binary form must reproduce the above copyright *
+* notice and either the full list of conditions and the following *
+* disclaimer or a link to both. *
+* 3. If we meet one day and you think this stuff is worth it, you may buy *
+* me a coke in return. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
+* SUCH DAMAGE. *
+*****************************************************************************/
+
+#ifndef USB_H
+#define USB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-hub.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+struct usb_pipe;
+
+// Beschreibt einen Hub (sowohl Roothub als auch einen normalen).
+struct usb_hub {
+ // Da ein Hub immer nur entweder Root- oder normaler Hub sein kann, macht
+ // sich eine Union hier ganz gut.
+ union {
+ struct usb_device* usb;
+ struct usb_hc* hc;
+ } dev;
+ // true, wenn es sich um einen Roothub handelt.
+ bool root_hub;
+ // Anzahl der Ports am Hub.
+ int ports;
+
+ /**
+ * Wird aufgerufen, wenn eine neue Pipe benötigt wird. Ist bereits eine
+ * Pipe zur angegebenen Geräte-/Endpunkt-Kombination vorhanden, so sollte
+ * diese entfernt werden. Der Pointer darf NULL sein, um anzuzeigen, dass
+ * die Funktion nicht benötigt wird. Normale Hubs müssen jedoch dafür
+ * sorgen, dass die vom Hostcontroller (Roothub) bereitgestellte Funktion
+ * aufgerufen wird (es genügt, einfach den Pointer vom übergeordneten Hub
+ * zu kopieren, der Roothub muss dies erkennen können).
+ *
+ * @param hub Der Hub, an dem das Gerät hängt.
+ * @param pipe Die neu hinzuzufügende Pipe.
+ */
+ void (*add_pipe)(struct usb_hub* hub, struct usb_pipe* pipe);
+
+ /**
+ * Deaktiviert einen Port (zum Aktivieren wird reset_port verwendet).
+ *
+ * @param hub Hub mit dem zu deaktivierenden Port.
+ * @param port Zu deaktivierender Port.
+ */
+ void (*disable_port)(struct usb_hub* hub, int port);
+
+ /**
+ * Treibt das Resetsignal auf einem Port und aktiviert ihn. Wenn nötig,
+ * muss außerdem das Resume-Signal getrieben werden, damit nach dem Aufruf
+ * dieser Funktion mit dem Gerät kommuniziert werden kann.
+ *
+ * @param hub Hub, an dem das Gerät hängt.
+ * @param port Port, an dem es hängt.
+ */
+ void (*reset_port)(struct usb_hub* hub, int port);
+
+ /**
+ * Überprüft einen Port und gibt dessen Status zurück.
+ *
+ * @param hub Zu untersuchender Hub.
+ * @param port Entsprechender Port.
+ *
+ * @return Kombination aus den in usb-hub.h mit USB_HUB beginnenden Flags.
+ */
+ int (*scan_port)(struct usb_hub* hub, int port);
+};
+
+// Beschreibt ein USB-Gerät
+struct usb_device {
+ // Hub, an dem es hängt
+ struct usb_hub* parent;
+ // Index des Ports, an dem es sich befindet
+ int hub_port;
+
+ // Zuständiger Hostcontroller
+ struct usb_hc* hc;
+ // Dort eindeutige USB-Adresse
+ int addr;
+
+ // Aktueller Status
+ enum usb_state state;
+ // Aktuelle Geschwindigkeit
+ int speed;
+
+ // Default Control Pipe
+ struct usb_pipe* ep0;
+ // Device-Descriptor
+ struct usb_device_descriptor* dev_desc;
+ // Alle Configuration-Descriptors
+ struct usb_config_descriptor** cfg_desc;
+ // Aktuelle Konfiguration
+ struct usb_config_descriptor* cur_cfg;
+};
+
+// USB-Gerätetreiber
+struct usb_ddrv {
+ // Prozess-ID
+ pid_t pid;
+ // Gibt an, welche Geräte er behandeln kann
+ struct usb_handle_devs handle;
+};
+
+// Bisher nicht behandeltes USB-Gerät (oder Interface)
+struct usb_unhandled {
+ // Das Gerät
+ struct usb_device* dev;
+ // Das Interface
+ struct usb_interface_descriptor* ifc;
+};
+
+
+/**
+ * Initialisiert die RPC-Handler und trägt sich als usb1 bei init ein-
+ */
+void register_rpc_interface(void);
+
+/**
+ * Enumeriert alle Geräte an einem Hub
+ *
+ * @param hub Der Hub
+ */
+void scan_hub(struct usb_hub* hub);
+
+/**
+ * Entstallt einen Endpunkt.
+ *
+ * @param pipe Zum Endpunkt gehörige Pipe
+ */
+void usb_clear_halt(struct usb_pipe* pipe);
+
+/**
+ * Führt einen Controltransfer durch.
+ *
+ * @param pipe Die Pipe
+ * @param type type-Feld des SETUP-Pakets
+ * @param request request-Feld des SETUP-Pakets
+ * @param value value-Feld des SETUP-Pakets
+ * @param index index-Feld des SETUP-Pakets
+ * @param length length-Feld des SETUP-Pakets
+ * @param buffer Speicherbereich, mit dem während der Datenphase gearbeitet
+ * werden soll.
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_control_transfer(struct usb_pipe* pipe, int type, int request,
+ int value, int index, int length, void* buffer);
+
+/**
+ * Führt einen Bulktransfer durch.
+ *
+ * @param pipe Die Pipe für den Transfer
+ * @param shm SHM-Bereich, mit dem gearbeitet werden soll
+ * @param length Länge des Transfers
+ *
+ * @return -errno bei Fehler, sonst neuer Wert des Toggle-Bits.
+ */
+int usb_shm_bulk_transfer(struct usb_pipe* pipe, uint32_t shm, size_t length);
+
+/**
+ * Führt einen Controltransfer durch. Entspricht usb_control_transfer, außer
+ * dass ein SHM-Bereich verwendet wird.
+ */
+int usb_shm_control_transfer(struct usb_pipe* pipe, int type, int request,
+ int value, int index, int length, uint32_t shm);
+
+/**
+ * Setzt die aktuelle Konfiguration eines Geräts.
+ *
+ * @param dev USB-Gerät
+ * @param config ID der neuen Konfiguration
+ */
+void usb_set_configuration(struct usb_device* dev, int config);
+
+#endif
--
1.6.4.2