Ranran <ransha...@gmail.com> writes:

> Hello,
>
> From my reading about HID gadget driver (hidg), it seems that it
> support input reports, but not get/set features.
> This is my understanding from the documentation:
> https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt
>
> Is that correct ?

you might wanna read the actual implementation, instead. If you're keen,
please update the documentation where it's lacking.

static int hidg_setup(struct usb_function *f,
                const struct usb_ctrlrequest *ctrl)
{
        struct f_hidg                   *hidg = func_to_hidg(f);
        struct usb_composite_dev        *cdev = f->config->cdev;
        struct usb_request              *req  = cdev->req;
        int status = 0;
        __u16 value, length;

        value   = __le16_to_cpu(ctrl->wValue);
        length  = __le16_to_cpu(ctrl->wLength);

        VDBG(cdev,
             "%s crtl_request : bRequestType:0x%x bRequest:0x%x Value:0x%x\n",
             __func__, ctrl->bRequestType, ctrl->bRequest, value);

        switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
        case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
                  | HID_REQ_GET_REPORT):
                VDBG(cdev, "get_report\n");

                /* send an empty report */
                length = min_t(unsigned, length, hidg->report_length);
                memset(req->buf, 0x0, length);

                goto respond;
                break;

        case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
                  | HID_REQ_GET_PROTOCOL):
                VDBG(cdev, "get_protocol\n");
                length = min_t(unsigned int, length, 1);
                ((u8 *) req->buf)[0] = hidg->protocol;
                goto respond;
                break;

        case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
                  | HID_REQ_SET_REPORT):
                VDBG(cdev, "set_report | wLength=%d\n", ctrl->wLength);
                goto stall;
                break;

        case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
                  | HID_REQ_SET_PROTOCOL):
                VDBG(cdev, "set_protocol\n");
                if (value > HID_REPORT_PROTOCOL)
                        goto stall;
                length = 0;
                /*
                 * We assume that programs implementing the Boot protocol
                 * are also compatible with the Report Protocol
                 */
                if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
                        hidg->protocol = value;
                        goto respond;
                }
                goto stall;
                break;

        case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
                  | USB_REQ_GET_DESCRIPTOR):
                switch (value >> 8) {
                case HID_DT_HID:
                {
                        struct hid_descriptor hidg_desc_copy = hidg_desc;

                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
                        hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT;
                        hidg_desc_copy.desc[0].wDescriptorLength =
                                cpu_to_le16(hidg->report_desc_length);

                        length = min_t(unsigned short, length,
                                                   hidg_desc_copy.bLength);
                        memcpy(req->buf, &hidg_desc_copy, length);
                        goto respond;
                        break;
                }
                case HID_DT_REPORT:
                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
                        length = min_t(unsigned short, length,
                                                   hidg->report_desc_length);
                        memcpy(req->buf, hidg->report_desc, length);
                        goto respond;
                        break;

                default:
                        VDBG(cdev, "Unknown descriptor request 0x%x\n",
                                 value >> 8);
                        goto stall;
                        break;
                }
                break;

        default:
                VDBG(cdev, "Unknown request 0x%x\n",
                         ctrl->bRequest);
                goto stall;
                break;
        }

stall:
        return -EOPNOTSUPP;

respond:
        req->zero = 0;
        req->length = length;
        status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
        if (status < 0)
                ERROR(cdev, "usb_ep_queue error on ep0 %d\n", value);
        return status;
}

-- 
balbi

Attachment: signature.asc
Description: PGP signature

Reply via email to