static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)

{

    struct usbdevfs_urb *urb;

    AsyncURB *aurb;

    int ret, value, index;



    /* 

     * Process certain standard device requests.

     * These are infrequent and are processed synchronously.

     */

    value = le16_to_cpu(s->ctrl.req.wValue);

    index = le16_to_cpu(s->ctrl.req.wIndex);



    dprintf("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",

        s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index, 

        s->ctrl.len);



    if (s->ctrl.req.bRequestType == 0) {

        switch (s->ctrl.req.bRequest) {

        case USB_REQ_SET_ADDRESS:

            return usb_host_set_address(s, value);



        case USB_REQ_SET_CONFIGURATION:

            return usb_host_set_config(s, value & 0xff);

        }

    }



    if (s->ctrl.req.bRequestType == 1 &&

                  s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE)

        return usb_host_set_interface(s, index, value);



    /* The rest are asynchronous */



    aurb = async_alloc();

    aurb->hdev   = s;

    aurb->packet = p;



    /* 

     * Setup ctrl transfer.

     *

     * s->ctrl is layed out such that data buffer immediately follows

     * 'req' struct which is exactly what usbdevfs expects.

     */ 

    urb = &aurb->urb;



    urb->type     = USBDEVFS_URB_TYPE_CONTROL;

    urb->endpoint = p->devep;



    urb->buffer        = &s->ctrl.req;

    urb->buffer_length = 8 + s->ctrl.len;



    urb->usercontext = s;



    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);



    dprintf("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);



    if (ret < 0) {

        dprintf("husb: submit failed. errno %d\n", errno);

        async_free(aurb);



        switch(errno) {

        case ETIMEDOUT:

            return USB_RET_NAK;

        case EPIPE:

        default:

            return USB_RET_STALL;

        }

    }



    usb_defer_packet(p, async_cancel, aurb);

    return USB_RET_ASYNC;

}
