diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c index a44fca5beac225f8e863fee784cf81dfed18aef9..215381554e6ad8ab3244c1fa195b73bb44bfcab9 100644 --- a/drivers/platform/msm/usb_bam.c +++ b/drivers/platform/msm/usb_bam.c @@ -35,6 +35,8 @@ #define USB_BAM_NR_PORTS 4 +#define ARRAY_INDEX_FROM_ADDR(base, addr) ((addr) - (base)) + enum usb_bam_sm { USB_BAM_SM_INIT = 0, USB_BAM_SM_PLUG_NOTIFIED, @@ -296,8 +298,7 @@ static void usb_bam_set_inactivity_timer(enum usb_bam bam) */ for (i = 0; i < ctx.max_connections; i++) { pipe_connect = &usb_bam_connections[i]; - if (pipe_connect->bam_type == bam && - pipe_connect->enabled) { + if (pipe_connect->bam_type == bam && pipe_connect->enabled) { pipe = ctx.usb_bam_sps.sps_pipes[i]; break; } @@ -583,6 +584,7 @@ static int connect_pipe_bam2bam_ipa(u8 idx, pipe_connect->activity_notify = ipa_params->activity_notify; pipe_connect->inactivity_notify = ipa_params->inactivity_notify; pipe_connect->priv = ipa_params->priv; + pipe_connect->reset_pipe_after_lpm = ipa_params->reset_pipe_after_lpm; /* IPA input parameters */ ipa_in_params.client_bam_hdl = usb_handle; @@ -749,7 +751,7 @@ static int disconnect_pipe(u8 idx) static bool _usb_bam_resume_core(void) { - pr_debug("%s: Resuming usb peripheral/host device", __func__); + pr_debug("Resuming usb peripheral/host device\n"); if (usb_device) pm_runtime_resume(usb_device); @@ -1081,6 +1083,57 @@ int usb_bam_connect(int idx, u32 *bam_pipe_idx) return 0; } +/* This function is in expectation that the SPS team expose similar + * functionality. As a result, it is written so that when the + * function does become available, it'll have the same (expected) API. + */ +static int __sps_reset_pipe(struct sps_pipe *pipe, u32 idx) +{ + int ret; + struct sps_connect *sps_connection = + &ctx.usb_bam_sps.sps_connections[idx]; + + ret = sps_disconnect(pipe); + if (ret) { + pr_err("%s: sps_disconnect() failed %d\n", __func__, ret); + return ret; + } + + ret = sps_connect(pipe, sps_connection); + if (ret < 0) { + pr_err("%s: sps_connect() failed %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static void reset_pipe_for_resume(struct usb_bam_pipe_connect *pipe_connect) +{ + int ret; + u32 idx = ARRAY_INDEX_FROM_ADDR(usb_bam_connections, pipe_connect); + struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx]; + + if (!pipe_connect->reset_pipe_after_lpm || + pipe_connect->pipe_type != USB_BAM_PIPE_BAM2BAM) { + pr_debug("No need to reset pipe %d\n", idx); + return; + } + + ret = __sps_reset_pipe(pipe, idx); + if (ret) { + pr_err("%s failed to reset the USB sps pipe\n", __func__); + return; + } + + ret = ipa_reset_endpoint(pipe_connect->ipa_clnt_hdl); + if (ret) { + pr_err("%s failed to reset the IPA pipe\n", __func__); + return; + } + +} + /* Stop PROD transfers in case they were started */ static void stop_prod_transfers(struct usb_bam_pipe_connect *pipe_connect) { @@ -1109,7 +1162,7 @@ static void start_cons_transfers(struct usb_bam_pipe_connect *pipe_connect) if (pipe_connect->start && pipe_connect->cons_stopped) { pr_debug("%s: Enqueue CONS transfer", __func__); pipe_connect->start(pipe_connect->start_stop_param, - PEER_PERIPHERAL_TO_USB); + PEER_PERIPHERAL_TO_USB); pipe_connect->cons_stopped = 0; } } @@ -1190,14 +1243,14 @@ static void usb_bam_finish_suspend(enum usb_bam cur_bam) cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx]; pr_debug("pipes_suspended=%d pipes_to_suspend=%d", - info[cur_bam].pipes_suspended, - info[cur_bam].pipes_to_suspend); + info[cur_bam].pipes_suspended, + info[cur_bam].pipes_to_suspend); spin_unlock(&usb_bam_ipa_handshake_info_lock); ret = sps_is_pipe_empty(cons_pipe, &cons_empty); if (ret) { pr_err("%s: sps_is_pipe_empty failed with %d\n", - __func__, ret); + __func__, ret); goto no_lpm; } @@ -1215,9 +1268,9 @@ static void usb_bam_finish_suspend(enum usb_bam cur_bam) pr_debug("%s: Suspending pipe\n", __func__); /* ACK on the last pipe */ if ((info[cur_bam].pipes_suspended + 1) * 2 == - ctx.pipes_enabled_per_bam[cur_bam] && - info[cur_bam].cur_cons_state == - IPA_RM_RESOURCE_RELEASED) { + ctx.pipes_enabled_per_bam[cur_bam] && + info[cur_bam].cur_cons_state == + IPA_RM_RESOURCE_RELEASED) { ipa_rm_notify_completion( IPA_RM_RESOURCE_RELEASED, ipa_rm_resource_cons[cur_bam]); @@ -1578,7 +1631,7 @@ static void wait_for_prod_release(enum usb_bam cur_bam) pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret); } -static int check_pipes_empty(u8 src_idx, u8 dst_idx) +static bool check_pipes_empty(u8 src_idx, u8 dst_idx) { struct sps_pipe *prod_pipe, *cons_pipe; struct usb_bam_pipe_connect *prod_pipe_connect, *cons_pipe_connect; @@ -1596,18 +1649,32 @@ static int check_pipes_empty(u8 src_idx, u8 dst_idx) cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx]; pr_debug("prod_pipe=%p, cons_pipe=%p", prod_pipe, cons_pipe); - if (!prod_pipe || sps_is_pipe_empty(prod_pipe, &prod_empty) || - !cons_pipe || sps_is_pipe_empty(cons_pipe, &cons_empty)) { - pr_err("%s: sps_is_pipe_empty failed with\n", __func__); - return 1; + if (!cons_pipe || (!prod_pipe && + prod_pipe_connect->pipe_type == USB_BAM_PIPE_BAM2BAM)) { + pr_err("Missing a pipe!\n"); + return false; + } + + if (prod_pipe && sps_is_pipe_empty(prod_pipe, &prod_empty)) { + pr_err("sps_is_pipe_empty(prod) failed\n"); + return false; + } else { + prod_empty = true; } + + if (sps_is_pipe_empty(cons_pipe, &cons_empty)) { + pr_err("sps_is_pipe_empty(cons) failed\n"); + return false; + } + if (!prod_empty || !cons_empty) { - pr_err("%s: pipes not empty prod=%d cond=%d", __func__, + pr_err("pipes not empty prod=%d cond=%d", prod_empty, cons_empty); - return 0; + return false; } - return 1; + return true; + } void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params) @@ -1763,6 +1830,9 @@ static void usb_bam_finish_resume(struct work_struct *w) idx = suspended - 1; dst_idx = info[cur_bam].resume_dst_idx[idx]; pipe_connect = &usb_bam_connections[dst_idx]; + spin_unlock(&usb_bam_ipa_handshake_info_lock); + reset_pipe_for_resume(pipe_connect); + spin_lock(&usb_bam_ipa_handshake_info_lock); if (pipe_connect->cons_stopped) { pr_debug("%s: Starting CONS on %d", __func__, dst_idx); start_cons_transfers(pipe_connect); diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c index b4f4363e5fc04f736d22e37e598d23f0f79eeb61..6097adb11ef7afa8336f17a75af5edd65dcaf914 100644 --- a/drivers/usb/gadget/u_bam.c +++ b/drivers/usb/gadget/u_bam.c @@ -118,10 +118,13 @@ struct bam_ch_info { struct usb_request *rx_req; struct usb_request *tx_req; - u32 src_pipe_idx; - u32 dst_pipe_idx; - u8 src_connection_idx; - u8 dst_connection_idx; + u32 src_pipe_idx; + u32 dst_pipe_idx; + u8 src_connection_idx; + u8 dst_connection_idx; + int src_bam_idx; + int dst_bam_idx; + enum transport_type trans; struct usb_bam_connect_ipa_params ipa_params; @@ -777,9 +780,53 @@ static void gbam_stop_endless_tx(struct gbam_port *port) spin_unlock(&port->port_lock_dl); } + +/* + * This function configured data fifo based on index passed to get bam2bam + * configuration. + */ +static void configure_data_fifo(u8 idx, struct usb_ep *ep, + enum usb_bam_pipe_type pipe_type) +{ + struct u_bam_data_connect_info bam_info; + struct sps_mem_buffer data_fifo = {0}; + + if (pipe_type == USB_BAM_PIPE_BAM2BAM) { + get_bam2bam_connection_info(idx, + &bam_info.usb_bam_handle, + &bam_info.usb_bam_pipe_idx, + &bam_info.peer_pipe_idx, + NULL, &data_fifo); + + msm_data_fifo_config(ep, + data_fifo.phys_base, + data_fifo.size, + bam_info.usb_bam_pipe_idx); + } +} + + static void gbam_start(void *param, enum usb_bam_pipe_dir dir) { struct gbam_port *port = param; + struct f_rmnet *dev = NULL; + struct usb_gadget *gadget = NULL; + struct bam_ch_info *d; + + if (port) { + dev = port_to_rmnet(port->gr); + d = &port->data_ch; + } else { + pr_err("%s: port is NULL\n", __func__); + return; + } + + if (dev && dev->cdev) + gadget = dev->cdev->gadget; + else { + pr_err("%s: dev or dev->cdev are NULL\n", __func__); + return; + } if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) @@ -787,6 +834,22 @@ static void gbam_start(void *param, enum usb_bam_pipe_dir dir) else gbam_start_rx(port); } else { + if (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)) { + u8 idx; + + idx = usb_bam_get_connection_idx(gadget->name, + IPA_P_BAM, PEER_PERIPHERAL_TO_USB, + USB_BAM_DEVICE, 0); + if (idx < 0) { + pr_err("%s: get_connection_idx failed\n", + __func__); + return; + } + configure_data_fifo(idx, + port->port_usb->in, + d->dst_pipe_type); + } gbam_start_endless_tx(port); } } @@ -998,30 +1061,6 @@ static void gbam_connect_work(struct work_struct *w) pr_debug("%s: done\n", __func__); } -/* - * This function configured data fifo based on index passed to get bam2bam - * configuration. - */ -static void configure_data_fifo(u8 idx, struct usb_ep *ep, - enum usb_bam_pipe_type pipe_type) -{ - struct u_bam_data_connect_info bam_info; - struct sps_mem_buffer data_fifo = {0}; - - if (pipe_type == USB_BAM_PIPE_BAM2BAM) { - get_bam2bam_connection_info(idx, - &bam_info.usb_bam_handle, - &bam_info.usb_bam_pipe_idx, - &bam_info.peer_pipe_idx, - NULL, &data_fifo); - - msm_data_fifo_config(ep, - data_fifo.phys_base, - data_fifo.size, - bam_info.usb_bam_pipe_idx); - } -} - static void gbam2bam_connect_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, connect_w); @@ -1089,6 +1128,9 @@ static void gbam2bam_connect_work(struct work_struct *w) teth_bridge_params.usb_notify_cb; d->ipa_params.priv = teth_bridge_params.private_data; + d->ipa_params.reset_pipe_after_lpm = + (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC; d->ipa_params.skip_ep_cfg = teth_bridge_params.skip_ep_cfg; @@ -1101,18 +1143,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { - u8 idx; - - idx = usb_bam_get_connection_idx(gadget->name, - IPA_P_BAM, USB_TO_PEER_PERIPHERAL, + d->src_bam_idx = usb_bam_get_connection_idx( + gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); - if (idx < 0) { + if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } - configure_data_fifo(idx, port->port_usb->out, + configure_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); } @@ -1120,6 +1160,9 @@ static void gbam2bam_connect_work(struct work_struct *w) if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { d->ipa_params.notify = d->ul_params.teth_cb; d->ipa_params.priv = d->ul_params.teth_priv; + d->ipa_params.reset_pipe_after_lpm = + (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.dir = PEER_PERIPHERAL_TO_USB; ret = usb_bam_connect_ipa(&d->ipa_params); @@ -1130,18 +1173,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { - u8 idx; - - idx = usb_bam_get_connection_idx(gadget->name, - IPA_P_BAM, PEER_PERIPHERAL_TO_USB, + d->dst_bam_idx = usb_bam_get_connection_idx( + gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); - if (idx < 0) { + if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } - configure_data_fifo(idx, port->port_usb->in, + configure_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); } @@ -1264,10 +1305,18 @@ static void gbam2bam_suspend_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, suspend_w); struct bam_ch_info *d = &port->data_ch; + int ret; pr_debug("%s: suspend work started\n", __func__); - usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port); + ret = usb_bam_register_wake_cb(d->dst_connection_idx, + gbam_wake_cb, port); + if (ret) { + pr_err("%s(): Failed to register BAM wake callback.\n", + __func__); + return; + } + if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { usb_bam_register_start_stop_cbs(d->dst_connection_idx, gbam_start, gbam_stop, port); @@ -1279,12 +1328,40 @@ static void gbam2bam_resume_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, resume_w); struct bam_ch_info *d = &port->data_ch; + struct f_rmnet *dev = NULL; + struct usb_gadget *gadget = NULL; + int ret; pr_debug("%s: resume work started\n", __func__); + if (port) + dev = port_to_rmnet(port->gr); + if (dev && dev->cdev) { + gadget = dev->cdev->gadget; + } else { + pr_err("Unable to retrieve gadget handle\n"); + return; + } - usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); - if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) + ret = usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); + if (ret) { + pr_err("%s(): Failed to register BAM wake callback.\n", + __func__); + return; + } + + if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { + if (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)) { + configure_data_fifo(d->src_bam_idx, + port->port_usb->out, + d->src_pipe_type); + configure_data_fifo(d->dst_bam_idx, + port->port_usb->in, + d->dst_pipe_type); + msm_dwc3_reset_dbm_ep(port->port_usb->in); + } usb_bam_resume(&d->ipa_params); + } } static int gbam_peer_reset_cb(void *param) diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c index a0d8b245ae6da205526fb8554bb4d764b5177021..0ae7826072fdc0b660a31477225679fc5130d508 100644 --- a/drivers/usb/gadget/u_bam_data.c +++ b/drivers/usb/gadget/u_bam_data.c @@ -81,6 +81,8 @@ struct bam_data_ch_info { u32 dst_pipe_idx; u8 src_connection_idx; u8 dst_connection_idx; + int src_bam_idx; + int dst_bam_idx; enum function_type func_type; enum transport_type trans; @@ -653,6 +655,10 @@ static void bam2bam_data_connect_work(struct work_struct *w) bam_data_ipa_sys2bam_notify_cb; d->ul_params.teth_priv = d->ipa_params.priv; d->ipa_params.priv = &d->ul_params; + } else { + d->ipa_params.reset_pipe_after_lpm = + (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)); } ret = usb_bam_connect_ipa(&d->ipa_params); @@ -665,18 +671,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep = d->ipa_params.ipa_cons_ep_idx; if (gadget_is_dwc3(gadget)) { - u8 idx; - - idx = usb_bam_get_connection_idx(gadget->name, - IPA_P_BAM, USB_TO_PEER_PERIPHERAL, - USB_BAM_DEVICE, 0); - if (idx < 0) { + d->src_bam_idx = usb_bam_get_connection_idx( + gadget->name, + IPA_P_BAM, USB_TO_PEER_PERIPHERAL, + USB_BAM_DEVICE, 0); + if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } - configure_usb_data_fifo(idx, port->port_usb->out, + configure_usb_data_fifo(d->src_bam_idx, + port->port_usb->out, d->src_pipe_type); } @@ -699,6 +705,13 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->ipa_params.skip_ep_cfg = rndis_qc_get_skip_ep_config(); } + + if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) { + d->ipa_params.reset_pipe_after_lpm = + (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)); + } + ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", @@ -712,18 +725,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep); if (gadget_is_dwc3(gadget)) { - u8 idx; - - idx = usb_bam_get_connection_idx(gadget->name, - IPA_P_BAM, PEER_PERIPHERAL_TO_USB, - USB_BAM_DEVICE, 0); - if (idx < 0) { + d->dst_bam_idx = usb_bam_get_connection_idx( + gadget->name, + IPA_P_BAM, PEER_PERIPHERAL_TO_USB, + USB_BAM_DEVICE, 0); + if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } - configure_usb_data_fifo(idx, port->port_usb->in, + configure_usb_data_fifo(d->dst_bam_idx, + port->port_usb->in, d->dst_pipe_type); } @@ -1204,6 +1217,16 @@ static int bam_data_wake_cb(void *param) static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) { struct bam_data_port *port = param; + struct data_port *d_port = port->port_usb; + struct bam_data_ch_info *d = &port->data_ch; + struct usb_gadget *gadget; + + if (!d_port || !d_port->cdev || !d_port->cdev->gadget) { + pr_err("%s:d_port,cdev or gadget is NULL\n", __func__); + return; + } + + gadget = d_port->cdev->gadget; if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) @@ -1211,6 +1234,22 @@ static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) else bam_data_start_rx(port); } else { + if (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)) { + u8 idx; + + idx = usb_bam_get_connection_idx(gadget->name, + IPA_P_BAM, PEER_PERIPHERAL_TO_USB, + USB_BAM_DEVICE, 0); + if (idx < 0) { + pr_err("%s: get_connection_idx failed\n", + __func__); + return; + } + configure_data_fifo(idx, + port->port_usb->in, + d->dst_pipe_type); + } bam_data_start_endless_tx(port); } @@ -1293,6 +1332,8 @@ static void bam2bam_data_resume_work(struct work_struct *w) struct bam_data_port *port = container_of(w, struct bam_data_port, resume_w); struct bam_data_ch_info *d = &port->data_ch; + struct data_port *d_port = port->port_usb; + struct usb_gadget *gadget = d_port->cdev->gadget; int ret; pr_debug("%s: resume work started\n", __func__); @@ -1309,8 +1350,19 @@ static void bam2bam_data_resume_work(struct work_struct *w) return; } - if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) + if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { + if (gadget_is_dwc3(gadget) && + msm_dwc3_reset_ep_after_lpm(gadget)) { + configure_usb_data_fifo(d->src_bam_idx, + port->port_usb->out, + d->src_pipe_type); + configure_usb_data_fifo(d->dst_bam_idx, + port->port_usb->in, + d->dst_pipe_type); + msm_dwc3_reset_dbm_ep(port->port_usb->in); + } usb_bam_resume(&d->ipa_params); + } } void u_bam_data_set_max_xfer_size(u32 max_transfer_size) diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 079e6277733528298e0b2adf5fb25385ef8ed785..51d5ce2bdd6e33ed86bf2427ea5d1ff294f2d606 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -615,6 +615,8 @@ int msm_ep_unconfig(struct usb_ep *ep); void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable); int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size, u8 dst_pipe_idx); +bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget); +int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); void msm_dwc3_restart_usb_session(struct usb_gadget *gadget); @@ -652,5 +654,16 @@ static inline int msm_register_usb_ext_notification( { return -ENODEV; } + +static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) +{ + return false; +} + +static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep) +{ + return -ENODEV; +} + #endif #endif diff --git a/include/linux/usb_bam.h b/include/linux/usb_bam.h index 20e50e0f878e8e4e926f47cfe2c5ecd5b9d7b040..a94ebcf699235e80b3006f6149e04d1c3a4ce144 100644 --- a/include/linux/usb_bam.h +++ b/include/linux/usb_bam.h @@ -83,6 +83,7 @@ struct usb_bam_connect_ipa_params { int (*activity_notify)(void *priv); int (*inactivity_notify)(void *priv); bool skip_ep_cfg; + bool reset_pipe_after_lpm; }; /** @@ -162,6 +163,7 @@ struct usb_bam_pipe_connect { void (*start)(void *, enum usb_bam_pipe_dir); void (*stop)(void *, enum usb_bam_pipe_dir); void *start_stop_param; + bool reset_pipe_after_lpm; }; /**