Page 81 - Linux Inside τ. 9

Basic HTML Version

Linux Inside
81
τις υπόλοιπες και επιτρέπει στο λειτουργικό να αντιστοιχίσει
τον κατάλληλο driver στη συσκευή για συσκευές με μη τυπο-
ποιημένη λειτουργικότητα. Επίσης, περιλαμβάνει μία λίστα
από Configuration Descriptors.
Configuration Descriptor:
Ο configuration descriptor πε-
ριγράφει παραμέτρους όπως τα σχετικά με την κατανάλωση
ρεύματος. Αν και οι περισσότερες συσκευές έχουν μόνο έναν
Configuration Descriptor, είναι δυνατόν μία συσκευή να έχει
και πάνω από έναν (π.χ., ένα Configuration για bus powered
και ένα για mains powered). Επίσης, περιλαμβάνει τη λίστα με
τα Interfaces που αντιστοιχούν στο Configuration.
Interface Descriptor:
Κάθε Interface μίας συσκευής αντι-
στοιχεί σε μία «τυποποιημένη λειτουργία» (class: π.χ., HID ή
Mass Storage). Μία συσκευή μπορεί να έχει πάνω από ένα
interface – π.χ., ένα πολυμηχάνημα μπορεί να έχει άλλο
interface για το σαρωτή, άλλο για τον εκτυπωτή και άλλο για
το fax, ή ένα τηλέφωνο μπορεί να είναι υλοποιημένο ως ένα
USB audio interface για τον ήχο και ένα USB και ένα USB HID
interface για τα keypad, LCD, buzzer κ.λπ. Το σημαντικότερο
κομμάτι ενός interface, φυσικά, είναι η λίστα με τα Endpoints.
Endpoint:
Μπορείτε να φανταστείτε ένα Endpoint σαν ένα
socket στο Unix. Κάθε φορά που κάποιος λέει «στέλνω ένα
πακέτο σε μία USB συσκευή», στην πραγματικότητα εννοεί ότι
στέλνει το πακέτο σε ένα συγκεκριμένο Endpoint της συσκευ-
ής. Δυστυχώς, ο χώρος του άρθρου αυτού δεν φτάνει για να
αναπτύξουμε επαρκώς τα Endpoints και τις κατηγορίες τους.
Οπότε, ας αρκεστούμε στο ότι υπάρχει πάντα τουλάχιστον
ένα Endpoint (το Endpoint #0), στο οποίο στέλνονται τα λεγό-
μενα πακέτα ελέγχου (control packets), μέσω των οποίων γί-
νεται η διαδικασία της απαρίθμησης που περιγράψαμε, μετα-
ξύ άλλων.
Φυσικά, τα παραπάνω αγγίζουν απλά την επιφάνεια του…
παγόβουνου όσον αφορά στο USB και τη λειτουργικότητα/ευ-
ελιξία του. Όποιος ενδιαφέρεται για ανάλυση σε περισσότερο
βάθος, μπορεί να απευθυνθεί στις πολύ κατατοπιστικές πη-
γές [6] και [7].
Η συσκευή μας
Όπως είπαμε, στόχος του άρθρου είναι να αναπτύξουμε
μία εικονική συσκευή με αρκετή λειτουργικότητα, ώστε να
περνά επιτυχώς από τη διαδικασία της απαρίθμησης
(enumeration) που αναφέραμε παραπάνω. Προηγουμένως
όμως, πρέπει να βεβαιωθούμε ότι η συσκευή ενσωματώνεται
σωστά και στην υποδομή του QEMU. Δηλαδή, αφενός πρέπει
το αρχείο της συσκευής να μεταγλωττίζεται κανονικά και αφε-
τέρου πρέπει να μπορούμε να ζητήσουμε να συμπεριληφθεί η
συσκευή μας σε μία εικονική μηχανή μέσω γραμμής εντολών,
με την παράμετρο -device (νέα μέθοδος καθορισμού συσκευ-
ών) ή/και με την παράμετρο -usbdevice (παλιά μέθοδος) κ.λπ.
Αυτά γενικά απλά συνεπάγονται την προσθήκη επιπλέον δε-
δομένων στο αρχείο του κώδικα της συσκευής μας. Οι παρά-
μετροι που επιλέξαμε για τη συσκευή είναι να έχει όνομα
dummyusb, να είναι USB 1.1 συσκευή, να έχει
VendorID=0xdead και ProductID=0xbeef, Version=1.0, ένα
μόνο Configuration, το οποίο θα είναι bus powered και να εί-
ναι προσβάσιμη από τη γραμμή εντολών με «-device usb-
dummy» ή «-usbdevice dummy».
Με βάση αυτές τις επιλογές, ο κώδικας της συσκευής μας
διαμορφώνεται ως εξής (δείτε τον πλήρη κώδικα στο
goo.gl/IYeEW):
#include "hw/hw.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
typedef struct USBDummyState {
USBDevice dev;
} USBDummyState;
enum {
STR_MANUFACTURER = 1,
STR_PRODUCT,
STR_SERIALNUMBER,
};
static const USBDescStrings desc_strings = {
[STR_MANUFACTURER] = "QEMU",
[STR_PRODUCT] = "USBDUMMY",
[STR_SERIALNUMBER] = "1",
};
static const VMStateDescription
vmstate_usb_dummy = {
.name = "usb-dummy",
.unmigratable = 1,
};
static const USBDescIface desc_iface_dummy = {
.bInterfaceNumber = 0,
.bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
};
static const USBDescDevice desc_device_dummy = {
.bcdUSB = 0x0110,
.bMaxPacketSize0 = 8,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
Linux Labs – QEMU
Η έξοδος του lsusb για τη συσκευή μας.
2