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

Commit 6851e8cc authored by Vamsi Krishna Samavedam's avatar Vamsi Krishna Samavedam Committed by Elson Roy Serrao
Browse files

Usb: f_gsi: Add uevent support for connect/disconnect events



Currently gsi driver indicates the state change by sending zero length
packet. Send uevents to indicate to specific gsi protocol connect and
disconnect state as well.

Change-Id: Icfad5ccba74b7f33b1bacad685d4eb15520e72b5
Signed-off-by: default avatarVamsi Krishna Samavedam <vskrishn@codeaurora.org>
Signed-off-by: default avatarElson Roy Serrao <eserrao@codeaurora.org>
parent eafa5790
Loading
Loading
Loading
Loading
+77 −1
Original line number Diff line number Diff line
@@ -1741,6 +1741,15 @@ static unsigned int gsi_xfer_bitrate(struct usb_gadget *g)
		return 19 * 64 * 1 * 1000 * 8;
}

static void gsi_uevent_work(struct work_struct *w)
{
	struct gsi_ctrl_port *c_port =
			container_of(w, struct gsi_ctrl_port, uevent_work);

	if (c_port->dev)
		kobject_uevent(&c_port->dev->kobj, KOBJ_CHANGE);
}

static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
{
	int ret;
@@ -1760,6 +1769,9 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
	spin_lock_init(&gsi->c_port.lock);

	init_waitqueue_head(&gsi->c_port.read_wq);
	INIT_WORK(&gsi->c_port.uevent_work, gsi_uevent_work);
	gsi->c_port.dev = NULL;
	gsi->c_port.uevent_wq = NULL;

	if (gsi->prot_id == IPA_USB_RMNET)
		strlcat(gsi->c_port.name, GSI_RMNET_CTRL_NAME, sz);
@@ -1775,6 +1787,10 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
	if (!ctrl_dev_create)
		return 0;

	gsi->c_port.uevent_wq = alloc_workqueue(gsi->c_port.name,
						WQ_UNBOUND | WQ_MEM_RECLAIM |
						WQ_FREEZABLE, 1);

	minor = ida_simple_get(&gsi_ida, 0, MAX_CDEV_INSTANCES, GFP_KERNEL);
	if (minor < 0) {
		pr_err("%s: No more minor numbers left! rc:%d\n", __func__,
@@ -1790,7 +1806,7 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
		goto err_cdev_add;
	}

	dev = device_create(gsi_class, NULL, MKDEV(major, minor), NULL,
	dev = device_create(gsi_class, NULL, MKDEV(major, minor), &gsi->c_port,
			gsi->c_port.name);
	if (IS_ERR(dev)) {
		log_event_err("%s: device_create failed for (%s)\n", __func__,
@@ -1799,6 +1815,8 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
		goto err_create_dev;
	}

	gsi->c_port.dev = dev;

	return 0;

err_create_dev:
@@ -2325,6 +2343,10 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
			gsi->rmnet_dtr_status = line_state;
		log_event_dbg("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE DTR:%d\n",
						__func__, line_state);
		if (gsi->c_port.uevent_wq)
			queue_work(gsi->c_port.uevent_wq,
					&gsi->c_port.uevent_work);

		gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
		value = 0;
		break;
@@ -2557,6 +2579,9 @@ static int gsi_set_alt(struct usb_function *f, unsigned int intf,
			gsi->prot_id == IPA_USB_MBIM)
		gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);

	if (gsi->c_port.uevent_wq)
		queue_work(gsi->c_port.uevent_wq, &gsi->c_port.uevent_work);

	return ret;

notify_ep_disable:
@@ -2589,6 +2614,10 @@ static void gsi_disable(struct usb_function *f)
	}

	gsi_ctrl_clear_cpkt_queues(gsi, false);

	if (gsi->c_port.uevent_wq)
		queue_work(gsi->c_port.uevent_wq, &gsi->c_port.uevent_work);

	/* send 0 len pkt to qti/qbi/gps to notify state change */
	gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
	gsi->c_port.notify_req_queued = false;
@@ -3748,11 +3777,22 @@ static void gsi_inst_clean(struct gsi_opts *opts)
{
	if (opts->gsi->c_port.cdev.dev) {
		struct cdev *cdev = &opts->gsi->c_port.cdev;
		struct f_gsi *gsi = opts->gsi;
		int minor = MINOR(cdev->dev);

		if (gsi->c_port.dev)
			dev_set_drvdata(gsi->c_port.dev, NULL);

		if (gsi->c_port.uevent_wq) {
			cancel_work_sync(&gsi->c_port.uevent_work);
			destroy_workqueue(gsi->c_port.uevent_wq);
			gsi->c_port.uevent_wq = NULL;
		}

		device_destroy(gsi_class, cdev->dev);
		cdev_del(cdev);
		cdev->dev = 0;
		gsi->c_port.dev = NULL;
		ida_simple_remove(&gsi_ida, minor);
	}

@@ -3904,6 +3944,41 @@ DECLARE_USB_FUNCTION(gsi, gsi_alloc_inst, gsi_alloc);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("GSI function driver");

static int usb_gsi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct gsi_ctrl_port *c_port = dev_get_drvdata(dev);
	struct f_gsi *gsi;
	char *str = "undefined";

	if (!c_port) {
		dev_dbg(dev, "%s: gsi is not initialized\n", __func__);
		add_uevent_var(env, "STATE=%s", str);
		return 0;
	}

	gsi = c_port_to_gsi(c_port);

	switch (gsi->prot_id) {
	case IPA_USB_RMNET:
		str = gsi->rmnet_dtr_status ? "connected" : "disconnected";
		break;
	case IPA_USB_MBIM:
	case IPA_USB_DIAG:
	case IPA_USB_GPS:
		str = atomic_read(&gsi->connected) ?
					"connected" : "disconnected";
		break;
	default:
		return 0;
	}

	add_uevent_var(env, "STATE=%s", str);

	log_event_dbg("%s:STATE=%s\n", c_port->name, str);

	return 0;
}

static int fgsi_init(void)
{
	int i;
@@ -3927,6 +4002,7 @@ static int fgsi_init(void)
		pr_err("%s: class_create() failed:%d\n", __func__, ret);
		return ret;
	}
	gsi_class->dev_uevent = usb_gsi_uevent;

	ret = alloc_chrdev_region(&dev, 0, MAX_CDEV_INSTANCES, "gsi_usb");
	if (ret) {
+4 −0
Original line number Diff line number Diff line
@@ -240,6 +240,10 @@ struct gsi_ctrl_port {
	unsigned int modem_to_host;
	unsigned int cpkt_drop_cnt;
	unsigned int get_encap_cnt;

	struct device *dev;
	struct work_struct uevent_work;
	struct workqueue_struct *uevent_wq;
};

struct gsi_data_port {