Received: by 10.213.65.68 with SMTP id h4csp785690imn; Tue, 13 Mar 2018 23:10:02 -0700 (PDT) X-Google-Smtp-Source: AG47ELtfXm0gLuQOHknelRCJ/To+Oh0IVE13gQ+J1xHT+VJcdIg19qsmpLIiBVeE15KindlgJAsC X-Received: by 2002:a17:902:8341:: with SMTP id z1-v6mr2928272pln.386.1521007802543; Tue, 13 Mar 2018 23:10:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521007802; cv=none; d=google.com; s=arc-20160816; b=hC9oY5OqCkmx/TY++/kFYUN1RcUIhgqPORW2g5fuP9svaBtTGFweHF71jKrCCNURS4 KlK7I3mhv/Fl7O7DqIOSjVQMwufz73sOdlf+/EjUZwH2y7/M9K+Ii5dp2k/0GOOlw1Hs gsAYYpOwEGy4r4hX/e8B5WE3QNTdwLOiyrYZBPdVDMfeTKjhpzubqdPTmIq16Z7Iwsmu qLDj3Xmcd4QgMGcRousfKhWw/kbmplcZAho1rPeFwWsxkN5GA25hYHBVmU92mznpe2V4 0UoTLcAqVI8iyndvhODMewie9HxwX6ql6dVYC/7AI3/EAT3XwmMYuFN4I73ZL6Qv/T+c bEFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=CrXXgLRWUqzXGBKZI3P3b9KZqoKblCe+80vyvIiIJhA=; b=p5Fq6SjKzPSMYfKaDcG0/1BW2Wkg5IbMREzedIOSAxlbrMq3F9uF34OtmQSDVCcPdt jWM5DW4VgqUEpU0KX1OUb+vuEdMkWPz5wLKcwigVqxhijKx0rRNBgO0RY3Dt3AXGI+RC l6hdS8izOAIthFNRSXOS8gLj2nIfh59Q0xvl7x/dPmqAXQFe4EcoSBoBF6BFppORPiNk sMLF2UjvC6WsvCDsqswlNwsJxbsLg4Fu4a26nvt+RptDgN5eU8ET7Drg5KMCLio38TE1 8MlrTEQaUN8w6DblwShjdTHmYBI9JGCNLpNYIu7FZ4/lsBRv7GViw4E0kJ0inMiQ6sHv eFwQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q15-v6si1437794plk.518.2018.03.13.23.09.47; Tue, 13 Mar 2018 23:10:02 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753419AbeCNGIY (ORCPT + 99 others); Wed, 14 Mar 2018 02:08:24 -0400 Received: from Mailgw01.mediatek.com ([1.203.163.78]:17326 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1751440AbeCNGIP (ORCPT ); Wed, 14 Mar 2018 02:08:15 -0400 X-UUID: a352ee4261e3465e80877d0821e7c2a2-20180314 Received: from mtkcas34.mediatek.inc [(172.27.4.250)] by mailgw01.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 453249713; Wed, 14 Mar 2018 14:02:49 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by MTKMBS31N1.mediatek.inc (172.27.4.69) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Wed, 14 Mar 2018 14:02:48 +0800 Received: from localhost.localdomain (10.17.3.153) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1210.3 via Frontend Transport; Wed, 14 Mar 2018 14:02:47 +0800 From: Chunfeng Yun To: Greg Kroah-Hartman CC: Matthias Brugger , Heikki Krogerus , Serge Semin , Chunfeng Yun , Guenter Roeck , Kate Stewart , Thomas Gleixner , Alan Stern , , , , Subject: [PATCH] usb: misc: supports Apple Carplay driver Date: Wed, 14 Mar 2018 14:02:36 +0800 Message-ID: <1521007356-12306-2-git-send-email-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1521007356-12306-1-git-send-email-chunfeng.yun@mediatek.com> References: <1521007356-12306-1-git-send-email-chunfeng.yun@mediatek.com> MIME-Version: 1.0 Content-Type: text/plain X-MTK: N Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The driver is used to support Apple carplay feature by a debugfs interface which can force the driver to send a USB Vendor Request of "Apple Device to Host Mode Switch" to switch Apple Device into host mode. Signed-off-by: Chunfeng Yun --- drivers/usb/misc/Kconfig | 9 ++ drivers/usb/misc/Makefile | 1 + drivers/usb/misc/carplay.c | 205 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 drivers/usb/misc/carplay.c diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 68d2f2c..c010c95 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -275,3 +275,12 @@ config USB_CHAOSKEY To compile this driver as a module, choose M here: the module will be called chaoskey. + +config USB_CARPLAY + tristate "USB carplay driver support" + help + The driver is used to support Apple carplay feature. + It is realized by sending a USB Vendor Request of "Apple Device to + Host Mode Switch" to switch Apple Device into host mode. + When the users want to use carplay, they can force the driver to send + this Vendor Request by a debugfs interface. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 109f54f..94380e7 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o +obj-$(CONFIG_USB_CARPLAY) += carplay.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o diff --git a/drivers/usb/misc/carplay.c b/drivers/usb/misc/carplay.c new file mode 100644 index 0000000..bfd41f3 --- /dev/null +++ b/drivers/usb/misc/carplay.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * carplay.c - carplay usb driver + * + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Chunfeng Yun + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * usage: + * The requirement for the platform using Carplay feature is that support + * the USB Dual Role Switch feature, and must have a USB-A receptacle + * that is capable of functioning in both USB Host and USB Device roles. + * + * 1. Apple iphone is enumerated as a usb device + * 2. switch Apple iphone to host mode, by, e.g. + * echo host > /sys/kernel/debug/usb/carplay.1-1/mode + * 3. switch the platform to device mode, but meanwhile should keep vbus alive; + * 4. use carplay feature after the platform is enumerated as a usb device; + * 5. when unplug usb cable, switch the platform back to host mode. + * + * step 2 is supported by this driver; + * step 1, 3, 4, 5 should be supported by the USB Dual-Role Controller Driver + * on the platform. + * + * For more detailed information, please refer to "Chapter 46. USB Role Switch" + * in MFI Accessroy Interface Specification.pdf + */ + +#define CARPLAY_NAME "carplay" +#define VENDER_REQ_DEV_TO_HOST 0x51 + +struct usb_carplay { + struct usb_interface *intf; + struct usb_device *udev; + struct dentry *droot; + struct device *idev; + bool is_host; +}; + +static int carplay_switch_to_host(struct usb_carplay *ucp) +{ + struct usb_device *udev = ucp->udev; + int retval; + + if (!ucp->udev) + return -ENODEV; + + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + VENDER_REQ_DEV_TO_HOST, USB_TYPE_VENDOR, + 1, 0, NULL, 0, USB_CTRL_GET_TIMEOUT); + + dev_dbg(ucp->idev, "%s retval = %d\n", __func__, retval); + + if (retval != 0) { + dev_err(ucp->idev, "%s fail retval = %d\n", __func__, retval); + return retval; + } + ucp->is_host = true; + + return 0; +} + +static int carplay_mode_show(struct seq_file *sf, void *unused) +{ + struct usb_carplay *ucp = sf->private; + + seq_printf(sf, "current mode: %s\n(usage: echo host > mode)\n", + ucp->is_host ? "host" : "device"); + + return 0; +} + +static int carplay_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, carplay_mode_show, inode->i_private); +} + +static ssize_t carplay_mode_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *sf = file->private_data; + struct usb_carplay *ucp = sf->private; + char buf[16]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "host", 4) && !ucp->is_host) { + carplay_switch_to_host(ucp); + } else { + dev_err(ucp->idev, "wrong setting\n"); + return -EINVAL; + } + + return count; +} + +static const struct file_operations carplay_mode_fops = { + .open = carplay_mode_open, + .write = carplay_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *carplay_debugfs_init(struct usb_carplay *ucp) +{ + struct dentry *root; + const char *udev_name = dev_name(&ucp->udev->dev); + char name[16]; + + snprintf(name, sizeof(name), "%s.%s", CARPLAY_NAME, udev_name); + root = debugfs_create_dir(name, usb_debug_root); + if (!root) { + dev_err(ucp->idev, "create debugfs root failed\n"); + return root; + } + ucp->droot = root; + + return debugfs_create_file("mode", 0664, root, ucp, + &carplay_mode_fops); +} + +static void carplay_debugfs_exit(struct usb_carplay *ucp) +{ + debugfs_remove_recursive(ucp->droot); +} + +static int carplay_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_carplay *ucp; + struct dentry *de; + + udev = interface_to_usbdev(intf); + + ucp = kzalloc(sizeof(*ucp), GFP_KERNEL); + if (!ucp) + return -ENOMEM; + + ucp->udev = usb_get_dev(udev); + ucp->intf = intf; + ucp->idev = &intf->dev; + usb_set_intfdata(intf, ucp); + ucp->is_host = false; + + de = carplay_debugfs_init(ucp); + if (IS_ERR_OR_NULL(de)) { + usb_set_intfdata(intf, NULL); + usb_put_dev(ucp->udev); + kfree(ucp); + return -ENOMEM; + } + + dev_info(ucp->idev, "carplay attached\n"); + return 0; +} + +static void carplay_disconnect(struct usb_interface *intf) +{ + struct usb_carplay *ucp = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + usb_put_dev(ucp->udev); + carplay_debugfs_exit(ucp); + kfree(ucp); + dev_info(&intf->dev, "carplay disconnected\n"); +} + +static const struct usb_device_id carplay_id_table[] = { + /* generic EZ-USB FX2 controller (or development board) */ + { USB_DEVICE(0x05ac, 0x12a8) }, + {} +}; + +MODULE_DEVICE_TABLE(usb, carplay_id_table); + +static struct usb_driver carplay_driver = { + .name = CARPLAY_NAME, + .id_table = carplay_id_table, + .probe = carplay_probe, + .disconnect = carplay_disconnect, +}; + +module_usb_driver(carplay_driver); + +MODULE_AUTHOR("Chunfeng Yun "); +MODULE_DESCRIPTION("USB Carplay Driver"); +MODULE_LICENSE("GPL"); -- 1.7.9.5