int mtp_function_init(void) { int ret; #if !defined(CONFIG_LGE_USB_GADGET_MTP_DRIVER) struct proc_dir_entry *mtp_proc = NULL; #endif ret = misc_register(&mtp_device); if (ret) { printk(KERN_ERR "mtp device failed to initialize\n"); } ret = misc_register(&mtp_csr_device); if (ret) { printk(KERN_ERR "mtp csr device failed to initialize\n"); } #if !defined(CONFIG_LGE_USB_GADGET_MTP_DRIVER) mtp_proc = create_proc_entry("mtpctl", 0666, 0); if (!mtp_proc) { mtp_err("creating /proc/mtpctl failed\n"); return 1; } mtp_proc->proc_fops = &mtp_ctl_fops; #endif return ret; }
static void mtp_int_complete(struct usb_ep *ep, struct usb_request *req) { mtp_debug("status is %d %d\n", req->status, req->actual); if (req->status == -ECONNRESET) usb_ep_fifo_flush(ep); if (req->status != 0) mtp_err("status is %d %p len=%d\n", req->status, req, req->actual); g_usb_mtp_context.intr_in_busy = 0; return; }
static void mtp_in_complete(struct usb_ep *ep, struct usb_request *req) { mtp_debug("status is %d %p %d\n", req->status, req, req->actual); if (req->status == -ECONNRESET) usb_ep_fifo_flush(ep); if (req->status != 0) { g_usb_mtp_context.error = 1; mtp_err("status is %d %p len=%d\n", req->status, req, req->actual); } req_put(&g_usb_mtp_context.tx_reqs, req); wake_up(&g_usb_mtp_context.tx_wq); }
static void start_out_receive(void) { struct usb_request *req; int ret; /* if we have idle read requests, get them queued */ while ((req = req_get(&g_usb_mtp_context.rx_reqs))) { req->length = BULK_BUFFER_SIZE; ret = usb_ep_queue(g_usb_mtp_context.bulk_out, req, GFP_ATOMIC); if (ret < 0) { mtp_err("error %d\n", ret); g_usb_mtp_context.error = 1; req_put(&g_usb_mtp_context.rx_reqs, req); } } }
int mtp_bind_config(struct usb_configuration *c) { int ret = 0; int status; printk(KERN_INFO "Gadget Usb: mtp_bind_config\n"); init_waitqueue_head(&g_usb_mtp_context.rx_wq); init_waitqueue_head(&g_usb_mtp_context.tx_wq); init_waitqueue_head(&g_usb_mtp_context.ctl_rx_wq); init_waitqueue_head(&g_usb_mtp_context.ctl_tx_wq); INIT_LIST_HEAD(&g_usb_mtp_context.rx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.rx_done_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.tx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.ctl_rx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.ctl_rx_done_reqs); status = usb_string_id(c->cdev); if (status >= 0) { mtp_string_defs1[STRING_INTERFACE].id = status; intf_desc.iInterface = status; } mtp_string_defs2[STRING_MTP].id = mtp_ext_str_idx; g_usb_mtp_context.cdev = c->cdev; g_usb_mtp_context.function.name = "mtp"; g_usb_mtp_context.function.descriptors = fs_mtp_descs; g_usb_mtp_context.function.hs_descriptors = hs_mtp_descs; g_usb_mtp_context.function.strings = mtp_strings; g_usb_mtp_context.function.bind = mtp_function_bind; g_usb_mtp_context.function.unbind = mtp_function_unbind; g_usb_mtp_context.function.setup = mtp_function_setup; g_usb_mtp_context.function.set_alt = mtp_function_set_alt; g_usb_mtp_context.function.disable = mtp_function_disable; /* start disabled */ g_usb_mtp_context.function.hidden = 1; ret = usb_add_function(c, &g_usb_mtp_context.function); if (ret) { mtp_err("MTP gadget driver failed to initialize\n"); return ret; } return 0; }
static void mtp_out_complete(struct usb_ep *ep, struct usb_request *req) { mtp_debug("status is %d %p %d\n", req->status, req, req->actual); if (req->status == 0) { req_put(&g_usb_mtp_context.rx_done_reqs, req); } else { mtp_err("status is %d %p len=%d\n", req->status, req, req->actual); g_usb_mtp_context.error = 1; if (req->status == -ECONNRESET) { #ifdef CONFIG_LGE_USB_GADGET_MTP_DRIVER lg_mtp_debug("LG_FW : BULK OUT DATA Flush!!\n"); #endif usb_ep_fifo_flush(ep); } req_put(&g_usb_mtp_context.rx_reqs, req); } wake_up(&g_usb_mtp_context.rx_wq); }
static int mtp_function_bind(struct usb_configuration *c, struct usb_function *f) { int n, rc, id; struct usb_ep *ep; struct usb_request *req; struct proc_dir_entry *mtp_proc = NULL; spin_lock_init(&g_usb_mtp_context.lock); g_usb_mtp_context.cdev = c->cdev; /* allocate interface ID(s) */ id = usb_interface_id(c, f); if (id < 0) return id; intf_desc.bInterfaceNumber = id; /* Find all the endpoints we will use */ ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget, &fs_bulk_in_desc); if (!ep) { mtp_err("auto-configure hs_bulk_in_desc error\n"); goto autoconf_fail; } ep->driver_data = &g_usb_mtp_context; g_usb_mtp_context.bulk_in = ep; ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget, &fs_bulk_out_desc); if (!ep) { mtp_err("auto-configure hs_bulk_out_desc error\n"); goto autoconf_fail; } ep->driver_data = &g_usb_mtp_context; g_usb_mtp_context.bulk_out = ep; ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget, &fs_intr_in_desc); if (!ep) { mtp_err("auto-configure hs_intr_in_desc error\n"); goto autoconf_fail; } ep->driver_data = &g_usb_mtp_context; g_usb_mtp_context.intr_in = ep; if (gadget_is_dualspeed(g_usb_mtp_context.cdev->gadget)) { /* Assume endpoint addresses are the same for both speeds */ hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; } rc = -ENOMEM; for (n = 0; n < MAX_BULK_RX_REQ_NUM; n++) { req = req_new(g_usb_mtp_context.bulk_out, BULK_BUFFER_SIZE); if (!req) goto autoconf_fail; pending_reqs[n] = req; req->complete = mtp_out_complete; req_put(&g_usb_mtp_context.rx_reqs, req); } for (n = 0; n < MAX_BULK_TX_REQ_NUM; n++) { req = req_new(g_usb_mtp_context.bulk_in, BULK_BUFFER_SIZE); if (!req) goto autoconf_fail; req->complete = mtp_in_complete; req_put(&g_usb_mtp_context.tx_reqs, req); } for (n = 0; n < MAX_CTL_RX_REQ_NUM; n++) ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, &ctl_reqs[n]); g_usb_mtp_context.int_tx_req = req_new(g_usb_mtp_context.intr_in, BULK_BUFFER_SIZE); if (!g_usb_mtp_context.int_tx_req) goto autoconf_fail; g_usb_mtp_context.intr_in_busy = 0; g_usb_mtp_context.int_tx_req->complete = mtp_int_complete; g_usb_mtp_context.ctl_tx_req = req_new(g_usb_mtp_context.cdev->gadget->ep0, 512); if (!g_usb_mtp_context.ctl_tx_req) goto autoconf_fail; misc_register(&mtp_device); mtp_proc = create_proc_entry("mtpctl", 0666, 0); if (!mtp_proc) { mtp_err("creating /proc/mtpctl failed\n"); goto autoconf_fail; } mtp_proc->proc_fops = &mtp_ctl_fops; return 0; autoconf_fail: rc = -ENOTSUPP; mtp_function_unbind(c, f); return rc; }
static ssize_t mtp_ctl_write(struct file *file, const char *buf, size_t count, loff_t *pos) { struct mtp_ctl_msg_header msg; struct usb_request *req = NULL; struct usb_ep *ep0; int ret; mtp_debug("count=%d\n", count); ret = wait_event_interruptible(g_usb_mtp_context.ctl_tx_wq, (g_usb_mtp_context.online || g_usb_mtp_context.ctl_cancel)); if (g_usb_mtp_context.ctl_cancel) { mtp_debug("ctl_cancel return in mtp_ctl_write 1\n"); g_usb_mtp_context.ctl_cancel = 0; return -EINVAL; } if (ret < 0) return ret; ep0 = g_usb_mtp_context.cdev->gadget->ep0; if (count > ep0->maxpacket || count < MTP_CTL_MSG_HEADER_SIZE) { mtp_err("size invalid\n"); return -ENOMEM; } /* msg info */ if (copy_from_user(&msg, buf, MTP_CTL_MSG_HEADER_SIZE)) return -EINVAL; mtp_debug("msg len = %d, msg id = %d", msg.msg_len, msg.msg_id); if (msg.msg_id != MTP_CTL_CLASS_REPLY) { mtp_err("invalid id %d", msg.msg_id); return -EINVAL; } /* sending the data */ req = g_usb_mtp_context.ctl_tx_req; if (!req) return -ENOMEM; req->length = count - MTP_CTL_MSG_HEADER_SIZE; req->complete = mtp_ctl_write_complete; if (copy_from_user(req->buf, (u8 *)buf + MTP_CTL_MSG_HEADER_SIZE, req->length)) { return -EINVAL; } ctl_tx_done = 0; if (usb_ep_queue(ep0, req, GFP_ATOMIC)) { req->status = 0; mtp_ctl_write_complete(ep0, req); return -EIO; } ret = wait_event_interruptible(g_usb_mtp_context.ctl_tx_wq, (ctl_tx_done || g_usb_mtp_context.ctl_cancel)); ctl_tx_done = 0; if (g_usb_mtp_context.ctl_cancel) { mtp_debug("ctl_cancel return in mtp_ctl_write\n"); g_usb_mtp_context.ctl_cancel = 0; return -EINVAL; } if (ret < 0) return ret; mtp_debug("return count=%d\n", count); return count; }
static ssize_t mtp_ctl_read(struct file *file, char *buf, size_t count, loff_t *pos) { int ret, size = sizeof(struct usb_ctrlrequest); struct mtp_ctl_msg_header msg; mtp_debug("count=%d\n", count); if (!g_usb_mtp_context.online) return -EINVAL; if (!cur_creq) { ret = wait_event_interruptible(g_usb_mtp_context.ctl_rx_wq, ((cur_creq = ctl_req_get(&g_usb_mtp_context.ctl_rx_done_reqs)) || g_usb_mtp_context.ctl_cancel || g_usb_mtp_context.reset)); if (g_usb_mtp_context.ctl_cancel) { mtp_debug("ctl_cancel return in mtp_ctl_read\n"); if (cur_creq) { ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, cur_creq); if (g_usb_mtp_context.reset) cur_creq = NULL; } g_usb_mtp_context.ctl_cancel = 0; if (!g_usb_mtp_context.reset) return -EINVAL; } if (g_usb_mtp_context.reset) { mtp_debug("ctl_reset return in mtp_ctl_read\n"); if (cur_creq) ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, cur_creq); g_usb_mtp_context.reset = 0; return -EHOSTRESET; } if (ret < 0) { mtp_err("wait_event_interruptible return %d\n", ret); return ret; } } msg.msg_id = MTP_CTL_CLASS_REQ; msg.msg_len = MTP_CTL_MSG_SIZE; if (cur_creq->creq.bRequest == MTP_CLASS_CANCEL_REQ) msg.msg_len = MTP_CTL_MSG_SIZE + MTP_CANCEL_REQ_DATA_SIZE; if (cur_creq->header == 1) { cur_creq->header = 0; if (copy_to_user(buf, &msg, MTP_CTL_MSG_HEADER_SIZE)) goto ctl_read_fail; ret = MTP_CTL_MSG_HEADER_SIZE; mtp_debug("msg header return %d\n", ret); } else { if (copy_to_user(buf, &cur_creq->creq, size)) goto ctl_read_fail; ret = size; if (cur_creq->creq.bRequest == MTP_CLASS_CANCEL_REQ) { if (copy_to_user(buf + size, &cur_creq->cancel_data, MTP_CANCEL_REQ_DATA_SIZE)) goto ctl_read_fail; ret += MTP_CANCEL_REQ_DATA_SIZE; } mtp_debug("prepare %d %x\n", ret, cur_creq->creq.bRequest); ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, cur_creq); cur_creq = NULL; } mtp_debug("return %d\n", ret); return ret; ctl_read_fail: ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, cur_creq); cur_creq = NULL; mtp_debug("return -EFAULT\n"); return -EFAULT; }
static int mtp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int len, clen, count, n; struct usb_request *req; struct mtp_event_data event; if (!g_usb_mtp_context.online) return -EINVAL; switch (cmd) { case MTP_IOC_EVENT: if (g_usb_mtp_context.intr_in_busy) { mtp_err("interrupt in request busy\n"); return -EBUSY; } count = MIN(_IOC_SIZE(cmd), MTP_EVENT_SIZE); if (copy_from_user(event.data, (void *)arg, count)) return -EINVAL; /* length is in little endian */ memcpy(&len, event.data, sizeof(len)); clen = le32_to_cpu(len); mtp_debug("len=%d cpu len=%d\n", len, clen); /* send event through interrupt in */ req = g_usb_mtp_context.int_tx_req; if (!req) return -EINVAL; count = MIN(MTP_EVENT_SIZE, clen); memcpy(req->buf, event.data, count); req->length = count; req->zero = 0; g_usb_mtp_context.intr_in_busy = 1; if (usb_ep_queue(g_usb_mtp_context.intr_in, req, GFP_ATOMIC)) { g_usb_mtp_context.intr_in_busy = 0; return -EINVAL; } break; case MTP_IOC_SEND_ZLP: req = req_get(&g_usb_mtp_context.tx_reqs); if (!req) return -EINVAL; req->length = 0; req->zero = 0; if (usb_ep_queue(g_usb_mtp_context.bulk_in, req, GFP_ATOMIC)) { req_put(&g_usb_mtp_context.tx_reqs, req); return -EINVAL; } break; case MTP_IOC_GET_EP_SIZE_IN: /* get endpoint buffer size for bulk in */ len = BULK_BUFFER_SIZE; if (copy_to_user((void *)arg, &len, sizeof(int))) return -EINVAL; break; case MTP_IOC_CANCEL_IO: mtp_debug("MTP_IOC_CANCEL_IO:\n"); g_usb_mtp_context.cancel = 1; for (n = 0; n < MAX_BULK_RX_REQ_NUM; n++) { req = pending_reqs[n]; if (req && req->actual) { mtp_err("n=%d %p %d\n", n, req, req->actual); req->actual = 0; } } /* we've cancelled the recv urb, start new one */ mtp_debug("MTP_IOC_CANCEL_IO end:\n"); wake_up(&g_usb_mtp_context.rx_wq); wake_up(&g_usb_mtp_context.tx_wq); break; case MTP_IOC_DEVICE_RESET: g_usb_mtp_context.cancel = 1; g_usb_mtp_context.ctl_cancel = 1; wake_up(&g_usb_mtp_context.rx_wq); wake_up(&g_usb_mtp_context.tx_wq); wake_up(&g_usb_mtp_context.ctl_rx_wq); wake_up(&g_usb_mtp_context.ctl_tx_wq); break; } return 0; }
static ssize_t mtp_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { struct usb_request *req; int rc = count, xfer; int ret; while (count > 0) { mtp_debug("count=%d\n", count); if (g_usb_mtp_context.error) return -EIO; /* get an idle tx request to use */ ret = wait_event_interruptible(g_usb_mtp_context.tx_wq, (g_usb_mtp_context.online || g_usb_mtp_context.cancel)); if (g_usb_mtp_context.cancel) { mtp_debug("cancel return in mtp_write at beginning\n"); g_usb_mtp_context.cancel = 0; return -EINVAL; } if (ret < 0) { mtp_err("wait_event_interruptible return %d\n", ret); rc = ret; break; } req = 0; mtp_debug("get tx req\n"); ret = wait_event_interruptible(g_usb_mtp_context.tx_wq, ((req = req_get(&g_usb_mtp_context.tx_reqs)) || g_usb_mtp_context.cancel)); mtp_debug("got tx req\n"); if (g_usb_mtp_context.cancel) { mtp_debug("cancel return in mtp_write get req\n"); if (req != 0) req_put(&g_usb_mtp_context.tx_reqs, req); g_usb_mtp_context.cancel = 0; return -EINVAL; } if (ret < 0) { mtp_err("wait_event_interruptible return(2) %d\n", ret); rc = ret; break; } if (req != 0) { if (count > BULK_BUFFER_SIZE) xfer = BULK_BUFFER_SIZE; else xfer = count; if (copy_from_user(req->buf, buf, xfer)) { req_put(&g_usb_mtp_context.tx_reqs, req); rc = -EFAULT; break; } req->length = xfer; ret = usb_ep_queue(g_usb_mtp_context.bulk_in, req, GFP_ATOMIC); if (ret < 0) { mtp_err("error %d\n", ret); g_usb_mtp_context.error = 1; req_put(&g_usb_mtp_context.tx_reqs, req); rc = ret; break; } buf += xfer; count -= xfer; mtp_debug("xfer=%d\n", xfer); } } mtp_debug("mtp_write returning %d\n", rc); return rc; }
static ssize_t mtp_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { struct usb_request *req = 0; int xfer, rc = count; int ret; while (count > 0) { mtp_debug("count=%d\n", count); if (g_usb_mtp_context.error) return -EIO; /* we will block until we're online */ ret = wait_event_interruptible(g_usb_mtp_context.rx_wq, (g_usb_mtp_context.online || g_usb_mtp_context.cancel)); if (g_usb_mtp_context.cancel) { mtp_debug("cancel return in mtp_read at beginning\n"); g_usb_mtp_context.cancel = 0; return -EINVAL; } if (ret < 0) { mtp_err("wait_event_interruptible return %d\n", ret); rc = ret; break; } /* if we have idle read requests, get them queued */ while (1) { req = req_get(&g_usb_mtp_context.rx_reqs); if (!req) break; requeue_req: req->length = BULK_BUFFER_SIZE; mtp_debug("rx %p queue\n", req); ret = usb_ep_queue(g_usb_mtp_context.bulk_out, req, GFP_ATOMIC); if (ret < 0) { mtp_err("queue error %d\n", ret); g_usb_mtp_context.error = 1; req_put(&g_usb_mtp_context.rx_reqs, req); return ret; } } /* if we have data pending, give it to userspace */ if (g_usb_mtp_context.data_len > 0) { if (g_usb_mtp_context.data_len < count) xfer = g_usb_mtp_context.data_len; else xfer = count; if (copy_to_user(buf, g_usb_mtp_context.read_buf, xfer)) { rc = -EFAULT; break; } g_usb_mtp_context.read_buf += xfer; g_usb_mtp_context.data_len -= xfer; buf += xfer; count -= xfer; mtp_debug("xfer=%d\n", xfer); /* if we've emptied the buffer, release the request */ if (g_usb_mtp_context.data_len == 0) { req_put(&g_usb_mtp_context.rx_reqs, g_usb_mtp_context.cur_read_req); g_usb_mtp_context.cur_read_req = 0; } continue; } /* wait for a request to complete */ req = 0; mtp_debug("wait req finish\n"); ret = wait_event_interruptible(g_usb_mtp_context.rx_wq, ((req = req_get(&g_usb_mtp_context.rx_done_reqs)) || g_usb_mtp_context.cancel)); mtp_debug("req finished\n"); if (g_usb_mtp_context.cancel) { if (req != 0) req_put(&g_usb_mtp_context.rx_reqs, req); mtp_debug("cancel return in mtp_read at complete\n"); g_usb_mtp_context.cancel = 0; return -EINVAL; } if (ret < 0) { mtp_err("wait_event_interruptible(2) return %d\n", ret); rc = ret; break; } if (req != 0) { /* if we got a 0-len one we need to put it back into ** service. if we made it the current read req we'd ** be stuck forever */ if (req->actual == 0) goto requeue_req; g_usb_mtp_context.cur_read_req = req; g_usb_mtp_context.data_len = req->actual; g_usb_mtp_context.read_buf = req->buf; mtp_debug("rx %p done actual=%d\n", req, req->actual); } } mtp_debug("mtp_read returning %d\n", rc); return rc; }
static int mtp_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wLength = le16_to_cpu(ctrl->wLength); struct usb_composite_dev *cdev = f->config->cdev; struct usb_request *req = cdev->req; struct ctl_req_wrapper *ctl_req; if (f->hidden == 1) return value; mtp_debug("bRequestType=0x%x bRequest=0x%x wIndex=0x%x wLength=0x%x\n", ctrl->bRequestType, ctrl->bRequest, wIndex, wLength); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_VENDOR: switch (ctrl->bRequest) { case MTP_MOD_VENDOR_CODE: if (wIndex == mtp_ext_id) { memcpy(req->buf, mtp_ext_desc, sizeof(mtp_ext_desc)); if (wLength < mtp_ext_desc[0]) value = wLength; else value = mtp_ext_desc[0]; req->zero = 0; req->length = value; if (usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC)) mtp_err("ep0 in queue failed\n"); } break; default: break; } break; case USB_TYPE_CLASS: switch (ctrl->bRequest) { case MTP_CLASS_CANCEL_REQ: case MTP_CLASS_GET_EXTEND_EVEVT_DATA: case MTP_CLASS_GET_DEVICE_STATUS: mtp_debug("ctl request=0x%x\n", ctrl->bRequest); ctl_req = ctl_req_get(&g_usb_mtp_context.ctl_rx_reqs); if (!ctl_req) { mtp_err("get free ctl req failed\n"); break; } memcpy(&ctl_req->creq, ctrl, sizeof(struct usb_ctrlrequest)); ctl_req->header = 1; ctl_req_put(&g_usb_mtp_context.ctl_rx_done_reqs, ctl_req); value = 0; if ((ctrl->bRequest == MTP_CLASS_CANCEL_REQ) && wLength == MTP_CANCEL_REQ_DATA_SIZE) { memset(&ctl_req->cancel_data, 0, MTP_CANCEL_REQ_DATA_SIZE); value = wLength; cdev->gadget->ep0->driver_data = ctl_req; req->complete = mtp_ctl_read_complete; req->zero = 0; req->length = wLength; if (usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC)) { mtp_err("ep0 out queue failed\n"); mtp_ctl_read_complete(cdev->gadget->ep0, req); } } else wake_up(&g_usb_mtp_context.ctl_rx_wq); break; default: break; } } mtp_debug("return value=%d\n", value); return value; }
int mtp_function_add(struct usb_composite_dev *cdev, struct usb_configuration *c) #endif { int ret = 0; int status; init_waitqueue_head(&g_usb_mtp_context.rx_wq); init_waitqueue_head(&g_usb_mtp_context.tx_wq); init_waitqueue_head(&g_usb_mtp_context.ctl_rx_wq); init_waitqueue_head(&g_usb_mtp_context.ctl_tx_wq); INIT_LIST_HEAD(&g_usb_mtp_context.rx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.rx_done_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.tx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.ctl_rx_reqs); INIT_LIST_HEAD(&g_usb_mtp_context.ctl_rx_done_reqs); status = usb_string_id(c->cdev); if (status >= 0) { mtp_string_defs[STRING_INTERFACE].id = status; intf_desc.iInterface = status; } mtp_string_defs[STRING_MTP].id = mtp_ext_str_idx; #ifdef CONFIG_LGE_USB_GADGET_FUNC_BIND_ONLY_INIT g_usb_mtp_context.cdev = c->cdev; #else g_usb_mtp_context.cdev = cdev; #endif g_usb_mtp_context.function.name = "mtp"; g_usb_mtp_context.function.descriptors = fs_mtp_descs; g_usb_mtp_context.function.hs_descriptors = hs_mtp_descs; g_usb_mtp_context.function.strings = mtp_strings; g_usb_mtp_context.function.bind = mtp_function_bind; g_usb_mtp_context.function.unbind = mtp_function_unbind; g_usb_mtp_context.function.setup = mtp_function_setup; g_usb_mtp_context.function.set_alt = mtp_function_set_alt; g_usb_mtp_context.function.disable = mtp_function_disable; #ifndef CONFIG_LGE_USB_GADGET_FUNC_BIND_ONLY_INIT ret = mtp_function_init(); if (ret) goto mtp_exit; ret = misc_register(&mtp_enable_device); if (ret) goto misc_deregister; #endif #ifdef CONFIG_LGE_USB_GADGET_FUNC_BIND_ONLY_INIT /* start disabled */ g_usb_mtp_context.function.disabled = 1; #endif ret = usb_add_function(c, &g_usb_mtp_context.function); if (ret) { mtp_err("MTP gadget driver failed to initialize\n"); return ret; } return 0; #ifndef CONFIG_LGE_USB_GADGET_FUNC_BIND_ONLY_INIT mtp_misc_deregister: misc_deregister(&mtp_enable_device); mtp_exit: mtp_function_exit(); return ret; #endif }
static int mtp_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wLength = le16_to_cpu(ctrl->wLength); struct usb_composite_dev *cdev = f->config->cdev; struct usb_request *req = cdev->req; // int result = -EOPNOTSUPP; mtp_debug("bRequestType=0x%x bRequest=0x%x wIndex=0x%x wLength=0x%x\n", ctrl->bRequestType, ctrl->bRequest, wIndex, wLength); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_VENDOR: switch (ctrl->bRequest) { case MTP_MOD_VENDOR_CODE: if (wIndex == mtp_ext_id) { memcpy(req->buf, mtp_ext_desc, sizeof(mtp_ext_desc)); if (wLength < mtp_ext_desc[0]) value = wLength; else value = mtp_ext_desc[0]; req->zero = 0; req->length = value; if (usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC)) mtp_err("ep0 in queue failed\n"); } break; default: break; } break; case USB_TYPE_CLASS: switch (ctrl->bRequest) { case MTP_CLASS_CANCEL_REQ: case MTP_CLASS_GET_EXTEND_EVEVT_DATA: case MTP_CLASS_RESET_REQ: case MTP_CLASS_GET_DEVICE_STATUS: #ifdef CONFIG_LGE_USB_GADGET_MTP_DRIVER g_bRequest = ctrl->bRequest; if(g_bRequest == MTP_CLASS_CANCEL_REQ) { lg_mtp_debug("LG_FW : MTP CANCEL Request PC => Device!!\n"); cancel_noti = 1; } else if(g_bRequest == MTP_CLASS_GET_DEVICE_STATUS) { lg_mtp_debug("LG_FW : MTP GET DEVICE Request PC => Device!!\n"); } #endif mtp_debug("ctl request=0x%x\n", ctrl->bRequest); value = 0; if ((ctrl->bRequest == MTP_CLASS_CANCEL_REQ) && wLength == MTP_CANCEL_REQ_DATA_SIZE) { value = wLength; req->zero = 0; req->length = wLength; lg_mtp_debug("LG_FW : MTP Cancel Request Length [%d] \n", wLength); if (usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC)) { mtp_err("ep0 out queue failed\n"); } } break; default: break; } } mtp_debug("return value=%d\n", value); return value; }