aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory Herrero <gregory.herrero@intel.com>2015-01-30 03:09:28 -0500
committerFelipe Balbi <balbi@ti.com>2015-01-30 11:30:44 -0500
commit9e14d0a566f48d33a9253096963b3b8199e4df57 (patch)
tree22e316e69be3e2b907a758ee64914782b3a20696
parentc00dd4a6ec20a58ed38be85f8e47efda40625f17 (diff)
usb: dwc2: gadget: add TEST_MODE feature support
Handle SET_FEATURE TEST_MODE request sent by the host. Slightly rework FEATURE request handling to allow parsing other request types than Endpoint. Also add a debugfs to change test mode value from user space. Tested-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Gregory Herrero <gregory.herrero@intel.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/dwc2/core.h4
-rw-r--r--drivers/usb/dwc2/gadget.c189
2 files changed, 186 insertions, 7 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index f09b3deffdee..c750fd3d88b3 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -567,12 +567,14 @@ struct dwc2_hw_params {
567 * @num_of_eps: Number of available EPs (excluding EP0) 567 * @num_of_eps: Number of available EPs (excluding EP0)
568 * @debug_root: Root directrory for debugfs. 568 * @debug_root: Root directrory for debugfs.
569 * @debug_file: Main status file for debugfs. 569 * @debug_file: Main status file for debugfs.
570 * @debug_testmode: Testmode status file for debugfs.
570 * @debug_fifo: FIFO status file for debugfs. 571 * @debug_fifo: FIFO status file for debugfs.
571 * @ep0_reply: Request used for ep0 reply. 572 * @ep0_reply: Request used for ep0 reply.
572 * @ep0_buff: Buffer for EP0 reply data, if needed. 573 * @ep0_buff: Buffer for EP0 reply data, if needed.
573 * @ctrl_buff: Buffer for EP0 control requests. 574 * @ctrl_buff: Buffer for EP0 control requests.
574 * @ctrl_req: Request for EP0 control packets. 575 * @ctrl_req: Request for EP0 control packets.
575 * @ep0_state: EP0 control transfers state 576 * @ep0_state: EP0 control transfers state
577 * @test_mode: USB test mode requested by the host
576 * @last_rst: Time of last reset 578 * @last_rst: Time of last reset
577 * @eps: The endpoints being supplied to the gadget framework 579 * @eps: The endpoints being supplied to the gadget framework
578 * @g_using_dma: Indicate if dma usage is enabled 580 * @g_using_dma: Indicate if dma usage is enabled
@@ -610,6 +612,7 @@ struct dwc2_hsotg {
610 612
611 struct dentry *debug_root; 613 struct dentry *debug_root;
612 struct dentry *debug_file; 614 struct dentry *debug_file;
615 struct dentry *debug_testmode;
613 struct dentry *debug_fifo; 616 struct dentry *debug_fifo;
614 617
615 /* DWC OTG HW Release versions */ 618 /* DWC OTG HW Release versions */
@@ -706,6 +709,7 @@ struct dwc2_hsotg {
706 void *ep0_buff; 709 void *ep0_buff;
707 void *ctrl_buff; 710 void *ctrl_buff;
708 enum dwc2_ep0_state ep0_state; 711 enum dwc2_ep0_state ep0_state;
712 u8 test_mode;
709 713
710 struct usb_gadget gadget; 714 struct usb_gadget gadget;
711 unsigned int enabled:1; 715 unsigned int enabled:1;
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 02d0e9af9242..67ea258335ad 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -35,6 +35,7 @@
35#include <linux/usb/gadget.h> 35#include <linux/usb/gadget.h>
36#include <linux/usb/phy.h> 36#include <linux/usb/phy.h>
37#include <linux/platform_data/s3c-hsotg.h> 37#include <linux/platform_data/s3c-hsotg.h>
38#include <linux/uaccess.h>
38 39
39#include "core.h" 40#include "core.h"
40#include "hw.h" 41#include "hw.h"
@@ -835,6 +836,32 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
835} 836}
836 837
837/** 838/**
839 * s3c_hsotg_set_test_mode - Enable usb Test Modes
840 * @hsotg: The driver state.
841 * @testmode: requested usb test mode
842 * Enable usb Test Mode requested by the Host.
843 */
844static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
845{
846 int dctl = readl(hsotg->regs + DCTL);
847
848 dctl &= ~DCTL_TSTCTL_MASK;
849 switch (testmode) {
850 case TEST_J:
851 case TEST_K:
852 case TEST_SE0_NAK:
853 case TEST_PACKET:
854 case TEST_FORCE_EN:
855 dctl |= testmode << DCTL_TSTCTL_SHIFT;
856 break;
857 default:
858 return -EINVAL;
859 }
860 writel(dctl, hsotg->regs + DCTL);
861 return 0;
862}
863
864/**
838 * s3c_hsotg_send_reply - send reply to control request 865 * s3c_hsotg_send_reply - send reply to control request
839 * @hsotg: The device state 866 * @hsotg: The device state
840 * @ep: Endpoint 0 867 * @ep: Endpoint 0
@@ -968,19 +995,48 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
968 struct s3c_hsotg_ep *ep; 995 struct s3c_hsotg_ep *ep;
969 int ret; 996 int ret;
970 bool halted; 997 bool halted;
998 u32 recip;
999 u32 wValue;
1000 u32 wIndex;
971 1001
972 dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 1002 dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
973 __func__, set ? "SET" : "CLEAR"); 1003 __func__, set ? "SET" : "CLEAR");
974 1004
975 if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { 1005 wValue = le16_to_cpu(ctrl->wValue);
976 ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 1006 wIndex = le16_to_cpu(ctrl->wIndex);
1007 recip = ctrl->bRequestType & USB_RECIP_MASK;
1008
1009 switch (recip) {
1010 case USB_RECIP_DEVICE:
1011 switch (wValue) {
1012 case USB_DEVICE_TEST_MODE:
1013 if ((wIndex & 0xff) != 0)
1014 return -EINVAL;
1015 if (!set)
1016 return -EINVAL;
1017
1018 hsotg->test_mode = wIndex >> 8;
1019 ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
1020 if (ret) {
1021 dev_err(hsotg->dev,
1022 "%s: failed to send reply\n", __func__);
1023 return ret;
1024 }
1025 break;
1026 default:
1027 return -ENOENT;
1028 }
1029 break;
1030
1031 case USB_RECIP_ENDPOINT:
1032 ep = ep_from_windex(hsotg, wIndex);
977 if (!ep) { 1033 if (!ep) {
978 dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 1034 dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
979 __func__, le16_to_cpu(ctrl->wIndex)); 1035 __func__, wIndex);
980 return -ENOENT; 1036 return -ENOENT;
981 } 1037 }
982 1038
983 switch (le16_to_cpu(ctrl->wValue)) { 1039 switch (wValue) {
984 case USB_ENDPOINT_HALT: 1040 case USB_ENDPOINT_HALT:
985 halted = ep->halted; 1041 halted = ep->halted;
986 1042
@@ -1031,9 +1087,10 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
1031 default: 1087 default:
1032 return -ENOENT; 1088 return -ENOENT;
1033 } 1089 }
1034 } else 1090 break;
1035 return -ENOENT; /* currently only deal with endpoint */ 1091 default:
1036 1092 return -ENOENT;
1093 }
1037 return 1; 1094 return 1;
1038} 1095}
1039 1096
@@ -1734,6 +1791,17 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
1734 if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 1791 if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
1735 dev_dbg(hsotg->dev, "zlp packet sent\n"); 1792 dev_dbg(hsotg->dev, "zlp packet sent\n");
1736 s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 1793 s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
1794 if (hsotg->test_mode) {
1795 int ret;
1796
1797 ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode);
1798 if (ret < 0) {
1799 dev_dbg(hsotg->dev, "Invalid Test #%d\n",
1800 hsotg->test_mode);
1801 s3c_hsotg_stall_ep0(hsotg);
1802 return;
1803 }
1804 }
1737 s3c_hsotg_enqueue_setup(hsotg); 1805 s3c_hsotg_enqueue_setup(hsotg);
1738 return; 1806 return;
1739 } 1807 }
@@ -2045,6 +2113,7 @@ void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
2045 return; 2113 return;
2046 2114
2047 hsotg->connected = 0; 2115 hsotg->connected = 0;
2116 hsotg->test_mode = 0;
2048 2117
2049 for (ep = 0; ep < hsotg->num_of_eps; ep++) { 2118 for (ep = 0; ep < hsotg->num_of_eps; ep++) {
2050 if (hsotg->eps_in[ep]) 2119 if (hsotg->eps_in[ep])
@@ -3257,6 +3326,103 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
3257} 3326}
3258 3327
3259/** 3328/**
3329 * testmode_write - debugfs: change usb test mode
3330 * @seq: The seq file to write to.
3331 * @v: Unused parameter.
3332 *
3333 * This debugfs entry modify the current usb test mode.
3334 */
3335static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
3336 count, loff_t *ppos)
3337{
3338 struct seq_file *s = file->private_data;
3339 struct dwc2_hsotg *hsotg = s->private;
3340 unsigned long flags;
3341 u32 testmode = 0;
3342 char buf[32];
3343
3344 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3345 return -EFAULT;
3346
3347 if (!strncmp(buf, "test_j", 6))
3348 testmode = TEST_J;
3349 else if (!strncmp(buf, "test_k", 6))
3350 testmode = TEST_K;
3351 else if (!strncmp(buf, "test_se0_nak", 12))
3352 testmode = TEST_SE0_NAK;
3353 else if (!strncmp(buf, "test_packet", 11))
3354 testmode = TEST_PACKET;
3355 else if (!strncmp(buf, "test_force_enable", 17))
3356 testmode = TEST_FORCE_EN;
3357 else
3358 testmode = 0;
3359
3360 spin_lock_irqsave(&hsotg->lock, flags);
3361 s3c_hsotg_set_test_mode(hsotg, testmode);
3362 spin_unlock_irqrestore(&hsotg->lock, flags);
3363 return count;
3364}
3365
3366/**
3367 * testmode_show - debugfs: show usb test mode state
3368 * @seq: The seq file to write to.
3369 * @v: Unused parameter.
3370 *
3371 * This debugfs entry shows which usb test mode is currently enabled.
3372 */
3373static int testmode_show(struct seq_file *s, void *unused)
3374{
3375 struct dwc2_hsotg *hsotg = s->private;
3376 unsigned long flags;
3377 int dctl;
3378
3379 spin_lock_irqsave(&hsotg->lock, flags);
3380 dctl = readl(hsotg->regs + DCTL);
3381 dctl &= DCTL_TSTCTL_MASK;
3382 dctl >>= DCTL_TSTCTL_SHIFT;
3383 spin_unlock_irqrestore(&hsotg->lock, flags);
3384
3385 switch (dctl) {
3386 case 0:
3387 seq_puts(s, "no test\n");
3388 break;
3389 case TEST_J:
3390 seq_puts(s, "test_j\n");
3391 break;
3392 case TEST_K:
3393 seq_puts(s, "test_k\n");
3394 break;
3395 case TEST_SE0_NAK:
3396 seq_puts(s, "test_se0_nak\n");
3397 break;
3398 case TEST_PACKET:
3399 seq_puts(s, "test_packet\n");
3400 break;
3401 case TEST_FORCE_EN:
3402 seq_puts(s, "test_force_enable\n");
3403 break;
3404 default:
3405 seq_printf(s, "UNKNOWN %d\n", dctl);
3406 }
3407
3408 return 0;
3409}
3410
3411static int testmode_open(struct inode *inode, struct file *file)
3412{
3413 return single_open(file, testmode_show, inode->i_private);
3414}
3415
3416static const struct file_operations testmode_fops = {
3417 .owner = THIS_MODULE,
3418 .open = testmode_open,
3419 .write = testmode_write,
3420 .read = seq_read,
3421 .llseek = seq_lseek,
3422 .release = single_release,
3423};
3424
3425/**
3260 * state_show - debugfs: show overall driver and device state. 3426 * state_show - debugfs: show overall driver and device state.
3261 * @seq: The seq file to write to. 3427 * @seq: The seq file to write to.
3262 * @v: Unused parameter. 3428 * @v: Unused parameter.
@@ -3490,6 +3656,14 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
3490 if (IS_ERR(hsotg->debug_file)) 3656 if (IS_ERR(hsotg->debug_file))
3491 dev_err(hsotg->dev, "%s: failed to create state\n", __func__); 3657 dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
3492 3658
3659 hsotg->debug_testmode = debugfs_create_file("testmode",
3660 S_IRUGO | S_IWUSR, root,
3661 hsotg, &testmode_fops);
3662
3663 if (IS_ERR(hsotg->debug_testmode))
3664 dev_err(hsotg->dev, "%s: failed to create testmode\n",
3665 __func__);
3666
3493 hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, 3667 hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
3494 hsotg, &fifo_fops); 3668 hsotg, &fifo_fops);
3495 3669
@@ -3544,6 +3718,7 @@ static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
3544 } 3718 }
3545 3719
3546 debugfs_remove(hsotg->debug_file); 3720 debugfs_remove(hsotg->debug_file);
3721 debugfs_remove(hsotg->debug_testmode);
3547 debugfs_remove(hsotg->debug_fifo); 3722 debugfs_remove(hsotg->debug_fifo);
3548 debugfs_remove(hsotg->debug_root); 3723 debugfs_remove(hsotg->debug_root);
3549} 3724}