Re: [PATCH 04/13] usb: dwc2: gadget: add TEST_MODE feature support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I got following error:
drivers/usb/dwc2/gadget.c: In function ‘testmode_write’:
drivers/usb/dwc2/gadget.c:3409:2: error: implicit declaration of
function ‘copy_from_user’ [-Werror=implicit-function-declaration]

You should add:
+#include <linux/uaccess.h>

Best regards,
Robert Baldyga

On 01/15/2015 06:09 PM, Mian Yousaf Kaukab wrote:
> From: Gregory Herrero <gregory.herrero@xxxxxxxxx>
> 
> 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.
> 
> Signed-off-by: Gregory Herrero <gregory.herrero@xxxxxxxxx>
> ---
>  drivers/usb/dwc2/core.h   |   4 +
>  drivers/usb/dwc2/gadget.c | 188 ++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 185 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index f09b3de..c750fd3 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -567,12 +567,14 @@ struct dwc2_hw_params {
>   * @num_of_eps:         Number of available EPs (excluding EP0)
>   * @debug_root:         Root directrory for debugfs.
>   * @debug_file:         Main status file for debugfs.
> + * @debug_testmode:     Testmode status file for debugfs.
>   * @debug_fifo:         FIFO status file for debugfs.
>   * @ep0_reply:          Request used for ep0 reply.
>   * @ep0_buff:           Buffer for EP0 reply data, if needed.
>   * @ctrl_buff:          Buffer for EP0 control requests.
>   * @ctrl_req:           Request for EP0 control packets.
>   * @ep0_state:          EP0 control transfers state
> + * @test_mode:          USB test mode requested by the host
>   * @last_rst:           Time of last reset
>   * @eps:                The endpoints being supplied to the gadget framework
>   * @g_using_dma:          Indicate if dma usage is enabled
> @@ -610,6 +612,7 @@ struct dwc2_hsotg {
>  
>  	struct dentry *debug_root;
>  	struct dentry *debug_file;
> +	struct dentry *debug_testmode;
>  	struct dentry *debug_fifo;
>  
>  	/* DWC OTG HW Release versions */
> @@ -706,6 +709,7 @@ struct dwc2_hsotg {
>  	void *ep0_buff;
>  	void *ctrl_buff;
>  	enum dwc2_ep0_state ep0_state;
> +	u8 test_mode;
>  
>  	struct usb_gadget gadget;
>  	unsigned int enabled:1;
> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index 0202230..1966406 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -835,6 +835,32 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
>  }
>  
>  /**
> + * s3c_hsotg_set_test_mode - Enable usb Test Modes
> + * @hsotg: The driver state.
> + * @testmode: requested usb test mode
> + * Enable usb Test Mode requested by the Host.
> + */
> +static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
> +{
> +	int dctl = readl(hsotg->regs + DCTL);
> +
> +	dctl &= ~DCTL_TSTCTL_MASK;
> +	switch (testmode) {
> +	case TEST_J:
> +	case TEST_K:
> +	case TEST_SE0_NAK:
> +	case TEST_PACKET:
> +	case TEST_FORCE_EN:
> +		dctl |= testmode << DCTL_TSTCTL_SHIFT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	writel(dctl, hsotg->regs + DCTL);
> +	return 0;
> +}
> +
> +/**
>   * s3c_hsotg_send_reply - send reply to control request
>   * @hsotg: The device state
>   * @ep: Endpoint 0
> @@ -968,19 +994,48 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
>  	struct s3c_hsotg_ep *ep;
>  	int ret;
>  	bool halted;
> +	u32 recip;
> +	u32 wValue;
> +	u32 wIndex;
>  
>  	dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
>  		__func__, set ? "SET" : "CLEAR");
>  
> -	if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
> -		ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
> +	wValue = le16_to_cpu(ctrl->wValue);
> +	wIndex = le16_to_cpu(ctrl->wIndex);
> +	recip = ctrl->bRequestType & USB_RECIP_MASK;
> +
> +	switch (recip) {
> +	case USB_RECIP_DEVICE:
> +		switch (wValue) {
> +		case USB_DEVICE_TEST_MODE:
> +			if ((wIndex & 0xff) != 0)
> +				return -EINVAL;
> +			if (!set)
> +				return -EINVAL;
> +
> +			hsotg->test_mode = wIndex >> 8;
> +			ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
> +			if (ret) {
> +				dev_err(hsotg->dev,
> +					"%s: failed to send reply\n", __func__);
> +				return ret;
> +			}
> +			break;
> +		default:
> +			return -ENOENT;
> +		}
> +		break;
> +
> +	case USB_RECIP_ENDPOINT:
> +		ep = ep_from_windex(hsotg, wIndex);
>  		if (!ep) {
>  			dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
> -				__func__, le16_to_cpu(ctrl->wIndex));
> +				__func__, wIndex);
>  			return -ENOENT;
>  		}
>  
> -		switch (le16_to_cpu(ctrl->wValue)) {
> +		switch (wValue) {
>  		case USB_ENDPOINT_HALT:
>  			halted = ep->halted;
>  
> @@ -1031,9 +1086,10 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
>  		default:
>  			return -ENOENT;
>  		}
> -	} else
> -		return -ENOENT;  /* currently only deal with endpoint */
> -
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
>  	return 1;
>  }
>  
> @@ -1734,6 +1790,17 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
>  	if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
>  		dev_dbg(hsotg->dev, "zlp packet sent\n");
>  		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
> +		if (hsotg->test_mode) {
> +			int ret;
> +
> +			ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode);
> +			if (ret < 0) {
> +				dev_dbg(hsotg->dev, "Invalid Test #%d\n",
> +						hsotg->test_mode);
> +				s3c_hsotg_stall_ep0(hsotg);
> +				return;
> +			}
> +		}
>  		s3c_hsotg_enqueue_setup(hsotg);
>  		return;
>  	}
> @@ -2045,6 +2112,7 @@ void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
>  		return;
>  
>  	hsotg->connected = 0;
> +	hsotg->test_mode = 0;
>  
>  	for (ep = 0; ep < hsotg->num_of_eps; ep++) {
>  		if (hsotg->eps_in[ep])
> @@ -3253,6 +3321,103 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
>  }
>  
>  /**
> + * testmode_write - debugfs: change usb test mode
> + * @seq: The seq file to write to.
> + * @v: Unused parameter.
> + *
> + * This debugfs entry modify the current usb test mode.
> + */
> +static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
> +		count, loff_t *ppos)
> +{
> +	struct seq_file		*s = file->private_data;
> +	struct dwc2_hsotg	*hsotg = s->private;
> +	unsigned long		flags;
> +	u32			testmode = 0;
> +	char			buf[32];
> +
> +	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
> +		return -EFAULT;
> +
> +	if (!strncmp(buf, "test_j", 6))
> +		testmode = TEST_J;
> +	else if (!strncmp(buf, "test_k", 6))
> +		testmode = TEST_K;
> +	else if (!strncmp(buf, "test_se0_nak", 12))
> +		testmode = TEST_SE0_NAK;
> +	else if (!strncmp(buf, "test_packet", 11))
> +		testmode = TEST_PACKET;
> +	else if (!strncmp(buf, "test_force_enable", 17))
> +		testmode = TEST_FORCE_EN;
> +	else
> +		testmode = 0;
> +
> +	spin_lock_irqsave(&hsotg->lock, flags);
> +	s3c_hsotg_set_test_mode(hsotg, testmode);
> +	spin_unlock_irqrestore(&hsotg->lock, flags);
> +	return count;
> +}
> +
> +/**
> + * testmode_show - debugfs: show usb test mode state
> + * @seq: The seq file to write to.
> + * @v: Unused parameter.
> + *
> + * This debugfs entry shows which usb test mode is currently enabled.
> + */
> +static int testmode_show(struct seq_file *s, void *unused)
> +{
> +	struct dwc2_hsotg *hsotg = s->private;
> +	unsigned long flags;
> +	int dctl;
> +
> +	spin_lock_irqsave(&hsotg->lock, flags);
> +	dctl = readl(hsotg->regs + DCTL);
> +	dctl &= DCTL_TSTCTL_MASK;
> +	dctl >>= DCTL_TSTCTL_SHIFT;
> +	spin_unlock_irqrestore(&hsotg->lock, flags);
> +
> +	switch (dctl) {
> +	case 0:
> +		seq_puts(s, "no test\n");
> +		break;
> +	case TEST_J:
> +		seq_puts(s, "test_j\n");
> +		break;
> +	case TEST_K:
> +		seq_puts(s, "test_k\n");
> +		break;
> +	case TEST_SE0_NAK:
> +		seq_puts(s, "test_se0_nak\n");
> +		break;
> +	case TEST_PACKET:
> +		seq_puts(s, "test_packet\n");
> +		break;
> +	case TEST_FORCE_EN:
> +		seq_puts(s, "test_force_enable\n");
> +		break;
> +	default:
> +		seq_printf(s, "UNKNOWN %d\n", dctl);
> +	}
> +
> +	return 0;
> +}
> +
> +static int testmode_open(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, testmode_show, inode->i_private);
> +}
> +
> +static const struct file_operations testmode_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= testmode_open,
> +	.write		= testmode_write,
> +	.read		= seq_read,
> +	.llseek		= seq_lseek,
> +	.release	= single_release,
> +};
> +
> +/**
>   * state_show - debugfs: show overall driver and device state.
>   * @seq: The seq file to write to.
>   * @v: Unused parameter.
> @@ -3486,6 +3651,14 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
>  	if (IS_ERR(hsotg->debug_file))
>  		dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
>  
> +	hsotg->debug_testmode = debugfs_create_file("testmode",
> +					S_IRUGO | S_IWUSR, root,
> +					hsotg, &testmode_fops);
> +
> +	if (IS_ERR(hsotg->debug_testmode))
> +		dev_err(hsotg->dev, "%s: failed to create testmode\n",
> +				__func__);
> +
>  	hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
>  						hsotg, &fifo_fops);
>  
> @@ -3540,6 +3713,7 @@ static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
>  	}
>  
>  	debugfs_remove(hsotg->debug_file);
> +	debugfs_remove(hsotg->debug_testmode);
>  	debugfs_remove(hsotg->debug_fifo);
>  	debugfs_remove(hsotg->debug_root);
>  }
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux