Merge "usb: gadget: Add DPL support using IPA over BAM2BAM"

This commit is contained in:
Linux Build Service Account 2016-12-20 14:04:29 -08:00 committed by Gerrit - the friendly Code Review server
commit 03a382981c
4 changed files with 421 additions and 235 deletions

View file

@ -26,20 +26,18 @@
#define RMNET_NOTIFY_INTERVAL 5
#define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification)
#define ACM_CTRL_DTR (1 << 0)
/* TODO: use separate structures for data and
* control paths
*/
struct f_rmnet {
struct usb_function func;
enum qti_port_type qti_port_type;
enum ipa_func_type func_type;
struct grmnet port;
int ifc_id;
atomic_t online;
atomic_t ctrl_online;
struct usb_composite_dev *cdev;
struct gadget_ipa_port ipa_port;
spinlock_t lock;
/* usb eps*/
@ -47,11 +45,9 @@ struct f_rmnet {
struct usb_request *notify_req;
/* control info */
struct gadget_ipa_port ipa_port;
struct list_head cpkt_resp_q;
unsigned long notify_count;
unsigned long cpkts_len;
} *rmnet_port;
};
static struct usb_interface_descriptor rmnet_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
@ -213,6 +209,70 @@ static struct usb_gadget_strings *rmnet_strings[] = {
NULL,
};
static struct usb_interface_descriptor dpl_data_intf_desc = {
.bLength = sizeof(dpl_data_intf_desc),
.bDescriptorType = USB_DT_INTERFACE,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
};
static struct usb_endpoint_descriptor dpl_hs_data_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor dpl_ss_data_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor dpl_data_ep_comp_desc = {
.bLength = sizeof(dpl_data_ep_comp_desc),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
.bMaxBurst = 1,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
static struct usb_descriptor_header *dpl_hs_data_only_desc[] = {
(struct usb_descriptor_header *) &dpl_data_intf_desc,
(struct usb_descriptor_header *) &dpl_hs_data_desc,
NULL,
};
static struct usb_descriptor_header *dpl_ss_data_only_desc[] = {
(struct usb_descriptor_header *) &dpl_data_intf_desc,
(struct usb_descriptor_header *) &dpl_ss_data_desc,
(struct usb_descriptor_header *) &dpl_data_ep_comp_desc,
NULL,
};
/* string descriptors: */
static struct usb_string dpl_string_defs[] = {
[0].s = "QDSS DATA",
{}, /* end of list */
};
static struct usb_gadget_strings dpl_string_table = {
.language = 0x0409,
.strings = dpl_string_defs,
};
static struct usb_gadget_strings *dpl_strings[] = {
&dpl_string_table,
NULL,
};
static void frmnet_ctrl_response_available(struct f_rmnet *dev);
/* ------- misc functions --------------------*/
@ -227,6 +287,24 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r)
return container_of(r, struct f_rmnet, port);
}
int name_to_prot(struct f_rmnet *dev, const char *name)
{
if (!name)
goto error;
if (!strncasecmp("rmnet", name, MAX_INST_NAME_LEN)) {
dev->qti_port_type = QTI_PORT_RMNET;
dev->func_type = USB_IPA_FUNC_RMNET;
} else if (!strncasecmp("dpl", name, MAX_INST_NAME_LEN)) {
dev->qti_port_type = QTI_PORT_DPL;
dev->func_type = USB_IPA_FUNC_DPL;
}
return 0;
error:
return -EINVAL;
}
static struct usb_request *
frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags)
{
@ -279,51 +357,57 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
/* -------------------------------------------*/
static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf)
static int gport_rmnet_connect(struct f_rmnet *dev)
{
int ret;
int src_connection_idx = 0, dst_connection_idx = 0;
struct usb_gadget *gadget = dev->cdev->gadget;
enum usb_ctrl usb_bam_type;
int bam_pipe_num = (dev->qti_port_type == QTI_PORT_DPL) ? 1 : 0;
ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id);
ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id);
if (ret) {
pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
__func__, ret);
return ret;
}
if (dev->qti_port_type == QTI_PORT_DPL)
dev->port.send_encap_cmd(QTI_PORT_DPL, NULL, 0);
dev->ipa_port.cdev = dev->cdev;
ipa_data_port_select(USB_IPA_FUNC_RMNET);
ipa_data_port_select(dev->func_type);
usb_bam_type = usb_bam_get_bam_type(gadget->name);
src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
QTI_PORT_RMNET);
dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
QTI_PORT_RMNET);
if (dev->ipa_port.in) {
dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, PEER_PERIPHERAL_TO_USB,
USB_BAM_DEVICE, bam_pipe_num);
}
if (dev->ipa_port.out) {
src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, USB_TO_PEER_PERIPHERAL,
USB_BAM_DEVICE, bam_pipe_num);
}
if (dst_connection_idx < 0 || src_connection_idx < 0) {
pr_err("%s: usb_bam_get_connection_idx failed\n",
__func__);
gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
return -EINVAL;
}
ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET,
ret = ipa_data_connect(&dev->ipa_port, dev->func_type,
src_connection_idx, dst_connection_idx);
if (ret) {
pr_err("%s: ipa_data_connect failed: err:%d\n",
__func__, ret);
gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
return ret;
}
return 0;
}
static int gport_rmnet_disconnect(struct f_rmnet *dev)
{
gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET);
gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
ipa_data_disconnect(&dev->ipa_port, dev->func_type);
return 0;
}
@ -333,24 +417,25 @@ static void frmnet_free(struct usb_function *f)
opts = container_of(f->fi, struct f_rmnet_opts, func_inst);
opts->refcnt--;
kfree(rmnet_port);
rmnet_port = NULL;
}
static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_gadget *gadget = c->cdev->gadget;
pr_debug("%s: start unbinding\n", __func__);
if (gadget_is_superspeed(c->cdev->gadget))
pr_debug("%s: start unbinding\nclear_desc\n", __func__);
if (gadget_is_superspeed(gadget) && f->ss_descriptors)
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget))
if (gadget_is_dualspeed(gadget) && f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->fs_descriptors);
frmnet_free_req(dev->notify, dev->notify_req);
if (f->fs_descriptors)
usb_free_descriptors(f->fs_descriptors);
kfree(f->name);
if (dev->notify_req)
frmnet_free_req(dev->notify, dev->notify_req);
}
static void frmnet_purge_responses(struct f_rmnet *dev)
@ -384,11 +469,11 @@ static void frmnet_suspend(struct usb_function *f)
pr_debug("%s: dev: %p remote_wakeup: %d\n",
__func__, dev, remote_wakeup_allowed);
usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET,
remote_wakeup_allowed);
if (dev->notify) {
usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
}
ipa_data_suspend(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
}
static void frmnet_resume(struct usb_function *f)
@ -404,8 +489,7 @@ static void frmnet_resume(struct usb_function *f)
pr_debug("%s: dev: %p remote_wakeup: %d\n",
__func__, dev, remote_wakeup_allowed);
ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET,
remote_wakeup_allowed);
ipa_data_resume(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
}
static void frmnet_disable(struct usb_function *f)
@ -413,15 +497,13 @@ static void frmnet_disable(struct usb_function *f)
struct f_rmnet *dev = func_to_rmnet(f);
pr_debug("%s: Disabling\n", __func__);
usb_ep_disable(dev->notify);
dev->notify->driver_data = NULL;
atomic_set(&dev->online, 0);
if (dev->notify) {
usb_ep_disable(dev->notify);
dev->notify->driver_data = NULL;
frmnet_purge_responses(dev);
}
frmnet_purge_responses(dev);
msm_ep_unconfig(dev->ipa_port.out);
msm_ep_unconfig(dev->ipa_port.in);
gport_rmnet_disconnect(dev);
}
@ -430,64 +512,78 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_composite_dev *cdev = f->config->cdev;
int ret;
struct list_head *cpkt;
int ret = 0;
pr_debug("%s: dev: %p\n", __func__, dev);
dev->cdev = cdev;
if (dev->notify->driver_data) {
pr_debug("%s: reset port\n", __func__);
usb_ep_disable(dev->notify);
}
ret = config_ep_by_speed(cdev->gadget, f, dev->notify);
if (ret) {
dev->notify->desc = NULL;
ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
dev->notify->name, ret);
return ret;
}
ret = usb_ep_enable(dev->notify);
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, dev->notify->name, ret);
dev->notify->desc = NULL;
return ret;
}
dev->notify->driver_data = dev;
if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) {
if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) ||
config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) {
pr_err("%s(): config_ep_by_speed failed.\n", __func__);
ret = -EINVAL;
goto err_disable_ep;
if (dev->notify) {
if (dev->notify->driver_data) {
pr_debug("%s: reset port\n", __func__);
usb_ep_disable(dev->notify);
}
dev->ipa_port.cdev = dev->cdev;
ret = config_ep_by_speed(cdev->gadget, f, dev->notify);
if (ret) {
dev->notify->desc = NULL;
ERROR(cdev,
"config_ep_by_speed failed for ep %s, result %d\n",
dev->notify->name, ret);
return ret;
}
ret = usb_ep_enable(dev->notify);
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, dev->notify->name, ret);
dev->notify->desc = NULL;
return ret;
}
dev->notify->driver_data = dev;
}
ret = gport_rmnet_connect(dev, intf);
if (dev->ipa_port.in && !dev->ipa_port.in->desc
&& config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in)) {
pr_err("%s(): config_ep_by_speed failed.\n",
__func__);
dev->ipa_port.in->desc = NULL;
ret = -EINVAL;
goto err_disable_ep;
}
if (dev->ipa_port.out && !dev->ipa_port.out->desc
&& config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) {
pr_err("%s(): config_ep_by_speed failed.\n",
__func__);
dev->ipa_port.out->desc = NULL;
ret = -EINVAL;
goto err_disable_ep;
}
ret = gport_rmnet_connect(dev);
if (ret) {
pr_err("%s(): gport_rmnet_connect fail with err:%d\n",
__func__, ret);
__func__, ret);
goto err_disable_ep;
}
atomic_set(&dev->online, 1);
/*
* In case notifications were aborted, but there are pending control
* packets in the response queue, re-add the notifications.
*/
list_for_each(cpkt, &dev->cpkt_resp_q)
frmnet_ctrl_response_available(dev);
* In case notifications were aborted, but there are
* pending control packets in the response queue,
* re-add the notifications.
*/
if (dev->qti_port_type == QTI_PORT_RMNET) {
struct list_head *cpkt;
list_for_each(cpkt, &dev->cpkt_resp_q)
frmnet_ctrl_response_available(dev);
}
return ret;
err_disable_ep:
dev->ipa_port.in->desc = NULL;
dev->ipa_port.out->desc = NULL;
usb_ep_disable(dev->notify);
if (dev->notify && dev->notify->driver_data)
usb_ep_disable(dev->notify);
return ret;
}
@ -813,108 +909,119 @@ invalid:
return ret;
}
static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
static int ipa_update_function_bind_params(struct f_rmnet *dev,
struct usb_composite_dev *cdev, struct ipa_function_bind_info *info)
{
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_ep *ep;
struct usb_composite_dev *cdev = c->cdev;
int ret = -ENODEV;
struct usb_ep *ep;
struct usb_function *f = &dev->func;
int status;
if (rmnet_string_defs[0].id == 0) {
ret = usb_string_id(c->cdev);
if (ret < 0) {
pr_err("%s: failed to get string id, err:%d\n",
__func__, ret);
return ret;
/* maybe allocate device-global string IDs */
if (info->string_defs[0].id != 0)
goto skip_string_id_alloc;
if (info->data_str_idx >= 0 && info->data_desc) {
/* data interface label */
status = usb_string_id(cdev);
if (status < 0)
return status;
info->string_defs[info->data_str_idx].id = status;
info->data_desc->iInterface = status;
}
skip_string_id_alloc:
if (info->data_desc)
info->data_desc->bInterfaceNumber = dev->ifc_id;
if (info->fs_in_desc) {
ep = usb_ep_autoconfig(cdev->gadget, info->fs_in_desc);
if (!ep) {
pr_err("%s: usb epin autoconfig failed\n",
__func__);
return -ENODEV;
}
rmnet_string_defs[0].id = ret;
dev->ipa_port.in = ep;
ep->driver_data = cdev;
}
pr_debug("%s: start binding\n", __func__);
dev->ifc_id = usb_interface_id(c, f);
if (dev->ifc_id < 0) {
pr_err("%s: unable to allocate ifc id, err:%d\n",
__func__, dev->ifc_id);
return dev->ifc_id;
if (info->fs_out_desc) {
ep = usb_ep_autoconfig(cdev->gadget, info->fs_out_desc);
if (!ep) {
pr_err("%s: usb epout autoconfig failed\n",
__func__);
status = -ENODEV;
goto ep_auto_out_fail;
}
dev->ipa_port.out = ep;
ep->driver_data = cdev;
}
rmnet_interface_desc.bInterfaceNumber = dev->ifc_id;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_in_desc);
if (!ep) {
pr_err("%s: usb epin autoconfig failed\n", __func__);
return -ENODEV;
}
dev->ipa_port.in = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc);
if (!ep) {
pr_err("%s: usb epout autoconfig failed\n", __func__);
ret = -ENODEV;
goto ep_auto_out_fail;
}
dev->ipa_port.out = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc);
if (!ep) {
pr_err("%s: usb epnotify autoconfig failed\n", __func__);
ret = -ENODEV;
goto ep_auto_notify_fail;
}
dev->notify = ep;
ep->driver_data = cdev;
dev->notify_req = frmnet_alloc_req(ep,
if (info->fs_notify_desc) {
ep = usb_ep_autoconfig(cdev->gadget, info->fs_notify_desc);
if (!ep) {
pr_err("%s: usb epnotify autoconfig failed\n",
__func__);
status = -ENODEV;
goto ep_auto_notify_fail;
}
dev->notify = ep;
ep->driver_data = cdev;
dev->notify_req = frmnet_alloc_req(ep,
sizeof(struct usb_cdc_notification),
GFP_KERNEL);
if (IS_ERR(dev->notify_req)) {
pr_err("%s: unable to allocate memory for notify req\n",
if (IS_ERR(dev->notify_req)) {
pr_err("%s: unable to allocate memory for notify req\n",
__func__);
ret = -ENOMEM;
goto ep_notify_alloc_fail;
status = -ENOMEM;
goto ep_notify_alloc_fail;
}
dev->notify_req->complete = frmnet_notify_complete;
dev->notify_req->context = dev;
}
dev->notify_req->complete = frmnet_notify_complete;
dev->notify_req->context = dev;
ret = -ENOMEM;
f->fs_descriptors = usb_copy_descriptors(rmnet_fs_function);
status = -ENOMEM;
f->fs_descriptors = usb_copy_descriptors(info->fs_desc_hdr);
if (!f->fs_descriptors) {
pr_err("%s: no descriptors,usb_copy descriptors(fs)failed\n",
pr_err("%s: no descriptors, usb_copy descriptors(fs)failed\n",
__func__);
goto fail;
}
if (gadget_is_dualspeed(cdev->gadget)) {
rmnet_hs_in_desc.bEndpointAddress =
rmnet_fs_in_desc.bEndpointAddress;
rmnet_hs_out_desc.bEndpointAddress =
rmnet_fs_out_desc.bEndpointAddress;
rmnet_hs_notify_desc.bEndpointAddress =
rmnet_fs_notify_desc.bEndpointAddress;
if (info->fs_in_desc && info->hs_in_desc)
info->hs_in_desc->bEndpointAddress =
info->fs_in_desc->bEndpointAddress;
if (info->fs_out_desc && info->hs_out_desc)
info->hs_out_desc->bEndpointAddress =
info->fs_out_desc->bEndpointAddress;
if (info->fs_notify_desc && info->hs_notify_desc)
info->hs_notify_desc->bEndpointAddress =
info->fs_notify_desc->bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(rmnet_hs_function);
f->hs_descriptors = usb_copy_descriptors(info->hs_desc_hdr);
if (!f->hs_descriptors) {
pr_err("%s: no hs_descriptors,usb_copy descriptors(hs)failed\n",
__func__);
pr_err("%s: no hs_descriptors, usb_copy descriptors(hs)failed\n",
__func__);
goto fail;
}
}
if (gadget_is_superspeed(cdev->gadget)) {
rmnet_ss_in_desc.bEndpointAddress =
rmnet_fs_in_desc.bEndpointAddress;
rmnet_ss_out_desc.bEndpointAddress =
rmnet_fs_out_desc.bEndpointAddress;
rmnet_ss_notify_desc.bEndpointAddress =
rmnet_fs_notify_desc.bEndpointAddress;
if (info->fs_in_desc && info->ss_in_desc)
info->ss_in_desc->bEndpointAddress =
info->fs_in_desc->bEndpointAddress;
if (info->fs_out_desc && info->ss_out_desc)
info->ss_out_desc->bEndpointAddress =
info->fs_out_desc->bEndpointAddress;
if (info->fs_notify_desc && info->ss_notify_desc)
info->ss_notify_desc->bEndpointAddress =
info->fs_notify_desc->bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->ss_descriptors = usb_copy_descriptors(rmnet_ss_function);
f->ss_descriptors = usb_copy_descriptors(info->ss_desc_hdr);
if (!f->ss_descriptors) {
pr_err("%s: no ss_descriptors,usb_copy descriptors(ss)failed\n",
__func__);
@ -922,57 +1029,95 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
}
}
pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n",
__func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
dev->ipa_port.in->name, dev->ipa_port.out->name);
return 0;
fail:
if (f->ss_descriptors)
if (gadget_is_superspeed(cdev->gadget) && f->ss_descriptors)
usb_free_descriptors(f->ss_descriptors);
if (f->hs_descriptors)
if (gadget_is_dualspeed(cdev->gadget) && f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors);
if (f->fs_descriptors)
usb_free_descriptors(f->fs_descriptors);
if (dev->notify_req)
frmnet_free_req(dev->notify, dev->notify_req);
ep_notify_alloc_fail:
dev->notify->driver_data = NULL;
dev->notify = NULL;
dev->notify->driver_data = NULL;
dev->notify = NULL;
ep_auto_notify_fail:
dev->ipa_port.out->driver_data = NULL;
dev->ipa_port.out = NULL;
dev->ipa_port.out->driver_data = NULL;
dev->ipa_port.out = NULL;
ep_auto_out_fail:
dev->ipa_port.in->driver_data = NULL;
dev->ipa_port.in = NULL;
dev->ipa_port.in->driver_data = NULL;
dev->ipa_port.in = NULL;
return status;
}
static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_composite_dev *cdev = c->cdev;
int ret = -ENODEV;
struct ipa_function_bind_info info = {0};
pr_debug("%s: start binding\n", __func__);
dev->ifc_id = usb_interface_id(c, f);
if (dev->ifc_id < 0) {
pr_err("%s: unable to allocate ifc id, err:%d\n",
__func__, dev->ifc_id);
return dev->ifc_id;
}
info.data_str_idx = 0;
if (dev->qti_port_type == QTI_PORT_RMNET) {
info.string_defs = rmnet_string_defs;
info.data_desc = &rmnet_interface_desc;
info.fs_in_desc = &rmnet_fs_in_desc;
info.fs_out_desc = &rmnet_fs_out_desc;
info.fs_notify_desc = &rmnet_fs_notify_desc;
info.hs_in_desc = &rmnet_hs_in_desc;
info.hs_out_desc = &rmnet_hs_out_desc;
info.hs_notify_desc = &rmnet_hs_notify_desc;
info.ss_in_desc = &rmnet_ss_in_desc;
info.ss_out_desc = &rmnet_ss_out_desc;
info.ss_notify_desc = &rmnet_ss_notify_desc;
info.fs_desc_hdr = rmnet_fs_function;
info.hs_desc_hdr = rmnet_hs_function;
info.ss_desc_hdr = rmnet_ss_function;
} else {
info.string_defs = dpl_string_defs;
info.data_desc = &dpl_data_intf_desc;
info.fs_in_desc = &dpl_hs_data_desc;
info.hs_in_desc = &dpl_hs_data_desc;
info.ss_in_desc = &dpl_ss_data_desc;
info.fs_desc_hdr = dpl_hs_data_only_desc;
info.hs_desc_hdr = dpl_hs_data_only_desc;
info.ss_desc_hdr = dpl_ss_data_only_desc;
}
ret = ipa_update_function_bind_params(dev, cdev, &info);
return ret;
}
static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi)
{
struct f_rmnet_opts *opts;
int status;
struct f_rmnet_opts *opts;
struct f_rmnet *dev;
struct usb_function *f;
unsigned long flags;
/* allocate and initialize one new instance */
status = -ENOMEM;
opts = container_of(fi, struct f_rmnet_opts, func_inst);
opts->refcnt++;
dev = opts->dev;
spin_lock_irqsave(&dev->lock, flags);
f = &dev->func;
f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0);
spin_unlock_irqrestore(&dev->lock, flags);
if (!f->name) {
pr_err("%s: cannot allocate memory for name\n", __func__);
return ERR_PTR(-ENOMEM);
if (dev->qti_port_type == QTI_PORT_RMNET) {
f->name = "rmnet";
f->strings = rmnet_strings;
} else {
f->name = "dpl";
f->strings = dpl_strings;
}
f->strings = rmnet_strings;
f->bind = frmnet_bind;
f->unbind = frmnet_unbind;
f->disable = frmnet_disable;
@ -1004,21 +1149,53 @@ static void rmnet_free_inst(struct usb_function_instance *f)
{
struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts,
func_inst);
ipa_data_free(USB_IPA_FUNC_RMNET);
ipa_data_free(opts->dev->func_type);
kfree(opts->dev);
kfree(opts);
}
static int rmnet_set_inst_name(struct usb_function_instance *fi,
const char *name)
{
int name_len;
int ret;
int name_len, ret = 0;
struct f_rmnet *dev;
struct f_rmnet_opts *opts = container_of(fi,
struct f_rmnet_opts, func_inst);
name_len = strlen(name) + 1;
if (name_len > MAX_INST_NAME_LEN)
return -ENAMETOOLONG;
ret = ipa_data_setup(USB_IPA_FUNC_RMNET);
dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
if (!dev)
return -ENOMEM;
spin_lock_init(&dev->lock);
/* Update qti->qti_port_type */
ret = name_to_prot(dev, name);
if (ret < 0) {
pr_err("%s: failed to find prot for %s instance\n",
__func__, name);
goto fail;
}
if (dev->qti_port_type >= QTI_NUM_PORTS ||
dev->func_type >= USB_IPA_NUM_FUNCS) {
pr_err("%s: invalid prot\n", __func__);
ret = -EINVAL;
goto fail;
}
INIT_LIST_HEAD(&dev->cpkt_resp_q);
ret = ipa_data_setup(dev->func_type);
if (ret)
goto fail;
opts->dev = dev;
return 0;
fail:
kfree(dev);
return ret;
}
@ -1062,14 +1239,6 @@ static struct usb_function_instance *rmnet_alloc_inst(void)
static struct usb_function *rmnet_alloc(struct usb_function_instance *fi)
{
struct f_rmnet_opts *opts = container_of(fi,
struct f_rmnet_opts, func_inst);
rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
if (!rmnet_port)
return ERR_PTR(-ENOMEM);
opts->dev = rmnet_port;
spin_lock_init(&rmnet_port->lock);
INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q);
return frmnet_bind_config(fi);
}

View file

@ -204,7 +204,6 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf)
{
struct qti_ctrl_port *port;
struct grmnet *g_rmnet = NULL;
struct gqdss *g_dpl = NULL;
unsigned long flags;
pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr);
@ -224,17 +223,13 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf)
port->ep_type = DATA_EP_TYPE_HSUSB;
port->intf = intf;
if (gr && port->port_type == QTI_PORT_RMNET) {
if (gr) {
port->port_usb = gr;
g_rmnet = (struct grmnet *)gr;
g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
g_rmnet->notify_modem = gqti_ctrl_notify_modem;
} else if (gr && port->port_type == QTI_PORT_DPL) {
port->port_usb = gr;
g_dpl = (struct gqdss *)gr;
g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
g_dpl->notify_modem = gqti_ctrl_notify_modem;
atomic_set(&port->line_state, 1);
if (port->port_type == QTI_PORT_DPL)
atomic_set(&port->line_state, 1);
} else {
spin_unlock_irqrestore(&port->lock, flags);
pr_err("%s(): Port is used without port type.\n", __func__);
@ -263,7 +258,6 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport)
unsigned long flags;
struct rmnet_ctrl_pkt *cpkt;
struct grmnet *g_rmnet = NULL;
struct gqdss *g_dpl = NULL;
pr_debug("%s: gadget:%p\n", __func__, gr);
@ -287,14 +281,10 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport)
port->ipa_cons_idx = -1;
port->port_usb = NULL;
if (gr && port->port_type == QTI_PORT_RMNET) {
if (gr) {
g_rmnet = (struct grmnet *)gr;
g_rmnet->send_encap_cmd = NULL;
g_rmnet->notify_modem = NULL;
} else if (gr && port->port_type == QTI_PORT_DPL) {
g_dpl = (struct gqdss *)gr;
g_dpl->send_encap_cmd = NULL;
g_dpl->notify_modem = NULL;
} else {
pr_err("%s(): unrecognized gadget type(%d).\n",
__func__, port->port_type);

View file

@ -837,13 +837,16 @@ void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
* the BAM disconnect API. This lets us restore this info when
* the USB bus is resumed.
*/
gp->in_ep_desc_backup = gp->in->desc;
gp->out_ep_desc_backup = gp->out->desc;
pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
gp->in_ep_desc_backup,
gp->out_ep_desc_backup);
if (gp->in) {
gp->in_ep_desc_backup = gp->in->desc;
pr_debug("in_ep_desc_backup = %p\n",
gp->in_ep_desc_backup);
}
if (gp->out) {
gp->out_ep_desc_backup = gp->out->desc;
pr_debug("out_ep_desc_backup = %p\n",
gp->out_ep_desc_backup);
}
ipa_data_disconnect(gp, func);
return;
}
@ -919,8 +922,8 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
struct ipa_data_ch_info *port;
unsigned long flags;
struct usb_gadget *gadget = NULL;
u8 src_connection_idx;
u8 dst_connection_idx;
u8 src_connection_idx = 0;
u8 dst_connection_idx = 0;
enum usb_ctrl usb_bam_type;
pr_debug("dev:%p port number:%d\n", gp, func);
@ -944,20 +947,25 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
gadget = gp->cdev->gadget;
/* resume with remote wakeup disabled */
if (!remote_wakeup_enabled) {
/* Restore endpoint descriptors info. */
gp->in->desc = gp->in_ep_desc_backup;
gp->out->desc = gp->out_ep_desc_backup;
pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
gp->in_ep_desc_backup,
gp->out_ep_desc_backup);
int bam_pipe_num = (func == USB_IPA_FUNC_DPL) ? 1 : 0;
usb_bam_type = usb_bam_get_bam_type(gadget->name);
src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
0);
dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
0);
/* Restore endpoint descriptors info. */
if (gp->in) {
gp->in->desc = gp->in_ep_desc_backup;
pr_debug("in_ep_desc_backup = %p\n",
gp->in_ep_desc_backup);
dst_connection_idx = usb_bam_get_connection_idx(
usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB,
USB_BAM_DEVICE, bam_pipe_num);
}
if (gp->out) {
gp->out->desc = gp->out_ep_desc_backup;
pr_debug("out_ep_desc_backup = %p\n",
gp->out_ep_desc_backup);
src_connection_idx = usb_bam_get_connection_idx(
usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL,
USB_BAM_DEVICE, bam_pipe_num);
}
ipa_data_connect(gp, func,
src_connection_idx, dst_connection_idx);
return;

View file

@ -47,6 +47,25 @@ struct gadget_ipa_port {
};
struct ipa_function_bind_info {
struct usb_string *string_defs;
int data_str_idx;
struct usb_interface_descriptor *data_desc;
struct usb_endpoint_descriptor *fs_in_desc;
struct usb_endpoint_descriptor *fs_out_desc;
struct usb_endpoint_descriptor *fs_notify_desc;
struct usb_endpoint_descriptor *hs_in_desc;
struct usb_endpoint_descriptor *hs_out_desc;
struct usb_endpoint_descriptor *hs_notify_desc;
struct usb_endpoint_descriptor *ss_in_desc;
struct usb_endpoint_descriptor *ss_out_desc;
struct usb_endpoint_descriptor *ss_notify_desc;
struct usb_descriptor_header **fs_desc_hdr;
struct usb_descriptor_header **hs_desc_hdr;
struct usb_descriptor_header **ss_desc_hdr;
};
/* for configfs support */
#define MAX_INST_NAME_LEN 40