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

Unverified Commit 7f985237 authored by derfelot's avatar derfelot Committed by GitHub
Browse files

Merge pull request #40 from Flamefire/usb_patches

Add ANDROID USB patches
parents 65e781d4 4a161802
Loading
Loading
Loading
Loading
+107 −40
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/kref.h>

#include <linux/types.h>
#include <linux/file.h>
@@ -73,6 +74,7 @@ struct acc_dev {
	struct usb_function function;
	struct usb_composite_dev *cdev;
	spinlock_t lock;
	struct acc_dev_ref *ref;

	struct usb_ep *ep_in;
	struct usb_ep *ep_out;
@@ -80,13 +82,13 @@ struct acc_dev {
	/* online indicates state of function_set_alt & function_unbind
	 * set to 1 when we connect
	 */
	int online:1;
	int online;

	/* disconnected indicates state of open & release
	 * Set to 1 when we disconnect.
	 * Not cleared until our file is closed.
	 */
	int disconnected:1;
	int disconnected;

	/* strings sent by the host */
	char manufacturer[ACC_STRING_SIZE];
@@ -243,14 +245,48 @@ static struct usb_gadget_strings *acc_strings[] = {
	NULL,
};

/* temporary variable used between acc_open() and acc_gadget_bind() */
static struct acc_dev *_acc_dev;
struct acc_dev_ref {
	struct kref	kref;
	struct acc_dev	*acc_dev;
};

static struct acc_dev_ref _acc_dev_ref = {
	.kref = KREF_INIT(0),
};

struct acc_instance {
	struct usb_function_instance func_inst;
	const char *name;
};

static struct acc_dev *get_acc_dev(void)
{
	struct acc_dev_ref *ref = &_acc_dev_ref;

	return kref_get_unless_zero(&ref->kref) ? ref->acc_dev : NULL;
}

static void __put_acc_dev(struct kref *kref)
{
	struct acc_dev_ref *ref = container_of(kref, struct acc_dev_ref, kref);
	struct acc_dev *dev = ref->acc_dev;

	/* Cancel any async work */
	cancel_delayed_work_sync(&dev->start_work);
	cancel_work_sync(&dev->hid_work);

	ref->acc_dev = NULL;
	kfree(dev);
}

static void put_acc_dev(struct acc_dev *dev)
{
	struct acc_dev_ref *ref = dev->ref;

	WARN_ON(ref->acc_dev != dev);
	kref_put(&ref->kref, __put_acc_dev);
}

static inline struct acc_dev *func_to_dev(struct usb_function *f)
{
	return container_of(f, struct acc_dev, function);
@@ -316,7 +352,10 @@ static void acc_set_disconnected(struct acc_dev *dev)

static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
{
	struct acc_dev *dev = _acc_dev;
	struct acc_dev *dev = get_acc_dev();

	if (!dev)
		return;

	if (req->status == -ESHUTDOWN) {
		pr_debug("acc_complete_in set disconnected");
@@ -326,11 +365,15 @@ static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
	req_put(dev, &dev->tx_idle, req);

	wake_up(&dev->write_wq);
	put_acc_dev(dev);
}

static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
{
	struct acc_dev *dev = _acc_dev;
	struct acc_dev *dev = get_acc_dev();

	if (!dev)
		return;

	dev->rx_done = 1;
	if (req->status == -ESHUTDOWN) {
@@ -339,6 +382,7 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
	}

	wake_up(&dev->read_wq);
	put_acc_dev(dev);
}

static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
@@ -803,24 +847,36 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)

static int acc_open(struct inode *ip, struct file *fp)
{
	printk(KERN_INFO "acc_open\n");
	if (atomic_xchg(&_acc_dev->open_excl, 1))
	struct acc_dev *dev = get_acc_dev();

	if (!dev)
		return -ENODEV;

	if (atomic_xchg(&dev->open_excl, 1)) {
		put_acc_dev(dev);
		return -EBUSY;
	}

	_acc_dev->disconnected = 0;
	fp->private_data = _acc_dev;
	dev->disconnected = 0;
	fp->private_data = dev;
	return 0;
}

static int acc_release(struct inode *ip, struct file *fp)
{
	printk(KERN_INFO "acc_release\n");
	struct acc_dev *dev = fp->private_data;

	if (!dev)
		return -ENOENT;

	WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0));
	/* indicate that we are disconnected
	 * still could be online so don't touch online flag
	 */
	_acc_dev->disconnected = 1;
	dev->disconnected = 1;

	fp->private_data = NULL;
	WARN_ON(!atomic_xchg(&dev->open_excl, 0));
	put_acc_dev(dev);
	return 0;
}

@@ -876,7 +932,7 @@ static void acc_complete_setup_noop(struct usb_ep *ep, struct usb_request *req)
int acc_ctrlrequest(struct usb_composite_dev *cdev,
				const struct usb_ctrlrequest *ctrl)
{
	struct acc_dev	*dev = _acc_dev;
	struct acc_dev	*dev = get_acc_dev();
	int	value = -EOPNOTSUPP;
	struct acc_hid_dev *hid;
	int offset;
@@ -893,12 +949,6 @@ int acc_ctrlrequest(struct usb_composite_dev *cdev,
	 */
	if (!dev)
		return -ENODEV;
/*
 *	printk(KERN_INFO "acc_ctrlrequest "
 *			"%02x.%02x v%04x i%04x l%u\n",
 *			b_requestType, b_request,
 *			w_value, w_index, w_length);
 */

	if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
		if (b_request == ACCESSORY_START) {
@@ -987,6 +1037,7 @@ err:
			"%02x.%02x v%04x i%04x l%u\n",
			ctrl->bRequestType, ctrl->bRequest,
			w_value, w_index, w_length);
	put_acc_dev(dev);
	return value;
}
EXPORT_SYMBOL_GPL(acc_ctrlrequest);
@@ -1065,10 +1116,6 @@ kill_all_hid_devices(struct acc_dev *dev)
	struct list_head *entry, *temp;
	unsigned long flags;

	/* do nothing if usb accessory device doesn't exist */
	if (!dev)
		return;

	spin_lock_irqsave(&dev->lock, flags);
	list_for_each_safe(entry, temp, &dev->hid_list) {
		hid = list_entry(entry, struct acc_hid_dev, list);
@@ -1153,12 +1200,15 @@ static void acc_hid_delete(struct acc_hid_dev *hid)

static void acc_hid_work(struct work_struct *data)
{
	struct acc_dev *dev = _acc_dev;
	struct acc_dev *dev = get_acc_dev();
	struct list_head	*entry, *temp;
	struct acc_hid_dev *hid;
	struct list_head	new_list, dead_list;
	unsigned long flags;

	if (!dev)
		return;

	INIT_LIST_HEAD(&new_list);

	spin_lock_irqsave(&dev->lock, flags);
@@ -1204,6 +1254,8 @@ static void acc_hid_work(struct work_struct *data)
			hid_destroy_device(hid->hid);
		acc_hid_delete(hid);
	}

	put_acc_dev(dev);
}

static int acc_function_set_alt(struct usb_function *f,
@@ -1260,9 +1312,13 @@ static void acc_function_disable(struct usb_function *f)

static int acc_setup(void)
{
	struct acc_dev_ref *ref = &_acc_dev_ref;
	struct acc_dev *dev;
	int ret;

	if (kref_read(&ref->kref))
		return -EBUSY;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;
@@ -1278,16 +1334,22 @@ static int acc_setup(void)
	INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
	INIT_WORK(&dev->hid_work, acc_hid_work);

	dev->ref = ref;
	if (cmpxchg_relaxed(&ref->acc_dev, NULL, dev)) {
		ret = -EBUSY;
		goto err_free_dev;
	}

	ret = misc_register(&acc_device);
	if (ret)
		goto err;

	/* _acc_dev must be set before calling usb_gadget_register_driver */
	_acc_dev = dev;
		goto err_zap_ptr;

	kref_init(&ref->kref);
	return 0;

err:
err_zap_ptr:
	ref->acc_dev = NULL;
err_free_dev:
	kfree(dev);
	pr_err("USB accessory gadget driver failed to initialize\n");
	return ret;
@@ -1295,16 +1357,24 @@ err:

void acc_disconnect(void)
{
	struct acc_dev *dev = get_acc_dev();

	if (!dev)
		return;

	/* unregister all HID devices if USB is disconnected */
	kill_all_hid_devices(_acc_dev);
	kill_all_hid_devices(dev);
	put_acc_dev(dev);
}
EXPORT_SYMBOL_GPL(acc_disconnect);

static void acc_cleanup(void)
{
	struct acc_dev *dev = get_acc_dev();

	misc_deregister(&acc_device);
	kfree(_acc_dev);
	_acc_dev = NULL;
	put_acc_dev(dev);
	put_acc_dev(dev); /* Pairs with kref_init() in acc_setup() */
}
static struct acc_instance *to_acc_instance(struct config_item *item)
{
@@ -1364,7 +1434,6 @@ static void acc_free_inst(struct usb_function_instance *fi)
static struct usb_function_instance *acc_alloc_inst(void)
{
	struct acc_instance *fi_acc;
	struct acc_dev *dev;
	int err;

	fi_acc = kzalloc(sizeof(*fi_acc), GFP_KERNEL);
@@ -1376,19 +1445,19 @@ static struct usb_function_instance *acc_alloc_inst(void)
	err = acc_setup();
	if (err) {
		kfree(fi_acc);
		pr_err("Error setting ACCESSORY\n");
		return ERR_PTR(err);
	}

	config_group_init_type_name(&fi_acc->func_inst.group,
					"", &acc_func_type);
	dev = _acc_dev;
	return  &fi_acc->func_inst;
}

static void acc_free(struct usb_function *f)
{
/*NO-OP: no function specific resource allocation in mtp_alloc*/
	struct acc_dev *dev = func_to_dev(f);

	put_acc_dev(dev);
}

int acc_ctrlrequest_configfs(struct usb_function *f,
@@ -1401,9 +1470,7 @@ int acc_ctrlrequest_configfs(struct usb_function *f,

static struct usb_function *acc_alloc(struct usb_function_instance *fi)
{
	struct acc_dev *dev = _acc_dev;

	pr_info("acc_alloc\n");
	struct acc_dev *dev = get_acc_dev();

	dev->function.name = "accessory";
	dev->function.strings = acc_strings,