Page 82 - Linux Inside τ. 9

Basic HTML Version

Linux Inside
82
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = 0x80,
.bMaxPower = 40,
.nif = 1,
.ifs = &desc_iface_dummy,
},
},
};
static const USBDesc desc_usbdummy = {
.id = {
.idVendor = 0xdead,
.idProduct = 0xbeef,
.bcdDevice = 0x0100,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_dummy,
.str = desc_strings,
};
static int usb_dummy_initfn(USBDevice *dev)
{
usb_desc_create_serial(dev);
usb_desc_init(dev);
return 0;
}
static int usb_dummy_handle_control(
USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
{
int ret;
ret = usb_desc_handle_control(dev, p, request,
value, index,
length, data);
if (ret >= 0) {
return ret;
}
return 0;
}
static void usb_dummy_class_init(
ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->product_desc = "A dummy USB Device";
uc->usb_desc = &desc_usbdummy;
uc->init = usb_dummy_initfn;
uc->handle_control = usb_dummy_handle_control;
dc->desc = "Dummy USB Device for QEMU";
dc->vmsd = &vmstate_usb_dummy;
}
static TypeInfo dummy_info = {
.name = "usb-dummy",
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBDummyState),
.class_init = usb_dummy_class_init,
};
static void usb_dummy_register_types(void)
{
type_register_static(&dummy_info);
usb_legacy_register("usb-dummy", "dummy", NULL);
}
type_init(usb_dummy_register_types)
Όπως βλέπετε, ο κώδικας είναι ιδιαίτερα απλός και κατα-
νοητός. Δεν υπάρχουν καθόλου loops, nested ifs και γενικά
«αλγόριθμοι», αλλά απλή ανάθεση δεδομένων. Ίσως ο τρό-
πος που γίνεται η ανάθεση μέσα στις δομές να ξενίσει τους
τυχόν αρχάριους στη C. Αν ανήκετε σε αυτή την κατηγορία,
ψάξτε στο Google για «C99 static initializers». Ίσως παρατη-
ρήσατε ότι το στυλ αυτό προγραμματισμού με τις static δο-
μές και τους function pointers θυμίζει πολύ το πώς ο πυρήνας
Linux (και το GObject ως ένα βαθμό) επίσης υλοποιεί το
object model του και έχετε δίκιο, ο πυρήνας πιθανότατα ήταν
η πηγή έμπνευσης αυτού του μοντέλου.
Η base class του dummy device μας, μάλιστα (USBDevice),
περιλαμβάνει τον απαραίτητο κώδικα για να στείλει τους
descriptors στο host και έτσι απλά την επικαλούμαστε στη μέ-
θοδο:
usb_dummy_handle_control
(θυμηθείτε ότι control packets είναι τα πακέτα μέσω των
οποίων γίνεται η απαρίθμηση).
Κάτι άλλο που ίσως να ξενίσει είναι η δομή:
vmstate_usb_dummy
την οποία, όμως, μπορείτε να αγνοήσετε προς το παρόν
Linux Labs – QEMU
USB Interfaces και Linux
Η υλοποίηση της λειτουργικότητας μέσω τυποποιημένων
Interfaces βοηθά και στη γρηγορότερη υποστήριξη μίας συσκευής
στο Linux! Είναι σημαντικό να κατανοήσουμε ότι ένας «class
driver» στο Linux συνδέεται όχι με ένα USB Configuration ή Device,
αλλά με ένα Interface. Αυτό σημαίνει ότι ακόμα και για συσκευές
χωρίς πλήρη υποστήριξη μπορεί να υπάρχει driver για ένα από τα
Interfaces. Π.χ., ο γράφων πρόσφατα απέκτησε ένα USB VoIP τη-
λέφωνο της Crypto (στην πραγματικότητα, rebranded από τη
Yealink). Το τηλέφωνο αυτό είναι υλοποιημένο ως composite συ-
σκευή με δύο Interfaces: Audio και HID. Χωρίς να χρειαστεί καθό-
λου κώδικας, το Audio κομμάτι δούλεψε αμέσως με τον usb-audio
driver του Linux, καθιστώντας τη συσκευή εν μέρει λειτουργική και
μειώνοντας την απαιτούμενη ποσότητα reverse engineering! Κάτι
παρόμοιο συμβαίνει και με το μετρητή επιπέδων γλυκόζης, που
αποτελεί το τρέχον reverse engineering project του γράφοντος.
Το εργαλείο του USB.org για HID report descriptors.
3