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

Commit ec22e5d2 authored by Vamsi Krishna Samavedam's avatar Vamsi Krishna Samavedam
Browse files

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



Currently gsi driver indicates the state change by 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>
parent 931284c5
Loading
Loading
Loading
Loading
+81 −1
Original line number Diff line number Diff line
@@ -1640,6 +1640,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;
@@ -1654,6 +1663,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;

	switch (gsi->prot_id) {
	case USB_PROT_RMNET_IPA:
@@ -1683,6 +1695,10 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
	else
		strlcat(gsi->c_port.name, cdev_name, sz);

	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__,
@@ -1698,7 +1714,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__,
@@ -1707,6 +1723,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:
@@ -2156,6 +2174,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;
@@ -2520,6 +2542,9 @@ static int gsi_set_alt(struct usb_function *f, unsigned int intf,
				gsi->prot_id == USB_PROT_MBIM_IPA)
		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 0;

notify_ep_disable:
@@ -2553,6 +2578,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;
@@ -3711,14 +3740,27 @@ static int gsi_set_inst_name(struct usb_function_instance *fi,
static void gsi_free_inst(struct usb_function_instance *f)
{
	struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst);
	struct f_gsi *gsi;

	if (opts && opts->gsi && opts->gsi->c_port.cdev.dev) {
		struct cdev *cdev = &opts->gsi->c_port.cdev;
		int minor = MINOR(cdev->dev);
		gsi = opts->gsi;

		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);
	}

@@ -3759,6 +3801,43 @@ 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 USB_PROT_RMNET_IPA:
	case USB_PROT_RMNET_ETHER:
		str = gsi->rmnet_dtr_status ? "connected" : "disconnected";
		break;
	case USB_PROT_MBIM_IPA:
	case USB_PROT_DIAG_IPA:
	case USB_PROT_DPL_ETHER:
	case USB_PROT_GPS_CTRL:
		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;
@@ -3789,6 +3868,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
@@ -220,6 +220,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 {