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