Inhaltsverzeichnis
USB Port
allgemeines
USB ist die Abkürzung für Universal Serial Bus, und wie der Name schon sagt ist es wirklich ein universeller serieller Bus. Er ist der Nachfolger für die meisten Schnittstellen des PCs, beispielsweise für die serielle Schnittstelle (RS-232) und den Parallelport sowie PS/2 (Maus- u. Tastatur-Anschluss). Für den Hobby-Elektroniker ist der USB-Bus attraktiv, da er den Bus auch zur Stromversorgung nutzen kann und sich um das Protokoll und Parameter wie die Geschwindigkeit wenig Gedanken machen muss.
Von dem USB-Stardard wird USB mechanisch, elektrisch und logisch spezifiziert. Im Gegensatz zum Parallelport sind daher die Datenprotokolle hier schon im Standard spezifiziert. USB ist auch interruptfähig, d. h. ein Peripheriegerät kann über den Bus einen Interrupt auslösen. Wie auch Firewire hat USB eine Stromversorgungs- und eine Massen-Ader, mit der die Peripheriegeräte mit 5 V Versorgungsspannung mit bis zu 500 mA versorgt werden können. Eine gute Übersicht über die Pins und Modi des USB findet man unter http://de.wikipedia.org/wiki/USB . Auf diesem in der Mitte der 90er entwickelten Bus werden die Daten differentiell über ein Aderpaar übertragen. Hierdurch können die Daten, im Gegensatz zu Firewire, das (mindestens) zwei Adernpaare verwendet, nicht gleichzeitig gesendet und empfangen werden. Dadurch verwendet USB weniger Hardware und ist entsprechend auch bei den Kabeln billiger als Alternativen wie Firewire. Dies hat, im Vergleich zu Firewire, einige Nachteile, wie sich beispielsweise an externen Festplatten sowohl bei der Performance (Latenzzeit u. Transferrate) als auch der CPU-Last zeigt. Ein weiterer Nachteil ist, dass es an einem USB-Bus nur einen Controller gibt, der den Bus verwaltet. Hierdurch können USB-Peripherie-Geräte über einen Bus nicht direkt miteinander kommunizieren und auch PCs können nicht direkt verbunden werden, während dies mit Firewire geht.
USB kann die anderen Schnittstellen (Parallelport, PS/2 usw.) auch nicht immer vollständig ersetzen, denn über einen gewöhnlichen Parallelport können die Pins mit bis zu 400 kHz geschaltet werden und Interrupts ebenso schnell eingelesen werden, aber USB ist hierbei viel langsamer und daher für harte Echtzeit weniger geeignet.
Da zum Ansteuern der USB-Hardware spezifische Treiber benötigt werden, greift die Software für die am USB angeschlossene Hardware praktisch nie direkt auf die Hardware zu, sondern verwendet die Schnittstellen zum USB-Treiber. Aus diesem Grund wird hier nur die indirekte Ansteuerung des USB behandelt.
In der Praxis gibt es mit dem USB-Bus einige Probleme, weil sich die Hersteller nicht immer an die Standards halten. Als Folge hiervon funktioniert nicht jedes USB-Gerät an jedem PC; einige Kombinationen sind einfach unverträglich. Dies Phänomen ist aber auch von anderer Hardware bekannt, beispielsweise PCI-Karten. Ein weiteres Problem ist, dass der USB nicht sehr stabil ist und beispielsweise Kartenleser nach einigen Tagen am USB-Bus Fehler produzieren, die durch ein Reset in Form eines kurzen abziehen und wieder Ansteckens behoben werden. Diese Fehler zeigen sind beispielsweise in Schreib-Lese-Fehler und die Meldung, dass das Speichermedium nur lesbar ist, auch wenn kein Schreibschutz aktiv wurde.
USB-Standards
| USB 3.2 versions | ||||
|---|---|---|---|---|
| New name | Old name | Original name | SuperSpeed name | Max speed |
| USB 3.2 Gen 2x2 | N/A | USB 3.2 | SuperSpeed USB 20Gbps | 20Gbps |
| USB 3.2 Gen 2 | USB 3.1 Gen 2 | USB 3.1 | SuperSpeed USB 10Gbps | 10Gbps |
| USB 3.2 Gen 1 | USB 3.1 Gen 1 | USB 3.0 | SuperSpeed USB | 5Gbps |
C/C++
usbpanicbutton.c
Mit "lsusb -vvv" lassen sich Informationen über die HID Struktur eines USB Geräts ermitteln.
/*==============================================
PoC for USB Panic Button under unix
--------------------------------------------
by: Benjamin Kendinibilir
needs: libusb and libhid
compile: gcc usbpanicbutton.c -o upb -lhid
run: sudo ./upb (needs root)
==============================================*/
#include <hid.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#define VENDOR_ID 0x1130
#define PRODUCT_ID 0x0202
#define IFACE_NO 0
#define PACKET_SIZE 8
#define PATH1 0x00010000
#define PATH2 0x00000000
#define PATH_LEN 2
int loop = 1;
void endloop(int signum) {
loop = 0;
}
int main(int argc, char *argv[]) {
hid_return ret;
HIDInterface* hid;
char packet[PACKET_SIZE];
int const path_in[] = { PATH1, PATH2 };
int const path_out[] = { PATH1, PATH2 };
HIDInterfaceMatcher matcher = { VENDOR_ID, PRODUCT_ID, NULL, NULL, 0 };
#ifdef DEBUG
hid_set_debug(HID_DEBUG_ALL);
hid_set_debug_stream(stderr);
hid_set_usb_debug(0);
#endif
ret = hid_init();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_init failed with return code %d\n", ret);
return 1;
}
hid = hid_new_HIDInterface();
if (hid == 0) {
fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n");
return 1;
}
ret = hid_force_open(hid, IFACE_NO, &matcher, 3);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_force_open failed with return code %d\n", ret);
return 1;
}
#ifdef DEBUG
ret = hid_write_identification(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_write_identification failed with return code %d\n", ret);
return 1;
}
ret = hid_dump_tree(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_dump_tree failed with return code %d\n", ret);
return 1;
}
#endif
signal(SIGINT, endloop);
signal(SIGHUP, endloop);
signal(SIGTERM, endloop);
printf("waiting for panic button action:\n");
while(loop) {
ret = hid_get_input_report(hid, path_out, PATH_LEN, packet, PACKET_SIZE);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_get_input_report failed with return code %d\n", ret);
}
if(packet[0] == 0x1) {
printf("BAM!\n");
fflush(stdout);
}
usleep(200000);
}
printf("cleaning up... ");
ret = hid_close(hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_close failed with return code %d\n", ret);
return 1;
}
hid_delete_HIDInterface(&hid);
ret = hid_cleanup();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_cleanup failed with return code %d\n", ret);
return 1;
}
printf("exit.\n");
return 0;
}
generic_hid.c
Demonstrates communicating with generic HID-class USB devices using libusb-1.0.
/*
* generic_hid.c
*
* Created on: Apr 22, 2011
* Author: Jan Axelson
*
* Demonstrates communicating with a device designed for use with a generic HID-class USB device.
* Sends and receives 2-byte reports.
* Requires: an attached HID-class device that supports 2-byte
* Input, Output, and Feature reports.
* The device firmware should respond to a received report by sending a report.
* Change VENDOR_ID and PRODUCT_ID to match your device's Vendor ID and Product ID.
* See Lvr.com/winusb.htm for example device firmware.
* This firmware is adapted from code provided by Xiaofan.
* Note: libusb error codes are negative numbers.
The application uses the libusb 1.0 API from libusb.org.
Compile the application with the -lusb-1.0 option.
Use the -I option if needed to specify the path to the libusb.h header file. For example:
-I/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/include/libusb-1.0
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libusb.h>
// Values for bmRequestType in the Setup transaction's Data packet.
static const int CONTROL_REQUEST_TYPE_IN = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE;
static const int CONTROL_REQUEST_TYPE_OUT = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE;
// From the HID spec:
static const int HID_GET_REPORT = 0x01;
static const int HID_SET_REPORT = 0x09;
static const int HID_REPORT_TYPE_INPUT = 0x01;
static const int HID_REPORT_TYPE_OUTPUT = 0x02;
static const int HID_REPORT_TYPE_FEATURE = 0x03;
// With firmware support, transfers can be > the endpoint's max packet size.
static const int MAX_CONTROL_IN_TRANSFER_SIZE = 2;
static const int MAX_CONTROL_OUT_TRANSFER_SIZE = 2;
static const int INTERFACE_NUMBER = 0;
static const int TIMEOUT_MS = 5000;
int exchange_feature_reports_via_control_transfers(libusb_device_handle *devh);
int exchange_input_and_output_reports_via_control_transfers(libusb_device_handle *devh);
int exchange_input_and_output_reports_via_interrupt_transfers(libusb_device_handle *devh);
int main(void)
{
// Change these as needed to match idVendor and idProduct in your device's device descriptor.
static const int VENDOR_ID = 0x0925;
static const int PRODUCT_ID = 0x7001;
struct libusb_device_handle *devh = NULL;
int device_ready = 0;
int result;
result = libusb_init(NULL);
if (result >= 0)
{
devh = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID);
if (devh != NULL)
{
// The HID has been detected.
// Detach the hidusb driver from the HID to enable using libusb.
libusb_detach_kernel_driver(devh, INTERFACE_NUMBER);
{
result = libusb_claim_interface(devh, INTERFACE_NUMBER);
if (result >= 0)
{
device_ready = 1;
}
else
{
fprintf(stderr, "libusb_claim_interface error %d\n", result);
}
}
}
else
{
fprintf(stderr, "Unable to find the device.\n");
}
}
else
{
fprintf(stderr, "Unable to initialize libusb.\n");
}
if (device_ready)
{
// Send and receive data.
exchange_input_and_output_reports_via_interrupt_transfers(devh);
exchange_input_and_output_reports_via_control_transfers(devh);
exchange_feature_reports_via_control_transfers(devh);
// Finished using the device.
libusb_release_interface(devh, 0);
}
libusb_close(devh);
libusb_exit(NULL);
return 0;
}
// Uses control transfers to write a Feature report to the HID
// and receive a Feature report from the HID.
// Returns - zero on success, libusb error code on failure.
int exchange_feature_reports_via_control_transfers(libusb_device_handle *devh)
{
int bytes_received;
int bytes_sent;
char data_in[MAX_CONTROL_IN_TRANSFER_SIZE];
char data_out[MAX_CONTROL_OUT_TRANSFER_SIZE]; int i = 0;
int result = 0;
// Store example data in the output buffer for sending.
// This example uses binary data.
for (i=0;i < MAX_CONTROL_OUT_TRANSFER_SIZE; i++)
{
data_out[i]=0x30+i;
}
// Send data to the device.
bytes_sent = libusb_control_transfer(
devh,
CONTROL_REQUEST_TYPE_OUT ,
HID_SET_REPORT,
(HID_REPORT_TYPE_FEATURE<<8)|0x00,
INTERFACE_NUMBER,
data_out,
sizeof(data_out),
TIMEOUT_MS);
if (bytes_sent >= 0)
{
printf("Feature report data sent:\n");
for(i = 0; i < bytes_sent; i++)
{
printf("%02x ",data_out[i]);
}
printf("\n");
// Request data from the device.
bytes_received = libusb_control_transfer(
devh,
CONTROL_REQUEST_TYPE_IN ,
HID_GET_REPORT,
(HID_REPORT_TYPE_FEATURE<<8)|0x00,
INTERFACE_NUMBER,
data_in,
MAX_CONTROL_IN_TRANSFER_SIZE,
TIMEOUT_MS);
if (bytes_received >= 0)
{
printf("Feature report data received:\n");
for(i = 0; i < bytes_received; i++)
{
printf("%02x ",data_in[i]);
}
printf("\n");
}
else
{
fprintf(stderr, "Error receiving Feature report %d\n", result);
return result;
}
}
else
{
fprintf(stderr, "Error sending Feature report %d\n", result);
return result;
}
return 0;
}
// Uses control transfers to write an Output report to the HID
// and receive an Input report from the HID.
// Returns - zero on success, libusb error code on failure.
int exchange_input_and_output_reports_via_control_transfers(libusb_device_handle *devh)
{
int bytes_received;
int bytes_sent;
char data_in[MAX_CONTROL_IN_TRANSFER_SIZE];
char data_out[MAX_CONTROL_OUT_TRANSFER_SIZE]; int i = 0;
int result = 0;
// Store example data in the output buffer for sending.
// This example uses binary data.
for (i=0;i < MAX_CONTROL_OUT_TRANSFER_SIZE; i++)
{
data_out[i]=0x40+i;
}
// Send data to the device.
bytes_sent = libusb_control_transfer(
devh,
CONTROL_REQUEST_TYPE_OUT ,
HID_SET_REPORT,
(HID_REPORT_TYPE_OUTPUT<<8)|0x00,
INTERFACE_NUMBER,
data_out,
sizeof(data_out),
TIMEOUT_MS);
if (bytes_sent >= 0)
{
printf("Output report data sent:\n");
for(i = 0; i < bytes_sent; i++)
{
printf("%02x ",data_out[i]);
}
printf("\n");
// Request data from the device.
bytes_received = libusb_control_transfer(
devh,
CONTROL_REQUEST_TYPE_IN ,
HID_GET_REPORT,
(HID_REPORT_TYPE_INPUT<<8)|0x00,
INTERFACE_NUMBER,
data_in,
MAX_CONTROL_IN_TRANSFER_SIZE,
TIMEOUT_MS);
if (bytes_received >= 0)
{
printf("Input report data received:\n");
for(i = 0; i < bytes_received; i++)
{
printf("%02x ",data_in[i]);
}
printf("\n");
}
else
{
fprintf(stderr, "Error receiving Input report %d\n", result);
return result;
}
}
else
{
fprintf(stderr, "Error sending Input report %d\n", result);
return result;
}
return 0;
}
// Use interrupt transfers to to write data to the device and receive data from the device.
// Returns - zero on success, libusb error code on failure.
int exchange_input_and_output_reports_via_interrupt_transfers(libusb_device_handle *devh)
{
// Assumes interrupt endpoint 2 IN and OUT:
static const int INTERRUPT_IN_ENDPOINT = 0x81;
static const int INTERRUPT_OUT_ENDPOINT = 0x01;
// With firmware support, transfers can be > the endpoint's max packet size.
static const int MAX_INTERRUPT_IN_TRANSFER_SIZE = 2;
static const int MAX_INTERRUPT_OUT_TRANSFER_SIZE = 2;
int bytes_transferred;
int i = 0;
int result = 0;;
char data_in[MAX_INTERRUPT_IN_TRANSFER_SIZE];
char data_out[MAX_INTERRUPT_OUT_TRANSFER_SIZE];
// Store data in a buffer for sending.
for (i=0;i < MAX_INTERRUPT_OUT_TRANSFER_SIZE; i++)
{
data_out[i]=0x40+i;
}
// Write data to the device.
result = libusb_interrupt_transfer(
devh,
INTERRUPT_OUT_ENDPOINT,
data_out,
MAX_INTERRUPT_OUT_TRANSFER_SIZE,
&bytes_transferred,
TIMEOUT_MS);
if (result >= 0)
{
printf("Data sent via interrupt transfer:\n");
for(i = 0; i < bytes_transferred; i++)
{
printf("%02x ",data_out[i]);
}
printf("\n");
// Read data from the device.
result = libusb_interrupt_transfer(
devh,
INTERRUPT_IN_ENDPOINT,
data_in,
MAX_INTERRUPT_OUT_TRANSFER_SIZE,
&bytes_transferred,
TIMEOUT_MS);
if (result >= 0)
{
if (bytes_transferred > 0)
{
printf("Data received via interrupt transfer:\n");
for(i = 0; i < bytes_transferred; i++)
{
printf("%02x ",data_in[i]);
}
printf("\n");
}
else
{
fprintf(stderr, "No data received in interrupt transfer (%d)\n", result);
return -1;
}
}
else
{
fprintf(stderr, "Error receiving data via interrupt transfer %d\n", result);
return result;
}
}
else
{
fprintf(stderr, "Error sending data via interrupt transfer %d\n", result);
return result;
}
return 0;
}
