Re: [PATCH 1/3] ANDROID: usb: gadget: f_accessory: Add Android Accessory function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

rickyniu <rickyniu@xxxxxxxxxx> writes:
> From: Benoit Goby <benoit@xxxxxxxxxxx>

missing Signed-off-by for author

> USB accessory mode allows users to connect USB host hardware
> specifically designed for Android-powered devices. The accessories
> must adhere to the Android accessory protocol outlined in the
> http://accessories.android.com documentation. This allows
> Android devices that cannot act as a USB host to still interact with
> USB hardware. When an Android device is in USB accessory mode, the
> attached Android USB accessory acts as the host, provides power
> to the USB bus, and enumerates connected devices.

The protocol is still a HID protocol, is it? Why couldn't you use f_hid.c?

> Signed-off-by: Mike Lockwood <lockwood@xxxxxxxxxxx>
> [AmitP: Folded following android-4.9 commit changes into this patch
>         ceb2f0aac624 ("ANDROID: usb: gadget: accessory: Fix section mismatch")
>         Parts of e27543931009 ("ANDROID: usb: gadget: Fixes and hacks to make android usb gadget compile on 3.8")
>         1b07ec751563 ("ANDROID: drivers: usb: gadget: 64-bit related type fixes")]
> Signed-off-by: Amit Pundir <amit.pundir@xxxxxxxxxx>
> [astrachan: Folded the following changes into this patch:
>             9d5891d516e2 ("ANDROID: usb: gadget: f_accessory: Add ACCESSORY_SET_AUDIO_MODE control request and ioctl")
>             dc66cfce9622 ("ANDROID: usb: gadget: f_accessory: Add support for HID input devices")
>             5f1ac9c2871b ("ANDROID: usb: gadget: f_accessory: move userspace interface to uapi")
>             9a6241722cd8 ("ANDROID: usb: gadget: f_accessory: Enabled Zero Length Packet (ZLP) for acc_write")
>             31a0ecd5a825 ("ANDROID: usb: gadget: f_accessory: check for accessory device before disconnecting HIDs")
>             580721fa6cbc ("ANDROID: usb: gadget: f_accessory: Migrate to USB_FUNCTION API")
>             7f407172fb28 ("ANDROID: usb: gadget: f_accessory: Fix for UsbAccessory clean unbind.")
>             ebc98ac5a22f ("ANDROID: usb: gadget: f_accessory: fix false disconnect due to a signal sent to the reading process")
>             71c6dc5ffdab ("ANDROID: usb: gadget: f_accessory: assign no-op request complete callbacks")
>             675047ee68e9 ("ANDROID: usb: gadget: f_accessory: Move gadget functions code")
>             b2bedaa5c7df ("CHROMIUM: usb: gadget: f_accessory: add .raw_request callback")]
> Signed-off-by: Alistair Strachan <astrachan@xxxxxxxxxx>
> Signed-off-by: rickyniu <rickyniu@xxxxxxxxxx>

We need an actual name here, IIRC.

> diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
> new file mode 100644
> index 000000000000..514eadee1793
> --- /dev/null
> +++ b/drivers/usb/gadget/function/f_accessory.c
> @@ -0,0 +1,1352 @@

missing SPDX license identifier comment

> +/*
> + * Gadget Function Driver for Android USB accessories
> + *
> + * Copyright (C) 2011 Google, Inc.
> + * Author: Mike Lockwood <lockwood@xxxxxxxxxxx>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +/* #define DEBUG */
> +/* #define VERBOSE_DEBUG */

these shouldn't be necessary

> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/poll.h>
> +#include <linux/delay.h>
> +#include <linux/wait.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/kthread.h>
> +#include <linux/freezer.h>
> +
> +#include <linux/types.h>
> +#include <linux/file.h>
> +#include <linux/device.h>
> +#include <linux/miscdevice.h>
> +
> +#include <linux/hid.h>
> +#include <linux/hiddev.h>
>
> +#include <linux/usb.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/f_accessory.h>
> +
> +#include <linux/configfs.h>
> +#include <linux/usb/composite.h>
> +
> +#define MAX_INST_NAME_LEN        40
> +#define BULK_BUFFER_SIZE    16384
> +#define ACC_STRING_SIZE     256
> +
> +#define PROTOCOL_VERSION    2
> +
> +/* String IDs */
> +#define INTERFACE_STRING_INDEX	0
> +
> +/* number of tx and rx requests to allocate */
> +#define TX_REQ_MAX 4
> +#define RX_REQ_MAX 2
> +
> +struct acc_hid_dev {
> +	struct list_head	list;
> +	struct hid_device *hid;
> +	struct acc_dev *dev;
> +	/* accessory defined ID */
> +	int id;
> +	/* HID report descriptor */
> +	u8 *report_desc;
> +	/* length of HID report descriptor */
> +	int report_desc_len;
> +	/* number of bytes of report_desc we have received so far */
> +	int report_desc_offset;
> +};
> +
> +struct acc_dev {
> +	struct usb_function function;
> +	struct usb_composite_dev *cdev;
> +	spinlock_t lock;
> +
> +	struct usb_ep *ep_in;
> +	struct usb_ep *ep_out;
> +
> +	/* online indicates state of function_set_alt & function_unbind
> +	 * set to 1 when we connect
> +	 */

wrong multi-line comment style

> +	int online:1;
> +
> +	/* disconnected indicates state of open & release
> +	 * Set to 1 when we disconnect.
> +	 * Not cleared until our file is closed.
> +	 */
> +	int disconnected:1;
> +
> +	/* strings sent by the host */
> +	char manufacturer[ACC_STRING_SIZE];
> +	char model[ACC_STRING_SIZE];
> +	char description[ACC_STRING_SIZE];
> +	char version[ACC_STRING_SIZE];
> +	char uri[ACC_STRING_SIZE];
> +	char serial[ACC_STRING_SIZE];
> +
> +	/* for acc_complete_set_string */
> +	int string_index;
> +
> +	/* set to 1 if we have a pending start request */
> +	int start_requested;
> +
> +	int audio_mode;
> +
> +	/* synchronize access to our device file */
> +	atomic_t open_excl;
> +
> +	struct list_head tx_idle;
> +
> +	wait_queue_head_t read_wq;
> +	wait_queue_head_t write_wq;
> +	struct usb_request *rx_req[RX_REQ_MAX];
> +	int rx_done;
> +
> +	/* delayed work for handling ACCESSORY_START */
> +	struct delayed_work start_work;
> +
> +	/* worker for registering and unregistering hid devices */
> +	struct work_struct hid_work;

why are these workers needed?

> +static struct usb_interface_descriptor acc_interface_desc = {
> +	.bLength                = USB_DT_INTERFACE_SIZE,
> +	.bDescriptorType        = USB_DT_INTERFACE,
> +	.bInterfaceNumber       = 0,
> +	.bNumEndpoints          = 2,
> +	.bInterfaceClass        = USB_CLASS_VENDOR_SPEC,
> +	.bInterfaceSubClass     = USB_SUBCLASS_VENDOR_SPEC,
> +	.bInterfaceProtocol     = 0,
> +};

const?

> +static struct usb_endpoint_descriptor acc_highspeed_in_desc = {
> +	.bLength                = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType        = USB_DT_ENDPOINT,
> +	.bEndpointAddress       = USB_DIR_IN,
> +	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize         = __constant_cpu_to_le16(512),
> +};

const?

> +static struct usb_endpoint_descriptor acc_highspeed_out_desc = {
> +	.bLength                = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType        = USB_DT_ENDPOINT,
> +	.bEndpointAddress       = USB_DIR_OUT,
> +	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize         = __constant_cpu_to_le16(512),
> +};

const?

> +static struct usb_endpoint_descriptor acc_fullspeed_in_desc = {
> +	.bLength                = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType        = USB_DT_ENDPOINT,
> +	.bEndpointAddress       = USB_DIR_IN,
> +	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
> +};

const?

> +static struct usb_endpoint_descriptor acc_fullspeed_out_desc = {
> +	.bLength                = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType        = USB_DT_ENDPOINT,
> +	.bEndpointAddress       = USB_DIR_OUT,
> +	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
> +};

const?

> +static struct usb_descriptor_header *fs_acc_descs[] = {
> +	(struct usb_descriptor_header *) &acc_interface_desc,
> +	(struct usb_descriptor_header *) &acc_fullspeed_in_desc,
> +	(struct usb_descriptor_header *) &acc_fullspeed_out_desc,
> +	NULL,
> +};

const?

> +static struct usb_descriptor_header *hs_acc_descs[] = {
> +	(struct usb_descriptor_header *) &acc_interface_desc,
> +	(struct usb_descriptor_header *) &acc_highspeed_in_desc,
> +	(struct usb_descriptor_header *) &acc_highspeed_out_desc,
> +	NULL,
> +};

const?

> +/* temporary variable used between acc_open() and acc_gadget_bind() */
> +static struct acc_dev *_acc_dev;

why?

> +struct acc_instance {
> +	struct usb_function_instance func_inst;
> +	const char *name;
> +};
> +
> +static inline struct acc_dev *func_to_dev(struct usb_function *f)
> +{
> +	return container_of(f, struct acc_dev, function);
> +}

this can be a define, but fine :-)

> +static void acc_request_free(struct usb_request *req, struct usb_ep *ep)
> +{
> +	if (req) {

why would req ever be NULL here?

> +static void req_put(struct acc_dev *dev, struct list_head *head,

how about we use a more descriptive name? Usually this would be called $prefix_enqueue().

> +		struct usb_request *req)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->lock, flags);
> +	list_add_tail(&req->list, head);
> +	spin_unlock_irqrestore(&dev->lock, flags);
> +}
> +
> +/* remove a request from the head of a list */
> +static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head)
> +{
> +	unsigned long flags;
> +	struct usb_request *req;
> +
> +	spin_lock_irqsave(&dev->lock, flags);
> +	if (list_empty(head)) {
> +		req = 0;
> +	} else {
> +		req = list_first_entry(head, struct usb_request, list);
> +		list_del(&req->list);
> +	}

list_first_entry_or_null()?

> +static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
> +{
> +	struct acc_dev *dev = _acc_dev;
> +
> +	if (req->status == -ESHUTDOWN) {
> +		pr_debug("acc_complete_in set disconnected");

yeah, we need something with a dev* for these prints.

> +static int acc_hid_start(struct hid_device *hid)
> +{
> +	return 0;
> +}
> +
> +static void acc_hid_stop(struct hid_device *hid)
> +{
> +}
> +
> +static int acc_hid_open(struct hid_device *hid)
> +{
> +	return 0;
> +}
> +
> +static void acc_hid_close(struct hid_device *hid)
> +{
> +}
> +
> +static int acc_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
> +	__u8 *buf, size_t len, unsigned char rtype, int reqtype)
> +{
> +	return 0;
> +}

what's with all the unimplemented methods?

> +static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
> +{
> +	struct acc_dev *dev = fp->private_data;
> +	char *src = NULL;
> +	int ret;
> +
> +	switch (code) {
> +	case ACCESSORY_GET_STRING_MANUFACTURER:
> +		src = dev->manufacturer;
> +		break;
> +	case ACCESSORY_GET_STRING_MODEL:
> +		src = dev->model;
> +		break;
> +	case ACCESSORY_GET_STRING_DESCRIPTION:
> +		src = dev->description;
> +		break;
> +	case ACCESSORY_GET_STRING_VERSION:
> +		src = dev->version;
> +		break;
> +	case ACCESSORY_GET_STRING_URI:
> +		src = dev->uri;
> +		break;
> +	case ACCESSORY_GET_STRING_SERIAL:
> +		src = dev->serial;
> +		break;
> +	case ACCESSORY_IS_START_REQUESTED:
> +		return dev->start_requested;
> +	case ACCESSORY_GET_AUDIO_MODE:
> +		return dev->audio_mode;
> +	}
> +	if (!src)
> +		return -EINVAL;

add this part as a default on the switch above?

> +
> +	ret = strlen(src) + 1;
> +	if (copy_to_user((void __user *)value, src, ret))
> +		ret = -EFAULT;
> +	return ret;
> +}
> +
> +static int acc_open(struct inode *ip, struct file *fp)
> +{
> +	printk(KERN_INFO "acc_open\n");

no printk() calls!

why couldn't you get your acc_dev from fp->private_data?

> +	if (atomic_xchg(&_acc_dev->open_excl, 1))

do you really need this to be an atomic_t?

> +int acc_ctrlrequest(struct usb_composite_dev *cdev,
> +				const struct usb_ctrlrequest *ctrl)
> +{
> +	struct acc_dev	*dev = _acc_dev;
> +	int	value = -EOPNOTSUPP;
> +	struct acc_hid_dev *hid;
> +	int offset;
> +	u8 b_requestType = ctrl->bRequestType;
> +	u8 b_request = ctrl->bRequest;
> +	u16	w_index = le16_to_cpu(ctrl->wIndex);
> +	u16	w_value = le16_to_cpu(ctrl->wValue);
> +	u16	w_length = le16_to_cpu(ctrl->wLength);
> +	unsigned long flags;
> +
> +/*
> +	printk(KERN_INFO "acc_ctrlrequest "
> +			"%02x.%02x v%04x i%04x l%u\n",
> +			b_requestType, b_request,
> +			w_value, w_index, w_length);
> +*/

commented out code? Please remove.

> +	if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
> +		if (b_request == ACCESSORY_START) {

looks like a switch statement is fitting here?

> +EXPORT_SYMBOL_GPL(acc_ctrlrequest);

why do you export this for any caller? Who is going to call this?

> +void acc_disconnect(void)
> +{
> +	/* unregister all HID devices if USB is disconnected */
> +	kill_all_hid_devices(_acc_dev);
> +}
> +EXPORT_SYMBOL_GPL(acc_disconnect);

why exported?

-- 
balbi

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux