/* * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of * this archive for more details. * * Copyright (C) 2006 Christian Limpach * Copyright (C) 2006 XenSource Ltd. * */ #include "vl.h" #include "block_int.h" static struct xs_handle *xsh = NULL; static char *hd_filename[MAX_DISKS]; static QEMUTimer *insert_timer = NULL; static int pasprintf(char **buf, const char *fmt, ...) { va_list ap; int ret = 0; if (*buf) free(*buf); va_start(ap, fmt); if (vasprintf(buf, fmt, ap) == -1) { buf = NULL; ret = -1; } va_end(ap); return ret; } static void insert_media(void *opaque) { int i; for (i = 0; i < MAX_DISKS; i++) { if (hd_filename[i]) { do_change(bs_table[i]->device_name, hd_filename[i]); free(hd_filename[i]); hd_filename[i] = NULL; } } } void xenstore_check_new_media_present(int timeout) { if (insert_timer == NULL) insert_timer = qemu_new_timer(rt_clock, insert_media, NULL); qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout); } void xenstore_parse_domain_config(int domid) { char **e = NULL; char *buf = NULL, *path; char *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL; int i; unsigned int len, num, hd_index; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; xsh = xs_daemon_open(); if (xsh == NULL) { fprintf(logfile, "Could not contact xenstore for domain config\n"); return; } path = xs_get_domain_path(xsh, domid); if (path == NULL) { fprintf(logfile, "xs_get_domain_path() error\n"); goto out; } if (pasprintf(&buf, "%s/device/vbd", path) == -1) goto out; e = xs_directory(xsh, XBT_NULL, buf, &num); if (e == NULL) goto out; for (i = 0; i < num; i++) { /* read the backend path */ if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1) continue; free(bpath); bpath = xs_read(xsh, XBT_NULL, buf, &len); if (bpath == NULL) continue; /* read the name of the device */ if (pasprintf(&buf, "%s/dev", bpath) == -1) continue; free(dev); dev = xs_read(xsh, XBT_NULL, buf, &len); if (dev == NULL) continue; if (strncmp(dev, "hd", 2) || strlen(dev) != 3) continue; hd_index = dev[2] - 'a'; if (hd_index >= MAX_DISKS) continue; /* read the type of the device */ if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1) continue; free(type); type = xs_read(xsh, XBT_NULL, buf, &len); /* read params to get the patch of the image -- read it last * so that we have its path in buf when setting up the * watch */ if (pasprintf(&buf, "%s/params", bpath) == -1) continue; free(params); params = xs_read(xsh, XBT_NULL, buf, &len); if (params == NULL) continue; if (params[0]) { hd_filename[hd_index] = params; /* strdup() */ params = NULL; /* don't free params on re-use */ } bs_table[hd_index] = bdrv_new(dev); /* check if it is a cdrom */ if (type && !strcmp(type, "cdrom")) { bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM); xs_watch(xsh, buf, dev); } if (hd_filename[hd_index]) { if (bdrv_open(bs_table[hd_index], hd_filename[hd_index], 0 /* snapshot */) < 0) fprintf(stderr, "qemu: could not open hard disk image '%s'\n", hd_filename[hd_index]); } } out: free(type); free(params); free(dev); free(bpath); free(buf); free(path); free(e); return; } int xenstore_fd(void) { if (xsh) return xs_fileno(xsh); return -1; } void xenstore_process_event(void *opaque) { char **vec, *image = NULL; unsigned int len, num, hd_index; vec = xs_read_watch(xsh, &num); if (!vec) return; if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) || strlen(vec[XS_WATCH_TOKEN]) != 3) goto out; hd_index = vec[XS_WATCH_TOKEN][2] - 'a'; image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len); if (image == NULL || !strcmp(image, bs_table[hd_index]->filename)) goto out; /* gone or identical */ do_eject(0, vec[XS_WATCH_TOKEN]); bs_table[hd_index]->filename[0] = 0; if (hd_filename[hd_index]) { free(hd_filename[hd_index]); hd_filename[hd_index] = NULL; } if (image[0]) { hd_filename[hd_index] = strdup(image); xenstore_check_new_media_present(5000); } out: free(image); free(vec); } void xenstore_write_vncport(int display) { char *buf = NULL, *path; char *portstr = NULL; if (xsh == NULL) return; path = xs_get_domain_path(xsh, domid); if (path == NULL) { fprintf(logfile, "xs_get_domain_path() error\n"); goto out; } if (pasprintf(&buf, "%s/console/vnc-port", path) == -1) goto out; if (pasprintf(&portstr, "%d", 5900 + display) == -1) goto out; if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0) fprintf(logfile, "xs_write() vncport failed\n"); out: free(portstr); free(buf); } int xenstore_read_vncpasswd(int domid) { extern char vncpasswd[64]; char *buf = NULL, *path, *uuid = NULL, *passwd = NULL; unsigned int i, len, rc = 0; if (xsh == NULL) { return -1; } path = xs_get_domain_path(xsh, domid); if (path == NULL) { fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid); return -1; } pasprintf(&buf, "%s/vm", path); uuid = xs_read(xsh, XBT_NULL, buf, &len); if (uuid == NULL) { fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf); free(path); return -1; } pasprintf(&buf, "%s/vncpasswd", uuid); passwd = xs_read(xsh, XBT_NULL, buf, &len); if (passwd == NULL) { fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf); free(uuid); free(path); return rc; } for (i=0; i196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
#include <stdint.h>
#include "USBHID.h"
#include "USBHID_Types.h"
#include "USBDescriptor.h"
#include "HIDKeyboard.h"

#define DEFAULT_CONFIGURATION (1)


HIDKeyboard::HIDKeyboard(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release)
{
    USBDevice::connect();
}

bool HIDKeyboard::sendReport(report_keyboard_t report) {
    USBDevice::write(EP1IN, report.raw, sizeof(report), MAX_PACKET_SIZE_EP1);
    return true;
}

uint8_t HIDKeyboard::leds() {
    return led_state;
}

bool HIDKeyboard::USBCallback_setConfiguration(uint8_t configuration) {
    if (configuration != DEFAULT_CONFIGURATION) {
        return false;
    }

    // Configure endpoints > 0
    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
    //addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);

    // We activate the endpoint to be able to recceive data
    //readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
    return true;
}


uint8_t * HIDKeyboard::stringImanufacturerDesc() {
    static uint8_t stringImanufacturerDescriptor[] = {
        0x18,                                            /*bLength*/
        STRING_DESCRIPTOR,                               /*bDescriptorType 0x03*/
        't',0,'m',0,'k',0,'-',0,'k',0,'b',0,'d',0,'.',0,'c',0,'o',0,'m',0   /*bString iManufacturer*/
    };
    return stringImanufacturerDescriptor;
}

uint8_t * HIDKeyboard::stringIproductDesc() {
    static uint8_t stringIproductDescriptor[] = {
        0x0a,                                                       /*bLength*/
        STRING_DESCRIPTOR,                                          /*bDescriptorType 0x03*/
        'm',0,'b',0,'e',0,'d',0                                     /*bString iProduct*/
    };
    return stringIproductDescriptor;
}

uint8_t * HIDKeyboard::stringIserialDesc() {
    static uint8_t stringIserialDescriptor[] = {
        0x04,                                                           /*bLength*/
        STRING_DESCRIPTOR,                                              /*bDescriptorType 0x03*/
        '0',0                                                           /*bString iSerial*/
    };
    return stringIserialDescriptor;
}

uint8_t * HIDKeyboard::reportDesc() {
    static uint8_t reportDescriptor[] = {
        USAGE_PAGE(1), 0x01,                    // Generic Desktop
        USAGE(1), 0x06,                         // Keyboard
        COLLECTION(1), 0x01,                    // Application

        USAGE_PAGE(1), 0x07,                    // Key Codes
        USAGE_MINIMUM(1), 0xE0,
        USAGE_MAXIMUM(1), 0xE7,
        LOGICAL_MINIMUM(1), 0x00,
        LOGICAL_MAXIMUM(1), 0x01,
        REPORT_SIZE(1), 0x01,
        REPORT_COUNT(1), 0x08,
        INPUT(1), 0x02,                         // Data, Variable, Absolute

        REPORT_COUNT(1), 0x01,
        REPORT_SIZE(1), 0x08,
        INPUT(1), 0x01,                         // Constant

        REPORT_COUNT(1), 0x05,
        REPORT_SIZE(1), 0x01,
        USAGE_PAGE(1), 0x08,                    // LEDs
        USAGE_MINIMUM(1), 0x01,
        USAGE_MAXIMUM(1), 0x05,
        OUTPUT(1), 0x02,                        // Data, Variable, Absolute

        REPORT_COUNT(1), 0x01,
        REPORT_SIZE(1), 0x03,
        OUTPUT(1), 0x01,                        // Constant


        REPORT_COUNT(1), 0x06,
        REPORT_SIZE(1), 0x08,
        LOGICAL_MINIMUM(1), 0x00,
        LOGICAL_MAXIMUM(1), 0xFF,
        USAGE_PAGE(1), 0x07,                    // Key Codes
        USAGE_MINIMUM(1), 0x00,
        USAGE_MAXIMUM(1), 0xFF,
        INPUT(1), 0x00,                         // Data, Array
        END_COLLECTION(0),
    };
    reportLength = sizeof(reportDescriptor);
    return reportDescriptor;
}

uint16_t HIDKeyboard::reportDescLength() {
    reportDesc();
    return reportLength;
}

#define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
                               + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
                               + (1 * HID_DESCRIPTOR_LENGTH) \
                               + (1 * ENDPOINT_DESCRIPTOR_LENGTH))
uint8_t * HIDKeyboard::configurationDesc() {
    static uint8_t configurationDescriptor[] = {
        CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
        CONFIGURATION_DESCRIPTOR,       // bDescriptorType
        LSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (LSB)
        MSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (MSB)
        0x01,                           // bNumInterfaces
        DEFAULT_CONFIGURATION,          // bConfigurationValue
        0x00,                           // iConfiguration
        C_RESERVED | C_REMOTE_WAKEUP,   // bmAttributes
        C_POWER(100),                   // bMaxPowerHello World from Mbed

        INTERFACE_DESCRIPTOR_LENGTH,    // bLength
        INTERFACE_DESCRIPTOR,           // bDescriptorType
        0x00,                           // bInterfaceNumber
        0x00,                           // bAlternateSetting
        0x01,                           // bNumEndpoints
        HID_CLASS,                      // bInterfaceClass
        1,                              // bInterfaceSubClass (boot)
        1,                              // bInterfaceProtocol (keyboard)
        0x00,                           // iInterface

        HID_DESCRIPTOR_LENGTH,          // bLength
        HID_DESCRIPTOR,                 // bDescriptorType
        LSB(HID_VERSION_1_11),          // bcdHID (LSB)
        MSB(HID_VERSION_1_11),          // bcdHID (MSB)
        0x00,                           // bCountryCode
        0x01,                           // bNumDescriptors
        REPORT_DESCRIPTOR,              // bDescriptorType
        (uint8_t)(LSB(reportDescLength())),  // wDescriptorLength (LSB)
        (uint8_t)(MSB(reportDescLength())),  // wDescriptorLength (MSB)

        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
        ENDPOINT_DESCRIPTOR,            // bDescriptorType
        PHY_TO_DESC(EP1IN),             // bEndpointAddress
        E_INTERRUPT,                    // bmAttributes
        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
        1,                           // bInterval (milliseconds)
    };
    return configurationDescriptor;
}

#if 0
uint8_t * HIDKeyboard::deviceDesc() {
    static uint8_t deviceDescriptor[] = {
        DEVICE_DESCRIPTOR_LENGTH,       /* bLength */
        DEVICE_DESCRIPTOR,              /* bDescriptorType */
        LSB(USB_VERSION_2_0),           /* bcdUSB (LSB) */
        MSB(USB_VERSION_2_0),           /* bcdUSB (MSB) */
        0x00,                           /* bDeviceClass */
        0x00,                           /* bDeviceSubClass */
        0x00,                           /* bDeviceprotocol */
        MAX_PACKET_SIZE_EP0,            /* bMaxPacketSize0 */
        (uint8_t)(LSB(0xfeed)),                 /* idVendor (LSB) */
        (uint8_t)(MSB(0xfeed)),                 /* idVendor (MSB) */
        (uint8_t)(LSB(0x1bed)),                /* idProduct (LSB) */
        (uint8_t)(MSB(0x1bed)),                /* idProduct (MSB) */
        (uint8_t)(LSB(0x0002)),           /* bcdDevice (LSB) */
        (uint8_t)(MSB(0x0002)),           /* bcdDevice (MSB) */
        0,    /* iManufacturer */
        0,         /* iProduct */
        0,          /* iSerialNumber */
        0x01                            /* bNumConfigurations */
    };
    return deviceDescriptor;
}
#endif

bool HIDKeyboard::USBCallback_request() {
    bool success = false;
    CONTROL_TRANSFER * transfer = getTransferPtr();
    uint8_t *hidDescriptor;

    // Process additional standard requests

    if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
    {
        switch (transfer->setup.bRequest)
        {
            case GET_DESCRIPTOR:
                switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
                {
                    case REPORT_DESCRIPTOR:
                        if ((reportDesc() != NULL) \
                            && (reportDescLength() != 0))
                        {
                            transfer->remaining = reportDescLength();
                            transfer->ptr = reportDesc();
                            transfer->direction = DEVICE_TO_HOST;
                            success = true;
                        }
                        break;
                    case HID_DESCRIPTOR:
                            // Find the HID descriptor, after the configuration descriptor
                            hidDescriptor = findDescriptor(HID_DESCRIPTOR);
                            if (hidDescriptor != NULL)
                            {
                                transfer->remaining = HID_DESCRIPTOR_LENGTH;
                                transfer->ptr = hidDescriptor;
                                transfer->direction = DEVICE_TO_HOST;
                                success = true;
                            }
                            break;
                     
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }

    // Process class-specific requests
    if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
    {
        switch (transfer->setup.bRequest) {
            case SET_REPORT:
                // LED indicator
                // TODO: check Interface and Report length?
                // if (transfer->setup.wIndex == INTERFACE_KEYBOAD) { }
                // if (transfer->setup.wLength == 1)

                transfer->remaining = 1;
                //transfer->ptr = ?? what ptr should be set when OUT(not used?)
                transfer->direction = HOST_TO_DEVICE;
                transfer->notify = true;    /* notify with USBCallback_requestCompleted */
                success = true;
            default:
                break;
        }
    }

    return success;
}

void HIDKeyboard::USBCallback_requestCompleted(uint8_t * buf, uint32_t length)
{
    if (length > 0) {
        CONTROL_TRANSFER *transfer = getTransferPtr();
        if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
            switch (transfer->setup.bRequest) {
                case SET_REPORT:
                    led_state = buf[0];
                    break;
                default:
                    break;
            }
        }
    }
}