msm: usb: fix mdm bridge channel mismatch when disconnecting
The bridge_disconnect assumed the internal channel id in pre-defined order, which was not matched with the actual usb_interface to be disconnected. Due to this, other internal resources were freed unexpectedly and caused occasional crash during reset and power off. Implemented new routines for matching usb_interface and internal channel id to free proper resources when bridge_disconnect is called. Change-Id: I0ca604423dd36928f99fad3e21a24ed4699f96c3
This commit is contained in:
committed by
Iliyan Malchev
parent
5f7f224e7b
commit
becc299c0d
@@ -109,6 +109,25 @@ static unsigned int get_timestamp(void);
|
||||
static void dbg_timestamp(char *, struct sk_buff *);
|
||||
static int submit_rx_urb(struct data_bridge *dev, struct urb *urb,
|
||||
gfp_t flags);
|
||||
static void* interface[MAX_BRIDGE_DEVICES];
|
||||
|
||||
static inline int get_chid(struct usb_interface *iface)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
|
||||
if (interface[i] == iface)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void set_chid(struct usb_interface *iface, int chid)
|
||||
{
|
||||
if (chid >= 0 && chid < MAX_BRIDGE_DEVICES) {
|
||||
interface[chid] = iface;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool rx_halted(struct data_bridge *dev)
|
||||
{
|
||||
@@ -962,6 +981,8 @@ bridge_probe(struct usb_interface *iface, const struct usb_device_id *id)
|
||||
goto free_data_bridge;
|
||||
}
|
||||
|
||||
set_chid(iface, ch_id);
|
||||
|
||||
ch_id++;
|
||||
|
||||
return 0;
|
||||
@@ -983,17 +1004,26 @@ static void bridge_disconnect(struct usb_interface *intf)
|
||||
struct list_head *head;
|
||||
struct urb *rx_urb;
|
||||
unsigned long flags;
|
||||
int chid;
|
||||
|
||||
if (!dev) {
|
||||
err("%s: data device not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ch_id--;
|
||||
ctrl_bridge_disconnect(ch_id);
|
||||
ch_id--; /* leave it for now */
|
||||
|
||||
chid = get_chid(intf);
|
||||
|
||||
if (chid < 0) {
|
||||
err("%s: invalid interface\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ctrl_bridge_disconnect(chid);
|
||||
platform_device_unregister(dev->pdev);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
__dev[ch_id] = NULL;
|
||||
__dev[chid] = NULL;
|
||||
|
||||
cancel_work_sync(&dev->process_rx_w);
|
||||
cancel_work_sync(&dev->kevent);
|
||||
@@ -1010,6 +1040,8 @@ static void bridge_disconnect(struct usb_interface *intf)
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev);
|
||||
|
||||
set_chid(NULL, chid);
|
||||
}
|
||||
|
||||
/*bit position represents interface number*/
|
||||
|
||||
Reference in New Issue
Block a user