mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 16:46:15 -04:00
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: Vamsi Krishna Samavedam <vskrishn@codeaurora.org> Signed-off-by: Elson Roy Serrao <eserrao@codeaurora.org>
This commit is contained in:
parent
eafa579022
commit
6851e8ccd4
2 changed files with 81 additions and 1 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue