static void gs_free_requests(struct usb_ep *ep, struct list_head *head, int *allocated) { struct usb_request *req; while (!list_empty(head)) { req = list_entry(head->next, struct usb_request, list); list_del(&req->list); gs_free_req(ep, req); if (allocated) (*allocated)--; } }
/* * Context: caller owns port_lock, and port_usb is set */ static unsigned gs_start_rx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->read_pool; struct usb_ep *out = port->port_usb->out; unsigned started = 0; while (!list_empty(pool)) { struct usb_request *req; int status; struct tty_struct *tty; /* no more rx if closed */ tty = port->port_tty; if (!tty) break; req = list_entry(pool->next, struct usb_request, list); list_del(&req->list); req->length = RX_BUF_SIZE; /* drop lock while we call out; the controller driver * may need to call us back (e.g. for disconnect) */ spin_unlock(&port->port_lock); status = usb_ep_queue(out, req, GFP_ATOMIC); spin_lock(&port->port_lock); /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are * freed. Free the current request here. */ if (!port->port_usb) { started = 0; gs_free_req(out, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", out->name, status); list_add(&req->list, pool); break; } started++; } return started; }
static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { #ifdef CONFIG_MODEM_SUPPORT struct f_gser *gser = func_to_gser(f); #endif if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT gs_free_req(gser->notify, gser->notify_req); #endif kfree(func_to_gser(f)); }
static unsigned gs_start_rx(struct gs_port *port) { struct list_head *pool = &port->read_pool; struct usb_ep *out; unsigned started = 0; if (port->port_usb) out = port->port_usb->out; else return 0; while (!list_empty(pool)) { struct usb_request *req; int status; struct tty_struct *tty; tty = port->port_tty; if (!tty) break; if (port->read_started >= RX_QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); list_del(&req->list); req->length = RX_BUF_SIZE; spin_unlock(&port->port_lock); status = usb_ep_queue(out, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { started = 0; gs_free_req(out, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", out->name, status); list_add(&req->list, pool); break; } port->read_started++; } return port->read_started; }
/** * Gets a character from the usb endpoint under the * interrupt context * * Returns 0 or a negative error number */ static int __gs_poll_get_char(struct gs_port *port, char *ch) { struct gserial *gs = port->port_usb; struct usb_ep *ept = gs->out; struct usb_request *usb_req; int rv; int read_ch = -EINVAL; BUG_ON(!ept); for (;;) { read_ch = gs_poll_pop_buffer(); if (read_ch >= 0) { break; /* got a character, done */ } /** * There is nothing in buffer, start the USB endpoint to * receive something */ /* Replace complete function to intercept usb read */ usb_req = gs_alloc_req(ept, ept->maxpacket, GFP_ATOMIC); if (!usb_req) { pr_err("%s: OOM for read req\n", __func__); return -ENOMEM; } /* Queue request */ usb_req->length = ept->maxpacket; usb_req->complete = gs_poll_read_complete; if ((rv = usb_ep_queue(ept, usb_req, GFP_ATOMIC))) { pr_err("%s: usb_ep_queue err %d\n", __func__, rv); return rv; } /* Read and free request */ pr_vdebug("%s: polling for read\n", __func__); while ( usb_loop_poll_hw(ept, 1 /*rx*/) ); gs_free_req(ept, usb_req); } *ch = read_ch; return 0; }
static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { #ifdef CONFIG_MODEM_SUPPORT struct f_gser *gser = func_to_gser(f); #endif #ifdef FEATURE_PANTECH_MODEM_REOPEN_DELAY //tarial bug fix [execute work queue fail after changing usb mode] cancel_delayed_work_sync(&gser->connect_work); #endif if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT gs_free_req(gser->notify, gser->notify_req); #endif kfree(func_to_gser(f)); }
static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_gser *gser = func_to_gser(f); if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; #ifdef CONFIG_MODEM_SUPPORT if (gser->notify) { gs_free_req(gser->notify, gser->notify_req); gser->notify->driver_data = NULL; } #endif kfree(func_to_gser(f)); }
static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { #ifdef CONFIG_MODEM_SUPPORT struct f_gser *gser = func_to_gser(f); #endif if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT gs_free_req(gser->notify, gser->notify_req); #endif kfree(func_to_gser(f)); // << FerryWu, 2012/08/07, Fix strings table of USB descriptor gser_string_defs[0].id = 0; #ifdef CONFIG_MODEM_SUPPORT modem_string_defs[0].id = 0; nmea_string_defs[0].id = 0; #endif // >> FerryWu, 2012/08/07, Fix strings table of USB descriptor }
/* * gs_start_tx * * This function finds available write requests, calls * gs_send_packet to fill these packets with data, and * continues until either there are no more write requests * available or no more data to send. This function is * run whenever data arrives or write requests are available. * * Context: caller owns port_lock; port_usb is non-null. */ static int gs_start_tx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; struct usb_ep *in = port->port_usb->in; int status = 0; static long prev_len; bool do_tty_wake = false; while (!list_empty(pool)) { struct usb_request *req; int len; if (port->write_started >= TX_QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, TX_BUF_SIZE); if (len == 0) { /* Queue zero length packet explicitly to make it * work with UDCs which don't support req->zero flag */ if (prev_len && (prev_len % in->maxpacket == 0)) { req->length = 0; list_del(&req->list); spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { gs_free_req(in, req); break; } if (status) { printk(KERN_ERR "%s: %s err %d\n", __func__, "queue", status); list_add(&req->list, pool); } prev_len = 0; } wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may * happen too; maybe immediately before we queue this! * * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are * freed. Free the current request here. */ if (!port->port_usb) { do_tty_wake = false; gs_free_req(in, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } prev_len = req->length; port->nbytes_from_tty += req->length; port->write_started++; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; status = -ENODEV; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); if (!ep) goto fail; gser->port.in = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; ep->driver_data = cdev; /* claim */ #ifdef CONFIG_MODEM_SUPPORT ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); if (!ep) goto fail; gser->notify = ep; ep->driver_data = cdev; /* claim */ /* allocate notification */ gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); if (!gser->notify_req) goto fail; gser->notify_req->complete = gser_notify_complete; gser->notify_req->context = gser; #endif /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(gser_fs_function); if (!f->descriptors) goto fail; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ if (gadget_is_dualspeed(c->cdev->gadget)) { gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; #ifdef CONFIG_MODEM_SUPPORT gser_hs_notify_desc.bEndpointAddress = gser_fs_notify_desc.bEndpointAddress; #endif /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); if (!f->hs_descriptors) goto fail; } if (gadget_is_superspeed(c->cdev->gadget)) { gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(gser_ss_function); if (!f->ss_descriptors) goto fail; } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gser->port.in->name, gser->port.out->name); return 0; fail: if (f->descriptors) usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT if (gser->notify_req) gs_free_req(gser->notify, gser->notify_req); /* we might as well release our claims on endpoints */ if (gser->notify) gser->notify->driver_data = NULL; #endif /* we might as well release our claims on endpoints */ if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; }
static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; /* allocate instance-specific interface IDs */ #if defined(CONFIG_ANDROID_PANTECH_USB) // if((pantech_usb_carrier != CARRIER_QUALCOMM) && b_pantech_usb_module){ if(pantech_usb_carrier != CARRIER_QUALCOMM){ gser_fs_function = pantech_gser_fs_function; gser_hs_function = pantech_gser_hs_function; status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; //data_id : cdc interface number gser_acm_cdc_interface_desc.bInterfaceNumber = status; #if defined(FEATURE_ANDROID_PANTECH_USB_IAD) gser_interface_assoc_desc.bFirstInterface = status; #endif //acm interface status = usb_interface_id(c, f); if (status < 0) goto fail; gser_acm_data_interface_desc.bInterfaceNumber = status; }else{ gser_fs_function = qualcomm_gser_fs_function; gser_hs_function = qualcomm_gser_hs_function; status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; } #else status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; #endif status = -ENODEV; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); if (!ep) goto fail; gser->port.in = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; ep->driver_data = cdev; /* claim */ #ifdef CONFIG_MODEM_SUPPORT ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); if (!ep) goto fail; gser->notify = ep; ep->driver_data = cdev; /* claim */ /* allocate notification */ gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); if (!gser->notify_req) goto fail; gser->notify_req->complete = gser_notify_complete; gser->notify_req->context = gser; #endif /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(gser_fs_function); if (!f->descriptors) goto fail; gser->fs.in = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_in_desc); gser->fs.out = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_out_desc); #ifdef CONFIG_MODEM_SUPPORT gser->fs.notify = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_notify_desc); #endif /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ if (gadget_is_dualspeed(c->cdev->gadget)) { gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; #ifdef CONFIG_MODEM_SUPPORT gser_hs_notify_desc.bEndpointAddress = gser_fs_notify_desc.bEndpointAddress; #endif /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); if (!f->hs_descriptors) goto fail; gser->hs.in = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_in_desc); gser->hs.out = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_out_desc); #ifdef CONFIG_MODEM_SUPPORT gser->hs.notify = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_notify_desc); #endif } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gser->port.in->name, gser->port.out->name); return 0; fail: if (f->descriptors) usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT if (gser->notify_req) gs_free_req(gser->notify, gser->notify_req); /* we might as well release our claims on endpoints */ if (gser->notify) gser->notify->driver_data = NULL; #endif /* we might as well release our claims on endpoints */ if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; }
static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; status = -ENODEV; ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); if (!ep) goto fail; gser->port.in = ep; ep->driver_data = cdev; ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; ep->driver_data = cdev; #ifdef CONFIG_MODEM_SUPPORT ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); if (!ep) goto fail; gser->notify = ep; ep->driver_data = cdev; gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); if (!gser->notify_req) goto fail; gser->notify_req->complete = gser_notify_complete; gser->notify_req->context = gser; #endif f->descriptors = usb_copy_descriptors(gser_fs_function); if (!f->descriptors) goto fail; if (gadget_is_dualspeed(c->cdev->gadget)) { gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; #ifdef CONFIG_MODEM_SUPPORT gser_hs_notify_desc.bEndpointAddress = gser_fs_notify_desc.bEndpointAddress; #endif f->hs_descriptors = usb_copy_descriptors(gser_hs_function); if (!f->hs_descriptors) goto fail; } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gser->port.in->name, gser->port.out->name); return 0; fail: if (f->descriptors) usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT if (gser->notify_req) gs_free_req(gser->notify, gser->notify_req); if (gser->notify) gser->notify->driver_data = NULL; #endif if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; }
static int gs_start_tx(struct gs_port *port) { struct list_head *pool = &port->write_pool; struct usb_ep *in; int status = 0; static long prev_len; bool do_tty_wake = false; if (port->port_usb) in = port->port_usb->in; else return 0; while (!list_empty(pool)) { struct usb_request *req; int len; if (port->write_started >= TX_QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, TX_BUF_SIZE); if (len == 0) { if (prev_len && (prev_len % in->maxpacket == 0)) { req->length = 0; list_del(&req->list); spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { gs_free_req(in, req); break; } if (status) { printk(KERN_ERR "%s: %s err %d\n", __func__, "queue", status); list_add(&req->list, pool); } prev_len = 0; } wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { do_tty_wake = false; gs_free_req(in, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } prev_len = req->length; port->nbytes_from_tty += req->length; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) goto fail; #ifdef CONFIG_LGE_USB_GADGET_DRIVER gser_iad_descriptor.bFirstInterface = status; gser_control_interface_desc.bInterfaceNumber = status; gser_union_desc .bMasterInterface0 = status; status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; // [START] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial gser_data_interface_desc.bInterfaceNumber = status; gser_union_desc.bSlaveInterface0 = status; gser_call_mgmt_descriptor.bDataInterface = status; #else gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; // [START] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial #endif // [END] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial status = -ENODEV; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); if (!ep) goto fail; gser->port.in = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; ep->driver_data = cdev; /* claim */ #ifdef CONFIG_MODEM_SUPPORT ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); if (!ep) goto fail; gser->notify = ep; ep->driver_data = cdev; /* claim */ /* allocate notification */ #ifdef CONFIG_LGE_USB_GADGET_DRIVER gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 8, GFP_KERNEL); #else gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); #endif if (!gser->notify_req) goto fail; gser->notify_req->complete = gser_notify_complete; gser->notify_req->context = gser; #endif /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(gser_fs_function); if (!f->descriptors) goto fail; gser->fs.in = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_in_desc); gser->fs.out = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_out_desc); #ifdef CONFIG_MODEM_SUPPORT gser->fs.notify = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_notify_desc); #endif /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ if (gadget_is_dualspeed(c->cdev->gadget)) { gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; #ifdef CONFIG_MODEM_SUPPORT gser_hs_notify_desc.bEndpointAddress = gser_fs_notify_desc.bEndpointAddress; #endif /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); gser->hs.in = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_in_desc); gser->hs.out = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_out_desc); #ifdef CONFIG_MODEM_SUPPORT gser->hs.notify = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_notify_desc); #endif } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gser->port.in->name, gser->port.out->name); return 0; fail: #ifdef CONFIG_MODEM_SUPPORT if (gser->notify_req) gs_free_req(gser->notify, gser->notify_req); /* we might as well release our claims on endpoints */ if (gser->notify) gser->notify->driver_data = NULL; #endif /* we might as well release our claims on endpoints */ if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; }
/* * gs_start_tx * * This function finds available write requests, calls * gs_send_packet to fill these packets with data, and * continues until either there are no more write requests * available or no more data to send. This function is * run whenever data arrives or write requests are available. * * Context: caller owns port_lock; port_usb is non-null. */ static int gs_start_tx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; struct usb_ep *in = port->port_usb->in; int status = 0; static long prev_len; bool do_tty_wake = false; while (!list_empty(pool)) { struct usb_request *req; int len; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, TX_BUF_SIZE); if (len == 0) { /* Queue zero length packet */ #if 1 //QCT_SBA if (prev_len && (prev_len % in->maxpacket == 0)) { #else if (prev_len & (prev_len % in->maxpacket == 0)) { #endif req->length = 0; list_del(&req->list); spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { gs_free_req(in, req); break; } if (status) { printk(KERN_ERR "%s: %s err %d\n", __func__, "queue", status); list_add(&req->list, pool); } prev_len = 0; } wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may * happen too; maybe immediately before we queue this! * * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are * freed. Free the current request here. */ if (!port->port_usb) { do_tty_wake = false; gs_free_req(in, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } prev_len = req->length; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; } /* * Context: caller owns port_lock, and port_usb is set */ static unsigned gs_start_rx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->read_pool; struct usb_ep *out = port->port_usb->out; unsigned started = 0; while (!list_empty(pool)) { struct usb_request *req; int status; struct tty_struct *tty; /* no more rx if closed */ tty = port->port_tty; if (!tty) break; req = list_entry(pool->next, struct usb_request, list); list_del(&req->list); req->length = RX_BUF_SIZE; /* drop lock while we call out; the controller driver * may need to call us back (e.g. for disconnect) */ spin_unlock(&port->port_lock); status = usb_ep_queue(out, req, GFP_ATOMIC); spin_lock(&port->port_lock); /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are * freed. Free the current request here. */ if (!port->port_usb) { started = 0; gs_free_req(out, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", out->name, status); list_add(&req->list, pool); break; } started++; } return started; } /* * RX work queue takes data out of the RX queue and hands it up to the TTY * layer until it refuses to take any more data (or is throttled back). * Then it issues reads for any further data. * * If the RX queue becomes full enough that no usb_request is queued, * the OUT endpoint may begin NAKing as soon as its FIFO fills up. * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ static void gs_rx_push(struct work_struct *w) { struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; bool do_push = false; /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); tty = port->port_tty; while (!list_empty(queue)) { struct usb_request *req; req = list_first_entry(queue, struct usb_request, list); /* discard data if tty was closed */ if (!tty) goto recycle; /* leave data queued if tty was rx throttled */ if (test_bit(TTY_THROTTLED, &tty->flags)) break; switch (req->status) { case -ESHUTDOWN: disconnect = true; pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); break; default: /* presumably a transient fault */ pr_warning(PREFIX "%d: unexpected RX status %d\n", port->port_num, req->status); /* FALLTHROUGH */ case 0: /* normal completion */ break; } /* push data to (open) tty */ if (req->actual) { char *packet = req->buf; unsigned size = req->actual; unsigned n; int count; /* we may have pushed part of this packet already... */ n = port->n_read; if (n) { packet += n; size -= n; } count = tty_insert_flip_string(tty, packet, size); if (count) do_push = true; if (count != size) { /* stop pushing; TTY layer can't handle more */ port->n_read += count; pr_vdebug(PREFIX "%d: rx block %d/%d\n", port->port_num, count, req->actual); break; } port->n_read = 0; } recycle: list_move(&req->list, &port->read_pool); } /* Push from tty to ldisc; this is immediate with low_latency, and * may trigger callbacks to this driver ... so drop the spinlock. */ if (tty && do_push) { spin_unlock_irq(&port->port_lock); tty_flip_buffer_push(tty); wake_up_interruptible(&tty->read_wait); spin_lock_irq(&port->port_lock); /* tty may have been closed */ tty = port->port_tty; } /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any * this time around, there may be trouble unless there's an * implicit tty_unthrottle() call on its way... * * REVISIT we should probably add a timer to keep the work queue * from starving ... but it's not clear that case ever happens. */ if (!list_empty(queue) && tty) { if (!test_bit(TTY_THROTTLED, &tty->flags)) { if (do_push) queue_work(gserial_wq, &port->push); else pr_warning(PREFIX "%d: RX not scheduled?\n", port->port_num); } } /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) gs_start_rx(port); spin_unlock_irq(&port->port_lock); } static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) { struct gs_port *port = ep->driver_data; unsigned long flags; /* Queue all received data until the tty layer is ready for it. */ spin_lock_irqsave(&port->port_lock, flags); list_add_tail(&req->list, &port->read_queue); queue_work(gserial_wq, &port->push); spin_unlock_irqrestore(&port->port_lock, flags); } static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) { struct gs_port *port = ep->driver_data; unsigned long flags; spin_lock_irqsave(&port->port_lock, flags); list_add(&req->list, &port->write_pool); switch (req->status) { default: /* presumably a transient fault */ pr_warning("%s: unexpected %s status %d\n", __func__, ep->name, req->status); /* FALL THROUGH */ case 0: /* normal completion */ if (port->port_usb) gs_start_tx(port); break; case -ESHUTDOWN: /* disconnect */ pr_vdebug("%s: %s shutdown\n", __func__, ep->name); break; } spin_unlock_irqrestore(&port->port_lock, flags); } static void gs_free_requests(struct usb_ep *ep, struct list_head *head) { struct usb_request *req; while (!list_empty(head)) { req = list_entry(head->next, struct usb_request, list); list_del(&req->list); gs_free_req(ep, req); } } static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, int num, int size, void (*fn)(struct usb_ep *, struct usb_request *)) { int i; struct usb_request *req; /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't * do quite that many this time, don't fail ... we just won't * be as speedy as we might otherwise be. */ for (i = 0; i < num; i++) { req = gs_alloc_req(ep, size, GFP_ATOMIC); if (!req) return list_empty(head) ? -ENOMEM : 0; req->complete = fn; list_add_tail(&req->list, head); } return 0; }
/* ACM function driver setup/binding */ static int acm_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_acm *acm = func_to_acm(f); struct usb_string *us; int status; struct usb_ep *ep; acm_string_defs[ACM_CTRL_IDX].s = acm->ctrl_string_buf; acm_string_defs[ACM_DATA_IDX].s = acm->data_string_buf; acm_string_defs[ACM_IAD_IDX].s = acm->iad_string_buf; /* maybe allocate device-global string IDs, and patch descriptors */ us = usb_gstrings_attach(cdev, acm_strings, ARRAY_SIZE(acm_string_defs)); if (IS_ERR(us)) return PTR_ERR(us); acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id; acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id; acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id; acm_iad_descriptor.bFunctionProtocol = acm->iad_proto; acm_control_interface_desc.bInterfaceProtocol = acm->ctrl_intf_proto; /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) goto fail; acm->ctrl_id = status; acm_iad_descriptor.bFirstInterface = status; acm_control_interface_desc.bInterfaceNumber = status; acm_union_desc .bMasterInterface0 = status; status = usb_interface_id(c, f); if (status < 0) goto fail; acm->data_id = status; acm_data_interface_desc.bInterfaceNumber = status; acm_union_desc.bSlaveInterface0 = status; acm_call_mgmt_descriptor.bDataInterface = status; status = -ENODEV; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc); if (!ep) goto fail; acm->port.in = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc); if (!ep) goto fail; acm->port.out = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc); if (!ep) goto fail; acm->notify = ep; ep->driver_data = cdev; /* claim */ /* allocate notification */ acm->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); if (!acm->notify_req) goto fail; acm->notify_req->complete = acm_cdc_notify_complete; acm->notify_req->context = acm; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; acm_hs_notify_desc.bEndpointAddress = acm_fs_notify_desc.bEndpointAddress; acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, acm_ss_function); if (status) goto fail; DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", acm->port_num, gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", acm->port.in->name, acm->port.out->name, acm->notify->name); return 0; fail: if (acm->notify_req) { gs_free_req(acm->notify, acm->notify_req); acm->notify_req = NULL; } /* we might as well release our claims on endpoints */ if (acm->notify) acm->notify->driver_data = NULL; if (acm->port.out) acm->port.out->driver_data = NULL; if (acm->port.in) acm->port.in->driver_data = NULL; ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); return status; }