Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1b50653 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "defconfig: msm: Enable USB HID driver on MSM8996 Auto"

parents ac0b1cb2 63af97f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -461,6 +461,7 @@ CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
+1 −0
Original line number Diff line number Diff line
@@ -465,6 +465,7 @@ CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
+168 −29
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct f_hidg {
	/* configuration */
	unsigned char			bInterfaceSubClass;
	unsigned char			bInterfaceProtocol;
	unsigned char			protocol;
	unsigned short			report_desc_length;
	char				*report_desc;
	unsigned short			report_length;
@@ -98,6 +99,60 @@ static struct hid_descriptor hidg_desc = {
	/*.desc[0].wDescriptorLenght	= DYNAMIC */
};

/* Super-Speed Support */

static struct usb_endpoint_descriptor hidg_ss_in_ep_desc = {
	.bLength		= USB_DT_ENDPOINT_SIZE,
	.bDescriptorType	= USB_DT_ENDPOINT,
	.bEndpointAddress	= USB_DIR_IN,
	.bmAttributes		= USB_ENDPOINT_XFER_INT,
	/*.wMaxPacketSize	= DYNAMIC */
	.bInterval		= 4, /* FIXME: Add this field in the
				      * HID gadget configuration?
				      * (struct hidg_func_descriptor)
				      */
};

static struct usb_ss_ep_comp_descriptor hidg_ss_in_comp_desc = {
	.bLength                = sizeof(hidg_ss_in_comp_desc),
	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,

	/* .bMaxBurst           = 0, */
	/* .bmAttributes        = 0, */
	/* .wBytesPerInterval   = DYNAMIC */
};

static struct usb_endpoint_descriptor hidg_ss_out_ep_desc = {
	.bLength		= USB_DT_ENDPOINT_SIZE,
	.bDescriptorType	= USB_DT_ENDPOINT,
	.bEndpointAddress	= USB_DIR_OUT,
	.bmAttributes		= USB_ENDPOINT_XFER_INT,
	/*.wMaxPacketSize	= DYNAMIC */
	.bInterval		= 4, /* FIXME: Add this field in the
				      * HID gadget configuration?
				      * (struct hidg_func_descriptor)
				      */
};

static struct usb_ss_ep_comp_descriptor hidg_ss_out_comp_desc = {
	.bLength                = sizeof(hidg_ss_out_comp_desc),
	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,

	/* .bMaxBurst           = 0, */
	/* .bmAttributes        = 0, */
	/* .wBytesPerInterval   = DYNAMIC */
};

static struct usb_descriptor_header *hidg_ss_descriptors[] = {
	(struct usb_descriptor_header *)&hidg_interface_desc,
	(struct usb_descriptor_header *)&hidg_desc,
	(struct usb_descriptor_header *)&hidg_ss_in_ep_desc,
	(struct usb_descriptor_header *)&hidg_ss_in_comp_desc,
	(struct usb_descriptor_header *)&hidg_ss_out_ep_desc,
	(struct usb_descriptor_header *)&hidg_ss_out_comp_desc,
	NULL,
};

/* High-Speed Support */

static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
@@ -284,6 +339,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
			    size_t count, loff_t *offp)
{
	struct f_hidg *hidg  = file->private_data;
	struct usb_request *req;
	unsigned long flags;
	ssize_t status = -ENOMEM;

@@ -293,7 +349,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
	spin_lock_irqsave(&hidg->write_spinlock, flags);

#define WRITE_COND (!hidg->write_pending)

try_again:
	/* write queue */
	while (!WRITE_COND) {
		spin_unlock_irqrestore(&hidg->write_spinlock, flags);
@@ -308,10 +364,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
	}

	hidg->write_pending = 1;
	req = hidg->req;
	count  = min_t(unsigned, count, hidg->report_length);

	spin_unlock_irqrestore(&hidg->write_spinlock, flags);
	status = copy_from_user(hidg->req->buf, buffer, count);
	status = copy_from_user(req->buf, buffer, count);

	if (status != 0) {
		ERROR(hidg->func.config->cdev,
@@ -320,24 +377,38 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
		goto release_write_pending;
	}

	hidg->req->status   = 0;
	hidg->req->zero     = 0;
	hidg->req->length   = count;
	hidg->req->complete = f_hidg_req_complete;
	hidg->req->context  = hidg;
	spin_lock_irqsave(&hidg->write_spinlock, flags);

	status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
	/* when our function has been disabled by host */
	if (!hidg->req) {
		free_ep_req(hidg->in_ep, req);
		/*
		 * TODO
		 * Should we fail with error here?
		 */
		goto try_again;
	}

	req->status   = 0;
	req->zero     = 0;
	req->length   = count;
	req->complete = f_hidg_req_complete;
	req->context  = hidg;

	status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC);
	if (status < 0) {
		ERROR(hidg->func.config->cdev,
			"usb_ep_queue error on int endpoint %zd\n", status);
		goto release_write_pending;
		goto release_write_pending_unlocked;
	} else {
		status = count;
	}
	spin_unlock_irqrestore(&hidg->write_spinlock, flags);

	return status;
release_write_pending:
	spin_lock_irqsave(&hidg->write_spinlock, flags);
release_write_pending_unlocked:
	hidg->write_pending = 0;
	spin_unlock_irqrestore(&hidg->write_spinlock, flags);

@@ -457,7 +528,9 @@ static int hidg_setup(struct usb_function *f,
	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
		  | HID_REQ_GET_PROTOCOL):
		VDBG(cdev, "get_protocol\n");
		goto stall;
		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
@@ -469,6 +542,17 @@ static int hidg_setup(struct usb_function *f,
	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;

@@ -541,12 +625,23 @@ static void hidg_disable(struct usb_function *f)
		kfree(list);
	}
	spin_unlock_irqrestore(&hidg->read_spinlock, flags);

	spin_lock_irqsave(&hidg->write_spinlock, flags);
	if (!hidg->write_pending) {
		free_ep_req(hidg->in_ep, hidg->req);
		hidg->write_pending = 1;
	}

	hidg->req = NULL;
	spin_unlock_irqrestore(&hidg->write_spinlock, flags);
}

static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
	struct usb_composite_dev		*cdev = f->config->cdev;
	struct f_hidg				*hidg = func_to_hidg(f);
	struct usb_request			*req_in = NULL;
	unsigned long				flags;
	int i, status = 0;

	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -567,6 +662,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			goto fail;
		}
		hidg->in_ep->driver_data = hidg;

		req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length);
		if (!req_in) {
			status = -ENOMEM;
			goto disable_ep_in;
		}
	}


@@ -578,12 +679,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
					    hidg->out_ep);
		if (status) {
			ERROR(cdev, "config_ep_by_speed FAILED!\n");
			goto fail;
			goto free_req_in;
		}
		status = usb_ep_enable(hidg->out_ep);
		if (status < 0) {
			ERROR(cdev, "Enable OUT endpoint FAILED!\n");
			goto fail;
			goto free_req_in;
		}
		hidg->out_ep->driver_data = hidg;

@@ -599,17 +700,37 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
				req->context  = hidg;
				status = usb_ep_queue(hidg->out_ep, req,
						      GFP_ATOMIC);
				if (status)
				if (status) {
					ERROR(cdev, "%s queue req --> %d\n",
						hidg->out_ep->name, status);
					free_ep_req(hidg->out_ep, req);
				}
			} else {
				usb_ep_disable(hidg->out_ep);
				status = -ENOMEM;
				goto fail;
				goto disable_out_ep;
			}
		}
	}

	if (hidg->in_ep != NULL) {
		spin_lock_irqsave(&hidg->write_spinlock, flags);
		hidg->req = req_in;
		hidg->write_pending = 0;
		spin_unlock_irqrestore(&hidg->write_spinlock, flags);

		wake_up(&hidg->write_queue);
	}
	return 0;
disable_out_ep:
	usb_ep_disable(hidg->out_ep);
free_req_in:
	if (req_in)
		free_ep_req(hidg->in_ep, req_in);

disable_ep_in:
	if (hidg->in_ep)
		usb_ep_disable(hidg->in_ep);

fail:
	return status;
}
@@ -658,17 +779,18 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
		goto fail;
	hidg->out_ep = ep;

	/* preallocate request and buffer */
	status = -ENOMEM;
	hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length);
	if (!hidg->req)
		goto fail;

	/* set descriptor dynamic values */
	hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
	hidg->protocol = HID_REPORT_PROTOCOL;
	hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_ss_in_comp_desc.wBytesPerInterval =
				cpu_to_le16(hidg->report_length);
	hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_ss_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_ss_out_comp_desc.wBytesPerInterval =
				cpu_to_le16(hidg->report_length);
	hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	/*
@@ -684,12 +806,19 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
	hidg_hs_out_ep_desc.bEndpointAddress =
		hidg_fs_out_ep_desc.bEndpointAddress;

	hidg_ss_in_ep_desc.bEndpointAddress =
		hidg_fs_in_ep_desc.bEndpointAddress;
	hidg_ss_out_ep_desc.bEndpointAddress =
		hidg_fs_out_ep_desc.bEndpointAddress;

	status = usb_assign_descriptors(f, hidg_fs_descriptors,
			hidg_hs_descriptors, NULL);
			hidg_hs_descriptors, hidg_ss_descriptors);
	if (status)
		goto fail;

	spin_lock_init(&hidg->write_spinlock);
	hidg->write_pending = 1;
	hidg->req = NULL;
	spin_lock_init(&hidg->read_spinlock);
	init_waitqueue_head(&hidg->write_queue);
	init_waitqueue_head(&hidg->read_queue);
@@ -883,7 +1012,7 @@ static void hidg_free_inst(struct usb_function_instance *f)
	mutex_lock(&hidg_ida_lock);

	hidg_put_minor(opts->minor);
	if (idr_is_empty(&hidg_ida.idr))
	if (ida_is_empty(&hidg_ida))
		ghid_cleanup();

	mutex_unlock(&hidg_ida_lock);
@@ -909,7 +1038,7 @@ static struct usb_function_instance *hidg_alloc_inst(void)

	mutex_lock(&hidg_ida_lock);

	if (idr_is_empty(&hidg_ida.idr)) {
	if (ida_is_empty(&hidg_ida)) {
		status = ghid_setup(NULL, HIDG_MINORS);
		if (status)  {
			ret = ERR_PTR(status);
@@ -922,7 +1051,7 @@ static struct usb_function_instance *hidg_alloc_inst(void)
	if (opts->minor < 0) {
		ret = ERR_PTR(opts->minor);
		kfree(opts);
		if (idr_is_empty(&hidg_ida.idr))
		if (ida_is_empty(&hidg_ida))
			ghid_cleanup();
		goto unlock;
	}
@@ -954,10 +1083,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
	device_destroy(hidg_class, MKDEV(major, hidg->minor));
	cdev_del(&hidg->cdev);

	/* disable/free request and end point */
	usb_ep_disable(hidg->in_ep);
	free_ep_req(hidg->in_ep, hidg->req);

	usb_free_all_descriptors(f);
}

@@ -1009,6 +1134,20 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
}

DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);

static int __init afunc_init(void)
{
	return usb_function_register(&hidusb_func);
}

static void __exit afunc_exit(void)
{
	usb_function_unregister(&hidusb_func);
}

module_init(afunc_init);
module_exit(afunc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabien Chouteau");

+3 −3
Original line number Diff line number Diff line
@@ -1269,7 +1269,7 @@ static void gprinter_free_inst(struct usb_function_instance *f)
	mutex_lock(&printer_ida_lock);

	gprinter_put_minor(opts->minor);
	if (idr_is_empty(&printer_ida.idr))
	if (ida_is_empty(&printer_ida))
		gprinter_cleanup();

	mutex_unlock(&printer_ida_lock);
@@ -1293,7 +1293,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void)

	mutex_lock(&printer_ida_lock);

	if (idr_is_empty(&printer_ida.idr)) {
	if (ida_is_empty(&printer_ida)) {
		status = gprinter_setup(PRINTER_MINORS);
		if (status) {
			ret = ERR_PTR(status);
@@ -1306,7 +1306,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void)
	if (opts->minor < 0) {
		ret = ERR_PTR(opts->minor);
		kfree(opts);
		if (idr_is_empty(&printer_ida.idr))
		if (ida_is_empty(&printer_ida))
			gprinter_cleanup();
		goto unlock;
	}
+6 −0
Original line number Diff line number Diff line
@@ -344,6 +344,12 @@ struct hid_item {
#define HID_GROUP_WACOM				0x0101
#define HID_GROUP_LOGITECH_DJ_DEVICE		0x0102

/*
 * HID protocol status
 */
#define HID_REPORT_PROTOCOL	1
#define HID_BOOT_PROTOCOL	0

/*
 * This is the global environment of the parser. This information is
 * persistent for main-items. The global environment can be saved and
Loading