/** * ipa_data_connect() - Prepare IPA params and enable USB endpoints * @gp: USB IPA gadget port * @port_num: port number used by accelerated function * @src_connection_idx: USB BAM pipe index used as producer * @dst_connection_idx: USB BAM pipe index used as consumer * * It is being called from accelerated function driver (from set_alt()) to * initiate USB BAM IPA connection. This API is enabling accelerated endpoints * and schedule connect_work() which establishes USB IPA BAM communication. */ int ipa_data_connect(struct gadget_ipa_port *gp, u8 port_num, u8 src_connection_idx, u8 dst_connection_idx) { struct ipa_data_ch_info *port; unsigned long flags; int ret; pr_debug("dev:%p port#%d src_connection_idx:%d dst_connection_idx:%d\n", gp, port_num, src_connection_idx, dst_connection_idx); if (port_num >= n_ipa_ports) { pr_err("invalid portno#%d\n", port_num); ret = -ENODEV; goto err; } if (!gp) { pr_err("gadget port is null\n"); ret = -ENODEV; goto err; } port = ipa_data_ports[port_num]; spin_lock_irqsave(&port->port_lock, flags); port->port_usb = gp; port->src_connection_idx = src_connection_idx; port->dst_connection_idx = dst_connection_idx; port->ipa_params.src_pipe = &(port->src_pipe_idx); port->ipa_params.dst_pipe = &(port->dst_pipe_idx); port->ipa_params.src_idx = src_connection_idx; port->ipa_params.dst_idx = dst_connection_idx; /* * Disable Xfer complete and Xfer not ready interrupts by * marking endless flag which is used in UDC driver to enable * these interrupts. with this set, these interrupts for selected * endpoints won't be enabled. */ if (port->port_usb->in) { port->port_usb->in->endless = true; ret = usb_ep_enable(port->port_usb->in); if (ret) { pr_err("usb_ep_enable failed eptype:IN ep:%p", port->port_usb->in); port->port_usb->in->endless = false; goto err_usb_in; } } if (port->port_usb->out) { port->port_usb->out->endless = true; ret = usb_ep_enable(port->port_usb->out); if (ret) { pr_err("usb_ep_enable failed eptype:OUT ep:%p", port->port_usb->out); port->port_usb->out->endless = false; goto err_usb_out; } } if (!port->port_usb->out && !port->port_usb->in) { pr_err("%s(): No USB endpoint enabled.\n", __func__); ret = -EINVAL; goto err_usb_in; } queue_work(ipa_data_wq, &port->connect_w); spin_unlock_irqrestore(&port->port_lock, flags); return ret; err_usb_out: if (port->port_usb->in) port->port_usb->in->endless = false; err_usb_in: spin_unlock_irqrestore(&port->port_lock, flags); err: pr_debug("%s(): failed with error:%d\n", __func__, ret); return ret; }
/** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching * current device speed, and any framing wrapper(s) set up. * Context: irqs blocked * * This is called to activate endpoints and let the network layer know * the connection is active ("carrier detect"). It may cause the I/O * queues to open and start letting network packets flow, but will in * any case activate the endpoints so that they respond properly to the * USB host. * * Verify net_device pointer returned using IS_ERR(). If it doesn't * indicate some error code (negative errno), ep->driver_data values * have been overwritten. */ struct net_device *gether_connect(struct gether *link) { struct eth_dev *dev = the_dev; int result = 0; if (!dev) return ERR_PTR(-EINVAL); link->in_ep->driver_data = dev; result = usb_ep_enable(link->in_ep, link->in); if (result != 0) { DBG(dev, "enable %s --> %d\n", link->in_ep->name, result); goto fail0; } link->out_ep->driver_data = dev; result = usb_ep_enable(link->out_ep, link->out); if (result != 0) { DBG(dev, "enable %s --> %d\n", link->out_ep->name, result); goto fail1; } if (result == 0) result = alloc_requests(dev, link, qlen(dev->gadget)); if (result == 0) { dev->zlp = link->is_zlp_ok; DBG(dev, "qlen %d\n", qlen(dev->gadget)); dev->header_len = link->header_len; dev->unwrap = link->unwrap; dev->wrap = link->wrap; spin_lock(&dev->lock); dev->port_usb = link; link->ioport = dev; if (netif_running(dev->net)) { if (link->open) link->open(link); } else { if (link->close) link->close(link); } spin_unlock(&dev->lock); netif_carrier_on(dev->net); if (netif_running(dev->net)) eth_start(dev, GFP_ATOMIC); /* on error, disable any endpoints */ } else { (void) usb_ep_disable(link->out_ep); fail1: (void) usb_ep_disable(link->in_ep); } fail0: /* caller is responsible for cleanup on error */ if (result < 0) return ERR_PTR(result); return dev->net; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have set up the TTY driver by calling * @gserial_setup(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; /* port 0 is console tty dirver */ if (0 == port_num) { if (!gs_console_tty_driver) return -ENXIO; } else { if (!gs_tty_driver || port_num >= n_ports) return -ENXIO; } /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; /* mask the not ready interrupt for usb netcard class function driver */ gser->out->enable_xfer_in_progress = 1; /* activate the endpoints */ status = usb_ep_enable(gser->in); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = (void*)port; port->port_usb = gser; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ gs_start_io(port);/* usb rx fifo is shared, so must submit rx req at any time */ #if ACM_TTY_SUPPORT_NOTIFY if (port->open_count) { pr_vdebug("gserial_connect: start ttyGS%d\n", port->port_num); //gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } #endif spin_unlock_irqrestore(&port->port_lock, flags); port->in_name = (char*)gser->in->name; port->out_name = (char*)gser->out->name; port->stat_port_is_connect = 1; return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; port->stat_port_is_connect = 0; return status; }
static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_acm *acm = func_to_acm(f); struct usb_composite_dev *cdev = f->config->cdev; bool is_setting = 0; int ret; D("+\n"); /* we know alt == 0, so this is an activation or a reset */ /* if it is single interface, intf, acm->ctrl_id and acm->data_id * are the same, so we can setting data and notify interface in the same time. * * if it is multi interface, acm->ctrl_id and acm->data_id are different, * so the setting is go ahead in different times. */ if (intf == acm->ctrl_id) { is_setting = 1; if (acm->notify) { if (acm->notify->driver_data) { VDBG(cdev, "reset acm control interface %d\n", intf); usb_ep_disable(acm->notify); } else { VDBG(cdev, "init acm ctrl interface %d\n", intf); if (config_ep_by_speed(cdev->gadget, f, acm->notify)) return -EINVAL; } ret = usb_ep_enable(acm->notify); if (ret < 0) { ERROR(cdev, "Enable acm interface ep failed\n"); return ret; } acm->notify->driver_data = acm; } } if (intf == acm->data_id) { is_setting = 1; if (acm->port.in->driver_data) { DBG(cdev, "reset acm ttyGS%d\n", acm->port_num); gacm_cdev_disconnect(&acm->port); } if (!acm->port.in->desc || !acm->port.out->desc) { DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); if (config_ep_by_speed(cdev->gadget, f, acm->port.in) || config_ep_by_speed(cdev->gadget, f, acm->port.out)) { acm->port.in->desc = NULL; acm->port.out->desc = NULL; return -EINVAL; } } gacm_cdev_connect(&acm->port, acm->port_num); bsp_usb_set_enum_stat(acm->data_id, 1); } if (!is_setting) return -EINVAL; D("-\n"); return 0; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have allocate @port_num by calling * @gserial_alloc_line(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; if (port_num >= MAX_U_SERIAL_PORTS) return -ENXIO; port = ports[port_num].port; if (!port) { pr_err("serial line %d not allocated.\n", port_num); return -EINVAL; } if (port->port_usb) { pr_err("serial line %d is in use.\n", port_num); return -EBUSY; } /* activate the endpoints */ status = usb_ep_enable(gser->in); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = port; port->port_usb = gser; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ if (atomic_read(&port->port.count)) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } spin_unlock_irqrestore(&port->port_lock, flags); return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; return status; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have set up the TTY driver by calling * @gserial_setup(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; pr_info("Davis: enter gserial_connect port_num %d\n", port_num); if (!gs_tty_driver || port_num >= n_ports) return -ENXIO; /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; /* activate the endpoints */ status = usb_ep_enable(gser->in, gser->in_desc); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out, gser->out_desc); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = port; port->port_usb = gser; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ if (port->open_count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } spin_unlock_irqrestore(&port->port_lock, flags); // Davis: open the gserial port #ifdef CONFIG_USB_SERIAL_RELAY if(port_num == GS_PORT_NUM) gs_init_port(port_num); #endif return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; return status; }
static int uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) { struct uvc_device *uvc = to_uvc(f); struct v4l2_event v4l2_event; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); if (interface == uvc->control_intf) { if (alt) return -EINVAL; if (uvc->state == UVC_STATE_DISCONNECTED) { memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_CONNECT; uvc_event->speed = f->config->cdev->gadget->speed; v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; } return 0; } if (interface != uvc->streaming_intf) return -EINVAL; /* TODO if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)) return alt ? -EINVAL : 0; */ switch (alt) { case 0: if (uvc->state != UVC_STATE_STREAMING) return 0; if (uvc->video.ep) usb_ep_disable(uvc->video.ep); memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMOFF; v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; break; case 1: if (uvc->state != UVC_STATE_CONNECTED) return 0; if (uvc->video.ep) usb_ep_enable(uvc->video.ep, &uvc_streaming_ep); memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_STREAMING; break; default: return -EINVAL; } return 0; }