123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- /* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <linux/kref.h>
- #include <linux/debugfs.h>
- #include <linux/platform_device.h>
- #include <linux/uaccess.h>
- #include <linux/ratelimit.h>
- #include <linux/usb/ch9.h>
- #include <linux/usb/cdc.h>
- #include <linux/termios.h>
- #include <asm/unaligned.h>
- #include <mach/usb_bridge.h>
- #define ACM_CTRL_DTR (1 << 0)
- #define DEFAULT_READ_URB_LENGTH 4096
- #define SUSPENDED BIT(0)
- enum ctrl_bridge_rx_state {
- RX_IDLE, /* inturb is not queued */
- RX_WAIT, /* inturb is queued and waiting for data */
- RX_BUSY, /* inturb is completed. processing RX */
- };
- struct ctrl_bridge {
- struct usb_device *udev;
- struct usb_interface *intf;
- char *name;
- unsigned int int_pipe;
- struct urb *inturb;
- void *intbuf;
- struct urb *readurb;
- void *readbuf;
- struct usb_anchor tx_submitted;
- struct usb_anchor tx_deferred;
- struct usb_ctrlrequest *in_ctlreq;
- struct bridge *brdg;
- struct platform_device *pdev;
- unsigned long flags;
- /* input control lines (DSR, CTS, CD, RI) */
- unsigned int cbits_tohost;
- /* output control lines (DTR, RTS) */
- unsigned int cbits_tomdm;
- spinlock_t lock;
- enum ctrl_bridge_rx_state rx_state;
- /* counters */
- unsigned int snd_encap_cmd;
- unsigned int get_encap_res;
- unsigned int resp_avail;
- unsigned int set_ctrl_line_sts;
- unsigned int notify_ser_state;
- };
- static struct ctrl_bridge *__dev[MAX_BRIDGE_DEVICES];
- static int get_ctrl_bridge_chid(char *xport_name)
- {
- struct ctrl_bridge *dev;
- int i;
- for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
- dev = __dev[i];
- if (!strncmp(dev->name, xport_name, BRIDGE_NAME_MAX_LEN))
- return i;
- }
- return -ENODEV;
- }
- unsigned int ctrl_bridge_get_cbits_tohost(unsigned int id)
- {
- struct ctrl_bridge *dev;
- if (id >= MAX_BRIDGE_DEVICES)
- return -EINVAL;
- dev = __dev[id];
- if (!dev)
- return -ENODEV;
- return dev->cbits_tohost;
- }
- EXPORT_SYMBOL(ctrl_bridge_get_cbits_tohost);
- int ctrl_bridge_set_cbits(unsigned int id, unsigned int cbits)
- {
- struct ctrl_bridge *dev;
- struct bridge *brdg;
- int retval;
- if (id >= MAX_BRIDGE_DEVICES)
- return -EINVAL;
- dev = __dev[id];
- if (!dev)
- return -ENODEV;
- pr_debug("%s: dev[id] =%u cbits : %u\n", __func__, id, cbits);
- brdg = dev->brdg;
- if (!brdg)
- return -ENODEV;
- dev->cbits_tomdm = cbits;
- retval = ctrl_bridge_write(id, NULL, 0);
- /* if DTR is high, update latest modem info to host */
- if (brdg && (cbits & ACM_CTRL_DTR) && brdg->ops.send_cbits)
- brdg->ops.send_cbits(brdg->ctx, dev->cbits_tohost);
- return retval;
- }
- EXPORT_SYMBOL(ctrl_bridge_set_cbits);
- static int ctrl_bridge_start_read(struct ctrl_bridge *dev, gfp_t gfp_flags)
- {
- int retval = 0;
- unsigned long flags;
- if (!dev->inturb) {
- dev_err(&dev->intf->dev, "%s: inturb is NULL\n", __func__);
- return -ENODEV;
- }
- retval = usb_submit_urb(dev->inturb, gfp_flags);
- if (retval < 0 && retval != -EPERM) {
- dev_err(&dev->intf->dev,
- "%s error submitting int urb %d\n",
- __func__, retval);
- }
- spin_lock_irqsave(&dev->lock, flags);
- if (retval)
- dev->rx_state = RX_IDLE;
- else
- dev->rx_state = RX_WAIT;
- spin_unlock_irqrestore(&dev->lock, flags);
- return retval;
- }
- static void resp_avail_cb(struct urb *urb)
- {
- struct ctrl_bridge *dev = urb->context;
- int resubmit_urb = 1;
- struct bridge *brdg = dev->brdg;
- unsigned long flags;
- /*usb device disconnect*/
- if (urb->dev->state == USB_STATE_NOTATTACHED)
- return;
- switch (urb->status) {
- case 0:
- /*success*/
- dev->get_encap_res++;
- if (brdg && brdg->ops.send_pkt)
- brdg->ops.send_pkt(brdg->ctx, urb->transfer_buffer,
- urb->actual_length);
- break;
- /*do not resubmit*/
- case -ESHUTDOWN:
- case -ENOENT:
- case -ECONNRESET:
- /* unplug */
- case -EPROTO:
- /*babble error*/
- resubmit_urb = 0;
- /*resubmit*/
- case -EOVERFLOW:
- default:
- dev_dbg(&dev->intf->dev, "%s: non zero urb status = %d\n",
- __func__, urb->status);
- }
- if (resubmit_urb) {
- /*re- submit int urb to check response available*/
- ctrl_bridge_start_read(dev, GFP_ATOMIC);
- } else {
- spin_lock_irqsave(&dev->lock, flags);
- dev->rx_state = RX_IDLE;
- spin_unlock_irqrestore(&dev->lock, flags);
- }
- usb_autopm_put_interface_async(dev->intf);
- }
- static void notification_available_cb(struct urb *urb)
- {
- int status;
- struct usb_cdc_notification *ctrl;
- struct ctrl_bridge *dev = urb->context;
- struct bridge *brdg = dev->brdg;
- unsigned int ctrl_bits;
- unsigned char *data;
- unsigned long flags;
- /*usb device disconnect*/
- if (urb->dev->state == USB_STATE_NOTATTACHED)
- return;
- spin_lock_irqsave(&dev->lock, flags);
- dev->rx_state = RX_IDLE;
- spin_unlock_irqrestore(&dev->lock, flags);
- switch (urb->status) {
- case 0:
- /*success*/
- break;
- case -ESHUTDOWN:
- case -ENOENT:
- case -ECONNRESET:
- case -EPROTO:
- /* unplug */
- return;
- case -EPIPE:
- dev_err(&dev->intf->dev,
- "%s: stall on int endpoint\n", __func__);
- /* TBD : halt to be cleared in work */
- case -EOVERFLOW:
- default:
- pr_debug_ratelimited("%s: non zero urb status = %d\n",
- __func__, urb->status);
- goto resubmit_int_urb;
- }
- ctrl = (struct usb_cdc_notification *)urb->transfer_buffer;
- data = (unsigned char *)(ctrl + 1);
- switch (ctrl->bNotificationType) {
- case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
- spin_lock_irqsave(&dev->lock, flags);
- dev->rx_state = RX_BUSY;
- spin_unlock_irqrestore(&dev->lock, flags);
- dev->resp_avail++;
- usb_autopm_get_interface_no_resume(dev->intf);
- usb_fill_control_urb(dev->readurb, dev->udev,
- usb_rcvctrlpipe(dev->udev, 0),
- (unsigned char *)dev->in_ctlreq,
- dev->readbuf,
- DEFAULT_READ_URB_LENGTH,
- resp_avail_cb, dev);
- status = usb_submit_urb(dev->readurb, GFP_ATOMIC);
- if (status) {
- dev_err(&dev->intf->dev,
- "%s: Error submitting Read URB %d\n",
- __func__, status);
- usb_autopm_put_interface_async(dev->intf);
- goto resubmit_int_urb;
- }
- return;
- case USB_CDC_NOTIFY_NETWORK_CONNECTION:
- dev_dbg(&dev->intf->dev, "%s network\n", ctrl->wValue ?
- "connected to" : "disconnected from");
- break;
- case USB_CDC_NOTIFY_SERIAL_STATE:
- dev->notify_ser_state++;
- ctrl_bits = get_unaligned_le16(data);
- dev_dbg(&dev->intf->dev, "serial state: %d\n", ctrl_bits);
- dev->cbits_tohost = ctrl_bits;
- if (brdg && brdg->ops.send_cbits)
- brdg->ops.send_cbits(brdg->ctx, ctrl_bits);
- break;
- default:
- dev_err(&dev->intf->dev, "%s: unknown notification %d received:"
- "index %d len %d data0 %d data1 %d",
- __func__, ctrl->bNotificationType, ctrl->wIndex,
- ctrl->wLength, data[0], data[1]);
- }
- resubmit_int_urb:
- ctrl_bridge_start_read(dev, GFP_ATOMIC);
- }
- int ctrl_bridge_open(struct bridge *brdg)
- {
- struct ctrl_bridge *dev;
- int ch_id;
- if (!brdg) {
- err("bridge is null\n");
- return -EINVAL;
- }
- ch_id = get_ctrl_bridge_chid(brdg->name);
- if (ch_id < 0 || ch_id >= MAX_BRIDGE_DEVICES) {
- err("%s: %s dev not found\n", __func__, brdg->name);
- return ch_id;
- }
- brdg->ch_id = ch_id;
- dev = __dev[ch_id];
- dev->brdg = brdg;
- dev->snd_encap_cmd = 0;
- dev->get_encap_res = 0;
- dev->resp_avail = 0;
- dev->set_ctrl_line_sts = 0;
- dev->notify_ser_state = 0;
- if (brdg->ops.send_cbits)
- brdg->ops.send_cbits(brdg->ctx, dev->cbits_tohost);
- return 0;
- }
- EXPORT_SYMBOL(ctrl_bridge_open);
- void ctrl_bridge_close(unsigned int id)
- {
- struct ctrl_bridge *dev;
- if (id >= MAX_BRIDGE_DEVICES)
- return;
- dev = __dev[id];
- if (!dev || !dev->brdg)
- return;
- dev_dbg(&dev->intf->dev, "%s:\n", __func__);
- ctrl_bridge_set_cbits(dev->brdg->ch_id, 0);
- dev->brdg = NULL;
- }
- EXPORT_SYMBOL(ctrl_bridge_close);
- static void ctrl_write_callback(struct urb *urb)
- {
- struct ctrl_bridge *dev = urb->context;
- if (urb->status) {
- pr_debug("Write status/size %d/%d\n",
- urb->status, urb->actual_length);
- }
- kfree(urb->transfer_buffer);
- kfree(urb->setup_packet);
- usb_free_urb(urb);
- /* if we are here after device disconnect
- * usb_unbind_interface() takes care of
- * residual pm_autopm_get_interface_* calls
- */
- if (urb->dev->state != USB_STATE_NOTATTACHED)
- usb_autopm_put_interface_async(dev->intf);
- }
- int ctrl_bridge_write(unsigned int id, char *data, size_t size)
- {
- int result;
- struct urb *writeurb;
- struct usb_ctrlrequest *out_ctlreq;
- struct ctrl_bridge *dev;
- unsigned long flags;
- if (id >= MAX_BRIDGE_DEVICES) {
- result = -EINVAL;
- goto free_data;
- }
- dev = __dev[id];
- if (!dev) {
- result = -ENODEV;
- goto free_data;
- }
- dev_dbg(&dev->intf->dev, "%s:[id]:%u: write (%d bytes)\n",
- __func__, id, size);
- writeurb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!writeurb) {
- dev_err(&dev->intf->dev, "%s: error allocating read urb\n",
- __func__);
- result = -ENOMEM;
- goto free_data;
- }
- out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_ATOMIC);
- if (!out_ctlreq) {
- dev_err(&dev->intf->dev,
- "%s: error allocating setup packet buffer\n",
- __func__);
- result = -ENOMEM;
- goto free_urb;
- }
- /* CDC Send Encapsulated Request packet */
- out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE);
- if (!data && !size) {
- out_ctlreq->bRequest = USB_CDC_REQ_SET_CONTROL_LINE_STATE;
- out_ctlreq->wValue = dev->cbits_tomdm;
- dev->set_ctrl_line_sts++;
- } else {
- out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
- out_ctlreq->wValue = 0;
- dev->snd_encap_cmd++;
- }
- out_ctlreq->wIndex =
- dev->intf->cur_altsetting->desc.bInterfaceNumber;
- out_ctlreq->wLength = cpu_to_le16(size);
- usb_fill_control_urb(writeurb, dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- (unsigned char *)out_ctlreq,
- (void *)data, size,
- ctrl_write_callback, dev);
- result = usb_autopm_get_interface_async(dev->intf);
- if (result < 0) {
- dev_dbg(&dev->intf->dev, "%s: unable to resume interface: %d\n",
- __func__, result);
- /*
- * Revisit: if (result == -EPERM)
- * bridge_suspend(dev->intf, PMSG_SUSPEND);
- */
- goto free_ctrlreq;
- }
- spin_lock_irqsave(&dev->lock, flags);
- if (test_bit(SUSPENDED, &dev->flags)) {
- usb_anchor_urb(writeurb, &dev->tx_deferred);
- spin_unlock_irqrestore(&dev->lock, flags);
- goto deferred;
- }
- usb_anchor_urb(writeurb, &dev->tx_submitted);
- spin_unlock_irqrestore(&dev->lock, flags);
- result = usb_submit_urb(writeurb, GFP_ATOMIC);
- if (result < 0) {
- dev_err(&dev->intf->dev, "%s: submit URB error %d\n",
- __func__, result);
- usb_autopm_put_interface_async(dev->intf);
- goto unanchor_urb;
- }
- deferred:
- return size;
- unanchor_urb:
- usb_unanchor_urb(writeurb);
- free_ctrlreq:
- kfree(out_ctlreq);
- free_urb:
- usb_free_urb(writeurb);
- free_data:
- kfree(data);
- return result;
- }
- EXPORT_SYMBOL(ctrl_bridge_write);
- int ctrl_bridge_suspend(unsigned int id)
- {
- struct ctrl_bridge *dev;
- unsigned long flags;
- if (id >= MAX_BRIDGE_DEVICES)
- return -EINVAL;
- dev = __dev[id];
- if (!dev)
- return -ENODEV;
- spin_lock_irqsave(&dev->lock, flags);
- if (!usb_anchor_empty(&dev->tx_submitted) || dev->rx_state == RX_BUSY) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EBUSY;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- usb_kill_urb(dev->inturb);
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->rx_state != RX_IDLE) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EBUSY;
- }
- if (!usb_anchor_empty(&dev->tx_submitted)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- ctrl_bridge_start_read(dev, GFP_KERNEL);
- return -EBUSY;
- }
- set_bit(SUSPENDED, &dev->flags);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- int ctrl_bridge_resume(unsigned int id)
- {
- struct ctrl_bridge *dev;
- struct urb *urb;
- unsigned long flags;
- int ret;
- if (id >= MAX_BRIDGE_DEVICES)
- return -EINVAL;
- dev = __dev[id];
- if (!dev)
- return -ENODEV;
- if (!test_bit(SUSPENDED, &dev->flags))
- return 0;
- spin_lock_irqsave(&dev->lock, flags);
- /* submit pending write requests */
- while ((urb = usb_get_from_anchor(&dev->tx_deferred))) {
- spin_unlock_irqrestore(&dev->lock, flags);
- /*
- * usb_get_from_anchor() does not drop the
- * ref count incremented by the usb_anchro_urb()
- * called in Tx submission path. Let us do it.
- */
- usb_put_urb(urb);
- usb_anchor_urb(urb, &dev->tx_submitted);
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0) {
- usb_unanchor_urb(urb);
- kfree(urb->setup_packet);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- usb_autopm_put_interface_async(dev->intf);
- }
- spin_lock_irqsave(&dev->lock, flags);
- }
- clear_bit(SUSPENDED, &dev->flags);
- spin_unlock_irqrestore(&dev->lock, flags);
- return ctrl_bridge_start_read(dev, GFP_KERNEL);
- }
- #if defined(CONFIG_DEBUG_FS)
- #define DEBUG_BUF_SIZE 1024
- static ssize_t ctrl_bridge_read_stats(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
- {
- struct ctrl_bridge *dev;
- char *buf;
- int ret;
- int i;
- int temp = 0;
- buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
- dev = __dev[i];
- if (!dev)
- continue;
- temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
- "\nName#%s dev %pK\n"
- "snd encap cmd cnt: %u\n"
- "get encap res cnt: %u\n"
- "res available cnt: %u\n"
- "set ctrlline sts cnt: %u\n"
- "notify ser state cnt: %u\n"
- "cbits_tomdm: %d\n"
- "cbits_tohost: %d\n"
- "suspended: %d\n",
- dev->name, dev,
- dev->snd_encap_cmd,
- dev->get_encap_res,
- dev->resp_avail,
- dev->set_ctrl_line_sts,
- dev->notify_ser_state,
- dev->cbits_tomdm,
- dev->cbits_tohost,
- test_bit(SUSPENDED, &dev->flags));
- }
- ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
- kfree(buf);
- return ret;
- }
- static ssize_t ctrl_bridge_reset_stats(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
- {
- struct ctrl_bridge *dev;
- int i;
- for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
- dev = __dev[i];
- if (!dev)
- continue;
- dev->snd_encap_cmd = 0;
- dev->get_encap_res = 0;
- dev->resp_avail = 0;
- dev->set_ctrl_line_sts = 0;
- dev->notify_ser_state = 0;
- }
- return count;
- }
- const struct file_operations ctrl_stats_ops = {
- .read = ctrl_bridge_read_stats,
- .write = ctrl_bridge_reset_stats,
- };
- struct dentry *ctrl_dent;
- struct dentry *ctrl_dfile;
- static void ctrl_bridge_debugfs_init(void)
- {
- ctrl_dent = debugfs_create_dir("ctrl_hsic_bridge", 0);
- if (IS_ERR(ctrl_dent))
- return;
- ctrl_dfile =
- debugfs_create_file("status", 0644, ctrl_dent, 0,
- &ctrl_stats_ops);
- if (!ctrl_dfile || IS_ERR(ctrl_dfile))
- debugfs_remove(ctrl_dent);
- }
- static void ctrl_bridge_debugfs_exit(void)
- {
- debugfs_remove(ctrl_dfile);
- debugfs_remove(ctrl_dent);
- }
- #else
- static void ctrl_bridge_debugfs_init(void) { }
- static void ctrl_bridge_debugfs_exit(void) { }
- #endif
- int
- ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in,
- char *name, int id)
- {
- struct ctrl_bridge *dev;
- struct usb_device *udev;
- struct usb_endpoint_descriptor *ep;
- u16 wMaxPacketSize;
- int retval = 0;
- int interval;
- udev = interface_to_usbdev(ifc);
- dev = __dev[id];
- if (!dev) {
- pr_err("%s:device not found\n", __func__);
- return -ENODEV;
- }
- dev->name = name;
- dev->pdev = platform_device_alloc(name, -1);
- if (!dev->pdev) {
- retval = -ENOMEM;
- dev_err(&ifc->dev, "%s: unable to allocate platform device\n",
- __func__);
- goto free_name;
- }
- dev->flags = 0;
- dev->udev = udev;
- dev->int_pipe = usb_rcvintpipe(udev,
- int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
- dev->intf = ifc;
- /*use max pkt size from ep desc*/
- ep = &dev->intf->cur_altsetting->endpoint[0].desc;
- dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->inturb) {
- dev_err(&ifc->dev, "%s: error allocating int urb\n", __func__);
- retval = -ENOMEM;
- goto pdev_put;
- }
- wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
- dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
- if (!dev->intbuf) {
- dev_err(&ifc->dev, "%s: error allocating int buffer\n",
- __func__);
- retval = -ENOMEM;
- goto free_inturb;
- }
- interval = int_in->desc.bInterval;
- usb_fill_int_urb(dev->inturb, udev, dev->int_pipe,
- dev->intbuf, wMaxPacketSize,
- notification_available_cb, dev, interval);
- dev->readurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->readurb) {
- dev_err(&ifc->dev, "%s: error allocating read urb\n",
- __func__);
- retval = -ENOMEM;
- goto free_intbuf;
- }
- dev->readbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
- if (!dev->readbuf) {
- dev_err(&ifc->dev, "%s: error allocating read buffer\n",
- __func__);
- retval = -ENOMEM;
- goto free_rurb;
- }
- dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
- if (!dev->in_ctlreq) {
- dev_err(&ifc->dev, "%s:error allocating setup packet buffer\n",
- __func__);
- retval = -ENOMEM;
- goto free_rbuf;
- }
- dev->in_ctlreq->bRequestType =
- (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
- dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
- dev->in_ctlreq->wValue = 0;
- dev->in_ctlreq->wIndex =
- dev->intf->cur_altsetting->desc.bInterfaceNumber;
- dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
- retval = platform_device_add(dev->pdev);
- if (retval) {
- dev_err(&ifc->dev, "%s:fail to add pdev\n", __func__);
- goto free_ctrlreq;
- }
- retval = ctrl_bridge_start_read(dev, GFP_KERNEL);
- if (retval) {
- dev_err(&ifc->dev, "%s:fail to start reading\n", __func__);
- goto pdev_del;
- }
- return 0;
- pdev_del:
- platform_device_del(dev->pdev);
- free_ctrlreq:
- kfree(dev->in_ctlreq);
- free_rbuf:
- kfree(dev->readbuf);
- free_rurb:
- usb_free_urb(dev->readurb);
- free_intbuf:
- kfree(dev->intbuf);
- free_inturb:
- usb_free_urb(dev->inturb);
- pdev_put:
- platform_device_put(dev->pdev);
- free_name:
- dev->name = "none";
- return retval;
- }
- void ctrl_bridge_disconnect(unsigned int id)
- {
- struct ctrl_bridge *dev = __dev[id];
- dev_dbg(&dev->intf->dev, "%s:\n", __func__);
- /*set device name to none to get correct channel id
- * at the time of bridge open
- */
- dev->name = "none";
- platform_device_unregister(dev->pdev);
- usb_scuttle_anchored_urbs(&dev->tx_deferred);
- usb_kill_anchored_urbs(&dev->tx_submitted);
- usb_kill_urb(dev->inturb);
- usb_kill_urb(dev->readurb);
- kfree(dev->in_ctlreq);
- kfree(dev->readbuf);
- kfree(dev->intbuf);
- usb_free_urb(dev->readurb);
- usb_free_urb(dev->inturb);
- }
- int ctrl_bridge_init(void)
- {
- struct ctrl_bridge *dev;
- int i;
- int retval = 0;
- for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- pr_err("%s: unable to allocate dev\n", __func__);
- retval = -ENOMEM;
- goto error;
- }
- /*transport name will be set during probe*/
- dev->name = "none";
- spin_lock_init(&dev->lock);
- init_usb_anchor(&dev->tx_submitted);
- init_usb_anchor(&dev->tx_deferred);
- __dev[i] = dev;
- }
- ctrl_bridge_debugfs_init();
- return 0;
- error:
- while (--i >= 0) {
- kfree(__dev[i]);
- __dev[i] = NULL;
- }
- return retval;
- }
- void ctrl_bridge_exit(void)
- {
- int i;
- ctrl_bridge_debugfs_exit();
- for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
- kfree(__dev[i]);
- __dev[i] = NULL;
- }
- }
|