ANDROID: usb: gadget: Add Android Accessory Function
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. There are issues (especially with regards to reference counting) which carry over from prior iterations of this driver, and therefore this driver should not be used as an example for other development. For these reasons, this patch is not eligible for android-mainline or future android16+ branches. Much of this functionality should be deprecated and removed. Bug: 120441124 Bug: 317149848 Change-Id: I6b7b6e7b2a348da0d57487e82913de6fe19f2b6e Signed-off-by: Neill Kapron <nkapron@google.com>
This commit is contained in:
@@ -540,6 +540,7 @@ CONFIG_USB_CONFIGFS_F_UAC2=y
|
||||
CONFIG_USB_CONFIGFS_F_MIDI=y
|
||||
CONFIG_USB_CONFIGFS_F_HID=y
|
||||
CONFIG_USB_CONFIGFS_F_UVC=y
|
||||
CONFIG_ANDROID_USB_CONFIGFS_F_ACC=y
|
||||
CONFIG_TYPEC=y
|
||||
CONFIG_TYPEC_TCPM=y
|
||||
CONFIG_TYPEC_TCPCI=y
|
||||
|
||||
@@ -502,6 +502,7 @@ CONFIG_USB_CONFIGFS_F_UAC2=y
|
||||
CONFIG_USB_CONFIGFS_F_MIDI=y
|
||||
CONFIG_USB_CONFIGFS_F_HID=y
|
||||
CONFIG_USB_CONFIGFS_F_UVC=y
|
||||
CONFIG_ANDROID_USB_CONFIGFS_F_ACC=y
|
||||
CONFIG_TYPEC=y
|
||||
CONFIG_TYPEC_TCPM=y
|
||||
CONFIG_TYPEC_TCPCI=y
|
||||
|
||||
@@ -221,6 +221,10 @@ config USB_F_PRINTER
|
||||
config USB_F_TCM
|
||||
tristate
|
||||
|
||||
# due to coupling with composite driver, can not be built as a module.
|
||||
config ANDROID_USB_F_ACC
|
||||
bool
|
||||
|
||||
# this first set of drivers all depend on bulk-capable hardware.
|
||||
|
||||
config USB_CONFIGFS
|
||||
@@ -517,6 +521,18 @@ config USB_CONFIGFS_F_TCM
|
||||
Both protocols can work on USB2.0 and USB3.0.
|
||||
UAS utilizes the USB 3.0 feature called streams support.
|
||||
|
||||
config ANDROID_USB_CONFIGFS_F_ACC
|
||||
bool "Accessory Gadget"
|
||||
depends on USB_CONFIGFS
|
||||
depends on HID=y
|
||||
select ANDROID_USB_F_ACC
|
||||
help
|
||||
This Accessory function adds support for the Android Open Accessory
|
||||
(AOA) protocol v2. Devices which support this protocol send vendor
|
||||
specific control_requests to describe what they are and what
|
||||
userspace application should handle their traffic. This function
|
||||
enables the data exchange with usersapce.
|
||||
|
||||
source "drivers/usb/gadget/legacy/Kconfig"
|
||||
|
||||
endif # USB_GADGET
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/android_accessory.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/webusb.h>
|
||||
#include <linux/unaligned.h>
|
||||
@@ -2241,6 +2242,23 @@ unknown:
|
||||
}
|
||||
f = NULL;
|
||||
|
||||
/*
|
||||
* Android: The accessory function can handle some control
|
||||
* requests despite not being allocated to a config. Therefore,
|
||||
* the upstream logic for checking req_match will not work until
|
||||
* the attached device issues an ACCESSORY_START command and
|
||||
* userspace tears down the gadget, adds the accessory function
|
||||
* to the config, and binds the config to the UDC again.
|
||||
*
|
||||
* To workaround the existing userspace limitiations, check to
|
||||
* see if the f_accessory driver can handle the ctrl request,
|
||||
* and if so, pass it along.
|
||||
*/
|
||||
if (android_acc_req_match_composite(cdev, ctrl)) {
|
||||
value = android_acc_setup_composite(cdev, ctrl);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_INTERFACE:
|
||||
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
|
||||
@@ -2316,6 +2334,12 @@ static void __composite_disconnect(struct usb_gadget *gadget)
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Android: f_accessory can handle HID packets without being bound to a
|
||||
* config so we unfortunately require this hook to clean it up.
|
||||
*/
|
||||
android_acc_disconnect();
|
||||
|
||||
android_set_disconnected(&cdev->android_opts);
|
||||
|
||||
/* REVISIT: should we have config and device level
|
||||
|
||||
@@ -52,3 +52,5 @@ usb_f_printer-y := f_printer.o
|
||||
obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o
|
||||
usb_f_tcm-y := f_tcm.o
|
||||
obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o
|
||||
usb_f_acc-y := android_f_accessory.o
|
||||
obj-$(CONFIG_ANDROID_USB_F_ACC) += usb_f_acc.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*/
|
||||
#ifndef __ANDROID_ACCESSORY_H
|
||||
#define __ANDROID_ACCESSORY_H
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
#ifdef CONFIG_ANDROID_USB_CONFIGFS_F_ACC
|
||||
|
||||
/**
|
||||
* android_acc_req_match_composite - used to check if the android accessory
|
||||
* driver can handle a usb_ctrlrequest
|
||||
* @cdev - the usb_composite_dev instance associated with the incoming ctrl
|
||||
* request
|
||||
* @ctrl - a usb_ctrlrequest for the accessory driver to check
|
||||
*
|
||||
* This function should be called in composite_setup() after other req_match
|
||||
* checks have failed and the usb_ctrlrequest is still unhandled.
|
||||
*
|
||||
* The reason this must be implemented instead of the standard req_match
|
||||
* interface is that the accessory function does not get bound to a config
|
||||
* by userspace until a connected device sends the ACCESSORY_START control
|
||||
* request, and therefore the composite driver does not know about f_accessory
|
||||
* yet we need to check for the control requests.
|
||||
*
|
||||
* Returns: true if the accessory driver can handle the request, false if not
|
||||
*/
|
||||
bool android_acc_req_match_composite(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl);
|
||||
|
||||
/**
|
||||
* android_acc_setup_composite - function for the f_accessory driver to handle
|
||||
* usb_ctrlrequests
|
||||
* @cdev - the usb_composite_dev instance associated with the incoming ctrl
|
||||
* request.
|
||||
* @ctrl - a usb_ctrlrequest to be handled by the f_accessory driver.
|
||||
*
|
||||
* This function should be called in composite_setup() after successfully
|
||||
* checking for ctrl request support in android_acc_req_match_composite().
|
||||
*
|
||||
* The reason this additional api must be defined is due to the fact that
|
||||
* userspace does not bind the f_accessory instance to a gadget config until
|
||||
* after receiving an ACCESSORY_START control request from a connected
|
||||
* accessory device, and therefore we have a circular dependency. The addition
|
||||
* of this allows compatibility with the existing Android userspace, but is
|
||||
* not ideal and should be refactored in the future.
|
||||
*
|
||||
* Returns: Negative error value upon failure, >=0 upon successful handdling
|
||||
* of the usb_ctrlrequest aligned with the standard composite function driver
|
||||
* setup() api.
|
||||
*/
|
||||
int android_acc_setup_composite(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl);
|
||||
|
||||
/**
|
||||
* android_acc_disconnect - used to cleanup the accessory function
|
||||
* and update the connection state on device disconnection.
|
||||
*
|
||||
* This should be called in the composite driver's __composite_disconnect()
|
||||
* path to notify the accessory function of device disconnect. This is
|
||||
* required because the accessory function exists outside of a gadget config
|
||||
* and therefore the composite driver's standard cleanup paths may not apply.
|
||||
*/
|
||||
void android_acc_disconnect(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline bool android_acc_req_match_composite(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int android_acc_setup_composite(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void android_acc_disconnect(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ANDROID_USB_CONFIGFS_F_ACC */
|
||||
#endif /* __ANDROID_ACCESSORY_H */
|
||||
@@ -0,0 +1,140 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Gadget Function Driver for Android USB accessories
|
||||
*
|
||||
* Copyright 2011-2024 Google LLC
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_ANDROID_ACCESSORY_H
|
||||
#define _UAPI_ANDROID_ACCESSORY_H
|
||||
|
||||
/* Use Google Vendor ID when in accessory mode */
|
||||
#define USB_ACCESSORY_VENDOR_ID 0x18D1
|
||||
|
||||
/* Product ID to use when in accessory mode */
|
||||
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
|
||||
|
||||
/* Product ID to use when in accessory mode and adb is enabled */
|
||||
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
|
||||
|
||||
/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
|
||||
#define ACCESSORY_STRING_MANUFACTURER 0
|
||||
#define ACCESSORY_STRING_MODEL 1
|
||||
#define ACCESSORY_STRING_DESCRIPTION 2
|
||||
#define ACCESSORY_STRING_VERSION 3
|
||||
#define ACCESSORY_STRING_URI 4
|
||||
#define ACCESSORY_STRING_SERIAL 5
|
||||
|
||||
#define ACC_STRING_SIZE 256
|
||||
|
||||
/* Control request for retrieving device's protocol version
|
||||
*
|
||||
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_GET_PROTOCOL
|
||||
* value: 0
|
||||
* index: 0
|
||||
* data: version number (16 bits little endian)
|
||||
* 1 for original accessory support
|
||||
* 2 adds HID and device to host audio support
|
||||
*/
|
||||
#define ACCESSORY_GET_PROTOCOL 51
|
||||
|
||||
/* Control request for host to send a string to the device
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SEND_STRING
|
||||
* value: 0
|
||||
* index: string ID
|
||||
* data: zero terminated UTF8 string
|
||||
*
|
||||
* The device can later retrieve these strings via the
|
||||
* ACCESSORY_GET_STRING_* ioctls
|
||||
*/
|
||||
#define ACCESSORY_SEND_STRING 52
|
||||
|
||||
/* Control request for starting device in accessory mode.
|
||||
* The host sends this after setting all its strings to the device.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_START
|
||||
* value: 0
|
||||
* index: 0
|
||||
* data: none
|
||||
*/
|
||||
#define ACCESSORY_START 53
|
||||
|
||||
/* Control request for registering a HID device.
|
||||
* Upon registering, a unique ID is sent by the accessory in the
|
||||
* value parameter. This ID will be used for future commands for
|
||||
* the device
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_REGISTER_HID_DEVICE
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: total length of the HID report descriptor
|
||||
* data: none
|
||||
*/
|
||||
#define ACCESSORY_REGISTER_HID 54
|
||||
|
||||
/* Control request for unregistering a HID device.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_REGISTER_HID
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: 0
|
||||
* data: none
|
||||
*/
|
||||
#define ACCESSORY_UNREGISTER_HID 55
|
||||
|
||||
/* Control request for sending the HID report descriptor.
|
||||
* If the HID descriptor is longer than the endpoint zero max packet size,
|
||||
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
|
||||
* commands. The data for the descriptor must be sent sequentially
|
||||
* if multiple packets are needed.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SET_HID_REPORT_DESC
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: offset of data in descriptor
|
||||
* (needed when HID descriptor is too big for one packet)
|
||||
* data: the HID report descriptor
|
||||
*/
|
||||
#define ACCESSORY_SET_HID_REPORT_DESC 56
|
||||
|
||||
/* Control request for sending HID events.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SEND_HID_EVENT
|
||||
* value: Accessory assigned ID for the HID device
|
||||
* index: 0
|
||||
* data: the HID report for the event
|
||||
*/
|
||||
#define ACCESSORY_SEND_HID_EVENT 57
|
||||
|
||||
/* Control request for setting the audio mode.
|
||||
*
|
||||
* DEPRECATED! Do not implement a new device which uses this.
|
||||
*
|
||||
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
|
||||
* request: ACCESSORY_SET_AUDIO_MODE
|
||||
* value: 0 - no audio
|
||||
* 1 - device to host, 44100 16-bit stereo PCM
|
||||
* index: 0
|
||||
* data: none
|
||||
*/
|
||||
#define ACCESSORY_SET_AUDIO_MODE 58
|
||||
|
||||
/* ioctls for retrieving strings set by the host */
|
||||
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[ACC_STRING_SIZE])
|
||||
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[ACC_STRING_SIZE])
|
||||
#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[ACC_STRING_SIZE])
|
||||
#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[ACC_STRING_SIZE])
|
||||
#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[ACC_STRING_SIZE])
|
||||
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[ACC_STRING_SIZE])
|
||||
/* returns 1 if there is a start request pending */
|
||||
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
|
||||
/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
|
||||
#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
|
||||
|
||||
#endif /* _UAPI_ANDROID__ACCESSORY_H */
|
||||
Reference in New Issue
Block a user