[RFC] [PATCH] Debugfs support for EHCI testing modes

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

 



Hi

I have just written a ehci testing driver which enables the testing modes used
for hw testing via a file in debugfs.  This patch is for 3.4.47 not any usb
branch. But if this driver is ready for mainline i will be happy to port it to
whatever branch you wish.

The only problem with the patch is that it is currently working on hw registers
as the usb control msg in this patch is not working. For the time beeing i just
commented out the usb_control_msg call and fiddled with the registers directly.
This is one thing which might not be mainline compatible?

The call not working is:
status = usb_control_msg(hub, usb_sndctrlpipe(hub,0),
                                               USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST,
                                               i << 8 | hub->portnum, NULL, 0, 1000);
                                               ^^^^^^^^^^^^^^^^^ this might be wrong?

I have the strong suspicion that the marked agument is wrong? The direct manipulation
of the portsc register works as expected. 

The testmodes array is magic in a way that the offset of the values corresponds directly
with the PTC field (Bits 19-16) of the Port Status Control register.

Also there is a driver which does the tests with a special usb test plug:
http://code.google.com/p/bricked/source/browse/drivers/usb/misc/ehset.c
Its also sending these usb_control_msg but these are also not working.

So if this usb_control_msg is working it would also be nice to get this driver mainlined.
Any hints whats needed to get this into mainline?

Best regards
Tim

Subject: [PATCH 20/23] usb-ehci: add usb testmodes to debugfs

---
 drivers/usb/host/ehci-dbg.c |  122 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 680e1a3..8db727b 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -18,6 +18,31 @@
 
 /* this file is part of ehci-hcd.c */
 
+#define PORTSC_OFFSET		0x184
+
+#define PTC_SHIFT			16
+#define PTC_MASK			(0xF << PTC_SHIFT)
+#define TEST_MODE_DISABLE	0
+#define J_STATE				1
+#define K_STATE				2
+#define SE0_NAK				3
+#define PACKET				4
+#define FORCE_ENABLE_HS		5
+#define FORCE_ENABLE_FS		6
+#define FORCE_ENABLE_LS		7
+#define TESTMODES_SIZE		8
+
+static char *testmodes[TESTMODES_SIZE] = {
+	"TEST_MODE_DISABLE",
+	"J_STATE",
+	"K_STATE",
+	"SE0",
+	"PACKET",
+	"FORCE_ENABLE_HS",
+	"FORCE_ENABLE_FS",
+	"FORCE_ENABLE_LS"
+};
+
 #define ehci_dbg(ehci, fmt, args...) \
 	dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
 #define ehci_err(ehci, fmt, args...) \
@@ -351,6 +376,9 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
 static int debug_async_open(struct inode *, struct file *);
 static int debug_periodic_open(struct inode *, struct file *);
 static int debug_registers_open(struct inode *, struct file *);
+static int debug_testmodes_open(struct inode *, struct file *);
+static ssize_t debug_testmodes_write(struct file *file,const char __user *buffer,
+					size_t count, loff_t *ppos);
 static int debug_async_open(struct inode *, struct file *);
 static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
 				   size_t count, loff_t *ppos);
@@ -382,6 +410,14 @@ static const struct file_operations debug_registers_fops = {
 	.release	= debug_close,
 	.llseek		= default_llseek,
 };
+static const struct file_operations debug_testmodes_fops = {
+	.owner		= THIS_MODULE,
+	.open		= debug_testmodes_open,
+	.read		= debug_output,
+	.write		= debug_testmodes_write,
+	.release	= debug_close,
+	.llseek		= default_llseek,
+};
 static const struct file_operations debug_lpm_fops = {
 	.owner		= THIS_MODULE,
 	.open		= simple_open,
@@ -867,6 +903,32 @@ done:
 	return buf->alloc_size - size;
 }
 
+static ssize_t fill_testmodes_buffer(struct debug_buffer *buf) 
+{
+	struct usb_hcd      *hcd;
+	struct ehci_hcd     *ehci;
+	unsigned long       flags;
+	unsigned        	temp, size, i, ptc;
+	char            	*next;
+
+	hcd = bus_to_hcd(buf->bus);
+	ehci = hcd_to_ehci (hcd);
+	next = buf->output_buf;
+	size = buf->alloc_size;
+	spin_lock_irqsave (&ehci->lock, flags);
+	ptc = (readl(hcd->regs + PORTSC_OFFSET) & PTC_MASK) >> PTC_SHIFT;
+	for(i = 0; i < TESTMODES_SIZE; i++) {
+		if(ptc == i) 
+			temp = scnprintf(next,size,"-> %s\n",testmodes[i]);
+		else
+			temp = scnprintf(next,size,"   %s\n",testmodes[i]);
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return buf->alloc_size - size;
+}
+
 static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
 				ssize_t (*fill_func)(struct debug_buffer *))
 {
@@ -942,6 +1004,7 @@ static int debug_close(struct inode *inode, struct file *file)
 
 	return 0;
 }
+
 static int debug_async_open(struct inode *inode, struct file *file)
 {
 	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
@@ -969,6 +1032,61 @@ static int debug_registers_open(struct inode *inode, struct file *file)
 	return file->private_data ? 0 : -ENOMEM;
 }
 
+static int debug_testmodes_open(struct inode *inode, struct file *file)
+{
+	struct debug_buffer *buf;
+	buf = alloc_buffer(inode->i_private, fill_testmodes_buffer);
+	if(!buf)
+		return -ENOMEM;
+	
+	buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+	file->private_data = buf;
+	return 0;
+}
+
+static ssize_t debug_testmodes_write(struct file *file,const char __user *buffer,
+					size_t count, loff_t *ppos)
+{
+	struct usb_hcd		*hcd;
+	struct ehci_hcd		*ehci;
+	struct usb_device	*hub;
+	char buf[50];
+	size_t len,slen;
+	int i;
+	int status = -1;
+	u32 rmw;
+
+	hcd = bus_to_hcd(((struct debug_buffer*)file->private_data)->bus);
+	ehci = hcd_to_ehci(hcd);
+	hub = hcd->self.root_hub;
+
+	len = min(count, (size_t) sizeof(buf) - 1);
+	if (copy_from_user(buf, buffer, len))
+		return -EFAULT;
+	buf[len] = '\0';
+	if (len > 0 && buf[len - 1] == '\n')
+		buf[len - 1] = '\0';
+
+	for(i=0; i<TESTMODES_SIZE; i++) {
+		slen = strlen(testmodes[i]);
+		if(!strncmp(buf,testmodes[i],slen)) {
+			/* for some reason this is not working 
+			status = usb_control_msg(hub, usb_sndctrlpipe(hub,0),
+						USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST,
+						i << 8 | hub->portnum, NULL, 0, 1000);
+			*/
+			rmw = readl(hcd->regs + PORTSC_OFFSET);
+			rmw &= ~PTC_MASK;
+			rmw |= (i << PTC_SHIFT) & PTC_MASK;
+			writel(rmw, hcd->regs + PORTSC_OFFSET);
+			status = 0;
+			break;
+		}
+	}
+	if(status>=0) return count;
+	else return -EINVAL;
+}
+
 static int debug_lpm_close(struct inode *inode, struct file *file)
 {
 	return 0;
@@ -1071,6 +1189,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
 						    &debug_registers_fops))
 		goto file_error;
 
+	if (!debugfs_create_file("testmode", S_IRUGO, ehci->debug_dir, bus,
+							&debug_testmodes_fops)) 
+		goto file_error;
+
 	if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
 						    &debug_lpm_fops))
 		goto file_error;
-- 
1.7.9.5


--
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