diff options
-rw-r--r-- | drivers/usb/host/ehci-dbg.c | 227 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 25 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 8 |
3 files changed, 219 insertions, 41 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 754a146cf828..39673f8194d9 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c | |||
@@ -323,7 +323,43 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } | |||
323 | 323 | ||
324 | #else | 324 | #else |
325 | 325 | ||
326 | /* troubleshooting help: expose state in sysfs */ | 326 | /* troubleshooting help: expose state in debugfs */ |
327 | |||
328 | static int debug_async_open(struct inode *, struct file *); | ||
329 | static int debug_periodic_open(struct inode *, struct file *); | ||
330 | static int debug_registers_open(struct inode *, struct file *); | ||
331 | static int debug_async_open(struct inode *, struct file *); | ||
332 | static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); | ||
333 | static int debug_close(struct inode *, struct file *); | ||
334 | |||
335 | static const struct file_operations debug_async_fops = { | ||
336 | .owner = THIS_MODULE, | ||
337 | .open = debug_async_open, | ||
338 | .read = debug_output, | ||
339 | .release = debug_close, | ||
340 | }; | ||
341 | static const struct file_operations debug_periodic_fops = { | ||
342 | .owner = THIS_MODULE, | ||
343 | .open = debug_periodic_open, | ||
344 | .read = debug_output, | ||
345 | .release = debug_close, | ||
346 | }; | ||
347 | static const struct file_operations debug_registers_fops = { | ||
348 | .owner = THIS_MODULE, | ||
349 | .open = debug_registers_open, | ||
350 | .read = debug_output, | ||
351 | .release = debug_close, | ||
352 | }; | ||
353 | |||
354 | static struct dentry *ehci_debug_root; | ||
355 | |||
356 | struct debug_buffer { | ||
357 | ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ | ||
358 | struct usb_bus *bus; | ||
359 | struct mutex mutex; /* protect filling of buffer */ | ||
360 | size_t count; /* number of characters filled into buffer */ | ||
361 | char *page; | ||
362 | }; | ||
327 | 363 | ||
328 | #define speed_char(info1) ({ char tmp; \ | 364 | #define speed_char(info1) ({ char tmp; \ |
329 | switch (info1 & (3 << 12)) { \ | 365 | switch (info1 & (3 << 12)) { \ |
@@ -441,10 +477,8 @@ done: | |||
441 | *nextp = next; | 477 | *nextp = next; |
442 | } | 478 | } |
443 | 479 | ||
444 | static ssize_t | 480 | static ssize_t fill_async_buffer(struct debug_buffer *buf) |
445 | show_async(struct device *dev, struct device_attribute *attr, char *buf) | ||
446 | { | 481 | { |
447 | struct usb_bus *bus; | ||
448 | struct usb_hcd *hcd; | 482 | struct usb_hcd *hcd; |
449 | struct ehci_hcd *ehci; | 483 | struct ehci_hcd *ehci; |
450 | unsigned long flags; | 484 | unsigned long flags; |
@@ -452,14 +486,13 @@ show_async(struct device *dev, struct device_attribute *attr, char *buf) | |||
452 | char *next; | 486 | char *next; |
453 | struct ehci_qh *qh; | 487 | struct ehci_qh *qh; |
454 | 488 | ||
455 | *buf = 0; | 489 | hcd = bus_to_hcd(buf->bus); |
456 | |||
457 | bus = dev_get_drvdata(dev); | ||
458 | hcd = bus_to_hcd(bus); | ||
459 | ehci = hcd_to_ehci (hcd); | 490 | ehci = hcd_to_ehci (hcd); |
460 | next = buf; | 491 | next = buf->page; |
461 | size = PAGE_SIZE; | 492 | size = PAGE_SIZE; |
462 | 493 | ||
494 | *next = 0; | ||
495 | |||
463 | /* dumps a snapshot of the async schedule. | 496 | /* dumps a snapshot of the async schedule. |
464 | * usually empty except for long-term bulk reads, or head. | 497 | * usually empty except for long-term bulk reads, or head. |
465 | * one QH per line, and TDs we know about | 498 | * one QH per line, and TDs we know about |
@@ -477,16 +510,12 @@ show_async(struct device *dev, struct device_attribute *attr, char *buf) | |||
477 | } | 510 | } |
478 | spin_unlock_irqrestore (&ehci->lock, flags); | 511 | spin_unlock_irqrestore (&ehci->lock, flags); |
479 | 512 | ||
480 | return strlen (buf); | 513 | return strlen(buf->page); |
481 | } | 514 | } |
482 | static DEVICE_ATTR(async, S_IRUGO, show_async, NULL); | ||
483 | 515 | ||
484 | #define DBG_SCHED_LIMIT 64 | 516 | #define DBG_SCHED_LIMIT 64 |
485 | 517 | static ssize_t fill_periodic_buffer(struct debug_buffer *buf) | |
486 | static ssize_t | ||
487 | show_periodic(struct device *dev, struct device_attribute *attr, char *buf) | ||
488 | { | 518 | { |
489 | struct usb_bus *bus; | ||
490 | struct usb_hcd *hcd; | 519 | struct usb_hcd *hcd; |
491 | struct ehci_hcd *ehci; | 520 | struct ehci_hcd *ehci; |
492 | unsigned long flags; | 521 | unsigned long flags; |
@@ -500,10 +529,9 @@ show_periodic(struct device *dev, struct device_attribute *attr, char *buf) | |||
500 | return 0; | 529 | return 0; |
501 | seen_count = 0; | 530 | seen_count = 0; |
502 | 531 | ||
503 | bus = dev_get_drvdata(dev); | 532 | hcd = bus_to_hcd(buf->bus); |
504 | hcd = bus_to_hcd(bus); | ||
505 | ehci = hcd_to_ehci (hcd); | 533 | ehci = hcd_to_ehci (hcd); |
506 | next = buf; | 534 | next = buf->page; |
507 | size = PAGE_SIZE; | 535 | size = PAGE_SIZE; |
508 | 536 | ||
509 | temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size); | 537 | temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size); |
@@ -623,14 +651,10 @@ show_periodic(struct device *dev, struct device_attribute *attr, char *buf) | |||
623 | 651 | ||
624 | return PAGE_SIZE - size; | 652 | return PAGE_SIZE - size; |
625 | } | 653 | } |
626 | static DEVICE_ATTR(periodic, S_IRUGO, show_periodic, NULL); | ||
627 | |||
628 | #undef DBG_SCHED_LIMIT | 654 | #undef DBG_SCHED_LIMIT |
629 | 655 | ||
630 | static ssize_t | 656 | static ssize_t fill_registers_buffer(struct debug_buffer *buf) |
631 | show_registers(struct device *dev, struct device_attribute *attr, char *buf) | ||
632 | { | 657 | { |
633 | struct usb_bus *bus; | ||
634 | struct usb_hcd *hcd; | 658 | struct usb_hcd *hcd; |
635 | struct ehci_hcd *ehci; | 659 | struct ehci_hcd *ehci; |
636 | unsigned long flags; | 660 | unsigned long flags; |
@@ -639,15 +663,14 @@ show_registers(struct device *dev, struct device_attribute *attr, char *buf) | |||
639 | static char fmt [] = "%*s\n"; | 663 | static char fmt [] = "%*s\n"; |
640 | static char label [] = ""; | 664 | static char label [] = ""; |
641 | 665 | ||
642 | bus = dev_get_drvdata(dev); | 666 | hcd = bus_to_hcd(buf->bus); |
643 | hcd = bus_to_hcd(bus); | ||
644 | ehci = hcd_to_ehci (hcd); | 667 | ehci = hcd_to_ehci (hcd); |
645 | next = buf; | 668 | next = buf->page; |
646 | size = PAGE_SIZE; | 669 | size = PAGE_SIZE; |
647 | 670 | ||
648 | spin_lock_irqsave (&ehci->lock, flags); | 671 | spin_lock_irqsave (&ehci->lock, flags); |
649 | 672 | ||
650 | if (bus->controller->power.power_state.event) { | 673 | if (buf->bus->controller->power.power_state.event) { |
651 | size = scnprintf (next, size, | 674 | size = scnprintf (next, size, |
652 | "bus %s, device %s (driver " DRIVER_VERSION ")\n" | 675 | "bus %s, device %s (driver " DRIVER_VERSION ")\n" |
653 | "%s\n" | 676 | "%s\n" |
@@ -789,26 +812,150 @@ done: | |||
789 | 812 | ||
790 | return PAGE_SIZE - size; | 813 | return PAGE_SIZE - size; |
791 | } | 814 | } |
792 | static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); | ||
793 | 815 | ||
794 | static inline void create_debug_files (struct ehci_hcd *ehci) | 816 | static struct debug_buffer *alloc_buffer(struct usb_bus *bus, |
817 | ssize_t (*fill_func)(struct debug_buffer *)) | ||
795 | { | 818 | { |
796 | struct device *dev = ehci_to_hcd(ehci)->self.dev; | 819 | struct debug_buffer *buf; |
797 | int retval; | 820 | |
821 | buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); | ||
798 | 822 | ||
799 | retval = device_create_file(dev, &dev_attr_async); | 823 | if (buf) { |
800 | retval = device_create_file(dev, &dev_attr_periodic); | 824 | buf->bus = bus; |
801 | retval = device_create_file(dev, &dev_attr_registers); | 825 | buf->fill_func = fill_func; |
826 | mutex_init(&buf->mutex); | ||
827 | } | ||
828 | |||
829 | return buf; | ||
802 | } | 830 | } |
803 | 831 | ||
804 | static inline void remove_debug_files (struct ehci_hcd *ehci) | 832 | static int fill_buffer(struct debug_buffer *buf) |
805 | { | 833 | { |
806 | struct device *dev = ehci_to_hcd(ehci)->self.dev; | 834 | int ret = 0; |
835 | |||
836 | if (!buf->page) | ||
837 | buf->page = (char *)get_zeroed_page(GFP_KERNEL); | ||
838 | |||
839 | if (!buf->page) { | ||
840 | ret = -ENOMEM; | ||
841 | goto out; | ||
842 | } | ||
843 | |||
844 | ret = buf->fill_func(buf); | ||
807 | 845 | ||
808 | device_remove_file(dev, &dev_attr_async); | 846 | if (ret >= 0) { |
809 | device_remove_file(dev, &dev_attr_periodic); | 847 | buf->count = ret; |
810 | device_remove_file(dev, &dev_attr_registers); | 848 | ret = 0; |
849 | } | ||
850 | |||
851 | out: | ||
852 | return ret; | ||
811 | } | 853 | } |
812 | 854 | ||
813 | #endif /* STUB_DEBUG_FILES */ | 855 | static ssize_t debug_output(struct file *file, char __user *user_buf, |
856 | size_t len, loff_t *offset) | ||
857 | { | ||
858 | struct debug_buffer *buf = file->private_data; | ||
859 | int ret = 0; | ||
860 | |||
861 | mutex_lock(&buf->mutex); | ||
862 | if (buf->count == 0) { | ||
863 | ret = fill_buffer(buf); | ||
864 | if (ret != 0) { | ||
865 | mutex_unlock(&buf->mutex); | ||
866 | goto out; | ||
867 | } | ||
868 | } | ||
869 | mutex_unlock(&buf->mutex); | ||
870 | |||
871 | ret = simple_read_from_buffer(user_buf, len, offset, | ||
872 | buf->page, buf->count); | ||
873 | |||
874 | out: | ||
875 | return ret; | ||
876 | |||
877 | } | ||
878 | |||
879 | static int debug_close(struct inode *inode, struct file *file) | ||
880 | { | ||
881 | struct debug_buffer *buf = file->private_data; | ||
814 | 882 | ||
883 | if (buf) { | ||
884 | if (buf->page) | ||
885 | free_page((unsigned long)buf->page); | ||
886 | kfree(buf); | ||
887 | } | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | static int debug_async_open(struct inode *inode, struct file *file) | ||
892 | { | ||
893 | file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); | ||
894 | |||
895 | return file->private_data ? 0 : -ENOMEM; | ||
896 | } | ||
897 | |||
898 | static int debug_periodic_open(struct inode *inode, struct file *file) | ||
899 | { | ||
900 | file->private_data = alloc_buffer(inode->i_private, | ||
901 | fill_periodic_buffer); | ||
902 | |||
903 | return file->private_data ? 0 : -ENOMEM; | ||
904 | } | ||
905 | |||
906 | static int debug_registers_open(struct inode *inode, struct file *file) | ||
907 | { | ||
908 | file->private_data = alloc_buffer(inode->i_private, | ||
909 | fill_registers_buffer); | ||
910 | |||
911 | return file->private_data ? 0 : -ENOMEM; | ||
912 | } | ||
913 | |||
914 | static inline void create_debug_files (struct ehci_hcd *ehci) | ||
915 | { | ||
916 | struct usb_bus *bus = &ehci_to_hcd(ehci)->self; | ||
917 | |||
918 | ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root); | ||
919 | if (!ehci->debug_dir) | ||
920 | goto dir_error; | ||
921 | |||
922 | ehci->debug_async = debugfs_create_file("async", S_IRUGO, | ||
923 | ehci->debug_dir, bus, | ||
924 | &debug_async_fops); | ||
925 | if (!ehci->debug_async) | ||
926 | goto async_error; | ||
927 | |||
928 | ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, | ||
929 | ehci->debug_dir, bus, | ||
930 | &debug_periodic_fops); | ||
931 | if (!ehci->debug_periodic) | ||
932 | goto periodic_error; | ||
933 | |||
934 | ehci->debug_registers = debugfs_create_file("registers", S_IRUGO, | ||
935 | ehci->debug_dir, bus, | ||
936 | &debug_registers_fops); | ||
937 | if (!ehci->debug_registers) | ||
938 | goto registers_error; | ||
939 | return; | ||
940 | |||
941 | registers_error: | ||
942 | debugfs_remove(ehci->debug_periodic); | ||
943 | periodic_error: | ||
944 | debugfs_remove(ehci->debug_async); | ||
945 | async_error: | ||
946 | debugfs_remove(ehci->debug_dir); | ||
947 | dir_error: | ||
948 | ehci->debug_periodic = NULL; | ||
949 | ehci->debug_async = NULL; | ||
950 | ehci->debug_dir = NULL; | ||
951 | } | ||
952 | |||
953 | static inline void remove_debug_files (struct ehci_hcd *ehci) | ||
954 | { | ||
955 | debugfs_remove(ehci->debug_registers); | ||
956 | debugfs_remove(ehci->debug_periodic); | ||
957 | debugfs_remove(ehci->debug_async); | ||
958 | debugfs_remove(ehci->debug_dir); | ||
959 | } | ||
960 | |||
961 | #endif /* STUB_DEBUG_FILES */ | ||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5f2d74ed5ad7..264182654f4c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
34 | #include <linux/moduleparam.h> | 34 | #include <linux/moduleparam.h> |
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | #include <linux/debugfs.h> | ||
36 | 37 | ||
37 | #include "../core/hcd.h" | 38 | #include "../core/hcd.h" |
38 | 39 | ||
@@ -978,15 +979,30 @@ static int __init ehci_hcd_init(void) | |||
978 | sizeof(struct ehci_qh), sizeof(struct ehci_qtd), | 979 | sizeof(struct ehci_qh), sizeof(struct ehci_qtd), |
979 | sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); | 980 | sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); |
980 | 981 | ||
982 | #ifdef DEBUG | ||
983 | ehci_debug_root = debugfs_create_dir("ehci", NULL); | ||
984 | if (!ehci_debug_root) | ||
985 | return -ENOENT; | ||
986 | #endif | ||
987 | |||
981 | #ifdef PLATFORM_DRIVER | 988 | #ifdef PLATFORM_DRIVER |
982 | retval = platform_driver_register(&PLATFORM_DRIVER); | 989 | retval = platform_driver_register(&PLATFORM_DRIVER); |
983 | if (retval < 0) | 990 | if (retval < 0) { |
991 | #ifdef DEBUG | ||
992 | debugfs_remove(ehci_debug_root); | ||
993 | ehci_debug_root = NULL; | ||
994 | #endif | ||
984 | return retval; | 995 | return retval; |
996 | } | ||
985 | #endif | 997 | #endif |
986 | 998 | ||
987 | #ifdef PCI_DRIVER | 999 | #ifdef PCI_DRIVER |
988 | retval = pci_register_driver(&PCI_DRIVER); | 1000 | retval = pci_register_driver(&PCI_DRIVER); |
989 | if (retval < 0) { | 1001 | if (retval < 0) { |
1002 | #ifdef DEBUG | ||
1003 | debugfs_remove(ehci_debug_root); | ||
1004 | ehci_debug_root = NULL; | ||
1005 | #endif | ||
990 | #ifdef PLATFORM_DRIVER | 1006 | #ifdef PLATFORM_DRIVER |
991 | platform_driver_unregister(&PLATFORM_DRIVER); | 1007 | platform_driver_unregister(&PLATFORM_DRIVER); |
992 | #endif | 1008 | #endif |
@@ -997,6 +1013,10 @@ static int __init ehci_hcd_init(void) | |||
997 | #ifdef PS3_SYSTEM_BUS_DRIVER | 1013 | #ifdef PS3_SYSTEM_BUS_DRIVER |
998 | retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); | 1014 | retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); |
999 | if (retval < 0) { | 1015 | if (retval < 0) { |
1016 | #ifdef DEBUG | ||
1017 | debugfs_remove(ehci_debug_root); | ||
1018 | ehci_debug_root = NULL; | ||
1019 | #endif | ||
1000 | #ifdef PLATFORM_DRIVER | 1020 | #ifdef PLATFORM_DRIVER |
1001 | platform_driver_unregister(&PLATFORM_DRIVER); | 1021 | platform_driver_unregister(&PLATFORM_DRIVER); |
1002 | #endif | 1022 | #endif |
@@ -1022,6 +1042,9 @@ static void __exit ehci_hcd_cleanup(void) | |||
1022 | #ifdef PS3_SYSTEM_BUS_DRIVER | 1042 | #ifdef PS3_SYSTEM_BUS_DRIVER |
1023 | ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); | 1043 | ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); |
1024 | #endif | 1044 | #endif |
1045 | #ifdef DEBUG | ||
1046 | debugfs_remove(ehci_debug_root); | ||
1047 | #endif | ||
1025 | } | 1048 | } |
1026 | module_exit(ehci_hcd_cleanup); | 1049 | module_exit(ehci_hcd_cleanup); |
1027 | 1050 | ||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 951d69fec513..10e71417c352 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -127,6 +127,14 @@ struct ehci_hcd { /* one per controller */ | |||
127 | #else | 127 | #else |
128 | # define COUNT(x) do {} while (0) | 128 | # define COUNT(x) do {} while (0) |
129 | #endif | 129 | #endif |
130 | |||
131 | /* debug files */ | ||
132 | #ifdef DEBUG | ||
133 | struct dentry *debug_dir; | ||
134 | struct dentry *debug_async; | ||
135 | struct dentry *debug_periodic; | ||
136 | struct dentry *debug_registers; | ||
137 | #endif | ||
130 | }; | 138 | }; |
131 | 139 | ||
132 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 140 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |