static int start_ipc(struct link_device *ld, struct io_device *iod) { struct sk_buff *skb; char data[1] = {'a'}; int err; struct usb_link_device *usb_ld = to_usb_link_device(ld); struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; mif_err("\n"); if (usb_ld->link_pm_data->hub_handshake_done) { mif_err("Aleady send start ipc, skip start ipc\n"); err = 0; goto exit; } if (!usb_ld->if_usb_connected) { mif_err("HSIC/USB not connected, skip start ipc\n"); err = -ENODEV; goto exit; } if (usb_ld->if_usb_initstates == INIT_IPC_START_DONE) { mif_debug("aleady IPC started\n"); err = 0; goto exit; } mif_info("send 'a'\n"); skb = alloc_skb(16, GFP_ATOMIC); if (unlikely(!skb)) return -ENOMEM; memcpy(skb_put(skb, 1), data, 1); skbpriv(skb)->iod = iod; skbpriv(skb)->ld = &usb_ld->ld; err = usb_tx_urb_with_skb(usb_ld, skb, pipe_data); if (err < 0) { mif_err("usb_tx_urb fail\n"); goto exit; } usb_ld->link_pm_data->hub_handshake_done = true; usb_ld->if_usb_initstates = INIT_IPC_START_DONE; exit: return err; }
static int start_ipc(struct link_device *ld, struct io_device *iod) { struct sk_buff *skb; char data[1] = {'a'}; int err; struct usb_link_device *usb_ld = to_usb_link_device(ld); struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; if (!usb_ld->if_usb_connected) { mif_err("HSIC not connected, skip start ipc\n"); err = -ENODEV; goto exit; } if (ld->mc->phone_state != STATE_ONLINE) { mif_err("[MODEM_IF] MODEM is not online, skip start ipc\n"); err = -ENODEV; goto exit; } mif_err("send 'a'\n"); skb = alloc_skb(16, GFP_ATOMIC); if (unlikely(!skb)) return -ENOMEM; memcpy(skb_put(skb, 1), data, 1); skbpriv(skb)->iod = iod; skbpriv(skb)->ld = ld; if (!usb_ld->if_usb_connected || !usb_ld->usbdev) return -ENODEV; usb_mark_last_busy(usb_ld->usbdev); err = usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data); if (err < 0) { mif_err("usb_tx_urb fail\n"); dev_kfree_skb_any(skb); goto exit; } exit: return err; }
static int _usb_tx_work(struct sk_buff *skb) { struct sk_buff_head *txq; struct io_device *iod = skbpriv(skb)->iod; struct link_device *ld = skbpriv(skb)->ld; struct usb_link_device *usb_ld = to_usb_link_device(ld); struct if_usb_devdata *pipe_data; switch (iod->format) { case IPC_BOOT: case IPC_FMT: /* boot device uses same intf with fmt*/ pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; txq = &ld->sk_fmt_tx_q; break; case IPC_RAW: pipe_data = &usb_ld->devdata[IF_USB_RAW_EP]; txq = &ld->sk_raw_tx_q; break; case IPC_RFS: pipe_data = &usb_ld->devdata[IF_USB_RFS_EP]; txq = &ld->sk_fmt_tx_q; break; default: /* wrong packet, drop it */ pipe_data = NULL; txq = NULL; break; } if (!pipe_data) return -ENOENT; #if 0 if (iod->format == IPC_FMT && usb_ld->if_usb_is_main) pr_skb("IPC-TX", skb); #endif if (iod->format == IPC_RAW) mif_debug("TX[RAW]\n"); return usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data); }
static void usb_tx_work(struct work_struct *work) { int ret = 0; struct link_device *ld = container_of(work, struct link_device, tx_delayed_work.work); struct usb_link_device *usb_ld = to_usb_link_device(ld); struct io_device *iod; struct sk_buff *skb; struct if_usb_devdata *pipe_data; struct link_pm_data *pm_data = usb_ld->link_pm_data; /*TODO: check the PHONE ACTIVE STATES */ /* because tx data wait until hub on with wait_for_complettion, it should queue to single_threaded work queue */ if (!link_pm_set_active(usb_ld)) return; while (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) { /* send skb from fmt_txq and raw_txq, * one by one for fair flow control */ skb = skb_dequeue(&ld->sk_fmt_tx_q); if (skb) { iod = skbpriv(skb)->iod; switch (iod->format) { case IPC_BOOT: case IPC_RAMDUMP: case IPC_FMT: /* boot device uses same intf with fmt*/ pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; break; case IPC_RFS: pipe_data = &usb_ld->devdata[IF_USB_RFS_EP]; break; default: /* wrong packet for fmt tx q , drop it */ dev_kfree_skb_any(skb); continue; } ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data); if (ret < 0) { mif_err("usb_tx_urb_with_skb, ret(%d)\n", ret); skb_queue_head(&ld->sk_fmt_tx_q, skb); return; } } skb = skb_dequeue(&ld->sk_raw_tx_q); if (skb) { pipe_data = &usb_ld->devdata[IF_USB_RAW_EP]; ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data); if (ret < 0) { mif_err("usb_tx_urb_with_skb " "for raw, ret(%d)\n", ret); skb_queue_head(&ld->sk_raw_tx_q, skb); return; } } } }
static int start_ipc(struct link_device *ld, struct io_device *iod) { struct sk_buff *skb; char data[1] = {'a'}; int err; struct usb_link_device *usb_ld = to_usb_link_device(ld); struct link_pm_data *pm_data = usb_ld->link_pm_data; struct device *dev = &usb_ld->usbdev->dev; struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; if (!usb_ld->if_usb_connected) { mif_err("HSIC not connected, skip start ipc\n"); err = -ENODEV; goto exit; } retry: if (ld->mc->phone_state != STATE_ONLINE) { mif_err("MODEM is not online, skip start ipc\n"); err = -ENODEV; goto exit; } /* check usb runtime pm first */ if (dev->power.runtime_status != RPM_ACTIVE) { if (!pm_data->resume_requested) { mif_debug("QW PM\n"); INIT_COMPLETION(pm_data->active_done); queue_delayed_work(pm_data->wq, &pm_data->link_pm_work, 0); } mif_debug("Wait pm\n"); err = wait_for_completion_timeout(&pm_data->active_done, msecs_to_jiffies(500)); /* timeout or -ERESTARTSYS */ if (err <= 0) goto retry; } pm_runtime_get_sync(dev); mif_err("send 'a'\n"); skb = alloc_skb(16, GFP_ATOMIC); if (unlikely(!skb)) { pm_runtime_put(dev); return -ENOMEM; } memcpy(skb_put(skb, 1), data, 1); skbpriv(skb)->iod = iod; skbpriv(skb)->ld = ld; if (!usb_ld->if_usb_connected || !usb_ld->usbdev) return -ENODEV; usb_mark_last_busy(usb_ld->usbdev); err = usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data); if (err < 0) { mif_err("usb_tx_urb fail\n"); dev_kfree_skb_any(skb); } pm_runtime_put(dev); exit: return err; }
static int _usb_tx_work(struct sk_buff *skb) { struct sk_buff_head *txq; struct io_device *iod = skbpriv(skb)->iod; struct link_device *ld = skbpriv(skb)->ld; struct usb_link_device *usb_ld = to_usb_link_device(ld); struct if_usb_devdata *pipe_data; int ret; switch (iod->format) { case IPC_BOOT: case IPC_FMT: /* boot device uses same intf with fmt*/ pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; txq = &ld->sk_fmt_tx_q; break; case IPC_RAW: pipe_data = &usb_ld->devdata[IF_USB_RAW_EP]; txq = &ld->sk_raw_tx_q; break; case IPC_RFS: pipe_data = &usb_ld->devdata[IF_USB_RFS_EP]; txq = &ld->sk_fmt_tx_q; break; default: /* wrong packet, drop it */ pipe_data = NULL; break; } if (!pipe_data) { dev_kfree_skb_any(skb); return -ENOENT; } if (iod->format == IPC_FMT && usb_ld->if_usb_is_main) pr_skb("IPC-TX", skb); if (iod->format == IPC_RAW) mif_debug("TX[RAW]\n"); if (iod->format == IPC_RFS) pr_skb("RFS-TX", skb); if (!usb_ld->if_usb_connected || !usb_ld->usbdev) return -ENODEV; usb_mark_last_busy(usb_ld->usbdev); ret = usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data); if (ret < 0) { if (ret == -ENODEV || ret == -ENOENT) { mif_err("link broken while in runtime active ..." " purge!\n"); return ret; } mif_err("usb_tx_urb_with_skb for iod(%d), ret=%d\n", iod->format, ret); skb_queue_head(txq, skb); queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, msecs_to_jiffies(20)); return ret; } return 0; }